diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 3dd3b4424cc8eb..1384f85e1894bd 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3676,6 +3676,7 @@ bool Hash::HashInit(const char* hash_type) { return false; } initialised_ = true; + finalized_ = false; return true; } @@ -3695,6 +3696,13 @@ void Hash::HashUpdate(const FunctionCallbackInfo& args) { THROW_AND_RETURN_IF_NOT_STRING_OR_BUFFER(args[0], "Data"); + if (!hash->initialised_) { + return env->ThrowError("Not initialized"); + } + if (hash->finalized_) { + return env->ThrowError("Digest already called"); + } + // Only copy the data if we have to, because it's a string bool r; if (args[0]->IsString()) { @@ -3722,6 +3730,9 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { if (!hash->initialised_) { return env->ThrowError("Not initialized"); } + if (hash->finalized_) { + return env->ThrowError("Digest already called"); + } enum encoding encoding = BUFFER; if (args.Length() >= 1) { @@ -3735,7 +3746,7 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len); EVP_MD_CTX_cleanup(&hash->mdctx_); - hash->initialised_ = false; + hash->finalized_ = true; Local rc = StringBytes::Encode(env->isolate(), reinterpret_cast(md_value), diff --git a/src/node_crypto.h b/src/node_crypto.h index 66c50efa2c040d..01c16b39b516c9 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -538,6 +538,7 @@ class Hash : public BaseObject { EVP_MD_CTX mdctx_; /* coverity[member_decl] */ const EVP_MD* md_; /* coverity[member_decl] */ bool initialised_; + bool finalized_; }; class SignBase : public BaseObject { diff --git a/test/parallel/test-crypto-hash.js b/test/parallel/test-crypto-hash.js index fce11eca046786..b5fc7e881c307b 100644 --- a/test/parallel/test-crypto-hash.js +++ b/test/parallel/test-crypto-hash.js @@ -98,3 +98,15 @@ assert.equal( assert.notEqual( hutf8, crypto.createHash('sha512').update('УТФ-8 text', 'binary').digest('hex')); + +var h3 = crypto.createHash('sha256'); +h3.digest(); +assert.throws(function() { + h3.digest(); +}, + /Digest already called/); + +assert.throws(function() { + h3.update('foo'); +}, + /Digest already called/);