Skip to content
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

src: start using ncrypto for CSPRNG calls #53984

Merged
merged 1 commit into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/crypto/crypto_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -547,9 +547,9 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
// OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was
// exposed in the public API. To retain compatibility, install a callback
// which restores the old algorithm.
if (CSPRNG(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)).is_err() ||
CSPRNG(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)).is_err() ||
CSPRNG(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)).is_err()) {
if (!ncrypto::CSPRNG(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) ||
!ncrypto::CSPRNG(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)) ||
!ncrypto::CSPRNG(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_))) {
return THROW_ERR_CRYPTO_OPERATION_FAILED(
env, "Error generating ticket keys");
}
Expand Down Expand Up @@ -1324,7 +1324,7 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,

if (enc) {
memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_));
if (CSPRNG(iv, 16).is_err() ||
if (!ncrypto::CSPRNG(iv, 16) ||
EVP_EncryptInit_ex(
ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_, iv) <= 0 ||
HMAC_Init_ex(hctx,
Expand Down
3 changes: 2 additions & 1 deletion src/crypto/crypto_keygen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "debug_utils-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "ncrypto.h"
#include "threadpoolwork-inl.h"
#include "v8.h"

Expand Down Expand Up @@ -71,7 +72,7 @@ Maybe<bool> SecretKeyGenTraits::AdditionalConfig(
KeyGenJobStatus SecretKeyGenTraits::DoKeyGen(Environment* env,
SecretKeyGenConfig* params) {
ByteSource::Builder bytes(params->length);
if (CSPRNG(bytes.data<unsigned char>(), params->length).is_err())
if (!ncrypto::CSPRNG(bytes.data<unsigned char>(), params->length))
return KeyGenJobStatus::FAILED;
params->out = std::move(bytes).release();
return KeyGenJobStatus::OK;
Expand Down
5 changes: 3 additions & 2 deletions src/crypto/crypto_random.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "crypto/crypto_util.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "ncrypto.h"
#include "threadpoolwork-inl.h"
#include "v8.h"

Expand Down Expand Up @@ -60,7 +61,7 @@ bool RandomBytesTraits::DeriveBits(
Environment* env,
const RandomBytesConfig& params,
ByteSource* unused) {
return CSPRNG(params.buffer, params.size).is_ok();
return ncrypto::CSPRNG(params.buffer, params.size);
}

void RandomPrimeConfig::MemoryInfo(MemoryTracker* tracker) const {
Expand Down Expand Up @@ -154,7 +155,7 @@ bool RandomPrimeTraits::DeriveBits(Environment* env,
ByteSource* unused) {
// BN_generate_prime_ex() calls RAND_bytes_ex() internally.
// Make sure the CSPRNG is properly seeded.
CHECK(CSPRNG(nullptr, 0).is_ok());
CHECK(ncrypto::CSPRNG(nullptr, 0));

if (BN_generate_prime_ex(
params.prime.get(),
Expand Down
34 changes: 0 additions & 34 deletions src/crypto/crypto_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,40 +49,6 @@ using v8::Value;

namespace crypto {

MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length) {
unsigned char* buf = static_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 PasswordCallback(char* buf, int size, int rwflag, void* u) {
const ByteSource* passphrase = *static_cast<const ByteSource**>(u);
if (passphrase != nullptr) {
Expand Down
13 changes: 0 additions & 13 deletions src/crypto/crypto_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,6 @@ void InitCrypto(v8::Local<v8::Object> target);

extern void UseExtraCaCerts(const std::string& file);

struct CSPRNGResult {
const bool ok;
MUST_USE_RESULT bool is_ok() const { return ok; }
MUST_USE_RESULT bool is_err() const { return !ok; }
};

// Either succeeds with exactly |length| bytes of cryptographically
// strong pseudo-random data, or fails. This function may block.
// Don't assume anything about the contents of |buffer| on error.
// As a special case, |length == 0| can be used to check if the CSPRNG
// is properly seeded without consuming entropy.
MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length);

int PasswordCallback(char* buf, int size, int rwflag, void* u);

int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
Expand Down
13 changes: 7 additions & 6 deletions src/inspector_io.cc
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
#include "inspector_io.h"

#include "inspector_socket_server.h"
#include "inspector/main_thread_interface.h"
#include "inspector/node_string.h"
#include "crypto/crypto_util.h"
#include "base_object-inl.h"
#include "crypto/crypto_util.h"
#include "debug_utils-inl.h"
#include "inspector/main_thread_interface.h"
#include "inspector/node_string.h"
#include "inspector_socket_server.h"
#include "ncrypto.h"
#include "node.h"
#include "node_internals.h"
#include "node_mutex.h"
#include "v8-inspector.h"
#include "util-inl.h"
#include "v8-inspector.h"
#include "zlib.h"

#include <deque>
Expand Down Expand Up @@ -46,7 +47,7 @@ std::string ScriptPath(uv_loop_t* loop, const std::string& script_name) {
// Used ver 4 - with numbers
std::string GenerateID() {
uint16_t buffer[8];
CHECK(crypto::CSPRNG(buffer, sizeof(buffer)).is_ok());
CHECK(ncrypto::CSPRNG(buffer, sizeof(buffer)));

char uuid[256];
snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
Expand Down
5 changes: 3 additions & 2 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "node_version.h"

#if HAVE_OPENSSL
#include "ncrypto.h"
#include "node_crypto.h"
#endif

Expand Down Expand Up @@ -1142,14 +1143,14 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
}

// Ensure CSPRNG is properly seeded.
CHECK(crypto::CSPRNG(nullptr, 0).is_ok());
CHECK(ncrypto::CSPRNG(nullptr, 0));

V8::SetEntropySource([](unsigned char* buffer, size_t length) {
// V8 falls back to very weak entropy when this function fails
// and /dev/urandom isn't available. That wouldn't be so bad if
// the entropy was only used for Math.random() but it's also used for
// hash table and address space layout randomization. Better to abort.
CHECK(crypto::CSPRNG(buffer, length).is_ok());
CHECK(ncrypto::CSPRNG(buffer, length));
return true;
});
#endif // !defined(OPENSSL_IS_BORINGSSL)
Expand Down
3 changes: 2 additions & 1 deletion src/quic/cid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <node_mutex.h>
#include <string_bytes.h>
#include "nbytes.h"
#include "ncrypto.h"
#include "quic/defs.h"

namespace node {
Expand Down Expand Up @@ -132,7 +133,7 @@ class RandomCIDFactory : public CID::Factory {
// a CID of the requested size, we regenerate the pool
// and reset it to zero.
if (pos_ + length_hint > kPoolSize) {
CHECK(crypto::CSPRNG(pool_, kPoolSize).is_ok());
CHECK(ncrypto::CSPRNG(pool_, kPoolSize));
pos_ = 0;
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/quic/endpoint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "application.h"
#include "bindingdata.h"
#include "defs.h"
#include "ncrypto.h"

namespace node {

Expand Down Expand Up @@ -87,7 +88,7 @@ namespace {
bool is_diagnostic_packet_loss(double probability) {
if (LIKELY(probability == 0.0)) return false;
unsigned char c = 255;
CHECK(crypto::CSPRNG(&c, 1).is_ok());
CHECK(ncrypto::CSPRNG(&c, 1));
return (static_cast<double>(c) / 255) < probability;
}
#endif // DEBUG
Expand Down
3 changes: 2 additions & 1 deletion src/quic/packet.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "bindingdata.h"
#include "cid.h"
#include "defs.h"
#include "ncrypto.h"
#include "tokens.h"

namespace node {
Expand Down Expand Up @@ -331,7 +332,7 @@ Packet* Packet::CreateStatelessResetPacket(

StatelessResetToken token(token_secret, path_descriptor.dcid);
uint8_t random[kRandlen];
CHECK(crypto::CSPRNG(random, kRandlen).is_ok());
CHECK(ncrypto::CSPRNG(random, kRandlen));

auto packet = Create(env,
listener,
Expand Down
3 changes: 2 additions & 1 deletion src/quic/session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "defs.h"
#include "endpoint.h"
#include "logstream.h"
#include "ncrypto.h"
#include "packet.h"
#include "preferredaddress.h"
#include "sessionticket.h"
Expand Down Expand Up @@ -2163,7 +2164,7 @@ struct Session::Impl {
static void on_rand(uint8_t* dest,
size_t destlen,
const ngtcp2_rand_ctx* rand_ctx) {
CHECK(crypto::CSPRNG(dest, destlen).is_ok());
CHECK(ncrypto::CSPRNG(dest, destlen));
}

static int on_early_data_rejected(ngtcp2_conn* conn, void* user_data) {
Expand Down
3 changes: 2 additions & 1 deletion src/quic/tokens.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <util-inl.h>
#include <algorithm>
#include "nbytes.h"
#include "ncrypto.h"

namespace node {
namespace quic {
Expand All @@ -22,7 +23,7 @@ TokenSecret::TokenSecret() : buf_() {
// If someone manages to get visibility into that cache then they would know
// the secrets for a larger number of tokens, which could be bad. For now,
// generating on each call is safer, even if less performant.
CHECK(crypto::CSPRNG(buf_, QUIC_TOKENSECRET_LEN).is_ok());
CHECK(ncrypto::CSPRNG(buf_, QUIC_TOKENSECRET_LEN));
}

TokenSecret::TokenSecret(const uint8_t* secret) : buf_() {
Expand Down
Loading