Skip to content

Commit f68a116

Browse files
bnoordhuisindutny
authored andcommitted
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.
1 parent 70f198d commit f68a116

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

src/node_crypto.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,41 @@ Handle<Value> ThrowCryptoTypeError(unsigned long err) {
157157
}
158158

159159

160+
// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG.
161+
// The entropy pool starts out empty and needs to fill up before the PRNG
162+
// can be used securely. Once the pool is filled, it never dries up again;
163+
// its contents is stirred and reused when necessary.
164+
//
165+
// OpenSSL normally fills the pool automatically but not when someone starts
166+
// generating random numbers before the pool is full: in that case OpenSSL
167+
// keeps lowering the entropy estimate to thwart attackers trying to guess
168+
// the initial state of the PRNG.
169+
//
170+
// When that happens, we will have to wait until enough entropy is available.
171+
// That should normally never take longer than a few milliseconds.
172+
//
173+
// OpenSSL draws from /dev/random and /dev/urandom. While /dev/random may
174+
// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't
175+
// block under normal circumstances.
176+
//
177+
// The only time when /dev/urandom may conceivably block is right after boot,
178+
// when the whole system is still low on entropy. That's not something we can
179+
// do anything about.
180+
inline void CheckEntropy() {
181+
for (;;) {
182+
int status = RAND_status();
183+
assert(status >= 0); // Cannot fail.
184+
if (status != 0)
185+
break;
186+
if (RAND_poll() == 0) // Give up, RAND_poll() not supported.
187+
break;
188+
}
189+
}
190+
191+
160192
bool EntropySource(unsigned char* buffer, size_t length) {
193+
// Ensure that OpenSSL's PRNG is properly seeded.
194+
CheckEntropy();
161195
// RAND_bytes() can return 0 to indicate that the entropy data is not truly
162196
// random. That's okay, it's still better than V8's stock source of entropy,
163197
// which is /dev/urandom on UNIX platforms and the current time on Windows.
@@ -3994,6 +4028,9 @@ void RandomBytesWork(uv_work_t* work_req) {
39944028
work_req_);
39954029
int r;
39964030

4031+
// Ensure that OpenSSL's PRNG is properly seeded.
4032+
CheckEntropy();
4033+
39974034
if (pseudoRandom == true) {
39984035
r = RAND_pseudo_bytes(reinterpret_cast<unsigned char*>(req->data_),
39994036
req->size_);

0 commit comments

Comments
 (0)