Skip to content

Commit

Permalink
crypto: do not advertise unsupported algorithms
Browse files Browse the repository at this point in the history
Fixes: nodejs#41857

PR-URL: nodejs#41864
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Filip Skokan <[email protected]>
  • Loading branch information
mscdex authored and bengl committed Feb 21, 2022
1 parent a96f40c commit d03b24b
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 3 deletions.
13 changes: 12 additions & 1 deletion src/crypto/crypto_cipher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,19 @@ void CipherBase::GetSSLCiphers(const FunctionCallbackInfo<Value>& args) {

void CipherBase::GetCiphers(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
MarkPopErrorOnReturn mark_pop_error_on_return;
CipherPushContext ctx(env);
EVP_CIPHER_do_all_sorted(array_push_back<EVP_CIPHER>, &ctx);
EVP_CIPHER_do_all_sorted(
#if OPENSSL_VERSION_MAJOR >= 3
array_push_back<EVP_CIPHER,
EVP_CIPHER_fetch,
EVP_CIPHER_free,
EVP_get_cipherbyname,
EVP_CIPHER_get0_name>,
#else
array_push_back<EVP_CIPHER>,
#endif
&ctx);
args.GetReturnValue().Set(ctx.ToJSArray());
}

Expand Down
13 changes: 12 additions & 1 deletion src/crypto/crypto_hash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,19 @@ void Hash::MemoryInfo(MemoryTracker* tracker) const {

void Hash::GetHashes(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
MarkPopErrorOnReturn mark_pop_error_on_return;
CipherPushContext ctx(env);
EVP_MD_do_all_sorted(array_push_back<EVP_MD>, &ctx);
EVP_MD_do_all_sorted(
#if OPENSSL_VERSION_MAJOR >= 3
array_push_back<EVP_MD,
EVP_MD_fetch,
EVP_MD_free,
EVP_get_digestbyname,
EVP_MD_get0_name>,
#else
array_push_back<EVP_MD>,
#endif
&ctx);
args.GetReturnValue().Set(ctx.ToJSArray());
}

Expand Down
40 changes: 39 additions & 1 deletion src/crypto/crypto_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,13 +616,51 @@ class CipherPushContext {
Environment* env_;
};

#if OPENSSL_VERSION_MAJOR >= 3
template <class TypeName,
TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*),
void free_type(TypeName*),
const TypeName* getbyname(const char*),
const char* getname(const TypeName*)>
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<CipherPushContext*>(arg)->push_back(from);
}
#else
template <class TypeName>
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<CipherPushContext*>(arg)->push_back(from);
}
#endif

inline bool IsAnyByteSource(v8::Local<v8::Value> arg) {
return arg->IsArrayBufferView() ||
Expand Down
16 changes: 16 additions & 0 deletions test/parallel/test-crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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);
Expand Down

0 comments on commit d03b24b

Please sign in to comment.