mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
lib: improve Web Cryptography key validation ordering
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: https://github.com/nodejs/node/pull/62749 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
This commit is contained in:
1 parent
b178842482
commit
4cb1f28413
12 files changed
+201
-57
No files matched your search
@@ -919,6 +919,14 @@ async function wrapKey(format, key, wrappingKey, algorithm) {
|
||||
} catch {
|
||||
algorithm = normalizeAlgorithm(algorithm, 'encrypt');
|
||||
}
|
||||
|
||||
if (algorithm.name !== wrappingKey[kAlgorithm].name)
|
||||
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
||||
|
||||
if (!ArrayPrototypeIncludes(wrappingKey[kKeyUsages], 'wrapKey'))
|
||||
throw lazyDOMException(
|
||||
'Unable to use this key to wrapKey', 'InvalidAccessError');
|
||||
|
||||
let keyData = await FunctionPrototypeCall(exportKey, this, format, key);
|
||||
|
||||
if (format === 'jwk') {
|
||||
@@ -997,6 +1005,13 @@ async function unwrapKey(
|
||||
|
||||
unwrappedKeyAlgo = normalizeAlgorithm(unwrappedKeyAlgo, 'importKey');
|
||||
|
||||
if (unwrapAlgo.name !== unwrappingKey[kAlgorithm].name)
|
||||
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
||||
|
||||
if (!ArrayPrototypeIncludes(unwrappingKey[kKeyUsages], 'unwrapKey'))
|
||||
throw lazyDOMException(
|
||||
'Unable to use this key to unwrapKey', 'InvalidAccessError');
|
||||
|
||||
let keyData = await cipherOrWrap(
|
||||
kWebCryptoCipherDecrypt,
|
||||
unwrapAlgo,
|
||||
@@ -1030,12 +1045,12 @@ async function signVerify(algorithm, key, data, signature) {
|
||||
}
|
||||
algorithm = normalizeAlgorithm(algorithm, usage);
|
||||
|
||||
if (!ArrayPrototypeIncludes(key[kKeyUsages], usage) ||
|
||||
algorithm.name !== key[kAlgorithm].name) {
|
||||
if (algorithm.name !== key[kAlgorithm].name)
|
||||
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
||||
|
||||
if (!ArrayPrototypeIncludes(key[kKeyUsages], usage))
|
||||
throw lazyDOMException(
|
||||
`Unable to use this key to ${usage}`,
|
||||
'InvalidAccessError');
|
||||
}
|
||||
`Unable to use this key to ${usage}`, 'InvalidAccessError');
|
||||
|
||||
switch (algorithm.name) {
|
||||
case 'RSA-PSS':
|
||||
@@ -1120,18 +1135,6 @@ async function verify(algorithm, key, signature, data) {
|
||||
}
|
||||
|
||||
async function cipherOrWrap(mode, algorithm, key, data, op) {
|
||||
// We use a Node.js style error here instead of a DOMException because
|
||||
// the WebCrypto spec is not specific what kind of error is to be thrown
|
||||
// in this case. Both Firefox and Chrome throw simple TypeErrors here.
|
||||
// The key algorithm and cipher algorithm must match, and the
|
||||
// key must have the proper usage.
|
||||
if (key[kAlgorithm].name !== algorithm.name ||
|
||||
!ArrayPrototypeIncludes(key[kKeyUsages], op)) {
|
||||
throw lazyDOMException(
|
||||
'The requested operation is not valid for the provided key',
|
||||
'InvalidAccessError');
|
||||
}
|
||||
|
||||
// While WebCrypto allows for larger input buffer sizes, we limit
|
||||
// those to sizes that can fit within uint32_t because of limitations
|
||||
// in the OpenSSL API.
|
||||
@@ -1182,6 +1185,14 @@ async function encrypt(algorithm, key, data) {
|
||||
});
|
||||
|
||||
algorithm = normalizeAlgorithm(algorithm, 'encrypt');
|
||||
|
||||
if (algorithm.name !== key[kAlgorithm].name)
|
||||
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
||||
|
||||
if (!ArrayPrototypeIncludes(key[kKeyUsages], 'encrypt'))
|
||||
throw lazyDOMException(
|
||||
'Unable to use this key to encrypt', 'InvalidAccessError');
|
||||
|
||||
return await cipherOrWrap(
|
||||
kWebCryptoCipherEncrypt,
|
||||
algorithm,
|
||||
@@ -1211,6 +1222,14 @@ async function decrypt(algorithm, key, data) {
|
||||
});
|
||||
|
||||
algorithm = normalizeAlgorithm(algorithm, 'decrypt');
|
||||
|
||||
if (algorithm.name !== key[kAlgorithm].name)
|
||||
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
||||
|
||||
if (!ArrayPrototypeIncludes(key[kKeyUsages], 'decrypt'))
|
||||
throw lazyDOMException(
|
||||
'Unable to use this key to decrypt', 'InvalidAccessError');
|
||||
|
||||
return await cipherOrWrap(
|
||||
kWebCryptoCipherDecrypt,
|
||||
algorithm,
|
||||
|
||||
@@ -49,7 +49,7 @@ async function testEncryptNoEncrypt({ keyBuffer, algorithm, plaintext }) {
|
||||
['decrypt']);
|
||||
|
||||
return assert.rejects(subtle.encrypt(algorithm, key, plaintext), {
|
||||
message: /The requested operation is not valid for the provided key/
|
||||
message: /Unable to use this key to encrypt/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ async function testEncryptNoDecrypt({ keyBuffer, algorithm, plaintext }) {
|
||||
const output = await subtle.encrypt(algorithm, key, plaintext);
|
||||
|
||||
return assert.rejects(subtle.decrypt(algorithm, key, output), {
|
||||
message: /The requested operation is not valid for the provided key/
|
||||
message: /Unable to use this key to decrypt/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -80,7 +80,23 @@ async function testEncryptWrongAlg({ keyBuffer, algorithm, plaintext }, alg) {
|
||||
['encrypt']);
|
||||
|
||||
return assert.rejects(subtle.encrypt(algorithm, key, plaintext), {
|
||||
message: /The requested operation is not valid for the provided key/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
async function testDecryptWrongAlg({ keyBuffer, algorithm, result }, alg) {
|
||||
if (result === undefined) return;
|
||||
assert.notStrictEqual(algorithm.name, alg);
|
||||
const keyFormat = alg === 'AES-OCB' ? 'raw-secret' : 'raw';
|
||||
const key = await subtle.importKey(
|
||||
keyFormat,
|
||||
keyBuffer,
|
||||
{ name: alg },
|
||||
false,
|
||||
['decrypt']);
|
||||
|
||||
return assert.rejects(subtle.decrypt(algorithm, key, result), {
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,6 +128,7 @@ async function testDecrypt({ keyBuffer, algorithm, result }) {
|
||||
variations.push(testEncryptNoEncrypt(vector));
|
||||
variations.push(testEncryptNoDecrypt(vector));
|
||||
variations.push(testEncryptWrongAlg(vector, 'AES-CTR'));
|
||||
variations.push(testDecryptWrongAlg(vector, 'AES-CTR'));
|
||||
});
|
||||
|
||||
failing.forEach((vector) => {
|
||||
@@ -149,6 +166,7 @@ async function testDecrypt({ keyBuffer, algorithm, result }) {
|
||||
variations.push(testEncryptNoEncrypt(vector));
|
||||
variations.push(testEncryptNoDecrypt(vector));
|
||||
variations.push(testEncryptWrongAlg(vector, 'AES-CBC'));
|
||||
variations.push(testDecryptWrongAlg(vector, 'AES-CBC'));
|
||||
});
|
||||
|
||||
// TODO(@jasnell): These fail for different reasons. Need to
|
||||
@@ -188,6 +206,7 @@ async function testDecrypt({ keyBuffer, algorithm, result }) {
|
||||
variations.push(testEncryptNoEncrypt(vector));
|
||||
variations.push(testEncryptNoDecrypt(vector));
|
||||
variations.push(testEncryptWrongAlg(vector, 'AES-CBC'));
|
||||
variations.push(testDecryptWrongAlg(vector, 'AES-CBC'));
|
||||
});
|
||||
|
||||
failing.forEach((vector) => {
|
||||
@@ -225,6 +244,7 @@ if (hasOpenSSL(3)) {
|
||||
variations.push(testEncryptNoEncrypt(vector));
|
||||
variations.push(testEncryptNoDecrypt(vector));
|
||||
variations.push(testEncryptWrongAlg(vector, 'AES-GCM'));
|
||||
variations.push(testDecryptWrongAlg(vector, 'AES-GCM'));
|
||||
});
|
||||
|
||||
failing.forEach((vector) => {
|
||||
|
||||
@@ -48,7 +48,7 @@ async function testEncryptNoEncrypt({ keyBuffer, algorithm, plaintext }) {
|
||||
['decrypt']);
|
||||
|
||||
return assert.rejects(subtle.encrypt(algorithm, key, plaintext), {
|
||||
message: /The requested operation is not valid for the provided key/
|
||||
message: /Unable to use this key to encrypt/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ async function testEncryptNoDecrypt({ keyBuffer, algorithm, plaintext }) {
|
||||
const output = await subtle.encrypt(algorithm, key, plaintext);
|
||||
|
||||
return assert.rejects(subtle.decrypt(algorithm, key, output), {
|
||||
message: /The requested operation is not valid for the provided key/
|
||||
message: /Unable to use this key to decrypt/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,7 +77,22 @@ async function testEncryptWrongAlg({ keyBuffer, algorithm, plaintext }, alg) {
|
||||
['encrypt']);
|
||||
|
||||
return assert.rejects(subtle.encrypt(algorithm, key, plaintext), {
|
||||
message: /The requested operation is not valid for the provided key/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
async function testDecryptWrongAlg({ keyBuffer, algorithm, result }, alg) {
|
||||
if (result === undefined) return;
|
||||
assert.notStrictEqual(algorithm.name, alg);
|
||||
const key = await subtle.importKey(
|
||||
'raw-secret',
|
||||
keyBuffer,
|
||||
{ name: alg },
|
||||
false,
|
||||
['decrypt']);
|
||||
|
||||
return assert.rejects(subtle.decrypt(algorithm, key, result), {
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,6 +122,7 @@ async function testDecrypt({ keyBuffer, algorithm, result }) {
|
||||
variations.push(testEncryptNoEncrypt(vector));
|
||||
variations.push(testEncryptNoDecrypt(vector));
|
||||
variations.push(testEncryptWrongAlg(vector, 'AES-GCM'));
|
||||
variations.push(testDecryptWrongAlg(vector, 'AES-GCM'));
|
||||
});
|
||||
|
||||
failing.forEach((vector) => {
|
||||
|
||||
@@ -147,7 +147,7 @@ async function testEncryptionWrongKey({ algorithm,
|
||||
['decrypt']);
|
||||
return assert.rejects(
|
||||
subtle.encrypt(algorithm, privateKey, plaintext), {
|
||||
message: /The requested operation is not valid/
|
||||
message: /Unable to use this key to encrypt/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ async function testEncryptionBadUsage({ algorithm,
|
||||
['decrypt']);
|
||||
return assert.rejects(
|
||||
subtle.encrypt(algorithm, publicKey, plaintext), {
|
||||
message: /The requested operation is not valid/
|
||||
message: /Unable to use this key to encrypt/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ async function testDecryptionWrongKey({ ciphertext,
|
||||
|
||||
return assert.rejects(
|
||||
subtle.decrypt(algorithm, publicKey, ciphertext), {
|
||||
message: /The requested operation is not valid/
|
||||
message: /Unable to use this key to decrypt/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ async function testDecryptionBadUsage({ ciphertext,
|
||||
|
||||
return assert.rejects(
|
||||
subtle.decrypt(algorithm, publicKey, ciphertext), {
|
||||
message: /The requested operation is not valid/
|
||||
message: /Unable to use this key to decrypt/
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -43,14 +43,14 @@ const { subtle } = globalThis.crypto;
|
||||
name: 'RSA-OAEP',
|
||||
}, privateKey, buf), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'The requested operation is not valid for the provided key'
|
||||
message: 'Unable to use this key to encrypt'
|
||||
});
|
||||
|
||||
await assert.rejects(() => subtle.decrypt({
|
||||
name: 'RSA-OAEP',
|
||||
}, publicKey, ciphertext), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'The requested operation is not valid for the provided key'
|
||||
message: 'Unable to use this key to decrypt'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -88,14 +88,14 @@ if (!process.features.openssl_is_boringssl) {
|
||||
name: 'RSA-OAEP',
|
||||
}, privateKey, buf), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'The requested operation is not valid for the provided key'
|
||||
message: 'Unable to use this key to encrypt'
|
||||
});
|
||||
|
||||
await assert.rejects(() => subtle.decrypt({
|
||||
name: 'RSA-OAEP',
|
||||
}, publicKey, ciphertext), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'The requested operation is not valid for the provided key'
|
||||
message: 'Unable to use this key to decrypt'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -88,17 +88,17 @@ async function testVerify({ name,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, hash }, hmacKey, signature, plaintext), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, hash }, rsaKeys.publicKey, signature, plaintext), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, hash }, okpKeys.publicKey, signature, plaintext), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
// Test failure when signature is altered
|
||||
@@ -210,17 +210,17 @@ async function testSign({ name,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, hash }, hmacKey, plaintext), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, hash }, rsaKeys.privateKey, plaintext), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, hash }, okpKeys.privateKey, plaintext), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -101,17 +101,17 @@ async function testVerify({ name,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, context }, hmacKey, signature, data), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, context }, rsaKeys.publicKey, signature, data), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, context }, ecKeys.publicKey, signature, data), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
if (name === 'Ed448' && supportsContext) {
|
||||
@@ -227,17 +227,17 @@ async function testSign({ name,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, context }, hmacKey, data), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, context }, rsaKeys.privateKey, data), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, context }, ecKeys.privateKey, data), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
if (name === 'Ed448' && supportsContext) {
|
||||
|
||||
@@ -62,7 +62,7 @@ async function testVerify({ hash,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, hash }, rsaKeys.publicKey, signature, plaintext), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
// Test failure when signature is altered
|
||||
@@ -165,7 +165,7 @@ async function testSign({ hash,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, hash }, rsaKeys.privateKey, plaintext), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ async function testVerify({ algorithm,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.verify(signParams, keyPair.publicKey, expected, data), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
// Test failure when signature is altered
|
||||
@@ -177,7 +177,7 @@ async function testSign({ algorithm,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.sign(signParams, keyPair.privateKey, data), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -86,17 +86,17 @@ async function testVerify({ name,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, context }, hmacKey, signature, data), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, context }, rsaKeys.publicKey, signature, data), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.verify({ name, context }, ecKeys.publicKey, signature, data), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
// Test failure when too long context
|
||||
@@ -194,17 +194,17 @@ async function testSign({ name,
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, context }, hmacKey, data), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, context }, rsaKeys.privateKey, data), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.sign({ name, context }, ecKeys.privateKey, data), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
// Test failure when too long context
|
||||
|
||||
@@ -82,12 +82,12 @@ async function testVerify({
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.verify(algorithm, hmacKey, signature, plaintext), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.verify(algorithm, ecdsaKeys.publicKey, signature, plaintext), {
|
||||
message: /Unable to use this key to verify/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
// Test failure when signature is altered
|
||||
@@ -185,12 +185,12 @@ async function testSign({
|
||||
// Test failure when using the wrong algorithms
|
||||
await assert.rejects(
|
||||
subtle.sign(algorithm, hmacKey, plaintext), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
subtle.sign(algorithm, ecdsaKeys.privateKey, plaintext), {
|
||||
message: /Unable to use this key to sign/
|
||||
message: /Key algorithm mismatch/
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -378,3 +378,92 @@ function testWrapping(name, keys) {
|
||||
});
|
||||
await Promise.all(variations);
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Test that wrapKey/unwrapKey validate the wrapping/unwrapping key's
|
||||
// algorithm and usage before proceeding.
|
||||
// Spec: https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey
|
||||
// Steps 9-10 (wrapping key checks) must precede step 12 (exportKey).
|
||||
(async function() {
|
||||
const hmacKey = await subtle.generateKey(
|
||||
{ name: 'HMAC', hash: 'SHA-256' },
|
||||
true,
|
||||
['sign', 'verify'],
|
||||
);
|
||||
|
||||
const ecKey = await subtle.generateKey(
|
||||
{ name: 'ECDSA', namedCurve: 'P-256' },
|
||||
true,
|
||||
['sign', 'verify'],
|
||||
);
|
||||
|
||||
// Wrong algorithm: wrapping key is HMAC but algorithm says AES-GCM.
|
||||
// Even though exporting ecKey.privateKey as 'spki' would also fail
|
||||
// (wrong key type for spki), the wrapping key check must come first.
|
||||
await assert.rejects(
|
||||
subtle.wrapKey('spki', ecKey.privateKey, hmacKey, {
|
||||
name: 'AES-GCM',
|
||||
iv: new Uint8Array(12),
|
||||
}), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'Key algorithm mismatch',
|
||||
});
|
||||
|
||||
// Missing wrapKey usage: aesKey only has encrypt/decrypt, not wrapKey.
|
||||
// Even though exporting ecKey.privateKey as 'spki' would also fail,
|
||||
// the usage check must come first.
|
||||
const aesKey = await subtle.generateKey(
|
||||
{ name: 'AES-GCM', length: 128 },
|
||||
true,
|
||||
['encrypt', 'decrypt'],
|
||||
);
|
||||
|
||||
await assert.rejects(
|
||||
subtle.wrapKey('spki', ecKey.privateKey, aesKey, {
|
||||
name: 'AES-GCM',
|
||||
iv: new Uint8Array(12),
|
||||
}), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'Unable to use this key to wrapKey',
|
||||
});
|
||||
|
||||
// Correct wrapping key algorithm and usage results in the expected
|
||||
// exportKey error (not the wrapping key validation error).
|
||||
const wrapKey = await subtle.generateKey(
|
||||
{ name: 'AES-GCM', length: 128 },
|
||||
true,
|
||||
['wrapKey'],
|
||||
);
|
||||
|
||||
await assert.rejects(
|
||||
subtle.wrapKey('spki', ecKey.privateKey, wrapKey, {
|
||||
name: 'AES-GCM',
|
||||
iv: new Uint8Array(12),
|
||||
}), {
|
||||
// exportKey('spki', privateKey) throws NotSupportedError
|
||||
name: 'NotSupportedError',
|
||||
});
|
||||
|
||||
// --- unwrapKey validation tests ---
|
||||
|
||||
const ciphertext = new Uint8Array(32); // Dummy ciphertext
|
||||
|
||||
// Wrong algorithm: unwrapping key is HMAC but algorithm says AES-GCM.
|
||||
await assert.rejects(
|
||||
subtle.unwrapKey('raw', ciphertext, hmacKey, {
|
||||
name: 'AES-GCM',
|
||||
iv: new Uint8Array(12),
|
||||
}, { name: 'AES-GCM', length: 128 }, true, ['encrypt']), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'Key algorithm mismatch',
|
||||
});
|
||||
|
||||
// Missing unwrapKey usage: aesKey only has encrypt/decrypt, not unwrapKey.
|
||||
await assert.rejects(
|
||||
subtle.unwrapKey('raw', ciphertext, aesKey, {
|
||||
name: 'AES-GCM',
|
||||
iv: new Uint8Array(12),
|
||||
}, { name: 'AES-GCM', length: 128 }, true, ['encrypt']), {
|
||||
name: 'InvalidAccessError',
|
||||
message: 'Unable to use this key to unwrapKey',
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
Reference in new issue
Block a user