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:
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() {