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>
This commit is contained in:
committed by
Adam Langley
parent
8fe1584023
commit
56b6c714c9
@@ -41,6 +41,11 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
|
||||
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
|
||||
|
||||
@@ -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 @@ struct rand_thread_state {
|
||||
// (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 @@ static void rand_get_seed(struct rand_thread_state *state,
|
||||
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 @@ static void rand_get_seed(struct rand_thread_state *state,
|
||||
|
||||
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
|
||||
|
||||
@@ -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 @@ static ssize_t boringssl_getrandom(void *buf, size_t buf_len, unsigned flags) {
|
||||
#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_requested)
|
||||
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 @@ static void init_once(void) {
|
||||
|
||||
if (have_getrandom) {
|
||||
*urandom_fd_bss_get() = kHaveGetrandom;
|
||||
maybe_set_extra_getrandom_flags();
|
||||
return;
|
||||
}
|
||||
#endif // USE_NR_getrandom
|
||||
@@ -346,11 +380,23 @@ void RAND_set_urandom_fd(int fd) {
|
||||
// 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 @@ static int fill_with_entropy(uint8_t *out, size_t len, int block) {
|
||||
|
||||
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 @@ static int fill_with_entropy(uint8_t *out, size_t len, int block) {
|
||||
|
||||
// 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 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
|
||||
#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();
|
||||
|
||||
Reference in New Issue
Block a user