-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
deps: start working on ncrypto dep #53803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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") { | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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' | ||
] | ||
}], | ||
] | ||
}, | ||
] | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.