mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 21:19:50 +01:00
3ef38c4bd7
WebCryptoAPI functions' arguments are now coersed and validated as per their WebIDL definitions like in other Web Crypto API implementations. This further improves interoperability with other implementations of Web Crypto API. PR-URL: https://github.com/nodejs/node/pull/46067 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
247 lines
6.6 KiB
JavaScript
247 lines
6.6 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
const assert = require('assert');
|
|
const { subtle } = globalThis.crypto;
|
|
|
|
const kTests = [
|
|
{
|
|
namedCurve: 'P-521',
|
|
pkcs8: '3081ee020100301006072a8648ce3d020106052b810400230481d63081d302010' +
|
|
'1044201a67ed321915a64aa359b7d648ddc2618fa8e8d1867e8f71830b10d25ed' +
|
|
'2891faf12f3c7e75421a2ea264f9a915320d274fe1470742b984e96b98912081f' +
|
|
'acd478da18189038186000400209d483f28666881c6641f3a126f400f51e46511' +
|
|
'70fe678c75e85712e2868adc850824997bebf0bc82b43028a6d2ec1777ca45279' +
|
|
'f7206a3ea8b5cd2073f493e45000cb54c3a5acaa268c56710428878d98b8afbf6' +
|
|
'8a612153632846d807e92672698f1b9c611de7d38e34cd6c73889092c56e52d68' +
|
|
'0f1dfd092b87ac8ef9ff3c8fb48',
|
|
spki: '30819b301006072a8648ce3d020106052b81040023038186000400ee69f94715d7' +
|
|
'01e9e2011333d4f4f96cba7d91f88b112baf75cf09cc1f8aca97618da9389822d2' +
|
|
'9b6fe9996a61203ef752b771e8958fc4677bb3778565ab60d6ed00deab6761895b' +
|
|
'935e3ad325fb8549e56f13786aa73f88a2ecfe40933473d8aef240c4dfd7d506f2' +
|
|
'2cdd0e55558f3fbf05ebf7efef7a72d78f46469b8448f26e2712',
|
|
result: '009c2bce57be80adab3b07385b8e5990eb7d6fdebdb01bf35371a4f6075e9d28',
|
|
},
|
|
{
|
|
namedCurve: 'P-384',
|
|
pkcs8: '3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010' +
|
|
'10430f871a5666589c14a5747263ef85b319cc023db6e35676c3d781eef8b055f' +
|
|
'cfbe86fa0d06d056b5195fb1323af8de25b3a16403620004f11965df7dd4594d0' +
|
|
'419c5086482a3b826b9797f9be0bd0d109c9e1e9989c1b9a92b8f269f98e17ad1' +
|
|
'84ba73c1f79762af45af8141602642da271a6bb0ffeb0cb4478fcf707e661aa6d' +
|
|
'6cdf51549c88c3f130be9e8201f6f6a09f4185aaf95c4',
|
|
spki: '3076301006072a8648ce3d020106052b810400220362000491822dc2af59c18f5b' +
|
|
'67f80df61a2603c2a8f0b3c0af822d63c279701a824560404401dde9a56ee52757' +
|
|
'ea8bc748d4c82b5337b48d7b65583a3d572438880036bac6730f42ca5278966bd5' +
|
|
'f21e86e21d30c5a6d0463ec513dd509ffcdcaf1ff5',
|
|
result: 'e0bd6bce0aef8ca48838a6e2fcc57e67b9c5e8860c5f0be9dabec53e454e18a0',
|
|
},
|
|
];
|
|
|
|
async function prepareKeys() {
|
|
const keys = {};
|
|
await Promise.all(
|
|
kTests.map(async ({ namedCurve, size, pkcs8, spki, result }) => {
|
|
const [
|
|
privateKey,
|
|
publicKey,
|
|
] = await Promise.all([
|
|
subtle.importKey(
|
|
'pkcs8',
|
|
Buffer.from(pkcs8, 'hex'),
|
|
{
|
|
name: 'ECDH',
|
|
namedCurve
|
|
},
|
|
true,
|
|
['deriveKey', 'deriveBits']),
|
|
subtle.importKey(
|
|
'spki',
|
|
Buffer.from(spki, 'hex'),
|
|
{
|
|
name: 'ECDH',
|
|
namedCurve
|
|
},
|
|
true,
|
|
[]),
|
|
]);
|
|
keys[namedCurve] = {
|
|
privateKey,
|
|
publicKey,
|
|
size,
|
|
result,
|
|
};
|
|
}));
|
|
return keys;
|
|
}
|
|
|
|
(async function() {
|
|
const keys = await prepareKeys();
|
|
const otherArgs = [
|
|
{ name: 'HMAC', hash: 'SHA-256', length: 256 },
|
|
true,
|
|
['sign', 'verify']];
|
|
|
|
await Promise.all(
|
|
Object.keys(keys).map(async (namedCurve) => {
|
|
const { result, privateKey, publicKey } = keys[namedCurve];
|
|
|
|
{
|
|
// Good parameters
|
|
const key = await subtle.deriveKey({
|
|
name: 'ECDH',
|
|
public: publicKey
|
|
}, privateKey, ...otherArgs);
|
|
|
|
const raw = await subtle.exportKey('raw', key);
|
|
|
|
assert.strictEqual(Buffer.from(raw).toString('hex'), result);
|
|
}
|
|
|
|
{
|
|
// Case insensitivity
|
|
const key = await subtle.deriveKey({
|
|
name: 'eCdH',
|
|
public: publicKey
|
|
}, privateKey, {
|
|
name: 'HmAc',
|
|
hash: 'SHA-256',
|
|
length: 256
|
|
}, true, ['sign', 'verify']);
|
|
|
|
const raw = await subtle.exportKey('raw', key);
|
|
|
|
assert.strictEqual(Buffer.from(raw).toString('hex'), result);
|
|
}
|
|
}));
|
|
|
|
// Error tests
|
|
{
|
|
// Missing public property
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{ name: 'ECDH' },
|
|
keys['P-384'].privateKey,
|
|
...otherArgs),
|
|
{ code: 'ERR_MISSING_OPTION' });
|
|
}
|
|
|
|
{
|
|
// The public property is not a CryptoKey
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{
|
|
name: 'ECDH',
|
|
public: { message: 'Not a CryptoKey' }
|
|
},
|
|
keys['P-384'].privateKey,
|
|
...otherArgs),
|
|
{ code: 'ERR_INVALID_ARG_TYPE' });
|
|
}
|
|
|
|
{
|
|
// Mismatched named curves
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{
|
|
name: 'ECDH',
|
|
public: keys['P-384'].publicKey
|
|
},
|
|
keys['P-521'].privateKey,
|
|
...otherArgs),
|
|
{ message: /Named curve mismatch/ });
|
|
}
|
|
|
|
{
|
|
// Incorrect public key algorithm
|
|
const { publicKey } = await subtle.generateKey(
|
|
{
|
|
name: 'ECDSA',
|
|
namedCurve: 'P-521'
|
|
},
|
|
false,
|
|
['sign', 'verify']);
|
|
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{
|
|
name: 'ECDH',
|
|
public: publicKey
|
|
},
|
|
keys['P-521'].privateKey,
|
|
...otherArgs),
|
|
{ message: /Keys must be ECDH, X25519, or X448 keys/ });
|
|
}
|
|
|
|
{
|
|
// Private key does not have correct usages
|
|
const privateKey = await subtle.importKey(
|
|
'pkcs8',
|
|
Buffer.from(kTests[0].pkcs8, 'hex'),
|
|
{
|
|
name: 'ECDH',
|
|
namedCurve: 'P-521'
|
|
}, false, ['deriveBits']);
|
|
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{
|
|
name: 'ECDH',
|
|
public: keys['P-521'].publicKey,
|
|
},
|
|
privateKey,
|
|
...otherArgs),
|
|
{ message: /baseKey does not have deriveKey usage/ });
|
|
}
|
|
|
|
{
|
|
// Base key is not a private key
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{
|
|
name: 'ECDH',
|
|
public: keys['P-521'].publicKey
|
|
},
|
|
keys['P-521'].publicKey,
|
|
...otherArgs),
|
|
{ name: 'InvalidAccessError' });
|
|
}
|
|
|
|
{
|
|
// Base key is not a private key
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{
|
|
name: 'ECDH',
|
|
public: keys['P-521'].privateKey
|
|
},
|
|
keys['P-521'].publicKey,
|
|
...otherArgs),
|
|
{ name: 'InvalidAccessError' });
|
|
}
|
|
|
|
{
|
|
// Public is a secret key
|
|
const keyData = globalThis.crypto.getRandomValues(new Uint8Array(32));
|
|
const key = await subtle.importKey(
|
|
'raw',
|
|
keyData,
|
|
{ name: 'AES-CBC', length: 256 },
|
|
false, ['encrypt']);
|
|
|
|
await assert.rejects(
|
|
subtle.deriveKey(
|
|
{
|
|
name: 'ECDH',
|
|
public: key
|
|
},
|
|
keys['P-521'].publicKey,
|
|
...otherArgs),
|
|
{ name: 'InvalidAccessError' });
|
|
}
|
|
})().then(common.mustCall());
|