1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-12-10 07:22:27 +03:00

Add cross signing key creation into key backup

Start of cross-signing impl
This commit is contained in:
David Baker
2019-01-30 18:10:40 +00:00
parent 5e3ff7fc27
commit 2b54f442d1
3 changed files with 107 additions and 5 deletions

View File

@@ -1685,6 +1685,12 @@ MatrixBaseApis.prototype.getKeyChanges = function(oldToken, newToken) {
); );
}; };
MatrixBaseApis.prototype.uploadDeviceSigningKeys = function(keys) {
return this._http.authedRequestWithPrefix(
undefined, "POST", "/keys/device_signing/upload", undefined, keys,
httpApi.PREFIX_UNSTABLE,
);
};
// Identity Server Operations // Identity Server Operations
// ========================== // ==========================

View File

@@ -51,6 +51,7 @@ import { isCryptoAvailable } from './crypto';
import { encodeRecoveryKey, decodeRecoveryKey } from './crypto/recoverykey'; import { encodeRecoveryKey, decodeRecoveryKey } from './crypto/recoverykey';
import { keyForNewBackup, keyForExistingBackup } from './crypto/backup_password'; import { keyForNewBackup, keyForExistingBackup } from './crypto/backup_password';
import { randomString } from './randomstring'; import { randomString } from './randomstring';
import { pkSign } from './crypto/PkSigning';
// Disable warnings for now: we use deprecated bluebird functions // Disable warnings for now: we use deprecated bluebird functions
// and need to migrate, but they spam the console with warnings. // and need to migrate, but they spam the console with warnings.
@@ -955,8 +956,14 @@ MatrixClient.prototype.prepareKeyBackupVersion = async function(password) {
throw new Error("End-to-end encryption disabled"); throw new Error("End-to-end encryption disabled");
} }
const decryption = new global.Olm.PkDecryption(); let decryption, encryption, signing;
try { try {
decryption = new global.Olm.PkDecryption();
encryption = new global.Olm.PkEncryption();
if (global.Olm.PkSigning) {
signing = new global.Olm.PkSigning();
}
let publicKey; let publicKey;
const authData = {}; const authData = {};
if (password) { if (password) {
@@ -969,14 +976,37 @@ MatrixClient.prototype.prepareKeyBackupVersion = async function(password) {
} }
authData.public_key = publicKey; authData.public_key = publicKey;
encryption.set_recipient_key(publicKey);
return { const returnInfo = {
algorithm: olmlib.MEGOLM_BACKUP_ALGORITHM, algorithm: olmlib.MEGOLM_BACKUP_ALGORITHM,
auth_data: authData, auth_data: authData,
recovery_key: encodeRecoveryKey(decryption.get_private_key()), recovery_key: encodeRecoveryKey(decryption.get_private_key()),
}; };
if (signing) {
const ssk_seed = signing.generate_seed();
// put the encrypted version of the seed in the auth data to upload
// XXX: our encryption really should support encrypting binary data.
authData.self_signing_key = encryption.encrypt(Buffer.from(ssk_seed).toString('base64'));
// and the unencrypted one in the returndata so we can use it later
returnInfo.ssk_seed = ssk_seed
// also keep the public part there
returnInfo.ssk_public = signing.init_with_seed(ssk_seed);
signing.free();
const usk_seed = signing.generate_seed();
authData.user_signing_key = encryption.encrypt(Buffer.from(usk_seed).toString('base64'));
returnInfo.usk_seed = usk_seed;
returnInfo.usk_public = signing.init_with_seed(usk_seed);
signing.free();
}
return returnInfo;
} finally { } finally {
decryption.free(); if (decryption) decryption.free();
if (encryption) encryption.free();
if (signing) signing.free();
} }
}; };
@@ -987,7 +1017,7 @@ MatrixClient.prototype.prepareKeyBackupVersion = async function(password) {
* @param {object} info Info object from prepareKeyBackupVersion * @param {object} info Info object from prepareKeyBackupVersion
* @returns {Promise<object>} Object with 'version' param indicating the version created * @returns {Promise<object>} Object with 'version' param indicating the version created
*/ */
MatrixClient.prototype.createKeyBackupVersion = function(info) { MatrixClient.prototype.createKeyBackupVersion = function(info, auth, replacesSsk) {
if (this._crypto === null) { if (this._crypto === null) {
throw new Error("End-to-end encryption disabled"); throw new Error("End-to-end encryption disabled");
} }
@@ -996,7 +1026,33 @@ MatrixClient.prototype.createKeyBackupVersion = function(info) {
algorithm: info.algorithm, algorithm: info.algorithm,
auth_data: info.auth_data, auth_data: info.auth_data,
}; };
return this._crypto._signObject(data.auth_data).then(() => {
const uskInfo = {
user_id: this.credentials.userId,
usage: ['user_signing'],
keys: {
['ed25519:' + info.usk_public]: info.usk_public,
},
};
pkSign(uskInfo, info.ssk_seed, this.credentials.userId);
const keys = {
self_signing_key: {
user_id: this.credentials.userId,
usage: ['self_signing'],
keys: {
['ed25519:' + info.ssk_public]: info.ssk_public,
},
replaces: replacesSsk,
},
user_signing_key: uskInfo,
auth,
};
return this.uploadDeviceSigningKeys(keys).then(() => {
return this._crypto._signObject(data.auth_data);
}).then(() => {
return this._http.authedRequest( return this._http.authedRequest(
undefined, "POST", "/room_keys/version", undefined, data, undefined, "POST", "/room_keys/version", undefined, data,
); );

40
src/crypto/PkSigning.js Normal file
View File

@@ -0,0 +1,40 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const anotherjson = require('another-json');
/**
* Higher level wrapper around olm.PkSigning that signs JSON objects
*/
export function pkSign(obj, seed, userId) {
const signing = new global.Olm.PkSigning();
try {
const pubkey = signing.init_with_seed(seed);
const sigs = obj.signatures || {};
const mysigs = sigs[userId] || {};
sigs[userId] = mysigs;
delete obj.signatures;
const unsigned = obj.unsigned;
if (obj.unsigned) delete obj.unsigned;
mysigs['ed25519:' + pubkey] = signing.sign(anotherjson.stringify(obj));
obj.signatures = sigs;
if (unsigned) obj.unsigned = unsigned;
} finally {
signing.free();
}
}