diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js index 4ab482a4307..847017529dc 100644 --- a/lib/internal/crypto/webcrypto.js +++ b/lib/internal/crypto/webcrypto.js @@ -1772,6 +1772,22 @@ class SubtleCrypto { context: '2nd argument', }); + let length = null; + let additionalAlgorithm; + if (lengthOrAdditionalAlgorithm === null || + typeof lengthOrAdditionalAlgorithm === 'number') { + if (lengthOrAdditionalAlgorithm !== null) { + length = webidl.converters['unsigned long'](lengthOrAdditionalAlgorithm, { + prefix, + context: '3rd argument', + enforceRange: true, + }); + } + } else { + additionalAlgorithm = webidl.converters.AlgorithmIdentifier( + lengthOrAdditionalAlgorithm, { prefix, context: '3rd argument' }); + } + switch (operation) { case 'decapsulateBits': case 'decapsulateKey': @@ -1795,17 +1811,7 @@ class SubtleCrypto { return false; } - let length; - let additionalAlgorithm; - if (operation === 'deriveKey') { - additionalAlgorithm = webidl.converters.AlgorithmIdentifier( - lengthOrAdditionalAlgorithm, - { - prefix, - context: '3rd argument', - }, - ); - + if (additionalAlgorithm !== undefined && operation === 'deriveKey') { if (!check('importKey', additionalAlgorithm)) { return false; } @@ -1817,39 +1823,14 @@ class SubtleCrypto { } operation = 'deriveBits'; - } else if (operation === 'wrapKey') { - additionalAlgorithm = webidl.converters.AlgorithmIdentifier( - lengthOrAdditionalAlgorithm, - { - prefix, - context: '3rd argument', - }, - ); - + } else if (additionalAlgorithm !== undefined && operation === 'wrapKey') { if (!check('exportKey', additionalAlgorithm)) { return false; } - } else if (operation === 'unwrapKey') { - additionalAlgorithm = webidl.converters.AlgorithmIdentifier( - lengthOrAdditionalAlgorithm, - { - prefix, - context: '3rd argument', - }, - ); - + } else if (additionalAlgorithm !== undefined && operation === 'unwrapKey') { if (!check('importKey', additionalAlgorithm)) { return false; } - } else if (operation === 'deriveBits') { - length = lengthOrAdditionalAlgorithm; - if (length !== null) { - length = webidl.converters['unsigned long'](length, { - prefix, - context: '3rd argument', - enforceRange: true, - }); - } } else if (operation === 'getPublicKey') { let normalizedAlgorithm; try { @@ -1870,15 +1851,8 @@ class SubtleCrypto { default: return false; } - } else if (operation === 'encapsulateKey' || operation === 'decapsulateKey') { - additionalAlgorithm = webidl.converters.AlgorithmIdentifier( - lengthOrAdditionalAlgorithm, - { - prefix, - context: '3rd argument', - }, - ); - + } else if (additionalAlgorithm !== undefined && + (operation === 'encapsulateKey' || operation === 'decapsulateKey')) { let sharedKeyLength; let normalizedAdditionalAlgorithm; try { diff --git a/test/fixtures/webcrypto/supports-level-2.mjs b/test/fixtures/webcrypto/supports-level-2.mjs index dacaa907002..2e2014bb5f1 100644 --- a/test/fixtures/webcrypto/supports-level-2.mjs +++ b/test/fixtures/webcrypto/supports-level-2.mjs @@ -268,12 +268,12 @@ export const vectors = { [hasX25519, 'X25519'], ], 'wrapKey': [ - [false, 'AES-KW'], + [true, 'AES-KW'], [true, 'AES-KW', 'AES-CTR'], [true, 'AES-KW', 'HMAC'], ], 'unwrapKey': [ - [false, 'AES-KW'], + [true, 'AES-KW'], [true, 'AES-KW', 'AES-CTR'], ], 'unsupported operation': [ diff --git a/test/parallel/test-webcrypto-supports-overloads.js b/test/parallel/test-webcrypto-supports-overloads.js new file mode 100644 index 00000000000..d59bf24fa60 --- /dev/null +++ b/test/parallel/test-webcrypto-supports-overloads.js @@ -0,0 +1,36 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const { supports } = SubtleCrypto; + +for (const operation of ['wrapKey', 'unwrapKey']) { + for (const length of [undefined, null, 0, 128]) { + assert.strictEqual(supports(operation, 'AES-KW', length), true); + } + assert.strictEqual(supports(operation, 'AES-KW'), true); +} + +for (const operation of ['digest', 'unknown', 'wrapKey', 'deriveBits']) { + for (const value of [-1, NaN, Infinity, 2 ** 32, Symbol()]) { + assert.throws(() => supports(operation, 'SHA-256', value), TypeError); + } +} + +const hkdf = { + name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(), info: new Uint8Array(), +}; +assert.strictEqual(supports('deriveBits', hkdf, 128), true); +for (const value of ['128', 'AES-GCM', {}, true, 128n]) { + assert.strictEqual(supports('deriveBits', hkdf, value), false); +} +assert.strictEqual(supports('deriveKey', hkdf), false); +assert.strictEqual(supports('deriveKey', hkdf, { name: 'AES-GCM', length: 128 }), true); + +if (supports('encapsulateBits', 'ML-KEM-768')) { + assert.strictEqual(supports('encapsulateKey', 'ML-KEM-768'), true); + assert.strictEqual(supports('decapsulateKey', 'ML-KEM-768', 128), true); +}