diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index d35d601abc70..7a4193813b5e 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -4998,11 +4998,7 @@ bool SSLPointer::isServer() const { EVPKeyPointer SSLPointer::getPeerTempKey() const { if (!ssl_) return {}; EVP_PKEY* raw_key = nullptr; -#ifndef OPENSSL_IS_BORINGSSL if (!SSL_get_peer_tmp_key(get(), &raw_key)) return {}; -#else - if (!SSL_get_server_tmp_key(get(), &raw_key)) return {}; -#endif return EVPKeyPointer(raw_key); } diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc index ad056b5610bc..759353f08f03 100644 --- a/src/crypto/crypto_common.cc +++ b/src/crypto/crypto_common.cc @@ -59,6 +59,9 @@ MaybeLocal GetValidationErrorReason(Environment* env, int err) { // Suggest --use-system-ca if the error indicates a certificate issue bool suggest_system_ca = (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) || +#ifdef OPENSSL_IS_BORINGSSL + (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) || +#endif (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) && !env->options()->use_system_ca); diff --git a/test/client-proxy/test-https-proxy-request-handshake-failure.mjs b/test/client-proxy/test-https-proxy-request-handshake-failure.mjs index 251d136afaa6..fdc427aea0df 100644 --- a/test/client-proxy/test-https-proxy-request-handshake-failure.mjs +++ b/test/client-proxy/test-https-proxy-request-handshake-failure.mjs @@ -13,6 +13,7 @@ if (!common.hasCrypto) // https must be dynamically imported so that builds without crypto support // can skip it. const { default: https } = await import('node:https'); +const { untrustedLeafErrorCodePattern } = await import('../common/tls.js'); const server = https.createServer({ cert: fixtures.readKey('agent8-cert.pem'), @@ -36,8 +37,10 @@ const { code, signal, stderr, stdout } = await runProxiedRequest({ HTTPS_PROXY: `http://localhost:${proxy.address().port}`, }); -// The proxy client should get a UNABLE_TO_VERIFY_LEAF_SIGNATURE during TLS handshake. -assert.match(stderr, /UNABLE_TO_VERIFY_LEAF_SIGNATURE/); +// The proxy client should report the untrusted leaf during the TLS handshake. +const errorCode = stderr.match(/code: '([^']+)'/); +assert(errorCode, stderr); +assert.match(errorCode[1], untrustedLeafErrorCodePattern); assert.strictEqual(stdout, ''); assert.strictEqual(code, 0); assert.strictEqual(signal, null); diff --git a/test/common/boringssl.js b/test/common/boringssl.js index ab7f0505b0ce..53d5044e545b 100644 --- a/test/common/boringssl.js +++ b/test/common/boringssl.js @@ -167,33 +167,6 @@ function testEphemeralKeyInfo() { })); } -/** - * The protocol matrix tests cover OpenSSL behavior for legacy TLS protocols. - * For BoringSSL we only need to exhibit that a TLSv1-only client cannot connect - * to a server whose minimum protocol is TLS 1.2; the client receives the - * protocol-version alert instead of the OpenSSL version-specific matrix. - */ -function testLegacyProtocolUnsupported() { - const server = tls.createServer({ - key: fixtures.readKey('agent2-key.pem'), - cert: fixtures.readKey('agent2-cert.pem'), - minVersion: 'TLSv1.2', - }, common.mustNotCall()); - - server.on('tlsClientError', common.mustCall()); - server.listen(0, common.mustCall(() => { - const client = tls.connect({ - port: server.address().port, - rejectUnauthorized: false, - secureProtocol: 'TLSv1_method', - }, common.mustNotCall()); - client.on('error', common.mustCall((err) => { - assert.strictEqual(err.code, 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION'); - server.close(); - })); - })); -} - /** * BoringSSL can load a multi-PFX option well enough to serve the ECDSA * identity, but it does not provide the same OpenSSL multi-identity selection @@ -335,7 +308,6 @@ module.exports = { assertNoCipherMatch, assertOpenSSLSecurityLevelsUnsupported, testEphemeralKeyInfo, - testLegacyProtocolUnsupported, testMultiPfxSelectionDifference, testPskTls13Unsupported, testRenegotiationUnsupported, diff --git a/test/common/tls.js b/test/common/tls.js index 8568659d13cc..fd69d6749e94 100644 --- a/test/common/tls.js +++ b/test/common/tls.js @@ -4,6 +4,14 @@ const crypto = require('crypto'); const net = require('net'); const assert = require('assert'); +const { isBoringSSL } = require('./crypto'); + +// Newer BoringSSL reports the missing issuer directly for a lone, +// non-self-signed leaf. Older BoringSSL and OpenSSL replace it with a leaf +// signature verification error. +exports.untrustedLeafErrorCodePattern = isBoringSSL ? + /^UNABLE_TO_(?:VERIFY_LEAF_SIGNATURE|GET_ISSUER_CERT_LOCALLY)$/ : + /^UNABLE_TO_VERIFY_LEAF_SIGNATURE$/; exports.ccs = Buffer.from('140303000101', 'hex'); diff --git a/test/internet/test-tls-add-ca-cert.js b/test/internet/test-tls-add-ca-cert.js index 2515758ec86c..28cb8c4502f6 100644 --- a/test/internet/test-tls-add-ca-cert.js +++ b/test/internet/test-tls-add-ca-cert.js @@ -33,7 +33,7 @@ tls.connect(opts, common.mustCall(end)); // The .ca option replaces the well-known roots, so connection fails. opts.ca = caCert; tls.connect(opts, fail).on('error', common.mustCall((err) => { - assert.strictEqual(err.message, 'unable to get local issuer certificate'); + assert.strictEqual(err.code, 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'); })); function fail() { diff --git a/test/parallel/test-crypto-dh-curves.js b/test/parallel/test-crypto-dh-curves.js index 22b05fb89609..ef5d0323d33f 100644 --- a/test/parallel/test-crypto-dh-curves.js +++ b/test/parallel/test-crypto-dh-curves.js @@ -21,12 +21,14 @@ const p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; crypto.createDiffieHellman(p, 'hex'); -if (!isBoringSSL) { +{ + // BoringSSL also flags these primes as unsuitable for generator 2. + const generatorError = isBoringSSL ? DH_NOT_SUITABLE_GENERATOR : 0; const notPrime = Buffer.from(p, 'hex'); notPrime[notPrime.length - 1] = 0xfd; assert.strictEqual( crypto.createDiffieHellman(notPrime, Buffer.from([2])).verifyError, - DH_CHECK_P_NOT_PRIME); + DH_CHECK_P_NOT_PRIME | generatorError); const notSafePrime = Buffer.from( 'd2d6d13e1c1e0bbb63c742199dee010411f089ac74f0f7213348388280700fd6' + @@ -34,7 +36,7 @@ if (!isBoringSSL) { 'hex'); assert.strictEqual( crypto.createDiffieHellman(notSafePrime, Buffer.from([2])).verifyError, - DH_CHECK_P_NOT_SAFE_PRIME); + DH_CHECK_P_NOT_SAFE_PRIME | generatorError); } const group = crypto.getDiffieHellman('modp14'); @@ -95,7 +97,7 @@ if (availableCurves.has('Oakley-EC2N-3')) { } // Test ECDH -if (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) { +if (availableCurves.has('prime256v1')) { const ecdh1 = crypto.createECDH('prime256v1'); const ecdh2 = crypto.createECDH('prime256v1'); const key1 = ecdh1.generateKeys(); @@ -109,8 +111,15 @@ if (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) { assert.strictEqual(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4); let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0]; assert(firstByte === 2 || firstByte === 3); - firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0]; - assert(firstByte === 6 || firstByte === 7); + if (isBoringSSL) { + assert.throws(() => ecdh1.getPublicKey('buffer', 'hybrid'), { + code: 'ERR_CRYPTO_OPERATION_FAILED', + message: 'Failed to get public key length', + }); + } else { + firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0]; + assert(firstByte === 6 || firstByte === 7); + } // Format value should be string assert.throws( @@ -121,127 +130,128 @@ if (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) { message: 'Invalid ECDH format: 10' }); - // ECDH should check that point is on curve - const ecdh3 = crypto.createECDH('secp256k1'); - if (hasFIPS(3)) { - assert.throws(() => ecdh3.generateKeys(), { - code: 'ERR_CRYPTO_OPERATION_FAILED', - }); - } else { - const key3 = ecdh3.generateKeys(); - - assert.throws( - () => ecdh2.computeSecret(key3, 'latin1', 'buffer'), - { - code: 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY', - name: 'Error', - message: 'Public key is not valid for specified curve' + // ECDH should allow .setPrivateKey()/.setPublicKey() + const ecdh4 = crypto.createECDH('prime256v1'); + + ecdh4.setPrivateKey(ecdh1.getPrivateKey()); + ecdh4.setPublicKey(ecdh1.getPublicKey()); + + const ecdh4Secret = ecdh4.computeSecret(ecdh2.getPublicKey()); + assert.deepStrictEqual(ecdh4.computeSecret(ecdh2.getPublicKey()), ecdh4Secret); + + if (availableCurves.has('secp256k1')) { + // ECDH should check that point is on curve + const ecdh3 = crypto.createECDH('secp256k1'); + if (hasFIPS(3)) { + assert.throws(() => ecdh3.generateKeys(), { + code: 'ERR_CRYPTO_OPERATION_FAILED', }); + } else { + const key3 = ecdh3.generateKeys(); + + assert.throws( + () => ecdh2.computeSecret(key3, 'latin1', 'buffer'), + { + code: 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY', + name: 'Error', + message: 'Public key is not valid for specified curve' + }); + + assert.throws(() => { + ecdh4.setPublicKey(ecdh3.getPublicKey()); + }, { message: 'Failed to convert Buffer to EC_POINT' }); + assert.deepStrictEqual(ecdh4.computeSecret(ecdh2.getPublicKey()), + ecdh4Secret); + + // Verify that we can use ECDH without having to use newly generated keys. + const ecdh5 = crypto.createECDH('secp256k1'); + + // Verify errors are thrown when retrieving keys from an uninitialized object. + assert.throws(() => { + ecdh5.getPublicKey(); + }, /^Error: Failed to get ECDH public key$/); - // ECDH should allow .setPrivateKey()/.setPublicKey() - const ecdh4 = crypto.createECDH('prime256v1'); - - ecdh4.setPrivateKey(ecdh1.getPrivateKey()); - ecdh4.setPublicKey(ecdh1.getPublicKey()); - - const ecdh4Secret = ecdh4.computeSecret(ecdh2.getPublicKey()); - assert.deepStrictEqual(ecdh4.computeSecret(ecdh2.getPublicKey()), - ecdh4Secret); - - assert.throws(() => { - ecdh4.setPublicKey(ecdh3.getPublicKey()); - }, { message: 'Failed to convert Buffer to EC_POINT' }); - assert.deepStrictEqual(ecdh4.computeSecret(ecdh2.getPublicKey()), - ecdh4Secret); - - // Verify that we can use ECDH without having to use newly generated keys. - const ecdh5 = crypto.createECDH('secp256k1'); - - // Verify errors are thrown when retrieving keys from an uninitialized object. - assert.throws(() => { - ecdh5.getPublicKey(); - }, /^Error: Failed to get ECDH public key$/); - - assert.throws(() => { - ecdh5.getPrivateKey(); - }, /^Error: Failed to get ECDH private key$/); - - // A valid private key for the secp256k1 curve. - const cafebabeKey = 'cafebabe'.repeat(8); - // Associated compressed and uncompressed public keys (points). - const cafebabePubPtComp = - '03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3'; - const cafebabePubPtUnComp = - '04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' + - '2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d'; - ecdh5.setPrivateKey(cafebabeKey, 'hex'); - assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey); - // Show that the public point (key) is generated while setting the - // private key. - assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); - - // Compressed and uncompressed public points/keys for other party's - // private key. - // 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF - const peerPubPtComp = - '02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae'; - const peerPubPtUnComp = - '04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' + - 'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e'; - - const sharedSecret = - '1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970'; - - assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'), - sharedSecret); - assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'), - sharedSecret); - assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'), - sharedSecret); - - // Verify that we still have the same key pair as before the computation. - assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey); - assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); - - // Verify setting and getting compressed and non-compressed serializations. - ecdh5.setPublicKey(cafebabePubPtComp, 'hex'); - assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); - assert.strictEqual( - ecdh5.getPublicKey('hex', 'compressed'), - cafebabePubPtComp - ); - ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex'); - assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); - assert.strictEqual( - ecdh5.getPublicKey('hex', 'compressed'), - cafebabePubPtComp - ); - - // Show why allowing the public key to be set on this type - // does not make sense. - ecdh5.setPublicKey(peerPubPtComp, 'hex'); - assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp); - assert.throws(() => { - // Error because the public key does not match the private key anymore. - ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'); - }, /Invalid key pair/); - - // Set to a valid key to show that later attempts to set an invalid key are - // rejected. - ecdh5.setPrivateKey(cafebabeKey, 'hex'); - - // Some invalid private keys for the secp256k1 curve. - const errMessage = /Private key is not valid for specified curve/; - ['0000000000000000000000000000000000000000000000000000000000000000', - 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', - 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', - ].forEach((element) => { assert.throws(() => { - ecdh5.setPrivateKey(element, 'hex'); - }, errMessage); - // Verify object state did not change. + ecdh5.getPrivateKey(); + }, /^Error: Failed to get ECDH private key$/); + + // A valid private key for the secp256k1 curve. + const cafebabeKey = 'cafebabe'.repeat(8); + // Associated compressed and uncompressed public keys (points). + const cafebabePubPtComp = + '03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3'; + const cafebabePubPtUnComp = + '04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' + + '2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d'; + ecdh5.setPrivateKey(cafebabeKey, 'hex'); assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey); - }); + // Show that the public point (key) is generated while setting the + // private key. + assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); + + // Compressed and uncompressed public points/keys for other party's + // private key. + // 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF + const peerPubPtComp = + '02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae'; + const peerPubPtUnComp = + '04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' + + 'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e'; + + const sharedSecret = + '1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970'; + + assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'), + sharedSecret); + assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'), + sharedSecret); + assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'), + sharedSecret); + + // Verify that we still have the same key pair as before the computation. + assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey); + assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); + + // Verify setting and getting compressed and non-compressed serializations. + ecdh5.setPublicKey(cafebabePubPtComp, 'hex'); + assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); + assert.strictEqual( + ecdh5.getPublicKey('hex', 'compressed'), + cafebabePubPtComp + ); + ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex'); + assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); + assert.strictEqual( + ecdh5.getPublicKey('hex', 'compressed'), + cafebabePubPtComp + ); + + // Show why allowing the public key to be set on this type + // does not make sense. + ecdh5.setPublicKey(peerPubPtComp, 'hex'); + assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp); + assert.throws(() => { + // Error because the public key does not match the private key anymore. + ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'); + }, /Invalid key pair/); + + // Set to a valid key to show that later attempts to set an invalid key are + // rejected. + ecdh5.setPrivateKey(cafebabeKey, 'hex'); + + // Some invalid private keys for the secp256k1 curve. + const errMessage = /Private key is not valid for specified curve/; + ['0000000000000000000000000000000000000000000000000000000000000000', + 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', + 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', + ].forEach((element) => { + assert.throws(() => { + ecdh5.setPrivateKey(element, 'hex'); + }, errMessage); + // Verify object state did not change. + assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey); + }); + } } } diff --git a/test/parallel/test-crypto-dh-group-setters.js b/test/parallel/test-crypto-dh-group-setters.js index ccc370e2352d..f759d29be0ff 100644 --- a/test/parallel/test-crypto-dh-group-setters.js +++ b/test/parallel/test-crypto-dh-group-setters.js @@ -1,19 +1,14 @@ 'use strict'; const common = require('../common'); -const { isBoringSSL } = require('../common/crypto'); if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); const crypto = require('crypto'); -if (isBoringSSL) { - common.skip('Skipping unsupported Diffie-Hellman tests'); -} - // Unlike DiffieHellman, DiffieHellmanGroup does not have any setters. -const dhg = crypto.getDiffieHellman('modp1'); +const dhg = crypto.getDiffieHellman('modp5'); assert.strictEqual(dhg.constructor, crypto.DiffieHellmanGroup); assert.strictEqual(dhg.setPrivateKey, undefined); assert.strictEqual(dhg.setPublicKey, undefined); diff --git a/test/parallel/test-crypto-dh-modp2-views.js b/test/parallel/test-crypto-dh-modp2-views.js index ce2d8823beec..0ce2f3d8af63 100644 --- a/test/parallel/test-crypto-dh-modp2-views.js +++ b/test/parallel/test-crypto-dh-modp2-views.js @@ -8,7 +8,11 @@ const crypto = require('crypto'); const { hasFIPS, modp2buf, isBoringSSL } = require('../common/crypto'); if (isBoringSSL) { - common.skip('Skipping unsupported Diffie-Hellman tests'); + // BoringSSL omits this named group but accepts its raw parameters. + assert.throws(() => crypto.createDiffieHellmanGroup('modp2'), { + code: 'ERR_CRYPTO_UNKNOWN_DH_GROUP', + message: 'Unknown DH group', + }); } if (hasFIPS(3)) { @@ -16,7 +20,8 @@ if (hasFIPS(3)) { code: 'ERR_INVALID_ARG_VALUE', }); } else { - const modp2 = crypto.createDiffieHellmanGroup('modp2'); + const modp2 = isBoringSSL ? crypto.createDiffieHellman(modp2buf, 2) : + crypto.createDiffieHellmanGroup('modp2'); const views = common.getArrayBufferViews(modp2buf); for (const buf of [modp2buf, ...views]) { diff --git a/test/parallel/test-crypto-dh-modp2.js b/test/parallel/test-crypto-dh-modp2.js index a0ec31a1eb4f..45e6eee319bf 100644 --- a/test/parallel/test-crypto-dh-modp2.js +++ b/test/parallel/test-crypto-dh-modp2.js @@ -8,7 +8,11 @@ const crypto = require('crypto'); const { hasFIPS, modp2buf, isBoringSSL } = require('../common/crypto'); if (isBoringSSL) { - common.skip('Skipping unsupported Diffie-Hellman tests'); + // BoringSSL omits this named group but accepts its raw parameters. + assert.throws(() => crypto.createDiffieHellmanGroup('modp2'), { + code: 'ERR_CRYPTO_UNKNOWN_DH_GROUP', + message: 'Unknown DH group', + }); } if (hasFIPS(3)) { @@ -16,7 +20,8 @@ if (hasFIPS(3)) { code: 'ERR_INVALID_ARG_VALUE', }); } else { - const modp2 = crypto.createDiffieHellmanGroup('modp2'); + const modp2 = isBoringSSL ? crypto.createDiffieHellman(modp2buf, 2) : + crypto.createDiffieHellmanGroup('modp2'); { // Ensure specific generator (buffer) works as expected. diff --git a/test/parallel/test-crypto-getcipherinfo.js b/test/parallel/test-crypto-getcipherinfo.js index faf45c766c5c..4c8e0c01c085 100644 --- a/test/parallel/test-crypto-getcipherinfo.js +++ b/test/parallel/test-crypto-getcipherinfo.js @@ -54,21 +54,13 @@ if (ciphers.includes('aes-128-wrap-inv')) { } assert(!ciphers.some((cipher) => /^\d+(?:\.\d+)+$/.test(cipher))); -if (!isBoringSSL) { - // A failed provider fetch must not contaminate the OpenSSL error queue. - assert.throws(() => createHash('sha256', { outputLength: 28 }), { - code: 'ERR_OSSL_EVP_NOT_XOF_OR_INVALID_LENGTH', - }); -} +// A failed provider fetch must not contaminate the OpenSSL error queue. +assert.throws(() => createHash('sha256', { outputLength: 28 }), { + code: 'ERR_OSSL_EVP_NOT_XOF_OR_INVALID_LENGTH', +}); for (const cipher of ciphers) { const info = getCipherInfo(cipher); - if (isBoringSSL && !info) { - // BoringSSL reports some legacy ciphers in getCiphers() but returns no - // info for them (e.g. des-ede3, des-ede3-ecb, rc2-40-cbc). - common.printSkipMessage(`Skipping unsupported ${cipher} test case`); - continue; - } assert(info); if (info.nid !== undefined) { const info2 = getCipherInfo(info.nid); diff --git a/test/parallel/test-crypto-key-objects-raw.js b/test/parallel/test-crypto-key-objects-raw.js index 4a129d1a6185..7cf4e7bb1693 100644 --- a/test/parallel/test-crypto-key-objects-raw.js +++ b/test/parallel/test-crypto-key-objects-raw.js @@ -121,12 +121,8 @@ if (hasOpenSSL(3, 5)) { { const unsupportedKeyTypes = [ ['rsa', 'rsa_public_2048.pem', 'rsa_private_2048.pem'], + ['dsa', 'dsa_public.pem', 'dsa_private.pem'], ]; - if (!isBoringSSL) { - unsupportedKeyTypes.push(['dsa', 'dsa_public.pem', 'dsa_private.pem']); - } else { - common.printSkipMessage('Skipping unsupported dsa test case'); - } for (const [type, pub, priv] of unsupportedKeyTypes) { const pubKeyObj = crypto.createPublicKey( fixtures.readKey(pub, 'ascii')); diff --git a/test/parallel/test-crypto-x509.js b/test/parallel/test-crypto-x509.js index 3f58a6cf0ccd..1467fd6104db 100644 --- a/test/parallel/test-crypto-x509.js +++ b/test/parallel/test-crypto-x509.js @@ -177,10 +177,8 @@ for (const [commonName, property] of [ assert.deepStrictEqual(x509.raw, der); - if (!isBoringSSL) { - assert.deepStrictEqual(x509.validFromDate, new Date('2022-09-03T21:40:37Z')); - assert.deepStrictEqual(x509.validToDate, new Date('2296-06-17T21:40:37Z')); - } + assert.deepStrictEqual(x509.validFromDate, new Date('2022-09-03T21:40:37Z')); + assert.deepStrictEqual(x509.validToDate, new Date('2296-06-17T21:40:37Z')); assert(x509.publicKey); assert.strictEqual(x509.publicKey.type, 'public'); @@ -565,10 +563,8 @@ UidvpWWipVLZgK+oDks+bKTobcoXGW9oXobiIYqslXPy -----END CERTIFICATE-----`.trim(); const c1 = new X509Certificate(certPemUTCTime); - if (!isBoringSSL) { - assert.deepStrictEqual(c1.validFromDate, new Date('1949-12-25T23:59:58Z')); - assert.deepStrictEqual(c1.validToDate, new Date('1950-01-01T23:59:58Z')); - } + assert.deepStrictEqual(c1.validFromDate, new Date('1949-12-25T23:59:58Z')); + assert.deepStrictEqual(c1.validToDate, new Date('1950-01-01T23:59:58Z')); // The GeneralizedTime format is used for dates in 2050 or later. const certPemGeneralizedTime = `-----BEGIN CERTIFICATE----- @@ -602,10 +598,8 @@ CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW -----END CERTIFICATE-----`.trim(); const c2 = new X509Certificate(certPemGeneralizedTime); - if (!isBoringSSL) { - assert.deepStrictEqual(c2.validFromDate, new Date('2049-12-26T00:00:01Z')); - assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z')); - } + assert.deepStrictEqual(c2.validFromDate, new Date('2049-12-26T00:00:01Z')); + assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z')); } { diff --git a/test/parallel/test-http2-session-reuse-different-authority.js b/test/parallel/test-http2-session-reuse-different-authority.js index d76f17a728f3..5ad46ecbe50a 100644 --- a/test/parallel/test-http2-session-reuse-different-authority.js +++ b/test/parallel/test-http2-session-reuse-different-authority.js @@ -5,6 +5,7 @@ if (!common.hasCrypto) const assert = require('assert'); const fixtures = require('../common/fixtures'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); const h2 = require('http2'); const tls = require('tls'); const { once } = require('events'); @@ -125,7 +126,7 @@ server.on('stream', (stream) => { session: first.session, }), { - code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + code: untrustedLeafErrorCodePattern, }, ); @@ -136,7 +137,7 @@ server.on('stream', (stream) => { maxVersion: 'TLSv1.2', }), { - code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + code: untrustedLeafErrorCodePattern, }, ); } finally { diff --git a/test/parallel/test-https-agent-create-connection.js b/test/parallel/test-https-agent-create-connection.js index 56e967476c8b..628cc14cecfe 100644 --- a/test/parallel/test-https-agent-create-connection.js +++ b/test/parallel/test-https-agent-create-connection.js @@ -5,6 +5,8 @@ const fixtures = require('../common/fixtures'); if (!common.hasCrypto) common.skip('missing crypto'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); + const assert = require('assert'); const https = require('https'); @@ -17,7 +19,6 @@ const options = { const expectedHeader = /^HTTP\/1\.1 200 OK/; const expectedBody = /hello world\n/; -const expectCertError = /^UNABLE_TO_VERIFY_LEAF_SIGNATURE$/; function checkRequest(socket, server) { let result = ''; @@ -112,7 +113,7 @@ function createServer() { const options = null; const socket = agent.createConnection(port, host, options); socket.on('error', common.mustCall((e) => { - assert.match(e.code, expectCertError); + assert.match(e.code, untrustedLeafErrorCodePattern); server.close(); })); })); @@ -127,7 +128,7 @@ function createServer() { const options = undefined; const socket = agent.createConnection(port, host, options); socket.on('error', common.mustCall((e) => { - assert.match(e.code, expectCertError); + assert.match(e.code, untrustedLeafErrorCodePattern); server.close(); })); })); diff --git a/test/parallel/test-https-options-boolean-check.js b/test/parallel/test-https-options-boolean-check.js index 776e966211c7..f4193fdf737d 100644 --- a/test/parallel/test-https-options-boolean-check.js +++ b/test/parallel/test-https-options-boolean-check.js @@ -42,20 +42,6 @@ const keyDataView = toDataView(keyBuff); const certDataView = toDataView(certBuff); const caArrDataView = toDataView(caCert); -function filterBoringSSLKeyCertArrayCases(options, setName) { - if (!isBoringSSL) - return options; - - // The array-valued cases exercise multi-identity key/cert handling. - // BoringSSL may reject those cases with backend key/cert mismatch errors - // before the boolean/type validation this test is targeting. Keep the scalar - // cases so https.createServer() option type validation is still covered. - common.printSkipMessage( - `BoringSSL: skipping ${setName} key/cert array cases`); - return options.filter(([key, cert]) => !Array.isArray(key) && - !Array.isArray(cert)); -} - // Checks to ensure https.createServer doesn't throw an error // Format ['key', 'cert'] const validOptions = [ @@ -72,18 +58,24 @@ const validOptions = [ [keyDataView, certDataView], [keyDataView, false], [false, certDataView], - [[keyBuff, keyBuff2], [certBuff, certBuff2]], - [[keyStr, keyStr2], [certStr, certStr2]], [[keyStr, keyStr2], false], [false, [certStr, certStr2]], [[{ pem: keyBuff }], false], [[{ pem: keyBuff }, { pem: keyBuff }], false], ]; -filterBoringSSLKeyCertArrayCases(validOptions, 'valid') - .forEach(([key, cert]) => { - https.createServer({ key, cert }); - }); +// Node's BoringSSL setup keeps one identity, so mixed RSA/EC key and +// certificate arrays fail with a key-type mismatch before option validation. +if (!isBoringSSL) { + validOptions.push( + [[keyBuff, keyBuff2], [certBuff, certBuff2]], + [[keyStr, keyStr2], [certStr, certStr2]], + ); +} + +validOptions.forEach(([key, cert]) => { + https.createServer({ key, cert }); +}); // Checks to ensure https.createServer predictably throws an error // Format ['key', 'cert', 'expected message'] @@ -96,14 +88,18 @@ const invalidKeyOptions = [ [true, false], [{ pem: keyBuff }, false], [1, false], - [[keyBuff, true], [certBuff, certBuff2], 1], [[true, keyStr2], [certStr, certStr2], 0], [[true, false], [certBuff, certBuff2], 0], [true, [certBuff, certBuff2]], ]; -for (const [key, cert, index] of - filterBoringSSLKeyCertArrayCases(invalidKeyOptions, 'invalid key')) { +// With both certificates loaded, BoringSSL rejects the RSA key against the +// last (EC) certificate before reaching the invalid second key. +if (!isBoringSSL) { + invalidKeyOptions.push([[keyBuff, true], [certBuff, certBuff2], 1]); +} + +for (const [key, cert, index] of invalidKeyOptions) { const val = index === undefined ? key : key[index]; assert.throws(() => { https.createServer({ key, cert }); @@ -131,8 +127,7 @@ const invalidCertOptions = [ [[keyStr, keyStr2], true], ]; -for (const [key, cert, index] of - filterBoringSSLKeyCertArrayCases(invalidCertOptions, 'invalid cert')) { +for (const [key, cert, index] of invalidCertOptions) { const val = index === undefined ? cert : cert[index]; assert.throws(() => { https.createServer({ key, cert }); diff --git a/test/parallel/test-https-session-reuse-different-servername.js b/test/parallel/test-https-session-reuse-different-servername.js index 138acd693501..5b27c9ae94d0 100644 --- a/test/parallel/test-https-session-reuse-different-servername.js +++ b/test/parallel/test-https-session-reuse-different-servername.js @@ -5,6 +5,7 @@ if (!common.hasCrypto) const assert = require('assert'); const fixtures = require('../common/fixtures'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); const https = require('https'); const tls = require('tls'); const { once } = require('events'); @@ -104,7 +105,7 @@ const server = https.createServer({ ca: [load('ca1-cert.pem')], }), { - code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + code: untrustedLeafErrorCodePattern, }, ); @@ -116,7 +117,7 @@ const server = https.createServer({ ca: [load('ca1-cert.pem')], }), { - code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + code: untrustedLeafErrorCodePattern, }, ); } finally { diff --git a/test/parallel/test-https-simple.js b/test/parallel/test-https-simple.js index b0562a1cd981..e9ccfbee0620 100644 --- a/test/parallel/test-https-simple.js +++ b/test/parallel/test-https-simple.js @@ -26,6 +26,8 @@ const fixtures = require('../common/fixtures'); if (!common.hasCrypto) common.skip('missing crypto'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); + const assert = require('assert'); const https = require('https'); @@ -93,7 +95,7 @@ server.listen(0, common.mustCall(() => { const checkCertReq = https.request(options, common.mustNotCall()).end(); checkCertReq.on('error', common.mustCall((e) => { - assert.strictEqual(e.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(e.code, untrustedLeafErrorCodePattern); done(); })); })); diff --git a/test/parallel/test-https-strict.js b/test/parallel/test-https-strict.js index a72168289d54..2f1da381c150 100644 --- a/test/parallel/test-https-strict.js +++ b/test/parallel/test-https-strict.js @@ -25,6 +25,8 @@ const fixtures = require('../common/fixtures'); if (!common.hasCrypto) common.skip('missing crypto'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); + // Disable strict server certificate validation by the client process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; @@ -148,7 +150,11 @@ function makeReq(path, port, error, host, ca) { server.expectCount++; req.on('response', common.mustCall((res) => { - assert.strictEqual(res.connection.authorizationError, error); + if (error instanceof RegExp) { + assert.match(res.connection.authorizationError, error); + } else { + assert.strictEqual(res.connection.authorizationError, error); + } responseErrors[path] = res.connection.authorizationError; pending--; if (pending === 0) { @@ -167,7 +173,7 @@ function allListening() { const port3 = server3.address().port; // server1: host 'agent1', signed by ca1 - makeReq('/inv1', port1, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + makeReq('/inv1', port1, untrustedLeafErrorCodePattern); makeReq('/inv1-ca1', port1, 'ERR_TLS_CERT_ALTNAME_INVALID', null, ca1); makeReq('/inv1-ca1ca2', port1, 'ERR_TLS_CERT_ALTNAME_INVALID', @@ -175,7 +181,7 @@ function allListening() { makeReq('/val1-ca1', port1, null, 'agent1', ca1); makeReq('/val1-ca1ca2', port1, null, 'agent1', [ca1, ca2]); makeReq('/inv1-ca2', port1, - 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', 'agent1', ca2); + untrustedLeafErrorCodePattern, 'agent1', ca2); // server2: self-signed, host = 'agent2' // doesn't matter that thename matches, all of these will error. @@ -186,14 +192,14 @@ function allListening() { 'agent2', [ca1, ca2]); // server3: host 'agent3', signed by ca2 - makeReq('/inv3', port3, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + makeReq('/inv3', port3, untrustedLeafErrorCodePattern); makeReq('/inv3-ca2', port3, 'ERR_TLS_CERT_ALTNAME_INVALID', null, ca2); makeReq('/inv3-ca1ca2', port3, 'ERR_TLS_CERT_ALTNAME_INVALID', null, [ca1, ca2]); makeReq('/val3-ca2', port3, null, 'agent3', ca2); makeReq('/val3-ca1ca2', port3, null, 'agent3', [ca1, ca2]); makeReq('/inv3-ca1', port3, - 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', 'agent1', ca1); + untrustedLeafErrorCodePattern, 'agent1', ca1); } diff --git a/test/parallel/test-tls-addca.js b/test/parallel/test-tls-addca.js index a99d53f55d3f..c8994b85dfea 100644 --- a/test/parallel/test-tls-addca.js +++ b/test/parallel/test-tls-addca.js @@ -9,6 +9,7 @@ const fixtures = require('../common/fixtures'); const { assert, connect, keys, tls } = require(fixtures.path('tls-connect')); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); const contextWithoutCert = tls.createSecureContext({}); const contextWithCert = tls.createSecureContext({}); @@ -34,7 +35,7 @@ connect({ server: serverOptions, }, common.mustCall((err, pair, cleanup) => { assert(err); - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); cleanup(); // This time it should connect because contextWithCert includes the needed CA diff --git a/test/parallel/test-tls-client-auth.js b/test/parallel/test-tls-client-auth.js index da06156e2e07..13f649daad13 100644 --- a/test/parallel/test-tls-client-auth.js +++ b/test/parallel/test-tls-client-auth.js @@ -11,6 +11,7 @@ const { hasOpenSSL, isBoringSSL } = require('../common/crypto'); const { assert, connect, keys, tls } = require(fixtures.path('tls-connect')); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); // Use ec10 and agent10, they are the only identities with intermediate CAs. const client = keys.ec10; @@ -185,7 +186,7 @@ connect({ cert: server.single, }, }, common.mustCall((err, pair, cleanup) => { - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); return cleanup(); })); diff --git a/test/parallel/test-tls-client-cert-resumption.js b/test/parallel/test-tls-client-cert-resumption.js index 790809678d66..223567c6ca1d 100644 --- a/test/parallel/test-tls-client-cert-resumption.js +++ b/test/parallel/test-tls-client-cert-resumption.js @@ -22,6 +22,7 @@ const assert = require('assert'); const crypto = require('crypto'); const tls = require('tls'); const fixtures = require('../common/fixtures'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); const { once } = require('events'); const ca = fixtures.readKey('ca1-cert.pem'); @@ -47,7 +48,7 @@ const CLIENTS = { cert: fixtures.readKey('agent3-cert.pem'), }, authorized: false, - authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + authorizationError: untrustedLeafErrorCodePattern, peerCN: 'agent3', }, missing: { // No client certificate @@ -93,7 +94,11 @@ async function testResumption(version, name) { // Both conns must report same expected auth state: assert.strictEqual(socket.authorized, authorized, where); - assert.strictEqual(socket.authorizationError, authorizationError, where); + if (authorizationError instanceof RegExp) { + assert.match(socket.authorizationError, authorizationError, where); + } else { + assert.strictEqual(socket.authorizationError, authorizationError, where); + } const peer = socket.getPeerCertificate(); if (peerCN === undefined) assert.deepStrictEqual(peer, {}, where); diff --git a/test/parallel/test-tls-friendly-error-message.js b/test/parallel/test-tls-friendly-error-message.js index 84471da487b2..612f520fe66f 100644 --- a/test/parallel/test-tls-friendly-error-message.js +++ b/test/parallel/test-tls-friendly-error-message.js @@ -25,6 +25,7 @@ if (!common.hasCrypto) common.skip('missing crypto'); const fixtures = require('../common/fixtures'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); const assert = require('assert'); const tls = require('tls'); @@ -39,6 +40,7 @@ tls.createServer({ key, cert }).on('connection', common.mustCall(function() { })).listen(0, common.mustCall(function() { const options = { port: this.address().port, rejectUnauthorized: true }; tls.connect(options).on('error', common.mustCall(function(err) { - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); + assert.match(err.message, /try running Node\.js with --use-system-ca/); })); })); diff --git a/test/parallel/test-tls-getprotocol.js b/test/parallel/test-tls-getprotocol.js index e3e0a1fa2418..6695d7a37bb5 100644 --- a/test/parallel/test-tls-getprotocol.js +++ b/test/parallel/test-tls-getprotocol.js @@ -13,7 +13,7 @@ const tls = require('tls'); const fixtures = require('../common/fixtures'); const fips3 = hasFIPS(3); -let clientConfigs = [ +const clientConfigs = [ { secureProtocol: 'TLSv1_method', version: 'TLSv1', @@ -28,24 +28,16 @@ let clientConfigs = [ }, ]; -if (isBoringSSL) { - // Remove the TLSv1 and TLSv1.1 cases. BoringSSL does not negotiate those - // legacy protocols in this configuration; keep TLSv1.2 to cover getProtocol() - // on a successful BoringSSL TLS handshake. - common.printSkipMessage('BoringSSL: skipping TLSv1/TLSv1.1 getProtocol cases'); - clientConfigs = clientConfigs.filter(({ version }) => version === 'TLSv1.2'); -} - const serverConfig = { - secureProtocol: 'TLS_method', + // BoringSSL's library default minimum is TLSv1.2, so enable legacy versions + // explicitly instead of relying on TLS_method's default minimum. + ...(isBoringSSL ? { minVersion: 'TLSv1' } : { secureProtocol: 'TLS_method' }), key: fixtures.readKey('agent2-key.pem'), cert: fixtures.readKey('agent2-cert.pem') }; -if (!isBoringSSL) { - serverConfig.ciphers = fips3 ? - 'ECDHE-RSA-AES256-GCM-SHA384' : 'RSA@SECLEVEL=0'; -} +serverConfig.ciphers = fips3 ? + 'ECDHE-RSA-AES256-GCM-SHA384' : isBoringSSL ? 'RSA' : 'RSA@SECLEVEL=0'; const expectedConnections = fips3 ? 1 : clientConfigs.length; const server = tls.createServer(serverConfig, common.mustCall(expectedConnections)); diff --git a/test/parallel/test-tls-min-max-version.js b/test/parallel/test-tls-min-max-version.js index 932ad7f0f219..3f91d946c232 100644 --- a/test/parallel/test-tls-min-max-version.js +++ b/test/parallel/test-tls-min-max-version.js @@ -11,11 +11,6 @@ const { hasFIPS, } = require('../common/crypto'); -if (isBoringSSL) { - require('../common/boringssl').testLegacyProtocolUnsupported(); - return; -} - const fixtures = require('../common/fixtures'); const { inspect } = require('util'); @@ -168,20 +163,39 @@ test(U, 'TLSv1.2', 'TLS1_2_method', U, U, U, test('TLSv1.2', U, 'TLS1_2_method', U, U, U, U, 'ERR_TLS_PROTOCOL_VERSION_CONFLICT'); -// TLS_method means "any supported protocol". +// TLS_method uses the library's default minimum protocol version. BoringSSL's +// default is TLSv1.2, even when older versions are explicitly enabled by the +// other peer. test(U, U, 'TLSv1_2_method', U, U, 'TLS_method', 'TLSv1.2'); -test(U, U, 'TLSv1_1_method', U, U, 'TLS_method', 'TLSv1.1'); -test(U, U, 'TLSv1_method', U, U, 'TLS_method', 'TLSv1'); test(U, U, 'TLS_method', U, U, 'TLSv1_2_method', 'TLSv1.2'); -test(U, U, 'TLS_method', U, U, 'TLSv1_1_method', 'TLSv1.1'); -test(U, U, 'TLS_method', U, U, 'TLSv1_method', 'TLSv1'); +for (const [method, version] of [ + ['TLSv1_1_method', 'TLSv1.1'], + ['TLSv1_method', 'TLSv1'], +]) { + const expected = isBoringSSL ? + [U, 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION', 'ERR_SSL_UNSUPPORTED_PROTOCOL'] : + [version]; + test(U, U, method, U, U, 'TLS_method', ...expected); + test(U, U, 'TLS_method', U, U, method, ...expected); +} // OpenSSL 1.1.1 and 3.0 use a different error code and alert (sent to the // client) when no protocols are enabled on the server. -const NO_PROTOCOLS_AVAILABLE_SERVER = hasOpenSSL(3) ? - 'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR'; -const NO_PROTOCOLS_AVAILABLE_SERVER_ALERT = hasOpenSSL(3) ? - 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION' : 'ERR_SSL_TLSV1_ALERT_INTERNAL_ERROR'; +// BoringSSL closes the connection without sending an alert in this case. +const NO_PROTOCOLS_AVAILABLE_SERVER = isBoringSSL ? + 'ERR_SSL_NO_SUPPORTED_VERSIONS_ENABLED' : hasOpenSSL(3) ? + 'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR'; +const NO_PROTOCOLS_AVAILABLE_SERVER_ALERT = isBoringSSL ? + 'ECONNRESET' : hasOpenSSL(3) ? + 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION' : 'ERR_SSL_TLSV1_ALERT_INTERNAL_ERROR'; +const NO_PROTOCOLS_AVAILABLE_CLIENT = isBoringSSL ? + 'ERR_SSL_NO_SUPPORTED_VERSIONS_ENABLED' : 'ERR_SSL_NO_PROTOCOLS_AVAILABLE'; +const NO_PROTOCOLS_AVAILABLE_CLIENT_ALERT = isBoringSSL ? + 'ECONNRESET' : 'ERR_SSL_UNEXPECTED_MESSAGE'; +// When a client rejects the server's legacy version, BoringSSL surfaces the +// protocol-version alert while OpenSSL reports a record version mismatch. +const UNSUPPORTED_PROTOCOL_SERVER_ERROR = isBoringSSL ? + 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION' : 'ERR_SSL_WRONG_VERSION_NUMBER'; // SSLv23 also means "any supported protocol" greater than the default // minimum (which is configurable via command line). @@ -198,9 +212,9 @@ if (DEFAULT_MIN_VERSION === 'TLSv1.3') { test(U, U, 'TLSv1_method', U, U, 'SSLv23_method', U, NO_PROTOCOLS_AVAILABLE_SERVER_ALERT, NO_PROTOCOLS_AVAILABLE_SERVER); test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method', - U, 'ERR_SSL_NO_PROTOCOLS_AVAILABLE', 'ERR_SSL_UNEXPECTED_MESSAGE'); + U, NO_PROTOCOLS_AVAILABLE_CLIENT, NO_PROTOCOLS_AVAILABLE_CLIENT_ALERT); test(U, U, 'SSLv23_method', U, U, 'TLSv1_method', - U, 'ERR_SSL_NO_PROTOCOLS_AVAILABLE', 'ERR_SSL_UNEXPECTED_MESSAGE'); + U, NO_PROTOCOLS_AVAILABLE_CLIENT, NO_PROTOCOLS_AVAILABLE_CLIENT_ALERT); } if (DEFAULT_MIN_VERSION === 'TLSv1.2') { @@ -211,9 +225,9 @@ if (DEFAULT_MIN_VERSION === 'TLSv1.2') { U, 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION', 'ERR_SSL_UNSUPPORTED_PROTOCOL'); test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method', - U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', 'ERR_SSL_WRONG_VERSION_NUMBER'); + U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', UNSUPPORTED_PROTOCOL_SERVER_ERROR); test(U, U, 'SSLv23_method', U, U, 'TLSv1_method', - U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', 'ERR_SSL_WRONG_VERSION_NUMBER'); + U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', UNSUPPORTED_PROTOCOL_SERVER_ERROR); } if (DEFAULT_MIN_VERSION === 'TLSv1.1') { @@ -223,7 +237,7 @@ if (DEFAULT_MIN_VERSION === 'TLSv1.1') { 'ERR_SSL_UNSUPPORTED_PROTOCOL'); test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method', 'TLSv1.1'); test(U, U, 'SSLv23_method', U, U, 'TLSv1_method', - U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', 'ERR_SSL_WRONG_VERSION_NUMBER'); + U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', UNSUPPORTED_PROTOCOL_SERVER_ERROR); } if (DEFAULT_MIN_VERSION === 'TLSv1') { @@ -250,9 +264,9 @@ if (DEFAULT_MIN_VERSION === 'TLSv1.2') { if (DEFAULT_MAX_VERSION === 'TLSv1.2') { test(U, U, U, U, U, 'TLSv1_1_method', - U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', 'ERR_SSL_WRONG_VERSION_NUMBER'); + U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', UNSUPPORTED_PROTOCOL_SERVER_ERROR); test(U, U, U, U, U, 'TLSv1_method', - U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', 'ERR_SSL_WRONG_VERSION_NUMBER'); + U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', UNSUPPORTED_PROTOCOL_SERVER_ERROR); } else { // TLS1.3 client hellos are not understood by TLS1.1 or below. test(U, U, U, U, U, 'TLSv1_1_method', @@ -274,7 +288,7 @@ if (DEFAULT_MIN_VERSION === 'TLSv1.1') { if (DEFAULT_MAX_VERSION === 'TLSv1.2') { test(U, U, U, U, U, 'TLSv1_method', - U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', 'ERR_SSL_WRONG_VERSION_NUMBER'); + U, 'ERR_SSL_UNSUPPORTED_PROTOCOL', UNSUPPORTED_PROTOCOL_SERVER_ERROR); } else { // TLS1.3 client hellos are not understood by TLS1.1 or below. test(U, U, U, U, U, 'TLSv1_method', diff --git a/test/parallel/test-tls-name-constraints-cn.js b/test/parallel/test-tls-name-constraints-cn.js index 0aae9502eeb0..22b87e4e0192 100644 --- a/test/parallel/test-tls-name-constraints-cn.js +++ b/test/parallel/test-tls-name-constraints-cn.js @@ -3,9 +3,6 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); const { isBoringSSL } = require('../common/crypto'); -// BoringSSL rejects DNS-like CNs without SANs under name constraints, -// even when the CN is permitted by those constraints. -if (isBoringSSL) common.skip('requires OpenSSL CN name constraints'); const assert = require('assert'); const tls = require('tls'); @@ -14,14 +11,19 @@ const fixtures = require('../common/fixtures'); const ca = fixtures.readKey('name-constraints-ca-cert.pem'); const key = fixtures.readKey('agent1-key.pem'); -// A DNS SAN prevents CN fallback; an email SAN does not. Name constraints -// must cover the CN whenever hostname verification can use it. +// A DNS SAN prevents CN fallback; an email SAN does not. OpenSSL constrains +// the CN whenever hostname verification can use it. BoringSSL instead rejects +// DNS-like CNs when the SAN extension is absent, but does not constrain the CN +// when an email SAN is present, so that case remains authorized. +const constraintError = isBoringSSL ? + /Issuer has name constraints but leaf has no SANs/ : + /permitted subtree violation/; for (const version of ['TLSv1.2', 'TLSv1.3']) { for (const [name, servername, valid] of [ - ['permitted', 'www.example.com', true], + ['permitted', 'www.example.com', !isBoringSSL], ['excluded', 'outside.invalid', false], ['dns-san', 'www.example.com', true], - ['email-san', 'outside.invalid', false], + ['email-san', 'outside.invalid', isBoringSSL], ]) { for (const rejectUnauthorized of [true, false]) { const rejected = !valid && rejectUnauthorized; @@ -46,7 +48,7 @@ for (const version of ['TLSv1.2', 'TLSv1.3']) { })); client.on('error', rejected ? common.mustCall((err) => { assert.strictEqual(err.code, 'UNSPECIFIED'); - assert.match(err.message, /permitted subtree violation/); + assert.match(err.message, constraintError); }) : common.mustNotCall()); client.on('close', common.mustCall(() => server.close())); })); diff --git a/test/parallel/test-tls-options-boolean-check.js b/test/parallel/test-tls-options-boolean-check.js index 4366502aacb3..776548c838f3 100644 --- a/test/parallel/test-tls-options-boolean-check.js +++ b/test/parallel/test-tls-options-boolean-check.js @@ -42,20 +42,6 @@ const keyDataView = toDataView(keyBuff); const certDataView = toDataView(certBuff); const caArrDataView = toDataView(caCert); -function filterBoringSSLKeyCertArrayCases(options, setName) { - if (!isBoringSSL) - return options; - - // The array-valued cases exercise multi-identity key/cert handling. - // BoringSSL may reject those cases with backend key/cert mismatch errors - // before the boolean/type validation this test is targeting. Keep the scalar - // cases so tls.createServer() option type validation is still covered. - common.printSkipMessage( - `BoringSSL: skipping ${setName} key/cert array cases`); - return options.filter(([key, cert]) => !Array.isArray(key) && - !Array.isArray(cert)); -} - // Checks to ensure tls.createServer doesn't throw an error // Format ['key', 'cert'] const validOptions = [ @@ -72,18 +58,24 @@ const validOptions = [ [keyDataView, certDataView], [keyDataView, false], [false, certDataView], - [[keyBuff, keyBuff2], [certBuff, certBuff2]], - [[keyStr, keyStr2], [certStr, certStr2]], [[keyStr, keyStr2], false], [false, [certStr, certStr2]], [[{ pem: keyBuff }], false], [[{ pem: keyBuff }, { pem: keyBuff }], false], ]; -filterBoringSSLKeyCertArrayCases(validOptions, 'valid') - .forEach(([key, cert]) => { - tls.createServer({ key, cert }); - }); +// Node's BoringSSL setup keeps one identity, so mixed RSA/EC key and +// certificate arrays fail with a key-type mismatch before option validation. +if (!isBoringSSL) { + validOptions.push( + [[keyBuff, keyBuff2], [certBuff, certBuff2]], + [[keyStr, keyStr2], [certStr, certStr2]], + ); +} + +validOptions.forEach(([key, cert]) => { + tls.createServer({ key, cert }); +}); // Checks to ensure tls.createServer predictably throws an error // Format ['key', 'cert', 'expected message'] @@ -95,14 +87,18 @@ const invalidKeyOptions = [ [true, false], [true, false], [{ pem: keyBuff }, false], - [[keyBuff, true], [certBuff, certBuff2], 1], [[true, keyStr2], [certStr, certStr2], 0], [[true, false], [certBuff, certBuff2], 0], [true, [certBuff, certBuff2]], ]; -for (const [key, cert, index] of - filterBoringSSLKeyCertArrayCases(invalidKeyOptions, 'invalid key')) { +// With both certificates loaded, BoringSSL rejects the RSA key against the +// last (EC) certificate before reaching the invalid second key. +if (!isBoringSSL) { + invalidKeyOptions.push([[keyBuff, true], [certBuff, certBuff2], 1]); +} + +for (const [key, cert, index] of invalidKeyOptions) { const val = index === undefined ? key : key[index]; assert.throws(() => { tls.createServer({ key, cert }); @@ -130,8 +126,7 @@ const invalidCertOptions = [ [[keyStr, keyStr2], true], ]; -for (const [key, cert, index] of - filterBoringSSLKeyCertArrayCases(invalidCertOptions, 'invalid cert')) { +for (const [key, cert, index] of invalidCertOptions) { const val = index === undefined ? cert : cert[index]; assert.throws(() => { tls.createServer({ key, cert }); diff --git a/test/parallel/test-tls-psk-alpn-callback-exception-handling.js b/test/parallel/test-tls-psk-alpn-callback-exception-handling.js index 0045517b0224..50701b633e94 100644 --- a/test/parallel/test-tls-psk-alpn-callback-exception-handling.js +++ b/test/parallel/test-tls-psk-alpn-callback-exception-handling.js @@ -15,11 +15,6 @@ const { isBoringSSL } = require('../common/crypto'); if (!common.hasCrypto) common.skip('missing crypto'); -if (isBoringSSL) { - require('../common/boringssl').testPskTls13Unsupported(); - return; -} - const assert = require('assert'); const { describe, it } = require('node:test'); const https = require('node:https'); @@ -27,6 +22,8 @@ const tls = require('tls'); const fixtures = require('../common/fixtures'); const CIPHERS = 'PSK+HIGH'; +// BoringSSL's PSK callbacks support the certificate-less setup under TLS 1.2. +const pskOptions = isBoringSSL ? { maxVersion: 'TLSv1.2' } : {}; const TEST_TIMEOUT = 5000; // Helper to create a promise that rejects on uncaughtException or timeout @@ -75,6 +72,7 @@ describe('TLS callback exception handling', () => { it('pskCallback returning invalid type emits tlsClientError', async (t) => { const server = tls.createServer({ ciphers: CIPHERS, + ...pskOptions, pskCallback: () => { // Return invalid type (string instead of object/Buffer) return 'invalid-should-be-object-or-buffer'; @@ -116,7 +114,10 @@ describe('TLS callback exception handling', () => { await promise; }); - it('newSession synchronous error emits error', async (t) => { + it('newSession synchronous error emits error', { + skip: isBoringSSL && + 'BoringSSL does not trigger the TLS 1.3 newSession callback in this test', + }, async (t) => { const server = tls.createServer({ key: fixtures.readKey('agent2-key.pem'), cert: fixtures.readKey('agent2-cert.pem'), @@ -284,6 +285,7 @@ describe('TLS callback exception handling', () => { it('pskCallback throwing emits tlsClientError', async (t) => { const server = tls.createServer({ ciphers: CIPHERS, + ...pskOptions, pskCallback: () => { throw new Error('Intentional callback error'); }, @@ -411,6 +413,7 @@ describe('TLS callback exception handling', () => { const server = tls.createServer({ ciphers: CIPHERS, + ...pskOptions, pskCallback: () => PSK, pskIdentityHint: 'test-hint', }); @@ -453,6 +456,7 @@ describe('TLS callback exception handling', () => { const server = tls.createServer({ ciphers: CIPHERS, + ...pskOptions, pskCallback: () => PSK, pskIdentityHint: 'test-hint', }); diff --git a/test/parallel/test-tls-psk-circuit.js b/test/parallel/test-tls-psk-circuit.js index 9cd4a68676ec..0e4bf3a09f29 100644 --- a/test/parallel/test-tls-psk-circuit.js +++ b/test/parallel/test-tls-psk-circuit.js @@ -7,11 +7,6 @@ if (!common.hasCrypto) { const { isBoringSSL, hasOpenSSL } = require('../common/crypto'); -if (isBoringSSL) { - require('../common/boringssl').testPskTls13Unsupported(); - return; -} - const assert = require('assert'); const tls = require('tls'); @@ -64,8 +59,16 @@ function test(secret, opts, error) { })); } -test({ psk: USERS.UserA, identity: 'UserA' }); test({ psk: USERS.UserA, identity: 'UserA' }, { maxVersion: 'TLSv1.2' }); + +if (isBoringSSL) { + // Keep the TLS 1.2 callback and data checks above. The remaining cases use + // TLS 1.3, which Node's BoringSSL PSK integration does not support yet. + require('../common/boringssl').testPskTls13Unsupported(); + return; +} + +test({ psk: USERS.UserA, identity: 'UserA' }); test({ psk: USERS.UserA, identity: 'UserA' }, { minVersion: 'TLSv1.3' }); test({ psk: USERS.UserB, identity: 'UserB' }); test({ psk: USERS.UserB, identity: 'UserB' }, { minVersion: 'TLSv1.3' }); diff --git a/test/parallel/test-tls-psk-server.js b/test/parallel/test-tls-psk-server.js index 29d164f019da..527c06d553a2 100644 --- a/test/parallel/test-tls-psk-server.js +++ b/test/parallel/test-tls-psk-server.js @@ -5,14 +5,7 @@ if (!common.hasCrypto) { common.skip('missing crypto'); } -const { isBoringSSL } = require('../common/crypto'); - -if (isBoringSSL) { - require('../common/boringssl').testPskTls13Unsupported(); - return; -} - -const { opensslCli } = require('../common/crypto'); +const { isBoringSSL, opensslCli } = require('../common/crypto'); if (!opensslCli) { common.skip('missing openssl cli'); @@ -29,6 +22,8 @@ const IDENTITY = 'TestUser'; const server = tls.createServer({ ciphers: CIPHERS, + // BoringSSL requires TLS 1.2 for this certificate-less PSK handshake. + ...(isBoringSSL ? { maxVersion: 'TLSv1.2' } : {}), pskIdentityHint: IDENTITY, pskCallback: common.mustCall((socket, identity) => { assert.ok(socket instanceof tls.TLSSocket); diff --git a/test/parallel/test-tls-session-reuse-different-servername.js b/test/parallel/test-tls-session-reuse-different-servername.js index c3ae4be15785..68e84227b889 100644 --- a/test/parallel/test-tls-session-reuse-different-servername.js +++ b/test/parallel/test-tls-session-reuse-different-servername.js @@ -5,6 +5,7 @@ if (!common.hasCrypto) const assert = require('assert'); const fixtures = require('../common/fixtures'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); const tls = require('tls'); const { once } = require('events'); @@ -90,7 +91,7 @@ async function testVersion(minVersion, maxVersion) { return socket; }), { - code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + code: untrustedLeafErrorCodePattern, }, ); @@ -107,7 +108,7 @@ async function testVersion(minVersion, maxVersion) { return socket; }), { - code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', + code: untrustedLeafErrorCodePattern, }, ); } finally { diff --git a/test/parallel/test-tls-set-default-ca-certificates-append-fetch.mjs b/test/parallel/test-tls-set-default-ca-certificates-append-fetch.mjs index ca8436b22b0a..7c76a0ed77ac 100644 --- a/test/parallel/test-tls-set-default-ca-certificates-append-fetch.mjs +++ b/test/parallel/test-tls-set-default-ca-certificates-append-fetch.mjs @@ -11,7 +11,7 @@ import assert from 'node:assert'; if (!common.hasCrypto) common.skip('missing crypto'); -const { includesCert } = await import('../common/tls.js'); +const { includesCert, untrustedLeafErrorCodePattern } = await import('../common/tls.js'); const { default: https } = await import('node:https'); const { default: tls } = await import('node:tls'); @@ -37,7 +37,7 @@ const url = `https://localhost:${server.address().port}/hello-world`; await assert.rejects( fetch(url), (err) => { - assert.strictEqual(err.cause.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.cause.code, untrustedLeafErrorCodePattern); return true; }, ); diff --git a/test/parallel/test-tls-set-default-ca-certificates-append-https-request.js b/test/parallel/test-tls-set-default-ca-certificates-append-https-request.js index d7a3baded420..fc49df44bf74 100644 --- a/test/parallel/test-tls-set-default-ca-certificates-append-https-request.js +++ b/test/parallel/test-tls-set-default-ca-certificates-append-https-request.js @@ -10,7 +10,7 @@ const assert = require('assert'); const https = require('https'); const tls = require('tls'); const fixtures = require('../common/fixtures'); -const { includesCert } = require('../common/tls'); +const { includesCert, untrustedLeafErrorCodePattern } = require('../common/tls'); const bundledCerts = tls.getCACertificates('bundled'); const fixtureCert = fixtures.readKey('fake-startcom-root-cert.pem'); @@ -43,7 +43,7 @@ server.listen(0, common.mustCall(() => { req1.on('error', common.mustCall((err) => { console.log(err); // Should fail with certificate verification error - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); // Now add the fake-startcom-root-cert to bundled certs - connection should succeed tls.setDefaultCACertificates([...bundledCerts, fixtureCert]); diff --git a/test/parallel/test-tls-set-default-ca-certificates-reset-fetch.mjs b/test/parallel/test-tls-set-default-ca-certificates-reset-fetch.mjs index 479b415d4c51..1affeaa2f0d2 100644 --- a/test/parallel/test-tls-set-default-ca-certificates-reset-fetch.mjs +++ b/test/parallel/test-tls-set-default-ca-certificates-reset-fetch.mjs @@ -11,6 +11,7 @@ import assert from 'node:assert'; if (!common.hasCrypto) common.skip('missing crypto'); +const { untrustedLeafErrorCodePattern } = await import('../common/tls.js'); const { default: https } = await import('node:https'); const { default: tls } = await import('node:tls'); @@ -39,7 +40,7 @@ tls.setDefaultCACertificates([]); await assert.rejects( fetch(`https://127.0.0.1:${server.address().port}/empty-ca-test`), (err) => { - assert.strictEqual(err.cause.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.cause.code, untrustedLeafErrorCodePattern); return true; }, ); diff --git a/test/parallel/test-tls-set-default-ca-certificates-reset-https-request.js b/test/parallel/test-tls-set-default-ca-certificates-reset-https-request.js index 7389cacf6d66..b358d382f35a 100644 --- a/test/parallel/test-tls-set-default-ca-certificates-reset-https-request.js +++ b/test/parallel/test-tls-set-default-ca-certificates-reset-https-request.js @@ -9,6 +9,7 @@ const assert = require('assert'); const https = require('https'); const tls = require('tls'); const fixtures = require('../common/fixtures'); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); // Test HTTPS connection succeeds with proper CA, fails after removing it const server = https.createServer({ @@ -49,7 +50,7 @@ server.listen(0, common.mustCall(() => { req2.on('error', common.mustCall((err) => { // Should fail with certificate verification error. - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); server.close(); })); diff --git a/test/parallel/test-tls-socket-default-options.js b/test/parallel/test-tls-socket-default-options.js index 8dfd912285dc..dcab2db4ae7e 100644 --- a/test/parallel/test-tls-socket-default-options.js +++ b/test/parallel/test-tls-socket-default-options.js @@ -8,13 +8,14 @@ const assert = require('assert'); const { connect, keys, tls } = require(fixtures.path('tls-connect')); +const { untrustedLeafErrorCodePattern } = require('../common/tls'); test(undefined, (err) => { - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); }); test({}, (err) => { - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); }); test( @@ -30,8 +31,7 @@ test( test( { secureContext: tls.createSecureContext(), ca: keys.agent1.ca }, (err) => { - assert.strictEqual(err.code, - 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); }); function test(client, callback) { @@ -42,7 +42,7 @@ function test(client, callback) { cert: keys.agent1.cert, }, }, common.mustCall(function(err, pair, cleanup) { - assert.strictEqual(err.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.code, untrustedLeafErrorCodePattern); let recv = ''; pair.server.server.once('secureConnection', common.mustCall((conn) => { conn.on('data', (data) => recv += data); diff --git a/test/sequential/test-tls-psk-client.js b/test/sequential/test-tls-psk-client.js index 5cb429f47dec..37aa43a841f2 100644 --- a/test/sequential/test-tls-psk-client.js +++ b/test/sequential/test-tls-psk-client.js @@ -5,14 +5,7 @@ if (!common.hasCrypto) { common.skip('missing crypto'); } -const { isBoringSSL } = require('../common/crypto'); - -if (isBoringSSL) { - require('../common/boringssl').testPskTls13Unsupported(); - return; -} - -const { opensslCli } = require('../common/crypto'); +const { isBoringSSL, opensslCli } = require('../common/crypto'); if (!opensslCli) { common.skip('missing openssl cli'); @@ -95,6 +88,8 @@ waitForPort(common.PORT, common.mustCall((err) => { function runClient(message, cb) { const s = tls.connect(common.PORT, { ciphers: CIPHERS, + // BoringSSL requires TLS 1.2 for this certificate-less PSK handshake. + ...(isBoringSSL ? { maxVersion: 'TLSv1.2' } : {}), checkServerIdentity: () => {}, pskCallback(hint) { // 'hint' will be null in TLS1.3. diff --git a/test/system-ca/test-native-intermediate-certs.mjs b/test/system-ca/test-native-intermediate-certs.mjs index edf1315422f8..02211fda5c19 100644 --- a/test/system-ca/test-native-intermediate-certs.mjs +++ b/test/system-ca/test-native-intermediate-certs.mjs @@ -11,6 +11,8 @@ if (!common.hasCrypto) { common.skip('requires crypto'); } +const { untrustedLeafErrorCodePattern } = await import('../common/tls.js'); + // To run this test, the system needs to be configured to trust // the CA certificate first (which needs an interactive GUI approval, e.g. TouchID): // see the README.md in this folder for instructions on how to do this. @@ -72,7 +74,7 @@ describe('use-system-ca', function() { if (common.isWindows) { assert.strictEqual(err.cause.code, 'UNABLE_TO_GET_ISSUER_CERT'); } else { - assert.strictEqual(err.cause.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.cause.code, untrustedLeafErrorCodePattern); } } }); diff --git a/test/system-ca/test-set-default-ca-certificates-append-system-ca.mjs b/test/system-ca/test-set-default-ca-certificates-append-system-ca.mjs index 0cbd9804c365..a359d6b74835 100644 --- a/test/system-ca/test-set-default-ca-certificates-append-system-ca.mjs +++ b/test/system-ca/test-set-default-ca-certificates-append-system-ca.mjs @@ -13,6 +13,7 @@ if (!common.hasCrypto) { common.skip('requires crypto'); } +const { untrustedLeafErrorCodePattern } = await import('../common/tls.js'); const { default: https } = await import('node:https'); const { default: tls } = await import('node:tls'); @@ -32,7 +33,7 @@ const url = `https://localhost:${server.address().port}/hello-world`; await assert.rejects( fetch(url), (err) => { - assert.strictEqual(err.cause.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.cause.code, untrustedLeafErrorCodePattern); return true; }, ); diff --git a/test/system-ca/test-use-system-ca-worker-disable.mjs b/test/system-ca/test-use-system-ca-worker-disable.mjs index 43f3f2937602..e0eadc547843 100644 --- a/test/system-ca/test-use-system-ca-worker-disable.mjs +++ b/test/system-ca/test-use-system-ca-worker-disable.mjs @@ -14,6 +14,8 @@ if (!common.hasCrypto) { common.skip('requires crypto'); } +const { untrustedLeafErrorCodePattern } = await import('../common/tls.js'); + // To run this test, the system needs to be configured to trust // the CA certificate first (which needs an interactive GUI approval, e.g. TouchID): // see the README.md in this folder for instructions on how to do this. @@ -61,7 +63,7 @@ describe('use-system-ca', function() { const [message] = await once(worker, 'message'); assert.strictEqual(message.ok, false); assert( - message.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' || + untrustedLeafErrorCodePattern.test(message.code) || message.code === 'SELF_SIGNED_CERT_IN_CHAIN', `Expected certificate verification error but got: ${JSON.stringify( message, diff --git a/test/system-ca/test-use-system-ca-worker-enable.mjs b/test/system-ca/test-use-system-ca-worker-enable.mjs index f5f3faab4814..226c2e804bff 100644 --- a/test/system-ca/test-use-system-ca-worker-enable.mjs +++ b/test/system-ca/test-use-system-ca-worker-enable.mjs @@ -14,6 +14,8 @@ if (!common.hasCrypto) { common.skip('requires crypto'); } +const { untrustedLeafErrorCodePattern } = await import('../common/tls.js'); + // To run this test, the system needs to be configured to trust // the CA certificate first (which needs an interactive GUI approval, e.g. TouchID): // see the README.md in this folder for instructions on how to do this. @@ -57,7 +59,7 @@ describe('use-system-ca', function() { workerData: { url }, }); await assert.rejects(fetch(url), (err) => { - assert.strictEqual(err.cause.code, 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'); + assert.match(err.cause.code, untrustedLeafErrorCodePattern); return true; });