summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2021-09-27 15:28:39 -0700
committerCommit Bot <commit-bot@chromium.org>2021-09-28 00:01:28 +0000
commit2d15ff2e3f9295f935f498d7f40fe64ee90fc950 (patch)
tree4da54bdc6768abf95745d856703a854577baaa47
parentc07531e0ae87765121ef70979fa8f8e8cb27d0a9 (diff)
downloadchrome-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.c30
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);
}