Files
node/test/parallel/test-crypto-key-encoding-provider-cipher.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

114 lines
3.4 KiB
JavaScript

'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const { hasFIPS, isBoringSSL } = require('../common/crypto');
if (isBoringSSL)
common.skip('OpenSSL providers are required');
const assert = require('assert');
const {
createPrivateKey,
createPublicKey,
generateKeyPair,
generateKeyPairSync,
getCiphers,
sign,
verify,
} = require('crypto');
// Resolve an AES-256-CBC provider alias and retain the fetched cipher while
// encoding private keys and running asynchronous key generation jobs.
const cipher = '2.16.840.1.101.3.4.1.42';
const passphrase = 'provider cipher passphrase';
const keyOptions = { namedCurve: 'prime256v1' };
const { publicKey, privateKey } = generateKeyPairSync('ec', keyOptions);
const data = Buffer.from('encrypted private key');
function checkPrivateKey(encoded, format, type, expectedPublicKey) {
const decrypted = createPrivateKey({
key: encoded,
format,
type,
passphrase,
});
assert(createPublicKey(decrypted).equals(expectedPublicKey));
const signature = sign('sha256', data, decrypted);
assert(verify('sha256', data, expectedPublicKey, signature));
}
for (const format of ['pem', 'der']) {
const privateKeyEncoding = {
format,
type: 'pkcs8',
cipher,
passphrase,
};
const exported = privateKey.export(privateKeyEncoding);
if (format === 'pem')
assert.match(exported, /^-----BEGIN ENCRYPTED PRIVATE KEY-----/);
checkPrivateKey(exported, format, 'pkcs8', publicKey);
const generated = generateKeyPairSync('ec', {
...keyOptions,
privateKeyEncoding,
});
checkPrivateKey(generated.privateKey, format, 'pkcs8', generated.publicKey);
// Async jobs copy the encoding configuration. Its fetched cipher must remain
// valid after the configuration used to create the job has been destroyed.
generateKeyPair('ec', {
...keyOptions,
privateKeyEncoding,
}, common.mustSucceed((generatedPublicKey, generatedPrivateKey) => {
checkPrivateKey(generatedPrivateKey, format, 'pkcs8', generatedPublicKey);
}));
}
// Provider lookup must preserve the restrictions of each key format.
const sec1 = { format: 'pem', type: 'sec1', cipher, passphrase };
// Traditional PEM encryption uses MD5 to derive its key.
if (!hasFIPS())
checkPrivateKey(privateKey.export(sec1), 'pem', 'sec1', publicKey);
assert.throws(() => privateKey.export({ ...sec1, format: 'der' }), {
code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS',
});
const unknownCipher = {
format: 'pem',
type: 'pkcs8',
cipher: 'unknown-private-key-cipher',
passphrase,
};
const unknownCipherError = {
code: 'ERR_CRYPTO_UNKNOWN_CIPHER',
message: 'Unknown cipher',
};
assert.throws(() => privateKey.export(unknownCipher), unknownCipherError);
assert.throws(() => generateKeyPairSync('ec', {
...keyOptions,
privateKeyEncoding: unknownCipher,
}), unknownCipherError);
assert.throws(() => generateKeyPair('ec', {
...keyOptions,
privateKeyEncoding: unknownCipher,
}, common.mustNotCall()), unknownCipherError);
// Provider-only ciphers must reach the serializer, which still rejects ciphers
// without an ASN.1 identifier when writing PKCS8.
if (getCiphers().includes('aes-128-cbc-cts')) {
for (const format of ['pem', 'der']) {
assert.throws(() => privateKey.export({
format,
type: 'pkcs8',
cipher: 'aes-128-cbc-cts',
passphrase,
}), {
code: 'ERR_OSSL_ASN1_CIPHER_HAS_NO_OBJECT_IDENTIFIER',
});
}
}