You've already forked matrix-js-sdk
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:
@@ -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
|
||||||
// ==========================
|
// ==========================
|
||||||
|
|||||||
@@ -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
40
src/crypto/PkSigning.js
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user