From a88e77a55186c833914974a4728afe3a4f3743c0 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 26 Oct 2020 07:23:55 +0100 Subject: [PATCH 01/40] src: fix crypto_hkdf.cc compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently there are three compilation errors generated for crypto_hkdf.cc: ./src/crypto/crypto_hkdf.cc: In static member function ‘static bool node::crypto::HKDFTraits::DeriveBits(node::Environment*, const node::crypto::HKDFConfig&, node::crypto::ByteSource*)’: ../src/crypto/crypto_hkdf.cc:113:24: error: invalid conversion from ‘const char*’ to ‘const unsigned char*’ [-fpermissive] 113 | params.salt.get(), | ~~~~~~~~~~~~~~~^~ | | | const char* In file included from ../src/crypto/crypto_util.h:18, from ../src/crypto/crypto_keys.h:6, from ../src/crypto/crypto_hkdf.h:6, from ../src/crypto/crypto_hkdf.cc:1: /openssl_build_master/include/openssl/kdf.h:130:54: note: initializing argument 2 of ‘int EVP_PKEY_CTX_set1_hkdf_salt( EVP_PKEY_CTX*, const unsigned char*, int)’ 130 | const unsigned char *salt, int saltlen); | ~~~~~~~~~~~~~~~~~~~~~^~~~ --- src/crypto/crypto_hkdf.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crypto/crypto_hkdf.cc b/src/crypto/crypto_hkdf.cc index f6339b129baea6..0aa96ada47abe4 100644 --- a/src/crypto/crypto_hkdf.cc +++ b/src/crypto/crypto_hkdf.cc @@ -110,15 +110,15 @@ bool HKDFTraits::DeriveBits( !EVP_PKEY_CTX_set_hkdf_md(ctx.get(), params.digest) || !EVP_PKEY_CTX_set1_hkdf_salt( ctx.get(), - params.salt.get(), + reinterpret_cast(params.salt.get()), params.salt.size()) || !EVP_PKEY_CTX_set1_hkdf_key( ctx.get(), - params.key->GetSymmetricKey(), + reinterpret_cast(params.key->GetSymmetricKey()), params.key->GetSymmetricKeySize()) || !EVP_PKEY_CTX_add1_hkdf_info( ctx.get(), - params.info.get(), + reinterpret_cast(params.info.get()), params.info.size())) { return false; } From 3d9a5e5159a41bf63a7440781bd383b3e1d91adb Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 8 Jul 2020 09:55:32 +0200 Subject: [PATCH 02/40] build: add OPENSSL_API_COMPAT macro This commit adds the OPENSSL_API_COMPAT macro and sets it to version 1.0.0 of OpenSSL when linking with a shared OpenSSL library. The motivation for this is that when linking against OpenSSL 3.x there are a lot of deprecation warnings and this allows them to be avoided. When we later upgrade the code base to 3.x this value can then be updated. --- node.gypi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/node.gypi b/node.gypi index ad088b133be471..f9dba2d4bdd4f4 100644 --- a/node.gypi +++ b/node.gypi @@ -361,7 +361,11 @@ ], }], ], - }]] + }, { + # Set 1.0.0 as the API compability level to avoid the + # deprecation warnings when using OpenSSL 3.0. + 'defines': ['OPENSSL_API_COMPAT=0x10000000L'], + }]] }, { 'defines': [ 'HAVE_OPENSSL=0' ] From a8d117ce53a0d2cfe4ac0cb94ea015830854080b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 17 Jun 2020 13:44:09 +0200 Subject: [PATCH 03/40] test: add hasOpenSSL3 constant This commit adds a constant to identify if the version of OpenSSl is 3 or above. The motivation for this is it allows for checking this value in tests to make sure that they work with OpenSSL 3.x, and also with earlier versions. --- test/common/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/common/index.js b/test/common/index.js index b70972b1a54d26..89c4fcaaa99568 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -51,6 +51,9 @@ const noop = () => {}; const hasCrypto = Boolean(process.versions.openssl) && !process.env.NODE_SKIP_CRYPTO; +const hasOpenSSL3 = hasCrypto && + require('crypto').constants.OPENSSL_VERSION_NUMBER >= 805306368; + // Check for flags. Skip this for workers (both, the `cluster` module and // `worker_threads`) and child processes. // If the binary was built without-ssl then the crypto flags are @@ -726,6 +729,7 @@ const common = { getTTYfd, hasIntl, hasCrypto, + hasOpenSSL3, hasMultiLocalhost, invalidArgTypeHelper, isAIX, From 2a68e7bc839652d92354a415a2114f86eb1f775b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 17 Jun 2020 13:47:23 +0200 Subject: [PATCH 04/40] test: fix diffie-hellman 'module to small' failures This commit fixes a number of test failures reported when using OpenSSL 3.0, for example: Error: error:0500007E:Diffie-Hellman routines::modulus too small Check have been added for OpenSSL 3 and use the larger sizes only for OpenSSL 3.0 as these sizes seem to cause timeouts when using OpenSSL 1.1.1. --- test/parallel/test-crypto-binary-default.js | 3 +- test/parallel/test-crypto-classes.js | 2 +- test/parallel/test-crypto-dh-leak.js | 3 +- test/parallel/test-crypto-dh-odd-key.js | 2 +- test/parallel/test-crypto-dh.js | 50 +++++++++++++++------ test/parallel/test-crypto-keygen.js | 8 ++-- test/parallel/test-crypto-secure-heap.js | 3 +- 7 files changed, 48 insertions(+), 23 deletions(-) diff --git a/test/parallel/test-crypto-binary-default.js b/test/parallel/test-crypto-binary-default.js index a2fb2e82670567..ada50d6b9c9656 100644 --- a/test/parallel/test-crypto-binary-default.js +++ b/test/parallel/test-crypto-binary-default.js @@ -583,7 +583,8 @@ assert.throws( // Test Diffie-Hellman with two parties sharing a secret, // using various encodings as we go along { - const dh1 = crypto.createDiffieHellman(common.hasFipsCrypto ? 1024 : 256); + const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256; + const dh1 = crypto.createDiffieHellman(size); const p1 = dh1.getPrime('buffer'); const dh2 = crypto.createDiffieHellman(p1, 'base64'); const key1 = dh1.generateKeys(); diff --git a/test/parallel/test-crypto-classes.js b/test/parallel/test-crypto-classes.js index ce4e2922de8062..dd073274aef765 100644 --- a/test/parallel/test-crypto-classes.js +++ b/test/parallel/test-crypto-classes.js @@ -24,7 +24,7 @@ const TEST_CASES = { if (!common.hasFipsCrypto) { TEST_CASES.Cipher = ['aes192', 'secret']; TEST_CASES.Decipher = ['aes192', 'secret']; - TEST_CASES.DiffieHellman = [256]; + TEST_CASES.DiffieHellman = [common.hasOpenSSL3 ? 1024 : 256]; } for (const [clazz, args] of Object.entries(TEST_CASES)) { diff --git a/test/parallel/test-crypto-dh-leak.js b/test/parallel/test-crypto-dh-leak.js index 5c4c0c61d4f41c..fe8c138ac2c98f 100644 --- a/test/parallel/test-crypto-dh-leak.js +++ b/test/parallel/test-crypto-dh-leak.js @@ -12,7 +12,8 @@ const crypto = require('crypto'); const before = process.memoryUsage.rss(); { - const dh = crypto.createDiffieHellman(common.hasFipsCrypto ? 1024 : 256); + const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256; + const dh = crypto.createDiffieHellman(size); const publicKey = dh.generateKeys(); const privateKey = dh.getPrivateKey(); for (let i = 0; i < 5e4; i += 1) { diff --git a/test/parallel/test-crypto-dh-odd-key.js b/test/parallel/test-crypto-dh-odd-key.js index d5410daca6fb23..69a1eb56c866b3 100644 --- a/test/parallel/test-crypto-dh-odd-key.js +++ b/test/parallel/test-crypto-dh-odd-key.js @@ -30,7 +30,7 @@ const crypto = require('crypto'); function test() { const odd = Buffer.alloc(39, 'A'); - const c = crypto.createDiffieHellman(32); + const c = crypto.createDiffieHellman(common.hasOpenSSL3 ? 1024 : 32); c.setPrivateKey(odd); c.generateKeys(); } diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index 5336301391b6c7..643dd55d5f6333 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -8,7 +8,8 @@ const crypto = require('crypto'); // Test Diffie-Hellman with two parties sharing a secret, // using various encodings as we go along -const dh1 = crypto.createDiffieHellman(common.hasFipsCrypto ? 1024 : 256); +const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256; +const dh1 = crypto.createDiffieHellman(size); const p1 = dh1.getPrime('buffer'); const dh2 = crypto.createDiffieHellman(p1, 'buffer'); let key1 = dh1.generateKeys(); @@ -38,11 +39,19 @@ assert.throws(() => crypto.createDiffieHellman('abcdef', 13.37), { }); for (const bits of [-1, 0, 1]) { - assert.throws(() => crypto.createDiffieHellman(bits), { - code: 'ERR_OSSL_BN_BITS_TOO_SMALL', - name: 'Error', - message: /bits too small/, - }); + if (common.hasOpenSSL3) { + assert.throws(() => crypto.createDiffieHellman(bits), { + code: 'ERR_OSSL_DH_MODULUS_TOO_SMALL', + name: 'Error', + message: /modulus too small/, + }); + } else { + assert.throws(() => crypto.createDiffieHellman(bits), { + code: 'ERR_OSSL_BN_BITS_TOO_SMALL', + name: 'Error', + message: /bits too small/, + }); + } } // Through a fluke of history, g=0 defaults to DH_GENERATOR (2). @@ -143,13 +152,23 @@ const secret4 = dh4.computeSecret(key2, 'hex', 'base64'); assert.strictEqual(secret1, secret4); -const wrongBlockLength = { - message: 'error:0606506D:digital envelope' + - ' routines:EVP_DecryptFinal_ex:wrong final block length', - code: 'ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH', - library: 'digital envelope routines', - reason: 'wrong final block length' -}; +let wrongBlockLength; +if (common.hasOpenSSL3) { + wrongBlockLength = { + message: 'error:3900006B:Provider routines::wrong final block length', + code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH', + library: 'Provider routines', + reason: 'wrong final block length' + }; +} else { + wrongBlockLength = { + message: 'error:0606506D:digital envelope' + + ' routines:EVP_DecryptFinal_ex:wrong final block length', + code: 'ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH', + library: 'digital envelope routines', + reason: 'wrong final block length' + }; +} // Run this one twice to make sure that the dh3 clears its error properly { @@ -168,7 +187,10 @@ const wrongBlockLength = { assert.throws(() => { dh3.computeSecret(''); -}, { message: 'Supplied key is too small' }); +}, { message: common.hasOpenSSL3 ? + 'error:05000066:Diffie-Hellman routines::invalid public key' : + 'Supplied key is too small' +}); // Create a shared using a DH group. const alice = crypto.createDiffieHellmanGroup('modp5'); diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index b80b35135743d9..237cfdd697c51c 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -342,7 +342,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); // Test async DSA key generation. generateKeyPair('dsa', { - modulusLength: 512, + modulusLength: common.hasOpenSSL3 ? 2048 : 512, divisorLength: 256, publicKeyEncoding: { type: 'spki', @@ -359,8 +359,8 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); // The private key is DER-encoded. assert(Buffer.isBuffer(privateKeyDER)); - assertApproximateSize(publicKey, 440); - assertApproximateSize(privateKeyDER, 336); + assertApproximateSize(publicKey, common.hasOpenSSL3 ? 1194 : 440); + assertApproximateSize(privateKeyDER, common.hasOpenSSL3 ? 721 : 336); // Since the private key is encrypted, signing shouldn't work anymore. assert.throws(() => { @@ -1029,7 +1029,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); // Test classic Diffie-Hellman key generation. { generateKeyPair('dh', { - primeLength: 1024 + primeLength: common.hasOpenSSL3 ? 2048 : 1024 }, common.mustSucceed((publicKey, privateKey) => { assert.strictEqual(publicKey.type, 'public'); assert.strictEqual(publicKey.asymmetricKeyType, 'dh'); diff --git a/test/parallel/test-crypto-secure-heap.js b/test/parallel/test-crypto-secure-heap.js index f6bdc3a2d8a05c..fd6a90658d129d 100644 --- a/test/parallel/test-crypto-secure-heap.js +++ b/test/parallel/test-crypto-secure-heap.js @@ -29,7 +29,8 @@ if (process.argv[2] === 'child') { assert.strictEqual(a.used, 0); { - const dh1 = createDiffieHellman(common.hasFipsCrypto ? 1024 : 256); + const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256; + const dh1 = createDiffieHellman(size); const p1 = dh1.getPrime('buffer'); const dh2 = createDiffieHellman(p1, 'buffer'); const key1 = dh1.generateKeys(); From dbd22066fa1cc6bb2c3405f2493aea9aec3161f4 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 17 Jun 2020 14:29:31 +0200 Subject: [PATCH 05/40] test: add OpenSSL3 error message check test-tls-key-mismatch.js --- test/parallel/test-tls-key-mismatch.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-tls-key-mismatch.js b/test/parallel/test-tls-key-mismatch.js index b0c8affadefe95..fdbb3676267a9d 100644 --- a/test/parallel/test-tls-key-mismatch.js +++ b/test/parallel/test-tls-key-mismatch.js @@ -29,7 +29,8 @@ const fixtures = require('../common/fixtures'); const assert = require('assert'); const tls = require('tls'); -const errorMessageRegex = +const errorMessageRegex = common.hasOpenSSL3 ? + /^Error: error:05800074:x509 certificate routines::key values mismatch$/ : /^Error: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch$/; const options = { From b8e7c2d9ae6ef444c2a49897ebf8a7eb77cb80ff Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 17 Jun 2020 14:41:41 +0200 Subject: [PATCH 06/40] test: add OpenSSL3 error message check test-tls-client-renegotiation-13.js --- test/parallel/test-tls-client-renegotiation-13.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-tls-client-renegotiation-13.js b/test/parallel/test-tls-client-renegotiation-13.js index 075eb70e917c06..a32baed0249a0a 100644 --- a/test/parallel/test-tls-client-renegotiation-13.js +++ b/test/parallel/test-tls-client-renegotiation-13.js @@ -29,7 +29,9 @@ connect({ const ok = client.renegotiate({}, common.mustCall((err) => { assert.throws(() => { throw err; }, { - message: 'error:1420410A:SSL routines:SSL_renegotiate:wrong ssl version', + message: common.hasOpenSSL3 ? + 'error:0A00010A:SSL routines::wrong ssl version' : + 'error:1420410A:SSL routines:SSL_renegotiate:wrong ssl version', code: 'ERR_SSL_WRONG_SSL_VERSION', library: 'SSL routines', reason: 'wrong ssl version', From b1b268b04420ebb595cd4a2b54402ce2637c6f1b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 17 Jun 2020 14:53:00 +0200 Subject: [PATCH 07/40] test: add OpenSSL3 error message check test-crypto-stream.js --- test/parallel/test-crypto-stream.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-crypto-stream.js b/test/parallel/test-crypto-stream.js index 2d005c89db3f09..008ab129f0e019 100644 --- a/test/parallel/test-crypto-stream.js +++ b/test/parallel/test-crypto-stream.js @@ -71,7 +71,11 @@ const cipher = crypto.createCipheriv('aes-128-cbc', key, iv); const decipher = crypto.createDecipheriv('aes-128-cbc', badkey, iv); cipher.pipe(decipher) - .on('error', common.expectsError({ + .on('error', common.expectsError(common.hasOpenSSL3 ? { + message: /bad decrypt/, + library: 'Provider routines', + reason: 'bad decrypt', + } : { message: /bad decrypt/, function: 'EVP_DecryptFinal_ex', library: 'digital envelope routines', From 5ecbb48f5d84c7597f54825be55c30c925ae436c Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 18 Jun 2020 13:21:01 +0200 Subject: [PATCH 08/40] test: add OpenSSL3 specific version regex test-process-versions.js --- test/parallel/test-process-versions.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index 788c380449b802..666c8ead3b15d2 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -35,7 +35,13 @@ assert(/^\d+\.\d+\.\d+(?:\.\d+)?-node\.\d+(?: \(candidate\))?$/ assert(/^\d+$/.test(process.versions.modules)); if (common.hasCrypto) { - assert(/^\d+\.\d+\.\d+[a-z]?(\+quic)?(-fips)?$/.test(process.versions.openssl)); + const versionRegex = common.hasOpenSSL3 ? + // The following also matches a development version of OpenSSL 3.x which + // can be in the format '3.0.0-alpha4-dev'. This can be handy when building + // and linking against the main development branch of OpenSSL. + /^\d+\.\d+\.\d+(-[-a-z0-9]+)?$/ : + /^\d+\.\d+\.\d+[a-z]?(\+quic)?(-fips)?$/; + assert(versionRegex.test(process.versions.openssl)); } for (let i = 0; i < expected_keys.length; i++) { From 470fc73c9e972164d3be4ee70d262d99ba5677ad Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 18 Jun 2020 15:33:05 +0200 Subject: [PATCH 09/40] test: add OpenSSL3 error message check test-crypto-private-decrypt-gh32240.js --- test/parallel/test-crypto-private-decrypt-gh32240.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-crypto-private-decrypt-gh32240.js b/test/parallel/test-crypto-private-decrypt-gh32240.js index 4b48774145a3f8..875888622cb5f7 100644 --- a/test/parallel/test-crypto-private-decrypt-gh32240.js +++ b/test/parallel/test-crypto-private-decrypt-gh32240.js @@ -34,5 +34,7 @@ function decrypt(key) { } decrypt(pkey); -assert.throws(() => decrypt(pkeyEncrypted), { code: 'ERR_MISSING_PASSPHRASE' }); +assert.throws(() => decrypt(pkeyEncrypted), common.hasOpenSSL3 ? + { message: 'Failed to read asymmetric key' } : + { code: 'ERR_MISSING_PASSPHRASE' }); decrypt(pkey); // Should not throw. From 80834e2c50118ffb29d10be8e6d012576e2505ac Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 22 Jun 2020 10:57:16 +0200 Subject: [PATCH 10/40] test: add OpenSSL3 error message check test-tls-alert-handling.js --- test/parallel/test-tls-alert-handling.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-tls-alert-handling.js b/test/parallel/test-tls-alert-handling.js index f9f42e2d51c04d..bd86149bc5ac22 100644 --- a/test/parallel/test-tls-alert-handling.js +++ b/test/parallel/test-tls-alert-handling.js @@ -33,7 +33,7 @@ let iter = 0; const errorHandler = common.mustCall((err) => { assert.strictEqual(err.code, 'ERR_SSL_WRONG_VERSION_NUMBER'); assert.strictEqual(err.library, 'SSL routines'); - assert.strictEqual(err.function, 'ssl3_get_record'); + if (!common.hasOpenSSL3) assert.strictEqual(err.function, 'ssl3_get_record'); assert.strictEqual(err.reason, 'wrong version number'); errorReceived = true; if (canCloseServer()) @@ -89,7 +89,8 @@ function sendBADTLSRecord() { client.on('error', common.mustCall((err) => { assert.strictEqual(err.code, 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION'); assert.strictEqual(err.library, 'SSL routines'); - assert.strictEqual(err.function, 'ssl3_read_bytes'); + if (!common.hasOpenSSL3) + assert.strictEqual(err.function, 'ssl3_read_bytes'); assert.strictEqual(err.reason, 'tlsv1 alert protocol version'); })); } From d6eae6d774692915f54d371b7e5b18ad5e487b14 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 22 Jun 2020 11:27:22 +0200 Subject: [PATCH 11/40] test: add OpenSSL3 error message check test-crypto-padding.js --- test/parallel/test-crypto-padding.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/parallel/test-crypto-padding.js b/test/parallel/test-crypto-padding.js index 909c014bd0f87a..f1f14b472997e7 100644 --- a/test/parallel/test-crypto-padding.js +++ b/test/parallel/test-crypto-padding.js @@ -82,12 +82,17 @@ assert.strictEqual(enc(EVEN_LENGTH_PLAIN, true), EVEN_LENGTH_ENCRYPTED); assert.throws(function() { // Input must have block length %. enc(ODD_LENGTH_PLAIN, false); -}, { +}, common.hasOpenSSL3 ? { + message: 'error:1C80006B:Provider routines::wrong final block length', + code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH', + reason: 'wrong final block length', +} : { message: 'error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:' + 'data not multiple of block length', code: 'ERR_OSSL_EVP_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH', reason: 'data not multiple of block length', -}); +} +); assert.strictEqual( enc(EVEN_LENGTH_PLAIN, false), EVEN_LENGTH_ENCRYPTED_NOPAD @@ -104,7 +109,11 @@ assert.strictEqual(dec(EVEN_LENGTH_ENCRYPTED, false).length, 48); assert.throws(function() { // Must have at least 1 byte of padding (PKCS): assert.strictEqual(dec(EVEN_LENGTH_ENCRYPTED_NOPAD, true), EVEN_LENGTH_PLAIN); -}, { +}, common.hasOpenSSL3 ? { + message: 'error:1C800064:Provider routines::bad decrypt', + reason: 'bad decrypt', + code: 'ERR_OSSL_BAD_DECRYPT', +} : { message: 'error:06065064:digital envelope routines:EVP_DecryptFinal_ex:' + 'bad decrypt', reason: 'bad decrypt', From e27bde8bdf497bfb529fef0c3c504ebe933a3319 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 22 Jun 2020 12:13:49 +0200 Subject: [PATCH 12/40] test: add OpenSSL3 error message check test-crypto-sign-verify.js --- test/parallel/test-crypto-sign-verify.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-crypto-sign-verify.js b/test/parallel/test-crypto-sign-verify.js index 8240e3685a42ee..3977d16dfad372 100644 --- a/test/parallel/test-crypto-sign-verify.js +++ b/test/parallel/test-crypto-sign-verify.js @@ -63,7 +63,9 @@ const keySize = 2048; key: keyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }); - }, { message: 'bye, bye, error stack' }); + }, { message: common.hasOpenSSL3 ? + 'error:1C8000A5:Provider routines::illegal or unsupported padding mode' : + 'bye, bye, error stack' }); delete Object.prototype.opensslErrorStack; } @@ -339,7 +341,10 @@ assert.throws( key: keyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }); - }, { + }, common.hasOpenSSL3 ? { + code: 'ERR_OSSL_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE', + message: /illegal or unsupported padding mode/, + } : { code: 'ERR_OSSL_RSA_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE', message: /illegal or unsupported padding mode/, opensslErrorStack: [ From f879b9c3790ae463021906553320086a513a2c09 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 22 Jun 2020 13:56:05 +0200 Subject: [PATCH 13/40] test: add OpenSSL3 error message check test-crypto-key-objects.js --- test/parallel/test-crypto-key-objects.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/test/parallel/test-crypto-key-objects.js b/test/parallel/test-crypto-key-objects.js index 6ee5334851dace..871d5da66c2bd3 100644 --- a/test/parallel/test-crypto-key-objects.js +++ b/test/parallel/test-crypto-key-objects.js @@ -292,7 +292,9 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem', // This should not cause a crash: https://github.com/nodejs/node/issues/25247 assert.throws(() => { createPrivateKey({ key: '' }); - }, { + }, common.hasOpenSSL3 ? { + message: 'Failed to read private key', + } : { message: 'error:0909006C:PEM routines:get_name:no start line', code: 'ERR_OSSL_PEM_NO_START_LINE', reason: 'no start line', @@ -500,7 +502,10 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem', { // Reading an encrypted key without a passphrase should fail. - assert.throws(() => createPrivateKey(privateDsa), { + assert.throws(() => createPrivateKey(privateDsa), common.hasOpenSSL3 ? { + name: 'Error', + message: 'Failed to read private key', + } : { name: 'TypeError', code: 'ERR_MISSING_PASSPHRASE', message: 'Passphrase required for encrypted key' @@ -512,7 +517,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem', key: privateDsa, format: 'pem', passphrase: Buffer.alloc(1025, 'a') - }), { + }), common.hasOpenSSL3 ? { name: 'Error' } : { code: 'ERR_OSSL_PEM_BAD_PASSWORD_READ', name: 'Error' }); @@ -524,7 +529,9 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem', format: 'pem', passphrase: Buffer.alloc(1024, 'a') }), { - message: /bad decrypt/ + message: common.hasOpenSSL3 ? + 'Failed to read private key' : + /bad decrypt/ }); const publicKey = createPublicKey(publicDsa); From b320aa38dad190d68ef20fd3fc81233dec4e3bc6 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 23 Jun 2020 14:24:34 +0200 Subject: [PATCH 14/40] test: add OpenSSL3 error message checks test-crypto.js --- test/parallel/test-crypto.js | 58 ++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 6b72dbd21cd07d..623320fb1907f1 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -216,8 +216,13 @@ assert.throws(() => { ].join('\n'); crypto.createSign('SHA256').update('test').sign(priv); }, (err) => { - assert.ok(!('opensslErrorStack' in err)); - assert.throws(() => { throw err; }, { + if (!common.hasOpenSSL3) + assert.ok(!('opensslErrorStack' in err)); + assert.throws(() => { throw err; }, common.hasOpenSSL3 ? { + name: 'Error', + message: 'error:02000070:rsa routines::digest too big for rsa key', + library: 'rsa routines', + } : { name: 'Error', message: /routines:RSA_sign:digest too big for rsa key$/, library: 'rsa routines', @@ -228,30 +233,33 @@ assert.throws(() => { return true; }); -assert.throws(() => { - // The correct header inside `rsa_private_pkcs8_bad.pem` should have been - // -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- - // instead of - // -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- - const sha1_privateKey = fixtures.readKey('rsa_private_pkcs8_bad.pem', - 'ascii'); - // This would inject errors onto OpenSSL's error stack - crypto.createSign('sha1').sign(sha1_privateKey); -}, (err) => { - // Do the standard checks, but then do some custom checks afterwards. - assert.throws(() => { throw err; }, { - message: 'error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag', - library: 'asn1 encoding routines', - function: 'asn1_check_tlen', - reason: 'wrong tag', - code: 'ERR_OSSL_ASN1_WRONG_TAG', +if (!common.hasOpenSSL3) { + assert.throws(() => { + // The correct header inside `rsa_private_pkcs8_bad.pem` should have been + // -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- + // instead of + // -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- + const sha1_privateKey = fixtures.readKey('rsa_private_pkcs8_bad.pem', + 'ascii'); + // This would inject errors onto OpenSSL's error stack + crypto.createSign('sha1').sign(sha1_privateKey); + }, (err) => { + // Do the standard checks, but then do some custom checks afterwards. + assert.throws(() => { throw err; }, { + message: 'error:0D0680A8:asn1 encoding routines:asn1_check_tlen:' + + 'wrong tag', + library: 'asn1 encoding routines', + function: 'asn1_check_tlen', + reason: 'wrong tag', + code: 'ERR_OSSL_ASN1_WRONG_TAG', + }); + // Throws crypto error, so there is an opensslErrorStack property. + // The openSSL stack should have content. + assert(Array.isArray(err.opensslErrorStack)); + assert(err.opensslErrorStack.length > 0); + return true; }); - // Throws crypto error, so there is an opensslErrorStack property. - // The openSSL stack should have content. - assert(Array.isArray(err.opensslErrorStack)); - assert(err.opensslErrorStack.length > 0); - return true; -}); +} // Make sure memory isn't released before being returned console.log(crypto.randomBytes(16)); From 183d4d9aa14f3a0fe384d00a58fa015c7798cddb Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 24 Jun 2020 06:00:06 +0200 Subject: [PATCH 15/40] test: add OpenSSL3 checks test-crypto-rsa-dsa.js --- test/parallel/test-crypto-rsa-dsa.js | 45 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/test/parallel/test-crypto-rsa-dsa.js b/test/parallel/test-crypto-rsa-dsa.js index 04de044be69aaa..94c810fa6f24c6 100644 --- a/test/parallel/test-crypto-rsa-dsa.js +++ b/test/parallel/test-crypto-rsa-dsa.js @@ -27,7 +27,7 @@ const dsaPkcs8KeyPem = fixtures.readKey('dsa_private_pkcs8.pem'); const ec = new TextEncoder(); -const decryptError = { +const openssl1DecryptError = { message: 'error:06065064:digital envelope routines:EVP_DecryptFinal_ex:' + 'bad decrypt', code: 'ERR_OSSL_EVP_BAD_DECRYPT', @@ -36,6 +36,13 @@ const decryptError = { library: 'digital envelope routines', }; +const decryptError = common.hasOpenSSL3 ? + { message: 'Failed to read asymmetric key' } : openssl1DecryptError; + +const decryptPrivateKeyError = common.hasOpenSSL3 ? { + message: 'Failed to read private key', +} : openssl1DecryptError; + function getBufferCopy(buf) { return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); } @@ -136,19 +143,25 @@ function getBufferCopy(buf) { assert.strictEqual(decryptedBufferWithPassword.toString(), input); // Now with RSA_NO_PADDING. Plaintext needs to match key size. - const plaintext = 'x'.repeat(rsaKeySize / 8); - encryptedBuffer = crypto.privateEncrypt({ - padding: crypto.constants.RSA_NO_PADDING, - key: rsaKeyPemEncrypted, - passphrase: bufferPassword - }, Buffer.from(plaintext)); - - decryptedBufferWithPassword = crypto.publicDecrypt({ - padding: crypto.constants.RSA_NO_PADDING, - key: rsaKeyPemEncrypted, - passphrase: bufferPassword - }, encryptedBuffer); - assert.strictEqual(decryptedBufferWithPassword.toString(), plaintext); + // OpenSSL 3.x has a rsa_check_padding that will cause an error if + // RSA_NO_PADDING is used. + if (!common.hasOpenSSL3) { + { + const plaintext = 'x'.repeat(rsaKeySize / 8); + encryptedBuffer = crypto.privateEncrypt({ + padding: crypto.constants.RSA_NO_PADDING, + key: rsaKeyPemEncrypted, + passphrase: bufferPassword + }, Buffer.from(plaintext)); + + decryptedBufferWithPassword = crypto.publicDecrypt({ + padding: crypto.constants.RSA_NO_PADDING, + key: rsaKeyPemEncrypted, + passphrase: bufferPassword + }, encryptedBuffer); + assert.strictEqual(decryptedBufferWithPassword.toString(), plaintext); + } + } encryptedBuffer = crypto.publicEncrypt(certPem, bufferToEncrypt); @@ -343,7 +356,7 @@ rsaSign.update(rsaPubPem); assert.throws(() => { const signOptions = { key: rsaKeyPemEncrypted, passphrase: 'wrong' }; rsaSign.sign(signOptions, 'hex'); -}, decryptError); +}, decryptPrivateKeyError); // // Test RSA signing and verification @@ -442,7 +455,7 @@ const input = 'I AM THE WALRUS'; sign.update(input); assert.throws(() => { sign.sign({ key: dsaKeyPemEncrypted, passphrase: 'wrong' }, 'hex'); - }, decryptError); + }, decryptPrivateKeyError); } { From f135cd00bc1bfedd7ba0176606de206e9a389cea Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 23 Jun 2020 13:19:35 +0200 Subject: [PATCH 16/40] test: add min/max iv lengths for OpenSSL3 test-crypto-cipheriv-decipheriv.js This commit adds min and max IV lengths to the test crypto-cipheriv-decipher-iv when OpenSSL 3.x is in use. The motivation for this is that OpenSSL 3.x has a check in providers/implementations/ciphers/ciphercommon_gcm: if (iv != NULL) { if (ivlen < ctx->ivlen_min || ivlen > sizeof(ctx->iv)) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); return 0; } And the ivlen_min is 8 and max is 64: (lldb) expr ctx->ivlen_min (size_t) $25 = 8 (lldb) expr sizeof(ctx->iv) (unsigned long) $28 = 64 (size_t) $25 = 8 --- test/parallel/test-crypto-cipheriv-decipheriv.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-crypto-cipheriv-decipheriv.js b/test/parallel/test-crypto-cipheriv-decipheriv.js index ea5b675db13487..87f3641fb188bd 100644 --- a/test/parallel/test-crypto-cipheriv-decipheriv.js +++ b/test/parallel/test-crypto-cipheriv-decipheriv.js @@ -193,7 +193,9 @@ assert.throws( errMessage); // But all other IV lengths should be accepted. -for (let n = 1; n < 256; n += 1) { +const minIvLength = common.hasOpenSSL3 ? 8 : 1; +const maxIvLength = common.hasOpenSSL3 ? 64 : 256; +for (let n = minIvLength; n < maxIvLength; n += 1) { if (common.hasFipsCrypto && n < 12) continue; crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16), Buffer.alloc(n)); } From 9afc54db0b166a22af4ca86b4804932e04d2c7fb Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 22 Jun 2020 14:22:29 +0200 Subject: [PATCH 17/40] test: skip blowfish if using OpenSSL3 test-crypto-ecb.js This commit adds a check and a skip if using OpenSSL 3.x. The reason for this is that Blowfish (BF) is only available when using the legacy provider in OpenSSL 3.x. --- test/parallel/test-crypto-ecb.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/parallel/test-crypto-ecb.js b/test/parallel/test-crypto-ecb.js index c88ebaabb05e7f..aecd858ef3bf1e 100644 --- a/test/parallel/test-crypto-ecb.js +++ b/test/parallel/test-crypto-ecb.js @@ -27,6 +27,10 @@ if (!common.hasCrypto) if (common.hasFipsCrypto) common.skip('BF-ECB is not FIPS 140-2 compatible'); +if (common.hasOpenSSL3) + common.skip('Blowfish is only available with the legacy provider in ' + + 'OpenSSl 3.x'); + const assert = require('assert'); const crypto = require('crypto'); From ae768e270e959589781703e90f9dcb20569558ee Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 23 Jun 2020 11:17:00 +0200 Subject: [PATCH 18/40] test: skip tls-cert-ext-encoding for OpenSSL 3.x test-tls-cert-ext-encoding.js --- test/parallel/test-tls-cert-ext-encoding.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/parallel/test-tls-cert-ext-encoding.js b/test/parallel/test-tls-cert-ext-encoding.js index d4b89473dc126d..4556b5791851c5 100644 --- a/test/parallel/test-tls-cert-ext-encoding.js +++ b/test/parallel/test-tls-cert-ext-encoding.js @@ -3,6 +3,16 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); +if (common.hasOpenSSL3) + // TODO(danbev) This test fails with the following error: + // error:0D00008F:asn1 encoding routines::no matching choice type + // + // I've not been able to figure out the reason for this but there + // is a note in https://wiki.openssl.org/index.php/OpenSSL_3.0 which + // indicates that this might not work at the moment: + // "OCSP, PEM, ASN.1 have some very limited library context support" + common.skip('when using OpenSSL 3.x'); + // NOTE: This certificate is hand-generated, hence it is not located in // `test/fixtures/keys` to avoid confusion. // From 6145d5738183f33ff675cf1d4cd986c0ea997878 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 25 Aug 2020 08:51:43 +0200 Subject: [PATCH 19/40] test: update error msg regex for OpenSSL 3.x test-tls-set-secure-context.js --- test/parallel/test-tls-set-secure-context.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-tls-set-secure-context.js b/test/parallel/test-tls-set-secure-context.js index f72daff6ef14fb..1e2abffa98bf67 100644 --- a/test/parallel/test-tls-set-secure-context.js +++ b/test/parallel/test-tls-set-secure-context.js @@ -53,9 +53,12 @@ server.listen(0, common.mustCall(() => { server.setSecureContext(credentialOptions[1]); firstResponse.write('request-'); + const errorMessageRegex = common.hasOpenSSL3 ? + /^Error: self-signed certificate$/ : + /^Error: self signed certificate$/; await assert.rejects(async () => { await makeRequest(port, 3); - }, /^Error: self signed certificate$/); + }, errorMessageRegex); server.setSecureContext(credentialOptions[0]); assert.strictEqual(await makeRequest(port, 4), 'success'); @@ -64,7 +67,7 @@ server.listen(0, common.mustCall(() => { firstResponse.end('fun!'); await assert.rejects(async () => { await makeRequest(port, 5); - }, /^Error: self signed certificate$/); + }, errorMessageRegex); assert.strictEqual(await firstRequest, 'multi-request-success-fun!'); server.close(); From fda8d728793ef381045ccf006f92a544a4d4bde2 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 25 Aug 2020 09:42:02 +0200 Subject: [PATCH 20/40] test: update OpenSSL 3.x error codes test-crypto-dh.js --- test/parallel/test-crypto-dh.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index 643dd55d5f6333..d08d07de4f8063 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -155,7 +155,7 @@ assert.strictEqual(secret1, secret4); let wrongBlockLength; if (common.hasOpenSSL3) { wrongBlockLength = { - message: 'error:3900006B:Provider routines::wrong final block length', + message: 'error:1C80006B:Provider routines::wrong final block length', code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH', library: 'Provider routines', reason: 'wrong final block length' @@ -188,9 +188,8 @@ if (common.hasOpenSSL3) { assert.throws(() => { dh3.computeSecret(''); }, { message: common.hasOpenSSL3 ? - 'error:05000066:Diffie-Hellman routines::invalid public key' : - 'Supplied key is too small' -}); + 'error:02800066:Diffie-Hellman routines::invalid public key' : + 'Supplied key is too small' }); // Create a shared using a DH group. const alice = crypto.createDiffieHellmanGroup('modp5'); From 1ff4d8d1cf3e03c3fb688938281c6d7017508435 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 25 Aug 2020 11:44:16 +0200 Subject: [PATCH 21/40] test: add openssl 3.x check to --openssl-config tests test-crypto-fips.js This commit adds a check to skip tests that depend on OpenSSL 1.x config files. These test will not work with OpenSSL 3.x as the configuration files have changed. Once FIPS support is available in OpenSSL 3.x we should revisit these test and add tests specific to OpenSSL 3.x. --- test/parallel/test-crypto-fips.js | 249 +++++++++++++++--------------- 1 file changed, 127 insertions(+), 122 deletions(-) diff --git a/test/parallel/test-crypto-fips.js b/test/parallel/test-crypto-fips.js index a1ed6451842c54..204951514a8ede 100644 --- a/test/parallel/test-crypto-fips.js +++ b/test/parallel/test-crypto-fips.js @@ -66,21 +66,6 @@ testHelper( 'require("crypto").getFips()', { ...process.env, 'OPENSSL_CONF': '' }); -// --enable-fips should turn FIPS mode on -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--enable-fips'], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").getFips()', - process.env); - -// --force-fips should turn FIPS mode on -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--force-fips'], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").getFips()', - process.env); // If Node was configured using --shared-openssl fips support might be // available depending on how OpenSSL was built. If fips support is @@ -120,120 +105,140 @@ if (!sharedOpenSSL()) { Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); } -testHelper( - 'stdout', - [`--openssl-config=${CNF_FIPS_OFF}`], - FIPS_DISABLED, - 'require("crypto").getFips()', - Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); +// OpenSSL 3.x has changed the configuration files so the following tests +// will not work as expected with that version. +// TODO(danbev) Revisit these test once FIPS support is available in +// OpenSSL 3.x. +if (!common.hasOpenSSL3) { + testHelper( + 'stdout', + [`--openssl-config=${CNF_FIPS_OFF}`], + FIPS_DISABLED, + 'require("crypto").getFips()', + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON })); -// --enable-fips should take precedence over OpenSSL config file -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").getFips()', - process.env); + // --enable-fips should take precedence over OpenSSL config file + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").getFips()', + process.env); + // --force-fips should take precedence over OpenSSL config file + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").getFips()', + process.env); + // --enable-fips should turn FIPS mode on + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--enable-fips'], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").getFips()', + process.env); -// OPENSSL_CONF should _not_ make a difference to --enable-fips -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--enable-fips'], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").getFips()', - Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); + // --force-fips should turn FIPS mode on + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--force-fips'], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").getFips()', + process.env); -// --force-fips should take precedence over OpenSSL config file -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").getFips()', - process.env); + // OPENSSL_CONF should _not_ make a difference to --enable-fips + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--enable-fips'], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").getFips()', + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); -// Using OPENSSL_CONF should not make a difference to --force-fips -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--force-fips'], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").getFips()', - Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); + // Using OPENSSL_CONF should not make a difference to --force-fips + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--force-fips'], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").getFips()', + Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF })); -// setFipsCrypto should be able to turn FIPS mode on -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - [], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - '(require("crypto").setFips(true),' + - 'require("crypto").getFips())', - process.env); + // setFipsCrypto should be able to turn FIPS mode on + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + [], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + '(require("crypto").setFips(true),' + + 'require("crypto").getFips())', + process.env); -// setFipsCrypto should be able to turn FIPS mode on and off -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - [], - testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, - '(require("crypto").setFips(true),' + - 'require("crypto").setFips(false),' + - 'require("crypto").getFips())', - process.env); + // setFipsCrypto should be able to turn FIPS mode on and off + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + [], + testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, + '(require("crypto").setFips(true),' + + 'require("crypto").setFips(false),' + + 'require("crypto").getFips())', + process.env); -// setFipsCrypto takes precedence over OpenSSL config file, FIPS on -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - [`--openssl-config=${CNF_FIPS_OFF}`], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - '(require("crypto").setFips(true),' + - 'require("crypto").getFips())', - process.env); - -// setFipsCrypto takes precedence over OpenSSL config file, FIPS off -testHelper( - 'stdout', - [`--openssl-config=${CNF_FIPS_ON}`], - FIPS_DISABLED, - '(require("crypto").setFips(false),' + - 'require("crypto").getFips())', - process.env); + // setFipsCrypto takes precedence over OpenSSL config file, FIPS on + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + [`--openssl-config=${CNF_FIPS_OFF}`], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + '(require("crypto").setFips(true),' + + 'require("crypto").getFips())', + process.env); -// --enable-fips does not prevent use of setFipsCrypto API -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--enable-fips'], - testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, - '(require("crypto").setFips(false),' + - 'require("crypto").getFips())', - process.env); - -// --force-fips prevents use of setFipsCrypto API -testHelper( - 'stderr', - ['--force-fips'], - testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").setFips(false)', - process.env); + // setFipsCrypto takes precedence over OpenSSL config file, FIPS off + testHelper( + 'stdout', + [`--openssl-config=${CNF_FIPS_ON}`], + FIPS_DISABLED, + '(require("crypto").setFips(false),' + + 'require("crypto").getFips())', + process.env); -// --force-fips makes setFipsCrypto enable a no-op (FIPS stays on) -testHelper( - testFipsCrypto() ? 'stdout' : 'stderr', - ['--force-fips'], - testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, - '(require("crypto").setFips(true),' + - 'require("crypto").getFips())', - process.env); - -// --force-fips and --enable-fips order does not matter -testHelper( - 'stderr', - ['--force-fips', '--enable-fips'], - testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").setFips(false)', - process.env); + // --enable-fips does not prevent use of setFipsCrypto API + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--enable-fips'], + testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING, + '(require("crypto").setFips(false),' + + 'require("crypto").getFips())', + process.env); -// --enable-fips and --force-fips order does not matter -testHelper( - 'stderr', - ['--enable-fips', '--force-fips'], - testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, - 'require("crypto").setFips(false)', - process.env); + // --force-fips prevents use of setFipsCrypto API + testHelper( + 'stderr', + ['--force-fips'], + testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").setFips(false)', + process.env); + + // --force-fips makes setFipsCrypto enable a no-op (FIPS stays on) + testHelper( + testFipsCrypto() ? 'stdout' : 'stderr', + ['--force-fips'], + testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING, + '(require("crypto").setFips(true),' + + 'require("crypto").getFips())', + process.env); + + // --force-fips and --enable-fips order does not matter + testHelper( + 'stderr', + ['--force-fips', '--enable-fips'], + testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").setFips(false)', + process.env); + + // --enable-fips and --force-fips order does not matter + testHelper( + 'stderr', + ['--enable-fips', '--force-fips'], + testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING, + 'require("crypto").setFips(false)', + process.env); +} From 0f8b754d3db579ab672a7a5a218eda8130bf2e47 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 27 Aug 2020 14:55:16 +0200 Subject: [PATCH 22/40] test: specify security level 0 for tls-session-cache test-tls-session-cache.js Currently this test will fail if the default security level 1 is used when linked against OpenSSL 3.x. --- test/parallel/test-tls-session-cache.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/parallel/test-tls-session-cache.js b/test/parallel/test-tls-session-cache.js index 2be093a4f596fc..92d39f763fc3b8 100644 --- a/test/parallel/test-tls-session-cache.js +++ b/test/parallel/test-tls-session-cache.js @@ -50,6 +50,7 @@ function doTest(testOptions, callback) { requestCert: true, rejectUnauthorized: false, secureProtocol: 'TLS_method', + ciphers: 'RSA@SECLEVEL=0' }; let requestCount = 0; let resumeCount = 0; From 14973b512b32d66e0f9906b00e041cff36a04f54 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 31 Aug 2020 06:16:22 +0200 Subject: [PATCH 23/40] test: set security level to 0 test-https-agent-session-eviction.js, test-tls-getprotocol.js, test-tls-min-max-version.js --- test/parallel/test-https-agent-session-eviction.js | 3 ++- test/parallel/test-tls-getprotocol.js | 1 + test/parallel/test-tls-min-max-version.js | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-https-agent-session-eviction.js b/test/parallel/test-https-agent-session-eviction.js index 3f5cd36e8b1799..940c43cc40bf15 100644 --- a/test/parallel/test-https-agent-session-eviction.js +++ b/test/parallel/test-https-agent-session-eviction.js @@ -13,7 +13,8 @@ const { SSL_OP_NO_TICKET } = require('crypto').constants; const options = { key: readKey('agent1-key.pem'), cert: readKey('agent1-cert.pem'), - secureOptions: SSL_OP_NO_TICKET + secureOptions: SSL_OP_NO_TICKET, + ciphers: 'RSA@SECLEVEL=0' }; // Create TLS1.2 server diff --git a/test/parallel/test-tls-getprotocol.js b/test/parallel/test-tls-getprotocol.js index a76ff0f3442a97..e4a16a818b5ba1 100644 --- a/test/parallel/test-tls-getprotocol.js +++ b/test/parallel/test-tls-getprotocol.js @@ -18,6 +18,7 @@ const clientConfigs = [ const serverConfig = { secureProtocol: 'TLS_method', + ciphers: 'RSA@SECLEVEL=0', key: fixtures.readKey('agent2-key.pem'), cert: fixtures.readKey('agent2-cert.pem') }; diff --git a/test/parallel/test-tls-min-max-version.js b/test/parallel/test-tls-min-max-version.js index 7ef0f12426537c..9a0ce8cd06e09e 100644 --- a/test/parallel/test-tls-min-max-version.js +++ b/test/parallel/test-tls-min-max-version.js @@ -32,6 +32,7 @@ function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) { minVersion: smin, maxVersion: smax, secureProtocol: sprot, + ciphers: 'ALL@SECLEVEL=0' }, }, common.mustCall((err, pair, cleanup) => { function u(_) { return _ === undefined ? 'U' : _; } From e2d35923418e5c245646321f338659818dcdeec4 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 31 Aug 2020 09:47:36 +0200 Subject: [PATCH 24/40] test: test-crypto-keygen fixes for OpenSSL 3.x test-crypto-keygen.js Note that there is still an issue with OpenSSL 3.x for which there is an open issue: https://github.com/openssl/openssl/issues/12384 --- test/parallel/test-crypto-keygen.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 237cfdd697c51c..9ddd15918b6a79 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -192,7 +192,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); // Now do the same with an encrypted private key. generateKeyPair('rsa', { - publicExponent: 0x1001, + publicExponent: 0x10001, modulusLength: 512, publicKeyEncoding, privateKeyEncoding: { @@ -210,11 +210,17 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); // Since the private key is encrypted, signing shouldn't work anymore. const publicKey = { key: publicKeyDER, ...publicKeyEncoding }; - assert.throws(() => testSignVerify(publicKey, privateKey), { + const expectedError = common.hasOpenSSL3 ? { + name: 'Error', + code: 'ERR_OSSL_OSSL_STORE_UI_PROCESS_INTERRUPTED_OR_CANCELLED', + message: 'error:1600006D:STORE routines::ui process interrupted or ' + + 'cancelled' + } : { name: 'TypeError', code: 'ERR_MISSING_PASSPHRASE', message: 'Passphrase required for encrypted key' - }); + }; + assert.throws(() => testSignVerify(publicKey, privateKey), expectedError); const key = { key: privateKey, passphrase: 'secret' }; testEncryptDecrypt(publicKey, key); From 3e117b9df8a3b696030c0b1f4c8436478acdc145 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 8 Sep 2020 14:18:45 +0200 Subject: [PATCH 25/40] test: add security level 0 to test-https-agent-additional-options.js --- test/parallel/test-https-agent-additional-options.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/parallel/test-https-agent-additional-options.js b/test/parallel/test-https-agent-additional-options.js index 2b5446b9e3d194..c92b17641d0b58 100644 --- a/test/parallel/test-https-agent-additional-options.js +++ b/test/parallel/test-https-agent-additional-options.js @@ -13,6 +13,7 @@ const options = { cert: fixtures.readKey('agent1-cert.pem'), ca: fixtures.readKey('ca1-cert.pem'), minVersion: 'TLSv1.1', + ciphers: 'ALL@SECLEVEL=0' }; const server = https.Server(options, (req, res) => { @@ -27,6 +28,7 @@ function getBaseOptions(port) { ca: options.ca, rejectUnauthorized: true, servername: 'agent1', + ciphers: 'ALL@SECLEVEL=0' }; } From 4003105a484d5d20aa860a8e8dfdde12b19d867f Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 8 Sep 2020 14:18:45 +0200 Subject: [PATCH 26/40] test: add security level 0 to test-tls-write-error.js --- test/parallel/test-tls-write-error.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-tls-write-error.js b/test/parallel/test-tls-write-error.js index 2783e62d063a28..776fe65c722637 100644 --- a/test/parallel/test-tls-write-error.js +++ b/test/parallel/test-tls-write-error.js @@ -16,7 +16,8 @@ const server_cert = fixtures.readKey('agent1-cert.pem'); const opts = { key: server_key, - cert: server_cert + cert: server_cert, + ciphers: 'ALL@SECLEVEL=0' }; const server = https.createServer(opts, (req, res) => { From 2964e25aee9d9ecee3dc260b81314b684d486b51 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 13 Oct 2020 12:34:50 +0200 Subject: [PATCH 27/40] test: fix "bad ffc parameters" error test-crypto-keygen.js --- test/parallel/test-crypto-keygen.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 9ddd15918b6a79..11242b06fb656f 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -213,8 +213,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); const expectedError = common.hasOpenSSL3 ? { name: 'Error', code: 'ERR_OSSL_OSSL_STORE_UI_PROCESS_INTERRUPTED_OR_CANCELLED', - message: 'error:1600006D:STORE routines::ui process interrupted or ' + - 'cancelled' + message: 'Failed to read private key' } : { name: 'TypeError', code: 'ERR_MISSING_PASSPHRASE', @@ -388,7 +387,6 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); }); })); } - { // Test async DSA key object generation. generateKeyPair('dsa', { From af5997f189713a930f75f2d71c14009bc1a9eb7f Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 27 Oct 2020 09:11:51 +0100 Subject: [PATCH 28/40] test: add OpenSSL3.x checks to test-crypto-hkdf.js --- test/parallel/test-crypto-hkdf.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/parallel/test-crypto-hkdf.js b/test/parallel/test-crypto-hkdf.js index 777f184d6b8366..ee9f56c87c430d 100644 --- a/test/parallel/test-crypto-hkdf.js +++ b/test/parallel/test-crypto-hkdf.js @@ -113,11 +113,14 @@ const { }); } -[ +const algorithms = [ ['sha256', 'secret', 'salt', 'info', 10], ['sha512', 'secret', 'salt', '', 15], - ['whirlpool', 'secret', '', 'info', 20], -].forEach(([ hash, secret, salt, info, length ]) => { +]; +if (!common.hasOpenSSL3) + algorithms.push(['whirlpool', 'secret', '', 'info', 20]); + +algorithms.forEach(([ hash, secret, salt, info, length ]) => { { const syncResult = hkdfSync(hash, secret, salt, info, length); assert(syncResult instanceof ArrayBuffer); @@ -204,7 +207,8 @@ const { } }); -{ + +if (!common.hasOpenSSL3) { const kKnownUnsupported = ['shake128', 'shake256']; getHashes() .filter((hash) => !kKnownUnsupported.includes(hash)) From ed8848700b841ba4840bd4988bd7909bbfd78a2b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 27 Oct 2020 09:31:16 +0100 Subject: [PATCH 29/40] test: add OpenSSl3.x check in test-crypto-pbkdf2.js --- test/parallel/test-crypto-pbkdf2.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-crypto-pbkdf2.js b/test/parallel/test-crypto-pbkdf2.js index ea0fbab7744b1f..260bdd394ce05e 100644 --- a/test/parallel/test-crypto-pbkdf2.js +++ b/test/parallel/test-crypto-pbkdf2.js @@ -223,9 +223,11 @@ assert.throws( } ); -const kNotPBKDF2Supported = ['shake128', 'shake256']; -crypto.getHashes() - .filter((hash) => !kNotPBKDF2Supported.includes(hash)) - .forEach((hash) => { - runPBKDF2(new Uint8Array(10), 'salt', 8, 8, hash); - }); +if (!common.hasOpenSSL3) { + const kNotPBKDF2Supported = ['shake128', 'shake256']; + crypto.getHashes() + .filter((hash) => !kNotPBKDF2Supported.includes(hash)) + .forEach((hash) => { + runPBKDF2(new Uint8Array(10), 'salt', 8, 8, hash); + }); +} From 8a42ca9c8d76d929da0bde9dcb06f09550182f58 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 27 Oct 2020 13:44:15 +0100 Subject: [PATCH 30/40] test: add OpenSSL3.x checks test-crypto-keygen.js --- test/parallel/test-crypto-keygen.js | 71 +++++++++++++++++------------ 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 11242b06fb656f..82ed8c238006cf 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -105,10 +105,10 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); assert.strictEqual(typeof publicKey, 'string'); assert(pkcs1PubExp.test(publicKey)); - assertApproximateSize(publicKey, 162); + assertApproximateSize(publicKey, common.hasOpenSSL3 ? 426 : 162); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs8Exp.test(privateKey)); - assertApproximateSize(privateKey, 512); + assertApproximateSize(privateKey, common.hasOpenSSL3 ? 1704 : 512); testEncryptDecrypt(publicKey, privateKey); testSignVerify(publicKey, privateKey); @@ -179,11 +179,11 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKey) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, 74); + assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs1PrivExp.test(privateKey)); - assertApproximateSize(privateKey, 512); + assertApproximateSize(privateKey, common.hasOpenSSL3 ? 1675 : 512); const publicKey = { key: publicKeyDER, ...publicKeyEncoding }; testEncryptDecrypt(publicKey, privateKey); @@ -203,7 +203,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKey) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, 74); + assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs1EncExp('AES-256-CBC').test(privateKey)); @@ -212,7 +212,6 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); const publicKey = { key: publicKeyDER, ...publicKeyEncoding }; const expectedError = common.hasOpenSSL3 ? { name: 'Error', - code: 'ERR_OSSL_OSSL_STORE_UI_PROCESS_INTERRUPTED_OR_CANCELLED', message: 'Failed to read private key' } : { name: 'TypeError', @@ -239,7 +238,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKeyDER) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, 74); + assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); assert(Buffer.isBuffer(privateKeyDER)); @@ -280,7 +279,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKeyDER) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, 74); + assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); assert(Buffer.isBuffer(privateKeyDER)); @@ -475,11 +474,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); assert(sec1EncExp('AES-128-CBC').test(privateKey)); // Since the private key is encrypted, signing shouldn't work anymore. - assert.throws(() => testSignVerify(publicKey, privateKey), { - name: 'TypeError', - code: 'ERR_MISSING_PASSPHRASE', - message: 'Passphrase required for encrypted key' - }); + assert.throws(() => testSignVerify(publicKey, privateKey), + common.hasOpenSSL3 ? { + message: 'Failed to read private key' + } : { + name: 'TypeError', + code: 'ERR_MISSING_PASSPHRASE', + message: 'Passphrase required for encrypted key' + }); testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' }); })); @@ -505,11 +507,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); assert(sec1EncExp('AES-128-CBC').test(privateKey)); // Since the private key is encrypted, signing shouldn't work anymore. - assert.throws(() => testSignVerify(publicKey, privateKey), { - name: 'TypeError', - code: 'ERR_MISSING_PASSPHRASE', - message: 'Passphrase required for encrypted key' - }); + assert.throws(() => testSignVerify(publicKey, privateKey), + common.hasOpenSSL3 ? { + message: 'Failed to read private key' + } : { + name: 'TypeError', + code: 'ERR_MISSING_PASSPHRASE', + message: 'Passphrase required for encrypted key' + }); testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' }); })); @@ -538,11 +543,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); assert(pkcs8EncExp.test(privateKey)); // Since the private key is encrypted, signing shouldn't work anymore. - assert.throws(() => testSignVerify(publicKey, privateKey), { - name: 'TypeError', - code: 'ERR_MISSING_PASSPHRASE', - message: 'Passphrase required for encrypted key' - }); + assert.throws(() => testSignVerify(publicKey, privateKey), + common.hasOpenSSL3 ? { + message: 'Failed to read private key' + } : { + name: 'TypeError', + code: 'ERR_MISSING_PASSPHRASE', + message: 'Passphrase required for encrypted key' + }); testSignVerify(publicKey, { key: privateKey, @@ -572,11 +580,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); assert(pkcs8EncExp.test(privateKey)); // Since the private key is encrypted, signing shouldn't work anymore. - assert.throws(() => testSignVerify(publicKey, privateKey), { - name: 'TypeError', - code: 'ERR_MISSING_PASSPHRASE', - message: 'Passphrase required for encrypted key' - }); + assert.throws(() => testSignVerify(publicKey, privateKey), + common.hasOpenSSL3 ? { + message: 'Failed to read private key' + } : { + name: 'TypeError', + code: 'ERR_MISSING_PASSPHRASE', + message: 'Passphrase required for encrypted key' + }); testSignVerify(publicKey, { key: privateKey, @@ -625,11 +636,11 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); const { publicKey, privateKey } = keys; assert.strictEqual(typeof publicKey, 'string'); assert(pkcs1PubExp.test(publicKey)); - assertApproximateSize(publicKey, 180); + assertApproximateSize(publicKey, common.hasOpenSSL3 ? 426 : 180); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs1PrivExp.test(privateKey)); - assertApproximateSize(privateKey, 512); + assertApproximateSize(privateKey, common.hasOpenSSL3 ? 1675 : 512); testEncryptDecrypt(publicKey, privateKey); testSignVerify(publicKey, privateKey); From 408186f4341549a7a93e676b0dff97848a6b780e Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 11 Jan 2021 12:52:01 +0100 Subject: [PATCH 31/40] test: fix error regex for OpenSSL 3.x test-tls-passphase.js --- test/parallel/test-tls-passphrase.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-tls-passphrase.js b/test/parallel/test-tls-passphrase.js index c3a99c3eb34833..610bbefe46c9c0 100644 --- a/test/parallel/test-tls-passphrase.js +++ b/test/parallel/test-tls-passphrase.js @@ -223,7 +223,8 @@ server.listen(0, common.mustCall(function() { }, onSecureConnect()); })).unref(); -const errMessagePassword = /bad decrypt/; +const errMessagePassword = common.hasOpenSSL3 ? + /processing error/ : /bad decrypt/; // Missing passphrase assert.throws(function() { From 875f060e22b6cd4af3d4fedc99d832e7e190f247 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 12 Jan 2021 15:16:15 +0100 Subject: [PATCH 32/40] test: add OpenSSL3.x checks test-crypto-x509.js This commit adds an check for OpenSSL 3.0 to deal with changes to the newline output of infoAccess. Refs: https://github.com/danbev/learning-libcrypto/blob/master/notes/issues.md#test-crypto-x509js --- test/parallel/test-crypto-x509.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-crypto-x509.js b/test/parallel/test-crypto-x509.js index d768a1b9c5e661..0915cb61fd4226 100644 --- a/test/parallel/test-crypto-x509.js +++ b/test/parallel/test-crypto-x509.js @@ -46,9 +46,10 @@ OU=Node.js CN=ca1 emailAddress=ry@tinyclouds.org`; -const infoAccessCheck = `OCSP - URI:http://ocsp.nodejs.org/ -CA Issuers - URI:http://ca.nodejs.org/ca.cert -`; +let infoAccessCheck = `OCSP - URI:http://ocsp.nodejs.org/ +CA Issuers - URI:http://ca.nodejs.org/ca.cert`; +if (!common.hasOpenSSL3) + infoAccessCheck += '\n'; const der = Buffer.from( '308202d830820241a003020102020900ecc9b856270da9a830' + @@ -207,8 +208,11 @@ const der = Buffer.from( 'CN=ca1\n' + 'emailAddress=ry@tinyclouds.org', infoAccess: - 'OCSP - URI:http://ocsp.nodejs.org/\n' + - 'CA Issuers - URI:http://ca.nodejs.org/ca.cert\n', + common.hasOpenSSL3 ? + 'OCSP - URI:http://ocsp.nodejs.org/\n' + + 'CA Issuers - URI:http://ca.nodejs.org/ca.cert' : + 'OCSP - URI:http://ocsp.nodejs.org/\n' + + 'CA Issuers - URI:http://ca.nodejs.org/ca.cert\n', modulus: 'EF5440701637E28ABB038E5641F828D834C342A9D25EDBB86A2BF' + '6FBD809CB8E037A98B71708E001242E4DEB54C6164885F599DD87' + 'A23215745955BE20417E33C4D0D1B80C9DA3DE419A2607195D2FB' + From 37bb747306a01f1ef6d43f25dc1d823011f12ca7 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 13 Jan 2021 06:14:07 +0100 Subject: [PATCH 33/40] test: add OpenSSL3.x checks test-crypto-sign-verify.js --- test/parallel/test-crypto-sign-verify.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-crypto-sign-verify.js b/test/parallel/test-crypto-sign-verify.js index 3977d16dfad372..dc90e5b311bdf3 100644 --- a/test/parallel/test-crypto-sign-verify.js +++ b/test/parallel/test-crypto-sign-verify.js @@ -44,7 +44,9 @@ const keySize = 2048; `-----BEGIN RSA PRIVATE KEY----- AAAAAAAAAAAA -----END RSA PRIVATE KEY-----`); - }, { message: 'bye, bye, library' }); + }, { message: common.hasOpenSSL3 ? + 'Failed to read private key' : + 'bye, bye, library' }); delete Object.prototype.library; From 4aff4cb12396f39b2e7e3a75d1dcdb385cae5338 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 10 Feb 2021 11:30:22 +0100 Subject: [PATCH 34/40] test: remove OpenSSL3 specific sizes test-crypto-keygen.js --- test/parallel/test-crypto-keygen.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 82ed8c238006cf..dd005f8ea94000 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -105,10 +105,10 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); assert.strictEqual(typeof publicKey, 'string'); assert(pkcs1PubExp.test(publicKey)); - assertApproximateSize(publicKey, common.hasOpenSSL3 ? 426 : 162); + assertApproximateSize(publicKey, 162); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs8Exp.test(privateKey)); - assertApproximateSize(privateKey, common.hasOpenSSL3 ? 1704 : 512); + assertApproximateSize(privateKey, 512); testEncryptDecrypt(publicKey, privateKey); testSignVerify(publicKey, privateKey); @@ -179,11 +179,11 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKey) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); + assertApproximateSize(publicKeyDER, 74); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs1PrivExp.test(privateKey)); - assertApproximateSize(privateKey, common.hasOpenSSL3 ? 1675 : 512); + assertApproximateSize(privateKey, 512); const publicKey = { key: publicKeyDER, ...publicKeyEncoding }; testEncryptDecrypt(publicKey, privateKey); @@ -203,7 +203,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKey) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); + assertApproximateSize(publicKeyDER, 74); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs1EncExp('AES-256-CBC').test(privateKey)); @@ -238,7 +238,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKeyDER) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); + assertApproximateSize(publicKeyDER, 74); assert(Buffer.isBuffer(privateKeyDER)); @@ -279,7 +279,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } }, common.mustSucceed((publicKeyDER, privateKeyDER) => { assert(Buffer.isBuffer(publicKeyDER)); - assertApproximateSize(publicKeyDER, common.hasOpenSSL3 ? 270 : 74); + assertApproximateSize(publicKeyDER, 74); assert(Buffer.isBuffer(privateKeyDER)); @@ -636,11 +636,11 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); const { publicKey, privateKey } = keys; assert.strictEqual(typeof publicKey, 'string'); assert(pkcs1PubExp.test(publicKey)); - assertApproximateSize(publicKey, common.hasOpenSSL3 ? 426 : 180); + assertApproximateSize(publicKey, 180); assert.strictEqual(typeof privateKey, 'string'); assert(pkcs1PrivExp.test(privateKey)); - assertApproximateSize(privateKey, common.hasOpenSSL3 ? 1675 : 512); + assertApproximateSize(privateKey, 512); testEncryptDecrypt(publicKey, privateKey); testSignVerify(publicKey, privateKey); @@ -1044,7 +1044,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); // Test classic Diffie-Hellman key generation. { generateKeyPair('dh', { - primeLength: common.hasOpenSSL3 ? 2048 : 1024 + primeLength: 1024 }, common.mustSucceed((publicKey, privateKey) => { assert.strictEqual(publicKey.type, 'public'); assert.strictEqual(publicKey.asymmetricKeyType, 'dh'); From 7d598719099b14610662b25ff66971d7ba78d2b8 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 10 Feb 2021 11:30:58 +0100 Subject: [PATCH 35/40] test: add OpenSSL3 check for empty passphrase test test-crypto-keygen.js --- test/parallel/test-crypto-keygen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index dd005f8ea94000..af73d5a6b45fd6 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -1261,7 +1261,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); } } -{ +if (!common.hasOpenSSL3) { // Passing an empty passphrase string should not cause OpenSSL's default // passphrase prompt in the terminal. // See https://github.com/nodejs/node/issues/35898. From d92e224a8a1ec492b95206a04fc93a6300af8dde Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 1 Mar 2021 10:09:43 +0100 Subject: [PATCH 36/40] test: add OpenSSL 3.0 checks in test-crypto-dh-stateless.js --- test/parallel/test-crypto-dh-stateless.js | 29 +++++++++++++++-------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/test/parallel/test-crypto-dh-stateless.js b/test/parallel/test-crypto-dh-stateless.js index 3d0c1b497d7adc..9e26a318669c4e 100644 --- a/test/parallel/test-crypto-dh-stateless.js +++ b/test/parallel/test-crypto-dh-stateless.js @@ -57,7 +57,6 @@ const alicePrivateKey = crypto.createPrivateKey({ '-----END PRIVATE KEY-----', format: 'pem' }); - const alicePublicKey = crypto.createPublicKey({ key: '-----BEGIN PUBLIC KEY-----\n' + 'MIIBnzCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc\n' + @@ -135,7 +134,6 @@ const dh = crypto.createDiffieHellman(group.getPrime(), group.getGenerator()); dh.setPrivateKey(privateKey); // Test simple Diffie-Hellman, no curves involved. - test({ publicKey: alicePublicKey, privateKey: alicePrivateKey }, { publicKey: bobPublicKey, privateKey: bobPrivateKey }, dh.computeSecret(publicKey)); @@ -146,23 +144,31 @@ test(crypto.generateKeyPairSync('dh', { group: 'modp5' }), test(crypto.generateKeyPairSync('dh', { group: 'modp5' }), crypto.generateKeyPairSync('dh', { prime: group.getPrime() })); -for (const [params1, params2] of [ +const list = [ // Same generator, but different primes. - [{ group: 'modp5' }, { group: 'modp18' }], + [{ group: 'modp5' }, { group: 'modp18' }]]; + +// TODO(danbev): Take a closer look if there should be a check in OpenSSL3 +// when the dh parameters differ. +if (!common.hasOpenSSL3) { // Same primes, but different generator. - [{ group: 'modp5' }, { prime: group.getPrime(), generator: 5 }], + list.push([{ group: 'modp5' }, { prime: group.getPrime(), generator: 5 }]); // Same generator, but different primes. - [{ primeLength: 1024 }, { primeLength: 1024 }] -]) { + list.push([{ primeLength: 1024 }, { primeLength: 1024 }]); +} + +for (const [params1, params2] of list) { assert.throws(() => { test(crypto.generateKeyPairSync('dh', params1), crypto.generateKeyPairSync('dh', params2)); - }, { + }, common.hasOpenSSL3 ? { + name: 'Error', + code: 'ERR_OSSL_DH_INVALID_PUBLIC_KEY' + } : { name: 'Error', code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS' }); } - { const privateKey = crypto.createPrivateKey({ key: '-----BEGIN PRIVATE KEY-----\n' + @@ -214,7 +220,10 @@ const not256k1 = crypto.getCurves().find((c) => /^sec.*(224|384|512)/.test(c)); assert.throws(() => { test(crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' }), crypto.generateKeyPairSync('ec', { namedCurve: not256k1 })); -}, { +}, common.hasOpenSSL3 ? { + name: 'Error', + code: 'ERR_OSSL_EC_INCOMPATIBLE_OBJECTS' +} : { name: 'Error', code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS' }); From ec3237ab6c4f101940b6dc753fc240495d97702b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 1 Mar 2021 14:28:22 +0100 Subject: [PATCH 37/40] src: use EVP_default_properties_is_fips_enabled This commit adds a macro check for OpenSSL 3 and used EVP_default_properties_is_fips_enabled instead of FIPS_mode which has been removed in OpenSSL 3. --- src/crypto/crypto_cipher.cc | 11 ++++++++++- src/crypto/crypto_sig.cc | 5 +++++ src/crypto/crypto_util.cc | 18 ++++++++++++++++++ src/node.cc | 4 ++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index 47764b5bc7f153..c9c3563ef917ec 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -342,8 +342,11 @@ void CipherBase::Init(const char* cipher_type, unsigned int auth_tag_len) { HandleScope scope(env()->isolate()); MarkPopErrorOnReturn mark_pop_error_on_return; - +#if OPENSSL_VERSION_MAJOR >= 3 + if (EVP_default_properties_is_fips_enabled(nullptr)) { +#else if (FIPS_mode()) { +#endif return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(), "crypto.createCipher() is not supported in FIPS mode."); } @@ -527,7 +530,13 @@ bool CipherBase::InitAuthenticated( } // TODO(tniessen) Support CCM decryption in FIPS mode + +#if OPENSSL_VERSION_MAJOR >= 3 + if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher && + EVP_default_properties_is_fips_enabled(nullptr)) { +#else if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher && FIPS_mode()) { +#endif THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(), "CCM encryption not supported in FIPS mode"); return false; diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc index 946ac250f2fa01..43790a5970424e 100644 --- a/src/crypto/crypto_sig.cc +++ b/src/crypto/crypto_sig.cc @@ -28,7 +28,12 @@ namespace crypto { namespace { bool ValidateDSAParameters(EVP_PKEY* key) { /* Validate DSA2 parameters from FIPS 186-4 */ +#if OPENSSL_VERSION_MAJOR >= 3 + if (EVP_default_properties_is_fips_enabled(nullptr) && + EVP_PKEY_DSA == EVP_PKEY_base_id(key)) { +#else if (FIPS_mode() && EVP_PKEY_DSA == EVP_PKEY_base_id(key)) { +#endif DSA* dsa = EVP_PKEY_get0_DSA(key); const BIGNUM* p; DSA_get0_pqg(dsa, &p, nullptr, nullptr); diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 9644dc4dc7f9aa..9c35a7cabbf551 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -137,7 +137,12 @@ void InitCryptoOnce() { unsigned long err = 0; // NOLINT(runtime/int) if (per_process::cli_options->enable_fips_crypto || per_process::cli_options->force_fips_crypto) { +#if OPENSSL_VERSION_MAJOR >= 3 + if (0 == EVP_default_properties_is_fips_enabled(nullptr) && + !EVP_default_properties_enable_fips(nullptr, 1)) { +#else if (0 == FIPS_mode() && !FIPS_mode_set(1)) { +#endif err = ERR_get_error(); } } @@ -160,7 +165,12 @@ void InitCryptoOnce() { } void GetFipsCrypto(const FunctionCallbackInfo& args) { +#if OPENSSL_VERSION_MAJOR >= 3 + args.GetReturnValue().Set(EVP_default_properties_is_fips_enabled(nullptr) ? + 1 : 0); +#else args.GetReturnValue().Set(FIPS_mode() ? 1 : 0); +#endif } void SetFipsCrypto(const FunctionCallbackInfo& args) { @@ -168,10 +178,18 @@ void SetFipsCrypto(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); bool enable = args[0]->BooleanValue(env->isolate()); +#if OPENSSL_VERSION_MAJOR >= 3 + if (enable == EVP_default_properties_is_fips_enabled(nullptr)) +#else if (enable == FIPS_mode()) +#endif return; // No action needed. +#if OPENSSL_VERSION_MAJOR >= 3 + if (!EVP_default_properties_enable_fips(nullptr, enable)) { +#else if (!FIPS_mode_set(enable)) { +#endif unsigned long err = ERR_get_error(); // NOLINT(runtime/int) return ThrowCryptoError(env, err); } diff --git a/src/node.cc b/src/node.cc index eed3a1dbfa83cc..b757013ce125cd 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1015,8 +1015,12 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) { } // In the case of FIPS builds we should make sure // the random source is properly initialized first. +#if OPENSSL_VERSION_MAJOR >= 3 + if (EVP_default_properties_is_fips_enabled(nullptr)) { +#else if (FIPS_mode()) { OPENSSL_init(); +#endif } // V8 on Windows doesn't have a good source of entropy. Seed it from // OpenSSL's pool. From 8efd22a9d42092b16dcbc053098786df421f3019 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 8 Sep 2020 14:15:49 +0200 Subject: [PATCH 38/40] test: add OpenSSL 3.x checks to test-tls-min-max-version.js --- test/parallel/test-tls-min-max-version.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-tls-min-max-version.js b/test/parallel/test-tls-min-max-version.js index 9a0ce8cd06e09e..8dbef1fa37aa2d 100644 --- a/test/parallel/test-tls-min-max-version.js +++ b/test/parallel/test-tls-min-max-version.js @@ -14,6 +14,14 @@ const DEFAULT_MAX_VERSION = tls.DEFAULT_MAX_VERSION; function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) { assert(proto || cerr || serr, 'test missing any expectations'); + + let ciphers; + if (common.hasOpenSSL3 && (proto === 'TLSv1' || proto === 'TLSv1.1' || + proto === 'TLSv1_1_method' || proto === 'TLSv1_method' || + sprot === 'TLSv1_1_method' || sprot === 'TLSv1_method')) { + if (serr !== 'ERR_SSL_UNSUPPORTED_PROTOCOL') + ciphers = 'ALL@SECLEVEL=0'; + } // Report where test was called from. Strip leading garbage from // at Object. (file:line) // from the stack location, we only want the file:line part. @@ -25,6 +33,7 @@ function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) { minVersion: cmin, maxVersion: cmax, secureProtocol: cprot, + ciphers: ciphers }, server: { cert: keys.agent6.cert, @@ -32,12 +41,12 @@ function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) { minVersion: smin, maxVersion: smax, secureProtocol: sprot, - ciphers: 'ALL@SECLEVEL=0' + ciphers: ciphers }, }, common.mustCall((err, pair, cleanup) => { function u(_) { return _ === undefined ? 'U' : _; } console.log('test:', u(cmin), u(cmax), u(cprot), u(smin), u(smax), u(sprot), - 'expect', u(proto), u(cerr), u(serr)); + u(ciphers), 'expect', u(proto), u(cerr), u(serr)); console.log(' ', where); if (!proto) { console.log('client', pair.client.err ? pair.client.err.code : undefined); @@ -110,16 +119,19 @@ test(U, U, 'TLS_method', U, U, 'TLSv1_method', 'TLSv1'); // minimum (which is configurable via command line). if (DEFAULT_MIN_VERSION === 'TLSv1.3') { test(U, U, 'TLSv1_2_method', U, U, 'SSLv23_method', - U, 'ECONNRESET', 'ERR_SSL_INTERNAL_ERROR'); + U, 'ECONNRESET', common.hasOpenSSL3 ? + 'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR'); } else { test(U, U, 'TLSv1_2_method', U, U, 'SSLv23_method', 'TLSv1.2'); } if (DEFAULT_MIN_VERSION === 'TLSv1.3') { test(U, U, 'TLSv1_1_method', U, U, 'SSLv23_method', - U, 'ECONNRESET', 'ERR_SSL_INTERNAL_ERROR'); + U, 'ECONNRESET', common.hasOpenSSL3 ? + 'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR'); test(U, U, 'TLSv1_method', U, U, 'SSLv23_method', - U, 'ECONNRESET', 'ERR_SSL_INTERNAL_ERROR'); + U, 'ECONNRESET', common.hasOpenSSL3 ? + 'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR'); test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method', U, 'ERR_SSL_NO_PROTOCOLS_AVAILABLE', 'ERR_SSL_UNEXPECTED_MESSAGE'); test(U, U, 'SSLv23_method', U, U, 'TLSv1_method', From 23b653f9e5ac575ed27f555e052344393d8d09b5 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 5 Mar 2021 15:33:32 +0100 Subject: [PATCH 39/40] src: aquire mutex lock in ManagedEVPPKey::operator= This commit aquires the Mutex in ManagedEVPPKey::operator= to avoid multiple threads updating the underlying EVP_PKEY in OpenSSL 3.0. There are additional changes to the code to avoid dead locks, making sure to release the lock before aquiring a new lock. Refs: https://github.com/nodejs/node/commit/79d44baae2 --- src/crypto/crypto_ec.cc | 34 +++++++++++++++++++++------------- src/crypto/crypto_keygen.h | 3 +++ src/crypto/crypto_keys.cc | 2 ++ src/crypto/crypto_keys.h | 2 +- src/crypto/crypto_sig.cc | 7 ++----- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc index 3e2c2031adb8e4..6718d9eed203bb 100644 --- a/src/crypto/crypto_ec.cc +++ b/src/crypto/crypto_ec.cc @@ -463,19 +463,22 @@ bool ECDHBitsTraits::DeriveBits( char* data = nullptr; size_t len = 0; + ManagedEVPPKey m_privkey = params.private_->GetAsymmetricKey(); + ManagedEVPPKey m_pubkey = params.public_->GetAsymmetricKey(); switch (params.id_) { case EVP_PKEY_X25519: // Fall through case EVP_PKEY_X448: { - EVPKeyCtxPointer ctx( - EVP_PKEY_CTX_new( - params.private_->GetAsymmetricKey().get(), - nullptr)); + EVPKeyCtxPointer ctx = nullptr; + { + ctx.reset(EVP_PKEY_CTX_new(m_privkey.get(), nullptr)); + } + Mutex::ScopedLock pub_lock(*m_pubkey.mutex()); if (EVP_PKEY_derive_init(ctx.get()) <= 0 || EVP_PKEY_derive_set_peer( ctx.get(), - params.public_->GetAsymmetricKey().get()) <= 0 || + m_pubkey.get()) <= 0 || EVP_PKEY_derive(ctx.get(), nullptr, &len) <= 0) { return false; } @@ -492,10 +495,14 @@ bool ECDHBitsTraits::DeriveBits( break; } default: { - const EC_KEY* private_key = - EVP_PKEY_get0_EC_KEY(params.private_->GetAsymmetricKey().get()); - const EC_KEY* public_key = - EVP_PKEY_get0_EC_KEY(params.public_->GetAsymmetricKey().get()); + const EC_KEY* private_key; + { + Mutex::ScopedLock priv_lock(*m_privkey.mutex()); + private_key = EVP_PKEY_get0_EC_KEY(m_privkey.get()); + } + + Mutex::ScopedLock pub_lock(*m_pubkey.mutex()); + const EC_KEY* public_key = EVP_PKEY_get0_EC_KEY(m_pubkey.get()); const EC_GROUP* group = EC_KEY_get0_group(private_key); if (group == nullptr) @@ -627,10 +634,10 @@ WebCryptoKeyExportStatus EC_Raw_Export( } CHECK_NOT_NULL(fn); // Get the size of the raw key data - if (fn(key_data->GetAsymmetricKey().get(), nullptr, &len) == 0) + if (fn(m_pkey.get(), nullptr, &len) == 0) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; data = MallocOpenSSL(len); - if (fn(key_data->GetAsymmetricKey().get(), data, &len) == 0) + if (fn(m_pkey.get(), data, &len) == 0) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; } else { if (key_data->GetKeyType() != kKeyTypePublic) @@ -751,6 +758,7 @@ Maybe ExportJWKEdKey( std::shared_ptr key, Local target) { ManagedEVPPKey pkey = key->GetAsymmetricKey(); + Mutex::ScopedLock lock(*pkey.mutex()); const char* curve = nullptr; switch (EVP_PKEY_id(pkey.get())) { @@ -919,8 +927,8 @@ Maybe GetEcKeyDetail( // implementation here is a adapted from Chromium's impl here: // https://github.com/chromium/chromium/blob/7af6cfd/components/webcrypto/algorithms/ecdsa.cc -size_t GroupOrderSize(ManagedEVPPKey key) { - EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get()); +size_t GroupOrderSize(const ManagedEVPPKey& key) { + const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get()); CHECK_NOT_NULL(ec); const EC_GROUP* group = EC_KEY_get0_group(ec); BignumPointer order(BN_new()); diff --git a/src/crypto/crypto_keygen.h b/src/crypto/crypto_keygen.h index 6231eb7eef8320..e96d850cee1b5a 100644 --- a/src/crypto/crypto_keygen.h +++ b/src/crypto/crypto_keygen.h @@ -235,6 +235,9 @@ struct KeyPairGenConfig final : public MemoryRetainer { AlgorithmParams params; KeyPairGenConfig() = default; + ~KeyPairGenConfig() { + Mutex::ScopedLock priv_lock(*key.mutex()); + } explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept : public_key_encoding(other.public_key_encoding), diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 4f0102a0eede41..f72ca8322db960 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -559,6 +559,8 @@ ManagedEVPPKey::ManagedEVPPKey(const ManagedEVPPKey& that) { } ManagedEVPPKey& ManagedEVPPKey::operator=(const ManagedEVPPKey& that) { + Mutex::ScopedLock lock(*that.mutex_); + pkey_.reset(that.get()); if (pkey_) diff --git a/src/crypto/crypto_keys.h b/src/crypto/crypto_keys.h index 21ccb73e330aa8..bf1498e62851eb 100644 --- a/src/crypto/crypto_keys.h +++ b/src/crypto/crypto_keys.h @@ -74,7 +74,7 @@ struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig { // use. class ManagedEVPPKey : public MemoryRetainer { public: - ManagedEVPPKey() = default; + ManagedEVPPKey() : mutex_(std::make_shared()) {} explicit ManagedEVPPKey(EVPKeyPointer&& pkey); ManagedEVPPKey(const ManagedEVPPKey& that); ManagedEVPPKey& operator=(const ManagedEVPPKey& that); diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc index 43790a5970424e..8ea32d360360ec 100644 --- a/src/crypto/crypto_sig.cc +++ b/src/crypto/crypto_sig.cc @@ -878,7 +878,7 @@ bool SignTraits::DeriveBits( case SignConfiguration::kSign: { size_t len; unsigned char* data = nullptr; - if (IsOneShot(params.key->GetAsymmetricKey())) { + if (IsOneShot(m_pkey)) { EVP_DigestSign( context.get(), nullptr, @@ -910,10 +910,7 @@ bool SignTraits::DeriveBits( return false; if (UseP1363Encoding(m_pkey, params.dsa_encoding)) { - *out = ConvertSignatureToP1363( - env, - params.key->GetAsymmetricKey(), - buf); + *out = ConvertSignatureToP1363(env, m_pkey, buf); } else { buf.Resize(len); *out = std::move(buf); From 6b8c50496e523403d4c418ab6eaac39a8e58c0ea Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 9 Mar 2021 08:48:26 +0100 Subject: [PATCH 40/40] src: use const for EVP_PKEY legacy function calls This commit add const to EC_KEY, DSA, RSA pointer to avoid compilation errors when linking against OpenSSL 3.0. Refs: https://github.com/openssl/openssl/commit/7bc0fdd3fd4535e06c35b92d71afab9a6de94cc5 --- src/crypto/crypto_dsa.cc | 2 +- src/crypto/crypto_ec.cc | 6 +++--- src/crypto/crypto_rsa.cc | 8 ++++---- src/crypto/crypto_sig.cc | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/crypto/crypto_dsa.cc b/src/crypto/crypto_dsa.cc index d3446eb60a2789..6ee8cf7e18c02e 100644 --- a/src/crypto/crypto_dsa.cc +++ b/src/crypto/crypto_dsa.cc @@ -138,7 +138,7 @@ Maybe GetDsaKeyDetail( int type = EVP_PKEY_id(m_pkey.get()); CHECK(type == EVP_PKEY_DSA); - DSA* dsa = EVP_PKEY_get0_DSA(m_pkey.get()); + const DSA* dsa = EVP_PKEY_get0_DSA(m_pkey.get()); CHECK_NOT_NULL(dsa); DSA_get0_pqg(dsa, &p, &q, nullptr); diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc index 6718d9eed203bb..ea4c70ad5d8c84 100644 --- a/src/crypto/crypto_ec.cc +++ b/src/crypto/crypto_ec.cc @@ -614,7 +614,7 @@ WebCryptoKeyExportStatus EC_Raw_Export( CHECK(m_pkey); Mutex::ScopedLock lock(*m_pkey.mutex()); - EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get()); + const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get()); unsigned char* data; size_t len = 0; @@ -703,7 +703,7 @@ Maybe ExportJWKEcKey( Mutex::ScopedLock lock(*m_pkey.mutex()); CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC); - EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get()); + const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get()); CHECK_NOT_NULL(ec); const EC_POINT* pub = EC_KEY_get0_public_key(ec); @@ -910,7 +910,7 @@ Maybe GetEcKeyDetail( Mutex::ScopedLock lock(*m_pkey.mutex()); CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC); - EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get()); + const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get()); CHECK_NOT_NULL(ec); const EC_GROUP* group = EC_KEY_get0_group(ec); diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc index c3250ea2e42ac1..22c20a3031899c 100644 --- a/src/crypto/crypto_rsa.cc +++ b/src/crypto/crypto_rsa.cc @@ -371,11 +371,11 @@ Maybe ExportJWKRsaKey( // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL // versions older than 1.1.1e via FIPS / dynamic linking. - RSA* rsa; + const RSA* rsa; if (OpenSSL_version_num() >= 0x1010105fL) { rsa = EVP_PKEY_get0_RSA(m_pkey.get()); } else { - rsa = static_cast(EVP_PKEY_get0(m_pkey.get())); + rsa = static_cast(EVP_PKEY_get0(m_pkey.get())); } CHECK_NOT_NULL(rsa); @@ -520,11 +520,11 @@ Maybe GetRsaKeyDetail( // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL // versions older than 1.1.1e via FIPS / dynamic linking. - RSA* rsa; + const RSA* rsa; if (OpenSSL_version_num() >= 0x1010105fL) { rsa = EVP_PKEY_get0_RSA(m_pkey.get()); } else { - rsa = static_cast(EVP_PKEY_get0(m_pkey.get())); + rsa = static_cast(EVP_PKEY_get0(m_pkey.get())); } CHECK_NOT_NULL(rsa); diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc index 8ea32d360360ec..cb1ce31be73700 100644 --- a/src/crypto/crypto_sig.cc +++ b/src/crypto/crypto_sig.cc @@ -34,7 +34,7 @@ bool ValidateDSAParameters(EVP_PKEY* key) { #else if (FIPS_mode() && EVP_PKEY_DSA == EVP_PKEY_base_id(key)) { #endif - DSA* dsa = EVP_PKEY_get0_DSA(key); + const DSA* dsa = EVP_PKEY_get0_DSA(key); const BIGNUM* p; DSA_get0_pqg(dsa, &p, nullptr, nullptr); size_t L = BN_num_bits(p); @@ -108,11 +108,11 @@ unsigned int GetBytesOfRS(const ManagedEVPPKey& pkey) { int bits, base_id = EVP_PKEY_base_id(pkey.get()); if (base_id == EVP_PKEY_DSA) { - DSA* dsa_key = EVP_PKEY_get0_DSA(pkey.get()); + const DSA* dsa_key = EVP_PKEY_get0_DSA(pkey.get()); // Both r and s are computed mod q, so their width is limited by that of q. bits = BN_num_bits(DSA_get0_q(dsa_key)); } else if (base_id == EVP_PKEY_EC) { - EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); + const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); bits = EC_GROUP_order_bits(ec_group); } else {