Skip to content

Commit

Permalink
src: ensure that openssl's PRNG is fully seeded
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bnoordhuis authored and indutny committed Mar 26, 2014
1 parent 70f198d commit f68a116
Showing 1 changed file with 37 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,41 @@ Handle<Value> 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.
Expand Down Expand Up @@ -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<unsigned char*>(req->data_),
req->size_);
Expand Down

0 comments on commit f68a116

Please sign in to comment.