crypto: use EVP_MD_fetch and cache EVP_MD for hashes
On OpenSSL 3, migrate from EVP_get_digestbyname() to EVP_MD_fetch() to get the implementation and use a per-Environment cache for it. The EVP_MDs are freed during Environment cleanup. Drive-by: declare the smart pointer for EVP_MD_CTX as EVPMDCtxPointer instead of EVPMDPointer to avoid confusion with EVP_MD pointers. PR-URL: https://github.com/nodejs/node/pull/51034 Refs: https://www.openssl.org/docs/man3.0/man7/crypto.html#Explicit-fetching Refs: https://github.com/nodejs/performance/issues/136 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
59e7444766
commit
57c22e4a22
@ -19,6 +19,8 @@ const {
|
|||||||
normalizeHashName,
|
normalizeHashName,
|
||||||
validateMaxBufferLength,
|
validateMaxBufferLength,
|
||||||
kHandle,
|
kHandle,
|
||||||
|
getCachedHashId,
|
||||||
|
getHashCache,
|
||||||
} = require('internal/crypto/util');
|
} = require('internal/crypto/util');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -59,13 +61,17 @@ const kFinalized = Symbol('kFinalized');
|
|||||||
function Hash(algorithm, options) {
|
function Hash(algorithm, options) {
|
||||||
if (!new.target)
|
if (!new.target)
|
||||||
return new Hash(algorithm, options);
|
return new Hash(algorithm, options);
|
||||||
if (!(algorithm instanceof _Hash))
|
const isCopy = algorithm instanceof _Hash;
|
||||||
|
if (!isCopy)
|
||||||
validateString(algorithm, 'algorithm');
|
validateString(algorithm, 'algorithm');
|
||||||
const xofLen = typeof options === 'object' && options !== null ?
|
const xofLen = typeof options === 'object' && options !== null ?
|
||||||
options.outputLength : undefined;
|
options.outputLength : undefined;
|
||||||
if (xofLen !== undefined)
|
if (xofLen !== undefined)
|
||||||
validateUint32(xofLen, 'options.outputLength');
|
validateUint32(xofLen, 'options.outputLength');
|
||||||
this[kHandle] = new _Hash(algorithm, xofLen);
|
// Lookup the cached ID from JS land because it's faster than decoding
|
||||||
|
// the string in C++ land.
|
||||||
|
const algorithmId = isCopy ? -1 : getCachedHashId(algorithm);
|
||||||
|
this[kHandle] = new _Hash(algorithm, xofLen, algorithmId, getHashCache());
|
||||||
this[kState] = {
|
this[kState] = {
|
||||||
[kFinalized]: false,
|
[kFinalized]: false,
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,7 @@ const {
|
|||||||
getHashes: _getHashes,
|
getHashes: _getHashes,
|
||||||
setEngine: _setEngine,
|
setEngine: _setEngine,
|
||||||
secureHeapUsed: _secureHeapUsed,
|
secureHeapUsed: _secureHeapUsed,
|
||||||
|
getCachedAliases,
|
||||||
} = internalBinding('crypto');
|
} = internalBinding('crypto');
|
||||||
|
|
||||||
const { getOptionValue } = require('internal/options');
|
const { getOptionValue } = require('internal/options');
|
||||||
@ -66,6 +67,13 @@ const {
|
|||||||
lazyDOMException,
|
lazyDOMException,
|
||||||
} = require('internal/util');
|
} = require('internal/util');
|
||||||
|
|
||||||
|
const {
|
||||||
|
namespace: {
|
||||||
|
isBuildingSnapshot,
|
||||||
|
addSerializeCallback,
|
||||||
|
},
|
||||||
|
} = require('internal/v8/startup_snapshot');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isDataView,
|
isDataView,
|
||||||
isArrayBufferView,
|
isArrayBufferView,
|
||||||
@ -87,6 +95,23 @@ function toBuf(val, encoding) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _hashCache;
|
||||||
|
function getHashCache() {
|
||||||
|
if (_hashCache === undefined) {
|
||||||
|
_hashCache = getCachedAliases();
|
||||||
|
if (isBuildingSnapshot()) {
|
||||||
|
// For dynamic linking, clear the map.
|
||||||
|
addSerializeCallback(() => { _hashCache = undefined; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _hashCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCachedHashId(algorithm) {
|
||||||
|
const result = getHashCache()[algorithm];
|
||||||
|
return result === undefined ? -1 : result;
|
||||||
|
}
|
||||||
|
|
||||||
const getCiphers = cachedResult(() => filterDuplicateStrings(_getCiphers()));
|
const getCiphers = cachedResult(() => filterDuplicateStrings(_getCiphers()));
|
||||||
const getHashes = cachedResult(() => filterDuplicateStrings(_getHashes()));
|
const getHashes = cachedResult(() => filterDuplicateStrings(_getHashes()));
|
||||||
const getCurves = cachedResult(() => filterDuplicateStrings(_getCurves()));
|
const getCurves = cachedResult(() => filterDuplicateStrings(_getCurves()));
|
||||||
@ -574,4 +599,6 @@ module.exports = {
|
|||||||
getStringOption,
|
getStringOption,
|
||||||
getUsagesUnion,
|
getUsagesUnion,
|
||||||
secureHeapUsed,
|
secureHeapUsed,
|
||||||
|
getCachedHashId,
|
||||||
|
getHashCache,
|
||||||
};
|
};
|
||||||
|
@ -79,7 +79,7 @@ using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
|
|||||||
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
||||||
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
||||||
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
||||||
using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
||||||
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
||||||
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
||||||
using BignumPointer = DeleteFnPtr<BIGNUM, BN_clear_free>;
|
using BignumPointer = DeleteFnPtr<BIGNUM, BN_clear_free>;
|
||||||
|
@ -14,11 +14,13 @@ namespace node {
|
|||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::FunctionTemplate;
|
using v8::FunctionTemplate;
|
||||||
|
using v8::Int32;
|
||||||
using v8::Isolate;
|
using v8::Isolate;
|
||||||
using v8::Just;
|
using v8::Just;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
using v8::Maybe;
|
using v8::Maybe;
|
||||||
using v8::MaybeLocal;
|
using v8::MaybeLocal;
|
||||||
|
using v8::Name;
|
||||||
using v8::Nothing;
|
using v8::Nothing;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::Uint32;
|
using v8::Uint32;
|
||||||
@ -34,22 +36,170 @@ void Hash::MemoryInfo(MemoryTracker* tracker) const {
|
|||||||
tracker->TrackFieldWithSize("md", digest_ ? md_len_ : 0);
|
tracker->TrackFieldWithSize("md", digest_ ? md_len_ : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
array_push_back<EVP_MD,
|
void PushAliases(const char* name, void* data) {
|
||||||
EVP_MD_fetch,
|
static_cast<std::vector<std::string>*>(data)->push_back(name);
|
||||||
EVP_MD_free,
|
}
|
||||||
EVP_get_digestbyname,
|
|
||||||
EVP_MD_get0_name>,
|
EVP_MD* GetCachedMDByID(Environment* env, size_t id) {
|
||||||
|
CHECK_LT(id, env->evp_md_cache.size());
|
||||||
|
EVP_MD* result = env->evp_md_cache[id].get();
|
||||||
|
CHECK_NOT_NULL(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MaybeCachedMD {
|
||||||
|
EVP_MD* explicit_md = nullptr;
|
||||||
|
const EVP_MD* implicit_md = nullptr;
|
||||||
|
int32_t cache_id = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
MaybeCachedMD FetchAndMaybeCacheMD(Environment* env, const char* search_name) {
|
||||||
|
const EVP_MD* implicit_md = EVP_get_digestbyname(search_name);
|
||||||
|
if (!implicit_md) return {nullptr, nullptr, -1};
|
||||||
|
|
||||||
|
const char* real_name = EVP_MD_get0_name(implicit_md);
|
||||||
|
if (!real_name) return {nullptr, implicit_md, -1};
|
||||||
|
|
||||||
|
auto it = env->alias_to_md_id_map.find(real_name);
|
||||||
|
if (it != env->alias_to_md_id_map.end()) {
|
||||||
|
size_t id = it->second;
|
||||||
|
return {GetCachedMDByID(env, id), implicit_md, static_cast<int32_t>(id)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
EVP_MD* explicit_md = EVP_MD_fetch(nullptr, real_name, nullptr);
|
||||||
|
if (!explicit_md) return {nullptr, implicit_md, -1};
|
||||||
|
|
||||||
|
// Cache the EVP_MD* fetched.
|
||||||
|
env->evp_md_cache.emplace_back(explicit_md);
|
||||||
|
size_t id = env->evp_md_cache.size() - 1;
|
||||||
|
|
||||||
|
// Add all the aliases to the map to speed up next lookup.
|
||||||
|
std::vector<std::string> aliases;
|
||||||
|
EVP_MD_names_do_all(explicit_md, PushAliases, &aliases);
|
||||||
|
for (const auto& alias : aliases) {
|
||||||
|
env->alias_to_md_id_map.emplace(alias, id);
|
||||||
|
}
|
||||||
|
env->alias_to_md_id_map.emplace(search_name, id);
|
||||||
|
|
||||||
|
return {explicit_md, implicit_md, static_cast<int32_t>(id)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSupportedHashAlgorithmsAndCacheMD(const EVP_MD* md,
|
||||||
|
const char* from,
|
||||||
|
const char* to,
|
||||||
|
void* arg) {
|
||||||
|
if (!from) return;
|
||||||
|
Environment* env = static_cast<Environment*>(arg);
|
||||||
|
auto result = FetchAndMaybeCacheMD(env, from);
|
||||||
|
if (result.explicit_md) {
|
||||||
|
env->supported_hash_algorithms.push_back(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
array_push_back<EVP_MD>,
|
void SaveSupportedHashAlgorithms(const EVP_MD* md,
|
||||||
|
const char* from,
|
||||||
|
const char* to,
|
||||||
|
void* arg) {
|
||||||
|
if (!from) return;
|
||||||
|
Environment* env = static_cast<Environment*>(arg);
|
||||||
|
env->supported_hash_algorithms.push_back(from);
|
||||||
|
}
|
||||||
|
#endif // OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
|
||||||
|
const std::vector<std::string>& GetSupportedHashAlgorithms(Environment* env) {
|
||||||
|
if (env->supported_hash_algorithms.empty()) {
|
||||||
|
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
// Since we'll fetch the EVP_MD*, cache them along the way to speed up
|
||||||
|
// later lookups instead of throwing them away immediately.
|
||||||
|
EVP_MD_do_all_sorted(SaveSupportedHashAlgorithmsAndCacheMD, env);
|
||||||
|
#else
|
||||||
|
EVP_MD_do_all_sorted(SaveSupportedHashAlgorithms, env);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return env->supported_hash_algorithms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hash::GetHashes(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Local<Context> context = args.GetIsolate()->GetCurrentContext();
|
||||||
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
const std::vector<std::string>& results = GetSupportedHashAlgorithms(env);
|
||||||
|
|
||||||
|
Local<Value> ret;
|
||||||
|
if (ToV8Value(context, results).ToLocal(&ret)) {
|
||||||
|
args.GetReturnValue().Set(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hash::GetCachedAliases(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Isolate* isolate = args.GetIsolate();
|
||||||
|
Local<Context> context = args.GetIsolate()->GetCurrentContext();
|
||||||
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
std::vector<Local<Name>> names;
|
||||||
|
std::vector<Local<Value>> values;
|
||||||
|
size_t size = env->alias_to_md_id_map.size();
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
names.reserve(size);
|
||||||
|
values.reserve(size);
|
||||||
|
for (auto& [alias, id] : env->alias_to_md_id_map) {
|
||||||
|
names.push_back(OneByteString(isolate, alias.c_str(), alias.size()));
|
||||||
|
values.push_back(v8::Uint32::New(isolate, id));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
CHECK(env->alias_to_md_id_map.empty());
|
||||||
|
#endif
|
||||||
|
Local<Value> prototype = v8::Null(isolate);
|
||||||
|
Local<Object> result =
|
||||||
|
Object::New(isolate, prototype, names.data(), values.data(), size);
|
||||||
|
args.GetReturnValue().Set(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const EVP_MD* GetDigestImplementation(Environment* env,
|
||||||
|
Local<Value> algorithm,
|
||||||
|
Local<Value> cache_id_val,
|
||||||
|
Local<Value> algorithm_cache) {
|
||||||
|
CHECK(algorithm->IsString());
|
||||||
|
CHECK(cache_id_val->IsInt32());
|
||||||
|
CHECK(algorithm_cache->IsObject());
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
int32_t cache_id = cache_id_val.As<Int32>()->Value();
|
||||||
|
if (cache_id != -1) { // Alias already cached, return the cached EVP_MD*.
|
||||||
|
return GetCachedMDByID(env, cache_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only decode the algorithm when we don't have it cached to avoid
|
||||||
|
// unnecessary overhead.
|
||||||
|
Isolate* isolate = env->isolate();
|
||||||
|
Utf8Value utf8(isolate, algorithm);
|
||||||
|
|
||||||
|
auto result = FetchAndMaybeCacheMD(env, *utf8);
|
||||||
|
if (result.cache_id != -1) {
|
||||||
|
// Add the alias to both C++ side and JS side to speedup the lookup
|
||||||
|
// next time.
|
||||||
|
env->alias_to_md_id_map.emplace(*utf8, result.cache_id);
|
||||||
|
if (algorithm_cache.As<Object>()
|
||||||
|
->Set(isolate->GetCurrentContext(),
|
||||||
|
algorithm,
|
||||||
|
v8::Int32::New(isolate, result.cache_id))
|
||||||
|
.IsNothing()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.explicit_md ? result.explicit_md : result.implicit_md;
|
||||||
|
#else
|
||||||
|
Utf8Value utf8(env->isolate(), algorithm);
|
||||||
|
return EVP_get_digestbyname(*utf8);
|
||||||
#endif
|
#endif
|
||||||
&ctx);
|
|
||||||
args.GetReturnValue().Set(ctx.ToJSArray());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hash::Initialize(Environment* env, Local<Object> target) {
|
void Hash::Initialize(Environment* env, Local<Object> target) {
|
||||||
@ -65,6 +215,7 @@ void Hash::Initialize(Environment* env, Local<Object> target) {
|
|||||||
SetConstructorFunction(context, target, "Hash", t);
|
SetConstructorFunction(context, target, "Hash", t);
|
||||||
|
|
||||||
SetMethodNoSideEffect(context, target, "getHashes", GetHashes);
|
SetMethodNoSideEffect(context, target, "getHashes", GetHashes);
|
||||||
|
SetMethodNoSideEffect(context, target, "getCachedAliases", GetCachedAliases);
|
||||||
|
|
||||||
HashJob::Initialize(env, target);
|
HashJob::Initialize(env, target);
|
||||||
|
|
||||||
@ -77,24 +228,24 @@ void Hash::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
|||||||
registry->Register(HashUpdate);
|
registry->Register(HashUpdate);
|
||||||
registry->Register(HashDigest);
|
registry->Register(HashDigest);
|
||||||
registry->Register(GetHashes);
|
registry->Register(GetHashes);
|
||||||
|
registry->Register(GetCachedAliases);
|
||||||
|
|
||||||
HashJob::RegisterExternalReferences(registry);
|
HashJob::RegisterExternalReferences(registry);
|
||||||
|
|
||||||
registry->Register(InternalVerifyIntegrity);
|
registry->Register(InternalVerifyIntegrity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// new Hash(algorithm, algorithmId, xofLen, algorithmCache)
|
||||||
void Hash::New(const FunctionCallbackInfo<Value>& args) {
|
void Hash::New(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
const Hash* orig = nullptr;
|
const Hash* orig = nullptr;
|
||||||
const EVP_MD* md = nullptr;
|
const EVP_MD* md = nullptr;
|
||||||
|
|
||||||
if (args[0]->IsObject()) {
|
if (args[0]->IsObject()) {
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&orig, args[0].As<Object>());
|
ASSIGN_OR_RETURN_UNWRAP(&orig, args[0].As<Object>());
|
||||||
md = EVP_MD_CTX_md(orig->mdctx_.get());
|
md = EVP_MD_CTX_md(orig->mdctx_.get());
|
||||||
} else {
|
} else {
|
||||||
const Utf8Value hash_type(env->isolate(), args[0]);
|
md = GetDigestImplementation(env, args[0], args[2], args[3]);
|
||||||
md = EVP_get_digestbyname(*hash_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<unsigned int> xof_md_len = Nothing<unsigned int>();
|
Maybe<unsigned int> xof_md_len = Nothing<unsigned int>();
|
||||||
@ -284,7 +435,7 @@ bool HashTraits::DeriveBits(
|
|||||||
Environment* env,
|
Environment* env,
|
||||||
const HashConfig& params,
|
const HashConfig& params,
|
||||||
ByteSource* out) {
|
ByteSource* out) {
|
||||||
EVPMDPointer ctx(EVP_MD_CTX_new());
|
EVPMDCtxPointer ctx(EVP_MD_CTX_new());
|
||||||
|
|
||||||
if (UNLIKELY(!ctx ||
|
if (UNLIKELY(!ctx ||
|
||||||
EVP_DigestInit_ex(ctx.get(), params.digest, nullptr) <= 0 ||
|
EVP_DigestInit_ex(ctx.get(), params.digest, nullptr) <= 0 ||
|
||||||
@ -357,6 +508,5 @@ void InternalVerifyIntegrity(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
args.GetReturnValue().Set(rc.FromMaybe(Local<Value>()));
|
args.GetReturnValue().Set(rc.FromMaybe(Local<Value>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace crypto
|
} // namespace crypto
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -25,6 +25,7 @@ class Hash final : public BaseObject {
|
|||||||
bool HashUpdate(const char* data, size_t len);
|
bool HashUpdate(const char* data, size_t len);
|
||||||
|
|
||||||
static void GetHashes(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetHashes(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetCachedAliases(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
@ -34,7 +35,7 @@ class Hash final : public BaseObject {
|
|||||||
Hash(Environment* env, v8::Local<v8::Object> wrap);
|
Hash(Environment* env, v8::Local<v8::Object> wrap);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EVPMDPointer mdctx_ {};
|
EVPMDCtxPointer mdctx_{};
|
||||||
unsigned int md_len_ = 0;
|
unsigned int md_len_ = 0;
|
||||||
ByteSource digest_;
|
ByteSource digest_;
|
||||||
};
|
};
|
||||||
|
@ -73,7 +73,7 @@ bool ApplyRSAOptions(const ManagedEVPPKey& pkey,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<BackingStore> Node_SignFinal(Environment* env,
|
std::unique_ptr<BackingStore> Node_SignFinal(Environment* env,
|
||||||
EVPMDPointer&& mdctx,
|
EVPMDCtxPointer&& mdctx,
|
||||||
const ManagedEVPPKey& pkey,
|
const ManagedEVPPKey& pkey,
|
||||||
int padding,
|
int padding,
|
||||||
Maybe<int> pss_salt_len) {
|
Maybe<int> pss_salt_len) {
|
||||||
@ -391,7 +391,7 @@ Sign::SignResult Sign::SignFinal(
|
|||||||
if (!mdctx_)
|
if (!mdctx_)
|
||||||
return SignResult(kSignNotInitialised);
|
return SignResult(kSignNotInitialised);
|
||||||
|
|
||||||
EVPMDPointer mdctx = std::move(mdctx_);
|
EVPMDCtxPointer mdctx = std::move(mdctx_);
|
||||||
|
|
||||||
if (!ValidateDSAParameters(pkey.get()))
|
if (!ValidateDSAParameters(pkey.get()))
|
||||||
return SignResult(kSignPrivateKey);
|
return SignResult(kSignPrivateKey);
|
||||||
@ -511,7 +511,7 @@ SignBase::Error Verify::VerifyFinal(const ManagedEVPPKey& pkey,
|
|||||||
unsigned char m[EVP_MAX_MD_SIZE];
|
unsigned char m[EVP_MAX_MD_SIZE];
|
||||||
unsigned int m_len;
|
unsigned int m_len;
|
||||||
*verify_result = false;
|
*verify_result = false;
|
||||||
EVPMDPointer mdctx = std::move(mdctx_);
|
EVPMDCtxPointer mdctx = std::move(mdctx_);
|
||||||
|
|
||||||
if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
|
if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
|
||||||
return kSignPublicKey;
|
return kSignPublicKey;
|
||||||
@ -696,7 +696,7 @@ bool SignTraits::DeriveBits(
|
|||||||
const SignConfiguration& params,
|
const SignConfiguration& params,
|
||||||
ByteSource* out) {
|
ByteSource* out) {
|
||||||
ClearErrorOnReturn clear_error_on_return;
|
ClearErrorOnReturn clear_error_on_return;
|
||||||
EVPMDPointer context(EVP_MD_CTX_new());
|
EVPMDCtxPointer context(EVP_MD_CTX_new());
|
||||||
EVP_PKEY_CTX* ctx = nullptr;
|
EVP_PKEY_CTX* ctx = nullptr;
|
||||||
|
|
||||||
switch (params.mode) {
|
switch (params.mode) {
|
||||||
|
@ -42,7 +42,7 @@ class SignBase : public BaseObject {
|
|||||||
SET_SELF_SIZE(SignBase)
|
SET_SELF_SIZE(SignBase)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EVPMDPointer mdctx_;
|
EVPMDCtxPointer mdctx_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sign : public SignBase {
|
class Sign : public SignBase {
|
||||||
|
@ -62,7 +62,7 @@ using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
|
|||||||
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
||||||
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
||||||
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
||||||
using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
||||||
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
||||||
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
||||||
using BignumPointer = DeleteFnPtr<BIGNUM, BN_clear_free>;
|
using BignumPointer = DeleteFnPtr<BIGNUM, BN_clear_free>;
|
||||||
|
14
src/env.h
14
src/env.h
@ -49,6 +49,10 @@
|
|||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
|
#if HAVE_OPENSSL
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -1028,6 +1032,16 @@ class Environment : public MemoryRetainer {
|
|||||||
kExitInfoFieldCount
|
kExitInfoFieldCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if HAVE_OPENSSL
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
// We declare another alias here to avoid having to include crypto_util.h
|
||||||
|
using EVPMDPointer = DeleteFnPtr<EVP_MD, EVP_MD_free>;
|
||||||
|
std::vector<EVPMDPointer> evp_md_cache;
|
||||||
|
#endif // OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
std::unordered_map<std::string, size_t> alias_to_md_id_map;
|
||||||
|
std::vector<std::string> supported_hash_algorithms;
|
||||||
|
#endif // HAVE_OPENSSL
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>,
|
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>,
|
||||||
v8::Local<v8::Value>),
|
v8::Local<v8::Value>),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user