Skip to content

Commit 03c4f58

Browse files
committed
Support passing an async function to do X.509 signing
Also requires a validity function.
1 parent 6fe2efc commit 03c4f58

5 files changed

Lines changed: 78 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
Changes in next release
2+
=======================
3+
## ✨ Features
4+
5+
* Allow passing a signing function when setting up Rust crypto ([#5483](https://github.com/matrix-org/matrix-js-sdk/pull/5483)). Contributed by @andybalaam.
6+
17
Changes in [42.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v42.2.0) (2026-08-18)
28
==================================================================================================
39
## 🐛 Bug Fixes

spec/integ/crypto/rust-crypto.spec.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ eXmIj7ZEOIsufPdiYuKDp/aUdgUHmuCGyegfoCJze36SdFX5q6z8Aq5nKPtz+FM=
155155
-----END CERTIFICATE-----
156156
`;
157157

158-
it("should pass on the caCertsPem if supplied", async () => {
158+
it("should pass on the caCertsPem and sign function if supplied", async () => {
159159
// Given a Matrix client
160160
const matrixClient = createClient({
161161
baseUrl: "http://test.server",
@@ -165,8 +165,18 @@ eXmIj7ZEOIsufPdiYuKDp/aUdgUHmuCGyegfoCJze36SdFX5q6z8Aq5nKPtz+FM=
165165

166166
const initFromStore = vi.spyOn(OlmMachine, "initFromStore");
167167

168+
const x509Signer = async (item: Uint8Array) => {
169+
return {
170+
signature_bytes: item,
171+
certificate_chain: "MYCHAIN",
172+
signature_scheme: "RsaPssSha512" as const,
173+
};
174+
};
175+
176+
const x509Validity = () => 12000.3;
177+
168178
// When we init Rust crypto and pass a PEM for the CA certs
169-
await matrixClient.initRustCrypto({ caCertsPem: CA_PEM });
179+
await matrixClient.initRustCrypto({ caCertsPem: CA_PEM, x509Signer, x509Validity });
170180

171181
// Then that PEM was passed in to the Olm machine
172182
expect(initFromStore).toHaveBeenCalledWith(
@@ -175,6 +185,8 @@ eXmIj7ZEOIsufPdiYuKDp/aUdgUHmuCGyegfoCJze36SdFX5q6z8Aq5nKPtz+FM=
175185
expect.anything(),
176186
expect.anything(),
177187
CA_PEM,
188+
x509Signer,
189+
x509Validity,
178190
);
179191
});
180192

spec/unit/rust-crypto/rust-crypto.spec.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,12 @@ describe("initRustCrypto", () => {
141141
mockStore,
142142
logger,
143143
undefined,
144+
undefined,
145+
undefined,
144146
);
145147
});
146148

147-
it("passes through the store params (key) and CA certs", async () => {
149+
it("passes through the store params (key), CA certs and sign function", async () => {
148150
const mockStore = { free: vi.fn() } as unknown as StoreHandle;
149151
vi.spyOn(StoreHandle, "openWithKey").mockResolvedValue(mockStore);
150152

@@ -154,6 +156,16 @@ describe("initRustCrypto", () => {
154156
const storeKey = new Uint8Array(32);
155157
const logger = new DebugLogger(debug("matrix-js-sdk:test:initRustCrypto"));
156158
const caCertsPem = "MY_PEM etc...";
159+
const x509Signer = async (item: Uint8Array) => {
160+
return {
161+
signature_bytes: item,
162+
certificate_chain: "CHAIN",
163+
signature_scheme: "RsaPssSha512" as const,
164+
};
165+
};
166+
const x509Validity = () => {
167+
return 10000;
168+
};
157169

158170
await initRustCrypto({
159171
logger,
@@ -165,6 +177,8 @@ describe("initRustCrypto", () => {
165177
storePrefix: "storePrefix",
166178
storeKey: storeKey,
167179
caCertsPem,
180+
x509Signer,
181+
x509Validity,
168182
});
169183

170184
expect(StoreHandle.openWithKey).toHaveBeenCalledWith("storePrefix", storeKey, logger);
@@ -174,6 +188,8 @@ describe("initRustCrypto", () => {
174188
mockStore,
175189
logger,
176190
caCertsPem,
191+
x509Signer,
192+
x509Validity,
177193
);
178194
});
179195

@@ -204,6 +220,8 @@ describe("initRustCrypto", () => {
204220
mockStore,
205221
logger,
206222
undefined,
223+
undefined,
224+
undefined,
207225
);
208226
});
209227

src/client.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1980,7 +1980,14 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
19801980
* @param args.caCertsPem - Optional PEM-formatted string that provides CA certificates. These will be used to check
19811981
* X.509 signatures on user identities. Any user identity that has a valid signature according to the supplied
19821982
* CAs will be considered verified, without any manual verification taking place.
1983-
*
1983+
* NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
1984+
* @param args.x509Signer - Optional async function for signing some data with an X.509 certificate. Used to sign
1985+
* the user's identity so compatible clients will recognise this user as verified without manual verification
1986+
* taking place. If you supply this you must also supply rawX509Validity.
1987+
* NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
1988+
* @param args.x509Validity - Optional function returning the validity period of the X.509 certificate used for
1989+
* signing, as the number of milliseconds since the Unix epoch. If you supply this you must also supply
1990+
* rawX509Signer.
19841991
* NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
19851992
*
19861993
* @returns a Promise which will resolve when the crypto layer has been
@@ -1993,6 +2000,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
19932000
storageKey?: Uint8Array;
19942001
storagePassword?: string;
19952002
caCertsPem?: string;
2003+
x509Signer?: (item: Uint8Array) => Promise<{
2004+
signature_bytes: Uint8Array;
2005+
certificate_chain: string;
2006+
signature_scheme: "RsaPssSha512";
2007+
}>;
2008+
x509Validity?: () => number;
19962009
} = {},
19972010
): Promise<void> {
19982011
if (this.cryptoBackend) {
@@ -2040,6 +2053,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
20402053
enableEncryptedStateEvents: this.enableEncryptedStateEvents,
20412054

20422055
caCertsPem: args.caCertsPem,
2056+
x509Signer: args.x509Signer,
2057+
x509Validity: args.x509Validity,
20432058
});
20442059

20452060
rustCrypto.setSupportedVerificationMethods(this.verificationMethods);

src/rust-crypto/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,25 @@ export interface InitRustCryptoArgs {
103103
* considered verified, without any manual verification taking place.
104104
*/
105105
caCertsPem?: string;
106+
107+
/**
108+
* Optional async function for signing some data with an X.509 certificate.
109+
* Used to sign the user's identity so compatible clients will recognise
110+
* this user as verified without manual verification taking place. If you
111+
* supply this you must also supply rawX509Validity.
112+
*/
113+
x509Signer?: (item: Uint8Array) => Promise<{
114+
signature_bytes: Uint8Array;
115+
certificate_chain: string;
116+
signature_scheme: "RsaPssSha512";
117+
}>;
118+
119+
/**
120+
* Optional function returning the validity period of the X.509 certificate
121+
* used for signing, as the number of milliseconds since the Unix epoch. If
122+
* you supply this you must also supply rawX509Signer.
123+
*/
124+
x509Validity?: () => number;
106125
}
107126

108127
/**
@@ -158,6 +177,8 @@ async function initOlmMachine(
158177
legacyCryptoStore,
159178
enableEncryptedStateEvents,
160179
caCertsPem,
180+
x509Signer,
181+
x509Validity,
161182
}: InitRustCryptoArgs,
162183
storeHandle: StoreHandle,
163184
): Promise<RustCrypto> {
@@ -169,6 +190,8 @@ async function initOlmMachine(
169190
storeHandle,
170191
logger,
171192
caCertsPem,
193+
x509Signer,
194+
x509Validity,
172195
);
173196

174197
// A final migration step, now that we have an OlmMachine.

0 commit comments

Comments
 (0)