From 7371d335acfbf940066abcc3c8b7345bcfd1bb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sun, 4 Sep 2022 18:51:36 +0200 Subject: [PATCH] src: use V8 entropy source if RAND_bytes() != 1 RAND_bytes() may return 0 to indicate an error, in which case the buffer might not have been filled with random data at all. Instead of ignoring this case, let V8 use its own entropy source. Historically, this used to be a weak source of entropy, but V8 now implements a proper source even on Windows. And even if V8's own entropy source turns out to be weak, it does not matter much: V8's PRNG itself is not cryptographically secure, so even if it is seeded from a cryptographically secure entropy source, it does not produce cryptographically secure random numbers. PR-URL: https://github.com/nodejs/node/pull/44493 Reviewed-By: Rich Trott Reviewed-By: Ben Noordhuis Reviewed-By: Luigi Pinca Reviewed-By: Mohammed Keyvanzadeh --- src/crypto/crypto_util.cc | 14 ++++++++++---- src/crypto/crypto_util.h | 2 +- src/node.cc | 6 ++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc index 324dd11e301942..7255344276d73d 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc @@ -76,10 +76,16 @@ void CheckEntropy() { bool EntropySource(unsigned char* buffer, size_t length) { // Ensure that OpenSSL's PRNG is properly seeded. CheckEntropy(); - // RAND_bytes() can return 0 to indicate that the entropy data is not truly - // random. That's okay, it's still better than V8's stock source of entropy, - // which is /dev/urandom on UNIX platforms and the current time on Windows. - return RAND_bytes(buffer, length) != -1; + // If RAND_bytes() returns 0 or -1, the data might not be random at all. In + // that case, return false, which causes V8 to use its own entropy source. The + // quality of V8's entropy source depends on multiple factors and we should + // not assume that it is cryptographically secure (even though it often is). + // However, even if RAND_bytes() fails and V8 resorts to its potentially weak + // entropy source, it really does not matter much: V8 only uses the entropy + // source to seed its own PRNG, which itself is not cryptographically secure. + // In other words, even a cryptographically secure entropy source would not + // guarantee cryptographically secure random numbers in V8. + return RAND_bytes(buffer, length) == 1; } int PasswordCallback(char* buf, int size, int rwflag, void* u) { diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h index 4afae1884fe40e..f1fbd6c2471cbe 100644 --- a/src/crypto/crypto_util.h +++ b/src/crypto/crypto_util.h @@ -134,7 +134,7 @@ struct MarkPopErrorOnReturn { void CheckEntropy(); // Generate length bytes of random data. If this returns false, the data -// may not be truly random but it's still generally good enough. +// might not be random at all and should not be used. bool EntropySource(unsigned char* buffer, size_t length); int PasswordCallback(char* buf, int size, int rwflag, void* u); diff --git a/src/node.cc b/src/node.cc index c2bbfb737478aa..9f6a4a6a6abea1 100644 --- a/src/node.cc +++ b/src/node.cc @@ -980,8 +980,10 @@ std::unique_ptr InitializeOncePerProcess( return result; } - // V8 on Windows doesn't have a good source of entropy. Seed it from - // OpenSSL's pool. + // Seed V8's PRNG from OpenSSL's pool. This is recommended by V8 and a + // potentially better source of randomness than what V8 uses by default, but + // it does not guarantee that pseudo-random values produced by V8 will be + // cryptograhically secure. V8::SetEntropySource(crypto::EntropySource); #endif // HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL) }