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();