Commit ff6027d4872 for nodejs
commit ff6027d487279e16bc0e2fa7956e3e41fcd8013d
Author: Filip Skokan <panva.ip@gmail.com>
Date: Tue Sep 22 22:19:32 2026 +0200
crypto: reject duplicate unknown key usages
Check all JWK key_ops entries for duplicates before ignoring unknown
usage names.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66237
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js
index 34e09b8b6ed..537870f25e8 100644
--- a/lib/internal/crypto/util.js
+++ b/lib/internal/crypto/util.js
@@ -1220,15 +1220,16 @@ function validateKeyOps(keyOps, usagesSet) {
if (keyOps === undefined) return;
validateArray(keyOps, 'keyData.key_ops');
let keyOpsMask = 0;
+ const seen = new SafeSet();
for (let n = 0; n < keyOps.length; n++) {
const op = keyOps[n];
+ if (seen.has(op))
+ throw lazyDOMException('Duplicate key operation', 'DataError');
+ seen.add(op);
const opMask = kUsageMasks[op];
// Skipping unknown key ops
if (opMask === undefined)
continue;
- // Have we seen it already? if so, error
- if (keyOpsMask & opMask)
- throw lazyDOMException('Duplicate key operation', 'DataError');
keyOpsMask |= opMask;
// TODO(@jasnell): RFC7517 section 4.3 strong recommends validating
diff --git a/test/parallel/test-webcrypto-key-ops-duplicates.js b/test/parallel/test-webcrypto-key-ops-duplicates.js
new file mode 100644
index 00000000000..4a666a1caa4
--- /dev/null
+++ b/test/parallel/test-webcrypto-key-ops-duplicates.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const { subtle } = globalThis.crypto;
+
+(async () => {
+ const algorithm = { name: 'HMAC', hash: 'SHA-256' };
+ const jwk = { kty: 'oct', k: 'AAAAAAAAAAAAAAAAAAAAAA' };
+ await subtle.importKey('jwk', { ...jwk, key_ops: ['sign', 'future'] },
+ algorithm, false, ['sign']);
+ for (const key_ops of [['sign', 'sign'], ['sign', 'future', 'future']]) {
+ await assert.rejects(subtle.importKey('jwk', { ...jwk, key_ops },
+ algorithm, false, ['sign']),
+ { name: 'DataError' });
+ }
+})().then(common.mustCall());