diff options
author | Vadim Sukhomlinov <sukhomlinov@google.com> | 2021-09-23 10:08:49 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-09-24 00:14:58 +0000 |
commit | 5044b81a4c797a058a21e95349437f04ab33e2ed (patch) | |
tree | 73a3592d60e2acaf46cd0a8bfb027b4b49f79a2d | |
parent | 78d460f72b65a2a01f81c2bc115da96bc331f5df (diff) | |
download | chrome-ec-5044b81a4c797a058a21e95349437f04ab33e2ed.tar.gz |
cr50: switch ECDSA to use enum dcrypto_result, added FIPS checks
We have to block access to crypto functions when FIPS errors occurred.
To achieve this:
1. Provide wrappers for ECDSA P-256 sign and verify functions
a) DCRYPTO_p256_ecdsa_verify as wrapper for dcrypto_p256_ecdsa_verify
b) DCRYPTO_p256_ecdsa_sign as wrapper for
dcrypto_p256_fips_sign_internal with additional check for FIPS
DRBG initialization which is needed for signing.
2. Switch all ECDSA functions, both internal and external to use
enum dcrypto_result instead of inconsistent 0/1 values.
3. Added warning for unused result code for ECDSA functions.
4. Updated documentation for public APIs
5. In DCRYPTO_p256_key_from_bytes() implemented clear distinction between
bad candidate and failures due to FIPS or pair-wise consistency.
6. U2F, rma_auth, TPM ecc, etc updated to use new return codes.
BUG=b:197893750
TEST=make BOARD=cr50 CRYPTO_TEST=1; rma_auth, u2f_test, etc.
test/tpm_test/tpmtest.py
TCG tests
----------------------------- Test Result Summary ----------------------
Test executed on: Thu Sep 23 09:56:42 2021
Performed Tests: 248
Passed Tests: 248
Failed Tests: 0
Errors: 0
Warnings: 0
========================================================================
Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com>
Change-Id: I0251bf511771c1c1fd281f6db706d1dedac3e8b8
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3179708
Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Auto-Submit: Vadim Sukhomlinov <sukhomlinov@chromium.org>
-rw-r--r-- | board/cr50/dcrypto/dcrypto.h | 91 | ||||
-rw-r--r-- | board/cr50/dcrypto/dcrypto_p256.c | 43 | ||||
-rw-r--r-- | board/cr50/dcrypto/dcrypto_runtime.c | 31 | ||||
-rw-r--r-- | board/cr50/dcrypto/fips.c | 10 | ||||
-rw-r--r-- | board/cr50/dcrypto/fips_rand.c | 11 | ||||
-rw-r--r-- | board/cr50/dcrypto/internal.h | 127 | ||||
-rw-r--r-- | board/cr50/dcrypto/p256.c | 1 | ||||
-rw-r--r-- | board/cr50/dcrypto/p256_ec.c | 86 | ||||
-rw-r--r-- | board/cr50/dcrypto/p256_ecies.c | 14 | ||||
-rw-r--r-- | board/cr50/dcrypto/u2f.c | 49 | ||||
-rw-r--r-- | board/cr50/dcrypto/x509.c | 2 | ||||
-rw-r--r-- | board/cr50/tpm2/ecc.c | 37 | ||||
-rw-r--r-- | board/host/dcrypto.h | 6 | ||||
-rw-r--r-- | common/rma_auth.c | 12 | ||||
-rw-r--r-- | test/u2f.c | 20 |
15 files changed, 353 insertions, 187 deletions
diff --git a/board/cr50/dcrypto/dcrypto.h b/board/cr50/dcrypto/dcrypto.h index 36f2c40fee..d7ce9ebc8c 100644 --- a/board/cr50/dcrypto/dcrypto.h +++ b/board/cr50/dcrypto/dcrypto.h @@ -46,6 +46,10 @@ enum hashing_mode { HASH_NULL = 4 /* Only supported for PKCS#1 signing */ }; +#ifndef __warn_unused_result +#define __warn_unused_result __attribute__((warn_unused_result)) +#endif + /* * AES implementation, based on a hardware AES block. * FIPS Publication 197, The Advanced Encryption Standard (AES) @@ -333,53 +337,92 @@ bool p256_from_be_bin_size(const uint8_t *src, size_t len, p256_int *dst); * * @param x point coordinate * @param y point coordinate + * * @return DCRYPTO_OK if (x,y) is a valid point, DCRYPTO_FAIL otherwise */ -enum dcrypto_result DCRYPTO_p256_is_valid_point(const p256_int *x, - const p256_int *y); +enum dcrypto_result DCRYPTO_p256_is_valid_point( + const p256_int *x, const p256_int *y) __warn_unused_result; -/* DCRYPTO_p256_base_point_mul sets {out_x,out_y} = nG, where n is < the - * order of the group. +/** + * Base point multiplications (compute public key from private). + * Sets {out_x,out_y} = nG, where n is < the order of the group. + * + * @param out_x output public key component x + * @param out_y output public key component y + * @param n private key + * + * @return DCRYPTO_OK if successful */ -int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, - const p256_int *n); +enum dcrypto_result DCRYPTO_p256_base_point_mul( + p256_int *out_x, p256_int *out_y, + const p256_int *n) __warn_unused_result; /** * DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < * the order of the group. Prior to computation check than {in_x,in_y} is - * on NIST P-256 curve. + * on NIST P-256 curve. Used to implement ECDH. * * @param out_x output shared coordinate x * @param out_y output shared coordinate y * @param n private key * @param in_x input public point x * @param in_y input public point y - * @return 1 if success + * + * @return DCRYPTO_OK if success */ -int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, const p256_int *n, - const p256_int *in_x, const p256_int *in_y); -/* +enum dcrypto_result DCRYPTO_p256_point_mul( + p256_int *out_x, p256_int *out_y, const p256_int *n, + const p256_int *in_x, const p256_int *in_y) __warn_unused_result; + +/** * Key selection based on FIPS-186-4, section B.4.2 (Key Pair * Generation by Testing Candidates). - * Produce uniform private key from seed. + * + * @param x output public key component x + * @param y output public key component y + * @param d output private key + * @param bytes 32 byte random seed + * + * d = p256_from_bytes(bytes) + 1 + * * If x or y is NULL, the public key part is not computed. - * Returns !0 on success. + * + * @return DCRYPTO_OK on success, DCRYPTO_RETRY if d is out of range, try + * with another seed bytes and DCRYPTO_FAIL for any other error. */ -int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, - const uint8_t bytes[P256_NBYTES]); +enum dcrypto_result DCRYPTO_p256_key_from_bytes( + p256_int *x, p256_int *y, p256_int *d, + const uint8_t bytes[P256_NBYTES]) __warn_unused_result; /** - * TODO: Provide provide proper wrappers for dcrypto_p256_ecdsa_verify() - * and fips_p256_ecdsa_sign() + * Verify NIST P-256 signature. + * + * @param key_x public key coordinate x + * @param key_y public key coordinate x + * @param message message digest to verify + * @param r signature component r + * @param s signature component s + * + * @return DCRYPTO_OK if success */ -int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, - const p256_int *message, const p256_int *r, - const p256_int *s) - __attribute__((warn_unused_result)); +enum dcrypto_result DCRYPTO_p256_ecdsa_verify( + const p256_int *key_x, const p256_int *key_y, const p256_int *message, + const p256_int *r, const p256_int *s) __warn_unused_result; -/* 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); +/** + * NIST ECDSA P-256 Sign. + * + * @param key private key + * @param message message digest (in p256_int form) + * @param r output signature component r + * @param s output signature component s + * + * @return DCRYPTO_OK if success. + */ +enum dcrypto_result DCRYPTO_p256_ecdsa_sign(const p256_int *key, + const p256_int *message, + p256_int *r, + p256_int *s) __warn_unused_result; /************************************************************/ diff --git a/board/cr50/dcrypto/dcrypto_p256.c b/board/cr50/dcrypto/dcrypto_p256.c index 841259cef7..bb9aff456c 100644 --- a/board/cr50/dcrypto/dcrypto_p256.c +++ b/board/cr50/dcrypto/dcrypto_p256.c @@ -134,8 +134,10 @@ static void dcrypto_ecc_init(void) CP1W(d, 0, 8); } -int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, - const p256_int *message, p256_int *r, p256_int *s) +enum dcrypto_result 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 nonce; @@ -143,17 +145,19 @@ int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, /* 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; + result |= dcrypto_p256_ecdsa_sign_raw(&nonce, key, message, r, s) - + DCRYPTO_OK; /* Wipe temp nonce */ p256_clear(&nonce); - return result == 0; + return dcrypto_ok_if_zero(result); } -int dcrypto_p256_ecdsa_sign_raw(const p256_int *nonce, const p256_int *key, - const p256_int *message, p256_int *r, - p256_int *s) +enum dcrypto_result 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; @@ -186,10 +190,11 @@ int dcrypto_p256_ecdsa_sign_raw(const p256_int *nonce, const p256_int *key, CP8W(k, &rnd); dcrypto_unlock(); - return result == 0; + return dcrypto_ok_if_zero(result); } -int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) +enum dcrypto_result dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, + p256_int *y) { int result; p256_int rnd; @@ -217,11 +222,13 @@ int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) CP8W(d, &dmem_ecc->rnd); dcrypto_unlock(); - return result == 0; + return dcrypto_ok_if_zero(result); } -int dcrypto_p256_point_mul(const p256_int *k, const p256_int *in_x, - const p256_int *in_y, p256_int *x, p256_int *y) +enum dcrypto_result dcrypto_p256_point_mul(const p256_int *k, + const p256_int *in_x, + const p256_int *in_y, p256_int *x, + p256_int *y) { int result; p256_int rnd; @@ -254,12 +261,14 @@ int dcrypto_p256_point_mul(const p256_int *k, const p256_int *in_x, CP8W(y, &rnd); dcrypto_unlock(); - return result == 0; + return dcrypto_ok_if_zero(result); } -int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, - const p256_int *message, const p256_int *r, - const p256_int *s) +enum dcrypto_result dcrypto_p256_ecdsa_verify(const p256_int *key_x, + const p256_int *key_y, + const p256_int *message, + const p256_int *r, + const p256_int *s) { int i, result; @@ -279,7 +288,7 @@ int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, result |= (dmem_ecc->rnd.a[i] ^ r->a[i]); dcrypto_unlock(); - return result == 0; + return dcrypto_ok_if_zero(result); } enum dcrypto_result dcrypto_p256_is_valid_point(const p256_int *x, diff --git a/board/cr50/dcrypto/dcrypto_runtime.c b/board/cr50/dcrypto/dcrypto_runtime.c index 618d355362..0c79d34310 100644 --- a/board/cr50/dcrypto/dcrypto_runtime.c +++ b/board/cr50/dcrypto/dcrypto_runtime.c @@ -367,11 +367,11 @@ static const p256_int s_golden = { 0xd55d07a0, 0x1efb1274, 0x94afb5c9 }, }; -static int call_on_bigger_stack(uint32_t stack, - int (*func)(p256_int *, p256_int *), - p256_int *r, p256_int *s) +static enum dcrypto_result call_on_bigger_stack( + uint32_t stack, enum dcrypto_result (*func)(p256_int *, p256_int *), + p256_int *r, p256_int *s) { - int result = 0; + enum dcrypto_result result = DCRYPTO_FAIL; /* Move to new stack and call the function */ __asm__ volatile("mov r4, sp\n" @@ -384,10 +384,8 @@ static int call_on_bigger_stack(uint32_t stack, : [result] "=r"(result) /* output */ : [new_stack] "r"(stack), [r] "r"(r), [s] "r"(s), [func] "r"(func) /* input */ - : "r0", "r1", "r2", "r3", "r4", - "lr" /* clobbered registers */ - ); - + : /* clobbered registers */ + "r0", "r1", "r2", "r3", "r4", "lr"); return result; } @@ -396,11 +394,11 @@ static int call_on_bigger_stack(uint32_t stack, * in: r - ptr to entropy, s - ptr to message. * out: r,s - generated signature. */ -static int ecdsa_sign_go(p256_int *r, p256_int *s) +static enum dcrypto_result ecdsa_sign_go(p256_int *r, p256_int *s) { struct drbg_ctx drbg; p256_int d; - int ret = 0; + enum dcrypto_result ret = 0; p256_int message = *s; /* drbg init with same entropy */ @@ -410,7 +408,7 @@ static int ecdsa_sign_go(p256_int *r, p256_int *s) if (p256_hmac_drbg_generate(&drbg, &d) != HMAC_DRBG_SUCCESS) { /* to be consistent with ecdsa_sign error return */ drbg_exit(&drbg); - return 0; + return DCRYPTO_FAIL; } /* drbg_reseed with entropy and message */ @@ -427,7 +425,8 @@ static int command_dcrypto_ecdsa_test(int argc, char *argv[]) { p256_int entropy, message, r, s; struct sha256_ctx hsh; - int result = 0; + enum dcrypto_result result = DCRYPTO_FAIL; + enum ec_error_list ret; char *new_stack; const uint32_t new_stack_size = 2 * 1024; @@ -444,11 +443,11 @@ static int command_dcrypto_ecdsa_test(int argc, char *argv[]) r = entropy; s = message; - result = shared_mem_acquire(new_stack_size, &new_stack); + ret = shared_mem_acquire(new_stack_size, &new_stack); - if (result != EC_SUCCESS) { + if (ret != EC_SUCCESS) { ccprintf("Failed to acquire stack memory: %d\n", result); - return result; + return ret; } for (uint32_t i = 0; i < ECDSA_TEST_ITERATIONS; i++) { @@ -456,7 +455,7 @@ static int command_dcrypto_ecdsa_test(int argc, char *argv[]) new_stack_size, ecdsa_sign_go, &r, &s); - if (!result) { + if (result != DCRYPTO_OK) { ccprintf("ECDSA TEST fail: %d\n", result); return EC_ERROR_INVAL; } diff --git a/board/cr50/dcrypto/fips.c b/board/cr50/dcrypto/fips.c index b3b401fdfb..391fee5657 100644 --- a/board/cr50/dcrypto/fips.c +++ b/board/cr50/dcrypto/fips.c @@ -389,7 +389,7 @@ static bool fips_ecdsa_sign_pwct(void) * 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); + return dcrypto_p256_key_pwct(&fips_drbg, &d, &x, &y) == DCRYPTO_OK; } #endif @@ -452,7 +452,7 @@ static bool fips_ecdsa_sign_verify_kat(void) 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_p256_ecdsa_sign_raw(&k, &d, &msg, &r, &s) - DCRYPTO_OK; passed |= DCRYPTO_equals(r.a, R.a, sizeof(R)) - DCRYPTO_OK; passed |= DCRYPTO_equals(s.a, S.a, sizeof(S)) - DCRYPTO_OK; @@ -461,14 +461,16 @@ static bool fips_ecdsa_sign_verify_kat(void) msg.a[0] ^= 1; /* KAT for verification */ - passed |= dcrypto_p256_ecdsa_verify(&Qx, &Qy, &msg, &r, &s) - 1; + passed |= + dcrypto_p256_ecdsa_verify(&Qx, &Qy, &msg, &r, &s) - DCRYPTO_OK; /** * Flip 1 bit in digest. Signature verification should fail. */ msg.a[5] ^= 0x10; - passed |= dcrypto_p256_ecdsa_verify(&Qx, &Qy, &msg, &r, &s); + passed |= dcrypto_p256_ecdsa_verify(&Qx, &Qy, &msg, &r, &s) - + DCRYPTO_FAIL; return passed == 0; } diff --git a/board/cr50/dcrypto/fips_rand.c b/board/cr50/dcrypto/fips_rand.c index 3c3b4bbfb6..0a0609b0cd 100644 --- a/board/cr50/dcrypto/fips_rand.c +++ b/board/cr50/dcrypto/fips_rand.c @@ -352,17 +352,6 @@ enum hmac_result fips_p256_hmac_drbg_generate(struct drbg_ctx *drbg, 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) -{ - /* Also check for fips_crypto_allowed(). */ - if (!fips_drbg_init()) - return 0; - - return dcrypto_p256_fips_sign_internal(&fips_drbg, key, message, r, s); -} - #ifndef CRYPTO_TEST_CMD_RAND_PERF #define CRYPTO_TEST_CMD_RAND_PERF 0 #endif diff --git a/board/cr50/dcrypto/internal.h b/board/cr50/dcrypto/internal.h index 7d64fc69b3..cd5e351dbd 100644 --- a/board/cr50/dcrypto/internal.h +++ b/board/cr50/dcrypto/internal.h @@ -207,37 +207,94 @@ int p256_cmp(const p256_int *a, const p256_int *b); /* Return -1 if a < b. */ int p256_lt_blinded(const p256_int *a, const p256_int *b); - /** * 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 + * @param k valid random per-message 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 DCRYPTO_OK if successful + */ +enum dcrypto_result dcrypto_p256_ecdsa_sign_raw( + const p256_int *k, const p256_int *key, const p256_int *message, + p256_int *r, p256_int *s) __warn_unused_result; + +/** + * ECDSA P-256 Sign using provide DRBG as source for per-message random + * nonces. Used primarily for deterministic signatures per RFC 6979. + * + * @param drbg initialized DRBG + * @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 DCRYPTO_OK if successful + */ +enum dcrypto_result dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, + const p256_int *key, + const p256_int *message, + p256_int *r, + p256_int *s) __warn_unused_result; + +/** + * Compute k*G (base point multiplication). Used to compute public key + * from private scalar. + * + * @param k private key + * @param x output component x + * @param y output component y + * + * @return DCRYPTO_OK if successful + */ +enum dcrypto_result dcrypto_p256_base_point_mul( + const p256_int *k, p256_int *x, p256_int *y) __warn_unused_result; + +/** + * Compute multiplication of input point (in_x, in_y) by scalar k. + * Used to compute shared point in ECDH. + * + * @param k private key + * @param in_x input public component x + * @param in_y input public component y + * @param x output shared component x + * @param y output shared component y + * + * @return DCRYPTO_OK if successful + */ +enum dcrypto_result dcrypto_p256_point_mul(const p256_int *k, + const p256_int *in_x, + const p256_int *in_y, p256_int *x, + p256_int *y) __warn_unused_result; + +/** + * Verify ECDSA NIST P-256 signature. + * + * @param key_x public key component x + * @param key_y public key component y + * @param message message digest converted to p256_int + * @param r signature component r + * @param s signature component s + * + * @return DCRYPTO_OK if signature is valid */ -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)); -int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) - __attribute__((warn_unused_result)); -int dcrypto_p256_point_mul(const p256_int *k, - const p256_int *in_x, const p256_int *in_y, - p256_int *x, p256_int *y) - __attribute__((warn_unused_result)); -int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, - const p256_int *message, const p256_int *r, - const p256_int *s) - __attribute__((warn_unused_result)); -enum dcrypto_result dcrypto_p256_is_valid_point(const p256_int *x, - const p256_int *y) - __attribute__((warn_unused_result)); +enum dcrypto_result dcrypto_p256_ecdsa_verify( + const p256_int *key_x, const p256_int *key_y, const p256_int *message, + const p256_int *r, const p256_int *s) __warn_unused_result; + +/** + * Verify that provided point is on NIST P-256 curve. + * + * @param x public key component x + * @param y public key component y + * + * @return DCRYPTO_OK if point is on curve + */ +enum dcrypto_result dcrypto_p256_is_valid_point( + const p256_int *x, const p256_int *y) __warn_unused_result; /** * Pair-wise consistency test for private and public key. @@ -246,10 +303,12 @@ enum dcrypto_result dcrypto_p256_is_valid_point(const p256_int *x, * @param d - private key (scalar) * @param x - public key part * @param y - public key part - * @return !0 on success + * + * @return DCRYPTO_OK on success */ -int DCRYPTO_p256_key_pwct(struct drbg_ctx *drbg, const p256_int *d, - const p256_int *x, const p256_int *y); +enum dcrypto_result dcrypto_p256_key_pwct( + struct drbg_ctx *drbg, const p256_int *d, const p256_int *x, + const p256_int *y) __warn_unused_result; /* Wipe content of rnd with pseudo-random values. */ void p256_fast_random(p256_int *rnd); @@ -266,11 +325,11 @@ enum hmac_result p256_hmac_drbg_generate(struct drbg_ctx *ctx, p256_int *k_out); * @param message - Message to sign as P-256 (in little-endian) * @param r - Generated signature * @param s - Generated signature - * @return int + * @return DCRYPTO_OK if success */ -int dcrypto_p256_fips_sign_internal(struct drbg_ctx *drbg, const p256_int *key, - const p256_int *message, p256_int *r, - p256_int *s); +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, diff --git a/board/cr50/dcrypto/p256.c b/board/cr50/dcrypto/p256.c index cfbf068b7a..52d65fbaae 100644 --- a/board/cr50/dcrypto/p256.c +++ b/board/cr50/dcrypto/p256.c @@ -190,6 +190,7 @@ void p256_fast_random(p256_int *rnd) P256_DIGIT(rnd, i) = fast_random(); } +/* B.5.2 Per-Message Secret Number Generation by Testing Candidates */ enum hmac_result p256_hmac_drbg_generate(struct drbg_ctx *ctx, p256_int *rnd) { enum hmac_result result; diff --git a/board/cr50/dcrypto/p256_ec.c b/board/cr50/dcrypto/p256_ec.c index 5c7f355a67..d9e87b699a 100644 --- a/board/cr50/dcrypto/p256_ec.c +++ b/board/cr50/dcrypto/p256_ec.c @@ -4,15 +4,38 @@ */ #include "internal.h" +enum dcrypto_result DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, + const p256_int *key_y, + const p256_int *message, + const p256_int *r, + const p256_int *s) +{ + if (!fips_crypto_allowed()) + return DCRYPTO_FAIL; + + return dcrypto_p256_ecdsa_verify(key_x, key_y, message, r, s); +} + +/* return codes match dcrypto_p256_ecdsa_sign */ +enum dcrypto_result DCRYPTO_p256_ecdsa_sign(const p256_int *key, + const p256_int *message, + p256_int *r, p256_int *s) +{ + if (!fips_drbg_init()) /* Also check for fips_crypto_allowed(). */ + return DCRYPTO_FAIL; + + return dcrypto_p256_fips_sign_internal(&fips_drbg, key, message, r, s); +} + /* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the * order of the group. */ -int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, - const p256_int *n) +enum dcrypto_result DCRYPTO_p256_base_point_mul(p256_int *out_x, + p256_int *out_y, const p256_int *n) { - if (p256_is_zero(n) != 0) { + if (!fips_crypto_allowed() || p256_is_zero(n)) { p256_clear(out_x); p256_clear(out_y); - return 0; + return DCRYPTO_FAIL; } return dcrypto_p256_base_point_mul(n, out_x, out_y); @@ -21,27 +44,29 @@ int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, enum dcrypto_result DCRYPTO_p256_is_valid_point(const p256_int *x, const p256_int *y) { + if (!fips_crypto_allowed()) + return DCRYPTO_FAIL; return dcrypto_p256_is_valid_point(x, y); } /* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < * the order of the group. */ -int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, const p256_int *n, - const p256_int *in_x, const p256_int *in_y) +enum dcrypto_result DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n, const p256_int *in_x, const p256_int *in_y) { - if (p256_is_zero(n) != 0 || + if (!fips_crypto_allowed() || p256_is_zero(n) || (dcrypto_p256_is_valid_point(in_x, in_y) != DCRYPTO_OK)) { p256_clear(out_x); p256_clear(out_y); - return 0; + return DCRYPTO_FAIL; } return dcrypto_p256_point_mul(n, in_x, in_y, out_x, out_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) +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) { int result; p256_int k; @@ -49,47 +74,52 @@ int dcrypto_p256_fips_sign_internal(struct drbg_ctx *drbg, const p256_int *key, /* 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; + result |= dcrypto_p256_ecdsa_sign_raw(&k, key, message, r, s) - + DCRYPTO_OK; /* Wipe temp k */ p256_clear(&k); - return result == 0; + return dcrypto_ok_if_zero(result); } -int DCRYPTO_p256_key_pwct(struct drbg_ctx *drbg, const p256_int *d, - const p256_int *x, const p256_int *y) +enum dcrypto_result 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; + enum dcrypto_result result; if (p256_is_zero(d)) - return 0; + return DCRYPTO_FAIL; /* set some pseudo-random message. */ p256_fast_random(&message); - if (dcrypto_p256_fips_sign_internal(drbg, d, &message, &r, &s) == 0) - return 0; + result = dcrypto_p256_fips_sign_internal(drbg, d, &message, &r, &s); + if (result != DCRYPTO_OK) + return result; #ifdef CRYPTO_TEST_SETUP if (fips_break_cmd == FIPS_BREAK_ECDSA_PWCT) message.a[0] = ~message.a[0]; #endif - result = dcrypto_p256_ecdsa_verify(x, y, &message, &r, &s); - return result; + return dcrypto_p256_ecdsa_verify(x, y, &message, &r, &s); } /** * Key selection based on FIPS-186-4, section B.4.2 (Key Pair * Generation by Testing Candidates). */ -int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, - const uint8_t key_bytes[P256_NBYTES]) +enum dcrypto_result DCRYPTO_p256_key_from_bytes(p256_int *x, + p256_int *y, p256_int *d, const uint8_t key_bytes[P256_NBYTES]) { p256_int key; p256_int tx, ty; + if (!fips_crypto_allowed()) + return DCRYPTO_FAIL; + p256_from_bin(key_bytes, &key); /** @@ -99,7 +129,7 @@ int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, * bring key in proper range. */ if (p256_lt_blinded(&key, &SECP256r1_nMin2) >= 0) - return 0; + return DCRYPTO_RETRY; p256_add_d(&key, 1, d); always_memset(&key, 0, sizeof(key)); @@ -110,8 +140,8 @@ int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, y = &ty; /* Compute public key (x,y) = d * G */ - if (dcrypto_p256_base_point_mul(d, x, y) == 0) - return 0; + if (dcrypto_p256_base_point_mul(d, x, y) != DCRYPTO_OK) + return DCRYPTO_FAIL; - return DCRYPTO_p256_key_pwct(&fips_drbg, d, x, y); + return dcrypto_p256_key_pwct(&fips_drbg, d, x, y); } diff --git a/board/cr50/dcrypto/p256_ecies.c b/board/cr50/dcrypto/p256_ecies.c index 1edef5f67d..e7324eccc2 100644 --- a/board/cr50/dcrypto/p256_ecies.c +++ b/board/cr50/dcrypto/p256_ecies.c @@ -6,7 +6,6 @@ #include "internal.h" #include "dcrypto.h" -#include "trng.h" #include "util.h" #define AES_KEY_BYTES 16 @@ -47,12 +46,14 @@ size_t DCRYPTO_ecies_encrypt( return 0; /* Generate emphemeral EC key. */ - rand_bytes(seed, sizeof(seed)); - if (!DCRYPTO_p256_key_from_bytes(&eph_x, &eph_y, &eph_d, seed)) + if (!fips_rand_bytes(seed, sizeof(seed))) + return 0; + if (DCRYPTO_p256_key_from_bytes(&eph_x, &eph_y, &eph_d, seed) != + DCRYPTO_OK) return 0; /* Compute DH point. */ - if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, - &eph_d, pub_x, pub_y)) + if (DCRYPTO_p256_point_mul(&secret_x, &secret_y, &eph_d, pub_x, + pub_y) != DCRYPTO_OK) return 0; /* Check for computational errors. */ if (dcrypto_p256_is_valid_point(&secret_x, &secret_y) != DCRYPTO_OK) @@ -140,7 +141,8 @@ size_t DCRYPTO_ecies_decrypt( * Verify that the public point is on the curve and compute the DH * point. */ - if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, d, &eph_x, &eph_y)) + if (DCRYPTO_p256_point_mul(&secret_x, &secret_y, d, &eph_x, &eph_y) != + DCRYPTO_OK) return 0; /* Check for computational errors. */ if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y) != DCRYPTO_OK) diff --git a/board/cr50/dcrypto/u2f.c b/board/cr50/dcrypto/u2f.c index e8f6584c69..414a8fe41a 100644 --- a/board/cr50/dcrypto/u2f.c +++ b/board/cr50/dcrypto/u2f.c @@ -158,6 +158,7 @@ static enum ec_error_list u2f_origin_user_key_pair( struct drbg_ctx drbg; size_t key_handle_size = 0; uint8_t *key_handle = NULL; + enum dcrypto_result result; if (kh_version == 0) { key_handle_size = sizeof(struct u2f_key_handle_v0); @@ -205,8 +206,12 @@ static enum ec_error_list u2f_origin_user_key_pair( hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed), dev_salt, P256_NBYTES); } - if (!DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, key_seed)) + result = DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, key_seed); + + if (result == DCRYPTO_RETRY) return EC_ERROR_TRY_AGAIN; + else if (result != DCRYPTO_OK) + return EC_ERROR_HW_INTERNAL; #ifdef CR50_DEV_U2F_VERBOSE ccprintf("user private key %ph\n", HEX_BUF(d, sizeof(*d))); @@ -418,7 +423,8 @@ enum ec_error_list u2f_sign(const struct u2f_state *state, /* Sign. */ hmac_drbg_init_rfc6979(&ctx, &origin_d, &h); - result = (dcrypto_p256_ecdsa_sign(&ctx, &origin_d, &h, &r, &s) != 0) ? + result = (dcrypto_p256_ecdsa_sign(&ctx, &origin_d, &h, &r, &s) == + DCRYPTO_OK) ? EC_SUCCESS : EC_ERROR_HW_INTERNAL; @@ -443,10 +449,11 @@ enum ec_error_list u2f_sign(const struct u2f_state *state, static bool g2f_individual_key_pair(const struct u2f_state *state, p256_int *d, p256_int *pk_x, p256_int *pk_y) { - uint32_t buf[SHA256_DIGEST_WORDS]; + struct sha256_digest buf; + enum dcrypto_result result; /* Incorporate HIK & diversification constant. */ - if (!app_hw_device_id(U2F_ATTEST, state->salt, buf)) + if (!app_hw_device_id(U2F_ATTEST, state->salt, buf.b32)) return false; /* Check that U2F state is valid. */ @@ -455,14 +462,19 @@ static bool g2f_individual_key_pair(const struct u2f_state *state, p256_int *d, if (state->drbg_entropy_size != 64) { /* Generate unbiased private key (non-FIPS path). */ - while (!DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, - (uint8_t *)buf)) { - struct sha256_ctx sha; - - SHA256_hw_init(&sha); - SHA256_update(&sha, buf, sizeof(buf)); - memcpy(buf, SHA256_final(&sha), sizeof(buf)); - } + do { + result = DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, + buf.b8); + switch (result) { + case DCRYPTO_OK: + break; + case DCRYPTO_RETRY: + SHA256_hw_hash(buf.b8, sizeof(buf), &buf); + break; + default: /* Any other result is error. */ + return false; + } + } while (result != DCRYPTO_OK); } else { struct drbg_ctx drbg; uint8_t key_candidate[P256_NBYTES]; @@ -480,10 +492,14 @@ static bool g2f_individual_key_pair(const struct u2f_state *state, p256_int *d, * Additional data = constant coming from HW. */ hmac_drbg_generate(&drbg, key_candidate, - sizeof(key_candidate), buf, + sizeof(key_candidate), buf.b32, sizeof(buf)); - } while (!DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, - key_candidate)); + result = DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, + key_candidate); + } while (result == DCRYPTO_RETRY); + + if (result != DCRYPTO_OK) + return false; } return true; @@ -554,7 +570,8 @@ enum ec_error_list u2f_attest(const struct u2f_state *state, /* Sign over the response w/ the attestation key. */ hmac_drbg_init_rfc6979(&dr_ctx, &d, &h); - result = (dcrypto_p256_ecdsa_sign(&dr_ctx, &d, &h, &r, &s) != 0) ? + result = (dcrypto_p256_ecdsa_sign(&dr_ctx, &d, &h, &r, &s) == + DCRYPTO_OK) ? EC_SUCCESS : EC_ERROR_HW_INTERNAL; p256_clear(&d); diff --git a/board/cr50/dcrypto/x509.c b/board/cr50/dcrypto/x509.c index 6c4a8f0b15..e8f5220e23 100644 --- a/board/cr50/dcrypto/x509.c +++ b/board/cr50/dcrypto/x509.c @@ -516,7 +516,7 @@ int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, SHA256_update(&sha, body, (ctx.p + ctx.n) - body); p256_from_bin(SHA256_final(&sha)->b8, &h); hmac_drbg_init_rfc6979(&drbg, d, &h); - result = dcrypto_p256_ecdsa_sign(&drbg, d, &h, &r, &s); + result = dcrypto_p256_ecdsa_sign(&drbg, d, &h, &r, &s) - DCRYPTO_OK; drbg_exit(&drbg); if (!result) return 0; diff --git a/board/cr50/tpm2/ecc.c b/board/cr50/tpm2/ecc.c index 5cd8e320b7..6e8f5792ed 100644 --- a/board/cr50/tpm2/ecc.c +++ b/board/cr50/tpm2/ecc.c @@ -41,7 +41,7 @@ CRYPT_RESULT _cpri__EccPointMultiply( TPMS_ECC_POINT *out, TPM_ECC_CURVE curve_id, TPM2B_ECC_PARAMETER *n1, TPMS_ECC_POINT *in, TPM2B_ECC_PARAMETER *n2) { - int result; + enum dcrypto_result result; p256_int n, in_x, in_y, out_x, out_y; switch (curve_id) { @@ -75,7 +75,7 @@ CRYPT_RESULT _cpri__EccPointMultiply( } p256_clear(&n); - if (result) { + if (result == DCRYPTO_OK) { out->x.b.size = sizeof(p256_int); out->y.b.size = sizeof(p256_int); p256_to_bin(&out_x, out->x.b.buffer); @@ -161,12 +161,17 @@ CRYPT_RESULT _cpri__GenerateKeyEcc( for (; count != 0; count++) { p256_int x, y, key; + enum dcrypto_result result; memcpy(marshaled_counter.t.buffer, &count, sizeof(count)); _cpri__KDFa(hash_alg, &local_seed.b, label, local_extra, &marshaled_counter.b, sizeof(key_bytes) * 8, key_bytes, NULL, FALSE); - if (DCRYPTO_p256_key_from_bytes(&x, &y, &key, key_bytes)) { + + result = DCRYPTO_p256_key_from_bytes(&x, &y, &key, key_bytes); + if (result == DCRYPTO_RETRY) + continue; + else if (result == DCRYPTO_OK) { q->x.b.size = sizeof(p256_int); p256_to_bin(&x, q->x.b.buffer); @@ -177,6 +182,10 @@ CRYPT_RESULT _cpri__GenerateKeyEcc( p256_to_bin(&key, d->b.buffer); p256_clear(&key); break; + } else { + /* Any other value for result is failure. */ + count = 0; + break; } } @@ -199,7 +208,7 @@ CRYPT_RESULT _cpri__SignEcc( uint8_t digest_local[sizeof(p256_int)]; const size_t digest_len = MIN(digest->size, sizeof(digest_local)); p256_int p256_digest, key, p256_r, p256_s; - int result; + enum dcrypto_result result; if (curve_id != TPM_ECC_NIST_P256) return CRYPT_PARAMETER; @@ -215,8 +224,8 @@ CRYPT_RESULT _cpri__SignEcc( digest->buffer, digest_len); p256_from_bin(digest_local, &p256_digest); - result = fips_p256_ecdsa_sign(&key, &p256_digest, &p256_r, - &p256_s); + result = DCRYPTO_p256_ecdsa_sign(&key, &p256_digest, &p256_r, + &p256_s); p256_clear(&key); r->b.size = sizeof(p256_int); @@ -224,7 +233,7 @@ CRYPT_RESULT _cpri__SignEcc( p256_to_bin(&p256_r, r->b.buffer); p256_to_bin(&p256_s, s->b.buffer); - if (result) + if (result == DCRYPTO_OK) return CRYPT_SUCCESS; else return CRYPT_FAIL; @@ -242,7 +251,6 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc( uint8_t digest_local[sizeof(p256_int)]; const size_t digest_len = MIN(digest->size, sizeof(digest_local)); p256_int p256_digest, q_x, q_y, p256_r, p256_s; - int result; if (curve_id != TPM_ECC_NIST_P256) return CRYPT_PARAMETER; @@ -261,13 +269,10 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc( digest->buffer, digest_len); p256_from_bin(digest_local, &p256_digest); - result = dcrypto_p256_ecdsa_verify(&q_x, &q_y, &p256_digest, - &p256_r, &p256_s); - - if (result) + if (DCRYPTO_p256_ecdsa_verify(&q_x, &q_y, &p256_digest, &p256_r, + &p256_s) == DCRYPTO_OK) return CRYPT_SUCCESS; - else - return CRYPT_FAIL; + return CRYPT_FAIL; } default: return CRYPT_PARAMETER; @@ -277,7 +282,7 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc( CRYPT_RESULT _cpri__GetEphemeralEcc(TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d, TPM_ECC_CURVE curve_id) { - int result; + enum dcrypto_result result; uint8_t key_bytes[P256_NBYTES] __aligned(4); p256_int x, y, key; @@ -291,7 +296,7 @@ CRYPT_RESULT _cpri__GetEphemeralEcc(TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d, always_memset(key_bytes, 0, sizeof(key_bytes)); - if (result) { + if (result == DCRYPTO_OK) { q->x.b.size = sizeof(p256_int); q->y.b.size = sizeof(p256_int); p256_to_bin(&x, q->x.b.buffer); diff --git a/board/host/dcrypto.h b/board/host/dcrypto.h index 481d724986..b9bd5b8be8 100644 --- a/board/host/dcrypto.h +++ b/board/host/dcrypto.h @@ -74,8 +74,10 @@ struct drbg_ctx { uint32_t reseed_counter; }; -int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, - const p256_int *message, p256_int *r, p256_int *s); +enum dcrypto_result dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, + const p256_int *key, + const p256_int *message, + p256_int *r, p256_int *s); void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key, const p256_int *message); diff --git a/common/rma_auth.c b/common/rma_auth.c index e2dcc4dea8..9de2d9984b 100644 --- a/common/rma_auth.c +++ b/common/rma_auth.c @@ -133,8 +133,14 @@ static int p256_get_pub_key_and_secret(uint8_t pub_key[P256_NBYTES], */ while (1) { struct sha256_ctx sha; + enum dcrypto_result result; - if (DCRYPTO_p256_key_from_bytes(&pk_x, &pk_y, &d, buf)) { + result = DCRYPTO_p256_key_from_bytes(&pk_x, &pk_y, &d, buf); + + if (result == DCRYPTO_FAIL) + return EC_ERROR_HW_INTERNAL; + + if (result == DCRYPTO_OK) { /* Is Y coordinate an odd value? */ if (p256_is_odd(&pk_y)) @@ -158,7 +164,9 @@ static int p256_get_pub_key_and_secret(uint8_t pub_key[P256_NBYTES], p256_from_bin(rma_key_blob.raw_blob + 1 + P256_NBYTES, &pk_y); /* Use input space for storing multiplication results. */ - DCRYPTO_p256_point_mul(&pk_x, &pk_y, &d, &pk_x, &pk_y); + if (DCRYPTO_p256_point_mul(&pk_x, &pk_y, &d, &pk_x, &pk_y) != + DCRYPTO_OK) + return EC_ERROR_HW_INTERNAL; /* X value is the seed for the shared secret. */ p256_to_bin(&pk_x, secret); diff --git a/test/u2f.c b/test/u2f.c index 36c1b5a1d4..21c5d6ea69 100644 --- a/test/u2f.c +++ b/test/u2f.c @@ -54,33 +54,33 @@ int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, return 0; } -int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, - const uint8_t key_bytes[P256_NBYTES]) +enum dcrypto_result DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, + p256_int *d, const uint8_t key_bytes[P256_NBYTES]) { p256_int key; p256_from_bin(key_bytes, &key); if (p256_lt_blinded(&key, &SECP256r1_nMin2) >= 0) - return 0; + return DCRYPTO_RETRY; p256_add_d(&key, 1, d); if (x == NULL || y == NULL) - return 1; + return DCRYPTO_OK; memset(x, 0, P256_NBYTES); memset(y, 0, P256_NBYTES); - return 1; + return DCRYPTO_OK; } -int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, - const p256_int *message, p256_int *r, p256_int *s) +enum dcrypto_result dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, + const p256_int *key, + const p256_int *message, + p256_int *r, p256_int *s) { memset(r, 0, sizeof(p256_int)); memset(s, 0, sizeof(p256_int)); - /* Return 1 for success, 0 for error. */ - return 1; + return DCRYPTO_OK; } - /******************************************************************************/ /* Mock implementations of U2F functionality. */ |