From 46dda316df76011a1c389446c8de3d0d155764de Mon Sep 17 00:00:00 2001 From: Brian White Date: Sat, 5 Feb 2022 14:42:22 -0500 Subject: [PATCH] crypto: do not advertise unsupported algorithms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/nodejs/node/issues/41857 PR-URL: https://github.com/nodejs/node/pull/41864 Reviewed-By: Tobias Nießen Reviewed-By: Benjamin Gruenbaum Reviewed-By: James M Snell Reviewed-By: Filip Skokan --- src/crypto/crypto_cipher.cc | 13 +++++++++++- src/crypto/crypto_hash.cc | 13 +++++++++++- src/crypto/crypto_util.h | 40 +++++++++++++++++++++++++++++++++++- test/parallel/test-crypto.js | 16 +++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index de5784b3c8f63d..90a0c4d1fd0bf4 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -235,8 +235,19 @@ void CipherBase::GetSSLCiphers(const FunctionCallbackInfo& args) { void CipherBase::GetCiphers(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + MarkPopErrorOnReturn mark_pop_error_on_return; CipherPushContext ctx(env); - EVP_CIPHER_do_all_sorted(array_push_back, &ctx); + EVP_CIPHER_do_all_sorted( +#if OPENSSL_VERSION_MAJOR >= 3 + array_push_back, +#else + array_push_back, +#endif + &ctx); args.GetReturnValue().Set(ctx.ToJSArray()); } diff --git a/src/crypto/crypto_hash.cc b/src/crypto/crypto_hash.cc index 9aa9c604da7dc1..ceea9e595708ba 100644 --- a/src/crypto/crypto_hash.cc +++ b/src/crypto/crypto_hash.cc @@ -35,8 +35,19 @@ void Hash::MemoryInfo(MemoryTracker* tracker) const { void Hash::GetHashes(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + MarkPopErrorOnReturn mark_pop_error_on_return; CipherPushContext ctx(env); - EVP_MD_do_all_sorted(array_push_back, &ctx); + EVP_MD_do_all_sorted( +#if OPENSSL_VERSION_MAJOR >= 3 + array_push_back, +#else + array_push_back, +#endif + &ctx); args.GetReturnValue().Set(ctx.ToJSArray()); } diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h index 5060fc3f2fbd67..c431159e6f77f8 100644 --- a/src/crypto/crypto_util.h +++ b/src/crypto/crypto_util.h @@ -616,13 +616,51 @@ class CipherPushContext { Environment* env_; }; +#if OPENSSL_VERSION_MAJOR >= 3 +template +void array_push_back(const TypeName* evp_ref, + const char* from, + const char* to, + void* arg) { + if (!from) + return; + + const TypeName* real_instance = getbyname(from); + if (!real_instance) + return; + + const char* real_name = getname(real_instance); + if (!real_name) + return; + + // EVP_*_fetch() does not support alias names, so we need to pass it the + // real/original algorithm name. + // We use EVP_*_fetch() as a filter here because it will only return an + // instance if the algorithm is supported by the public OpenSSL APIs (some + // algorithms are used internally by OpenSSL and are also passed to this + // callback). + TypeName* fetched = fetch_type(nullptr, real_name, nullptr); + if (!fetched) + return; + + free_type(fetched); + static_cast(arg)->push_back(from); +} +#else template -void array_push_back(const TypeName* md, +void array_push_back(const TypeName* evp_ref, const char* from, const char* to, void* arg) { + if (!from) + return; static_cast(arg)->push_back(from); } +#endif inline bool IsAnyByteSource(v8::Local arg) { return arg->IsArrayBufferView() || diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 58441be4d093f0..a8ceb169de2b3d 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -121,6 +121,19 @@ function validateList(list) { const cryptoCiphers = crypto.getCiphers(); assert(crypto.getCiphers().includes('aes-128-cbc')); validateList(cryptoCiphers); +// Make sure all of the ciphers are supported by OpenSSL +for (const algo of cryptoCiphers) { + const { ivLength, keyLength, mode } = crypto.getCipherInfo(algo); + let options; + if (mode === 'ccm') + options = { authTagLength: 8 }; + else if (mode === 'ocb' || algo === 'chacha20-poly1305') + options = { authTagLength: 16 }; + crypto.createCipheriv(algo, + crypto.randomBytes(keyLength), + crypto.randomBytes(ivLength || 0), + options); +} // Assume that we have at least AES256-SHA. const tlsCiphers = tls.getCiphers(); @@ -140,6 +153,9 @@ assert(!crypto.getHashes().includes('SHA256')); assert(crypto.getHashes().includes('RSA-SHA1')); assert(!crypto.getHashes().includes('rsa-sha1')); validateList(crypto.getHashes()); +// Make sure all of the hashes are supported by OpenSSL +for (const algo of crypto.getHashes()) + crypto.createHash(algo); // Assume that we have at least secp384r1. assert.notStrictEqual(crypto.getCurves().length, 0);