You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-26 17:03:12 +03:00
Get cross-signing private keys from secret storage
If you've already set up cross-signing elsewhere and start using a new device, this loads the private keys from secret storage and regenerates the public keys to match. We may also want to download the public keys from the homeserver's key sharing and verify that they match the private keys, but for now that's left as future work.
This commit is contained in:
@@ -105,6 +105,20 @@ export class CrossSigningInfo extends EventEmitter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the private keys exist in secret storage.
|
||||||
|
*
|
||||||
|
* @param {SecretStorage} secretStorage The secret store using account data
|
||||||
|
* @returns {boolean} Whether all private keys were found in storage
|
||||||
|
*/
|
||||||
|
isStoredInSecretStorage(secretStorage) {
|
||||||
|
let stored = true;
|
||||||
|
for (const name of ["master", "self_signing", "user_signing"]) {
|
||||||
|
stored &= secretStorage.isStored(`m.cross_signing.${name}`, false);
|
||||||
|
}
|
||||||
|
return stored;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store private keys in secret storage for use by other devices. This is
|
* Store private keys in secret storage for use by other devices. This is
|
||||||
* typically called in conjunction with the creation of new cross-signing
|
* typically called in conjunction with the creation of new cross-signing
|
||||||
@@ -119,6 +133,58 @@ export class CrossSigningInfo extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get private keys from secret storage created by some other device. This
|
||||||
|
* also passes the private keys to the app-specific callback.
|
||||||
|
*
|
||||||
|
* @param {SecretStorage} secretStorage The secret store using account data
|
||||||
|
*/
|
||||||
|
getFromSecretStorage(secretStorage) {
|
||||||
|
if (!this._callbacks.saveCrossSigningKeys) {
|
||||||
|
throw new Error("No saveCrossSigningKeys callback supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve private keys from secret storage
|
||||||
|
const privateKeys = {};
|
||||||
|
for (const name of ["master", "self_signing", "user_signing"]) {
|
||||||
|
privateKeys[name] = secretStorage.get(`m.cross_signing.${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regenerate public keys from private keys
|
||||||
|
// XXX: Do we want to _also_ download public keys from the homeserver to
|
||||||
|
// verify they agree...?
|
||||||
|
const signings = {};
|
||||||
|
const publicKeys = {};
|
||||||
|
const keys = {};
|
||||||
|
try {
|
||||||
|
for (const name of ["master", "self_signing", "user_signing"]) {
|
||||||
|
signings[name] = new global.Olm.PkSigning();
|
||||||
|
publicKeys[name] = signings[name].init_with_seed(privateKeys[name]);
|
||||||
|
keys[name] = {
|
||||||
|
user_id: this.userId,
|
||||||
|
usage: [name],
|
||||||
|
keys: {
|
||||||
|
['ed25519:' + publicKeys[name]]: publicKeys[name],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (name !== "master") {
|
||||||
|
pkSign(
|
||||||
|
keys[name], signings["master"],
|
||||||
|
this.userId, publicKeys["master"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
for (const signing of signings) {
|
||||||
|
signing.free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save public keys locally and private keys via app callback
|
||||||
|
Object.assign(this.keys, keys);
|
||||||
|
this._callbacks.saveCrossSigningKeys(privateKeys);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ID used to identify the user. This can also be used to test for
|
* Get the ID used to identify the user. This can also be used to test for
|
||||||
* the existence of a given key type.
|
* the existence of a given key type.
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ Crypto.prototype.init = async function() {
|
|||||||
(txn) => {
|
(txn) => {
|
||||||
this._cryptoStore.getCrossSigningKeys(txn, (keys) => {
|
this._cryptoStore.getCrossSigningKeys(txn, (keys) => {
|
||||||
if (keys) {
|
if (keys) {
|
||||||
|
logger.log("Loaded cross-signing public keys from crypto store");
|
||||||
this._crossSigningInfo.setKeys(keys);
|
this._crossSigningInfo.setKeys(keys);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -304,13 +305,25 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
|||||||
// effectively need it for both reading and writing secrets.
|
// effectively need it for both reading and writing secrets.
|
||||||
let crossSigningKeysChanged = false;
|
let crossSigningKeysChanged = false;
|
||||||
if (!this._crossSigningInfo.getId()) {
|
if (!this._crossSigningInfo.getId()) {
|
||||||
logger.log("Cross-signing keys not found, creating new keys");
|
logger.log(
|
||||||
|
"Cross-signing public keys not found on device, " +
|
||||||
|
"checking secret storage for private keys",
|
||||||
|
);
|
||||||
|
if (this._crossSigningInfo.isStoredInSecretStorage(this._secretStorage)) {
|
||||||
|
logger.log("Cross-signing private keys found in secret storage");
|
||||||
|
this._crossSigningInfo.getFromSecretStorage(this._secretStorage);
|
||||||
|
} else {
|
||||||
|
logger.log(
|
||||||
|
"Cross-signing private keys not found in secret storage, " +
|
||||||
|
"creating new keys",
|
||||||
|
);
|
||||||
await this.resetCrossSigningKeys(
|
await this.resetCrossSigningKeys(
|
||||||
CrossSigningLevel.MASTER,
|
CrossSigningLevel.MASTER,
|
||||||
{ doInteractiveAuthFlow },
|
{ doInteractiveAuthFlow },
|
||||||
);
|
);
|
||||||
crossSigningKeysChanged = true;
|
crossSigningKeysChanged = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if Secure Secret Storage has a default key. If we don't have one, create the
|
// 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).
|
// default key (which will also be signed by the cross-signing master key).
|
||||||
@@ -324,7 +337,7 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
|||||||
|
|
||||||
// If cross-signing keys changed, store them in Secure Secret Storage.
|
// If cross-signing keys changed, store them in Secure Secret Storage.
|
||||||
if (crossSigningKeysChanged) {
|
if (crossSigningKeysChanged) {
|
||||||
logger.log("Storing cross-signing keys in secret storage");
|
logger.log("Storing cross-signing private keys in secret storage");
|
||||||
// XXX: We need to think about how to re-do this step if it fails.
|
// XXX: We need to think about how to re-do this step if it fails.
|
||||||
await this._crossSigningInfo.storeInSecretStorage(this._secretStorage);
|
await this._crossSigningInfo.storeInSecretStorage(this._secretStorage);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user