tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 27f4f8868129f4aa133d2c60abad61aa2ff4419c
parent 59a21d243c628cb8e64ff59647d994715b255e5d
Author: Anna Weine <anna.weine@mozilla.com>
Date:   Thu, 11 Dec 2025 10:37:29 +0000

Bug 1994770 - [WebCrypto] Get key length for X25519 key derivation r=nss-reviewers,jschanck

Differential Revision: https://phabricator.services.mozilla.com/D269202

Diffstat:
Mdom/crypto/WebCryptoTask.cpp | 12+++++++++++-
Mdom/crypto/test/test_WebCrypto_ECDH.html | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp @@ -2499,7 +2499,17 @@ class DeriveX25519BitsTask : public ReturnArrayBufferViewTask { DeriveX25519BitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm) : mPrivKey(aKey.GetPrivateKey()) { - Init(aCx, aAlgorithm, aKey); + Maybe<size_t> lengthInBits; + mEarlyRv = GetKeyLengthForAlgorithmIfSpecified(aCx, aTargetAlgorithm, + lengthInBits); + if (lengthInBits.isNothing()) { + mLength.SetNull(); + } else { + mLength.SetValue(*lengthInBits); + } + if (NS_SUCCEEDED(mEarlyRv)) { + Init(aCx, aAlgorithm, aKey); + } } void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey) { diff --git a/dom/crypto/test/test_WebCrypto_ECDH.html b/dom/crypto/test/test_WebCrypto_ECDH.html @@ -427,6 +427,81 @@ TestArray.addTest( ); // ----------------------------------------------------------------------------- +// See bug 1994770 +TestArray.addTest( + "Derive an AES Key from two X25519 keys", + function() { + var that = this; + const alg = { name: 'X25519' }; + const lengths = [128, 192, 256]; + + async function deriveKey(algorithm, privateKey, publicKey, length) { + return window.crypto.subtle.deriveKey( + { name: algorithm.name, public: publicKey }, + privateKey, + { name: 'AES-GCM', length }, + true, + ['encrypt', 'decrypt'], + ); + } + + async function doTest(length) { + let keyPair1 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]); + let keyPair2 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]); + let derivedKey = await deriveKey(alg, keyPair1.privateKey, keyPair2.publicKey, length); + const raw = await window.crypto.subtle.exportKey('raw', derivedKey); + const bitLength = raw.byteLength * 8; + return bitLength === length; + } + + Promise.all(lengths.map(doTest)) + .then(complete(that, function(results) { + return results.every(result => result === true); + })) + .catch(error(that)); + } +); + +// See bug 1994770 +TestArray.addTest( + "Derive an AES Key from two X25519 keys (invalid length)", + function() { + var that = this; + const alg = { name: "X25519" }; + // AES-GCM only accepts 128, 192, 256. + const invalidLengths = [0, 64, 129, 200]; + + async function deriveKey(algorithm, privateKey, publicKey, length) { + return window.crypto.subtle.deriveKey( + { name: algorithm.name, public: publicKey }, + privateKey, + { name: "AES-GCM", length }, + true, + ["encrypt", "decrypt"], + ); + } + + async function doTest(length) { + let keyPair1 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]); + let keyPair2 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]); + try { + await deriveKey(alg, keyPair1.privateKey, keyPair2.publicKey, length); + return false; + } catch (e) { + return true; + } + } + + Promise.all(invalidLengths.map(doTest)) + .then(complete(that, function(results) { + return results.every(result => result === true); + }), + ) + .catch(error(that)); + } +); + +// ----------------------------------------------------------------------------- TestArray.addTest( "SPKI import/export of public ECDH keys (P-256)", function() {