You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-09 10:22:46 +03:00
Untangle cross-signing and secret storage
This untangles cross-signing and secret storage setup into separate path that can be invoked independently. There is no functional change with this patch, but instead this just separates one giant monster API into two. Part of https://github.com/vector-im/element-web/issues/13895
This commit is contained in:
@@ -20,7 +20,7 @@ import anotherjson from 'another-json';
|
||||
import * as olmlib from "../../../src/crypto/olmlib";
|
||||
import {TestClient} from '../../TestClient';
|
||||
import {HttpResponse, setHttpResponses} from '../../test-utils';
|
||||
import {resetCrossSigningKeys, createSecretStorageKey} from "./crypto-utils";
|
||||
import { resetCrossSigningKeys } from "./crypto-utils";
|
||||
import { MatrixError } from '../../../src/http-api';
|
||||
|
||||
async function makeTestClient(userInfo, options, keys) {
|
||||
@@ -71,8 +71,7 @@ describe("Cross Signing", function() {
|
||||
alice.setAccountData = async () => {};
|
||||
alice.getAccountDataFromServer = async () => {};
|
||||
// set Alice's cross-signing key
|
||||
await alice.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
await alice.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
expect(alice.uploadDeviceSigningKeys).toHaveBeenCalled();
|
||||
@@ -118,8 +117,7 @@ describe("Cross Signing", function() {
|
||||
// through failure, stopping before actually applying changes.
|
||||
let bootstrapDidThrow = false;
|
||||
try {
|
||||
await alice.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
await alice.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} catch (e) {
|
||||
|
@@ -326,9 +326,11 @@ describe("Secrets", function() {
|
||||
this.emit("accountData", event);
|
||||
};
|
||||
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await bob.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
|
||||
const crossSigning = bob._crypto._crossSigningInfo;
|
||||
@@ -379,13 +381,15 @@ describe("Secrets", function() {
|
||||
const secretStorage = bob._crypto._secretStorage;
|
||||
|
||||
// Set up cross-signing keys from scratch with specific storage key
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await bob.bootstrapSecretStorage({
|
||||
createSecretStorageKey: async () => ({
|
||||
// `pubkey` not used anymore with symmetric 4S
|
||||
keyInfo: { pubkey: storagePublicKey },
|
||||
privateKey: storagePrivateKey,
|
||||
}),
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
|
||||
// Clear local cross-signing keys and read from secret storage
|
||||
@@ -394,7 +398,7 @@ describe("Secrets", function() {
|
||||
crossSigning.toStorage(),
|
||||
);
|
||||
crossSigning.keys = {};
|
||||
await bob.bootstrapSecretStorage({
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
|
||||
@@ -517,9 +521,7 @@ describe("Secrets", function() {
|
||||
this.emit("accountData", event);
|
||||
};
|
||||
|
||||
await alice.bootstrapSecretStorage({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await alice.bootstrapSecretStorage();
|
||||
|
||||
expect(alice.getAccountData("m.secret_storage.default_key").getContent())
|
||||
.toEqual({key: "key_id"});
|
||||
@@ -659,9 +661,7 @@ describe("Secrets", function() {
|
||||
this.emit("accountData", event);
|
||||
};
|
||||
|
||||
await alice.bootstrapSecretStorage({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await alice.bootstrapSecretStorage();
|
||||
|
||||
const backupKey = alice.getAccountData("m.megolm_backup.v1")
|
||||
.getContent();
|
||||
|
@@ -1176,6 +1176,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
"legacyDeviceVerification",
|
||||
"prepareToEncrypt",
|
||||
"isCrossSigningReady",
|
||||
"bootstrapCrossSigning",
|
||||
"getCryptoTrustCrossSignedDevices",
|
||||
"setCryptoTrustCrossSignedDevices",
|
||||
"countSessionsNeedingBackup",
|
||||
@@ -1360,6 +1361,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
wrapCryptoFuncs(MatrixClient, [
|
||||
"getEventEncryptionInfo",
|
||||
"createRecoveryKeyFromPassphrase",
|
||||
"isSecretStorageReady",
|
||||
"bootstrapSecretStorage",
|
||||
"addSecretStorageKey",
|
||||
"hasSecretStorageKey",
|
||||
|
@@ -86,6 +86,7 @@ export class CrossSigningInfo extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Calls the app callback to ask for a private key
|
||||
*
|
||||
* @param {string} type The key type ("master", "self_signing", or "user_signing")
|
||||
* @param {string} expectedPubkey The matching public key or undefined to use
|
||||
* the stored public key for the given key type.
|
||||
@@ -204,6 +205,38 @@ export class CrossSigningInfo extends EventEmitter {
|
||||
return decodeBase64(encodedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the private keys exist in the local key cache.
|
||||
*
|
||||
* @returns {boolean} True if all keys are stored in the local cache.
|
||||
*/
|
||||
async isStoredInKeyCache() {
|
||||
const cacheCallbacks = this._cacheCallbacks;
|
||||
if (!cacheCallbacks) return false;
|
||||
for (const type of ["master", "self_signing", "user_signing"]) {
|
||||
if (!await cacheCallbacks.getCrossSigningKeyCache(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cross-signing private keys from the local cache.
|
||||
*
|
||||
* @returns {Map} A map from key type (string) to private key (Uint8Array)
|
||||
*/
|
||||
async getCrossSigningKeysFromCache() {
|
||||
const keys = new Map();
|
||||
const cacheCallbacks = this._cacheCallbacks;
|
||||
if (!cacheCallbacks) return keys;
|
||||
for (const type of ["master", "self_signing", "user_signing"]) {
|
||||
const privKey = await cacheCallbacks.getCrossSigningKeyCache(type);
|
||||
keys.set(type, privKey);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID used to identify the user. This can also be used to test for
|
||||
* the existence of a given key type.
|
||||
|
@@ -406,14 +406,12 @@ Crypto.prototype.createRecoveryKeyFromPassphrase = async function(password) {
|
||||
|
||||
/**
|
||||
* Checks whether cross signing:
|
||||
* - is enabled on this account
|
||||
* - is trusted by this device
|
||||
* - has private keys stored in secret storage
|
||||
* and that the account has a secret storage key
|
||||
* - is enabled on this account and trusted by this device
|
||||
* - has private keys either cached locally or stored in secret storage
|
||||
*
|
||||
* If this function returns false, bootstrapSecretStorage() can be used
|
||||
* If this function returns false, bootstrapCrossSigning() can be used
|
||||
* to fix things such that it returns true. That is to say, after
|
||||
* bootstrapSecretStorage() completes successfully, this function should
|
||||
* bootstrapCrossSigning() completes successfully, this function should
|
||||
* return true.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
@@ -422,18 +420,166 @@ Crypto.prototype.createRecoveryKeyFromPassphrase = async function(password) {
|
||||
*/
|
||||
Crypto.prototype.isCrossSigningReady = async function() {
|
||||
const publicKeysOnDevice = this._crossSigningInfo.getId();
|
||||
const privateKeysInStorage = await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
const privateKeysExistSomewhere = (
|
||||
await this._crossSigningInfo.isStoredInKeyCache() ||
|
||||
await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
)
|
||||
);
|
||||
const secretStorageKeyInAccount = await this._secretStorage.hasKey();
|
||||
|
||||
return (
|
||||
publicKeysOnDevice &&
|
||||
privateKeysInStorage &&
|
||||
secretStorageKeyInAccount
|
||||
privateKeysExistSomewhere
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether secret storage:
|
||||
* - is enabled on this account
|
||||
* - is storing cross-signing private keys
|
||||
* - is storing session backup key (if enabled)
|
||||
*
|
||||
* If this function returns false, bootstrapSecretStorage() can be used
|
||||
* to fix things such that it returns true. That is to say, after
|
||||
* bootstrapSecretStorage() completes successfully, this function should
|
||||
* return true.
|
||||
*
|
||||
* The secret storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @return {bool} True if secret storage is ready to be used on this device
|
||||
*/
|
||||
Crypto.prototype.isSecretStorageReady = async function() {
|
||||
const secretStorageKeyInAccount = await this._secretStorage.hasKey();
|
||||
const privateKeysInStorage = await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
);
|
||||
const sessionBackupInStorage = (
|
||||
!this._baseApis.getKeyBackupEnabled() ||
|
||||
this._baseApis.isKeyBackupKeyStored()
|
||||
);
|
||||
|
||||
return (
|
||||
secretStorageKeyInAccount &&
|
||||
privateKeysInStorage &&
|
||||
sessionBackupInStorage
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Bootstrap cross-signing by creating keys if needed. If everything is already
|
||||
* set up, then no changes are made, so this is safe to run to ensure
|
||||
* cross-signing is ready for use.
|
||||
*
|
||||
* This function:
|
||||
* - creates new cross-signing keys if they are not found locally cached nor in
|
||||
* secret storage (if it has been setup)
|
||||
*
|
||||
* @param {function} opts.authUploadDeviceSigningKeys Function
|
||||
* called to await an interactive auth flow when uploading device signing keys.
|
||||
* @param {bool} [opts.setupNewCrossSigning] Optional. Reset even if keys
|
||||
* already exist.
|
||||
* Args:
|
||||
* {function} A function that makes the request requiring auth. Receives the
|
||||
* auth data as an object. Can be called multiple times, first with an empty
|
||||
* authDict, to obtain the flows.
|
||||
*/
|
||||
Crypto.prototype.bootstrapCrossSigning = async function({
|
||||
authUploadDeviceSigningKeys,
|
||||
setupNewCrossSigning,
|
||||
} = {}) {
|
||||
logger.log("Bootstrapping cross-signing");
|
||||
|
||||
const delegateCryptoCallbacks = this._baseApis._cryptoCallbacks;
|
||||
const builder = new EncryptionSetupBuilder(
|
||||
this._baseApis.store.accountData,
|
||||
delegateCryptoCallbacks,
|
||||
);
|
||||
|
||||
const crossSigningInfo = new CrossSigningInfo(
|
||||
this._userId,
|
||||
builder.crossSigningCallbacks,
|
||||
builder.crossSigningCallbacks);
|
||||
|
||||
// Reset the cross-signing keys
|
||||
const resetCrossSigning = async () => {
|
||||
crossSigningInfo.resetKeys();
|
||||
// Sign master key with device key
|
||||
await this._signObject(crossSigningInfo.keys.master);
|
||||
|
||||
// Store auth flow helper function, as we need to call it when uploading
|
||||
// to ensure we handle auth errors properly.
|
||||
builder.addCrossSigningKeys(authUploadDeviceSigningKeys, crossSigningInfo.keys);
|
||||
|
||||
// Cross-sign own device
|
||||
const device = this._deviceList.getStoredDevice(this._userId, this._deviceId);
|
||||
const deviceSignature = await crossSigningInfo.signDevice(this._userId, device);
|
||||
builder.addKeySignature(this._userId, this._deviceId, deviceSignature);
|
||||
|
||||
// Sign message key backup with cross-signing master key
|
||||
if (this.backupInfo) {
|
||||
await crossSigningInfo.signObject(this.backupInfo.auth_data, "master");
|
||||
builder.addSessionBackup(this.backupInfo);
|
||||
}
|
||||
};
|
||||
|
||||
const publicKeysOnDevice = this._crossSigningInfo.getId();
|
||||
const privateKeysInCache = await this._crossSigningInfo.isStoredInKeyCache();
|
||||
const privateKeysInStorage = await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
);
|
||||
const privateKeysExistSomewhere = (
|
||||
privateKeysInCache ||
|
||||
privateKeysInStorage
|
||||
);
|
||||
|
||||
if (publicKeysOnDevice && privateKeysInCache) {
|
||||
logger.log(
|
||||
"Cross-signing public keys trusted and private keys found locally",
|
||||
);
|
||||
} else if (!privateKeysExistSomewhere || setupNewCrossSigning) {
|
||||
logger.log(
|
||||
"Cross-signing private keys not found locally or in secret storage, " +
|
||||
"creating new keys",
|
||||
);
|
||||
await resetCrossSigning();
|
||||
} else if (privateKeysInStorage) {
|
||||
logger.log(
|
||||
"Cross-signing private keys not found locally, but they are available " +
|
||||
"in secret storage, reading storage and caching locally",
|
||||
);
|
||||
await this.checkOwnCrossSigningTrust();
|
||||
}
|
||||
|
||||
// Assuming no app-supplied callback, default to storing new private keys in
|
||||
// secret storage if it exists. If it does not, it is assumed this will be
|
||||
// done as part of setting up secret storage later.
|
||||
const crossSigningPrivateKeys = builder.crossSigningCallbacks.privateKeys;
|
||||
if (
|
||||
crossSigningPrivateKeys.size &&
|
||||
!this._baseApis._cryptoCallbacks.saveCrossSigningKeys
|
||||
) {
|
||||
const secretStorage = new SecretStorage(
|
||||
builder.accountDataClientAdapter,
|
||||
builder.ssssCryptoCallbacks);
|
||||
if (await secretStorage.hasKey()) {
|
||||
logger.log("Storing cross-signing private keys in secret storage");
|
||||
// This is writing to in-memory account data in
|
||||
// builder.accountDataClientAdapter so won't fail
|
||||
await CrossSigningInfo.storeInSecretStorage(
|
||||
crossSigningPrivateKeys,
|
||||
secretStorage,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const operation = builder.buildOperation();
|
||||
await operation.apply(this);
|
||||
// This persists private keys and public keys as trusted,
|
||||
// only do this if apply succeeded for now as retry isn't in place yet
|
||||
await builder.persist(this);
|
||||
|
||||
logger.log("Cross-signing ready");
|
||||
};
|
||||
|
||||
/**
|
||||
* Bootstrap Secure Secret Storage if needed by creating a default key. If everything is
|
||||
@@ -448,12 +594,6 @@ Crypto.prototype.isCrossSigningReady = async function() {
|
||||
* - migrates Secure Secret Storage to use the latest algorithm, if an outdated
|
||||
* algorithm is found
|
||||
*
|
||||
* @param {function} opts.authUploadDeviceSigningKeys Function
|
||||
* called to await an interactive auth flow when uploading device signing keys.
|
||||
* Args:
|
||||
* {function} A function that makes the request requiring auth. Receives the
|
||||
* auth data as an object. Can be called multiple times, first with an empty
|
||||
* authDict, to obtain the flows.
|
||||
* @param {function} [opts.createSecretStorageKey] Optional. Function
|
||||
* called to await a secret storage key creation flow.
|
||||
* Returns:
|
||||
@@ -473,9 +613,7 @@ Crypto.prototype.isCrossSigningReady = async function() {
|
||||
* {Promise} A promise which resolves to key creation data for
|
||||
* SecretStorage#addKey: an object with `passphrase` and/or `pubkey` fields.
|
||||
*/
|
||||
|
||||
Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
authUploadDeviceSigningKeys,
|
||||
createSecretStorageKey = async () => ({ }),
|
||||
keyBackupInfo,
|
||||
setupNewKeyBackup,
|
||||
@@ -491,10 +629,6 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
const secretStorage = new SecretStorage(
|
||||
builder.accountDataClientAdapter,
|
||||
builder.ssssCryptoCallbacks);
|
||||
const crossSigningInfo = new CrossSigningInfo(
|
||||
this._userId,
|
||||
builder.crossSigningCallbacks,
|
||||
builder.crossSigningCallbacks);
|
||||
|
||||
// the ID of the new SSSS key, if we create one
|
||||
let newKeyId = null;
|
||||
@@ -519,27 +653,6 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
return keyId;
|
||||
};
|
||||
|
||||
// reset the cross-signing keys
|
||||
const resetCrossSigning = async () => {
|
||||
crossSigningInfo.resetKeys();
|
||||
// sign master key with device key
|
||||
await this._signObject(crossSigningInfo.keys.master);
|
||||
|
||||
// Store auth flow helper function, as we need to call it when uploading
|
||||
// to ensure we handle auth errors properly.
|
||||
builder.addCrossSigningKeys(authUploadDeviceSigningKeys, crossSigningInfo.keys);
|
||||
|
||||
// cross-sign own device
|
||||
const device = this._deviceList.getStoredDevice(this._userId, this._deviceId);
|
||||
const deviceSignature = await crossSigningInfo.signDevice(this._userId, device);
|
||||
builder.addKeySignature(this._userId, this._deviceId, deviceSignature);
|
||||
|
||||
if (keyBackupInfo) {
|
||||
await crossSigningInfo.signObject(keyBackupInfo.auth_data, "master");
|
||||
builder.addSessionBackup(keyBackupInfo);
|
||||
}
|
||||
};
|
||||
|
||||
const ensureCanCheckPassphrase = async (keyId, keyInfo) => {
|
||||
if (!keyInfo.mac) {
|
||||
const key = await this._baseApis._cryptoCallbacks.getSecretStorageKey(
|
||||
@@ -561,46 +674,36 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
|
||||
const oldSSSSKey = await this.getSecretStorageKey();
|
||||
const [oldKeyId, oldKeyInfo] = oldSSSSKey || [null, null];
|
||||
const decryptionKeys =
|
||||
await this._crossSigningInfo.isStoredInSecretStorage(this._secretStorage);
|
||||
const inStorage = !setupNewSecretStorage && decryptionKeys;
|
||||
const storageExists = (
|
||||
!setupNewSecretStorage &&
|
||||
oldKeyInfo &&
|
||||
oldKeyInfo.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES
|
||||
);
|
||||
|
||||
if (!inStorage && !keyBackupInfo) {
|
||||
if (!storageExists && !keyBackupInfo) {
|
||||
// either we don't have anything, or we've been asked to restart
|
||||
// from scratch
|
||||
logger.log(
|
||||
"Cross-signing private keys not found in secret storage, " +
|
||||
"creating new keys",
|
||||
"Secret storage does not exist, creating new storage key",
|
||||
);
|
||||
|
||||
await resetCrossSigning();
|
||||
|
||||
if (
|
||||
setupNewSecretStorage ||
|
||||
!oldKeyInfo ||
|
||||
oldKeyInfo.algorithm !== SECRET_STORAGE_ALGORITHM_V1_AES
|
||||
) {
|
||||
// if we already have a usable default SSSS key and aren't resetting SSSS just use it.
|
||||
// otherwise, create a new one
|
||||
// Note: we leave the old SSSS key in place: there could be other secrets using it, in theory.
|
||||
// We could move them to the new key but a) that would mean we'd need to prompt for the old
|
||||
// passphrase, and b) it's not clear that would be the right thing to do anyway.
|
||||
const { keyInfo, privateKey } = await createSecretStorageKey();
|
||||
newKeyId = await createSSSS(keyInfo, privateKey);
|
||||
}
|
||||
} else if (!inStorage && keyBackupInfo) {
|
||||
// if we already have a usable default SSSS key and aren't resetting
|
||||
// SSSS just use it. otherwise, create a new one
|
||||
// Note: we leave the old SSSS key in place: there could be other
|
||||
// secrets using it, in theory. We could move them to the new key but a)
|
||||
// that would mean we'd need to prompt for the old passphrase, and b)
|
||||
// it's not clear that would be the right thing to do anyway.
|
||||
const { keyInfo, privateKey } = await createSecretStorageKey();
|
||||
newKeyId = await createSSSS(keyInfo, privateKey);
|
||||
} else if (!storageExists && keyBackupInfo) {
|
||||
// we have an existing backup, but no SSSS
|
||||
|
||||
logger.log("Secret storage default key not found, using key backup key");
|
||||
logger.log("Secret storage does not exist, using key backup key");
|
||||
|
||||
// if we have the backup key already cached, use it; otherwise use the
|
||||
// callback to prompt for the key
|
||||
const backupKey = await this.getSessionBackupPrivateKey() ||
|
||||
await getKeyBackupPassphrase();
|
||||
|
||||
// create new cross-signing keys
|
||||
await resetCrossSigning();
|
||||
|
||||
// create a new SSSS key and use the backup key as the new SSSS key
|
||||
const opts = {};
|
||||
|
||||
@@ -624,36 +727,16 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
);
|
||||
|
||||
// The backup is trusted because the user provided the private key.
|
||||
// Sign the backup with the cross signing key so the key backup can
|
||||
// Sign the backup with the cross-signing key so the key backup can
|
||||
// be trusted via cross-signing.
|
||||
logger.log("Adding cross signing signature to key backup");
|
||||
await crossSigningInfo.signObject(
|
||||
await this._crossSigningInfo.signObject(
|
||||
keyBackupInfo.auth_data, "master",
|
||||
);
|
||||
builder.addSessionBackup(keyBackupInfo);
|
||||
} else if (!this._crossSigningInfo.getId()) {
|
||||
// we have SSSS, but we don't know if the server's cross-signing
|
||||
// keys should be trusted
|
||||
logger.log("Cross-signing private keys found in secret storage");
|
||||
|
||||
// TODO: take this use case out of bootstrapping
|
||||
// fetch the private keys and set up our local copy of the keys for
|
||||
// use
|
||||
//
|
||||
// so if some other device resets the cross-signing keys,
|
||||
// we mark them as untrusted from _onDeviceListUserCrossSigningUpdated
|
||||
// you can either fix this by hitting the verify this session which (might?) call this method,
|
||||
// or the reset button in the settings
|
||||
await this.checkOwnCrossSigningTrust();
|
||||
|
||||
if (oldKeyInfo && oldKeyInfo.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES) {
|
||||
// make sure that the default key has the information needed to
|
||||
// check the passphrase
|
||||
await ensureCanCheckPassphrase(oldKeyId, oldKeyInfo);
|
||||
}
|
||||
} else {
|
||||
// we have SSSS and we cross-signing is already set up
|
||||
logger.log("Cross signing keys are present in secret storage");
|
||||
// 4S is already set up
|
||||
logger.log("Secret storage exists");
|
||||
|
||||
if (oldKeyInfo && oldKeyInfo.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES) {
|
||||
// make sure that the default key has the information needed to
|
||||
@@ -662,21 +745,26 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
}
|
||||
}
|
||||
|
||||
const crossSigningPrivateKeys = builder.crossSigningCallbacks.privateKeys;
|
||||
if (crossSigningPrivateKeys.size) {
|
||||
// If we have cross-signing private keys cached, store them in secret
|
||||
// storage if they are not there already.
|
||||
if (
|
||||
!this._baseApis._cryptoCallbacks.saveCrossSigningKeys &&
|
||||
await this.isCrossSigningReady() &&
|
||||
!await this._crossSigningInfo.isStoredInSecretStorage(secretStorage)
|
||||
) {
|
||||
logger.log("Storing cross-signing private keys in secret storage");
|
||||
// Assuming no app-supplied callback, default to storing in SSSS.
|
||||
if (!this._baseApis._cryptoCallbacks.saveCrossSigningKeys) {
|
||||
// this is writing to in-memory account data in builder.accountDataClientAdapter
|
||||
// so won't fail
|
||||
await CrossSigningInfo.storeInSecretStorage(
|
||||
crossSigningPrivateKeys,
|
||||
secretStorage,
|
||||
);
|
||||
}
|
||||
const crossSigningPrivateKeys =
|
||||
await this._crossSigningInfo.getCrossSigningKeysFromCache();
|
||||
// This is writing to in-memory account data in
|
||||
// builder.accountDataClientAdapter so won't fail
|
||||
await CrossSigningInfo.storeInSecretStorage(
|
||||
crossSigningPrivateKeys,
|
||||
secretStorage,
|
||||
);
|
||||
}
|
||||
|
||||
if (setupNewKeyBackup && !keyBackupInfo) {
|
||||
logger.log("Creating new message key backup version");
|
||||
const info = await this._baseApis.prepareKeyBackupVersion(
|
||||
null /* random key */,
|
||||
// don't write to secret storage, as it will write to this._secretStorage.
|
||||
@@ -694,11 +782,10 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
auth_data: info.auth_data,
|
||||
};
|
||||
// sign with cross-sign master key
|
||||
await crossSigningInfo.signObject(data.auth_data, "master");
|
||||
await this._crossSigningInfo.signObject(data.auth_data, "master");
|
||||
// sign with the device fingerprint
|
||||
await this._signObject(data.auth_data);
|
||||
|
||||
|
||||
builder.addSessionBackup(data);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user