Skip to content

Commit

Permalink
Import cross signing keys and verify local device in `bootstrapCrossS…
Browse files Browse the repository at this point in the history
…igning`
  • Loading branch information
florianduros committed Jul 18, 2023
1 parent eb7faa6 commit 2724a05
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 7 deletions.
5 changes: 4 additions & 1 deletion spec/test-utils/mockEndpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export function mockInitialApiRequests(homeserverUrl: string) {
*/
export function mockSetupCrossSigningRequests(): void {
// have account_data requests return an empty object
fetchMock.get("express:/_matrix/client/r0/user/:userId/account_data/:type", {});
fetchMock.get("express:/_matrix/client/r0/user/:userId/account_data/:type", {
status: 404,
body: { errcode: "M_NOT_FOUND", error: "Account data not found." },
});

// we expect a request to upload signatures for our device ...
fetchMock.post({ url: "path:/_matrix/client/v3/keys/signatures/upload", name: "upload-sigs" }, {});
Expand Down
9 changes: 8 additions & 1 deletion spec/unit/rust-crypto/CrossSigningIdentity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm";

import { CrossSigningIdentity } from "../../../src/rust-crypto/CrossSigningIdentity";
import { OutgoingRequestProcessor } from "../../../src/rust-crypto/OutgoingRequestProcessor";
import { ServerSideSecretStorage } from "../../../src/secret-storage";

describe("CrossSigningIdentity", () => {
describe("bootstrapCrossSigning", () => {
Expand All @@ -31,6 +32,8 @@ describe("CrossSigningIdentity", () => {
/** A mock OutgoingRequestProcessor which crossSigning is connected to */
let outgoingRequestProcessor: Mocked<OutgoingRequestProcessor>;

let secretStorage: Mocked<ServerSideSecretStorage>;

beforeEach(async () => {
await RustSdkCryptoJs.initAsync();

Expand All @@ -44,7 +47,11 @@ describe("CrossSigningIdentity", () => {
makeOutgoingRequest: jest.fn(),
} as unknown as Mocked<OutgoingRequestProcessor>;

crossSigning = new CrossSigningIdentity(olmMachine, outgoingRequestProcessor);
secretStorage = {
get: jest.fn(),
} as unknown as Mocked<ServerSideSecretStorage>;

crossSigning = new CrossSigningIdentity(olmMachine, outgoingRequestProcessor, secretStorage);
});

it("should do nothing if keys are present on-device and in secret storage", async () => {
Expand Down
3 changes: 3 additions & 0 deletions spec/unit/rust-crypto/rust-crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ describe("RustCrypto", () => {
};
// @ts-ignore private property
rustCrypto.crossSigningIdentity = mockCrossSigningIdentity;
// @ts-ignore private property
rustCrypto.olmMachine.getDevice = jest.fn().mockReturnValue({ verify: jest.fn().mockReturnValue({}) });

await rustCrypto.bootstrapCrossSigning({});
expect(mockCrossSigningIdentity.bootstrapCrossSigning).toHaveBeenCalledWith({});
});
Expand Down
6 changes: 4 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2679,12 +2679,14 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* Check the copy of our cross-signing key that we have in the device list and
* see if we can get the private key. If so, mark it as trusted.
* @param opts - ICheckOwnCrossSigningTrustOpts object
*
* @deprecated Unneeded for the new crypto
*/
public checkOwnCrossSigningTrust(opts?: ICheckOwnCrossSigningTrustOpts): Promise<void> {
if (!this.crypto) {
if (!this.cryptoBackend) {
throw new Error("End-to-end encryption disabled");
}
return this.crypto.checkOwnCrossSigningTrust(opts);
return this.cryptoBackend.checkOwnCrossSigningTrust(opts);
}

/**
Expand Down
15 changes: 15 additions & 0 deletions src/crypto-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,14 @@ export interface CryptoApi {
*/
createRecoveryKeyFromPassphrase(password?: string): Promise<GeneratedSecretStorageKey>;

/**
* Check the cross signing trust of the current user
* Unneeded for new crypto
*
* @param opts - Options object.
*/
checkOwnCrossSigningTrust(opts?: CheckOwnCrossSigningTrustOpts): Promise<void>;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Device/User verification
Expand Down Expand Up @@ -490,5 +498,12 @@ export interface GeneratedSecretStorageKey {
encodedPrivateKey?: string;
}

/**
* Options object for {@link CryptoApi#checkOwnCrossSigningTrust}.
*/
export interface CheckOwnCrossSigningTrustOpts {
allowPrivateKeyRequests?: boolean;
}

export * from "./crypto-api/verification";
export * from "./crypto-api/keybackup";
12 changes: 10 additions & 2 deletions src/rust-crypto/CrossSigningIdentity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { BootstrapCrossSigningOpts } from "../crypto-api";
import { logger } from "../logger";
import { OutgoingRequest, OutgoingRequestProcessor } from "./OutgoingRequestProcessor";
import { UIAuthCallback } from "../interactive-auth";
import { ServerSideSecretStorage } from "../secret-storage";

/** Manages the cross-signing keys for our own user.
*
Expand All @@ -29,6 +30,7 @@ export class CrossSigningIdentity {
public constructor(
private readonly olmMachine: OlmMachine,
private readonly outgoingRequestProcessor: OutgoingRequestProcessor,
private readonly secretStorage: ServerSideSecretStorage,
) {}

/**
Expand All @@ -41,7 +43,13 @@ export class CrossSigningIdentity {
}

const olmDeviceStatus: CrossSigningStatus = await this.olmMachine.crossSigningStatus();
const privateKeysInSecretStorage = false; // TODO

// Fetch cross signing keys from the secret storage
const masterKey = await this.secretStorage.get("m.cross_signing.master");
const selfSigningKey = await this.secretStorage.get("m.cross_signing.self_signing");
const userSigningKey = await this.secretStorage.get("m.cross_signing.user_signing");
const privateKeysInSecretStorage = Boolean(masterKey && selfSigningKey && userSigningKey);

const olmDeviceHasKeys =
olmDeviceStatus.hasMaster && olmDeviceStatus.hasUserSigning && olmDeviceStatus.hasSelfSigning;

Expand All @@ -67,7 +75,7 @@ export class CrossSigningIdentity {
"bootStrapCrossSigning: Cross-signing private keys not found locally, but they are available " +
"in secret storage, reading storage and caching locally",
);
throw new Error("TODO");
await this.olmMachine.importCrossSigningKeys(masterKey, selfSigningKey, userSigningKey);
}

// TODO: we might previously have bootstrapped cross-signing but not completed uploading the keys to the
Expand Down
26 changes: 25 additions & 1 deletion src/rust-crypto/rust-crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
this.outgoingRequestProcessor = new OutgoingRequestProcessor(olmMachine, http);
this.keyClaimManager = new KeyClaimManager(olmMachine, this.outgoingRequestProcessor);
this.eventDecryptor = new EventDecryptor(olmMachine);
this.crossSigningIdentity = new CrossSigningIdentity(olmMachine, this.outgoingRequestProcessor);
this.crossSigningIdentity = new CrossSigningIdentity(olmMachine, this.outgoingRequestProcessor, secretStorage);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -386,6 +386,16 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
*/
public async bootstrapCrossSigning(opts: BootstrapCrossSigningOpts): Promise<void> {
await this.crossSigningIdentity.bootstrapCrossSigning(opts);

// Get the current device
const device: RustSdkCryptoJs.Device = await this.olmMachine.getDevice(
this.olmMachine.userId,
this.olmMachine.deviceId,
);

// Verify the device and upload the cross signing signatures
const request: RustSdkCryptoJs.SignatureUploadRequest = await device.verify();
await this.outgoingRequestProcessor.makeOutgoingRequest(request);
}

/**
Expand Down Expand Up @@ -658,6 +668,20 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
return new RustVerificationRequest(request, this.outgoingRequestProcessor, this._supportedVerificationMethods);
}

/**
* This function is unneeded for the rust-crypto.
* The cross signing key import and the device verification are done in {@link CryptoApi#bootstrapCrossSigning}
*
* The function is stub to keep the compatibility with the old crypto.
* More information: https://github.com/vector-im/element-web/issues/25648
*
*
* Implementation of {@link CryptoApi#checkOwnCrossSigningTrust}
*/
public async checkOwnCrossSigningTrust(): Promise<void> {
return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SyncCryptoCallbacks implementation
Expand Down

0 comments on commit 2724a05

Please sign in to comment.