Skip to content
2 changes: 1 addition & 1 deletion test/addons/openssl-binding/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ inline void Initialize(v8::Local<v8::Object> exports,
.ToLocalChecked();
assert(exports->Set(context, key, value).IsJust());

const SSL_METHOD* method = TLSv1_2_server_method();
const SSL_METHOD* method = TLS_server_method();
assert(method != nullptr);

key = v8::String::NewFromUtf8(isolate, "hash").ToLocalChecked();
Expand Down
31 changes: 21 additions & 10 deletions test/parallel/test-crypto-dh-stateless.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ const assert = require('assert');
const crypto = require('crypto');
const { hasOpenSSL } = require('../common/crypto');

// Error code for a key-type mismatch during (EC)DH. The underlying OpenSSL
// error code varies by version, and in OpenSSL 4.0 by platform: some builds
// report a generic internal error instead of a typed key-type mismatch.
// https://github.com/openssl/openssl/issues/30895
// TODO(panva): Tighten this check once/if fixed.
let keyTypeMismatchCode;
if (hasOpenSSL(4, 0)) {
keyTypeMismatchCode =
/^ERR_OSSL_EVP_(OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE|INTERNAL_ERROR)$/;
} else if (hasOpenSSL(3)) {
keyTypeMismatchCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
} else {
keyTypeMismatchCode = 'ERR_OSSL_EVP_DIFFERENT_KEY_TYPES';
}

assert.throws(() => crypto.diffieHellman(), {
name: 'TypeError',
code: 'ERR_INVALID_ARG_TYPE',
Expand Down Expand Up @@ -397,9 +412,7 @@ test(crypto.generateKeyPairSync('x25519'),
privateKey: crypto.generateKeyPairSync('x448').privateKey,
publicKey: crypto.generateKeyPairSync('x25519').publicKey,
};
testDHError(options, { code: hasOpenSSL(3) ?
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE' :
'ERR_OSSL_EVP_DIFFERENT_KEY_TYPES' });
testDHError(options, { code: keyTypeMismatchCode });
}

// Test all key encoding formats
Expand Down Expand Up @@ -541,23 +554,21 @@ for (const { privateKey: alicePriv, publicKey: bobPub } of [
testDHError({
privateKey: privKey(ec256.privateKey),
publicKey: pubKey(x25519.publicKey),
}, { code: hasOpenSSL(3) ?
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE' :
'ERR_OSSL_EVP_DIFFERENT_KEY_TYPES' });
}, { code: keyTypeMismatchCode });

// Unsupported key type (ed25519)
testDHError({
privateKey: privKey(ed25519.privateKey),
publicKey: pubKey(ed25519.publicKey),
}, { code: 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE' });
}, { code: hasOpenSSL(4, 0) ?
/^ERR_OSSL_EVP_(OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE|INTERNAL_ERROR)$/ :
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE' });

// Incompatible key types (x448 + x25519)
testDHError({
privateKey: privKey(x448.privateKey),
publicKey: pubKey(x25519.publicKey),
}, { code: hasOpenSSL(3) ?
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE' :
'ERR_OSSL_EVP_DIFFERENT_KEY_TYPES' });
}, { code: keyTypeMismatchCode });

// Zero x25519 public key
testDHError({
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-tls-alert-handling.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ function sendBADTLSRecord() {
// Different OpenSSL versions send different TLS alerts when the peer
// receives an invalid record on an established connection.
assert.match(err.code,
/ERR_SSL_(TLSV1_ALERT_PROTOCOL_VERSION|TLSV1_ALERT_RECORD_OVERFLOW|SSL\/TLS_ALERT_UNEXPECTED_MESSAGE)/);
/ERR_SSL_(TLSV1_ALERT_PROTOCOL_VERSION|TLSV1_ALERT_RECORD_OVERFLOW|(SSL\/)?TLS_ALERT_UNEXPECTED_MESSAGE)/);
assert.strictEqual(err.library, 'SSL routines');
if (!hasOpenSSL3 && !process.features.openssl_is_boringssl)
assert.strictEqual(err.function, 'ssl3_read_bytes');
assert.match(err.reason,
/tlsv1[\s_]alert[\s_]protocol[\s_]version|tlsv1[\s_]alert[\s_]record[\s_]overflow|ssl\/tls[\s_]alert[\s_]unexpected[\s_]message/i);
/tlsv1[\s_]alert[\s_]protocol[\s_]version|tlsv1[\s_]alert[\s_]record[\s_]overflow|(ssl\/)?tls[\s_]alert[\s_]unexpected[\s_]message/i);
}));
}
5 changes: 4 additions & 1 deletion test/parallel/test-tls-client-getephemeralkeyinfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ function test(size, type, name, cipher) {

test(undefined, undefined, undefined, 'AES256-SHA256');
test('auto', 'DH', undefined, 'DHE-RSA-AES256-GCM-SHA384');
if (!hasOpenSSL(3, 2)) {
if (hasOpenSSL(4, 0)) {
// OpenSSL 4.0 implements RFC 7919 FFDHE negotiation for TLS 1.2 and
// always selects FFDHE-2048 regardless of the server-supplied dhparam.
} else if (!hasOpenSSL(3, 2)) {
test(1024, 'DH', undefined, 'DHE-RSA-AES256-GCM-SHA384');
} else {
test(3072, 'DH', undefined, 'DHE-RSA-AES256-GCM-SHA384');
Expand Down
12 changes: 9 additions & 3 deletions test/parallel/test-tls-client-mindhsize.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const secLevel = require('internal/crypto/util').getOpenSSLSecLevel();
const assert = require('assert');
const tls = require('tls');
const fixtures = require('../common/fixtures');
const { hasOpenSSL } = require('../common/crypto');

const key = fixtures.readKey('agent2-key.pem');
const cert = fixtures.readKey('agent2-cert.pem');
Expand All @@ -24,7 +25,7 @@ function loadDHParam(n) {
return fixtures.readKey(`dh${n}.pem`);
}

function test(size, err, next) {
function test(size, err, next, minDHSizeOverride) {
const options = {
key: key,
cert: cert,
Expand All @@ -46,7 +47,7 @@ function test(size, err, next) {
// so that it fails when it makes a connection to the tls
// server where is too small. This depends on the openssl
// security level
const minDHSize = (secLevel > 1) ? 3072 : 2048;
const minDHSize = minDHSizeOverride ?? ((secLevel > 1) ? 3072 : 2048);
const client = tls.connect({
minDHSize: minDHSize,
port: this.address().port,
Expand Down Expand Up @@ -84,7 +85,12 @@ function testDHE3072() {
test(3072, false, null);
}

if (secLevel > 1) {
if (hasOpenSSL(4, 0)) {
// OpenSSL 4.0 implements RFC 7919 FFDHE negotiation for TLS 1.2 and
// ignores the server-supplied dhparam in favor of FFDHE-2048. The 3072
// success case is therefore replaced by a 2048 success case.
testDHE2048(true, () => test(2048, false, null, 2048));
} else if (secLevel > 1) {
// Minimum size for OpenSSL security level 2 and above is 2048 by default
testDHE2048(true, testDHE3072);
} else {
Expand Down
27 changes: 22 additions & 5 deletions test/parallel/test-tls-dhe.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ if (!common.hasCrypto) {

const {
opensslCli,
hasOpenSSL,
} = require('../common/crypto');

// OpenSSL has a set of security levels which affect what algorithms
Expand Down Expand Up @@ -104,9 +105,15 @@ function testCustomParam(keylen, expectedCipher) {
}

(async () => {
// By default, DHE is disabled while ECDHE is enabled.
// By default, DHE is disabled while ECDHE is enabled. OpenSSL 4.0
// implements RFC 7919 FFDHE negotiation for TLS 1.2 which enables DHE
// (with FFDHE-2048) even without a server-supplied dhparam.
for (const dhparam of [undefined, null]) {
await test(dhparam, null, ecdheCipher);
if (hasOpenSSL(4, 0)) {
await test(dhparam, 2048, dheCipher);
} else {
await test(dhparam, null, ecdheCipher);
}
}

// The DHE parameters selected by OpenSSL depend on the strength of the
Expand All @@ -124,14 +131,24 @@ function testCustomParam(keylen, expectedCipher) {

// Custom DHE parameters are supported (but discouraged).
// 1024 is disallowed at security level 2 and above so use 3072 instead
// for higher security levels
// for higher security levels.
// OpenSSL 4.0 implements RFC 7919 FFDHE negotiation for TLS 1.2 and
// ignores the server-supplied dhparam in favor of FFDHE-2048, so the
// negotiated key length is always 2048.
if (secLevel < 2) {
await testCustomParam(1024, dheCipher);
} else if (hasOpenSSL(4, 0)) {
await test(loadDHParam(3072), 2048, dheCipher);
} else {
await testCustomParam(3072, dheCipher);
}
await testCustomParam(2048, dheCipher);

// Invalid DHE parameters are discarded. ECDHE remains enabled.
await testCustomParam('error', ecdheCipher);
// Invalid DHE parameters are discarded. Prior to OpenSSL 4.0 this
// disabled DHE and ECDHE was negotiated; since 4.0, FFDHE-2048 is used.
if (hasOpenSSL(4, 0)) {
await test(loadDHParam('error'), 2048, dheCipher);
} else {
await testCustomParam('error', ecdheCipher);
}
})().then(common.mustCall());
15 changes: 13 additions & 2 deletions test/parallel/test-tls-ecdh-multiple.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if (!common.hasCrypto) {
common.skip('missing crypto');
}

const { opensslCli } = require('../common/crypto');
const { opensslCli, hasOpenSSL } = require('../common/crypto');
const crypto = require('crypto');

if (!opensslCli) {
Expand All @@ -24,11 +24,17 @@ function loadPEM(n) {
return fixtures.readKey(`${n}.pem`);
}

// OpenSSL 4.0 disables support for deprecated elliptic curves from RFC 8422
// (including secp256k1) by default.
const ecdhCurve = hasOpenSSL(4, 0) ?
'prime256v1:secp521r1' :
'secp256k1:prime256v1:secp521r1';

const options = {
key: loadPEM('agent2-key'),
cert: loadPEM('agent2-cert'),
ciphers: '-ALL:ECDHE-RSA-AES128-SHA256',
ecdhCurve: 'secp256k1:prime256v1:secp521r1',
ecdhCurve,
maxVersion: 'TLSv1.2',
};

Expand Down Expand Up @@ -60,6 +66,11 @@ const server = tls.createServer(options, (conn) => {
unsupportedCurves.push('brainpoolP256r1');
}

// Deprecated RFC 8422 curves are disabled by default in OpenSSL 4.0.
if (hasOpenSSL(4, 0)) {
unsupportedCurves.push('secp256k1');
}

unsupportedCurves.forEach((ecdhCurve) => {
assert.throws(() => tls.createServer({ ecdhCurve }),
/Error: Failed to set ECDH curve/);
Expand Down
3 changes: 3 additions & 0 deletions test/parallel/test-tls-error-stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const tls = require('tls');
assert.throws(() => {
tls.createSecureContext({ clientCertEngine: 'x' });
}, (err) => {
if (err.code === 'ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED')
common.skip('OpenSSL dropped engine support');

return err.name === 'Error' &&
/could not load the shared library/.test(err.message) &&
Array.isArray(err.opensslErrorStack) &&
Expand Down
27 changes: 24 additions & 3 deletions test/parallel/test-tls-ocsp-callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ if (!common.hasCrypto) {
const crypto = require('crypto');
const tls = require('tls');
const fixtures = require('../common/fixtures');
const { hasOpenSSL } = require('../common/crypto');

const assert = require('assert');

Expand Down Expand Up @@ -90,7 +91,10 @@ function test(testOptions, cb) {

client.on('OCSPResponse', common.mustCall((resp) => {
if (testOptions.response) {
assert.strictEqual(resp.toString(), testOptions.response);
if (Buffer.isBuffer(testOptions.response))
assert.deepStrictEqual(resp, testOptions.response);
else
assert.strictEqual(resp.toString(), testOptions.response);
client.destroy();
} else {
assert.strictEqual(resp, null);
Expand All @@ -103,10 +107,27 @@ function test(testOptions, cb) {
}));
}

// OpenSSL 3.6+ validates that the value passed to
// SSL_set_tlsext_status_ocsp_resp parses as DER, so the test responses need
// to be valid DER-encoded OCSPResponse values.
// Minimal OCSPResponse is SEQUENCE { ENUMERATED responseStatus } where
// 0 = successful and 1 = malformedRequest.
const response1 = Buffer.from([0x30, 0x03, 0x0a, 0x01, 0x00]);
const response2 = Buffer.from([0x30, 0x03, 0x0a, 0x01, 0x01]);

test({ ocsp: true, response: false });
test({ ocsp: true, response: 'hello world' });
test({ ocsp: true, response: response1 });
test({ ocsp: false });

if (!crypto.getFips()) {
test({ ocsp: true, response: 'hello pfx', pfx: pfx, passphrase: 'sample' });
test({ ocsp: true, response: response2, pfx: pfx, passphrase: 'sample' });
}

// Older OpenSSL versions accept arbitrary bytes (not just DER) as the OCSP
// response, so additionally exercise the string path there.
if (!hasOpenSSL(3, 6)) {
test({ ocsp: true, response: 'hello world' });
if (!crypto.getFips()) {
test({ ocsp: true, response: 'hello pfx', pfx: pfx, passphrase: 'sample' });
}
}
19 changes: 18 additions & 1 deletion test/parallel/test-tls-set-ciphers-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ if (!common.hasCrypto)
const assert = require('assert');
const tls = require('tls');
const fixtures = require('../common/fixtures');
const { hasOpenSSL } = require('../common/crypto');

{
const options = {
key: fixtures.readKey('agent2-key.pem'),
cert: fixtures.readKey('agent2-cert.pem'),
ciphers: 'aes256-sha'
ciphers: 'DES-CBC-SHA'
};
assert.throws(() => tls.createServer(options, common.mustNotCall()),
/no[_ ]cipher[_ ]match/i);
Expand All @@ -23,3 +24,19 @@ const fixtures = require('../common/fixtures');
assert.throws(() => tls.createServer(options, common.mustNotCall()),
/no[_ ]cipher[_ ]match/i);
}

// Cipher name matching is case-sensitive prior to OpenSSL 4.0, and
// case-insensitive starting with OpenSSL 4.0.
{
const options = {
key: fixtures.readKey('agent2-key.pem'),
cert: fixtures.readKey('agent2-cert.pem'),
ciphers: 'aes256-sha',
};
if (hasOpenSSL(4, 0)) {
tls.createServer(options).close();
} else {
assert.throws(() => tls.createServer(options, common.mustNotCall()),
/no[_ ]cipher[_ ]match/i);
}
}
Loading