Files
node/test/parallel/test-permission-openssl-store.js
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

94 lines
3.7 KiB
JavaScript

// Flags: --permission --allow-fs-read=* --allow-fs-write=* --allow-openssl-store --allow-child-process --allow-env=NODE_TEST_DIR,TEST_*
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const { isBoringSSL } = require('../common/crypto');
if (isBoringSSL)
common.skip('OpenSSL provider support is required');
// Verifies the openssl.store permission: allowed when --allow-openssl-store is
// set, can be dropped at runtime, and denied by default in a child process.
const assert = require('assert');
const dc = require('diagnostics_channel');
const fs = require('fs');
const path = require('path');
const { pathToFileURL } = require('url');
const { createPrivateKey, generateKeyPairSync } = require('crypto');
const { spawnSync } = require('child_process');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const file = path.join(tmpdir.path, 'priv.pem');
fs.writeFileSync(
file, generateKeyPairSync('ed25519').privateKey.export({
format: 'pem', type: 'pkcs8',
}));
const url = pathToFileURL(file);
assert.strictEqual(process.permission.has('openssl.store'), true);
assert.strictEqual(createPrivateKey(url).type, 'private');
// A plain object that merely looks like a URL is not one, so it never reaches
// a STORE loader and cannot be used to sidestep this permission.
assert.throws(() => createPrivateKey({
href: file,
protocol: 'pkcs11:',
}), { code: 'ERR_INVALID_ARG_TYPE' });
process.permission.drop('openssl.store');
assert.strictEqual(process.permission.has('openssl.store'), false);
const secret = 'store-permission-secret';
const messages = [];
dc.subscribe('node:permission-model:openssl-store', (message) => {
messages.push(message);
});
assert.throws(
() => createPrivateKey(new URL(`pkcs11:object=key;pin-value=${secret}`)),
(error) => {
assert.strictEqual(error.code, 'ERR_ACCESS_DENIED');
assert.strictEqual(error.permission, 'OpenSSLStore');
assert.strictEqual(error.resource, '');
assert.doesNotMatch(error.stack, new RegExp(secret));
return true;
});
assert.strictEqual(messages.length, 1);
assert.strictEqual(messages[0].permission, 'OpenSSLStore');
assert.strictEqual(messages[0].resource, '');
assert.doesNotMatch(JSON.stringify(messages[0]), new RegExp(secret));
// Denied by default when the flag is not provided.
{
const { status, stdout } = spawnSync(process.execPath, [
'--permission', '--allow-fs-read=*',
'-e', `try { require('crypto').createPrivateKey(new URL(${JSON.stringify(url.href)})); console.log('LOADED'); } catch (e) { console.log(e.code, e.permission); }`,
]);
assert.strictEqual(status, 0);
assert.match(stdout.toString(), /ERR_ACCESS_DENIED OpenSSLStore/);
}
// openssl.store grants the STORE loader authority to access files even when
// fs.read is not granted.
{
const { status, stdout } = spawnSync(process.execPath, [
'--permission', '--allow-openssl-store',
'-e', `try { require('crypto').createPrivateKey(new URL(${JSON.stringify(url.href)})); console.log('LOADED'); } catch (e) { console.log(e.code, e.permission); }`,
]);
assert.strictEqual(status, 0);
assert.match(stdout.toString(), /LOADED/);
}
// OpenSSL tries the file loader before the loader identified by an opaque URI.
{
const opaqueFile = 'pkcs11:priv.pem';
fs.copyFileSync(file, path.join(tmpdir.path, opaqueFile));
const { status, stdout } = spawnSync(process.execPath, [
'--permission', '--allow-openssl-store',
'-e', `try { require('crypto').createPrivateKey(new URL(${JSON.stringify(opaqueFile)})); console.log('LOADED'); } catch (e) { console.log(e.code, e.permission); }`,
], { cwd: tmpdir.path });
assert.strictEqual(status, 0);
assert.match(stdout.toString(), /LOADED/);
}