diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index 3cf6599a186c3f..b2fa04c6691539 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -32,6 +32,7 @@ const { setEngine: _setEngine, secureHeapUsed: _secureHeapUsed, getCachedAliases, + getOpenSSLSecLevelCrypto: getOpenSSLSecLevel, } = internalBinding('crypto'); const { getOptionValue } = require('internal/options'); @@ -631,4 +632,5 @@ module.exports = { secureHeapUsed, getCachedHashId, getHashCache, + getOpenSSLSecLevel, }; diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 60610b1b795c9b..5e36cf448158ff 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -31,6 +31,8 @@ using ncrypto::BIOPointer; using ncrypto::CryptoErrorList; using ncrypto::EnginePointer; using ncrypto::EVPKeyCtxPointer; +using ncrypto::SSLCtxPointer; +using ncrypto::SSLPointer; using v8::ArrayBuffer; using v8::BackingStore; using v8::BigInt; @@ -201,6 +203,27 @@ void TestFipsCrypto(const v8::FunctionCallbackInfo& args) { args.GetReturnValue().Set(ncrypto::testFipsEnabled() ? 1 : 0); } +void GetOpenSSLSecLevelCrypto(const FunctionCallbackInfo& args) { + // for BoringSSL assume the same as the default + int sec_level = 1; +#ifndef OPENSSL_IS_BORINGSSL + Environment* env = Environment::GetCurrent(args); + + auto ctx = SSLCtxPointer::New(); + if (!ctx) { + return ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_new"); + } + + auto ssl = SSLPointer::New(ctx); + if (!ssl) { + return ThrowCryptoError(env, ERR_get_error(), "SSL_new"); + } + + sec_level = SSL_get_security_level(ssl); +#endif // OPENSSL_IS_BORINGSSL + args.GetReturnValue().Set(sec_level); +} + void CryptoErrorStore::Capture() { errors_.clear(); while (const uint32_t err = ERR_get_error()) { @@ -704,6 +727,9 @@ void Initialize(Environment* env, Local target) { SetMethod(context, target, "secureBuffer", SecureBuffer); SetMethod(context, target, "secureHeapUsed", SecureHeapUsed); + + SetMethodNoSideEffect( + context, target, "getOpenSSLSecLevelCrypto", GetOpenSSLSecLevelCrypto); } void RegisterExternalReferences(ExternalReferenceRegistry* registry) { #ifndef OPENSSL_NO_ENGINE @@ -715,6 +741,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(TestFipsCrypto); registry->Register(SecureBuffer); registry->Register(SecureHeapUsed); + registry->Register(GetOpenSSLSecLevelCrypto); } } // namespace Util diff --git a/test/parallel/test-crypto-sec-level.js b/test/parallel/test-crypto-sec-level.js new file mode 100644 index 00000000000000..b48c308ba3d17f --- /dev/null +++ b/test/parallel/test-crypto-sec-level.js @@ -0,0 +1,11 @@ +// Flags: --expose-internals +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); + +const secLevel = require('internal/crypto/util').getOpenSSLSecLevel(); +assert.ok(secLevel >= 0 && secLevel <= 5); diff --git a/test/parallel/test-tls-dhe.js b/test/parallel/test-tls-dhe.js index 21739ce42428eb..bf968107d18abf 100644 --- a/test/parallel/test-tls-dhe.js +++ b/test/parallel/test-tls-dhe.js @@ -1,4 +1,4 @@ -// Flags: --no-warnings +// Flags: --no-warnings --expose-internals // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -25,6 +25,8 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); +const secLevel = require('internal/crypto/util').getOpenSSLSecLevel(); + if (!common.opensslCli) common.skip('missing openssl-cli'); @@ -43,7 +45,7 @@ const dheCipher = 'DHE-RSA-AES128-SHA256'; const ecdheCipher = 'ECDHE-RSA-AES128-SHA256'; const ciphers = `${dheCipher}:${ecdheCipher}`; -if (!common.hasOpenSSL(3, 2)) { +if (secLevel < 2) { // Test will emit a warning because the DH parameter size is < 2048 bits // when the test is run on versions lower than OpenSSL32 common.expectWarning('SecurityWarning', @@ -107,7 +109,9 @@ function testCustomParam(keylen, expectedCipher) { }, /DH parameter is less than 1024 bits/); // Custom DHE parameters are supported (but discouraged). - if (!common.hasOpenSSL(3, 2)) { + // 1024 is disallowed at security level 2 and above so use 3072 instead + // for higher security levels + if (secLevel < 2) { await testCustomParam(1024, dheCipher); } else { await testCustomParam(3072, dheCipher);