summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTobias Nießen <tniessen@tnie.de>2019-07-19 02:44:31 +0200
committerRich Trott <rtrott@gmail.com>2019-07-25 23:00:41 -0700
commit31d9b2f14fe9851b530c213b92e14b4646f6d131 (patch)
tree6499824adfea4686e4dfd9695204ae187a275905 /src
parent64e4b0c0ac5073e6606b1ccd79a464f2c5925741 (diff)
downloadandroid-node-v8-31d9b2f14fe9851b530c213b92e14b4646f6d131.tar.gz
android-node-v8-31d9b2f14fe9851b530c213b92e14b4646f6d131.tar.bz2
android-node-v8-31d9b2f14fe9851b530c213b92e14b4646f6d131.zip
crypto: add outputLength option to crypto.createHash
This change adds an outputLength option to crypto.createHash which allows users to produce variable-length hash values using XOF hash functons. Fixes: https://github.com/nodejs/node/issues/28757 PR-URL: https://github.com/nodejs/node/pull/28805 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node_crypto.cc53
-rw-r--r--src/node_crypto.h11
2 files changed, 56 insertions, 8 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index ef8983b2f7..91e62f41b3 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -4569,15 +4569,21 @@ void Hash::New(const FunctionCallbackInfo<Value>& args) {
const node::Utf8Value hash_type(env->isolate(), args[0]);
+ Maybe<unsigned int> xof_md_len = Nothing<unsigned int>();
+ if (!args[1]->IsUndefined()) {
+ CHECK(args[1]->IsUint32());
+ xof_md_len = Just<unsigned int>(args[1].As<Uint32>()->Value());
+ }
+
Hash* hash = new Hash(env, args.This());
- if (!hash->HashInit(*hash_type)) {
+ if (!hash->HashInit(*hash_type, xof_md_len)) {
return ThrowCryptoError(env, ERR_get_error(),
"Digest method not supported");
}
}
-bool Hash::HashInit(const char* hash_type) {
+bool Hash::HashInit(const char* hash_type, Maybe<unsigned int> xof_md_len) {
const EVP_MD* md = EVP_get_digestbyname(hash_type);
if (md == nullptr)
return false;
@@ -4586,6 +4592,18 @@ bool Hash::HashInit(const char* hash_type) {
mdctx_.reset();
return false;
}
+
+ md_len_ = EVP_MD_size(md);
+ if (xof_md_len.IsJust() && xof_md_len.FromJust() != md_len_) {
+ // This is a little hack to cause createHash to fail when an incorrect
+ // hashSize option was passed for a non-XOF hash function.
+ if ((EVP_MD_meth_get_flags(md) & EVP_MD_FLAG_XOF) == 0) {
+ EVPerr(EVP_F_EVP_DIGESTFINALXOF, EVP_R_NOT_XOF_OR_INVALID_LENGTH);
+ return false;
+ }
+ md_len_ = xof_md_len.FromJust();
+ }
+
return true;
}
@@ -4634,13 +4652,40 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) {
encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
}
- if (hash->md_len_ == 0) {
+ // TODO(tniessen): SHA3_squeeze does not work for zero-length outputs on all
+ // platforms and will cause a segmentation fault if called. This workaround
+ // causes hash.digest() to correctly return an empty buffer / string.
+ // See https://github.com/openssl/openssl/issues/9431.
+ if (!hash->has_md_ && hash->md_len_ == 0) {
+ hash->has_md_ = true;
+ }
+
+ if (!hash->has_md_) {
// 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_);
+
+ hash->md_value_ = MallocOpenSSL<unsigned char>(hash->md_len_);
+
+ size_t default_len = EVP_MD_CTX_size(hash->mdctx_.get());
+ int ret;
+ if (hash->md_len_ == default_len) {
+ ret = EVP_DigestFinal_ex(hash->mdctx_.get(), hash->md_value_,
+ &hash->md_len_);
+ } else {
+ ret = EVP_DigestFinalXOF(hash->mdctx_.get(), hash->md_value_,
+ hash->md_len_);
+ }
+
+ if (ret != 1) {
+ OPENSSL_free(hash->md_value_);
+ hash->md_value_ = nullptr;
+ return ThrowCryptoError(env, ERR_get_error());
+ }
+
+ hash->has_md_ = true;
}
Local<Value> error;
diff --git a/src/node_crypto.h b/src/node_crypto.h
index 3e337eaddb..07ca412e8f 100644
--- a/src/node_crypto.h
+++ b/src/node_crypto.h
@@ -585,7 +585,7 @@ class Hash : public BaseObject {
SET_MEMORY_INFO_NAME(Hash)
SET_SELF_SIZE(Hash)
- bool HashInit(const char* hash_type);
+ bool HashInit(const char* hash_type, v8::Maybe<unsigned int> xof_md_len);
bool HashUpdate(const char* data, int len);
protected:
@@ -596,18 +596,21 @@ class Hash : public BaseObject {
Hash(Environment* env, v8::Local<v8::Object> wrap)
: BaseObject(env, wrap),
mdctx_(nullptr),
- md_len_(0) {
+ has_md_(false),
+ md_value_(nullptr) {
MakeWeak();
}
~Hash() override {
- OPENSSL_cleanse(md_value_, md_len_);
+ if (md_value_ != nullptr)
+ OPENSSL_clear_free(md_value_, md_len_);
}
private:
EVPMDPointer mdctx_;
- unsigned char md_value_[EVP_MAX_MD_SIZE];
+ bool has_md_;
unsigned int md_len_;
+ unsigned char* md_value_;
};
class SignBase : public BaseObject {