summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2021-09-24 16:21:56 -0700
committerCommit Bot <commit-bot@chromium.org>2021-09-28 02:05:01 +0000
commit9fbc265dbcf7a98c46a55c6eac7667e16117eaef (patch)
treeab0cc5c17bae957db128bdaded9b5e2881980008
parent2d15ff2e3f9295f935f498d7f40fe64ee90fc950 (diff)
downloadchrome-ec-stabilize-14249.B-cr50_stab.tar.gz
cr50: refactor HMAC_DRBG to simplify reseeding and initialization logicstabilize-14249.B-cr50_stab
1) Move DRBG initialization flag inside DRBG context to prevent use of DRBG which is not properly initialized. 2) Add configurable reseed threshold to cover both deterministic key gen and non-deterministic randoms. Simplify reseeding logic, remove similar code snippets. Also, can support NDRBG with reseed threshold equal to 0, which will result in reseeding each time. 3) Adjust parameter names to match NIST SP 800-90A specification. 4) Enforce checking result of hmac_drbg_generate(), update call sites to check for errors. 5) Reseeding in generate function consumes additional data as per NIST SP 800-90Ar1 9.3.1 BUG=b:138577416 TEST=make BOARD=cr50 CRYPTO_TEST=1 DRBG_TEST=1; test/tpm_test/tpm_test.py in ccd: hmac_drbg rand_perf Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Change-Id: I0e780b5c237d7fbc64e8b0e74d12559a1f40f84c Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3183397 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org>
-rw-r--r--board/cr50/dcrypto/dcrypto_runtime.c6
-rw-r--r--board/cr50/dcrypto/fips.c6
-rw-r--r--board/cr50/dcrypto/fips_rand.c124
-rw-r--r--board/cr50/dcrypto/hmac_drbg.c147
-rw-r--r--board/cr50/dcrypto/internal.h78
-rw-r--r--board/cr50/dcrypto/p256_ec.c9
-rw-r--r--board/cr50/dcrypto/u2f.c31
-rw-r--r--chip/host/trng.c6
8 files changed, 208 insertions, 199 deletions
diff --git a/board/cr50/dcrypto/dcrypto_runtime.c b/board/cr50/dcrypto/dcrypto_runtime.c
index 15824ff32a..9e75aada5c 100644
--- a/board/cr50/dcrypto/dcrypto_runtime.c
+++ b/board/cr50/dcrypto/dcrypto_runtime.c
@@ -401,7 +401,8 @@ static enum dcrypto_result ecdsa_sign_go(p256_int *r, p256_int *s)
p256_int message = *s;
/* drbg init with same entropy */
- hmac_drbg_init(&drbg, r->a, sizeof(r->a), NULL, 0, NULL, 0);
+ hmac_drbg_init(&drbg, r->a, sizeof(r->a), NULL, 0, NULL, 0,
+ HMAC_DRBG_DO_NOT_AUTO_RESEED);
/* pick a key */
if (p256_hmac_drbg_generate(&drbg, &d) != DCRYPTO_OK) {
@@ -411,8 +412,7 @@ static enum dcrypto_result ecdsa_sign_go(p256_int *r, p256_int *s)
}
/* drbg_reseed with entropy and message */
- hmac_drbg_reseed(&drbg, r->a, sizeof(r->a), s->a, sizeof(s->a), NULL,
- 0);
+ hmac_drbg_reseed(&drbg, r->a, sizeof(r->a), s->a, sizeof(s->a));
ret = dcrypto_p256_ecdsa_sign(&drbg, &d, &message, r, s);
diff --git a/board/cr50/dcrypto/fips.c b/board/cr50/dcrypto/fips.c
index d6c1912029..9fdad94df7 100644
--- a/board/cr50/dcrypto/fips.c
+++ b/board/cr50/dcrypto/fips.c
@@ -281,7 +281,7 @@ static bool fips_hmac_drbg_instantiate_kat(struct drbg_ctx *ctx)
hmac_drbg_init(ctx, drbg_entropy0, sizeof(drbg_entropy0),
drbg_nonce0, sizeof(drbg_nonce0), drbg_perso0,
- sizeof(drbg_perso0));
+ sizeof(drbg_perso0), 10000);
return (DCRYPTO_equals(ctx->v, V0, sizeof(V0)) == DCRYPTO_OK) &&
(DCRYPTO_equals(ctx->k, K0, sizeof(K0)) == DCRYPTO_OK);
@@ -299,7 +299,7 @@ static bool fips_hmac_drbg_reseed_kat(struct drbg_ctx *ctx)
0x918D9EB7, 0xAE0CD544 };
hmac_drbg_reseed(ctx, drbg_entropy1, sizeof(drbg_entropy1),
- drbg_addtl_input1, sizeof(drbg_addtl_input1), NULL, 0);
+ drbg_addtl_input1, sizeof(drbg_addtl_input1));
return (DCRYPTO_equals(ctx->v, V1, sizeof(V1)) == DCRYPTO_OK) &&
(DCRYPTO_equals(ctx->k, K1, sizeof(K1)) == DCRYPTO_OK);
@@ -345,7 +345,7 @@ static bool fips_hmac_drbg_generate_kat(struct drbg_ctx *ctx)
buf[0] ^= 1;
hmac_drbg_reseed(ctx, buf, sizeof(drbg_entropy2), drbg_addtl_input2,
- sizeof(drbg_addtl_input2), NULL, 0);
+ sizeof(drbg_addtl_input2));
passed |= hmac_drbg_generate(ctx, buf, sizeof(buf), NULL, 0);
passed |= DCRYPTO_equals(buf, KA, sizeof(KA));
diff --git a/board/cr50/dcrypto/fips_rand.c b/board/cr50/dcrypto/fips_rand.c
index 265b48c983..f949993450 100644
--- a/board/cr50/dcrypto/fips_rand.c
+++ b/board/cr50/dcrypto/fips_rand.c
@@ -19,16 +19,6 @@
*/
struct drbg_ctx fips_drbg;
-#define ENTROPY_SIZE_BITS 512
-#define ENTROPY_SIZE_WORDS (BITS_TO_WORDS(ENTROPY_SIZE_BITS))
-
-/**
- * buffer for entropy condensing. initialized during
- * fips_trng_startup(), but also used in KAT tests,
- * thus size is enough to accommodate needs
- */
-static uint32_t entropy_fifo[ENTROPY_SIZE_WORDS];
-
/**
* NIST FIPS TRNG health tests (NIST SP 800-90B 4.3)
* If any of the approved continuous health tests are used by the entropy
@@ -46,7 +36,6 @@ static struct {
uint8_t rct_count; /* current windows size for RCT */
uint8_t oldest; /* position in APT window */
bool apt_initialized; /* flag APT window is filled with data */
- bool drbg_initialized; /* flag DRBG is initialized */
} rand_state;
/**
@@ -188,6 +177,7 @@ static uint64_t fips_trng32(void)
fips_set_status(error);
r = (uint32_t)r; /* Set result as invalid. */
}
+
return r;
}
@@ -231,6 +221,8 @@ bool fips_trng_bytes(void *buffer, size_t len)
/* FIPS TRNG power-up tests */
bool fips_trng_startup(int stage)
{
+ uint64_t r;
+
if (!stage) {
/**
* To hide TRNG latency, split it into 2 stages.
@@ -242,86 +234,57 @@ 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();
+ r = fips_trng32();
if (!rand_valid(r))
return false;
- /* store entropy for further use */
- entropy_fifo[i % ARRAY_SIZE(entropy_fifo)] = (uint32_t)r;
}
+ /* Also update seed for fast randoms. */
+ set_fast_random_seed((uint32_t)r);
return fips_powerup_passed();
}
+/* Assuming H=0.8, we need 550 bits from TRNG to get 440 bits. */
+#define ENTROPY_SIZE_BITS 550
+#define ENTROPY_SIZE_WORDS (BITS_TO_WORDS(ENTROPY_SIZE_BITS))
+
bool fips_drbg_init(void)
{
- uint64_t nonce;
- uint32_t random;
+ /* Buffer for Entropy + Nonce for DRBG initialization. */
+ uint32_t entropy_input[ENTROPY_SIZE_WORDS];
if (!fips_crypto_allowed())
return false;
- if (rand_state.drbg_initialized)
+ if (hmac_drbg_ctx_valid(&fips_drbg))
return true;
+
/**
- * initialize DRBG with 440 bits of entropy as required
- * by NIST SP 800-90A 10.1. Includes entropy and nonce,
- * both received from entropy source.
- * entropy_fifo contains 512 bits of noise with H>= 0.85
- * this is roughly equal to 435 bits of full entropy.
- * Add 32 * 0.85 = 27 bits from nonce.
+ * Get entropy + nonce from TRNG. Assume H>=0.8.
*/
- nonce = fips_trng32();
- 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)))
+ if (!fips_trng_bytes(entropy_input, sizeof(entropy_input)))
return false;
- hmac_drbg_init(&fips_drbg, &entropy_fifo, sizeof(entropy_fifo),
- &random, sizeof(random), NULL,
- 0);
-
- set_fast_random_seed((uint32_t)fips_trng32());
- rand_state.drbg_initialized = true;
- return true;
-}
-
-/* zeroize DRBG state */
-void fips_drbg_clear(void)
-{
- drbg_exit(&fips_drbg);
- rand_state.drbg_initialized = false;
-}
-
-static bool fips_drbg_reseed_with_entropy(struct drbg_ctx *ctx)
-{
- /* FIPS error is reported by failed TRNG test. */
- if (!fips_trng_bytes(&entropy_fifo, sizeof(entropy_fifo)))
- return false;
+ /**
+ * Pass combined seed containing total 550 bits of entropy and nonce,
+ * and assuming H=0.8, we will get total entropy in seed as 440bits as
+ * defined for HMAC DBRG in NIST SP 800-90Ar1 B.2.
+ * Required minimum entropy for the entropy input at instantiation =
+ * (3/2) security_strength (this includes the entropy required for the
+ * nonce). For 256-bit security, this means at least 384 bits.
+ *
+ * Maximum length of the personalization string = 160 bits.
+ * Maximum length of the entropy input = 1000 bits.
+ *
+ * Reseed_interval = 10 000 requests.
+ */
+ hmac_drbg_init(&fips_drbg, &entropy_input, sizeof(entropy_input), NULL,
+ 0, NULL, 0, 10000);
- hmac_drbg_reseed(ctx, entropy_fifo, sizeof(entropy_fifo),
- NULL, 0, NULL, 0);
+ always_memset(entropy_input, 0, sizeof(entropy_input));
return true;
}
-enum dcrypto_result fips_hmac_drbg_generate_reseed(struct drbg_ctx *ctx,
- void *out, size_t out_len,
- const void *input,
- size_t input_len)
-{
- enum dcrypto_result err =
- hmac_drbg_generate(ctx, out, out_len, input, input_len);
-
- while (err == DCRYPTO_RESEED_NEEDED) {
- if (!fips_drbg_reseed_with_entropy(ctx))
- return DCRYPTO_FAIL;
- err = hmac_drbg_generate(ctx, out, out_len, input, input_len);
- }
- return err;
-}
-
bool fips_rand_bytes(void *buffer, size_t len)
{
/**
@@ -335,10 +298,10 @@ bool fips_rand_bytes(void *buffer, size_t len)
/* HMAC_DRBG can only return up to 7500 bits in a single request */
while (len) {
- size_t request = (len > (7500 / 8)) ? (7500 / 8) : len;
+ size_t request = MIN(len, HMAC_DRBG_MAX_OUTPUT_SIZE);
- if (fips_hmac_drbg_generate_reseed(&fips_drbg, buffer, request,
- NULL, 0) != DCRYPTO_OK)
+ if (hmac_drbg_generate(&fips_drbg, buffer, request, NULL, 0) !=
+ DCRYPTO_OK)
return false;
len -= request;
buffer += request;
@@ -346,23 +309,6 @@ bool fips_rand_bytes(void *buffer, size_t len)
return true;
}
-enum dcrypto_result fips_p256_hmac_drbg_generate(struct drbg_ctx *drbg,
- p256_int *out)
-{
- enum dcrypto_result err;
-
- if (!fips_crypto_allowed())
- return DCRYPTO_FAIL;
-
- err = p256_hmac_drbg_generate(drbg, out);
- while (err == DCRYPTO_RESEED_NEEDED) {
- if (!fips_drbg_reseed_with_entropy(drbg))
- return DCRYPTO_FAIL;
- err = p256_hmac_drbg_generate(drbg, out);
- }
- return err;
-}
-
#ifndef CRYPTO_TEST_CMD_RAND_PERF
#define CRYPTO_TEST_CMD_RAND_PERF 0
#endif
diff --git a/board/cr50/dcrypto/hmac_drbg.c b/board/cr50/dcrypto/hmac_drbg.c
index 9793ad938e..d5f4960013 100644
--- a/board/cr50/dcrypto/hmac_drbg.c
+++ b/board/cr50/dcrypto/hmac_drbg.c
@@ -8,6 +8,10 @@
#include "extension.h"
#include "internal.h"
+/* Assuming H=0.8, we need 320 bits from TRNG to get 256 bits. */
+#define RESEED_ENTROPY_SIZE_BITS 320
+#define RESEED_ENTROPY_SIZE_WORDS (BITS_TO_WORDS(RESEED_ENTROPY_SIZE_BITS))
+
/* HMAC_DRBG flow in NIST SP 800-90Ar1, 10.2, RFC 6979
*/
/* V = HMAC(K, V) */
@@ -59,58 +63,91 @@ static void update(struct drbg_ctx *ctx,
p0, p0_len, p1, p1_len, p2, p2_len);
}
-void hmac_drbg_init(struct drbg_ctx *ctx,
- const void *p0, size_t p0_len,
- const void *p1, size_t p1_len,
- const void *p2, size_t p2_len)
+void hmac_drbg_init(struct drbg_ctx *ctx, const void *entropy,
+ size_t entropy_len, const void *nonce, size_t nonce_len,
+ const void *perso, size_t perso_len,
+ uint32_t reseed_threshold)
{
- /* K = 0x00 0x00 0x00 ... 0x00 */
- always_memset(ctx->k, 0x00, sizeof(ctx->k));
+ /**
+ * Clear the context. Also set
+ * K = 0x00 0x00 0x00 ... 0x00
+ * magic_cookie = 0
+ */
+ always_memset(ctx, 0x00, sizeof(*ctx));
/* V = 0x01 0x01 0x01 ... 0x01 */
- always_memset(ctx->v, 0x01, sizeof(ctx->v));
+ always_memset(ctx->v, 0x01, sizeof(ctx->v));
- update(ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ /* seed_material = entropy_input || nonce || personalization_string. */
+ update(ctx, entropy, entropy_len, nonce, nonce_len, perso, perso_len);
ctx->reseed_counter = 1;
+ ctx->reseed_threshold = reseed_threshold;
+ ctx->magic_cookie = DCRYPTO_OK;
}
void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key,
const p256_int *message)
{
- hmac_drbg_init(ctx,
- key->a, sizeof(key->a),
- message->a, sizeof(message->a),
- NULL, 0);
+ hmac_drbg_init(ctx, key->a, sizeof(key->a), message->a,
+ sizeof(message->a), NULL, 0,
+ HMAC_DRBG_DO_NOT_AUTO_RESEED);
}
-void hmac_drbg_reseed(struct drbg_ctx *ctx,
- const void *p0, size_t p0_len,
- const void *p1, size_t p1_len,
- const void *p2, size_t p2_len)
+void hmac_drbg_reseed(struct drbg_ctx *ctx, const void *entropy,
+ size_t entropy_len, const void *additional_input,
+ size_t additional_input_len)
{
- update(ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ /* seed_material = entropy_input || additional_input. */
+ update(ctx, entropy, entropy_len, additional_input,
+ additional_input_len, NULL, 0);
ctx->reseed_counter = 1;
}
-enum dcrypto_result hmac_drbg_generate(struct drbg_ctx *ctx,
- void *out, size_t out_len,
- const void *input, size_t input_len)
+enum dcrypto_result hmac_drbg_generate(struct drbg_ctx *ctx, void *out,
+ size_t out_len,
+ const void *additional_input,
+ size_t additional_input_len)
{
- /* According to NIST SP 800-90A rev 1 B.2
- * Maximum number of bits per request = 7500 bits
- * Reseed_interval = 10 000 requests.
+ /* Prevent misuse of uninitialized DRBG context. */
+ if (!hmac_drbg_ctx_valid(ctx))
+ return DCRYPTO_FAIL;
+
+ /**
+ * In addition to output length, check also additional input
+ * length to be reasonable.
*/
- if (out_len > 7500 / 8)
+
+ if (out_len > HMAC_DRBG_MAX_OUTPUT_SIZE ||
+ additional_input_len > HMAC_DRBG_MAX_OUTPUT_SIZE)
return DCRYPTO_FAIL;
- if (ctx->reseed_counter++ >= 10000)
+ /**
+ * Special case when no auto reseed is needed. Note, as we use unsigned
+ * 32-bit values, ctx->reseed_counter can never be larger
+ * than HMAC_DRBG_DO_NOT_AUTO_RESEED, so check explicitly.
+ */
+ if (ctx->reseed_counter == HMAC_DRBG_DO_NOT_AUTO_RESEED)
return DCRYPTO_RESEED_NEEDED;
- if (input_len)
- update(ctx, input, input_len, NULL, 0, NULL, 0);
+ if (ctx->reseed_counter > ctx->reseed_threshold) {
+ uint32_t entropy[RESEED_ENTROPY_SIZE_WORDS];
+
+ if (!fips_trng_bytes(&entropy, sizeof(entropy)))
+ return DCRYPTO_FAIL;
+
+ hmac_drbg_reseed(ctx, entropy, sizeof(entropy),
+ additional_input, additional_input_len);
+ additional_input_len = 0;
+ }
+
+ ctx->reseed_counter++;
+
+ if (additional_input_len)
+ update(ctx, additional_input, additional_input_len, NULL, 0,
+ NULL, 0);
while (out_len) {
- size_t n = out_len > sizeof(ctx->v) ? sizeof(ctx->v) : out_len;
+ size_t n = MIN(out_len, sizeof(ctx->v));
update_v(ctx->k, ctx->v);
@@ -119,15 +156,14 @@ enum dcrypto_result hmac_drbg_generate(struct drbg_ctx *ctx,
out_len -= n;
}
- update(ctx, input, input_len, NULL, 0, NULL, 0);
+ update(ctx, additional_input, additional_input_len, NULL, 0, NULL, 0);
return DCRYPTO_OK;
}
void drbg_exit(struct drbg_ctx *ctx)
{
- always_memset(ctx->k, 0x00, sizeof(ctx->k));
- always_memset(ctx->v, 0x00, sizeof(ctx->v));
+ always_memset(ctx, 0, sizeof(*ctx));
}
#ifndef CRYPTO_TEST_CMD_HMAC_DRBG
@@ -188,7 +224,10 @@ static int cmd_rfc6979(int argc, char **argv)
memcpy(&h1, SHA256_final(&ctx)->b8, SHA256_DIGEST_SIZE);
hmac_drbg_init_rfc6979(&drbg, x, &h1);
- hmac_drbg_generate(&drbg, k.a, sizeof(k), NULL, 0);
+ if (hmac_drbg_generate(&drbg, k.a, sizeof(k), NULL, 0) != DCRYPTO_OK) {
+ ccprintf("HMAC DRBG generate failed\n");
+ return EC_ERROR_HW_INTERNAL;
+ }
ccprintf("K = %ph\n", HEX_BUF(&k, 32));
drbg_exit(&drbg);
result = memcmp(&k, reference_k, sizeof(reference_k));
@@ -290,25 +329,25 @@ static int cmd_hmac_drbg(int argc, char **argv)
static uint8_t output[128];
int i, cmp_result;
+ enum dcrypto_result err;
for (i = 0; i < HMAC_TEST_COUNT; i++) {
- hmac_drbg_init(&ctx,
- init_entropy[i], sizeof(init_entropy[i]),
- init_nonce[i], sizeof(init_nonce[i]),
- NULL, 0);
+ hmac_drbg_init(&ctx, init_entropy[i], sizeof(init_entropy[i]),
+ init_nonce[i], sizeof(init_nonce[i]), NULL, 0,
+ 10000);
- hmac_drbg_reseed(&ctx,
- reseed_entropy[i], sizeof(reseed_entropy[i]),
- NULL, 0,
- NULL, 0);
+ hmac_drbg_reseed(&ctx, reseed_entropy[i],
+ sizeof(reseed_entropy[i]), NULL, 0);
- hmac_drbg_generate(&ctx,
- output, sizeof(output),
- NULL, 0);
+ err = hmac_drbg_generate(&ctx, output, sizeof(output), NULL, 0);
- hmac_drbg_generate(&ctx,
- output, sizeof(output),
- NULL, 0);
+ err |= hmac_drbg_generate(&ctx, output, sizeof(output), NULL,
+ 0);
+
+ if (err != DCRYPTO_OK) {
+ ccprintf("HMAC DRBG generate failed.\n");
+ return EC_ERROR_HW_INTERNAL;
+ }
cmp_result = memcmp(output, expected_output[i], sizeof(output));
ccprintf("HMAC DRBG generate test %d, %s\n",
@@ -327,15 +366,18 @@ static int cmd_hmac_drbg_rand(int argc, char **argv)
static struct drbg_ctx ctx;
static uint8_t output[128];
- int i;
+ size_t i;
/* Seed with 256 bits from TRNG. */
if (!fips_trng_bytes(output, 32))
return EC_ERROR_HW_INTERNAL;
- hmac_drbg_init(&ctx, output, 32, NULL, 0, NULL, 0);
-
- hmac_drbg_generate(&ctx, output, sizeof(output), NULL, 0);
+ hmac_drbg_init(&ctx, output, 32, NULL, 0, NULL, 0, 10000);
+ if (hmac_drbg_generate(&ctx, output, sizeof(output), NULL, 0) !=
+ DCRYPTO_OK) {
+ ccprintf("HMAC_DRBG generate failed.\n");
+ return EC_ERROR_HW_INTERNAL;
+ }
ccprintf("Randomly initialized HMAC DRBG, 1024 bit output: ");
for (i = 0; i < sizeof(output); i++)
@@ -438,11 +480,12 @@ static enum vendor_cmd_rc drbg_test(enum vendor_cmd_cc code, void *buf,
switch (drbg_op) {
case DRBG_INIT: {
- hmac_drbg_init(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ hmac_drbg_init(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len,
+ 10000);
break;
}
case DRBG_RESEED: {
- hmac_drbg_reseed(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ hmac_drbg_reseed(&drbg_ctx, p0, p0_len, p1, p1_len);
break;
}
case DRBG_GENERATE: {
diff --git a/board/cr50/dcrypto/internal.h b/board/cr50/dcrypto/internal.h
index 0967c50845..ed1f324079 100644
--- a/board/cr50/dcrypto/internal.h
+++ b/board/cr50/dcrypto/internal.h
@@ -90,27 +90,43 @@ int dcrypto_modexp_blinded(struct LITE_BIGNUM *output,
const struct LITE_BIGNUM *N,
uint32_t pubexp);
+/**
+ * NIST SP 800-90A HMAC_DRBG_SHA2-256.
+ */
struct drbg_ctx {
uint32_t k[SHA256_DIGEST_WORDS];
uint32_t v[SHA256_DIGEST_WORDS];
uint32_t reseed_counter;
+ uint32_t reseed_threshold;
+ enum dcrypto_result magic_cookie;
};
-
-/*
- * NIST SP 800-90A HMAC DRBG.
+/* According to NIST SP 800-90A rev 1 B.2
+ * Maximum number of bits per request = 7500 bit, ~937 bytes
*/
+#define HMAC_DRBG_MAX_OUTPUT_SIZE 937U
+
+#define HMAC_DRBG_DO_NOT_AUTO_RESEED 0xFFFFFFFF
+
+/* Check that DRBG is properly initialized. */
+static inline bool hmac_drbg_ctx_valid(const struct drbg_ctx *drbg)
+{
+ return drbg->magic_cookie == DCRYPTO_OK;
+}
/* Standard initialization. */
-void hmac_drbg_init(struct drbg_ctx *ctx, const void *p0, size_t p0_len,
- const void *p1, size_t p1_len, const void *p2,
- size_t p2_len);
+void hmac_drbg_init(struct drbg_ctx *ctx, const void *entropy,
+ size_t entropy_len, const void *nonce, size_t nonce_len,
+ const void *perso, size_t perso_len,
+ uint32_t reseed_threshold);
+
+void hmac_drbg_reseed(struct drbg_ctx *ctx, const void *entropy,
+ size_t entropy_len, const void *additional_input,
+ size_t additional_input_len);
-void hmac_drbg_reseed(struct drbg_ctx *ctx, const void *p0, size_t p0_len,
- const void *p1, size_t p1_len, const void *p2,
- size_t p2_len);
enum dcrypto_result hmac_drbg_generate(struct drbg_ctx *ctx, void *out,
size_t out_len, const void *input,
- size_t input_len);
+ size_t input_len) __warn_unused_result;
+
void drbg_exit(struct drbg_ctx *ctx);
/**
@@ -140,34 +156,24 @@ uint64_t read_rand(void);
*/
bool fips_trng_startup(int stage);
-
-/* initialize cr50-wide DRBG replacing rand */
+/**
+ * Check that Cr50-wide HMAC_DRBG seeded according NIST SP 800-90A
+ * recomendation is properly initialized and can be used.
+ * Includes fips_crypto_allowed() check.
+ * Initialize DRBG if it was not yet initialized.
+ */
bool fips_drbg_init(void);
-/* mark cr50-wide DRBG as not initialized */
-void fips_drbg_init_clear(void);
/* FIPS DRBG initialized at boot time/first use. */
extern struct drbg_ctx fips_drbg;
-/**
- * Generate valid P-256 random from FIPS DRBG, reseed DRBG with entropy from
- * verified TRNG if needed.
- *
- * @param drbg DRBG to use
- * @param out output value
- * @return DCRYPTO_OK if out contains random.
- */
-enum dcrypto_result fips_p256_hmac_drbg_generate(struct drbg_ctx *drbg,
- p256_int *out);
+/* Initialize for use as RFC6979 DRBG. */
+void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key,
+ const p256_int *message);
-/**
- * wrapper around hmac_drbg_generate to automatically reseed drbg
- * when needed.
- */
-enum dcrypto_result fips_hmac_drbg_generate_reseed(struct drbg_ctx *ctx,
- void *out, size_t out_len,
- const void *input,
- size_t input_len);
+/* Generate a p256 number between 1 < k < |p256| using provided DRBG. */
+enum dcrypto_result p256_hmac_drbg_generate(struct drbg_ctx *ctx,
+ p256_int *k_out);
/* Set seed for fast random number generator using LFSR. */
void set_fast_random_seed(uint32_t seed);
@@ -303,10 +309,6 @@ enum dcrypto_result dcrypto_p256_key_pwct(
/* Wipe content of rnd with pseudo-random values. */
void p256_fast_random(p256_int *rnd);
-/* Generate a p256 number between 1 < k < |p256| using provided DRBG. */
-enum dcrypto_result p256_hmac_drbg_generate(struct drbg_ctx *ctx,
- p256_int *k_out);
-
/**
* Sign using provided DRBG. Reseed DRBG with entropy from verified TRNG if
* needed.
@@ -322,10 +324,6 @@ enum dcrypto_result dcrypto_p256_fips_sign_internal(
struct drbg_ctx *drbg, const p256_int *key, const p256_int *message,
p256_int *r, p256_int *s) __warn_unused_result;
-/* Initialize for use as RFC6979 DRBG. */
-void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx,
- const p256_int *key,
- const p256_int *message);
/*
* Accelerator runtime.
diff --git a/board/cr50/dcrypto/p256_ec.c b/board/cr50/dcrypto/p256_ec.c
index 2f458080ce..5924848c23 100644
--- a/board/cr50/dcrypto/p256_ec.c
+++ b/board/cr50/dcrypto/p256_ec.c
@@ -63,6 +63,15 @@ enum dcrypto_result DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y,
return dcrypto_p256_point_mul(n, in_x, in_y, out_x, out_y);
}
+/**
+ * This function serves as workaround for gcc 11.2 crash.
+ */
+static enum dcrypto_result fips_p256_hmac_drbg_generate(struct drbg_ctx *ctx,
+ p256_int *rnd)
+{
+ return p256_hmac_drbg_generate(ctx, rnd);
+}
+
enum dcrypto_result dcrypto_p256_fips_sign_internal(struct drbg_ctx *drbg,
const p256_int *key,
const p256_int *message,
diff --git a/board/cr50/dcrypto/u2f.c b/board/cr50/dcrypto/u2f.c
index 414a8fe41a..76be43285d 100644
--- a/board/cr50/dcrypto/u2f.c
+++ b/board/cr50/dcrypto/u2f.c
@@ -183,9 +183,11 @@ static enum ec_error_list u2f_origin_user_key_pair(
*/
hmac_drbg_init(&drbg, state->drbg_entropy,
state->drbg_entropy_size, dev_salt, P256_NBYTES,
- NULL, 0);
- hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed),
- key_handle, key_handle_size);
+ NULL, 0, HMAC_DRBG_DO_NOT_AUTO_RESEED);
+ if (hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed),
+ key_handle,
+ key_handle_size) != DCRYPTO_OK)
+ return EC_ERROR_HW_INTERNAL;
} else {
/**
* FIPS-compliant path.
@@ -198,15 +200,18 @@ static enum ec_error_list u2f_origin_user_key_pair(
*/
hmac_drbg_init(&drbg, state->drbg_entropy,
state->drbg_entropy_size, key_handle,
- key_handle_size, NULL, 0);
+ key_handle_size, NULL, 0,
+ HMAC_DRBG_DO_NOT_AUTO_RESEED);
/**
* Additional data = Device_ID (constant coming from HW).
*/
- hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed), dev_salt,
- P256_NBYTES);
+ if (hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed),
+ dev_salt, P256_NBYTES) != DCRYPTO_OK)
+ return EC_ERROR_HW_INTERNAL;
}
result = DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, key_seed);
+ drbg_exit(&drbg);
if (result == DCRYPTO_RETRY)
return EC_ERROR_TRY_AGAIN;
@@ -427,7 +432,7 @@ enum ec_error_list u2f_sign(const struct u2f_state *state,
DCRYPTO_OK) ?
EC_SUCCESS :
EC_ERROR_HW_INTERNAL;
-
+ drbg_exit(&ctx);
p256_clear(&origin_d);
p256_to_bin(&r, sig->sig_r);
@@ -485,19 +490,21 @@ static bool g2f_individual_key_pair(const struct u2f_state *state, p256_int *d,
*/
hmac_drbg_init(&drbg, state->drbg_entropy,
state->drbg_entropy_size, state->salt,
- sizeof(state->salt), NULL, 0);
+ sizeof(state->salt), NULL, 0,
+ HMAC_DRBG_DO_NOT_AUTO_RESEED);
do {
/**
* Additional data = constant coming from HW.
*/
- hmac_drbg_generate(&drbg, key_candidate,
- sizeof(key_candidate), buf.b32,
- sizeof(buf));
+ if (hmac_drbg_generate(&drbg, key_candidate,
+ sizeof(key_candidate), buf.b32,
+ sizeof(buf)) != DCRYPTO_OK)
+ return false;
result = DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d,
key_candidate);
} while (result == DCRYPTO_RETRY);
-
+ drbg_exit(&drbg);
if (result != DCRYPTO_OK)
return false;
}
diff --git a/chip/host/trng.c b/chip/host/trng.c
index ccb7a68983..80b52ce452 100644
--- a/chip/host/trng.c
+++ b/chip/host/trng.c
@@ -40,6 +40,12 @@ test_mockable void rand_bytes(void *buffer, size_t len)
*b = (uint8_t)rand_r(&seed);
}
+test_mockable bool fips_trng_bytes(void *buffer, size_t len)
+{
+ rand_bytes(buffer, len);
+ return true;
+}
+
test_mockable bool fips_rand_bytes(void *buffer, size_t len)
{
rand_bytes(buffer, len);