summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2021-08-17 11:45:23 -0700
committerCommit Bot <commit-bot@chromium.org>2021-08-19 04:39:29 +0000
commit4de87085a2da49887ac90aae9df571afa84168f6 (patch)
treed817284193e4687a47aa332073454b61789e2cdc
parent994efaeb57aaa023e38b547ceede69930ed687fc (diff)
downloadchrome-ec-4de87085a2da49887ac90aae9df571afa84168f6.tar.gz
cr50: refactor TRNG use, implement rand() using read_rand()
In preparation to switching from TRNG to DRBG, refactor to remove duplicated code, reduce code size. 1. Isolate hardware-dependent code (trng.c) from platform-agnostic in fips_rand.c. This will enable better host emulation for tests. 2. Change how read_rand() returns status to take advantage of ARM ABI. Unfortunately any composite type on ARM is returned on stack. Use uint64_t with combined validity flag in high bits and random in low 32 bits. This alone reduce code size around 100 bytes. 3. Avoid code duplication by implementing rand() using read_rand(). 4. Drop use of common/trng.h to reduce dependency on code outside boundary. To be completed with migration to DRBG. BUG=b:138577416 TEST=make BOARD=cr50 CRYPTO_TEST=1; rand_perf and FIPS tests Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Change-Id: Ifdc42e7210414a4abeac8c132a684e451fbbc19c Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3100489 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org>
-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.