Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions .github/workflows/test-shared-openssl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Throwaway workflow used solely to gather test results for Node.js
# linked against OpenSSL 3.5, 3.6, and 4.0.
name: TEMP - Test Shared libraries (OpenSSL)

on:
pull_request:
push:
branches:
- tmp-openssl4

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

env:
FLAKY_TESTS: keep_retrying

permissions:
contents: read

jobs:
build-tarball:
name: Build slim tarball
runs-on: ubuntu-slim
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Make tarball
run: |
export DATESTRING=$(date "+%Y-%m-%d")
export COMMIT=$(git rev-parse --short=10 "$GITHUB_SHA")
./configure && make tar -j4 SKIP_XZ=1 SKIP_SHARED_DEPS=1
env:
DISTTYPE: nightly

- name: Upload tarball artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: tarballs
path: '*.tar.gz'
compression-level: 0

build:
needs: build-tarball
strategy:
fail-fast: false
matrix:
opensslPkg:
- openssl_1_1
- openssl_3
- openssl_3_5
- openssl_3_6
- openssl_4_0
system:
- x86_64-linux
- aarch64-linux
- x86_64-darwin
- aarch64-darwin
include:
- system: x86_64-linux
runner: ubuntu-24.04
- system: aarch64-linux
runner: ubuntu-24.04-arm
- system: x86_64-darwin
runner: macos-15-intel
- system: aarch64-darwin
runner: macos-latest
name: '${{ matrix.system }}: with shared libraries (${{ matrix.opensslPkg }})'
runs-on: ${{ matrix.runner }}
# We only care about the test results here, not about gating anything.
continue-on-error: true
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: tarballs
path: tarballs

- name: Extract tarball
run: |
tar xzf tarballs/*.tar.gz -C "$RUNNER_TEMP"
echo "TAR_DIR=$RUNNER_TEMP/$(basename tarballs/*.tar.gz .tar.gz)" >> "$GITHUB_ENV"

- uses: cachix/install-nix-action@96951a368ba55167b55f1c916f7d416bac6505fe # v31.10.3
with:
extra_nix_config: sandbox = true

- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
with:
name: nodejs
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}

- name: Configure sccache
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
core.exportVariable('SCCACHE_GHA_ENABLED', 'on');
core.exportVariable('ACTIONS_CACHE_SERVICE_V2', 'on');
core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
core.exportVariable('NIX_SCCACHE', '(import <nixpkgs> {}).sccache');

- name: Build Node.js and run tests
env:
# Allow evaluating packages marked insecure in nixpkgs (e.g. openssl_1_1).
NIXPKGS_ALLOW_INSECURE: '1'
run: |
nix-shell \
-I "nixpkgs=$TAR_DIR/tools/nix/pkgs.nix" \
--impure \
--pure --keep TAR_DIR --keep FLAKY_TESTS --keep NIXPKGS_ALLOW_INSECURE \
--keep SCCACHE_GHA_ENABLED --keep ACTIONS_CACHE_SERVICE_V2 --keep ACTIONS_RESULTS_URL --keep ACTIONS_RUNTIME_TOKEN \
--arg loadJSBuiltinsDynamically false \
--arg useSeparateDerivationForV8 true \
--arg ccache "${NIX_SCCACHE:-null}" \
--arg devTools '[]' \
--arg benchmarkTools '[]' \
--arg opensslPkg '(import <nixpkgs> {}).${{ matrix.opensslPkg }}' \
${{ endsWith(matrix.system, '-darwin') && '--arg withAmaro false --arg withLief false --arg withSQLite false --arg withFFI false --arg extraConfigFlags ''["--without-inspector" "--without-node-options"]'' \' || '\' }}
--run '
make -C "$TAR_DIR" run-ci -j4 V=1 TEST_CI_ARGS="-p actions --measure-flakiness 9 --skip-tests=$CI_SKIP_TESTS"
' "$TAR_DIR/shell.nix"
2 changes: 2 additions & 0 deletions shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
withFFI ? true,
withSSL ? true,
withTemporal ? false,
opensslPkg ? pkgs.openssl_3_5,
sharedLibDeps ? (
import ./tools/nix/sharedLibDeps.nix {
inherit
Expand All @@ -29,6 +30,7 @@
withFFI
withSSL
withTemporal
opensslPkg
;
}
),
Expand Down
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
32 changes: 22 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,22 @@ const assert = require('assert');
const crypto = require('crypto');
const { hasOpenSSL } = require('../common/crypto');

// Error code for a key-type mismatch during ECDH/EdDH derivation. 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).
// TODO(panva): report the OpenSSL 4.0 generic internal error behavior
// upstream and tighten this check once 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 +413,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 +555,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
Loading