You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-29 16:43:09 +03:00
verify cross-signing key with SAS
This commit is contained in:
@@ -22,6 +22,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
import expect from 'expect';
|
import expect from 'expect';
|
||||||
|
import olmlib from '../../../../lib/crypto/olmlib';
|
||||||
|
|
||||||
import sdk from '../../../..';
|
import sdk from '../../../..';
|
||||||
|
|
||||||
@@ -78,38 +79,35 @@ describe("SAS verification", function() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
alice.setDeviceVerified = expect.createSpy();
|
const aliceDevice = alice._crypto._olmDevice;
|
||||||
alice.getDeviceEd25519Key = () => {
|
const bobDevice = bob._crypto._olmDevice;
|
||||||
return "alice+base64+ed25519+key";
|
|
||||||
};
|
alice._crypto._deviceList.storeDevicesForUser("@bob:example.com", {
|
||||||
alice.getStoredDevice = () => {
|
Dynabook: {
|
||||||
return DeviceInfo.fromStorage(
|
user_id: "@bob:example.com",
|
||||||
{
|
device_id: "Dynabook",
|
||||||
|
algorithms: [olmlib.OLM_ALGORITHM, olmlib.MEGOLM_ALGORITHM],
|
||||||
keys: {
|
keys: {
|
||||||
"ed25519:Dynabook": "bob+base64+ed25519+key",
|
"ed25519:Dynabook": bobDevice.deviceEd25519Key,
|
||||||
|
"curve25519:Dynabook": bobDevice.deviceCurve25519Key,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Dynabook",
|
});
|
||||||
);
|
|
||||||
};
|
|
||||||
alice.downloadKeys = () => {
|
alice.downloadKeys = () => {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
bob.setDeviceVerified = expect.createSpy();
|
bob._crypto._deviceList.storeDevicesForUser("@alice:example.com", {
|
||||||
bob.getStoredDevice = () => {
|
Osborne2: {
|
||||||
return DeviceInfo.fromStorage(
|
user_id: "@alice:example.com",
|
||||||
{
|
device_id: "Osborne2",
|
||||||
|
algorithms: [olmlib.OLM_ALGORITHM, olmlib.MEGOLM_ALGORITHM],
|
||||||
keys: {
|
keys: {
|
||||||
"ed25519:Osborne2": "alice+base64+ed25519+key",
|
"ed25519:Osborne2": aliceDevice.deviceEd25519Key,
|
||||||
|
"curve25519:Osborne2": aliceDevice.deviceCurve25519Key,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Osborne2",
|
});
|
||||||
);
|
|
||||||
};
|
|
||||||
bob.getDeviceEd25519Key = () => {
|
|
||||||
return "bob+base64+ed25519+key";
|
|
||||||
};
|
|
||||||
bob.downloadKeys = () => {
|
bob.downloadKeys = () => {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
@@ -180,10 +178,12 @@ describe("SAS verification", function() {
|
|||||||
expect(macMethod).toBe("hkdf-hmac-sha256");
|
expect(macMethod).toBe("hkdf-hmac-sha256");
|
||||||
|
|
||||||
// make sure Alice and Bob verified each other
|
// make sure Alice and Bob verified each other
|
||||||
expect(alice.setDeviceVerified)
|
const bobDevice
|
||||||
.toHaveBeenCalledWith(bob.getUserId(), bob.deviceId);
|
= await alice.getStoredDevice("@bob:example.com", "Dynabook");
|
||||||
expect(bob.setDeviceVerified)
|
expect(bobDevice.isVerified()).toBeTruthy();
|
||||||
.toHaveBeenCalledWith(alice.getUserId(), alice.deviceId);
|
const aliceDevice
|
||||||
|
= await bob.getStoredDevice("@alice:example.com", "Osborne2");
|
||||||
|
expect(aliceDevice.isVerified()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to verify using the old MAC", async function() {
|
it("should be able to verify using the old MAC", async function() {
|
||||||
@@ -218,10 +218,40 @@ describe("SAS verification", function() {
|
|||||||
|
|
||||||
expect(macMethod).toBe("hmac-sha256");
|
expect(macMethod).toBe("hmac-sha256");
|
||||||
|
|
||||||
expect(alice.setDeviceVerified)
|
const bobDevice
|
||||||
.toHaveBeenCalledWith(bob.getUserId(), bob.deviceId);
|
= await alice.getStoredDevice("@bob:example.com", "Dynabook");
|
||||||
expect(bob.setDeviceVerified)
|
expect(bobDevice.isVerified()).toBeTruthy();
|
||||||
.toHaveBeenCalledWith(alice.getUserId(), alice.deviceId);
|
const aliceDevice
|
||||||
|
= await bob.getStoredDevice("@alice:example.com", "Osborne2");
|
||||||
|
expect(aliceDevice.isVerified()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should verify a cross-signing key", async function() {
|
||||||
|
const privateKeys = {};
|
||||||
|
alice.on("cross-signing:savePrivateKeys", function(e) {
|
||||||
|
privateKeys.alice = e;
|
||||||
|
});
|
||||||
|
await alice.resetCrossSigningKeys();
|
||||||
|
bob.on("cross-signing:savePrivateKeys", function(e) {
|
||||||
|
privateKeys.bob = e;
|
||||||
|
});
|
||||||
|
await bob.resetCrossSigningKeys();
|
||||||
|
|
||||||
|
bob.on("cross-signing:getKey", function(e) {
|
||||||
|
e.done(privateKeys.bob[e.type]);
|
||||||
|
});
|
||||||
|
|
||||||
|
bob._crypto._deviceList.storeCrossSigningForUser("@alice:example.com", {
|
||||||
|
keys: alice._crypto._crossSigningInfo.keys,
|
||||||
|
});
|
||||||
|
await Promise.all([
|
||||||
|
aliceVerifier.verify(),
|
||||||
|
bobPromise.then((verifier) => verifier.verify()),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(alice.checkDeviceTrust("@bob:example.com", "Dynabook")).toBe(1);
|
||||||
|
expect(bob.checkUserTrust("@alice:example.com")).toBe(6);
|
||||||
|
expect(bob.checkDeviceTrust("@alice:example.com", "Osborne2")).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -854,6 +854,9 @@ MatrixClient.prototype.resetCrossSigningKeys
|
|||||||
MatrixClient.prototype.setCrossSigningKeys
|
MatrixClient.prototype.setCrossSigningKeys
|
||||||
= wrapCryptoFunc("setCrossSigningKeys");
|
= wrapCryptoFunc("setCrossSigningKeys");
|
||||||
|
|
||||||
|
MatrixClient.prototype.getCrossSigningId
|
||||||
|
= wrapCryptoFunc("getCrossSigningId");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel a room key request for this event if one is ongoing and resend the
|
* Cancel a room key request for this event if one is ongoing and resend the
|
||||||
* request.
|
* request.
|
||||||
|
|||||||
@@ -286,6 +286,18 @@ Crypto.prototype.setCrossSigningKeys = function(keys) {
|
|||||||
this._baseApis.emit("cross-signing:keysChanged", {});
|
this._baseApis.emit("cross-signing:keysChanged", {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user's cross-signing key ID.
|
||||||
|
*
|
||||||
|
* @param {string} type The type of key to get the ID of. One of "master",
|
||||||
|
* "self_signing", or "user_signing". Defaults to "master".
|
||||||
|
*
|
||||||
|
* @returns {string} the key ID
|
||||||
|
*/
|
||||||
|
Crypto.prototype.getCrossSigningId = function(type) {
|
||||||
|
return this._crossSigningInfo.getId(type);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a given user is trusted.
|
* Check whether a given user is trusted.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ limitations under the License.
|
|||||||
import {MatrixEvent} from '../../models/event';
|
import {MatrixEvent} from '../../models/event';
|
||||||
import {EventEmitter} from 'events';
|
import {EventEmitter} from 'events';
|
||||||
import logger from '../../logger';
|
import logger from '../../logger';
|
||||||
|
import DeviceInfo from '../deviceinfo';
|
||||||
|
|
||||||
export default class VerificationBase extends EventEmitter {
|
export default class VerificationBase extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
@@ -192,11 +193,24 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
for (const [keyId, keyInfo] of Object.entries(keys)) {
|
for (const [keyId, keyInfo] of Object.entries(keys)) {
|
||||||
const deviceId = keyId.split(':', 2)[1];
|
const deviceId = keyId.split(':', 2)[1];
|
||||||
const device = await this._baseApis.getStoredDevice(userId, deviceId);
|
const device = await this._baseApis.getStoredDevice(userId, deviceId);
|
||||||
if (!device) {
|
if (device) {
|
||||||
logger.warn(`verification: Could not find device ${deviceId} to verify`);
|
|
||||||
} else {
|
|
||||||
await verifier(keyId, device, keyInfo);
|
await verifier(keyId, device, keyInfo);
|
||||||
verifiedDevices.push(deviceId);
|
verifiedDevices.push(deviceId);
|
||||||
|
} else {
|
||||||
|
const crossSigningInfo = this._baseApis._crypto._deviceList
|
||||||
|
.getStoredCrossSigningForUser(userId);
|
||||||
|
if (crossSigningInfo && crossSigningInfo.getId() === deviceId) {
|
||||||
|
await verifier(keyId, DeviceInfo.fromStorage({
|
||||||
|
keys: {
|
||||||
|
[keyId]: deviceId,
|
||||||
|
},
|
||||||
|
}, deviceId), keyInfo);
|
||||||
|
verifiedDevices.push(deviceId);
|
||||||
|
} else {
|
||||||
|
logger.warn(
|
||||||
|
`verification: Could not find device ${deviceId} to verify`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -354,19 +354,32 @@ export default class SAS extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_sendMAC(olmSAS, method) {
|
_sendMAC(olmSAS, method) {
|
||||||
const keyId = `ed25519:${this._baseApis.deviceId}`;
|
|
||||||
const mac = {};
|
const mac = {};
|
||||||
|
const keyList = [];
|
||||||
const baseInfo = "MATRIX_KEY_VERIFICATION_MAC"
|
const baseInfo = "MATRIX_KEY_VERIFICATION_MAC"
|
||||||
+ this._baseApis.getUserId() + this._baseApis.deviceId
|
+ this._baseApis.getUserId() + this._baseApis.deviceId
|
||||||
+ this.userId + this.deviceId
|
+ this.userId + this.deviceId
|
||||||
+ this.transactionId;
|
+ this.transactionId;
|
||||||
|
|
||||||
mac[keyId] = olmSAS[macMethods[method]](
|
const deviceKeyId = `ed25519:${this._baseApis.deviceId}`;
|
||||||
|
mac[deviceKeyId] = olmSAS[macMethods[method]](
|
||||||
this._baseApis.getDeviceEd25519Key(),
|
this._baseApis.getDeviceEd25519Key(),
|
||||||
baseInfo + keyId,
|
baseInfo + deviceKeyId,
|
||||||
);
|
);
|
||||||
|
keyList.push(deviceKeyId);
|
||||||
|
|
||||||
|
const crossSigningId = this._baseApis.getCrossSigningId();
|
||||||
|
if (crossSigningId) {
|
||||||
|
const crossSigningKeyId = `ed25519:${crossSigningId}`;
|
||||||
|
mac[crossSigningKeyId] = olmSAS[macMethods[method]](
|
||||||
|
crossSigningId,
|
||||||
|
baseInfo + crossSigningKeyId,
|
||||||
|
);
|
||||||
|
keyList.push(crossSigningKeyId);
|
||||||
|
}
|
||||||
|
|
||||||
const keys = olmSAS[macMethods[method]](
|
const keys = olmSAS[macMethods[method]](
|
||||||
keyId,
|
keyList.sort().join(","),
|
||||||
baseInfo + "KEY_IDS",
|
baseInfo + "KEY_IDS",
|
||||||
);
|
);
|
||||||
this._sendToDevice("m.key.verification.mac", { mac, keys });
|
this._sendToDevice("m.key.verification.mac", { mac, keys });
|
||||||
|
|||||||
Reference in New Issue
Block a user