Files
node/test/parallel/test-diagnostics-channel-crypto-fips-indicator.js
T
Filip Skokan acbc3ff133 test,benchmark: drop OpenSSL 1.x-only coverage
Delete test-crypto-ecb.js, which can no longer run anywhere: Blowfish
is available only from OpenSSL's legacy provider and is absent from
BoringSSL.

The addon and cctest version guards become OPENSSL_IS_BORINGSSL checks.
Remove legacy digest-alias coverage and unreachable OpenSSL 1.x
branches. JavaScript test and benchmark gates, skip reasons, and TLS
error expectations that distinguished OpenSSL 1.x from provider-backed
OpenSSL now distinguish BoringSSL, including PKCS12 parsing, named DH
groups, private-key serialization, RSA-PSS parameters, consolidated
provider caches, FIPS availability, and empty KMAC output. Keep the CCM
alternate finalization error only for BoringSSL.

Provider-only test skips use version-neutral terminology or state the
actual minimum OpenSSL version.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/64777
Fixes: https://github.com/nodejs/node/issues/56733
Refs: https://github.com/nodejs/node/pull/64211
Refs: https://github.com/nodejs/node/pull/63966
Refs: https://github.com/nodejs/node/pull/53329
Refs: https://github.com/nodejs/node/pull/48950
Refs: https://github.com/nodejs/node/issues/45465
Refs: https://github.com/nodejs/node/issues/42827
Refs: https://github.com/nodejs/node/issues/47076
Refs: https://github.com/nodejs/node/pull/62862
Refs: https://github.com/nodejs/node/pull/38512
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-10-25 22:36:32 +01:00

185 lines
5.5 KiB
JavaScript

'use strict';
const common = require('../common');
if (!common.hasCrypto) {
common.skip('missing crypto');
}
const assert = require('node:assert');
const diagnosticsChannel = require('node:diagnostics_channel');
const { once } = require('node:events');
const { Worker } = require('node:worker_threads');
const {
spawnSyncAndExitWithoutError,
} = require('../common/child_process');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');
const {
createHmac,
generateKeyPairSync,
sign,
subtle,
} = require('node:crypto');
const channelName = 'crypto.fips.indicator';
if (!hasOpenSSL(3, 4)) {
common.skip('OpenSSL 3.4 or later is required');
} else if (!hasFIPS(3, 4)) {
common.skip('an active OpenSSL FIPS provider is required');
} else if (!process.execArgv.includes('--enable-fips-indicator-events')) {
spawnSyncAndExitWithoutError(
process.execPath,
['--enable-fips-indicator-events', __filename],
);
} else {
run().then(common.mustCall());
}
function nextIndicator() {
const keepAlive = setInterval(common.mustNotCall(), 10_000);
const { promise, resolve } = Promise.withResolvers();
const subscriber = common.mustCall((event, name) => {
assert.strictEqual(name, channelName);
clearInterval(keepAlive);
assert.strictEqual(
diagnosticsChannel.unsubscribe(channelName, subscriber), true);
resolve(event);
});
diagnosticsChannel.subscribe(channelName, subscriber);
return promise;
}
function testUnsubscribeDuringDrain(key, privateKey) {
const keepAlive = setInterval(common.mustNotCall(), 10_000);
const { promise, resolve } = Promise.withResolvers();
const subscriber = common.mustCall(() => {
clearInterval(keepAlive);
assert.strictEqual(
diagnosticsChannel.unsubscribe(channelName, subscriber), true);
setImmediate(common.mustCall(resolve));
});
diagnosticsChannel.subscribe(channelName, subscriber);
createHmac('sha256', key).digest();
sign('sha1', Buffer.alloc(0), privateKey);
return promise;
}
async function testNoStaleIndicator(key) {
createHmac('sha256', key).digest();
const subscriber = common.mustNotCall();
diagnosticsChannel.subscribe(channelName, subscriber);
await new Promise((resolve) => setImmediate(resolve));
assert.strictEqual(
diagnosticsChannel.unsubscribe(channelName, subscriber), true);
}
async function run() {
const key = Buffer.alloc(13);
const keepAlive = setInterval(common.mustNotCall(), 10_000);
const { promise, resolve: resolveProbe } = Promise.withResolvers();
const probeSubscriber = (event) => {
clearInterval(keepAlive);
diagnosticsChannel.unsubscribe(channelName, probeSubscriber);
resolveProbe(event);
};
diagnosticsChannel.subscribe(channelName, probeSubscriber);
let output;
try {
output = createHmac('sha256', key).digest();
} catch (error) {
clearInterval(keepAlive);
diagnosticsChannel.unsubscribe(channelName, probeSubscriber);
assert.match(error.code, /^ERR_OSSL_/);
common.printSkipMessage(
'the FIPS provider rejects unapproved operations before signaling');
return;
}
assert.strictEqual(output.byteLength, 32);
assert.deepStrictEqual(await promise, {
operation: 'HMAC',
reason: 'keysize',
blocked: false,
count: 1,
dropped: 0,
});
await testNoStaleIndicator(key);
let eventPromise = nextIndicator();
createHmac('sha256', key).digest();
createHmac('sha256', key).digest();
assert.deepStrictEqual(await eventPromise, {
operation: 'HMAC',
reason: 'keysize',
blocked: false,
count: 2,
dropped: 0,
});
const secondSubscriber = common.mustCall();
diagnosticsChannel.subscribe(channelName, secondSubscriber);
eventPromise = nextIndicator();
createHmac('sha256', key).digest();
await eventPromise;
assert.strictEqual(
diagnosticsChannel.unsubscribe(channelName, secondSubscriber), true);
const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
await testUnsubscribeDuringDrain(key, privateKey);
const hmacKey = await subtle.importKey(
'raw', Buffer.alloc(13), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
eventPromise = nextIndicator();
const [signature, hmacEvent] = await Promise.all([
subtle.sign('HMAC', hmacKey, Buffer.alloc(0)),
eventPromise,
]);
assert.strictEqual(signature.byteLength, 32);
assert.strictEqual(hmacEvent.operation, 'HMAC');
assert.strictEqual(hmacEvent.reason, 'keysize');
assert.strictEqual(hmacEvent.blocked, false);
eventPromise = nextIndicator();
const worker = new Worker(`
'use strict';
const diagnosticsChannel = require('node:diagnostics_channel');
const { parentPort, workerData } = require('node:worker_threads');
const { createHmac } = require('node:crypto');
let indicatorCount = 0;
diagnosticsChannel.subscribe('crypto.fips.indicator', () => {
indicatorCount++;
});
const result = createHmac('sha256', workerData.key).digest();
setImmediate(() => {
parentPort.postMessage({
indicatorCount,
length: result.byteLength,
});
});
`, {
eval: true,
workerData: { key },
});
worker.on('error', common.mustNotCall());
const exitPromise = once(worker, 'exit');
const [[message], workerEvent] = await Promise.all([
once(worker, 'message'),
eventPromise,
]);
assert.deepStrictEqual(message, { indicatorCount: 0, length: 32 });
assert.deepStrictEqual(workerEvent, {
operation: 'HMAC',
reason: 'keysize',
blocked: false,
count: 1,
dropped: 0,
});
const [exitCode] = await exitPromise;
assert.strictEqual(exitCode, 0);
}