Merge entropy read in FIPS mode.

When seeding a DRBG for the first time we currently make two reads: one
to start the CRNGT and a second to read the actual seed. These reads can
be merged to save I/O.

Change-Id: I2a83edf7f3c8b9d6cebcde02195845be9fde19b2
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52526
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/rand/rand.c b/crypto/fipsmodule/rand/rand.c
index 7d6daed..f78e66a 100644
--- a/crypto/fipsmodule/rand/rand.c
+++ b/crypto/fipsmodule/rand/rand.c
@@ -184,7 +184,8 @@
 
 struct entropy_buffer {
   // bytes contains entropy suitable for seeding a DRBG.
-  uint8_t bytes[CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
+  uint8_t
+      bytes[CRNGT_BLOCK_SIZE + CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
   // bytes_valid indicates the number of bytes of |bytes| that contain valid
   // data.
   size_t bytes_valid;
@@ -248,36 +249,46 @@
 static void rand_get_seed(struct rand_thread_state *state,
                           uint8_t seed[CTR_DRBG_ENTROPY_LEN],
                           int *out_want_additional_input) {
-  if (!state->last_block_valid) {
-    int unused;
-    get_seed_entropy(state->last_block, sizeof(state->last_block), &unused);
-    state->last_block_valid = 1;
+  uint8_t entropy_bytes[sizeof(state->last_block) +
+                        CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
+  uint8_t *entropy = entropy_bytes;
+  size_t entropy_len = sizeof(entropy_bytes);
+
+  if (state->last_block_valid) {
+    // No need to fill |state->last_block| with entropy from the read.
+    entropy += sizeof(state->last_block);
+    entropy_len -= sizeof(state->last_block);
   }
 
-  uint8_t entropy[CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
-  get_seed_entropy(entropy, sizeof(entropy), out_want_additional_input);
+  get_seed_entropy(entropy, entropy_len, out_want_additional_input);
+
+  if (!state->last_block_valid) {
+    OPENSSL_memcpy(state->last_block, entropy, sizeof(state->last_block));
+    entropy += sizeof(state->last_block);
+    entropy_len -= sizeof(state->last_block);
+  }
 
   // See FIPS 140-2, section 4.9.2. This is the “continuous random number
   // generator test” which causes the program to randomly abort. Hopefully the
   // rate of failure is small enough not to be a problem in practice.
-  if (CRYPTO_memcmp(state->last_block, entropy, CRNGT_BLOCK_SIZE) == 0) {
+  if (CRYPTO_memcmp(state->last_block, entropy, sizeof(state->last_block)) ==
+      0) {
     fprintf(stderr, "CRNGT failed.\n");
     BORINGSSL_FIPS_abort();
   }
 
-  OPENSSL_STATIC_ASSERT(sizeof(entropy) % CRNGT_BLOCK_SIZE == 0, "");
-  for (size_t i = CRNGT_BLOCK_SIZE; i < sizeof(entropy);
-       i += CRNGT_BLOCK_SIZE) {
+  assert(entropy_len % CRNGT_BLOCK_SIZE == 0);
+  for (size_t i = CRNGT_BLOCK_SIZE; i < entropy_len; i += CRNGT_BLOCK_SIZE) {
     if (CRYPTO_memcmp(entropy + i - CRNGT_BLOCK_SIZE, entropy + i,
                       CRNGT_BLOCK_SIZE) == 0) {
       fprintf(stderr, "CRNGT failed.\n");
       BORINGSSL_FIPS_abort();
     }
   }
-  OPENSSL_memcpy(state->last_block,
-                 entropy + sizeof(entropy) - CRNGT_BLOCK_SIZE,
+  OPENSSL_memcpy(state->last_block, entropy + entropy_len - CRNGT_BLOCK_SIZE,
                  CRNGT_BLOCK_SIZE);
 
+  assert(entropy_len == BORINGSSL_FIPS_OVERREAD * CTR_DRBG_ENTROPY_LEN);
   OPENSSL_memcpy(seed, entropy, CTR_DRBG_ENTROPY_LEN);
 
   for (size_t i = 1; i < BORINGSSL_FIPS_OVERREAD; i++) {
diff --git a/crypto/fipsmodule/rand/urandom_test.cc b/crypto/fipsmodule/rand/urandom_test.cc
index 2c89912..dabaf39 100644
--- a/crypto/fipsmodule/rand/urandom_test.cc
+++ b/crypto/fipsmodule/rand/urandom_test.cc
@@ -420,8 +420,7 @@
   if (!have_rdrand()) {
     if ((!have_fork_detection() && !sysrand(true, kAdditionalDataLength)) ||
         // Initialise CRNGT.
-        (is_fips && !sysrand(true, 16)) ||
-        !sysrand(true, kSeedLength) ||
+        !sysrand(true, kSeedLength + (is_fips ? 16 : 0)) ||
         // Second entropy draw.
         (!have_fork_detection() && !sysrand(true, kAdditionalDataLength))) {
       return ret;
diff --git a/crypto/rand_extra/passive.c b/crypto/rand_extra/passive.c
index da7359b..f27803b 100644
--- a/crypto/rand_extra/passive.c
+++ b/crypto/rand_extra/passive.c
@@ -21,7 +21,8 @@
 // RAND_need_entropy is called by the FIPS module when it has blocked because of
 // a lack of entropy. This signal is used as an indication to feed it more.
 void RAND_need_entropy(size_t bytes_needed) {
-  uint8_t buf[CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
+  uint8_t buf[/* last_block size */ 16 +
+              CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
   size_t todo = sizeof(buf);
   if (todo > bytes_needed) {
     todo = bytes_needed;