mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
Refresh conditional algorithm registration on FIPS changes and use the current state for parameter restrictions. Use per-algorithm availability checks in normalization and native named key generation. Remove getPqcKeyTypes(). Enable supports() tests under FIPS and cover state transitions in warmed workers. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: https://github.com/nodejs/node/pull/66160 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
136 lines
3.6 KiB
JavaScript
136 lines
3.6 KiB
JavaScript
import * as common from '../common/index.mjs';
|
|
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
import * as assert from 'node:assert';
|
|
|
|
const { SubtleCrypto } = globalThis;
|
|
|
|
const sources = [
|
|
import('../fixtures/webcrypto/supports-level-2.mjs'),
|
|
import('../fixtures/webcrypto/supports-secure-curves.mjs'),
|
|
import('../fixtures/webcrypto/supports-modern-algorithms.mjs'),
|
|
import('../fixtures/webcrypto/supports-sha3.mjs'),
|
|
];
|
|
|
|
const vectors = {};
|
|
|
|
for await (const mod of sources) {
|
|
for (const op of Object.keys(mod.vectors)) {
|
|
vectors[op] ||= [];
|
|
vectors[op] = vectors[op].concat(mod.vectors[op]);
|
|
}
|
|
}
|
|
|
|
vectors.verify = vectors.sign;
|
|
vectors.decrypt = vectors.encrypt;
|
|
vectors.decapsulateBits = vectors.encapsulateBits;
|
|
|
|
for (const enc of vectors.encrypt) {
|
|
for (const exp of vectors.exportKey) {
|
|
vectors.wrapKey.push([enc[0] && exp[0], enc[1], exp[1]]);
|
|
}
|
|
}
|
|
|
|
for (const dec of vectors.decrypt) {
|
|
for (const imp of vectors.importKey) {
|
|
vectors.unwrapKey.push([dec[0] && imp[0], dec[1], imp[1]]);
|
|
}
|
|
}
|
|
|
|
for (const exportKey of vectors.exportKey) {
|
|
if (!exportKey[0]) vectors.getPublicKey.push(exportKey);
|
|
}
|
|
|
|
function supportsRawSecret(alg) {
|
|
if (typeof alg === 'string') {
|
|
alg = alg.toLowerCase();
|
|
return alg.startsWith('aes') ||
|
|
alg.startsWith('argon2') ||
|
|
alg.startsWith('kmac') ||
|
|
alg === 'chacha20-poly1305' ||
|
|
alg === 'pbkdf2' ||
|
|
alg === 'hkdf' ||
|
|
alg === 'hmac';
|
|
}
|
|
|
|
if (typeof alg?.name === 'string') {
|
|
return supportsRawSecret(alg.name);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function getSharedKeyLength(alg) {
|
|
switch (alg?.name?.toLowerCase?.() ?? alg?.toLowerCase?.()) {
|
|
case 'ml-kem-512':
|
|
case 'ml-kem-768':
|
|
case 'ml-kem-1024':
|
|
case 'mlkem768-p256':
|
|
case 'mlkem768-x25519':
|
|
case 'mlkem1024-p384':
|
|
return 256;
|
|
}
|
|
}
|
|
|
|
function supportsEncapsulatedRawSecret(encapsulationAlgorithm, alg) {
|
|
if (!supportsRawSecret(alg)) return false;
|
|
|
|
const sharedKeyLength = getSharedKeyLength(encapsulationAlgorithm);
|
|
const name = alg?.name?.toLowerCase?.() ?? alg?.toLowerCase?.();
|
|
if (name?.startsWith('aes')) {
|
|
return sharedKeyLength === 128 ||
|
|
sharedKeyLength === 192 ||
|
|
sharedKeyLength === 256;
|
|
}
|
|
|
|
switch (name) {
|
|
case 'chacha20-poly1305':
|
|
return sharedKeyLength === 256;
|
|
case 'hmac':
|
|
if (sharedKeyLength === 0) return false;
|
|
// Fall through
|
|
case 'kmac128':
|
|
case 'kmac256':
|
|
return typeof alg !== 'object' ||
|
|
typeof alg.length !== 'number' ||
|
|
Math.ceil(alg.length / 8) * 8 === sharedKeyLength;
|
|
default:
|
|
return sharedKeyLength !== undefined;
|
|
}
|
|
}
|
|
|
|
for (const encap of vectors.encapsulateBits) {
|
|
for (const imp of vectors.importKey) {
|
|
if (supportsEncapsulatedRawSecret(encap[1], imp[1])) {
|
|
vectors.encapsulateKey.push([encap[0] && imp[0], encap[1], imp[1]]);
|
|
} else {
|
|
vectors.encapsulateKey.push([false, encap[1], imp[1]]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const decap of vectors.decapsulateBits) {
|
|
for (const imp of vectors.importKey) {
|
|
if (supportsEncapsulatedRawSecret(decap[1], imp[1])) {
|
|
vectors.decapsulateKey.push([decap[0] && imp[0], decap[1], imp[1]]);
|
|
} else {
|
|
vectors.decapsulateKey.push([false, decap[1], imp[1]]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const operation of Object.keys(vectors)) {
|
|
for (const [expectation, ...args] of vectors[operation]) {
|
|
assert.strictEqual(
|
|
SubtleCrypto.supports(operation, ...args),
|
|
expectation,
|
|
new Error(
|
|
`expected ${expectation}, got ${!expectation}`,
|
|
{ cause: { operation, args } }
|
|
)
|
|
);
|
|
}
|
|
}
|