Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Changes in next release
=======================
## ✨ Features

* Allow passing a signing function when setting up Rust crypto ([#5483](https://github.com/matrix-org/matrix-js-sdk/pull/5483)). Contributed by @andybalaam.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is auto generated: just make the PR title your changelog entry and it will do the right thing.

Changes in [42.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v42.2.0) (2026-08-18)
==================================================================================================
## 🐛 Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
],
"dependencies": {
"@babel/runtime": "^8.0.0",
"@matrix-org/matrix-sdk-crypto-wasm": "^18.4.0",
"@matrix-org/matrix-sdk-crypto-wasm": "^18.6.0",
"another-json": "^0.2.0",
"bs58": "^6.0.0",
"content-type": "^2.0.0",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions spec/integ/crypto/rust-crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ eXmIj7ZEOIsufPdiYuKDp/aUdgUHmuCGyegfoCJze36SdFX5q6z8Aq5nKPtz+FM=
-----END CERTIFICATE-----
`;

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

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

const x509Signer = async (item: Uint8Array) => {
return {
signature_bytes: item,
certificate_chain: "MYCHAIN",
signature_scheme: "RsaPssSha512" as const,
};
};

const x509Validity = () => 12000.3;

// When we init Rust crypto and pass a PEM for the CA certs
await matrixClient.initRustCrypto({ caCertsPem: CA_PEM });
await matrixClient.initRustCrypto({ caCertsPem: CA_PEM, x509Signer, x509Validity });

// Then that PEM was passed in to the Olm machine
expect(initFromStore).toHaveBeenCalledWith(
Expand All @@ -175,6 +185,8 @@ eXmIj7ZEOIsufPdiYuKDp/aUdgUHmuCGyegfoCJze36SdFX5q6z8Aq5nKPtz+FM=
expect.anything(),
expect.anything(),
CA_PEM,
x509Signer,
x509Validity,
);
});

Expand Down
20 changes: 19 additions & 1 deletion spec/unit/rust-crypto/rust-crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,12 @@ describe("initRustCrypto", () => {
mockStore,
logger,
undefined,
undefined,
undefined,
);
});

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

Expand All @@ -154,6 +156,16 @@ describe("initRustCrypto", () => {
const storeKey = new Uint8Array(32);
const logger = new DebugLogger(debug("matrix-js-sdk:test:initRustCrypto"));
const caCertsPem = "MY_PEM etc...";
const x509Signer = async (item: Uint8Array) => {
return {
signature_bytes: item,
certificate_chain: "CHAIN",
signature_scheme: "RsaPssSha512" as const,
};
};
const x509Validity = () => {
return 10000;
};

await initRustCrypto({
logger,
Expand All @@ -165,6 +177,8 @@ describe("initRustCrypto", () => {
storePrefix: "storePrefix",
storeKey: storeKey,
caCertsPem,
x509Signer,
x509Validity,
});

expect(StoreHandle.openWithKey).toHaveBeenCalledWith("storePrefix", storeKey, logger);
Expand All @@ -174,6 +188,8 @@ describe("initRustCrypto", () => {
mockStore,
logger,
caCertsPem,
x509Signer,
x509Validity,
);
});

Expand Down Expand Up @@ -204,6 +220,8 @@ describe("initRustCrypto", () => {
mockStore,
logger,
undefined,
undefined,
undefined,
);
});

Expand Down
17 changes: 16 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1980,7 +1980,14 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* @param args.caCertsPem - Optional PEM-formatted string that provides CA certificates. These will be used to check
* X.509 signatures on user identities. Any user identity that has a valid signature according to the supplied
* CAs will be considered verified, without any manual verification taking place.
*
* NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
* @param args.x509Signer - Optional async function for signing some data with an X.509 certificate. Used to sign
* the user's identity so compatible clients will recognise this user as verified without manual verification
* taking place. If you supply this you must also supply rawX509Validity.
* NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
* @param args.x509Validity - Optional function returning the validity period of the X.509 certificate used for
* signing, as the number of milliseconds since the Unix epoch. If you supply this you must also supply
* rawX509Signer.
* NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
*
* @returns a Promise which will resolve when the crypto layer has been
Expand All @@ -1993,6 +2000,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
storageKey?: Uint8Array;
storagePassword?: string;
caCertsPem?: string;
x509Signer?: (item: Uint8Array) => Promise<{
signature_bytes: Uint8Array;
certificate_chain: string;
signature_scheme: "RsaPssSha512";
}>;
x509Validity?: () => number;
} = {},
): Promise<void> {
if (this.cryptoBackend) {
Expand Down Expand Up @@ -2040,6 +2053,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
enableEncryptedStateEvents: this.enableEncryptedStateEvents,

caCertsPem: args.caCertsPem,
x509Signer: args.x509Signer,
x509Validity: args.x509Validity,
});

rustCrypto.setSupportedVerificationMethods(this.verificationMethods);
Expand Down
23 changes: 23 additions & 0 deletions src/rust-crypto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ export interface InitRustCryptoArgs {
* considered verified, without any manual verification taking place.
*/
caCertsPem?: string;

/**
* Optional async function for signing some data with an X.509 certificate.
* Used to sign the user's identity so compatible clients will recognise
* this user as verified without manual verification taking place. If you
* supply this you must also supply rawX509Validity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs refer to raw prefixed functions which doesn't match the names? (Also, should they have some kind of link annotation?)

*/
x509Signer?: (item: Uint8Array) => Promise<{
signature_bytes: Uint8Array;
certificate_chain: string;
signature_scheme: "RsaPssSha512";
}>;

/**
* Optional function returning the validity period of the X.509 certificate
* used for signing, as the number of milliseconds since the Unix epoch. If
* you supply this you must also supply rawX509Signer.
*/
x509Validity?: () => number;
}

/**
Expand Down Expand Up @@ -158,6 +177,8 @@ async function initOlmMachine(
legacyCryptoStore,
enableEncryptedStateEvents,
caCertsPem,
x509Signer,
x509Validity,
}: InitRustCryptoArgs,
storeHandle: StoreHandle,
): Promise<RustCrypto> {
Expand All @@ -169,6 +190,8 @@ async function initOlmMachine(
storeHandle,
logger,
caCertsPem,
x509Signer,
x509Validity,
);

// A final migration step, now that we have an OlmMachine.
Expand Down
Loading