Merge pull request #1128 from matrix-org/dbkr/keybackup_migrate
Add support for passthrough SSSS secrets
This commit is contained in:
@@ -231,6 +231,27 @@ export default class SecretStorage extends EventEmitter {
|
||||
await this._baseApis.setAccountData(name, {encrypted});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a secret defined to be the same as the given key.
|
||||
* No secret information will be stored, instead the secret will
|
||||
* be stored with a marker to say that the contents of the secret is
|
||||
* the value of the given key.
|
||||
* This is useful for migration from systems that predate SSSS such as
|
||||
* key backup.
|
||||
*
|
||||
* @param {string} name The name of the secret
|
||||
* @param {string} keyId The ID of the key whose value will be the
|
||||
* value of the secret
|
||||
* @returns {Promise} resolved when account data is saved
|
||||
*/
|
||||
storePassthrough(name, keyId) {
|
||||
return this._baseApis.setAccountData(name, {
|
||||
[keyId]: {
|
||||
passthrough: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a secret from storage.
|
||||
*
|
||||
@@ -276,8 +297,13 @@ export default class SecretStorage extends EventEmitter {
|
||||
// fetch private key from app
|
||||
[keyId, decryption] = await this._getSecretStorageKey(keys);
|
||||
|
||||
// decrypt secret
|
||||
const encInfo = secretContent.encrypted[keyId];
|
||||
|
||||
// We don't actually need the decryption object if it's a passthrough
|
||||
// since we just want to return the key itself.
|
||||
if (encInfo.passthrough) return decryption.get_private_key();
|
||||
|
||||
// decrypt secret
|
||||
switch (keys[keyId].algorithm) {
|
||||
case SECRET_STORAGE_ALGORITHM_V1:
|
||||
return decryption.decrypt(
|
||||
|
||||
+40
-6
@@ -336,6 +336,8 @@ Crypto.prototype.createRecoveryKeyFromPassphrase = async function(password) {
|
||||
* auth data as an object.
|
||||
* @param {function} [opts.createSecretStorageKey] Optional. Function
|
||||
* called to await a secret storage key creation flow.
|
||||
* @param {object} [opts.keyBackupInfo] The current key backup object. If passed,
|
||||
* the passphrase and recovery key from this backup will be used.
|
||||
* Returns:
|
||||
* {Promise} A promise which resolves to key creation data for
|
||||
* SecretStorage#addKey: an object with `passphrase` and/or `pubkey` fields.
|
||||
@@ -343,6 +345,7 @@ Crypto.prototype.createRecoveryKeyFromPassphrase = async function(password) {
|
||||
Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
authUploadDeviceSigningKeys,
|
||||
createSecretStorageKey = async () => { },
|
||||
keyBackupInfo,
|
||||
} = {}) {
|
||||
logger.log("Bootstrapping Secure Secret Storage");
|
||||
|
||||
@@ -383,18 +386,49 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
{ authUploadDeviceSigningKeys },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
logger.log("Cross signing keys are present in secret storage");
|
||||
}
|
||||
|
||||
// Check if Secure Secret Storage has a default key. If we don't have one, create
|
||||
// the default key (which will also be signed by the cross-signing master key).
|
||||
if (!this.hasSecretStorageKey()) {
|
||||
logger.log("Secret storage default key not found, creating new key");
|
||||
const keyOptions = await createSecretStorageKey();
|
||||
const newKeyId = await this.addSecretStorageKey(
|
||||
SECRET_STORAGE_ALGORITHM_V1,
|
||||
keyOptions,
|
||||
);
|
||||
let newKeyId;
|
||||
if (keyBackupInfo) {
|
||||
logger.log("Secret storage default key not found, using key backup key");
|
||||
const opts = {
|
||||
pubkey: keyBackupInfo.auth_data.public_key,
|
||||
};
|
||||
|
||||
if (
|
||||
keyBackupInfo.auth_data.private_key_salt &&
|
||||
keyBackupInfo.auth_data.private_key_iterations
|
||||
) {
|
||||
opts.passphrase = {
|
||||
algorithm: "m.pbkdf2",
|
||||
iterations: keyBackupInfo.auth_data.private_key_iterations,
|
||||
salt: keyBackupInfo.auth_data.private_key_salt,
|
||||
};
|
||||
}
|
||||
|
||||
newKeyId = await this.addSecretStorageKey(
|
||||
SECRET_STORAGE_ALGORITHM_V1, opts,
|
||||
);
|
||||
|
||||
// Add an entry for the backup key in SSSS as a 'passthrough' key
|
||||
// (ie. the secret is the key itself).
|
||||
this._secretStorage.storePassthrough('m.megolm_backup.v1', newKeyId);
|
||||
} else {
|
||||
logger.log("Secret storage default key not found, creating new key");
|
||||
const keyOptions = await createSecretStorageKey();
|
||||
newKeyId = await this.addSecretStorageKey(
|
||||
SECRET_STORAGE_ALGORITHM_V1,
|
||||
keyOptions,
|
||||
);
|
||||
}
|
||||
await this.setDefaultSecretStorageKeyId(newKeyId);
|
||||
} else {
|
||||
logger.log("Have secret storage key");
|
||||
}
|
||||
|
||||
// If cross-signing keys were reset, store them in Secure Secret Storage.
|
||||
|
||||
Reference in New Issue
Block a user