Files
node/test/parallel/test-tls13-ciphers.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

146 lines
4.7 KiB
JavaScript

'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const { constants } = require('crypto');
const tls = require('tls');
const fixtures = require('../common/fixtures');
const { isBoringSSL } = require('../common/crypto');
const { spawnSyncAndAssert } = require('../common/child_process');
const { connect, keys } = require(fixtures.path('tls-connect'));
const aes128 = 'TLS_AES_128_GCM_SHA256';
const aes256 = 'TLS_AES_256_GCM_SHA384';
const tls13Ciphers = [aes128, aes256, 'TLS_CHACHA20_POLY1305_SHA256'];
const legacy = 'ECDHE-RSA-AES256-GCM-SHA384';
function test(clientCiphers, serverCiphers, expectedCipher, options = {}) {
connect({
client: {
rejectUnauthorized: false,
minVersion: 'TLSv1.2',
maxVersion: 'TLSv1.3',
ciphers: clientCiphers,
...options.client,
},
server: {
key: keys.agent2.key,
cert: keys.agent2.cert,
minVersion: 'TLSv1.2',
maxVersion: 'TLSv1.3',
ciphers: serverCiphers,
...options.server,
},
}, common.mustCall((err, pair, cleanup) => {
if (expectedCipher === undefined) {
assert(err);
assert.strictEqual(pair.server.err.code, 'ERR_SSL_NO_SHARED_CIPHER');
assert(pair.client.err);
} else {
assert.ifError(err);
const expected = Array.isArray(expectedCipher) ? expectedCipher : [expectedCipher];
const cipher = pair.client.conn.getCipher().name;
assert(expected.includes(cipher));
for (const { conn } of [pair.client, pair.server]) {
assert.strictEqual(conn.getCipher().name, cipher);
assert.strictEqual(conn.getProtocol(),
expectedCipher === legacy ? 'TLSv1.2' : 'TLSv1.3');
}
}
cleanup();
}));
}
function testLegacyOnlyCipherLists() {
for (const honorCipherOrder of [true, false]) {
const options = { server: { honorCipherOrder } };
// A legacy-only list retains the backend's TLS 1.3 defaults. Check that
// each peer can negotiate either AES suite without assuming their order.
test(aes128, legacy, aes128, options);
test(aes256, legacy, aes256, options);
test(legacy, aes128, aes128, options);
test(legacy, aes256, aes256, options);
test(legacy, legacy, tls13Ciphers, options);
}
}
if (process.argv[2] !== undefined) {
const mode = process.argv[2];
if (mode === 'runtime-defaults') {
tls.DEFAULT_CIPHERS = aes128;
} else {
assert.strictEqual(tls.DEFAULT_CIPHERS,
mode === 'cli-defaults' ? aes128 : legacy);
}
// Explicit TLS 1.3 defaults are still applied when ciphers is omitted, but
// must not replace the native defaults for an explicit legacy-only list.
test(undefined, undefined, mode === 'cli-legacy-defaults' ? tls13Ciphers : aes128);
testLegacyOnlyCipherLists();
return;
}
// Both peers must apply the configured TLS 1.3 cipher list.
test(aes256, undefined, aes256);
test(undefined, aes256, aes256);
test(aes128, aes256, undefined);
// Duplicate names and trailing whitespace must not cause rejection.
const duplicates = `${aes256} \t:${aes256}`;
test(duplicates, duplicates, aes256);
// Unknown TLS 1.3 cipher names are ignored, and exclusion rules are not
// interpreted in the TLS 1.3 list.
const list = `TLS_UNKNOWN:!${aes128}:${duplicates}`;
test(list, list, aes256);
for (const ciphers of ['TLS_UNKNOWN', `!${aes128}`]) {
assert.throws(() => tls.createSecureContext({ ciphers }), {
code: 'ERR_SSL_NO_CIPHER_MATCH',
});
}
if (isBoringSSL) {
assert.throws(() => tls.createSecureContext({
ciphers: 'TLS_AES_128_CCM_SHA256',
}), {
code: 'ERR_SSL_NO_CIPHER_MATCH',
});
}
// Honor the server's cipher-order option in TLS 1.3 as well as TLS 1.2.
test(`${aes256}:${aes128}`, `${aes128}:${aes256}`, aes128, {
server: { honorCipherOrder: true },
});
test(`${aes256}:${aes128}`, `${aes128}:${aes256}`, aes256, {
server: { honorCipherOrder: false },
});
testLegacyOnlyCipherLists();
// TLS 1.2 configuration and explicit protocol restrictions remain effective.
const mixed = `${legacy}:${aes256}`;
test(mixed, mixed, aes256);
test(mixed, mixed, legacy, {
client: { maxVersion: 'TLSv1.2' },
server: { maxVersion: 'TLSv1.2' },
});
test(mixed, mixed, legacy, {
server: { secureOptions: constants.SSL_OP_NO_TLSv1_3 },
});
// Empty public cipher strings continue to select Node's defaults.
test('', aes256, aes256);
test(aes256, '', aes256);
for (const [mode, ciphers] of [
['runtime-defaults', undefined],
['cli-defaults', aes128],
['cli-legacy-defaults', legacy],
]) {
spawnSyncAndAssert(process.execPath, [
...process.execArgv,
...(ciphers === undefined ? [] : [`--tls-cipher-list=${ciphers}`]),
__filename,
mode,
], {});
}