summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2021-09-02 08:55:45 -0700
committerCommit Bot <commit-bot@chromium.org>2021-09-15 03:13:08 +0000
commit4ad2fe9ff8dd7088050c8b8aa3ddcd722bcfaf4f (patch)
treecf0dc64e0db26d90a33fe6b9ba6ac5e60968ea64
parente33cd20b6898e8a8896795425dc4e9c7c51d12be (diff)
downloadchrome-ec-4ad2fe9ff8dd7088050c8b8aa3ddcd722bcfaf4f.tar.gz
cr50: update FIPS known-answer tests
1. KAT tests should check that result doesn't match expectation for modified input, not just failing on request. Added modification of input data in case test break is needed (during module validation). 2. For ECDSA added pair-wise consistency test with known key pair. However, this test adds roughly 40ms, so disable it and use sign test with fixed nonce instead. 3. Some internal changes to support functionality - internally provided dcrypto_p256_ecdsa_sign_raw() which takes precomputed nonce vs. drbg. This allows generation of nonce with reseeding of DRBG if needed. Also added dcrypto_p256_fips_sign_internal() which does same as dcrypto_p256_ecdsa_sign() except that it reseeds DRBG with entropy if needed. 4. Implemented ECDSA sign test with fixed nonce, and combined with verify test. This allows to free some space for test vectors. Also, store SHA256 of message as SHA256 is already tested. This saves another 96 bytes. 5. KAT test time increased 2X from ~40ms to 60ms due to ECDSA sign test. 5. Run SHA2-256 KAT before self-integrity test, as it is used for self-integrity. BUG=b:138577539 TEST=make BOARD=cr50 Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Change-Id: I1cbd470bc64ef3eb50e9a28055404fb998c65b61 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3144376 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Andrey Pronin <apronin@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
-rw-r--r--board/cr50/dcrypto/dcrypto.h4
-rw-r--r--board/cr50/dcrypto/dcrypto_p256.c32
-rw-r--r--board/cr50/dcrypto/fips.c219
-rw-r--r--board/cr50/dcrypto/fips_rand.c36
-rw-r--r--board/cr50/dcrypto/fips_rand.h14
-rw-r--r--board/cr50/dcrypto/internal.h29
-rw-r--r--board/cr50/dcrypto/p256_ec.c26
-rw-r--r--include/config.h2
8 files changed, 267 insertions, 95 deletions
diff --git a/board/cr50/dcrypto/dcrypto.h b/board/cr50/dcrypto/dcrypto.h
index 318a58e4e7..accb2f3a43 100644
--- a/board/cr50/dcrypto/dcrypto.h
+++ b/board/cr50/dcrypto/dcrypto.h
@@ -259,12 +259,14 @@ int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
/**
* Pair-wise consistency test for private and public key.
*
+ * @param drbg - DRBG to use for nonce generation
* @param d - private key (scalar)
* @param x - public key part
* @param y - public key part
* @return !0 on success
*/
-int DCRYPTO_p256_key_pwct(p256_int *d, p256_int *x, p256_int *y);
+int DCRYPTO_p256_key_pwct(struct drbg_ctx *drbg, const p256_int *d,
+ const p256_int *x, const p256_int *y);
/* P256 based integration encryption (DH+AES128+SHA256).
* Not FIPS 140-2 compliant, not used other than for tests
diff --git a/board/cr50/dcrypto/dcrypto_p256.c b/board/cr50/dcrypto/dcrypto_p256.c
index e13e9b51bb..02c4edd9eb 100644
--- a/board/cr50/dcrypto/dcrypto_p256.c
+++ b/board/cr50/dcrypto/dcrypto_p256.c
@@ -138,7 +138,25 @@ int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
const p256_int *message, p256_int *r, p256_int *s)
{
int result;
- p256_int k, rnd;
+ p256_int nonce;
+
+ /* Pick uniform 0 < k < R */
+ result = (p256_hmac_drbg_generate(drbg, &nonce) != HMAC_DRBG_SUCCESS);
+
+ result |= dcrypto_p256_ecdsa_sign_raw(&nonce, key, message, r, s) - 1;
+
+ /* Wipe temp nonce */
+ p256_clear(&nonce);
+
+ return result == 0;
+}
+
+int dcrypto_p256_ecdsa_sign_raw(const p256_int *nonce, const p256_int *key,
+ const p256_int *message, p256_int *r,
+ p256_int *s)
+{
+ int result;
+ p256_int rnd;
dcrypto_init_and_lock();
dcrypto_ecc_init();
@@ -148,13 +166,7 @@ int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
p256_fast_random(&rnd);
CP8W(rnd, &rnd);
- /* Pick uniform 0 < k < R */
- result |= (p256_hmac_drbg_generate(drbg, &k) != HMAC_DRBG_SUCCESS);
-
- CP8WB(k, &k, &rnd);
-
- /* Wipe temp k */
- p256_clear(&k);
+ CP8WB(k, nonce, &rnd);
CP8W(msg, message);
CP8WB(d, key, &rnd);
@@ -170,8 +182,8 @@ int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
}
/* Wipe d,k */
- CP8W(d, &k);
- CP8W(k, &k);
+ CP8W(d, &rnd);
+ CP8W(k, &rnd);
dcrypto_unlock();
return result == 0;
diff --git a/board/cr50/dcrypto/fips.c b/board/cr50/dcrypto/fips.c
index 349117d49b..f08b54aea7 100644
--- a/board/cr50/dcrypto/fips.c
+++ b/board/cr50/dcrypto/fips.c
@@ -145,6 +145,8 @@ static bool fips_sha256_kat(void)
static const uint8_t in[] = /* "etaonrishd" */ { 0x65, 0x74, 0x61, 0x6f,
0x6e, 0x72, 0x69, 0x73,
0x68, 0x64 };
+ uint8_t in_mem[sizeof(in)];
+
static const uint8_t ans[] = { 0xf5, 0x53, 0xcd, 0xb8, 0xcf, 0x1, 0xee,
0x17, 0x9b, 0x93, 0xc9, 0x68, 0xc0, 0xea,
0x40, 0x91, 0x6, 0xec, 0x8e, 0x11, 0x96,
@@ -152,10 +154,13 @@ static bool fips_sha256_kat(void)
0x50, 0x4f, 0x47, 0x57 };
SHA256_hw_init(&ctx);
- SHA256_update(&ctx, in, sizeof(in));
- return !(fips_break_cmd == FIPS_BREAK_SHA256) &&
- (DCRYPTO_equals(SHA256_final(&ctx), ans, SHA256_DIGEST_SIZE) ==
- DCRYPTO_OK);
+ memcpy(in_mem, in, sizeof(in));
+ if (fips_break_cmd == FIPS_BREAK_SHA256)
+ in_mem[0] ^= 1;
+
+ SHA256_update(&ctx, in_mem, sizeof(in_mem));
+ return DCRYPTO_equals(SHA256_final(&ctx), ans, SHA256_DIGEST_SIZE) ==
+ DCRYPTO_OK;
}
/* KAT for HMAC-SHA256, test values from OpenSSL. */
@@ -172,6 +177,8 @@ static bool fips_hmac_sha256_kat(void)
static const uint8_t in[] =
/* "Sample text" */ { 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65,
0x20, 0x74, 0x65, 0x78, 0x74 };
+ uint8_t in_mem[sizeof(in)];
+
static const uint8_t ans[] = { 0xe9, 0x17, 0xc1, 0x7b, 0x4c, 0x6b, 0x77,
0xda, 0xd2, 0x30, 0x36, 0x02, 0xf5, 0x72,
0x33, 0x87, 0x9f, 0xc6, 0x6e, 0x7b, 0x7e,
@@ -179,10 +186,12 @@ static bool fips_hmac_sha256_kat(void)
0xff, 0xda, 0x24, 0xf4 };
HMAC_SHA256_hw_init(&ctx, k, sizeof(k));
- HMAC_SHA256_update(&ctx, in, sizeof(in));
- return !(fips_break_cmd == FIPS_BREAK_HMAC_SHA256) &&
- (DCRYPTO_equals(HMAC_SHA256_hw_final(&ctx), ans,
- SHA256_DIGEST_SIZE) == DCRYPTO_OK);
+ memcpy(in_mem, in, sizeof(in));
+ if (fips_break_cmd == FIPS_BREAK_SHA256)
+ in_mem[0] ^= 1;
+ HMAC_SHA256_update(&ctx, in_mem, sizeof(in_mem));
+ return DCRYPTO_equals(HMAC_SHA256_hw_final(&ctx), ans,
+ SHA256_DIGEST_SIZE) == DCRYPTO_OK;
}
/**
@@ -325,23 +334,26 @@ static bool fips_hmac_drbg_generate_kat(struct drbg_ctx *ctx)
0xf1, 0x32, 0xf6, 0x86, 0xb7, 0x60, 0xf0, 0x12
};
uint8_t buf[128];
+ int passed;
+
+ passed = hmac_drbg_generate(ctx, buf, sizeof(buf), NULL, 0) -
+ HMAC_DRBG_SUCCESS;
- hmac_drbg_generate(ctx, buf, sizeof(buf), NULL, 0);
/* Verify internal drbg state */
- if (DCRYPTO_equals(ctx->v, V2, sizeof(V2)) != DCRYPTO_OK ||
- DCRYPTO_equals(ctx->k, K2, sizeof(K2)) != DCRYPTO_OK) {
- return false;
- }
+ passed |= DCRYPTO_equals(ctx->v, V2, sizeof(V2)) - DCRYPTO_OK;
+ passed |= DCRYPTO_equals(ctx->k, K2, sizeof(K2)) - DCRYPTO_OK;
- hmac_drbg_reseed(ctx, drbg_entropy2, sizeof(drbg_entropy2),
- drbg_addtl_input2, sizeof(drbg_addtl_input2), NULL, 0);
- /**
- * reuse entropy buffer to avoid allocating too much stack and memory
- * it will be cleaned up in TRNG health test
- */
- hmac_drbg_generate(ctx, buf, sizeof(buf), NULL, 0);
- return !(fips_break_cmd == FIPS_BREAK_HMAC_DRBG) &&
- DCRYPTO_equals(buf, KA, sizeof(KA) == DCRYPTO_OK);
+ memcpy(buf, drbg_entropy2, sizeof(drbg_entropy2));
+ if (fips_break_cmd == FIPS_BREAK_HMAC_DRBG)
+ buf[0] ^= 1;
+
+ hmac_drbg_reseed(ctx, buf, sizeof(drbg_entropy2), drbg_addtl_input2,
+ sizeof(drbg_addtl_input2), NULL, 0);
+
+ passed |= hmac_drbg_generate(ctx, buf, sizeof(buf), NULL, 0) -
+ HMAC_DRBG_SUCCESS;
+ passed |= DCRYPTO_equals(buf, KA, sizeof(KA)) - DCRYPTO_OK;
+ return passed == 0;
}
/* Known-answer test for HMAC_DRBG SHA256. */
@@ -354,58 +366,113 @@ static bool fips_hmac_drbg_kat(void)
fips_hmac_drbg_generate_kat(&ctx);
}
-/* Known-answer test for ECDSA NIST P-256 verify. */
-static bool fips_ecdsa_verify_kat(void)
+#ifdef CONFIG_FIPS_ECDSA_PWCT
+static bool fips_ecdsa_sign_pwct(void)
{
- static const p256_int qx = { .a = { 0xf49abf3c, 0xf82e6e12, 0x7a67c074,
- 0x5134e16f, 0xf8957a0c, 0xef4344a7,
- 0xd4bb3cb7, 0xe424dc61 } };
- static const p256_int qy = { .a = { 0xdfaee927, 0x3d6f60e7, 0xac85d124,
- 0x127e5965, 0xe1dddaf0, 0x1545949d,
- 0xa2bc4865, 0x970eed7a } };
- static const p256_int r = { .a = { 0xd9347f4f, 0xb72f981f, 0x6349b9da,
- 0x2ff540c7, 0x42017c64, 0x910be331,
- 0xa49c705c, 0xbf96b99a } };
- static const p256_int s = { .a = { 0x57ec871c, 0x920b9e0f, 0x75d98f31,
- 0x444e3230, 0x15abdf12, 0xe03b9cd4,
- 0x819089c2, 0x17c55095 } };
- static const uint8_t msg[128] = {
- 0xe1, 0x13, 0x0a, 0xf6, 0xa3, 0x8c, 0xcb, 0x41, 0x2a, 0x9c,
- 0x8d, 0x13, 0xe1, 0x5d, 0xbf, 0xc9, 0xe6, 0x9a, 0x16, 0x38,
- 0x5a, 0xf3, 0xc3, 0xf1, 0xe5, 0xda, 0x95, 0x4f, 0xd5, 0xe7,
- 0xc4, 0x5f, 0xd7, 0x5e, 0x2b, 0x8c, 0x36, 0x69, 0x92, 0x28,
- 0xe9, 0x28, 0x40, 0xc0, 0x56, 0x2f, 0xbf, 0x37, 0x72, 0xf0,
- 0x7e, 0x17, 0xf1, 0xad, 0xd5, 0x65, 0x88, 0xdd, 0x45, 0xf7,
- 0x45, 0x0e, 0x12, 0x17, 0xad, 0x23, 0x99, 0x22, 0xdd, 0x9c,
- 0x32, 0x69, 0x5d, 0xc7, 0x1f, 0xf2, 0x42, 0x4c, 0xa0, 0xde,
- 0xc1, 0x32, 0x1a, 0xa4, 0x70, 0x64, 0xa0, 0x44, 0xb7, 0xfe,
- 0x3c, 0x2b, 0x97, 0xd0, 0x3c, 0xe4, 0x70, 0xa5, 0x92, 0x30,
- 0x4c, 0x5e, 0xf2, 0x1e, 0xed, 0x9f, 0x93, 0xda, 0x56, 0xbb,
- 0x23, 0x2d, 0x1e, 0xeb, 0x00, 0x35, 0xf9, 0xbf, 0x0d, 0xfa,
- 0xfd, 0xcc, 0x46, 0x06, 0x27, 0x2b, 0x20, 0xa3
- };
+ /**
+ * Use fixed key pair:
+ * d = 1
+ * x = 6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296
+ * y = 4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5
+ */
+ p256_int d;
+ static const p256_int x = { .a = { 0xD898C296, 0xF4A13945, 0x2DEB33A0,
+ 0x77037D81, 0x63A440F2, 0xF8BCE6E5,
+ 0xE12C4247, 0x6B17D1F2 } };
- p256_int p256_digest;
- struct sha256_digest digest;
- uint8_t bad_msg[128];
+ static const p256_int y = { .a = { 0x37BF51F5, 0xCBB64068, 0x6B315ECE,
+ 0x2BCE3357, 0x7C0F9E16, 0x8EE7EB4A,
+ 0xFE1A7F9B, 0x4FE342E2 } };
+
+ memset(&d, 0, sizeof(d));
+ d.a[0] = 1; /* d = 1 in little-endian */
+
+ /**
+ * Note, fips_drbg is not instantiated yet, but rather is in
+ * pre-determined state with K=[0], V=[0].
+ */
+ return DCRYPTO_p256_key_pwct(&fips_drbg, &d, &x, &y);
+}
+#endif
+
+/**
+ * Test vector from https://csrc.nist.gov/CSRC/media/Projects/
+ * Cryptographic-Algorithm-Validation-Program/
+ * documents/dss/186-4ecdsatestvectors.zip
+ * P-256, SHA2-256, case 1
+ *
+ * Msg = 5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf41
+ * 6983fe165b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e
+ * 253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9
+ * d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8
+ * digest = 0x44, 0xac, 0xf6, 0xb7, 0xe3, 0x6c, 0x13, 0x42, 0xc2, 0xc5, 0x89,
+ * 0x72, 0x04, 0xfe, 0x09, 0x50, 0x4e, 0x1e, 0x2e, 0xfb, 0x1a, 0x90,
+ * 0x03, 0x77, 0xdb, 0xc4, 0xe7, 0xa6, 0xa1, 0x33, 0xec, 0x56
+ * d = 519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464
+ * Qx = 1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83
+ * Qy = ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9
+ * k = 94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de
+ * R = f3ac8061b514795b8843e3d6629527ed2afd6b1f6a555a7acabb5e6f79c8c2ac
+ * S = 8bf77819ca05a6b2786c76262bf7371cef97b218e96f175a3ccdda2acc058903
+ *
+ * All values are stored in internal little-endian representation.
+ *
+ */
+static bool fips_ecdsa_sign_verify_kat(void)
+{
+ static const uint8_t msg_digest[32] = {
+ 0x44, 0xac, 0xf6, 0xb7, 0xe3, 0x6c, 0x13, 0x42,
+ 0xc2, 0xc5, 0x89, 0x72, 0x04, 0xfe, 0x09, 0x50,
+ 0x4e, 0x1e, 0x2e, 0xfb, 0x1a, 0x90, 0x03, 0x77,
+ 0xdb, 0xc4, 0xe7, 0xa6, 0xa1, 0x33, 0xec, 0x56
+ };
+ static const p256_int d = { .a = { 0xda72b464, 0xca54a56d, 0x0b4e3eac,
+ 0x5b44c813, 0x59f4771a, 0x1f4fa8ee,
+ 0x715f8b58, 0x519b423d } };
+
+ static const p256_int k = { .a = { 0x642a68de, 0xb9670787, 0x824f5d33,
+ 0x3b4a6247, 0xf9e93c7f, 0xa280f245,
+ 0x4b906a61, 0x94a1bbb1 } };
+
+ static const p256_int Qx = { .a = { 0xc271bf83, 0x3c59ff46, 0x4bbfb12f,
+ 0xd3565de9, 0x48db8fcc, 0xf033bfa2,
+ 0x075fc7f4, 0x1ccbe91c } };
+ static const p256_int Qy = { .a = { 0xa89a4ca9, 0xdc7ccd5c, 0xb7404e78,
+ 0x6db7ca93, 0x0e6113e0, 0x1a1fdb2c,
+ 0x8811f9a2, 0xce4014c6 } };
+ static const p256_int R = { .a = { 0x79c8c2ac, 0xcabb5e6f, 0x6a555a7a,
+ 0x2afd6b1f, 0x629527ed, 0x8843e3d6,
+ 0xb514795b, 0xf3ac8061 } };
+
+ static const p256_int S = { .a = { 0xcc058903, 0x3ccdda2a, 0xe96f175a,
+ 0xef97b218, 0x2bf7371c, 0x786c7626,
+ 0xca05a6b2, 0x8bf77819 } };
+
+ p256_int msg, r, s;
int passed;
- SHA256_hw_hash(msg, sizeof(msg), &digest);
- p256_from_bin(digest.b8, &p256_digest);
- passed = dcrypto_p256_ecdsa_verify(&qx, &qy, &p256_digest, &r, &s);
- if (!passed)
- return false;
+ p256_from_bin(msg_digest, &msg);
+
+ /* KAT for ECDSA signing with fixed k. */
+ passed = dcrypto_p256_ecdsa_sign_raw(&k, &d, &msg, &r, &s) - 1;
+
+ passed |= DCRYPTO_equals(r.a, R.a, sizeof(R)) - DCRYPTO_OK;
+ passed |= DCRYPTO_equals(s.a, S.a, sizeof(S)) - DCRYPTO_OK;
+
+ if (fips_break_cmd == FIPS_BREAK_ECDSA)
+ msg.a[0] ^= 1;
+
+ /* KAT for verification */
+ passed |= dcrypto_p256_ecdsa_verify(&Qx, &Qy, &msg, &r, &s) - 1;
+
/**
- * create bad_msg same as msg but has one bit flipped in byte 92 (0x0a
- * vs 0x1a) this is to save space in flash vs. having bad message as
- * constant
+ * Flip 1 bit in digest. Signature verification should fail.
*/
- memcpy(bad_msg, msg, sizeof(msg));
- bad_msg[92] ^= 0x10;
- SHA256_hw_hash(bad_msg, sizeof(bad_msg), &digest);
- p256_from_bin(digest.b8, &p256_digest);
- passed = dcrypto_p256_ecdsa_verify(&qx, &qy, &p256_digest, &r, &s);
- return !(fips_break_cmd == FIPS_BREAK_ECDSA) && (passed == 0);
+ msg.a[5] ^= 0x10;
+
+ passed |= dcrypto_p256_ecdsa_verify(&Qx, &Qy, &msg, &r, &s);
+
+ return passed == 0;
}
#ifdef CONFIG_FIPS_AES_CBC_256
@@ -607,6 +674,10 @@ void fips_power_up_tests(void)
starttime = fips_vtable->get_time().val;
+ /* SHA2-256 is used for self-integrity test, so check it first. */
+ if (!fips_sha256_kat())
+ _fips_status |= FIPS_FATAL_SHA256;
+
if (fips_self_integrity() != DCRYPTO_OK)
_fips_status |= FIPS_FATAL_SELF_INTEGRITY;
@@ -621,8 +692,6 @@ void fips_power_up_tests(void)
if (EC_SUCCESS ==
fips_vtable->shared_mem_acquire(FIPS_KAT_STACK_SIZE, &stack_buf)) {
stack = stack_buf + FIPS_KAT_STACK_SIZE;
- if (!call_on_stack(stack, &fips_sha256_kat))
- _fips_status |= FIPS_FATAL_SHA256;
if (!call_on_stack(stack, &fips_hmac_sha256_kat))
_fips_status |= FIPS_FATAL_HMAC_SHA256;
/**
@@ -632,12 +701,18 @@ void fips_power_up_tests(void)
* first call to TRNG warm-up
*/
fips_trng_startup(0);
- if (!call_on_stack(stack, &fips_ecdsa_verify_kat))
- _fips_status |= FIPS_FATAL_ECDSA;
if (!call_on_stack(stack, &fips_hmac_drbg_kat))
_fips_status |= FIPS_FATAL_HMAC_DRBG;
+#ifdef CONFIG_FIPS_ECDSA_PWCT
+ if (!call_on_stack(stack, &fips_ecdsa_sign_pwct))
+ _fips_status |= FIPS_FATAL_ECDSA;
+#endif
+
+ if (!call_on_stack(stack, &fips_ecdsa_sign_verify_kat))
+ _fips_status |= FIPS_FATAL_ECDSA;
+
#ifdef CONFIG_FIPS_AES_CBC_256
if (!call_on_stack(stack, &fips_aes256_kat))
_fips_status |= FIPS_FATAL_AES256;
diff --git a/board/cr50/dcrypto/fips_rand.c b/board/cr50/dcrypto/fips_rand.c
index 926af66f96..dff7c1a61b 100644
--- a/board/cr50/dcrypto/fips_rand.c
+++ b/board/cr50/dcrypto/fips_rand.c
@@ -18,7 +18,7 @@
* Since raw TRNG input shouldn't be used as random number generator,
* all FIPS-compliant code use DRBG, seeded from TRNG
*/
-static struct drbg_ctx fips_drbg;
+struct drbg_ctx fips_drbg;
#define ENTROPY_SIZE_BITS 512
#define ENTROPY_SIZE_WORDS (BITS_TO_WORDS(ENTROPY_SIZE_BITS))
@@ -276,6 +276,17 @@ void fips_drbg_clear(void)
rand_state.drbg_initialized = 0;
}
+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;
+
+ hmac_drbg_reseed(ctx, entropy_fifo, sizeof(entropy_fifo),
+ NULL, 0, NULL, 0);
+ return true;
+}
+
enum hmac_result fips_hmac_drbg_generate_reseed(struct drbg_ctx *ctx, void *out,
size_t out_len,
const void *input,
@@ -285,14 +296,8 @@ enum hmac_result fips_hmac_drbg_generate_reseed(struct drbg_ctx *ctx, void *out,
hmac_drbg_generate(ctx, out, out_len, input, input_len);
while (err == HMAC_DRBG_RESEED_REQUIRED) {
- /* read another 512 bits of noise */
- if (!fips_trng_bytes(&entropy_fifo, sizeof(entropy_fifo))) {
- /* FIPS error is reported by failed TRNG test. */
+ if (!fips_drbg_reseed_with_entropy(ctx))
return HMAC_DRBG_RESEED_REQUIRED;
- }
-
- hmac_drbg_reseed(ctx, entropy_fifo, sizeof(entropy_fifo), NULL,
- 0, NULL, 0);
err = hmac_drbg_generate(ctx, out, out_len, input, input_len);
}
return err;
@@ -323,6 +328,19 @@ bool fips_rand_bytes(void *buffer, size_t len)
return true;
}
+enum hmac_result fips_p256_hmac_drbg_generate(struct drbg_ctx *drbg,
+ p256_int *out)
+{
+ enum hmac_result err = p256_hmac_drbg_generate(drbg, out);
+
+ while (err == HMAC_DRBG_RESEED_REQUIRED) {
+ if (!fips_drbg_reseed_with_entropy(drbg))
+ return HMAC_DRBG_RESEED_REQUIRED;
+ err = p256_hmac_drbg_generate(drbg, out);
+ }
+ return err;
+}
+
/* return codes match dcrypto_p256_ecdsa_sign */
int fips_p256_ecdsa_sign(const p256_int *key, const p256_int *message,
p256_int *r, p256_int *s)
@@ -332,7 +350,7 @@ int fips_p256_ecdsa_sign(const p256_int *key, const p256_int *message,
if (!rand_state.drbg_initialized && !fips_drbg_init())
return false;
- return dcrypto_p256_ecdsa_sign(&fips_drbg, key, message, r, s);
+ return dcrypto_p256_fips_sign_internal(&fips_drbg, key, message, r, s);
}
#ifndef CRYPTO_TEST_CMD_RAND_PERF
diff --git a/board/cr50/dcrypto/fips_rand.h b/board/cr50/dcrypto/fips_rand.h
index dca1f473bf..e42451cb0d 100644
--- a/board/cr50/dcrypto/fips_rand.h
+++ b/board/cr50/dcrypto/fips_rand.h
@@ -117,6 +117,20 @@ void fips_drbg_init_clear(void);
/* random bytes using FIPS-compliant HMAC_DRBG */
bool fips_rand_bytes(void *buffer, size_t len);
+/* 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 HMAC_DRBG_SUCCESS if out contains random.
+ */
+enum hmac_result fips_p256_hmac_drbg_generate(struct drbg_ctx *drbg,
+ p256_int *out);
+
/* wrapper around dcrypto_p256_ecdsa_sign using FIPS-compliant HMAC_DRBG */
int fips_p256_ecdsa_sign(const p256_int *key, const p256_int *message,
p256_int *r, p256_int *s);
diff --git a/board/cr50/dcrypto/internal.h b/board/cr50/dcrypto/internal.h
index b88d0a1d25..d681a1c1fb 100644
--- a/board/cr50/dcrypto/internal.h
+++ b/board/cr50/dcrypto/internal.h
@@ -219,6 +219,20 @@ void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst);
*/
bool p256_from_be_bin_size(const uint8_t *src, size_t len, p256_int *dst);
+/**
+ * Raw sign with provided nonce (k). Used internally and for testing.
+ *
+ * @param k - valid nonce for ECDSA sign
+ * @param key - valid private key for ECDSA sign
+ * @param message - message to sign encoded as p-256 int
+ * @param r - generated signature
+ * @param s - generated signature
+ * @return !0 if success
+ */
+int dcrypto_p256_ecdsa_sign_raw(const p256_int *k, const p256_int *key,
+ const p256_int *message, p256_int *r,
+ p256_int *s);
+
int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
const p256_int *message, p256_int *r, p256_int *s)
__attribute__((warn_unused_result));
@@ -241,6 +255,21 @@ void p256_fast_random(p256_int *rnd);
/* Generate a p256 number between 1 < k < |p256| using provided DRBG. */
enum hmac_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.
+ *
+ * @param drbg DRBG to use
+ * @param key P-256 private key
+ * @param message - Message to sign as P-256 (in little-endian)
+ * @param r - Generated signature
+ * @param s - Generated signature
+ * @return int
+ */
+int dcrypto_p256_fips_sign_internal(struct drbg_ctx *drbg, const p256_int *key,
+ const p256_int *message, p256_int *r,
+ p256_int *s);
+
/* Initialize for use as RFC6979 DRBG. */
void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx,
const p256_int *key,
diff --git a/board/cr50/dcrypto/p256_ec.c b/board/cr50/dcrypto/p256_ec.c
index 4c97c521fc..fe0f69c92b 100644
--- a/board/cr50/dcrypto/p256_ec.c
+++ b/board/cr50/dcrypto/p256_ec.c
@@ -38,7 +38,27 @@ int 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);
}
-int DCRYPTO_p256_key_pwct(p256_int *d, p256_int *x, p256_int *y)
+
+int dcrypto_p256_fips_sign_internal(struct drbg_ctx *drbg, const p256_int *key,
+ const p256_int *message, p256_int *r,
+ p256_int *s)
+{
+ int result;
+ p256_int k;
+
+ /* Pick uniform 0 < k < R */
+ result = fips_p256_hmac_drbg_generate(drbg, &k) - HMAC_DRBG_SUCCESS;
+
+ result |= dcrypto_p256_ecdsa_sign_raw(&k, key, message, r, s) - 1;
+
+ /* Wipe temp k */
+ p256_clear(&k);
+
+ return result == 0;
+}
+
+int DCRYPTO_p256_key_pwct(struct drbg_ctx *drbg, const p256_int *d,
+ const p256_int *x, const p256_int *y)
{
p256_int message, r, s;
int result;
@@ -49,7 +69,7 @@ int DCRYPTO_p256_key_pwct(p256_int *d, p256_int *x, p256_int *y)
/* set some pseudo-random message. */
p256_fast_random(&message);
- if (fips_p256_ecdsa_sign(d, &message, &r, &s) == 0)
+ if (dcrypto_p256_fips_sign_internal(drbg, d, &message, &r, &s) == 0)
return 0;
#ifdef CRYPTO_TEST_SETUP
@@ -93,5 +113,5 @@ int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
if (dcrypto_p256_base_point_mul(d, x, y) == 0)
return 0;
- return DCRYPTO_p256_key_pwct(d, x, y);
+ return DCRYPTO_p256_key_pwct(&fips_drbg, d, x, y);
}
diff --git a/include/config.h b/include/config.h
index 475c56f13f..6d8f7c6544 100644
--- a/include/config.h
+++ b/include/config.h
@@ -4901,5 +4901,7 @@
#undef CONFIG_FIPS_SW_HMAC_DRBG
/* Don't run AES CBC 256 test (not used for U2F anymore). */
#undef CONFIG_FIPS_AES_CBC_256
+/* Don't use ECDSA pair-wise consistency test. We verify sign/verify. */
+#undef CONFIG_FIPS_ECDSA_PWCT
#endif /* __CROS_EC_CONFIG_H */