Enable optional GRND_RANDOM flag to be passed to getrandom on Android.

Introduces optional extra flags for getrandom which are ORed in when
reading a FIPS seed.  Setting the Android read-only system property
ro.boringcrypto.hwrand to true will set the extra flags to GRND_RANDOM.

Testing: Built and tested on AOSP as http://r.android.com/1134926
and verified behaviour via the extra printfs in that CL and also
observing the flags passed to getrandom using strace.

Change-Id: Idd782df65ba0d49b8b1357b346caa4ef747587f1
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/38024
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/rand/internal.h b/crypto/fipsmodule/rand/internal.h
index c7ed74d..07563b7 100644
--- a/crypto/fipsmodule/rand/internal.h
+++ b/crypto/fipsmodule/rand/internal.h
@@ -41,6 +41,11 @@
 void CRYPTO_sysrand(uint8_t *buf, size_t len);
 
 #if defined(OPENSSL_URANDOM) && defined(BORINGSSL_FIPS)
+// CRYPTO_sysrand_for_seed fills |len| bytes at |buf| with entropy from the
+// operating system. It may draw from the |GRND_RANDOM| pool on Android,
+// depending on the vendor's configuration.
+void CRYPTO_sysrand_for_seed(uint8_t *buf, size_t len);
+
 // CRYPTO_sysrand_if_available fills |len| bytes at |buf| with entropy from the
 // operating system, if the entropy pool is initialized. If it is uninitialized,
 // it will not block and will instead fill |buf| with all zeros or early
diff --git a/crypto/fipsmodule/rand/rand.c b/crypto/fipsmodule/rand/rand.c
index 60e92c5..87d7b30 100644
--- a/crypto/fipsmodule/rand/rand.c
+++ b/crypto/fipsmodule/rand/rand.c
@@ -32,9 +32,9 @@
 
 
 // It's assumed that the operating system always has an unfailing source of
-// entropy which is accessed via |CRYPTO_sysrand|. (If the operating system
-// entropy source fails, it's up to |CRYPTO_sysrand| to abort the process—we
-// don't try to handle it.)
+// entropy which is accessed via |CRYPTO_sysrand[_for_seed]|. (If the operating
+// system entropy source fails, it's up to |CRYPTO_sysrand| to abort the
+// process—we don't try to handle it.)
 //
 // In addition, the hardware may provide a low-latency RNG. Intel's rdrand
 // instruction is the canonical example of this. When a hardware RNG is
@@ -61,11 +61,11 @@
   // (re)seeded. This is bound by |kReseedInterval|.
   unsigned calls;
   // last_block_valid is non-zero iff |last_block| contains data from
-  // |CRYPTO_sysrand|.
+  // |CRYPTO_sysrand_for_seed|.
   int last_block_valid;
 
 #if defined(BORINGSSL_FIPS)
-  // last_block contains the previous block from |CRYPTO_sysrand|.
+  // last_block contains the previous block from |CRYPTO_sysrand_for_seed|.
   uint8_t last_block[CRNGT_BLOCK_SIZE];
   // next and prev form a NULL-terminated, double-linked list of all states in
   // a process.
@@ -169,7 +169,7 @@
                           uint8_t seed[CTR_DRBG_ENTROPY_LEN]) {
   if (!state->last_block_valid) {
     if (!hwrand(state->last_block, sizeof(state->last_block))) {
-      CRYPTO_sysrand(state->last_block, sizeof(state->last_block));
+      CRYPTO_sysrand_for_seed(state->last_block, sizeof(state->last_block));
     }
     state->last_block_valid = 1;
   }
@@ -181,7 +181,7 @@
 
   int used_hwrand = hwrand(entropy, sizeof(entropy));
   if (!used_hwrand) {
-    CRYPTO_sysrand(entropy, sizeof(entropy));
+    CRYPTO_sysrand_for_seed(entropy, sizeof(entropy));
   }
 
   // See FIPS 140-2, section 4.9.2. This is the “continuous random number
diff --git a/crypto/fipsmodule/rand/urandom.c b/crypto/fipsmodule/rand/urandom.c
index 9fa0c97..33c0b03 100644
--- a/crypto/fipsmodule/rand/urandom.c
+++ b/crypto/fipsmodule/rand/urandom.c
@@ -36,6 +36,10 @@
 #endif
 #include <sys/syscall.h>
 
+#if defined(OPENSSL_ANDROID)
+#include <sys/system_properties.h>
+#endif
+
 #if !defined(OPENSSL_ANDROID)
 #define OPENSSL_HAS_GETAUXVAL
 #endif
@@ -120,6 +124,9 @@
 #if !defined(GRND_NONBLOCK)
 #define GRND_NONBLOCK 1
 #endif
+#if !defined(GRND_RANDOM)
+#define GRND_RANDOM 2
+#endif
 
 #endif  // OPENSSL_LINUX
 
@@ -138,10 +145,36 @@
 DEFINE_BSS_GET(int, urandom_fd)
 
 #if defined(USE_NR_getrandom)
+
 // getrandom_ready is one if |getrandom| had been initialized by the time
 // |init_once| was called and zero otherwise.
 DEFINE_BSS_GET(int, getrandom_ready)
+
+// extra_getrandom_flags_for_seed contains a value that is ORed into the flags
+// for getrandom() when reading entropy for a seed.
+DEFINE_BSS_GET(int, extra_getrandom_flags_for_seed)
+
+// On Android, check a system property to decide whether to set
+// |extra_getrandom_flags_for_seed| otherwise they will default to zero.  If
+// ro.oem_boringcrypto_hwrand is true then |extra_getrandom_flags_for_seed| will
+// be set to GRND_RANDOM, causing all random data to be drawn from the same
+// source as /dev/random.
+static void maybe_set_extra_getrandom_flags(void) {
+#if defined(BORINGSSL_FIPS) && defined(OPENSSL_ANDROID)
+  char value[PROP_VALUE_MAX + 1];
+  int length = __system_property_get("ro.boringcrypto.hwrand", value);
+  if (length < 0 || length > PROP_VALUE_MAX) {
+    return;
+  }
+
+  value[length] = 0;
+  if (strcasecmp(value, "true") == 0) {
+    *extra_getrandom_flags_for_seed_bss_get() = GRND_RANDOM;
+  }
 #endif
+}
+
+#endif  // USE_NR_getrandom
 
 DEFINE_STATIC_ONCE(rand_once)
 
@@ -176,6 +209,7 @@
 
   if (have_getrandom) {
     *urandom_fd_bss_get() = kHaveGetrandom;
+    maybe_set_extra_getrandom_flags();
     return;
   }
 #endif  // USE_NR_getrandom
@@ -346,11 +380,23 @@
 // on success and zero on error. If |block| is one, this function will block
 // until the entropy pool is initialized. Otherwise, this function may fail,
 // setting |errno| to |EAGAIN| if the entropy pool has not yet been initialized.
-static int fill_with_entropy(uint8_t *out, size_t len, int block) {
+// If |seed| is one, this function will OR in the value of
+// |*extra_getrandom_flags_for_seed()| when using |getrandom|.
+static int fill_with_entropy(uint8_t *out, size_t len, int block, int seed) {
   if (len == 0) {
     return 1;
   }
 
+#if defined(USE_NR_getrandom)
+  int getrandom_flags = 0;
+  if (block) {
+    getrandom_flags |= GRND_NONBLOCK;
+  }
+  if (seed) {
+    getrandom_flags |= *extra_getrandom_flags_for_seed_bss_get();
+  }
+#endif
+
   CRYPTO_once(rand_once_bss_get(), init_once);
   if (block) {
     CRYPTO_once(wait_for_entropy_once_bss_get(), wait_for_entropy);
@@ -364,7 +410,7 @@
 
     if (*urandom_fd_bss_get() == kHaveGetrandom) {
 #if defined(USE_NR_getrandom)
-      r = boringssl_getrandom(out, len, block ? 0 : GRND_NONBLOCK);
+      r = boringssl_getrandom(out, len, getrandom_flags);
 #elif defined(OPENSSL_MACOS)
       if (__builtin_available(macos 10.12, *)) {
         // |getentropy| can only request 256 bytes at a time.
@@ -400,7 +446,15 @@
 
 // CRYPTO_sysrand puts |requested| random bytes into |out|.
 void CRYPTO_sysrand(uint8_t *out, size_t requested) {
-  if (!fill_with_entropy(out, requested, /*block=*/1)) {
+  if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/0)) {
+    perror("entropy fill failed");
+    abort();
+  }
+}
+
+#if defined(BORINGSSL_FIPS)
+void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {
+  if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/1)) {
     perror("entropy fill failed");
     abort();
   }
@@ -412,12 +466,11 @@
 #endif
 }
 
-#if defined(BORINGSSL_FIPS)
 void CRYPTO_sysrand_if_available(uint8_t *out, size_t requested) {
   // Return all zeros if |fill_with_entropy| fails.
   OPENSSL_memset(out, 0, requested);
 
-  if (!fill_with_entropy(out, requested, /*block=*/0) &&
+  if (!fill_with_entropy(out, requested, /*block=*/0, /*seed=*/0) &&
       errno != EAGAIN) {
     perror("opportunistic entropy fill failed");
     abort();