Commit 09b8c8be0a4 for nodejs
commit 09b8c8be0a47a3a3a4e2d6ae11bcead55ef52c2b
Author: Filip Skokan <panva.ip@gmail.com>
Date: Tue Sep 22 22:18:26 2026 +0200
crypto: convert importKey data as a union
Choose the BufferSource or JsonWebKey branch from the value, then
check the requested format after algorithm normalization.
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/webcrypto.js b/lib/internal/crypto/webcrypto.js
index 847017529dc..73ae08fa1e1 100644
--- a/lib/internal/crypto/webcrypto.js
+++ b/lib/internal/crypto/webcrypto.js
@@ -1,6 +1,7 @@
'use strict';
const {
+ ArrayBufferIsView,
ArrayIsArray,
ArrayPrototypeSlice,
FunctionPrototypeCall,
@@ -39,6 +40,7 @@ const {
const {
codes: {
ERR_ILLEGAL_CONSTRUCTOR,
+ ERR_INVALID_ARG_TYPE,
ERR_INVALID_THIS,
},
} = require('internal/errors');
@@ -85,6 +87,7 @@ const {
} = require('internal/crypto/random');
const {
+ isArrayBuffer,
isPromise,
} = require('internal/util/types');
@@ -1114,7 +1117,8 @@ function importKeyImpl(
const prefix = prepareSubtleMethod(this, 'importKey', arguments.length, 5);
let i = 0;
format = convertSubtleArgument(prefix, 'KeyFormat', format, i++);
- const type = format === 'jwk' ? 'JsonWebKey' : 'BufferSource';
+ const type = ArrayBufferIsView(keyData) || isArrayBuffer(keyData) ?
+ 'BufferSource' : 'JsonWebKey';
keyData = convertSubtleArgument(prefix, type, keyData, i++);
algorithm = convertSubtleArgument(
prefix, 'AlgorithmIdentifier', algorithm, i++);
@@ -1124,6 +1128,11 @@ function importKeyImpl(
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
+ if ((format === 'jwk') !== (type === 'JsonWebKey')) {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'keyData', format === 'jwk' ? 'JsonWebKey' : 'BufferSource', keyData);
+ }
+
return FunctionPrototypeCall(
importKeySync,
this,
diff --git a/test/parallel/test-webcrypto-import-union.js b/test/parallel/test-webcrypto-import-union.js
new file mode 100644
index 00000000000..3391ba5c8dc
--- /dev/null
+++ b/test/parallel/test-webcrypto-import-union.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const { subtle } = globalThis.crypto;
+const jwk = { kty: 'oct', k: 'AAAAAAAAAAAAAAAAAAAAAA' };
+
+(async () => {
+ for (const data of [new ArrayBuffer(16), new Uint8Array(16),
+ new DataView(new ArrayBuffer(16)), Buffer.alloc(16)]) {
+ await assert.rejects(subtle.importKey('jwk', data, 'AES-GCM', true, ['encrypt']),
+ TypeError);
+ Object.assign(data, jwk);
+ await assert.rejects(subtle.importKey('jwk', data, 'AES-GCM', true, ['encrypt']),
+ TypeError);
+ await assert.rejects(subtle.importKey('jwk', data, 'unknown', true, ['encrypt']),
+ { name: 'NotSupportedError' });
+ }
+ await assert.rejects(subtle.importKey('raw', {}, 'unknown', true, ['encrypt']),
+ { name: 'NotSupportedError' });
+ await assert.rejects(subtle.importKey('raw', {}, 'AES-GCM', true, ['encrypt']),
+ TypeError);
+ for (const data of [null, new SharedArrayBuffer(16)]) {
+ await assert.rejects(subtle.importKey('jwk', data, 'AES-GCM', true, ['encrypt']),
+ { name: 'DataError' });
+ }
+ assert.strictEqual((await subtle.importKey('jwk', jwk, 'AES-GCM', true,
+ ['encrypt'])).type, 'secret');
+ await assert.rejects(subtle.importKey('raw', {
+ get kty() { throw new Error('converted JWK'); },
+ }, 'unknown', true, ['encrypt']), { message: 'converted JWK' });
+})().then(common.mustCall());