diff options
author | Tobias Nießen <tniessen@tnie.de> | 2019-06-16 11:26:03 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-07-02 09:07:40 +0200 |
commit | 990feafcb60d2516cfeb36449759087517b8ff8d (patch) | |
tree | 2ac21b2b826d5b40fc6a7e6f6f2d7fa5b43c36c3 /src | |
parent | 17efd9372bd460d2015abb351d53791881530514 (diff) | |
download | android-node-v8-990feafcb60d2516cfeb36449759087517b8ff8d.tar.gz android-node-v8-990feafcb60d2516cfeb36449759087517b8ff8d.tar.bz2 android-node-v8-990feafcb60d2516cfeb36449759087517b8ff8d.zip |
crypto: fix crash when calling digest after piping
When piping data into an SHA3 hash, EVP_DigestFinal_ex is called in
hash._flush, bypassing safeguards in the JavaScript layer. Calling
hash.digest causes EVP_DigestFinal_ex to be called again, resulting
in a segmentation fault in the SHA3 implementation of OpenSSL.
A relatively easy solution is to cache the result of calling
EVP_DigestFinal_ex until the Hash object is garbage collected.
PR-URL: https://github.com/nodejs/node/pull/28251
Fixes: https://github.com/nodejs/node/issues/28245
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'src')
-rw-r--r-- | src/node_crypto.cc | 16 | ||||
-rw-r--r-- | src/node_crypto.h | 9 |
2 files changed, 18 insertions, 7 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 813e1fc485..590c6d1c37 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -4634,16 +4634,20 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) { encoding = ParseEncoding(env->isolate(), args[0], BUFFER); } - unsigned char md_value[EVP_MAX_MD_SIZE]; - unsigned int md_len; - - EVP_DigestFinal_ex(hash->mdctx_.get(), md_value, &md_len); + if (hash->md_len_ == 0) { + // Some hash algorithms such as SHA3 do not support calling + // EVP_DigestFinal_ex more than once, however, Hash._flush + // and Hash.digest can both be used to retrieve the digest, + // so we need to cache it. + // See https://github.com/nodejs/node/issues/28245. + EVP_DigestFinal_ex(hash->mdctx_.get(), hash->md_value_, &hash->md_len_); + } Local<Value> error; MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(), - reinterpret_cast<const char*>(md_value), - md_len, + reinterpret_cast<const char*>(hash->md_value_), + hash->md_len_, encoding, &error); if (rc.IsEmpty()) { diff --git a/src/node_crypto.h b/src/node_crypto.h index aa29585533..3e337eaddb 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -595,12 +595,19 @@ class Hash : public BaseObject { Hash(Environment* env, v8::Local<v8::Object> wrap) : BaseObject(env, wrap), - mdctx_(nullptr) { + mdctx_(nullptr), + md_len_(0) { MakeWeak(); } + ~Hash() override { + OPENSSL_cleanse(md_value_, md_len_); + } + private: EVPMDPointer mdctx_; + unsigned char md_value_[EVP_MAX_MD_SIZE]; + unsigned int md_len_; }; class SignBase : public BaseObject { |