mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
deps: start working on ncrypto dep
Start moving src/crypto functionality out to a separate dep that can be shared with other projects that need to emulate Node.js crypto behavior. PR-URL: https://github.com/nodejs/node/pull/53803 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
parent
c77424c990
commit
efe5b81df9
3
Makefile
3
Makefile
@ -175,7 +175,8 @@ with-code-cache test-code-cache:
|
|||||||
out/Makefile: config.gypi common.gypi node.gyp \
|
out/Makefile: config.gypi common.gypi node.gyp \
|
||||||
deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \
|
deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \
|
||||||
deps/simdutf/simdutf.gyp deps/ada/ada.gyp deps/nbytes/nbytes.gyp \
|
deps/simdutf/simdutf.gyp deps/ada/ada.gyp deps/nbytes/nbytes.gyp \
|
||||||
tools/v8_gypfiles/toolchain.gypi tools/v8_gypfiles/features.gypi \
|
tools/v8_gypfiles/toolchain.gypi \
|
||||||
|
tools/v8_gypfiles/features.gypi \
|
||||||
tools/v8_gypfiles/inspector.gypi tools/v8_gypfiles/v8.gyp
|
tools/v8_gypfiles/inspector.gypi tools/v8_gypfiles/v8.gyp
|
||||||
$(PYTHON) tools/gyp_node.py -f make
|
$(PYTHON) tools/gyp_node.py -f make
|
||||||
|
|
||||||
|
14
deps/ncrypto/BUILD.gn
vendored
Normal file
14
deps/ncrypto/BUILD.gn
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
##############################################################################
|
||||||
|
# #
|
||||||
|
# DO NOT EDIT THIS FILE! #
|
||||||
|
# #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# This file is used by GN for building, which is NOT the build system used for
|
||||||
|
# building official binaries.
|
||||||
|
# Please modify the gyp files if you are making changes to build system.
|
||||||
|
|
||||||
|
import("unofficial.gni")
|
||||||
|
|
||||||
|
ncrypto_gn_build("ncrypto") {
|
||||||
|
}
|
5
deps/ncrypto/README.md
vendored
Normal file
5
deps/ncrypto/README.md
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Node.js crypto (ncrypto) library
|
||||||
|
|
||||||
|
The `ncrypto` library extracts the base internal implementation of Node.js crypto operations
|
||||||
|
that support both `node:crypto` and Web Crypto implementations and makes them available for
|
||||||
|
use in other projects that need to emulate Node.js' behavior.
|
92
deps/ncrypto/engine.cc
vendored
Normal file
92
deps/ncrypto/engine.cc
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "ncrypto.h"
|
||||||
|
|
||||||
|
namespace ncrypto {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Engine
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
EnginePointer::EnginePointer(ENGINE* engine_, bool finish_on_exit_)
|
||||||
|
: engine(engine_),
|
||||||
|
finish_on_exit(finish_on_exit_) {}
|
||||||
|
|
||||||
|
EnginePointer::EnginePointer(EnginePointer&& other) noexcept
|
||||||
|
: engine(other.engine),
|
||||||
|
finish_on_exit(other.finish_on_exit) {
|
||||||
|
other.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
EnginePointer::~EnginePointer() { reset(); }
|
||||||
|
|
||||||
|
EnginePointer& EnginePointer::operator=(EnginePointer&& other) noexcept {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
this->~EnginePointer();
|
||||||
|
return *new (this) EnginePointer(std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnginePointer::reset(ENGINE* engine_, bool finish_on_exit_) {
|
||||||
|
if (engine != nullptr) {
|
||||||
|
if (finish_on_exit) {
|
||||||
|
// This also does the equivalent of ENGINE_free.
|
||||||
|
ENGINE_finish(engine);
|
||||||
|
} else {
|
||||||
|
ENGINE_free(engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
engine = engine_;
|
||||||
|
finish_on_exit = finish_on_exit_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENGINE* EnginePointer::release() {
|
||||||
|
ENGINE* ret = engine;
|
||||||
|
engine = nullptr;
|
||||||
|
finish_on_exit = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnginePointer EnginePointer::getEngineByName(const std::string_view name,
|
||||||
|
CryptoErrorList* errors) {
|
||||||
|
MarkPopErrorOnReturn mark_pop_error_on_return(errors);
|
||||||
|
EnginePointer engine(ENGINE_by_id(name.data()));
|
||||||
|
if (!engine) {
|
||||||
|
// Engine not found, try loading dynamically.
|
||||||
|
engine = EnginePointer(ENGINE_by_id("dynamic"));
|
||||||
|
if (engine) {
|
||||||
|
if (!ENGINE_ctrl_cmd_string(engine.get(), "SO_PATH", name.data(), 0) ||
|
||||||
|
!ENGINE_ctrl_cmd_string(engine.get(), "LOAD", nullptr, 0)) {
|
||||||
|
engine.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EnginePointer::setAsDefault(uint32_t flags, CryptoErrorList* errors) {
|
||||||
|
if (engine == nullptr) return false;
|
||||||
|
ClearErrorOnReturn clear_error_on_return(errors);
|
||||||
|
return ENGINE_set_default(engine, flags) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EnginePointer::init(bool finish_on_exit) {
|
||||||
|
if (engine == nullptr) return false;
|
||||||
|
if (finish_on_exit) setFinishOnExit();
|
||||||
|
return ENGINE_init(engine) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVPKeyPointer EnginePointer::loadPrivateKey(const std::string_view key_name) {
|
||||||
|
if (engine == nullptr) return EVPKeyPointer();
|
||||||
|
return EVPKeyPointer(ENGINE_load_private_key(engine, key_name.data(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnginePointer::initEnginesOnce() {
|
||||||
|
static bool initialized = false;
|
||||||
|
if (!initialized) {
|
||||||
|
ENGINE_load_builtin_engines();
|
||||||
|
ENGINE_register_all_complete();
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENSSL_NO_ENGINE
|
||||||
|
|
||||||
|
} // namespace ncrypto
|
223
deps/ncrypto/ncrypto.cc
vendored
Normal file
223
deps/ncrypto/ncrypto.cc
vendored
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
#include "ncrypto.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include "openssl/bn.h"
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
#include "openssl/provider.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ncrypto {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
ClearErrorOnReturn::ClearErrorOnReturn(CryptoErrorList* errors) : errors_(errors) {
|
||||||
|
ERR_clear_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearErrorOnReturn::~ClearErrorOnReturn() {
|
||||||
|
if (errors_ != nullptr) errors_->capture();
|
||||||
|
ERR_clear_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClearErrorOnReturn::peeKError() { return ERR_peek_error(); }
|
||||||
|
|
||||||
|
MarkPopErrorOnReturn::MarkPopErrorOnReturn(CryptoErrorList* errors) : errors_(errors) {
|
||||||
|
ERR_set_mark();
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkPopErrorOnReturn::~MarkPopErrorOnReturn() {
|
||||||
|
if (errors_ != nullptr) errors_->capture();
|
||||||
|
ERR_pop_to_mark();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MarkPopErrorOnReturn::peekError() { return ERR_peek_error(); }
|
||||||
|
|
||||||
|
CryptoErrorList::CryptoErrorList(CryptoErrorList::Option option) {
|
||||||
|
if (option == Option::CAPTURE_ON_CONSTRUCT) capture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptoErrorList::capture() {
|
||||||
|
errors_.clear();
|
||||||
|
while(const auto err = ERR_get_error()) {
|
||||||
|
char buf[256];
|
||||||
|
ERR_error_string_n(err, buf, sizeof(buf));
|
||||||
|
errors_.emplace_front(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptoErrorList::add(std::string error) {
|
||||||
|
errors_.push_back(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> CryptoErrorList::pop_back() {
|
||||||
|
if (errors_.empty()) return std::nullopt;
|
||||||
|
std::string error = errors_.back();
|
||||||
|
errors_.pop_back();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> CryptoErrorList::pop_front() {
|
||||||
|
if (errors_.empty()) return std::nullopt;
|
||||||
|
std::string error = errors_.front();
|
||||||
|
errors_.pop_front();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
bool isFipsEnabled() {
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
return EVP_default_properties_is_fips_enabled(nullptr) == 1;
|
||||||
|
#else
|
||||||
|
return FIPS_mode() == 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setFipsEnabled(bool enable, CryptoErrorList* errors) {
|
||||||
|
if (isFipsEnabled() == enable) return true;
|
||||||
|
ClearErrorOnReturn clearErrorOnReturn(errors);
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
return EVP_default_properties_enable_fips(nullptr, enable ? 1 : 0) == 1;
|
||||||
|
#else
|
||||||
|
return FIPS_mode_set(enable ? 1 : 0) == 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool testFipsEnabled() {
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
OSSL_PROVIDER* fips_provider = nullptr;
|
||||||
|
if (OSSL_PROVIDER_available(nullptr, "fips")) {
|
||||||
|
fips_provider = OSSL_PROVIDER_load(nullptr, "fips");
|
||||||
|
}
|
||||||
|
const auto enabled = fips_provider == nullptr ? 0 :
|
||||||
|
OSSL_PROVIDER_self_test(fips_provider) ? 1 : 0;
|
||||||
|
#else
|
||||||
|
#ifdef OPENSSL_FIPS
|
||||||
|
const auto enabled = FIPS_selftest() ? 1 : 0;
|
||||||
|
#else // OPENSSL_FIPS
|
||||||
|
const auto enabled = 0;
|
||||||
|
#endif // OPENSSL_FIPS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Bignum
|
||||||
|
BignumPointer::BignumPointer(BIGNUM* bignum) : bn_(bignum) {}
|
||||||
|
|
||||||
|
BignumPointer::BignumPointer(BignumPointer&& other) noexcept
|
||||||
|
: bn_(other.release()) {}
|
||||||
|
|
||||||
|
BignumPointer& BignumPointer::operator=(BignumPointer&& other) noexcept {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
this->~BignumPointer();
|
||||||
|
return *new (this) BignumPointer(std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
BignumPointer::~BignumPointer() { reset(); }
|
||||||
|
|
||||||
|
void BignumPointer::reset(BIGNUM* bn) {
|
||||||
|
bn_.reset(bn);
|
||||||
|
}
|
||||||
|
|
||||||
|
BIGNUM* BignumPointer::release() {
|
||||||
|
return bn_.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t BignumPointer::byteLength() {
|
||||||
|
if (bn_ == nullptr) return 0;
|
||||||
|
return BN_num_bytes(bn_.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> BignumPointer::encode() {
|
||||||
|
return encodePadded(bn_.get(), byteLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> BignumPointer::encodePadded(size_t size) {
|
||||||
|
return encodePadded(bn_.get(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> BignumPointer::encode(const BIGNUM* bn) {
|
||||||
|
return encodePadded(bn, bn != nullptr ? BN_num_bytes(bn) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> BignumPointer::encodePadded(const BIGNUM* bn, size_t s) {
|
||||||
|
if (bn == nullptr) return std::vector<uint8_t>(0);
|
||||||
|
size_t size = std::max(s, static_cast<size_t>(BN_num_bytes(bn)));
|
||||||
|
std::vector<uint8_t> buf(size);
|
||||||
|
BN_bn2binpad(bn, buf.data(), size);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BignumPointer::operator==(const BignumPointer& other) noexcept {
|
||||||
|
if (bn_ == nullptr && other.bn_ != nullptr) return false;
|
||||||
|
if (bn_ != nullptr && other.bn_ == nullptr) return false;
|
||||||
|
if (bn_ == nullptr && other.bn_ == nullptr) return true;
|
||||||
|
return BN_cmp(bn_.get(), other.bn_.get()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BignumPointer::operator==(const BIGNUM* other) noexcept {
|
||||||
|
if (bn_ == nullptr && other != nullptr) return false;
|
||||||
|
if (bn_ != nullptr && other == nullptr) return false;
|
||||||
|
if (bn_ == nullptr && other == nullptr) return true;
|
||||||
|
return BN_cmp(bn_.get(), other) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Utility methods
|
||||||
|
|
||||||
|
bool CSPRNG(void* buffer, size_t length) {
|
||||||
|
auto buf = reinterpret_cast<unsigned char*>(buffer);
|
||||||
|
do {
|
||||||
|
if (1 == RAND_status()) {
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (1 == RAND_bytes_ex(nullptr, buf, length, 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
while (length > INT_MAX && 1 == RAND_bytes(buf, INT_MAX)) {
|
||||||
|
buf += INT_MAX;
|
||||||
|
length -= INT_MAX;
|
||||||
|
}
|
||||||
|
if (length <= INT_MAX && 1 == RAND_bytes(buf, static_cast<int>(length)))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
const auto code = ERR_peek_last_error();
|
||||||
|
// A misconfigured OpenSSL 3 installation may report 1 from RAND_poll()
|
||||||
|
// and RAND_status() but fail in RAND_bytes() if it cannot look up
|
||||||
|
// a matching algorithm for the CSPRNG.
|
||||||
|
if (ERR_GET_LIB(code) == ERR_LIB_RAND) {
|
||||||
|
const auto reason = ERR_GET_REASON(code);
|
||||||
|
if (reason == RAND_R_ERROR_INSTANTIATING_DRBG ||
|
||||||
|
reason == RAND_R_UNABLE_TO_FETCH_DRBG ||
|
||||||
|
reason == RAND_R_UNABLE_TO_CREATE_DRBG) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} while (1 == RAND_poll());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NoPasswordCallback(char* buf, int size, int rwflag, void* u) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PasswordCallback(char* buf, int size, int rwflag, void* u) {
|
||||||
|
const Buffer* passphrase = static_cast<const Buffer*>(u);
|
||||||
|
if (passphrase != nullptr) {
|
||||||
|
size_t buflen = static_cast<size_t>(size);
|
||||||
|
size_t len = passphrase->len;
|
||||||
|
if (buflen < len)
|
||||||
|
return -1;
|
||||||
|
memcpy(buf, reinterpret_cast<const char*>(passphrase->data), len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ncrypto
|
27
deps/ncrypto/ncrypto.gyp
vendored
Normal file
27
deps/ncrypto/ncrypto.gyp
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
'variables': {
|
||||||
|
'ncrypto_sources': [
|
||||||
|
'engine.cc',
|
||||||
|
'ncrypto.cc',
|
||||||
|
'ncrypto.h',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'ncrypto',
|
||||||
|
'type': 'static_library',
|
||||||
|
'include_dirs': ['.'],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': ['.'],
|
||||||
|
},
|
||||||
|
'sources': [ '<@(ncrypto_sources)' ],
|
||||||
|
'conditions': [
|
||||||
|
['node_shared_openssl=="false"', {
|
||||||
|
'dependencies': [
|
||||||
|
'../openssl/openssl.gyp:openssl'
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
298
deps/ncrypto/ncrypto.h
vendored
Normal file
298
deps/ncrypto/ncrypto.h
vendored
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#include "openssl/bn.h"
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/dh.h>
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#include <openssl/kdf.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
# include <openssl/engine.h>
|
||||||
|
#endif // !OPENSSL_NO_ENGINE
|
||||||
|
// The FIPS-related functions are only available
|
||||||
|
// when the OpenSSL itself was compiled with FIPS support.
|
||||||
|
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_MAJOR < 3
|
||||||
|
# include <openssl/fips.h>
|
||||||
|
#endif // OPENSSL_FIPS
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define NCRYPTO_MUST_USE_RESULT __attribute__((warn_unused_result))
|
||||||
|
#else
|
||||||
|
#define NCRYPTO_MUST_USE_RESULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ncrypto {
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Utility macros
|
||||||
|
|
||||||
|
#if NCRYPTO_DEVELOPMENT_CHECKS
|
||||||
|
#define NCRYPTO_STR(x) #x
|
||||||
|
#define NCRYPTO_REQUIRE(EXPR) \
|
||||||
|
{ \
|
||||||
|
if (!(EXPR) { abort(); }) }
|
||||||
|
|
||||||
|
#define NCRYPTO_FAIL(MESSAGE) \
|
||||||
|
do { \
|
||||||
|
std::cerr << "FAIL: " << (MESSAGE) << std::endl; \
|
||||||
|
abort(); \
|
||||||
|
} while (0);
|
||||||
|
#define NCRYPTO_ASSERT_EQUAL(LHS, RHS, MESSAGE) \
|
||||||
|
do { \
|
||||||
|
if (LHS != RHS) { \
|
||||||
|
std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \
|
||||||
|
NCRYPTO_FAIL(MESSAGE); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
#define NCRYPTO_ASSERT_TRUE(COND) \
|
||||||
|
do { \
|
||||||
|
if (!(COND)) { \
|
||||||
|
std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \
|
||||||
|
<< std::endl; \
|
||||||
|
NCRYPTO_FAIL(NCRYPTO_STR(COND)); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
#else
|
||||||
|
#define NCRYPTO_FAIL(MESSAGE)
|
||||||
|
#define NCRYPTO_ASSERT_EQUAL(LHS, RHS, MESSAGE)
|
||||||
|
#define NCRYPTO_ASSERT_TRUE(COND)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NCRYPTO_DISALLOW_COPY(Name) \
|
||||||
|
Name(const Name&) = delete; \
|
||||||
|
Name& operator=(const Name&) = delete;
|
||||||
|
#define NCRYPTO_DISALLOW_MOVE(Name) \
|
||||||
|
Name(Name&&) = delete; \
|
||||||
|
Name& operator=(Name&&) = delete;
|
||||||
|
#define NCRYPTO_DISALLOW_COPY_AND_MOVE(Name) \
|
||||||
|
NCRYPTO_DISALLOW_COPY(Name) \
|
||||||
|
NCRYPTO_DISALLOW_MOVE(Name)
|
||||||
|
#define NCRYPTO_DISALLOW_NEW_DELETE() \
|
||||||
|
void* operator new(size_t) = delete; \
|
||||||
|
void operator delete(void*) = delete;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Error handling utilities
|
||||||
|
|
||||||
|
// Capture the current OpenSSL Error Stack. The stack will be ordered such
|
||||||
|
// that the error currently at the top of the stack is at the end of the
|
||||||
|
// list and the error at the bottom of the stack is at the beginning.
|
||||||
|
class CryptoErrorList final {
|
||||||
|
public:
|
||||||
|
enum class Option {
|
||||||
|
NONE,
|
||||||
|
CAPTURE_ON_CONSTRUCT
|
||||||
|
};
|
||||||
|
CryptoErrorList(Option option = Option::CAPTURE_ON_CONSTRUCT);
|
||||||
|
|
||||||
|
void capture();
|
||||||
|
|
||||||
|
// Add an error message to the end of the stack.
|
||||||
|
void add(std::string message);
|
||||||
|
|
||||||
|
inline const std::string& peek_back() const { return errors_.back(); }
|
||||||
|
inline size_t size() const { return errors_.size(); }
|
||||||
|
inline bool empty() const { return errors_.empty(); }
|
||||||
|
|
||||||
|
inline auto begin() const noexcept { return errors_.begin(); }
|
||||||
|
inline auto end() const noexcept { return errors_.end(); }
|
||||||
|
inline auto rbegin() const noexcept { return errors_.rbegin(); }
|
||||||
|
inline auto rend() const noexcept { return errors_.rend(); }
|
||||||
|
|
||||||
|
std::optional<std::string> pop_back();
|
||||||
|
std::optional<std::string> pop_front();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<std::string> errors_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forcibly clears the error stack on destruction. This stops stale errors
|
||||||
|
// from popping up later in the lifecycle of crypto operations where they
|
||||||
|
// would cause spurious failures. It is a rather blunt method, though, and
|
||||||
|
// ERR_clear_error() isn't necessarily cheap.
|
||||||
|
//
|
||||||
|
// If created with a pointer to a CryptoErrorList, the current OpenSSL error
|
||||||
|
// stack will be captured before clearing the error.
|
||||||
|
class ClearErrorOnReturn final {
|
||||||
|
public:
|
||||||
|
ClearErrorOnReturn(CryptoErrorList* errors = nullptr);
|
||||||
|
~ClearErrorOnReturn();
|
||||||
|
NCRYPTO_DISALLOW_COPY_AND_MOVE(ClearErrorOnReturn)
|
||||||
|
NCRYPTO_DISALLOW_NEW_DELETE()
|
||||||
|
|
||||||
|
int peeKError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CryptoErrorList* errors_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pop errors from OpenSSL's error stack that were added between when this
|
||||||
|
// was constructed and destructed.
|
||||||
|
//
|
||||||
|
// If created with a pointer to a CryptoErrorList, the current OpenSSL error
|
||||||
|
// stack will be captured before resetting the error to the mark.
|
||||||
|
class MarkPopErrorOnReturn final {
|
||||||
|
public:
|
||||||
|
MarkPopErrorOnReturn(CryptoErrorList* errors = nullptr);
|
||||||
|
~MarkPopErrorOnReturn();
|
||||||
|
NCRYPTO_DISALLOW_COPY_AND_MOVE(MarkPopErrorOnReturn)
|
||||||
|
NCRYPTO_DISALLOW_NEW_DELETE()
|
||||||
|
|
||||||
|
int peekError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CryptoErrorList* errors_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Various smart pointer aliases for OpenSSL types.
|
||||||
|
|
||||||
|
template <typename T, void (*function)(T*)>
|
||||||
|
struct FunctionDeleter {
|
||||||
|
void operator()(T* pointer) const { function(pointer); }
|
||||||
|
typedef std::unique_ptr<T, FunctionDeleter> Pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, void (*function)(T*)>
|
||||||
|
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
|
||||||
|
|
||||||
|
using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
|
||||||
|
using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>;
|
||||||
|
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
|
||||||
|
using DHPointer = DeleteFnPtr<DH, DH_free>;
|
||||||
|
using DSAPointer = DeleteFnPtr<DSA, DSA_free>;
|
||||||
|
using DSASigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>;
|
||||||
|
using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>;
|
||||||
|
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
||||||
|
using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
|
||||||
|
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
||||||
|
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
|
||||||
|
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
||||||
|
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
||||||
|
using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
||||||
|
using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
|
||||||
|
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
|
||||||
|
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
||||||
|
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
||||||
|
using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>;
|
||||||
|
using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
|
||||||
|
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
|
||||||
|
using X509Pointer = DeleteFnPtr<X509, X509_free>;
|
||||||
|
|
||||||
|
class BignumPointer final {
|
||||||
|
public:
|
||||||
|
BignumPointer() = default;
|
||||||
|
explicit BignumPointer(BIGNUM* bignum);
|
||||||
|
BignumPointer(BignumPointer&& other) noexcept;
|
||||||
|
BignumPointer& operator=(BignumPointer&& other) noexcept;
|
||||||
|
NCRYPTO_DISALLOW_COPY(BignumPointer)
|
||||||
|
~BignumPointer();
|
||||||
|
|
||||||
|
bool operator==(const BignumPointer& other) noexcept;
|
||||||
|
bool operator==(const BIGNUM* other) noexcept;
|
||||||
|
inline bool operator==(std::nullptr_t) noexcept { return bn_ == nullptr; }
|
||||||
|
inline operator bool() const { return bn_ != nullptr; }
|
||||||
|
inline BIGNUM* get() const noexcept { return bn_.get(); }
|
||||||
|
void reset(BIGNUM* bn = nullptr);
|
||||||
|
BIGNUM* release();
|
||||||
|
|
||||||
|
size_t byteLength();
|
||||||
|
|
||||||
|
std::vector<uint8_t> encode();
|
||||||
|
std::vector<uint8_t> encodePadded(size_t size);
|
||||||
|
|
||||||
|
static std::vector<uint8_t> encode(const BIGNUM* bn);
|
||||||
|
static std::vector<uint8_t> encodePadded(const BIGNUM* bn, size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
class EnginePointer final {
|
||||||
|
public:
|
||||||
|
EnginePointer() = default;
|
||||||
|
|
||||||
|
explicit EnginePointer(ENGINE* engine_, bool finish_on_exit = false);
|
||||||
|
EnginePointer(EnginePointer&& other) noexcept;
|
||||||
|
EnginePointer& operator=(EnginePointer&& other) noexcept;
|
||||||
|
NCRYPTO_DISALLOW_COPY(EnginePointer)
|
||||||
|
~EnginePointer();
|
||||||
|
|
||||||
|
inline operator bool() const { return engine != nullptr; }
|
||||||
|
inline ENGINE* get() { return engine; }
|
||||||
|
inline void setFinishOnExit() { finish_on_exit = true; }
|
||||||
|
|
||||||
|
void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false);
|
||||||
|
|
||||||
|
bool setAsDefault(uint32_t flags, CryptoErrorList* errors = nullptr);
|
||||||
|
bool init(bool finish_on_exit = false);
|
||||||
|
EVPKeyPointer loadPrivateKey(const std::string_view key_name);
|
||||||
|
|
||||||
|
// Release ownership of the ENGINE* pointer.
|
||||||
|
ENGINE* release();
|
||||||
|
|
||||||
|
// Retrieve an OpenSSL Engine instance by name. If the name does not
|
||||||
|
// identify a valid named engine, the returned EnginePointer will be
|
||||||
|
// empty.
|
||||||
|
static EnginePointer getEngineByName(const std::string_view name,
|
||||||
|
CryptoErrorList* errors = nullptr);
|
||||||
|
|
||||||
|
// Call once when initializing OpenSSL at startup for the process.
|
||||||
|
static void initEnginesOnce();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ENGINE* engine = nullptr;
|
||||||
|
bool finish_on_exit = false;
|
||||||
|
};
|
||||||
|
#endif // !OPENSSL_NO_ENGINE
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// FIPS
|
||||||
|
bool isFipsEnabled();
|
||||||
|
|
||||||
|
bool setFipsEnabled(bool enabled, CryptoErrorList* errors);
|
||||||
|
|
||||||
|
bool testFipsEnabled();
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Various utilities
|
||||||
|
|
||||||
|
struct Buffer {
|
||||||
|
const void* data;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CSPRNG(void* buffer, size_t length) NCRYPTO_MUST_USE_RESULT;
|
||||||
|
|
||||||
|
// This callback is used to avoid the default passphrase callback in OpenSSL
|
||||||
|
// which will typically prompt for the passphrase. The prompting is designed
|
||||||
|
// for the OpenSSL CLI, but works poorly for some environments like Node.js
|
||||||
|
// because it involves synchronous interaction with the controlling terminal,
|
||||||
|
// something we never want, and use this function to avoid it.
|
||||||
|
int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
|
||||||
|
|
||||||
|
int PasswordCallback(char* buf, int size, int rwflag, void* u);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Version metadata
|
||||||
|
#define NCRYPTO_VERSION "0.0.1"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NCRYPTO_VERSION_MAJOR = 0,
|
||||||
|
NCRYPTO_VERSION_MINOR = 0,
|
||||||
|
NCRYPTO_VERSION_REVISION = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ncrypto
|
9
node.gyp
9
node.gyp
@ -940,6 +940,9 @@
|
|||||||
'<@(node_crypto_sources)',
|
'<@(node_crypto_sources)',
|
||||||
'<@(node_quic_sources)',
|
'<@(node_quic_sources)',
|
||||||
],
|
],
|
||||||
|
'dependencies': [
|
||||||
|
'deps/ncrypto/ncrypto.gyp:ncrypto',
|
||||||
|
],
|
||||||
}],
|
}],
|
||||||
[ 'OS in "linux freebsd mac solaris" and '
|
[ 'OS in "linux freebsd mac solaris" and '
|
||||||
'target_arch=="x64" and '
|
'target_arch=="x64" and '
|
||||||
@ -1201,6 +1204,9 @@
|
|||||||
'defines': [
|
'defines': [
|
||||||
'HAVE_OPENSSL=1',
|
'HAVE_OPENSSL=1',
|
||||||
],
|
],
|
||||||
|
'dependencies': [
|
||||||
|
'deps/ncrypto/ncrypto.gyp:ncrypto',
|
||||||
|
],
|
||||||
'sources': [ '<@(node_cctest_openssl_sources)' ],
|
'sources': [ '<@(node_cctest_openssl_sources)' ],
|
||||||
}],
|
}],
|
||||||
['v8_enable_inspector==1', {
|
['v8_enable_inspector==1', {
|
||||||
@ -1394,6 +1400,9 @@
|
|||||||
'defines': [ 'NODE_MKSNAPSHOT_USE_ARRAY_LITERALS=1' ],
|
'defines': [ 'NODE_MKSNAPSHOT_USE_ARRAY_LITERALS=1' ],
|
||||||
}],
|
}],
|
||||||
[ 'node_use_openssl=="true"', {
|
[ 'node_use_openssl=="true"', {
|
||||||
|
'dependencies': [
|
||||||
|
'deps/ncrypto/ncrypto.gyp:ncrypto',
|
||||||
|
],
|
||||||
'defines': [
|
'defines': [
|
||||||
'HAVE_OPENSSL=1',
|
'HAVE_OPENSSL=1',
|
||||||
],
|
],
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#include "crypto/crypto_context.h"
|
#include "crypto/crypto_context.h"
|
||||||
|
#include "base_object-inl.h"
|
||||||
#include "crypto/crypto_bio.h"
|
#include "crypto/crypto_bio.h"
|
||||||
#include "crypto/crypto_common.h"
|
#include "crypto/crypto_common.h"
|
||||||
#include "crypto/crypto_util.h"
|
#include "crypto/crypto_util.h"
|
||||||
#include "base_object-inl.h"
|
|
||||||
#include "env-inl.h"
|
#include "env-inl.h"
|
||||||
#include "memory_tracker-inl.h"
|
#include "memory_tracker-inl.h"
|
||||||
|
#include "ncrypto.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "node_buffer.h"
|
#include "node_buffer.h"
|
||||||
#include "node_options.h"
|
#include "node_options.h"
|
||||||
@ -655,26 +656,28 @@ void SecureContext::SetEngineKey(const FunctionCallbackInfo<Value>& args) {
|
|||||||
"experimental permission model is enabled");
|
"experimental permission model is enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoErrorStore errors;
|
ncrypto::CryptoErrorList errors;
|
||||||
Utf8Value engine_id(env->isolate(), args[1]);
|
Utf8Value engine_id(env->isolate(), args[1]);
|
||||||
EnginePointer engine = LoadEngineById(*engine_id, &errors);
|
auto engine = ncrypto::EnginePointer::getEngineByName(
|
||||||
|
engine_id.ToStringView(), &errors);
|
||||||
if (!engine) {
|
if (!engine) {
|
||||||
Local<Value> exception;
|
Local<Value> exception;
|
||||||
if (errors.ToException(env).ToLocal(&exception))
|
if (errors.empty()) {
|
||||||
|
errors.add(getNodeCryptoErrorString(NodeCryptoError::ENGINE_NOT_FOUND,
|
||||||
|
*engine_id));
|
||||||
|
}
|
||||||
|
if (cryptoErrorListToException(env, errors).ToLocal(&exception))
|
||||||
env->isolate()->ThrowException(exception);
|
env->isolate()->ThrowException(exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ENGINE_init(engine.get())) {
|
if (!engine.init(true /* finish on exit*/)) {
|
||||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(
|
||||||
env, "Failure to initialize engine");
|
env, "Failure to initialize engine");
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.finish_on_exit = true;
|
|
||||||
|
|
||||||
Utf8Value key_name(env->isolate(), args[0]);
|
Utf8Value key_name(env->isolate(), args[0]);
|
||||||
EVPKeyPointer key(ENGINE_load_private_key(engine.get(), *key_name,
|
auto key = engine.loadPrivateKey(key_name.ToStringView());
|
||||||
nullptr, nullptr));
|
|
||||||
|
|
||||||
if (!key)
|
if (!key)
|
||||||
return ThrowCryptoError(env, ERR_get_error(), "ENGINE_load_private_key");
|
return ThrowCryptoError(env, ERR_get_error(), "ENGINE_load_private_key");
|
||||||
@ -1143,12 +1146,17 @@ void SecureContext::SetClientCertEngine(
|
|||||||
"experimental permission model is enabled");
|
"experimental permission model is enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoErrorStore errors;
|
ncrypto::CryptoErrorList errors;
|
||||||
const Utf8Value engine_id(env->isolate(), args[0]);
|
const Utf8Value engine_id(env->isolate(), args[0]);
|
||||||
EnginePointer engine = LoadEngineById(*engine_id, &errors);
|
auto engine = ncrypto::EnginePointer::getEngineByName(
|
||||||
|
engine_id.ToStringView(), &errors);
|
||||||
if (!engine) {
|
if (!engine) {
|
||||||
Local<Value> exception;
|
Local<Value> exception;
|
||||||
if (errors.ToException(env).ToLocal(&exception))
|
if (errors.empty()) {
|
||||||
|
errors.add(getNodeCryptoErrorString(NodeCryptoError::ENGINE_NOT_FOUND,
|
||||||
|
*engine_id));
|
||||||
|
}
|
||||||
|
if (cryptoErrorListToException(env, errors).ToLocal(&exception))
|
||||||
env->isolate()->ThrowException(exception);
|
env->isolate()->ThrowException(exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ class SecureContext final : public BaseObject {
|
|||||||
X509Pointer issuer_;
|
X509Pointer issuer_;
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
bool client_cert_engine_provided_ = false;
|
bool client_cert_engine_provided_ = false;
|
||||||
EnginePointer private_key_engine_;
|
ncrypto::EnginePointer private_key_engine_;
|
||||||
#endif // !OPENSSL_NO_ENGINE
|
#endif // !OPENSSL_NO_ENGINE
|
||||||
|
|
||||||
unsigned char ticket_key_name_[16];
|
unsigned char ticket_key_name_[16];
|
||||||
|
@ -64,6 +64,26 @@ using v8::Value;
|
|||||||
namespace crypto {
|
namespace crypto {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Our custom implementation of the certificate verify callback
|
||||||
|
// used when establishing a TLS handshake. Because we cannot perform
|
||||||
|
// I/O quickly enough with X509_STORE_CTX_ APIs in this callback,
|
||||||
|
// we ignore preverify_ok errors here and let the handshake continue.
|
||||||
|
// In other words, this VerifyCallback is a non-op. It is imperative
|
||||||
|
// that the user user Connection::VerifyError after the `secure`
|
||||||
|
// callback has been made.
|
||||||
|
int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
|
||||||
|
// From https://www.openssl.org/docs/man1.1.1/man3/SSL_verify_cb:
|
||||||
|
//
|
||||||
|
// If VerifyCallback returns 1, the verification process is continued. If
|
||||||
|
// VerifyCallback always returns 1, the TLS/SSL handshake will not be
|
||||||
|
// terminated with respect to verification failures and the connection will
|
||||||
|
// be established. The calling process can however retrieve the error code
|
||||||
|
// of the last verification error using SSL_get_verify_result(3) or by
|
||||||
|
// maintaining its own error storage managed by VerifyCallback.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
SSL_SESSION* GetSessionCallback(
|
SSL_SESSION* GetSessionCallback(
|
||||||
SSL* s,
|
SSL* s,
|
||||||
const unsigned char* key,
|
const unsigned char* key,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "crypto/crypto_keys.h"
|
#include "crypto/crypto_keys.h"
|
||||||
#include "env-inl.h"
|
#include "env-inl.h"
|
||||||
#include "memory_tracker-inl.h"
|
#include "memory_tracker-inl.h"
|
||||||
|
#include "ncrypto.h"
|
||||||
#include "node_buffer.h"
|
#include "node_buffer.h"
|
||||||
#include "node_options-inl.h"
|
#include "node_options-inl.h"
|
||||||
#include "string_bytes.h"
|
#include "string_bytes.h"
|
||||||
@ -11,6 +12,10 @@
|
|||||||
#include "util-inl.h"
|
#include "util-inl.h"
|
||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
#include <openssl/engine.h>
|
||||||
|
#endif // !OPENSSL_NO_ENGINE
|
||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
@ -43,22 +48,6 @@ using v8::Uint8Array;
|
|||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
namespace crypto {
|
namespace crypto {
|
||||||
int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
|
|
||||||
// From https://www.openssl.org/docs/man1.1.1/man3/SSL_verify_cb:
|
|
||||||
//
|
|
||||||
// If VerifyCallback returns 1, the verification process is continued. If
|
|
||||||
// VerifyCallback always returns 1, the TLS/SSL handshake will not be
|
|
||||||
// terminated with respect to verification failures and the connection will
|
|
||||||
// be established. The calling process can however retrieve the error code
|
|
||||||
// of the last verification error using SSL_get_verify_result(3) or by
|
|
||||||
// maintaining its own error storage managed by VerifyCallback.
|
|
||||||
//
|
|
||||||
// Since we cannot perform I/O quickly enough with X509_STORE_CTX_ APIs in
|
|
||||||
// this callback, we ignore all preverify_ok errors and let the handshake
|
|
||||||
// continue. It is imperative that the user use Connection::VerifyError after
|
|
||||||
// the 'secure' callback has been made.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length) {
|
MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length) {
|
||||||
unsigned char* buf = static_cast<unsigned char*>(buffer);
|
unsigned char* buf = static_cast<unsigned char*>(buffer);
|
||||||
@ -206,21 +195,14 @@ void InitCryptoOnce() {
|
|||||||
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
|
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
ERR_load_ENGINE_strings();
|
ncrypto::EnginePointer::initEnginesOnce();
|
||||||
ENGINE_load_builtin_engines();
|
|
||||||
#endif // !OPENSSL_NO_ENGINE
|
#endif // !OPENSSL_NO_ENGINE
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
||||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||||
Mutex::ScopedLock fips_lock(fips_mutex);
|
Mutex::ScopedLock fips_lock(fips_mutex);
|
||||||
|
args.GetReturnValue().Set(ncrypto::isFipsEnabled() ? 1 : 0);
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
|
||||||
args.GetReturnValue().Set(EVP_default_properties_is_fips_enabled(nullptr) ?
|
|
||||||
1 : 0);
|
|
||||||
#else
|
|
||||||
args.GetReturnValue().Set(FIPS_mode() ? 1 : 0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
||||||
@ -232,43 +214,19 @@ void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CHECK(env->owns_process_state());
|
CHECK(env->owns_process_state());
|
||||||
bool enable = args[0]->BooleanValue(env->isolate());
|
bool enable = args[0]->BooleanValue(env->isolate());
|
||||||
|
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
ncrypto::CryptoErrorList errors;
|
||||||
if (enable == EVP_default_properties_is_fips_enabled(nullptr))
|
if (!ncrypto::setFipsEnabled(enable, &errors)) {
|
||||||
#else
|
Local<Value> exception;
|
||||||
if (static_cast<int>(enable) == FIPS_mode())
|
if (cryptoErrorListToException(env, errors).ToLocal(&exception)) {
|
||||||
#endif
|
env->isolate()->ThrowException(exception);
|
||||||
return; // No action needed.
|
}
|
||||||
|
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
|
||||||
if (!EVP_default_properties_enable_fips(nullptr, enable)) {
|
|
||||||
#else
|
|
||||||
if (!FIPS_mode_set(enable)) {
|
|
||||||
#endif
|
|
||||||
unsigned long err = ERR_get_error(); // NOLINT(runtime/int)
|
|
||||||
return ThrowCryptoError(env, err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||||
Mutex::ScopedLock fips_lock(fips_mutex);
|
Mutex::ScopedLock fips_lock(fips_mutex);
|
||||||
|
args.GetReturnValue().Set(ncrypto::testFipsEnabled() ? 1 : 0);
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
|
||||||
OSSL_PROVIDER* fips_provider = nullptr;
|
|
||||||
if (OSSL_PROVIDER_available(nullptr, "fips")) {
|
|
||||||
fips_provider = OSSL_PROVIDER_load(nullptr, "fips");
|
|
||||||
}
|
|
||||||
const auto enabled = fips_provider == nullptr ? 0 :
|
|
||||||
OSSL_PROVIDER_self_test(fips_provider) ? 1 : 0;
|
|
||||||
#else
|
|
||||||
#ifdef OPENSSL_FIPS
|
|
||||||
const auto enabled = FIPS_selftest() ? 1 : 0;
|
|
||||||
#else // OPENSSL_FIPS
|
|
||||||
const auto enabled = 0;
|
|
||||||
#endif // OPENSSL_FIPS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
args.GetReturnValue().Set(enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CryptoErrorStore::Capture() {
|
void CryptoErrorStore::Capture() {
|
||||||
@ -285,6 +243,60 @@ bool CryptoErrorStore::Empty() const {
|
|||||||
return errors_.empty();
|
return errors_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeLocal<Value> cryptoErrorListToException(
|
||||||
|
Environment* env, const ncrypto::CryptoErrorList& errors) {
|
||||||
|
// The CryptoErrorList contains a listing of zero or more errors.
|
||||||
|
// If there are no errors, it is likely a bug but we will return
|
||||||
|
// an error anyway.
|
||||||
|
if (errors.empty()) {
|
||||||
|
return Exception::Error(FIXED_ONE_BYTE_STRING(env->isolate(), "Ok"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last error in the list is the one that will be used as the
|
||||||
|
// error message. All other errors will be added to the .opensslErrorStack
|
||||||
|
// property. We know there has to be at least one error in the list at
|
||||||
|
// this point.
|
||||||
|
auto& last = errors.peek_back();
|
||||||
|
Local<String> message;
|
||||||
|
if (!String::NewFromUtf8(
|
||||||
|
env->isolate(), last.data(), NewStringType::kNormal, last.size())
|
||||||
|
.ToLocal(&message)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Local<Value> exception = Exception::Error(message);
|
||||||
|
CHECK(!exception.IsEmpty());
|
||||||
|
|
||||||
|
if (errors.size() > 1) {
|
||||||
|
CHECK(exception->IsObject());
|
||||||
|
Local<Object> exception_obj = exception.As<Object>();
|
||||||
|
std::vector<Local<Value>> stack(errors.size() - 1);
|
||||||
|
|
||||||
|
// Iterate over all but the last error in the list.
|
||||||
|
auto current = errors.begin();
|
||||||
|
auto last = errors.end();
|
||||||
|
last--;
|
||||||
|
while (current != last) {
|
||||||
|
Local<Value> error;
|
||||||
|
if (!ToV8Value(env->context(), *current).ToLocal(&error)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
stack.push_back(error);
|
||||||
|
++current;
|
||||||
|
}
|
||||||
|
|
||||||
|
Local<v8::Array> stackArray =
|
||||||
|
v8::Array::New(env->isolate(), &stack[0], stack.size());
|
||||||
|
|
||||||
|
if (!exception_obj
|
||||||
|
->Set(env->context(), env->openssl_error_stack(), stackArray)
|
||||||
|
.IsNothing()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
MaybeLocal<Value> CryptoErrorStore::ToException(
|
MaybeLocal<Value> CryptoErrorStore::ToException(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
Local<String> exception_string) const {
|
Local<String> exception_string) const {
|
||||||
@ -591,54 +603,8 @@ void ThrowCryptoError(Environment* env,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors) {
|
|
||||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
||||||
|
|
||||||
EnginePointer engine(ENGINE_by_id(id));
|
|
||||||
if (!engine) {
|
|
||||||
// Engine not found, try loading dynamically.
|
|
||||||
engine = EnginePointer(ENGINE_by_id("dynamic"));
|
|
||||||
if (engine) {
|
|
||||||
if (!ENGINE_ctrl_cmd_string(engine.get(), "SO_PATH", id, 0) ||
|
|
||||||
!ENGINE_ctrl_cmd_string(engine.get(), "LOAD", nullptr, 0)) {
|
|
||||||
engine.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!engine && errors != nullptr) {
|
|
||||||
errors->Capture();
|
|
||||||
if (errors->Empty()) {
|
|
||||||
errors->Insert(NodeCryptoError::ENGINE_NOT_FOUND, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SetEngine(const char* id, uint32_t flags, CryptoErrorStore* errors) {
|
|
||||||
ClearErrorOnReturn clear_error_on_return;
|
|
||||||
EnginePointer engine = LoadEngineById(id, errors);
|
|
||||||
if (!engine)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!ENGINE_set_default(engine.get(), flags)) {
|
|
||||||
if (errors != nullptr)
|
|
||||||
errors->Capture();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetEngine(const FunctionCallbackInfo<Value>& args) {
|
void SetEngine(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
CHECK(args.Length() >= 2 && args[0]->IsString());
|
|
||||||
uint32_t flags;
|
|
||||||
if (!args[1]->Uint32Value(env->context()).To(&flags)) return;
|
|
||||||
|
|
||||||
const node::Utf8Value engine_id(env->isolate(), args[0]);
|
|
||||||
|
|
||||||
if (UNLIKELY(env->permission()->enabled())) {
|
if (UNLIKELY(env->permission()->enabled())) {
|
||||||
return THROW_ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED(
|
return THROW_ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED(
|
||||||
env,
|
env,
|
||||||
@ -646,7 +612,16 @@ void SetEngine(const FunctionCallbackInfo<Value>& args) {
|
|||||||
"experimental permission model is enabled");
|
"experimental permission model is enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
args.GetReturnValue().Set(SetEngine(*engine_id, flags));
|
CHECK(args.Length() >= 2 && args[0]->IsString());
|
||||||
|
uint32_t flags;
|
||||||
|
if (!args[1]->Uint32Value(env->context()).To(&flags)) return;
|
||||||
|
|
||||||
|
const node::Utf8Value engine_id(env->isolate(), args[0]);
|
||||||
|
// If the engine name is not known, calling setAsDefault on the
|
||||||
|
// empty engine pointer will be non-op that always returns false.
|
||||||
|
args.GetReturnValue().Set(
|
||||||
|
ncrypto::EnginePointer::getEngineByName(engine_id.ToStringView())
|
||||||
|
.setAsDefault(flags));
|
||||||
}
|
}
|
||||||
#endif // !OPENSSL_NO_ENGINE
|
#endif // !OPENSSL_NO_ENGINE
|
||||||
|
|
||||||
@ -655,8 +630,8 @@ MaybeLocal<Value> EncodeBignum(
|
|||||||
const BIGNUM* bn,
|
const BIGNUM* bn,
|
||||||
int size,
|
int size,
|
||||||
Local<Value>* error) {
|
Local<Value>* error) {
|
||||||
std::vector<uint8_t> buf(size);
|
std::vector<uint8_t> buf = ncrypto::BignumPointer::encodePadded(bn, size);
|
||||||
CHECK_EQ(BN_bn2binpad(bn, buf.data(), size), size);
|
CHECK_EQ(buf.size(), static_cast<size_t>(size));
|
||||||
return StringBytes::Encode(
|
return StringBytes::Encode(
|
||||||
env->isolate(),
|
env->isolate(),
|
||||||
reinterpret_cast<const char*>(buf.data()),
|
reinterpret_cast<const char*>(buf.data()),
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
|
#include "ncrypto.h"
|
||||||
|
|
||||||
#include <openssl/dsa.h>
|
#include <openssl/dsa.h>
|
||||||
#include <openssl/ec.h>
|
#include <openssl/ec.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
@ -20,9 +22,7 @@
|
|||||||
#include <openssl/kdf.h>
|
#include <openssl/kdf.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
|
||||||
# include <openssl/engine.h>
|
|
||||||
#endif // !OPENSSL_NO_ENGINE
|
|
||||||
// The FIPS-related functions are only available
|
// The FIPS-related functions are only available
|
||||||
// when the OpenSSL itself was compiled with FIPS support.
|
// when the OpenSSL itself was compiled with FIPS support.
|
||||||
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_MAJOR < 3
|
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_MAJOR < 3
|
||||||
@ -54,39 +54,33 @@ constexpr size_t kSizeOf_EVP_PKEY_CTX = 80;
|
|||||||
constexpr size_t kSizeOf_HMAC_CTX = 32;
|
constexpr size_t kSizeOf_HMAC_CTX = 32;
|
||||||
|
|
||||||
// Define smart pointers for the most commonly used OpenSSL types:
|
// Define smart pointers for the most commonly used OpenSSL types:
|
||||||
using X509Pointer = DeleteFnPtr<X509, X509_free>;
|
using X509Pointer = ncrypto::X509Pointer;
|
||||||
using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>;
|
using BIOPointer = ncrypto::BIOPointer;
|
||||||
using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>;
|
using SSLCtxPointer = ncrypto::SSLCtxPointer;
|
||||||
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
|
using SSLSessionPointer = ncrypto::SSLSessionPointer;
|
||||||
using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
|
using SSLPointer = ncrypto::SSLPointer;
|
||||||
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
using PKCS8Pointer = ncrypto::PKCS8Pointer;
|
||||||
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
using EVPKeyPointer = ncrypto::EVPKeyPointer;
|
||||||
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
using EVPKeyCtxPointer = ncrypto::EVPKeyCtxPointer;
|
||||||
using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
using EVPMDCtxPointer = ncrypto::EVPMDCtxPointer;
|
||||||
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
using RSAPointer = ncrypto::RSAPointer;
|
||||||
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
using ECPointer = ncrypto::ECPointer;
|
||||||
using BignumPointer = DeleteFnPtr<BIGNUM, BN_clear_free>;
|
using BignumPointer = ncrypto::BignumPointer;
|
||||||
using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
|
using BignumCtxPointer = ncrypto::BignumCtxPointer;
|
||||||
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
|
using NetscapeSPKIPointer = ncrypto::NetscapeSPKIPointer;
|
||||||
using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
|
using ECGroupPointer = ncrypto::ECGroupPointer;
|
||||||
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
|
using ECPointPointer = ncrypto::ECPointPointer;
|
||||||
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
using ECKeyPointer = ncrypto::ECKeyPointer;
|
||||||
using DHPointer = DeleteFnPtr<DH, DH_free>;
|
using DHPointer = ncrypto::DHPointer;
|
||||||
using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>;
|
using ECDSASigPointer = ncrypto::ECDSASigPointer;
|
||||||
using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
|
using HMACCtxPointer = ncrypto::HMACCtxPointer;
|
||||||
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
|
using CipherCtxPointer = ncrypto::CipherCtxPointer;
|
||||||
using RsaPointer = DeleteFnPtr<RSA, RSA_free>;
|
using RsaPointer = ncrypto::RSAPointer;
|
||||||
using DsaPointer = DeleteFnPtr<DSA, DSA_free>;
|
using DsaPointer = ncrypto::DSAPointer;
|
||||||
using DsaSigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>;
|
using DsaSigPointer = ncrypto::DSASigPointer;
|
||||||
|
|
||||||
// Our custom implementation of the certificate verify callback
|
using ClearErrorOnReturn = ncrypto::ClearErrorOnReturn;
|
||||||
// used when establishing a TLS handshake. Because we cannot perform
|
using MarkPopErrorOnReturn = ncrypto::MarkPopErrorOnReturn;
|
||||||
// I/O quickly enough with X509_STORE_CTX_ APIs in this callback,
|
|
||||||
// we ignore preverify_ok errors here and let the handshake continue.
|
|
||||||
// In other words, this VerifyCallback is a non-op. It is imperative
|
|
||||||
// that the user user Connection::VerifyError after the `secure`
|
|
||||||
// callback has been made.
|
|
||||||
extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx);
|
|
||||||
|
|
||||||
bool ProcessFipsOptions();
|
bool ProcessFipsOptions();
|
||||||
|
|
||||||
@ -97,21 +91,6 @@ void InitCrypto(v8::Local<v8::Object> target);
|
|||||||
|
|
||||||
extern void UseExtraCaCerts(const std::string& file);
|
extern void UseExtraCaCerts(const std::string& file);
|
||||||
|
|
||||||
// Forcibly clear OpenSSL's error stack on return. This stops stale errors
|
|
||||||
// from popping up later in the lifecycle of crypto operations where they
|
|
||||||
// would cause spurious failures. It's a rather blunt method, though.
|
|
||||||
// ERR_clear_error() isn't necessarily cheap either.
|
|
||||||
struct ClearErrorOnReturn {
|
|
||||||
~ClearErrorOnReturn() { ERR_clear_error(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pop errors from OpenSSL's error stack that were added
|
|
||||||
// between when this was constructed and destructed.
|
|
||||||
struct MarkPopErrorOnReturn {
|
|
||||||
MarkPopErrorOnReturn() { ERR_set_mark(); }
|
|
||||||
~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CSPRNGResult {
|
struct CSPRNGResult {
|
||||||
const bool ok;
|
const bool ok;
|
||||||
MUST_USE_RESULT bool is_ok() const { return ok; }
|
MUST_USE_RESULT bool is_ok() const { return ok; }
|
||||||
@ -165,6 +144,21 @@ enum class NodeCryptoError {
|
|||||||
#undef V
|
#undef V
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string getNodeCryptoErrorString(const NodeCryptoError error,
|
||||||
|
Args&&... args) {
|
||||||
|
const char* error_string = nullptr;
|
||||||
|
switch (error) {
|
||||||
|
#define V(CODE, DESCRIPTION) \
|
||||||
|
case NodeCryptoError::CODE: \
|
||||||
|
error_string = DESCRIPTION; \
|
||||||
|
break;
|
||||||
|
NODE_CRYPTO_ERROR_CODES_MAP(V)
|
||||||
|
#undef V
|
||||||
|
}
|
||||||
|
return SPrintF(error_string, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
// Utility struct used to harvest error information from openssl's error stack
|
// Utility struct used to harvest error information from openssl's error stack
|
||||||
struct CryptoErrorStore final : public MemoryRetainer {
|
struct CryptoErrorStore final : public MemoryRetainer {
|
||||||
public:
|
public:
|
||||||
@ -200,6 +194,9 @@ void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) {
|
|||||||
std::forward<Args>(args)...));
|
std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::MaybeLocal<v8::Value> cryptoErrorListToException(
|
||||||
|
Environment* env, const ncrypto::CryptoErrorList& errors);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* MallocOpenSSL(size_t count) {
|
T* MallocOpenSSL(size_t count) {
|
||||||
void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
|
void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
|
||||||
@ -552,72 +549,6 @@ void ThrowCryptoError(Environment* env,
|
|||||||
unsigned long err, // NOLINT(runtime/int)
|
unsigned long err, // NOLINT(runtime/int)
|
||||||
const char* message = nullptr);
|
const char* message = nullptr);
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
|
||||||
struct EnginePointer {
|
|
||||||
ENGINE* engine = nullptr;
|
|
||||||
bool finish_on_exit = false;
|
|
||||||
|
|
||||||
inline EnginePointer() = default;
|
|
||||||
|
|
||||||
inline explicit EnginePointer(ENGINE* engine_, bool finish_on_exit_ = false)
|
|
||||||
: engine(engine_),
|
|
||||||
finish_on_exit(finish_on_exit_) {}
|
|
||||||
|
|
||||||
inline EnginePointer(EnginePointer&& other) noexcept
|
|
||||||
: engine(other.engine),
|
|
||||||
finish_on_exit(other.finish_on_exit) {
|
|
||||||
other.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ~EnginePointer() { reset(); }
|
|
||||||
|
|
||||||
inline EnginePointer& operator=(EnginePointer&& other) noexcept {
|
|
||||||
if (this == &other) return *this;
|
|
||||||
this->~EnginePointer();
|
|
||||||
return *new (this) EnginePointer(std::move(other));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline operator bool() const { return engine != nullptr; }
|
|
||||||
|
|
||||||
inline ENGINE* get() { return engine; }
|
|
||||||
|
|
||||||
inline void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false) {
|
|
||||||
if (engine != nullptr) {
|
|
||||||
if (finish_on_exit) {
|
|
||||||
// This also does the equivalent of ENGINE_free.
|
|
||||||
CHECK_EQ(ENGINE_finish(engine), 1);
|
|
||||||
} else {
|
|
||||||
CHECK_EQ(ENGINE_free(engine), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
engine = engine_;
|
|
||||||
finish_on_exit = finish_on_exit_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ENGINE* release() {
|
|
||||||
ENGINE* ret = engine;
|
|
||||||
engine = nullptr;
|
|
||||||
finish_on_exit = false;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors);
|
|
||||||
|
|
||||||
bool SetEngine(
|
|
||||||
const char* id,
|
|
||||||
uint32_t flags,
|
|
||||||
CryptoErrorStore* errors = nullptr);
|
|
||||||
|
|
||||||
void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
||||||
#endif // !OPENSSL_NO_ENGINE
|
|
||||||
|
|
||||||
void GetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
||||||
|
|
||||||
void SetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
||||||
|
|
||||||
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
||||||
|
|
||||||
class CipherPushContext {
|
class CipherPushContext {
|
||||||
public:
|
public:
|
||||||
inline explicit CipherPushContext(Environment* env) : env_(env) {}
|
inline explicit CipherPushContext(Environment* env) : env_(env) {}
|
||||||
|
@ -25,12 +25,13 @@
|
|||||||
|
|
||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
|
#include "ncrypto.h"
|
||||||
#if NODE_OPENSSL_HAS_QUIC
|
#if NODE_OPENSSL_HAS_QUIC
|
||||||
#include <openssl/quic.h>
|
#include <openssl/quic.h>
|
||||||
#endif
|
#endif
|
||||||
#endif // HAVE_OPENSSL
|
#endif // HAVE_OPENSSL
|
||||||
|
|
||||||
#ifdef OPENSSL_INFO_QUIC
|
#ifdef NODE_OPENSSL_HAS_QUIC
|
||||||
#include <ngtcp2/version.h>
|
#include <ngtcp2/version.h>
|
||||||
#include <nghttp3/version.h>
|
#include <nghttp3/version.h>
|
||||||
#endif
|
#endif
|
||||||
@ -118,6 +119,7 @@ Metadata::Versions::Versions() {
|
|||||||
|
|
||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
openssl = GetOpenSSLVersion();
|
openssl = GetOpenSSLVersion();
|
||||||
|
ncrypto = NCRYPTO_VERSION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NODE_HAVE_I18N_SUPPORT
|
#ifdef NODE_HAVE_I18N_SUPPORT
|
||||||
@ -125,7 +127,7 @@ Metadata::Versions::Versions() {
|
|||||||
unicode = U_UNICODE_VERSION;
|
unicode = U_UNICODE_VERSION;
|
||||||
#endif // NODE_HAVE_I18N_SUPPORT
|
#endif // NODE_HAVE_I18N_SUPPORT
|
||||||
|
|
||||||
#ifdef OPENSSL_INFO_QUIC
|
#ifdef NODE_OPENSSL_HAS_QUIC
|
||||||
ngtcp2 = NGTCP2_VERSION;
|
ngtcp2 = NGTCP2_VERSION;
|
||||||
nghttp3 = NGHTTP3_VERSION;
|
nghttp3 = NGHTTP3_VERSION;
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,7 +55,7 @@ namespace node {
|
|||||||
V(cjs_module_lexer)
|
V(cjs_module_lexer)
|
||||||
|
|
||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
#define NODE_VERSIONS_KEY_CRYPTO(V) V(openssl)
|
#define NODE_VERSIONS_KEY_CRYPTO(V) V(openssl) V(ncrypto)
|
||||||
#else
|
#else
|
||||||
#define NODE_VERSIONS_KEY_CRYPTO(V)
|
#define NODE_VERSIONS_KEY_CRYPTO(V)
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// Flags: --expose-internals
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
@ -34,6 +34,7 @@ if (hasUndici) {
|
|||||||
|
|
||||||
if (common.hasCrypto) {
|
if (common.hasCrypto) {
|
||||||
expected_keys.push('openssl');
|
expected_keys.push('openssl');
|
||||||
|
expected_keys.push('ncrypto');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (common.hasQuic) {
|
if (common.hasQuic) {
|
||||||
@ -78,6 +79,7 @@ assert.match(process.versions.modules, /^\d+$/);
|
|||||||
assert.match(process.versions.cjs_module_lexer, commonTemplate);
|
assert.match(process.versions.cjs_module_lexer, commonTemplate);
|
||||||
|
|
||||||
if (common.hasCrypto) {
|
if (common.hasCrypto) {
|
||||||
|
assert.match(process.versions.ncrypto, commonTemplate);
|
||||||
if (process.config.variables.node_shared_openssl) {
|
if (process.config.variables.node_shared_openssl) {
|
||||||
assert.ok(process.versions.openssl);
|
assert.ok(process.versions.openssl);
|
||||||
} else {
|
} else {
|
||||||
|
@ -178,6 +178,7 @@ template("node_gn_build") {
|
|||||||
deps += [ "//third_party/icu" ]
|
deps += [ "//third_party/icu" ]
|
||||||
}
|
}
|
||||||
if (node_use_openssl) {
|
if (node_use_openssl) {
|
||||||
|
deps += [ "deps/ncrypto" ]
|
||||||
public_deps += [ "deps/openssl" ]
|
public_deps += [ "deps/openssl" ]
|
||||||
sources += gypi_values.node_crypto_sources
|
sources += gypi_values.node_crypto_sources
|
||||||
}
|
}
|
||||||
@ -339,6 +340,7 @@ template("node_gn_build") {
|
|||||||
|
|
||||||
sources = gypi_values.node_cctest_sources
|
sources = gypi_values.node_cctest_sources
|
||||||
if (node_use_openssl) {
|
if (node_use_openssl) {
|
||||||
|
deps += [ "deps/ncrypto" ]
|
||||||
sources += gypi_values.node_cctest_openssl_sources
|
sources += gypi_values.node_cctest_openssl_sources
|
||||||
}
|
}
|
||||||
if (node_enable_inspector) {
|
if (node_enable_inspector) {
|
||||||
|
Loading…
Reference in New Issue
Block a user