summaryrefslogtreecommitdiff
path: root/src/crypto/fipsmodule/rand/rand.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/fipsmodule/rand/rand.c')
-rw-r--r--src/crypto/fipsmodule/rand/rand.c100
1 files changed, 55 insertions, 45 deletions
diff --git a/src/crypto/fipsmodule/rand/rand.c b/src/crypto/fipsmodule/rand/rand.c
index 357be391..54397f9b 100644
--- a/src/crypto/fipsmodule/rand/rand.c
+++ b/src/crypto/fipsmodule/rand/rand.c
@@ -23,6 +23,7 @@
#endif
#include <openssl/chacha.h>
+#include <openssl/ctrdrbg.h>
#include <openssl/mem.h>
#include <openssl/type_check.h>
@@ -162,19 +163,13 @@ static int rdrand(uint8_t *buf, size_t len) {
#if defined(BORINGSSL_FIPS)
void CRYPTO_get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
- int *out_used_cpu) {
- *out_used_cpu = 0;
+ int *out_want_additional_input) {
+ *out_want_additional_input = 0;
if (have_rdrand() && rdrand(out_entropy, out_entropy_len)) {
- *out_used_cpu = 1;
+ *out_want_additional_input = 1;
} else {
CRYPTO_sysrand_for_seed(out_entropy, out_entropy_len);
}
-
- if (boringssl_fips_break_test("CRNG")) {
- // This breaks the "continuous random number generator test" defined in FIPS
- // 140-2, section 4.9.2, and implemented in |rand_get_seed|.
- OPENSSL_memset(out_entropy, 0, out_entropy_len);
- }
}
// In passive entropy mode, entropy is supplied from outside of the module via
@@ -183,20 +178,22 @@ void CRYPTO_get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
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;
- // from_cpu is true if any of the contents of |bytes| were obtained directly
- // from the CPU.
- int from_cpu;
+ // want_additional_input is true if any of the contents of |bytes| were
+ // obtained via a method other than from the kernel. In these cases entropy
+ // from the kernel is also provided via an additional input to the DRBG.
+ int want_additional_input;
};
DEFINE_BSS_GET(struct entropy_buffer, entropy_buffer);
DEFINE_STATIC_MUTEX(entropy_buffer_lock);
void RAND_load_entropy(const uint8_t *entropy, size_t entropy_len,
- int from_cpu) {
+ int want_additional_input) {
struct entropy_buffer *const buffer = entropy_buffer_bss_get();
CRYPTO_STATIC_MUTEX_lock_write(entropy_buffer_lock_bss_get());
@@ -207,14 +204,15 @@ void RAND_load_entropy(const uint8_t *entropy, size_t entropy_len,
OPENSSL_memcpy(&buffer->bytes[buffer->bytes_valid], entropy, entropy_len);
buffer->bytes_valid += entropy_len;
- buffer->from_cpu |= from_cpu && (entropy_len != 0);
+ buffer->want_additional_input |=
+ want_additional_input && (entropy_len != 0);
CRYPTO_STATIC_MUTEX_unlock_write(entropy_buffer_lock_bss_get());
}
// get_seed_entropy fills |out_entropy_len| bytes of |out_entropy| from the
// global |entropy_buffer|.
static void get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
- int *out_used_cpu) {
+ int *out_want_additional_input) {
struct entropy_buffer *const buffer = entropy_buffer_bss_get();
if (out_entropy_len > sizeof(buffer->bytes)) {
abort();
@@ -227,53 +225,64 @@ static void get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
CRYPTO_STATIC_MUTEX_lock_write(entropy_buffer_lock_bss_get());
}
- *out_used_cpu = buffer->from_cpu;
+ *out_want_additional_input = buffer->want_additional_input;
OPENSSL_memcpy(out_entropy, buffer->bytes, out_entropy_len);
OPENSSL_memmove(buffer->bytes, &buffer->bytes[out_entropy_len],
buffer->bytes_valid - out_entropy_len);
buffer->bytes_valid -= out_entropy_len;
if (buffer->bytes_valid == 0) {
- buffer->from_cpu = 0;
+ buffer->want_additional_input = 0;
}
CRYPTO_STATIC_MUTEX_unlock_write(entropy_buffer_lock_bss_get());
}
-// rand_get_seed fills |seed| with entropy and sets |*out_used_cpu| to one if
-// that entropy came directly from the CPU and zero otherwise.
+// rand_get_seed fills |seed| with entropy and sets
+// |*out_want_additional_input| to one if that entropy came directly from the
+// CPU and zero otherwise.
static void rand_get_seed(struct rand_thread_state *state,
uint8_t seed[CTR_DRBG_ENTROPY_LEN],
- int *out_used_cpu) {
- if (!state->last_block_valid) {
- int unused;
- get_seed_entropy(state->last_block, sizeof(state->last_block), &unused);
- state->last_block_valid = 1;
+ int *out_want_additional_input) {
+ 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_used_cpu);
+ 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++) {
@@ -285,15 +294,16 @@ static void rand_get_seed(struct rand_thread_state *state,
#else
-// rand_get_seed fills |seed| with entropy and sets |*out_used_cpu| to one if
-// that entropy came directly from the CPU and zero otherwise.
+// rand_get_seed fills |seed| with entropy and sets
+// |*out_want_additional_input| to one if that entropy came directly from the
+// CPU and zero otherwise.
static void rand_get_seed(struct rand_thread_state *state,
uint8_t seed[CTR_DRBG_ENTROPY_LEN],
- int *out_used_cpu) {
+ int *out_want_additional_input) {
// If not in FIPS mode, we don't overread from the system entropy source and
// we don't depend only on the hardware RDRAND.
CRYPTO_sysrand_for_seed(seed, CTR_DRBG_ENTROPY_LEN);
- *out_used_cpu = 0;
+ *out_want_additional_input = 0;
}
#endif
@@ -352,16 +362,16 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
state->last_block_valid = 0;
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
- int used_cpu;
- rand_get_seed(state, seed, &used_cpu);
+ int want_additional_input;
+ rand_get_seed(state, seed, &want_additional_input);
uint8_t personalization[CTR_DRBG_ENTROPY_LEN] = {0};
size_t personalization_len = 0;
#if defined(OPENSSL_URANDOM)
- // If we used RDRAND, also opportunistically read from the system. This
- // avoids solely relying on the hardware once the entropy pool has been
- // initialized.
- if (used_cpu &&
+ // If we used something other than system entropy then also
+ // opportunistically read from the system. This avoids solely relying on the
+ // hardware once the entropy pool has been initialized.
+ if (want_additional_input &&
CRYPTO_sysrand_if_available(personalization, sizeof(personalization))) {
personalization_len = sizeof(personalization);
}
@@ -392,8 +402,8 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
if (state->calls >= kReseedInterval ||
state->fork_generation != fork_generation) {
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
- int used_cpu;
- rand_get_seed(state, seed, &used_cpu);
+ int want_additional_input;
+ rand_get_seed(state, seed, &want_additional_input);
#if defined(BORINGSSL_FIPS)
// Take a read lock around accesses to |state->drbg|. This is needed to
// avoid returning bad entropy if we race with