Skip to content

Commit

Permalink
src: start using ncrypto for CSPRNG calls
Browse files Browse the repository at this point in the history
PR-URL: #53984
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
  • Loading branch information
jasnell authored Jul 23, 2024
1 parent cf2bce6 commit c112b4b
Show file tree
Hide file tree
Showing 12 changed files with 29 additions and 67 deletions.
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

0 comments on commit c112b4b

Please sign in to comment.