summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/board.c4
-rw-r--r--board/cr50/dcrypto/trng.c46
-rw-r--r--board/cr50/fips_rand.c103
-rw-r--r--board/cr50/fips_rand.h25
4 files changed, 90 insertions, 88 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index dfa05b8ef9..96f90f6cee 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -13,6 +13,7 @@
#include "ec_version.h"
#include "endian.h"
#include "extension.h"
+#include "fips_rand.h"
#include "flash.h"
#include "flash_config.h"
#include "gpio.h"
@@ -34,7 +35,6 @@
#include "system_chip.h"
#include "task.h"
#include "tpm_registers.h"
-#include "trng.h"
#include "uart_bitbang.h"
#include "uartn.h"
#include "usart.h"
@@ -850,7 +850,7 @@ static void board_init(void)
configure_board_specific_gpios();
init_pmu();
reset_wake_logic();
- init_trng();
+ fips_init_trng();
maybe_trigger_ite_sync();
init_jittery_clock(1);
diff --git a/board/cr50/dcrypto/trng.c b/board/cr50/dcrypto/trng.c
index 94363b29c4..6045243615 100644
--- a/board/cr50/dcrypto/trng.c
+++ b/board/cr50/dcrypto/trng.c
@@ -4,10 +4,11 @@
*/
#include "common.h"
+#include "fips.h"
+#include "fips_rand.h"
#include "flash_log.h"
#include "init_chip.h"
#include "registers.h"
-#include "trng.h"
#include "watchdog.h"
#include "console.h"
@@ -39,7 +40,12 @@
*/
#define TRNG_EMPTY_COUNT 0x7ff
-void init_trng(void)
+/**
+ * Number of attempts to reset TRNG after stall is detected.
+ */
+#define TRNG_RESET_COUNT 8
+
+void fips_init_trng(void)
{
#if (!(defined(CONFIG_CUSTOMIZED_RO) && defined(SECTION_IS_RO)))
/*
@@ -101,25 +107,49 @@ void init_trng(void)
GWRITE(TRNG, GO_EVENT, 1);
}
-uint32_t rand(void)
-{ uint32_t empty_count = 0;
+uint64_t read_rand(void)
+{
+ uint32_t empty_count = 0;
+ uint32_t reset_count = 0;
+
+#ifdef CRYPTO_TEST_SETUP
+ /* Do we need to simulate error? */
+ if (fips_break_cmd == FIPS_BREAK_TRNG)
+ return (uint64_t)1UL << 32; /* Valid result, but value = 0. */
+#endif
- while (GREAD(TRNG, EMPTY)) {
+ /**
+ * Make sure we never hang in the loop - try at max TRNG_RESET_COUNT
+ * reset attempts, then return error
+ */
+ while (GREAD(TRNG, EMPTY) && (reset_count < TRNG_RESET_COUNT)) {
if (GREAD_FIELD(TRNG, FSM_STATE, FSM_IDLE) ||
empty_count > TRNG_EMPTY_COUNT) {
/* TRNG timed out, restart */
GWRITE(TRNG, STOP_WORK, 1);
-#if !defined(SECTION_IS_RO) && defined(CONFIG_FLASH_LOG)
flash_log_add_event(FE_LOG_TRNG_STALL, 0, NULL);
-#endif
GWRITE(TRNG, GO_EVENT, 1);
empty_count = 0;
+ reset_count++;
}
empty_count++;
}
- return GREAD(TRNG, READ_DATA);
+ /**
+ * High 32-bits set to zero in case of error;
+ * otherwise value >> 32 == 1
+ */
+ return (uint64_t)GREAD(TRNG, READ_DATA) |
+ ((uint64_t)(reset_count < TRNG_RESET_COUNT) << 32);
+}
+
+/* TODO(sukhomlinov): replace uses with fips_trng32(). */
+uint32_t rand(void)
+{
+ /* Just ignore validity status. */
+ return (uint32_t)read_rand();
}
+/* TODO(sukhomlinov): replace uses with fips_rand_bytes(). */
void rand_bytes(void *buffer, size_t len)
{
int random_togo = 0;
diff --git a/board/cr50/fips_rand.c b/board/cr50/fips_rand.c
index 85ffa9ef6c..e5488bcf29 100644
--- a/board/cr50/fips_rand.c
+++ b/board/cr50/fips_rand.c
@@ -11,7 +11,6 @@
#include "registers.h"
#include "task.h"
#include "timer.h"
-#include "trng.h"
#include "util.h"
/**
@@ -38,16 +37,6 @@ static uint32_t entropy_fifo[ENTROPY_SIZE_WORDS];
* at least 2^-50
*/
-/**
- * rand() should be able to return error code if reading from TRNG failed
- * return as struct with 2 params is more efficient as data is passed in
- * registers
- */
-struct rand_result {
- uint32_t random_value;
- bool valid;
-};
-
/* state data for TRNG health test */
static struct {
@@ -163,49 +152,6 @@ static bool fips_powerup_passed(void)
rand_state.apt_initialized;
}
-/**
- * Attempts to read TRNG_EMPTY before reporting a stall.
- * Practically data should be available in less than 777
- * cycles under normal conditions. Give 4 attempts to
- * reset before making decision TRNG is broken
- */
-#define TRNG_EMPTY_COUNT 777
-#define TRNG_RESET_COUNT 4
-
-/**
- * replica of rand() with interface which returns errors properly
- */
-static struct rand_result read_rand(void)
-{
- uint32_t empty_count = 0;
- uint32_t reset_count = 0;
-
-#ifdef CRYPTO_TEST_SETUP
- /* Do we need to simulate error? */
- if (fips_break_cmd == FIPS_BREAK_TRNG)
- return (struct rand_result){ .random_value = 0, .valid = true };
-#endif
-
- /**
- * make sure we never hang in the loop - try at max 1
- * reset attempt, then return error
- */
- while (GREAD(TRNG, EMPTY) && (reset_count < TRNG_RESET_COUNT)) {
- if (GREAD_FIELD(TRNG, FSM_STATE, FSM_IDLE) ||
- empty_count > TRNG_EMPTY_COUNT) {
- /* TRNG timed out, restart */
- GWRITE(TRNG, STOP_WORK, 1);
- flash_log_add_event(FE_LOG_TRNG_STALL, 0, NULL);
- GWRITE(TRNG, GO_EVENT, 1);
- empty_count = 0;
- reset_count++;
- }
- empty_count++;
- }
- return (struct rand_result){ .random_value = GREAD(TRNG, READ_DATA),
- .valid =
- (reset_count < TRNG_RESET_COUNT) };
-}
/**
* get random from TRNG and run continuous health tests.
@@ -213,26 +159,25 @@ static struct rand_result read_rand(void)
* @param power_up if non-zero indicates warm-up mode
* @return random value from TRNG
*/
-static struct rand_result fips_trng32(int power_up)
+static uint64_t fips_trng32(int power_up)
{
- struct rand_result r;
+ uint64_t r;
/* Continuous health tests should have been initialized by now */
if (!(power_up || fips_crypto_allowed()))
- return (struct rand_result){ .random_value = 0,
- .valid = false };
+ return 0;
/* get noise */
r = read_rand();
- if (r.valid) {
- if (!repetition_count_test(r.random_value)) {
+ if (rand_valid(r)) {
+ if (!repetition_count_test((uint32_t)r)) {
fips_set_status(FIPS_FATAL_TRNG_RCT);
- r.valid = false;
+ r = (uint32_t)r;
}
- if (!adaptive_proportion_test(r.random_value)) {
+ if (!adaptive_proportion_test((uint32_t)r)) {
fips_set_status(FIPS_FATAL_TRNG_APT);
- r.valid = false;
+ r = (uint32_t)r;
}
} else
fips_set_status(FIPS_FATAL_TRNG_OTHER);
@@ -243,8 +188,9 @@ static struct rand_result fips_trng32(int power_up)
bool fips_trng_bytes(void *buffer, size_t len)
{
uint8_t *buf = (uint8_t *)buffer;
- uint32_t random_togo = 0;
- struct rand_result r;
+ size_t random_togo = 0;
+ uint64_t rand;
+ uint32_t r;
/**
* Retrieve random numbers in 4 byte quantities and pack as many bytes
* as needed into 'buffer'. If len is not divisible by 4, the
@@ -252,14 +198,15 @@ bool fips_trng_bytes(void *buffer, size_t len)
*/
while (len--) {
if (!random_togo) {
- r = fips_trng32(0);
- if (!r.valid)
+ rand = fips_trng32(0);
+ if (!rand_valid(rand))
return false;
- random_togo = sizeof(r.random_value);
+ r = (uint32_t)rand;
+ random_togo = sizeof(r);
}
- *buf++ = (uint8_t)r.random_value;
+ *buf++ = (uint8_t)r;
random_togo--;
- r.random_value >>= 8;
+ r >>= 8;
}
return true;
}
@@ -278,19 +225,20 @@ 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++) {
- struct rand_result r = fips_trng32(1);
+ uint64_t r = fips_trng32(1);
- if (!r.valid)
+ if (!rand_valid(r))
return false;
/* store entropy for further use */
- entropy_fifo[i % ARRAY_SIZE(entropy_fifo)] = r.random_value;
+ entropy_fifo[i % ARRAY_SIZE(entropy_fifo)] = (uint32_t)r;
}
return fips_powerup_passed();
}
bool fips_drbg_init(void)
{
- struct rand_result nonce;
+ uint64_t nonce;
+ uint32_t random;
if (!fips_crypto_allowed())
return EC_ERROR_INVALID_CONFIG;
@@ -304,18 +252,19 @@ bool fips_drbg_init(void)
* Add 32 * 0.85 = 27 bits from nonce.
*/
nonce = fips_trng32(0);
- if (!nonce.valid)
+ if (!rand_valid(nonce))
return false;
+ random = (uint32_t)nonce;
/* read another 512 bits of noise */
if (!fips_trng_bytes(&entropy_fifo, sizeof(entropy_fifo)))
return false;
hmac_drbg_init(&fips_drbg, &entropy_fifo, sizeof(entropy_fifo),
- &nonce.random_value, sizeof(nonce.random_value), NULL,
+ &random, sizeof(random), NULL,
0);
- set_fast_random_seed(fips_trng32(0).random_value);
+ set_fast_random_seed((uint32_t)fips_trng32(0));
rand_state.drbg_initialized = 1;
return true;
}
diff --git a/board/cr50/fips_rand.h b/board/cr50/fips_rand.h
index 14eba3fe32..dca1f473bf 100644
--- a/board/cr50/fips_rand.h
+++ b/board/cr50/fips_rand.h
@@ -19,6 +19,29 @@ extern "C" {
#define TRNG_SAMPLE_BITS 1
/**
+ * Initialize the true random number generator (TRNG) in FIPS-compliant
+ * way:
+ * 1. Set 1-bit alphabet
+ * 2. Set maximum possible range for internal ring-oscillator
+ * 3. Disable any other post-processing beyond #2
+ **/
+void fips_init_trng(void);
+
+/**
+ * Returns random number with indication wherever reading is valid. This is
+ * different from rand() which doesn't provide any indication.
+ * High 32-bits set to zero in case of error; otherwise value >> 32 == 1
+ * Use of uint64_t vs. struct results in more efficient code.
+ */
+uint64_t read_rand(void);
+
+/* Return true if read_rand() result contains valid random from TRNG. */
+static inline bool rand_valid(uint64_t rand)
+{
+ return (rand >> 32) != 0;
+}
+
+/**
* TRNG Health Tests
*
* If any of the approved continuous health tests are used by the entropy
@@ -75,7 +98,7 @@ extern "C" {
* over at least 4096 consecutive samples.
* Note: This function can throw FIPS_FATAL_TRNG error
*
- * To hide latenccy of reading TRNG data, this test is executed in 2 stages
+ * To hide latency of reading TRNG data, this test is executed in 2 stages
* @param stage is 0 or 1, choosing the stage. On each stage 2048
* samples are processed. Assuming that some other tasks can be executed
* between stages, when TRNG FIFO if filled with samples.