diff options
Diffstat (limited to 'board/cr50/dcrypto/fips_rand.c')
-rw-r--r-- | board/cr50/dcrypto/fips_rand.c | 96 |
1 files changed, 52 insertions, 44 deletions
diff --git a/board/cr50/dcrypto/fips_rand.c b/board/cr50/dcrypto/fips_rand.c index e9a7fe7ac7..f50d6300fc 100644 --- a/board/cr50/dcrypto/fips_rand.c +++ b/board/cr50/dcrypto/fips_rand.c @@ -50,6 +50,12 @@ static struct { } rand_state; /** + * We use FIPS_UNINITIALIZED as default (zero) value to accumulate + * errors, so check it is really zero. + */ +BUILD_ASSERT(FIPS_UNINITIALIZED == 0); + +/** * NIST SP 800-90B 4.4.1 * The repetition count test detects abnormal runs of 0s or 1s. * RCT_CUTOFF_BITS must be >= 32. @@ -60,7 +66,7 @@ static struct { * readings, packed into 32-bit words. * @return false if test failed */ -static bool repetition_count_test(uint32_t rnd) +static enum fips_status repetition_count_test(uint32_t rnd) { uint32_t clz, ctz, clo, cto; @@ -77,7 +83,7 @@ static bool repetition_count_test(uint32_t rnd) */ if ((ctz + rand_state.last_clz >= RCT_CUTOFF_SAMPLES) || (cto + rand_state.last_clo >= RCT_CUTOFF_SAMPLES)) - return false; + return FIPS_FATAL_TRNG_RCT; /** * merge series of repetitive values - update running counters in @@ -96,7 +102,7 @@ static bool repetition_count_test(uint32_t rnd) /* check we collected enough bits for statistics */ if (rand_state.rct_count < RCT_CUTOFF_WORDS) ++rand_state.rct_count; - return true; + return FIPS_UNINITIALIZED; } static int misbalanced(uint32_t count) @@ -122,7 +128,7 @@ static int popcount(uint32_t x) * Instead of storing actual samples we can store pop counts * of each 32bit reading, which would fit in 8-bit. */ -bool adaptive_proportion_test(uint32_t rnd) +static enum fips_status adaptive_proportion_test(uint32_t rnd) { /* update rolling count */ rand_state.count -= rand_state.pops[rand_state.oldest]; @@ -142,8 +148,8 @@ bool adaptive_proportion_test(uint32_t rnd) } /* check when initialized */ if (rand_state.apt_initialized && misbalanced(rand_state.count)) - return false; - return true; + return FIPS_FATAL_TRNG_APT; + return FIPS_UNINITIALIZED; } static bool fips_powerup_passed(void) @@ -152,42 +158,45 @@ static bool fips_powerup_passed(void) rand_state.apt_initialized; } - /** - * get random from TRNG and run continuous health tests. + * Get random from TRNG and run continuous health tests. * it is also can simulate stuck-bit error - * @param power_up if non-zero indicates warm-up mode + * @param power_up if true indicates warm-up mode * @return random value from TRNG */ -static uint64_t fips_trng32(int power_up) +static uint64_t fips_trng32(void) { uint64_t r; + uint32_t remaining_tries = 4; + enum fips_status error = FIPS_UNINITIALIZED; - /* Continuous health tests should have been initialized by now */ - if (!(power_up || fips_crypto_allowed())) - return 0; - - /* get noise */ - r = read_rand(); + do { + r = read_rand(); - if (rand_valid(r)) { - if (!repetition_count_test((uint32_t)r)) { - fips_set_status(FIPS_FATAL_TRNG_RCT); - r = (uint32_t)r; - } - if (!adaptive_proportion_test((uint32_t)r)) { - fips_set_status(FIPS_FATAL_TRNG_APT); - r = (uint32_t)r; + /* We can't read from TRNG. read_rand() made several tries. */ + if (!rand_valid(r)) { + fips_set_status(FIPS_FATAL_TRNG_OTHER); + break; } - } else - fips_set_status(FIPS_FATAL_TRNG_OTHER); - + error = repetition_count_test((uint32_t)r); + error |= adaptive_proportion_test((uint32_t)r); + remaining_tries--; + /* Repeat several times if statistical tests doesn't pass. */ + } while (remaining_tries && error != FIPS_UNINITIALIZED); + + if (error != FIPS_UNINITIALIZED) { + fips_set_status(error); + r = (uint32_t)r; /* Set result as invalid. */ + } return r; } uint64_t fips_trng_rand32(void) { - return fips_trng32(0); + if (!fips_crypto_allowed()) + return 0; + + return fips_trng32(); } bool fips_trng_bytes(void *buffer, size_t len) @@ -196,6 +205,9 @@ bool fips_trng_bytes(void *buffer, size_t len) size_t random_togo = 0; uint64_t rand; uint32_t r; + + if (!fips_crypto_allowed()) + return false; /** * Retrieve random numbers in 4 byte quantities and pack as many bytes * as needed into 'buffer'. If len is not divisible by 4, the @@ -203,7 +215,7 @@ bool fips_trng_bytes(void *buffer, size_t len) */ while (len--) { if (!random_togo) { - rand = fips_trng32(0); + rand = fips_trng32(); if (!rand_valid(rand)) return false; r = (uint32_t)rand; @@ -230,7 +242,7 @@ bool fips_trng_startup(int stage) /* Startup tests per NIST SP800-90B, Section 4 */ /* 4096 1-bit samples, in 2 steps, 2048 bit in each */ for (uint32_t i = 0; i < (TRNG_INIT_WORDS) / 2; i++) { - uint64_t r = fips_trng32(1); + uint64_t r = fips_trng32(); if (!rand_valid(r)) return false; @@ -258,7 +270,7 @@ bool fips_drbg_init(void) * this is roughly equal to 435 bits of full entropy. * Add 32 * 0.85 = 27 bits from nonce. */ - nonce = fips_trng32(0); + nonce = fips_trng32(); if (!rand_valid(nonce)) return false; random = (uint32_t)nonce; @@ -271,7 +283,7 @@ bool fips_drbg_init(void) &random, sizeof(random), NULL, 0); - set_fast_random_seed((uint32_t)fips_trng32(0)); + set_fast_random_seed((uint32_t)fips_trng32()); rand_state.drbg_initialized = true; return true; } @@ -387,7 +399,11 @@ static int cmd_rand_perf(int argc, char **argv) starttime = get_time().val; for (k = 0; k < 10; k++) { for (j = 0; j < 100; j++) - fips_rand_bytes(buf, sizeof(buf)); + if (!fips_rand_bytes(buf, sizeof(buf))) { + ccprintf("DRBG test failed\n"); + return EC_ERROR_HW_INTERNAL; + } + ; watchdog_reload(); cflush(); } @@ -398,18 +414,10 @@ static int cmd_rand_perf(int argc, char **argv) starttime = get_time().val; for (k = 0; k < 10; k++) { for (j = 0; j < 100; j++) - rand_bytes(&buf, sizeof(buf)); - watchdog_reload(); - } - starttime = get_time().val - starttime; - ccprintf("time for 1000 rand_byte() = %llu\n", starttime); - cflush(); - - starttime = get_time().val; - for (k = 0; k < 10; k++) { - for (j = 0; j < 100; j++) - if (!fips_trng_bytes(&buf, sizeof(buf))) + if (!fips_trng_bytes(&buf, sizeof(buf))) { ccprintf("FIPS TRNG error\n"); + return EC_ERROR_HW_INTERNAL; + } watchdog_reload(); } starttime = get_time().val - starttime; |