summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Nießen <tniessen@tnie.de>2019-06-16 11:26:03 +0200
committerRichard Lau <rlau@redhat.com>2021-02-08 15:38:08 +0000
commit953a85035df05f3cb7763f801465a024ee0a5f1e (patch)
tree07f33e1462d48994514375b9f45c31e193a9420b
parent68a6b8d3751bcaa96f32bdb843f171a098f1cbdb (diff)
downloadnode-new-953a85035df05f3cb7763f801465a024ee0a5f1e.tar.gz
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> Backport-PR-URL: https://github.com/nodejs/node/pull/37009 Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Shelley Vohr <codebytere@gmail.com>
-rw-r--r--src/node_crypto.cc16
-rw-r--r--src/node_crypto.h9
2 files changed, 18 insertions, 7 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index 22342d4332..847b67bce2 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -3419,16 +3419,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 5cdbe359d4..56f30991b4 100644
--- a/src/node_crypto.h
+++ b/src/node_crypto.h
@@ -475,12 +475,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 {