From f68a116c3c061151ab120f10fdc9230192d6b157 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 25 Mar 2014 23:35:28 +0100 Subject: [PATCH] src: ensure that openssl's PRNG is fully seeded Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG. The entropy pool starts out empty and needs to fill up before the PRNG can be used securely. OpenSSL normally fills the pool automatically but not when someone starts generating random numbers before the pool is full: in that case OpenSSL keeps lowering the entropy estimate to thwart attackers trying to guess the initial state of the PRNG. When that happens, we wait until enough entropy is available, something that normally should never take longer than a few milliseconds. Fixes #7338. --- src/node_crypto.cc | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 702a1d1..bd0b953 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -157,7 +157,41 @@ Handle ThrowCryptoTypeError(unsigned long err) { } +// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG. +// The entropy pool starts out empty and needs to fill up before the PRNG +// can be used securely. Once the pool is filled, it never dries up again; +// its contents is stirred and reused when necessary. +// +// OpenSSL normally fills the pool automatically but not when someone starts +// generating random numbers before the pool is full: in that case OpenSSL +// keeps lowering the entropy estimate to thwart attackers trying to guess +// the initial state of the PRNG. +// +// When that happens, we will have to wait until enough entropy is available. +// That should normally never take longer than a few milliseconds. +// +// OpenSSL draws from /dev/random and /dev/urandom. While /dev/random may +// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't +// block under normal circumstances. +// +// The only time when /dev/urandom may conceivably block is right after boot, +// when the whole system is still low on entropy. That's not something we can +// do anything about. +inline void CheckEntropy() { + for (;;) { + int status = RAND_status(); + assert(status >= 0); // Cannot fail. + if (status != 0) + break; + if (RAND_poll() == 0) // Give up, RAND_poll() not supported. + break; + } +} + + 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. @@ -3994,6 +4028,9 @@ void RandomBytesWork(uv_work_t* work_req) { work_req_); int r; + // Ensure that OpenSSL's PRNG is properly seeded. + CheckEntropy(); + if (pseudoRandom == true) { r = RAND_pseudo_bytes(reinterpret_cast(req->data_), req->size_); -- 2.7.4