diff options
author | Vadim Sukhomlinov <sukhomlinov@google.com> | 2021-09-27 15:28:39 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-09-28 00:01:28 +0000 |
commit | 2d15ff2e3f9295f935f498d7f40fe64ee90fc950 (patch) | |
tree | 4da54bdc6768abf95745d856703a854577baaa47 | |
parent | c07531e0ae87765121ef70979fa8f8e8cb27d0a9 (diff) | |
download | chrome-ec-2d15ff2e3f9295f935f498d7f40fe64ee90fc950.tar.gz |
cr50: enhance ECDSA sign to retry if zero r or s produced.
ECDSA signing can vary rarely result in zero s or r value due to
combination of message, nonce and a private key. Detect such cases
and retry with another nonce.
BUG=b:134594373
TEST=make BOARD=cr50 CRYPTO_TEST=1; tpm_test;
in ccd: dcrypto_ecdsa, u2f_test
Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com>
Change-Id: I1378259a0dc0e2e62cf071b779c1115c4257dc73
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3188564
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_p256.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/board/cr50/dcrypto/dcrypto_p256.c b/board/cr50/dcrypto/dcrypto_p256.c index 858d0ce53c..a4bd603e7d 100644 --- a/board/cr50/dcrypto/dcrypto_p256.c +++ b/board/cr50/dcrypto/dcrypto_p256.c @@ -139,18 +139,24 @@ enum dcrypto_result dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *message, p256_int *r, p256_int *s) { - enum dcrypto_result result; + enum dcrypto_result ret1, ret2; p256_int nonce; - /* Pick uniform 0 < k < R */ - result = p256_hmac_drbg_generate(drbg, &nonce); + do { + /* Pick uniform 0 < k < R */ + ret1 = p256_hmac_drbg_generate(drbg, &nonce); + /* Don't even try with broken nonce. */ + if (ret1 != DCRYPTO_OK) + return ret1; - result |= dcrypto_p256_ecdsa_sign_raw(&nonce, key, message, r, s); + ret2 = dcrypto_p256_ecdsa_sign_raw(&nonce, key, message, r, s); + ret1 |= ret2; + } while (ret2 == DCRYPTO_RETRY); /* Wipe temp nonce */ p256_clear(&nonce); - return dcrypto_ok_if_zero(result - DCRYPTO_OK); + return dcrypto_ok_if_zero(ret1 - DCRYPTO_OK); } enum dcrypto_result dcrypto_p256_ecdsa_sign_raw(const p256_int *nonce, @@ -160,6 +166,7 @@ enum dcrypto_result dcrypto_p256_ecdsa_sign_raw(const p256_int *nonce, { int result; p256_int rnd; + bool s_zero, r_zero; dcrypto_init_and_lock(); dcrypto_ecc_init(); @@ -183,12 +190,23 @@ enum dcrypto_result dcrypto_p256_ecdsa_sign_raw(const p256_int *nonce, p256_clear(r); p256_clear(s); } + s_zero = p256_is_zero(s); + r_zero = p256_is_zero(r); /* Wipe d,k */ CP8W(d, &rnd); CP8W(k, &rnd); - dcrypto_unlock(); + + /** + * Very unlikely case where combination of private key, nonce and + * message results in zero r or s. + * r = nonce * G and take its x-coordinate: r = R.x mod n + * s = nonce^{-1} * (message + r * key) mod n + */ + if ((s_zero || r_zero) && !result) + return DCRYPTO_RETRY; + return dcrypto_ok_if_zero(result); } |