diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /services/fxaccounts/tests/xpcshell/test_keys.js | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'services/fxaccounts/tests/xpcshell/test_keys.js')
-rw-r--r-- | services/fxaccounts/tests/xpcshell/test_keys.js | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/services/fxaccounts/tests/xpcshell/test_keys.js b/services/fxaccounts/tests/xpcshell/test_keys.js new file mode 100644 index 0000000000..f984ba5deb --- /dev/null +++ b/services/fxaccounts/tests/xpcshell/test_keys.js @@ -0,0 +1,252 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { FX_OAUTH_CLIENT_ID } = ChromeUtils.import( + "resource://gre/modules/FxAccountsCommon.js" +); +const { FxAccountsKeys } = ChromeUtils.import( + "resource://gre/modules/FxAccountsKeys.jsm" +); + +// Ref https://github.com/mozilla/fxa-crypto-relier/ for the details +// of these test vectors. + +add_task(async function test_derive_scoped_key_test_vector() { + const keys = new FxAccountsKeys(null); + const uid = "aeaa1725c7a24ff983c6295725d5fc9b"; + const kB = "8b2e1303e21eee06a945683b8d495b9bf079ca30baa37eb8392d9ffa4767be45"; + const scopedKeyMetadata = { + identifier: "app_key:https%3A//example.com", + keyRotationTimestamp: 1510726317000, + keyRotationSecret: + "517d478cb4f994aa69930416648a416fdaa1762c5abf401a2acf11a0f185e98d", + }; + + const scopedKey = await keys._deriveScopedKey( + uid, + CommonUtils.hexToBytes(kB), + "app_key", + scopedKeyMetadata + ); + + Assert.deepEqual(scopedKey, { + kty: "oct", + kid: "1510726317-Voc-Eb9IpoTINuo9ll7bjA", + k: "Kkbk1_Q0oCcTmggeDH6880bQrxin2RLu5D00NcJazdQ", + }); +}); + +add_task(async function test_derive_legacy_sync_key_test_vector() { + const keys = new FxAccountsKeys(null); + const uid = "aeaa1725c7a24ff983c6295725d5fc9b"; + const kB = "eaf9570b7219a4187d3d6bf3cec2770c2e0719b7cc0dfbb38243d6f1881675e9"; + const scopedKeyMetadata = { + identifier: "https://identity.mozilla.com/apps/oldsync", + keyRotationTimestamp: 1510726317123, + keyRotationSecret: + "0000000000000000000000000000000000000000000000000000000000000000", + }; + + const scopedKey = await keys._deriveLegacyScopedKey( + uid, + CommonUtils.hexToBytes(kB), + "https://identity.mozilla.com/apps/oldsync", + scopedKeyMetadata + ); + + Assert.deepEqual(scopedKey, { + kty: "oct", + kid: "1510726317123-IqQv4onc7VcVE1kTQkyyOw", + k: + "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang", + }); +}); + +add_task(async function test_derive_multiple_keys_at_once() { + const keys = new FxAccountsKeys(null); + const uid = "aeaa1725c7a24ff983c6295725d5fc9b"; + const kB = "eaf9570b7219a4187d3d6bf3cec2770c2e0719b7cc0dfbb38243d6f1881675e9"; + const scopedKeysMetadata = { + app_key: { + identifier: "app_key:https%3A//example.com", + keyRotationTimestamp: 1510726317000, + keyRotationSecret: + "517d478cb4f994aa69930416648a416fdaa1762c5abf401a2acf11a0f185e98d", + }, + "https://identity.mozilla.com/apps/oldsync": { + identifier: "https://identity.mozilla.com/apps/oldsync", + keyRotationTimestamp: 1510726318123, + keyRotationSecret: + "0000000000000000000000000000000000000000000000000000000000000000", + }, + }; + + const scopedKeys = await keys._deriveScopedKeys( + uid, + CommonUtils.hexToBytes(kB), + scopedKeysMetadata + ); + + Assert.deepEqual(scopedKeys, { + app_key: { + kty: "oct", + kid: "1510726317-tUkxiR1lTlFrTgkF0tJidA", + k: "TYK6Hmj86PfKiqsk9DZmX61nxk9VsExGrwo94HP-0wU", + }, + "https://identity.mozilla.com/apps/oldsync": { + kty: "oct", + kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw", + k: + "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang", + }, + }); +}); + +add_task(async function test_rejects_bad_scoped_key_data() { + const keys = new FxAccountsKeys(null); + const uid = "aeaa1725c7a24ff983c6295725d5fc9b"; + const kB = "8b2e1303e21eee06a945683b8d495b9bf079ca30baa37eb8392d9ffa4767be45"; + const scopedKeyMetadata = { + identifier: "app_key:https%3A//example.com", + keyRotationTimestamp: 1510726317000, + keyRotationSecret: + "517d478cb4f994aa69930416648a416fdaa1762c5abf401a2acf11a0f185e98d", + }; + + await Assert.rejects( + keys._deriveScopedKey( + uid.slice(0, -1), + CommonUtils.hexToBytes(kB), + "app_key", + scopedKeyMetadata + ), + /uid must be a 32-character hex string/ + ); + await Assert.rejects( + keys._deriveScopedKey( + uid.slice(0, -1) + "Q", + CommonUtils.hexToBytes(kB), + "app_key", + scopedKeyMetadata + ), + /uid must be a 32-character hex string/ + ); + await Assert.rejects( + keys._deriveScopedKey( + uid, + CommonUtils.hexToBytes(kB).slice(0, -1), + "app_key", + scopedKeyMetadata + ), + /kBbytes must be exactly 32 bytes/ + ); + await Assert.rejects( + keys._deriveScopedKey(uid, CommonUtils.hexToBytes(kB), "app_key", { + ...scopedKeyMetadata, + identifier: "foo", + }), + /identifier must be a string of length >= 10/ + ); + await Assert.rejects( + keys._deriveScopedKey(uid, CommonUtils.hexToBytes(kB), "app_key", { + ...scopedKeyMetadata, + identifier: {}, + }), + /identifier must be a string of length >= 10/ + ); + await Assert.rejects( + keys._deriveScopedKey(uid, CommonUtils.hexToBytes(kB), "app_key", { + ...scopedKeyMetadata, + keyRotationTimestamp: "xyz", + }), + /keyRotationTimestamp must be a number/ + ); + await Assert.rejects( + keys._deriveScopedKey(uid, CommonUtils.hexToBytes(kB), "app_key", { + ...scopedKeyMetadata, + keyRotationTimestamp: 12345, + }), + /keyRotationTimestamp must round to a 10-digit number/ + ); + await Assert.rejects( + keys._deriveScopedKey(uid, CommonUtils.hexToBytes(kB), "app_key", { + ...scopedKeyMetadata, + keyRotationSecret: scopedKeyMetadata.keyRotationSecret.slice(0, -1), + }), + /keyRotationSecret must be a 64-character hex string/ + ); + await Assert.rejects( + keys._deriveScopedKey(uid, CommonUtils.hexToBytes(kB), "app_key", { + ...scopedKeyMetadata, + keyRotationSecret: scopedKeyMetadata.keyRotationSecret.slice(0, -1) + "z", + }), + /keyRotationSecret must be a 64-character hex string/ + ); +}); + +add_task( + async function test_graceful_handling_of_missing_ecosystem_telemetry_scope() { + const mockClient = { + getScopedKeyData: sinon + .mock() + .once() + .withExactArgs( + "session-token", + FX_OAUTH_CLIENT_ID, + SCOPE_OLD_SYNC + " " + SCOPE_ECOSYSTEM_TELEMETRY + ) + .returns( + Promise.resolve({ + // N.B. no SCOPE_ECOSYSTEM_TELEMETRY entry. + [SCOPE_OLD_SYNC]: { + identifier: SCOPE_OLD_SYNC, + keyRotationTimestamp: 1234567890000, + keyRotationSecret: + "0000000000000000000000000000000000000000000000000000000000000000", + }, + }) + ), + accountKeys: sinon + .mock() + .once() + .withExactArgs("key-fetch-token") + .returns({ + wrapKB: "00000000000000000000000000000000", + }), + }; + const mockState = { + getUserAccountData: async () => { + return { + uid: "aeaa1725c7a24ff983c6295725d5fc9b", + sessionToken: "session-token", + keyFetchToken: "key-fetch-token", + unwrapBKey: + "1111111111111111111111111111111111111111111111111111111111111111", + }; + }, + updateUserAccountData: sinon.spy(async data => { + return data; + }), + }; + + const keys = new FxAccountsKeys({ fxAccountsClient: mockClient }); + await keys._fetchAndUnwrapAndDeriveKeys( + mockState, + "session-token", + "key-fetch-token" + ); + + Assert.ok(mockState.updateUserAccountData.calledOnce); + const userData = mockState.updateUserAccountData.firstCall.args[0]; + + Assert.ok(userData.kSync); + Assert.ok(userData.scopedKeys[SCOPE_OLD_SYNC]); + Assert.equal(userData.ecosystemUserId, null); + Assert.equal(userData.scopedKeys[SCOPE_ECOSYSTEM_TELEMETRY], null); + + mockClient.getScopedKeyData.verify(); + mockClient.accountKeys.verify(); + } +); |