From 6467de5a88404b4fabc1dea9cb0cb4b18a07eac6 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Mon, 13 Jul 2020 12:32:57 +1000 Subject: [PATCH] Randomize z ordinates in scalar mult when timing resistant An RNG is required for shared secret calculation now. Use wc_ecc_set_rng() to set an RNG against the ECC object. ECC verification does not need timing resistance and does not randomize z ordinates. --- mcapi/crypto.c | 18 ++ src/internal.c | 8 +- src/tls.c | 9 + tests/api.c | 39 ++++ wolfcrypt/benchmark/benchmark.c | 7 + wolfcrypt/src/ecc.c | 329 +++++++++++++++++++++++++------- wolfcrypt/src/evp.c | 24 +++ wolfcrypt/src/pkcs7.c | 20 +- wolfcrypt/src/tfm.c | 3 +- wolfcrypt/test/test.c | 98 +++++++++- wolfssl/test.h | 7 + wolfssl/wolfcrypt/ecc.h | 12 +- 12 files changed, 493 insertions(+), 81 deletions(-) diff --git a/mcapi/crypto.c b/mcapi/crypto.c index 9437f1ede..18ec920c3 100644 --- a/mcapi/crypto.c +++ b/mcapi/crypto.c @@ -702,14 +702,32 @@ int CRYPT_ECC_DHE_SharedSecretMake(CRYPT_ECC_CTX* priv, CRYPT_ECC_CTX* pub, { int ret; unsigned int inOut = outSz; +#if defined(ECC_TIMING_RESISTANT) + WC_RNG rng; +#endif if (priv == NULL || pub == NULL || out == NULL || usedSz == NULL) return BAD_FUNC_ARG; +#if defined(ECC_TIMING_RESISTANT) + ret = wc_InitRng(&rng); + if (ret != 0) + return ret; + ret = wc_ecc_set_rng((ecc_key*)priv->holder, &rng); + if (ret != 0) { + wc_FreeRng(&rng); + return ret; + } +#endif + ret = wc_ecc_shared_secret((ecc_key*)priv->holder, (ecc_key*)pub->holder, out, &inOut); *usedSz = inOut; +#if defined(ECC_TIMING_RESISTANT) + wc_FreeRng(&rng); +#endif + return ret; } diff --git a/src/internal.c b/src/internal.c index 59ec5cda7..1038f9fe3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4243,7 +4243,13 @@ int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, ecc_key* pub_key, else #endif { - ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen); +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(priv_key, ssl->rng); + if (ret == 0) +#endif + ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen); } /* Handle async pending response */ diff --git a/src/tls.c b/src/tls.c index 145a3d23f..2a5d9ae34 100644 --- a/src/tls.c +++ b/src/tls.c @@ -7487,6 +7487,15 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) } ssl->ecdhCurveOID = ssl->peerEccKey->dp->oidSum; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(keyShareKey, ssl->rng); + if (ret != 0) { + return ret; + } +#endif + do { #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &keyShareKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); diff --git a/tests/api.c b/tests/api.c index ef0f1912d..78c9e4a84 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19056,6 +19056,14 @@ static int test_wc_ecc_shared_secret (void) ret = wc_ecc_make_key(&rng, keySz, &pubKey); } +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(&key, &rng); + } +#endif + printf(testingFmt, "wc_ecc_shared_secret()"); if (ret == 0) { ret = wc_ecc_shared_secret(&key, &pubKey, out, &outlen); @@ -20021,6 +20029,17 @@ static int test_wc_ecc_encryptDecrypt (void) } } +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(&srvKey, &rng); + } + if (ret == 0) { + ret = wc_ecc_set_rng(&cliKey, &rng); + } +#endif + printf(testingFmt, "wc_ecc_encrypt()"); if (ret == 0) { @@ -20353,6 +20372,14 @@ static int test_wc_ecc_shared_secret_ssh (void) printf(testingFmt, "ecc_shared_secret_ssh()"); +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(&key, &rng); + } +#endif + if (ret == 0) { ret = wc_ecc_shared_secret_ssh(&key, &key2.pubkey, secret, &secretLen); } @@ -22203,6 +22230,7 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) { #if defined(HAVE_PKCS7) PKCS7* pkcs7; + WC_RNG rng; word32 tempWrd32 = 0; byte* tmpBytePtr = NULL; const char input[] = "Test data to encode."; @@ -22370,6 +22398,10 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) #endif /* END HAVE_ECC */ }; /* END pkcs7EnvelopedVector */ +#ifdef ECC_TIMING_RESISTANT + AssertIntEQ(wc_InitRng(&rng), 0); +#endif + printf(testingFmt, "wc_PKCS7_EncodeEnvelopedData()"); AssertNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, devId)); @@ -22379,6 +22411,9 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) for (i = 0; i < testSz; i++) { AssertIntEQ(wc_PKCS7_InitWithCert(pkcs7, (testVectors + i)->cert, (word32)(testVectors + i)->certSz), 0); +#ifdef ECC_TIMING_RESISTANT + pkcs7->rng = &rng; +#endif pkcs7->content = (byte*)(testVectors + i)->content; pkcs7->contentSz = (testVectors + i)->contentSz; @@ -22501,6 +22536,10 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) } #endif /* HAVE_ECC */ +#ifdef ECC_TIMING_RESISTANT + wc_FreeRng(&rng); +#endif + #endif /* HAVE_PKCS7 */ } /* END test_wc_PKCS7_EncodeEnvelopedData() */ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 03b38d0f4..bcaae78ba 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -5311,6 +5311,13 @@ void bench_ecc(int doAsync) } #ifdef HAVE_ECC_DHE +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + for (i = 0; i < BENCH_MAX_PENDING; i++) { + (void)wc_ecc_set_rng(&genKey[i], &gRng); + } +#endif /* ECC Shared Secret */ bench_stats_start(&count, &start); diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 63f03502d..3482a4aea 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -2429,7 +2429,7 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp) #define M_POINTS 8 static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, - mp_int* a, mp_int* modulus, mp_digit mp) + mp_int* a, mp_int* modulus, mp_digit mp, WC_RNG* rng) { int err = MP_OKAY; int i; @@ -2437,6 +2437,8 @@ static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, int bitcnt = 0, mode = 0, digidx = 0; mp_digit buf; + (void)rng; + /* calc the M tab, which holds kG for k==8..15 */ /* M[0] == 8G */ if (err == MP_OKAY) @@ -2569,6 +2571,36 @@ static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, #else +static int wc_ecc_gen_z(WC_RNG* rng, int size, ecc_point* p, + mp_int* modulus, mp_digit mp, mp_int* tx, mp_int* ty) +{ + int err; + + err = wc_ecc_gen_k(rng, size, ty, modulus); + if (err == MP_OKAY) + err = mp_mul(p->z, ty, p->z); + if (err == MP_OKAY) + err = mp_montgomery_reduce(p->z, modulus, mp); + if (err == MP_OKAY) + err = mp_sqr(ty, tx); + if (err == MP_OKAY) + err = mp_montgomery_reduce(tx, modulus, mp); + if (err == MP_OKAY) + err = mp_mul(ty, tx, ty); + if (err == MP_OKAY) + err = mp_montgomery_reduce(ty, modulus, mp); + if (err == MP_OKAY) + err = mp_mul(p->x, tx, p->x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(p->x, modulus, mp); + if (err == MP_OKAY) + err = mp_mul(p->y, ty, p->y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(p->y, modulus, mp); + + return err; +} + #if defined(WC_NO_CACHE_RESISTANT) #define M_POINTS 4 #else @@ -2576,7 +2608,7 @@ static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, #endif static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, - mp_int* a, mp_int* modulus, mp_digit mp) + mp_int* a, mp_int* modulus, mp_digit mp, WC_RNG* rng) { int err = MP_OKAY; int i; @@ -2595,14 +2627,35 @@ static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, /* M[1] == 2G */ if (err == MP_OKAY) err = ecc_projective_dbl_point(tG, M[1], a, modulus, mp); + #ifdef WC_NO_CACHE_RESISTANT if (err == MP_OKAY) err = wc_ecc_copy_point(M[0], M[2]); + if (rng != NULL) { + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[0], + modulus, mp, M[3]->x, M[3]->y); + } + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[1], + modulus, mp, M[3]->x, M[3]->y); + } + } #else if (err == MP_OKAY) err = wc_ecc_copy_point(M[0], M[3]); if (err == MP_OKAY) err = wc_ecc_copy_point(M[1], M[4]); + if (rng != NULL) { + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[3], + modulus, mp, M[2]->x, M[2]->y); + } + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[4], + modulus, mp, M[2]->x, M[2]->y); + } + } #endif /* setup sliding window */ @@ -2638,10 +2691,10 @@ static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, if (mode == 0) { /* timing resistant - dummy operations */ if (err == MP_OKAY) - err = ecc_projective_add_point(M[1], M[2], M[2], a, modulus, + err = ecc_projective_add_point(M[1], M[2], M[3], a, modulus, mp); if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[2], M[3], a, modulus, mp); + err = ecc_projective_dbl_point(M[3], M[2], a, modulus, mp); } else { if (err == MP_OKAY) @@ -2842,7 +2895,7 @@ static void ecc_key_tmp_final(ecc_key* key, void* heap) */ #ifdef FP_ECC static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, - mp_int* modulus, int map, void* heap) + mp_int* modulus, WC_RNG* rng, int map, void* heap) #else int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, mp_int* modulus, int map, void* heap) @@ -2898,7 +2951,11 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, goto exit; } - err = ecc_mulmod(k, tG, R, M, a, modulus, mp); +#ifdef FP_ECC + err = ecc_mulmod(k, tG, R, M, a, modulus, mp, rng); +#else + err = ecc_mulmod(k, tG, R, M, a, modulus, mp, NULL); +#endif /* map R back from projective space */ if (err == MP_OKAY && map) err = ecc_map(R, modulus, mp); @@ -2953,57 +3010,140 @@ exit: return MP_OKAY on success */ int wc_ecc_mulmod_ex2(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, - mp_int* modulus, mp_int* order, int map, void* heap) + mp_int* modulus, mp_int* order, WC_RNG* rng, int map, + void* heap) +#ifndef WOLFSSL_SP_MATH { -#if !defined(WOLFSSL_SP_MATH) && defined(ECC_TIMING_RESISTANT) - int err; - mp_int t; - mp_int o; - mp_digit mask; - int i; + ecc_point *tG, *M[M_POINTS]; + int i, err; +#ifdef WOLFSSL_SMALL_STACK_CACHE + ecc_key key; +#endif + mp_digit mp; +#ifdef ECC_TIMING_RESISTANT + mp_int t; + mp_int o; + mp_digit mask; +#endif - if ((err = mp_init(&t)) != MP_OKAY) - return err; - if ((err = mp_init(&o)) != MP_OKAY) { - mp_free(&t); - return err; - } + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } - if (k == NULL || order == NULL) { - err = ECC_BAD_ARG_E; - } + /* init variables */ + tG = NULL; + XMEMSET(M, 0, sizeof(M)); - /* Make k at 1 bit longer than order. */ - if (err == MP_OKAY) { - err = mp_add(k, order, &t); - } - if (err == MP_OKAY) { - err = mp_copy(order, &o); - } - if (err == MP_OKAY) { - /* Only add if order + k has same number of bits as order */ - mask = (mp_digit)0 - (mp_count_bits(&t) == mp_count_bits(order)); - for (i = 0; i < o.used; i++) { - o.dp[i] &= mask; - } - err = mp_add(&t, &o, &t); - } +#ifdef WOLFSSL_SMALL_STACK_CACHE + err = ecc_key_tmp_init(&key, heap); + if (err != MP_OKAY) + goto exit; + R->key = &key; +#endif /* WOLFSSL_SMALL_STACK_CACHE */ - if (err == MP_OKAY) { - err = wc_ecc_mulmod_ex(&t, G, R, a, modulus, map, heap); - } + /* alloc ram for window temps */ + for (i = 0; i < M_POINTS; i++) { + M[i] = wc_ecc_new_point_h(heap); + if (M[i] == NULL) { + err = MEMORY_E; + goto exit; + } +#ifdef WOLFSSL_SMALL_STACK_CACHE + M[i]->key = &key; +#endif + } - mp_forcezero(&t); - mp_free(&o); - mp_free(&t); + /* make a copy of G in case R==G */ + tG = wc_ecc_new_point_h(heap); + if (tG == NULL) { + err = MEMORY_E; + goto exit; + } + if ((err = ecc_point_to_mont(G, tG, modulus, heap)) != MP_OKAY) { + goto exit; + } - return err; + /* init montgomery reduction */ + if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { + goto exit; + } + +#ifdef ECC_TIMING_RESISTANT + if ((err = mp_init(&t)) != MP_OKAY) + goto exit; + if ((err = mp_init(&o)) != MP_OKAY) { + mp_free(&t); + goto exit; + } + + /* Make k at 1 bit longer than order. */ + if (err == MP_OKAY) { + err = mp_add(k, order, &t); + } + if (err == MP_OKAY) { + err = mp_copy(order, &o); + } + if (err == MP_OKAY) { + /* Only add if order + k has same number of bits as order */ + mask = (mp_digit)0 - (mp_count_bits(&t) == mp_count_bits(order)); + for (i = 0; i < o.used; i++) { + o.dp[i] &= mask; + } + err = mp_add(&t, &o, &t); + } + mp_free(&o); + + if (err == MP_OKAY) + err = ecc_mulmod(&t, tG, R, M, a, modulus, mp, rng); + + mp_forcezero(&t); + mp_free(&t); #else - (void)order; + err = ecc_mulmod(k, tG, R, M, a, modulus, mp, rng); - return wc_ecc_mulmod_ex(k, G, R, a, modulus, map, heap); -#endif /* !WOLFSSL_SP_MATH && ECC_TIMING_RESISTANT */ + (void)order; +#endif + /* map R back from projective space */ + if (err == MP_OKAY && map) + err = ecc_map(R, modulus, mp); + +exit: + + /* done */ + wc_ecc_del_point_h(tG, heap); + for (i = 0; i < M_POINTS; i++) { + wc_ecc_del_point_h(M[i], heap); + } +#ifdef WOLFSSL_SMALL_STACK_CACHE + R->key = NULL; + ecc_key_tmp_free(&key, heap); +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + + return err; } +#else +{ + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + + (void)a; + (void)order; + (void)rng; + +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_mulmod_256(k, G, R, map, heap); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_mulmod_384(k, G, R, map, heap); + } +#endif + return ECC_BAD_ARG_E; +} +#endif /* !WOLFSSL_SP_MATH */ #endif /* !FP_ECC */ #endif /* !FREESCALE_LTC_ECC && !WOLFSSL_STM32_PKA */ @@ -3613,7 +3753,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, byte* out, word32* outlen, ecc_curve_spec* curve) { - int err; + int err = MP_OKAY; #ifndef WOLFSSL_SP_MATH ecc_point* result = NULL; word32 x = 0; @@ -3676,9 +3816,23 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, return MEMORY_E; } - /* Map in a separate call as this should be constant time */ - err = wc_ecc_mulmod_ex2(k, point, result, curve->Af, curve->prime, - curve->order, 0, private_key->heap); +#ifdef ECC_TIMING_RESISTANT + if (private_key->rng == NULL) { + err = MISSING_RNG_E; + } +#endif + + if (err == MP_OKAY) { + /* Map in a separate call as this should be constant time */ +#ifdef ECC_TIMING_RESISTANT + err = wc_ecc_mulmod_ex2(k, point, result, curve->Af, curve->prime, + curve->order, private_key->rng, 0, + private_key->heap); +#else + err = wc_ecc_mulmod_ex2(k, point, result, curve->Af, curve->prime, + curve->order, NULL, 0, private_key->heap); +#endif + } if (err == MP_OKAY) { err = mp_montgomery_setup(curve->prime, &mp); } @@ -3955,7 +4109,6 @@ static WC_INLINE void wc_ecc_reset(ecc_key* key) key->state = ECC_STATE_NONE; } - /* create the public ECC key from a private key * * key an initialized private key to generate public part from @@ -3969,8 +4122,8 @@ static WC_INLINE void wc_ecc_reset(ecc_key* key) * * returns MP_OKAY on success */ -static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, - ecc_point* pubOut) +static int ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, + ecc_point* pubOut, WC_RNG* rng) { int err = MP_OKAY; #if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) @@ -3981,6 +4134,8 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); #endif /* !WOLFSSL_ATECC508A */ + (void)rng; + if (key == NULL) { return BAD_FUNC_ARG; } @@ -4055,6 +4210,8 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, err = mp_copy(curve->Gx, base->x); if (err == MP_OKAY) err = mp_copy(curve->Gy, base->y); + if (err == MP_OKAY) + err = mp_montgomery_setup(curve->prime, &mp); if (err == MP_OKAY) err = mp_set(base->z, 1); @@ -4062,14 +4219,11 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, if (err == MP_OKAY) { /* Map in a separate call as this should be constant time */ err = wc_ecc_mulmod_ex2(&key->k, base, pub, curve->Af, curve->prime, - curve->order, 0, key->heap); + curve->order, rng, 0, key->heap); if (err == MP_MEM) { err = MEMORY_E; } } - if (err == MP_OKAY) { - err = mp_montgomery_setup(curve->prime, &mp); - } if (err == MP_OKAY) { /* Use constant time map if compiled in */ err = ecc_map_ex(pub, curve->prime, mp, 1); @@ -4128,7 +4282,23 @@ int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut) { WOLFSSL_ENTER("wc_ecc_make_pub"); - return wc_ecc_make_pub_ex(key, NULL, pubOut); + return ecc_make_pub_ex(key, NULL, pubOut, NULL); +} + +/* create the public ECC key from a private key - mask timing use random z + * + * key an initialized private key to generate public part from + * pubOut [out]ecc_point holding the public key, if NULL then public key part + * is cached in key instead. + * + * + * returns MP_OKAY on success + */ +int wc_ecc_make_pub_ex(ecc_key* key, ecc_point* pubOut, WC_RNG* rng) +{ + WOLFSSL_ENTER("wc_ecc_make_pub"); + + return ecc_make_pub_ex(key, NULL, pubOut, rng); } @@ -4305,7 +4475,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) /* generate public key from k */ if (err == MP_OKAY) - err = wc_ecc_make_pub_ex(key, curve, NULL); + err = ecc_make_pub_ex(key, curve, NULL, rng); if (err == MP_OKAY) key->type = ECC_PRIVATEKEY; @@ -5188,7 +5358,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, mp_free(key->sign_k); XFREE(key->sign_k, key->heap, DYNAMIC_TYPE_ECC); key->sign_k = NULL; - err = wc_ecc_make_pub_ex(pubkey, curve, NULL); + err = ecc_make_pub_ex(pubkey, curve, NULL, rng); } else #endif @@ -5992,7 +6162,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* checking if private key with no public part */ if (key->type == ECC_PRIVATEKEY_ONLY) { WOLFSSL_MSG("Verify called with private key, generating public part"); - err = wc_ecc_make_pub_ex(key, NULL, NULL); + err = ecc_make_pub_ex(key, NULL, NULL, NULL); if (err != MP_OKAY) { WOLFSSL_MSG("Unable to extract public key"); return err; @@ -6947,9 +7117,15 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) if (err == MP_OKAY) err = mp_set(base->z, 1); +#ifdef ECC_TIMING_RESISTANT if (err == MP_OKAY) err = wc_ecc_mulmod_ex2(&key->k, base, res, a, prime, curve->order, - 1, key->heap); + key->rng, 1, key->heap); +#else + if (err == MP_OKAY) + err = wc_ecc_mulmod_ex2(&key->k, base, res, a, prime, curve->order, + NULL, 1, key->heap); +#endif } if (err == MP_OKAY) { @@ -9657,7 +9833,7 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, if (err == MP_OKAY) err = accel_fp_mul(idx, k, R, a, modulus, mp, map); } else { - err = normal_ecc_mulmod(k, G, R, a, modulus, map, heap); + err = normal_ecc_mulmod(k, G, R, a, modulus, NULL, map, heap); } } @@ -9689,7 +9865,7 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, #ifndef WOLFSSL_SP_MATH static int normal_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, mp_int* modulus, mp_int* order, - int map, void* heap) + WC_RNG* rng, int map, void* heap) { int err; mp_int t; @@ -9721,7 +9897,7 @@ static int normal_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, } if (err == MP_OKAY) { - err = normal_ecc_mulmod(&t, G, R, a, modulus, map, heap); + err = normal_ecc_mulmod(&t, G, R, a, modulus, rng, map, heap); } mp_forcezero(&t); @@ -9743,7 +9919,7 @@ static int normal_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, return MP_OKAY if successful */ int wc_ecc_mulmod_ex2(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, - mp_int* modulus, mp_int* order, int map, void* heap) + mp_int* modulus, mp_int* order, WC_RNG* rng, int map, void* heap) { #ifndef WOLFSSL_SP_MATH int idx, err = MP_OKAY; @@ -9813,7 +9989,8 @@ int wc_ecc_mulmod_ex2(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, if (err == MP_OKAY) err = accel_fp_mul(idx, k, R, a, modulus, mp, map); } else { - err = normal_ecc_mulmod_ex(k, G, R, a, modulus, order, map, heap); + err = normal_ecc_mulmod_ex(k, G, R, a, modulus, order, rng, map, + heap); } } @@ -9908,6 +10085,22 @@ void wc_ecc_fp_free(void) #endif /* FP_ECC */ +#ifdef ECC_TIMING_RESISTANT +int wc_ecc_set_rng(ecc_key* key, WC_RNG* rng) +{ + int err = 0; + + if (key == NULL) { + err = BAD_FUNC_ARG; + } + else { + key->rng = rng; + } + + return err; +} +#endif + #ifdef HAVE_ECC_ENCRYPT diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index d81d84e18..9077cbba8 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1413,16 +1413,40 @@ int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_ } if (key) { word32 len32 = (word32)len; +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + WC_RNG rng; + if (wc_InitRng(&rng) != MP_OKAY) { + WOLFSSL_MSG("Init RNG failed"); + return WOLFSSL_FAILURE; + } + ((ecc_key*)ctx->pkey->ecc->internal)->rng = &rng; +#endif if (*keylen < len32) { WOLFSSL_MSG("buffer too short"); +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ((ecc_key*)ctx->pkey->ecc->internal)->rng = NULL; + wc_FreeRng(&rng); +#endif return WOLFSSL_FAILURE; } if (wc_ecc_shared_secret_ssh((ecc_key*)ctx->pkey->ecc->internal, (ecc_point*)ctx->peerKey->ecc->pub_key->internal, key, &len32) != MP_OKAY) { WOLFSSL_MSG("wc_ecc_shared_secret failed"); +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ((ecc_key*)ctx->pkey->ecc->internal)->rng = NULL; + wc_FreeRng(&rng); +#endif return WOLFSSL_FAILURE; } +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ((ecc_key*)ctx->pkey->ecc->internal)->rng = NULL; + wc_FreeRng(&rng); +#endif len = (int)len32; } *keylen = (size_t)len; diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index e420cad37..aa0dd65c6 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -5531,7 +5531,7 @@ static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID) /* create key encryption key (KEK) using key wrap algorithm and key encryption * algorithm, place in kari->kek. return 0 on success, <0 on error. */ -static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, +static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng, int keyWrapOID, int keyEncOID) { int ret; @@ -5566,6 +5566,19 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, if (secret == NULL) return MEMORY_E; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(kari->senderKey, rng); + if (ret != 0) + return ret; + ret = wc_ecc_set_rng(kari->recipKey, rng); + if (ret != 0) + return ret; +#else + (void)rng; +#endif + if (kari->direction == WC_PKCS7_ENCODE) { ret = wc_ecc_shared_secret(kari->senderKey, kari->recipKey, @@ -5797,7 +5810,7 @@ int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz, } /* generate KEK (key encryption key) */ - ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, keyAgreeOID); + ret = wc_PKCS7_KariGenerateKEK(kari, pkcs7->rng, keyWrapOID, keyAgreeOID); if (ret != 0) { wc_PKCS7_KariFree(kari); #ifdef WOLFSSL_SMALL_STACK @@ -9397,7 +9410,8 @@ static int wc_PKCS7_DecryptKari(PKCS7* pkcs7, byte* in, word32 inSz, } else { /* create KEK */ - ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, pkcs7->keyAgreeOID); + ret = wc_PKCS7_KariGenerateKEK(kari, pkcs7->rng, keyWrapOID, + pkcs7->keyAgreeOID); if (ret != 0) { wc_PKCS7_KariFree(kari); #ifdef WOLFSSL_SMALL_STACK diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index 5596d2464..bf128174e 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -3492,11 +3492,12 @@ int fp_montgomery_reduce_ex(fp_int *a, fp_int *m, fp_digit mp, int ct) a->used = pa+1; fp_clamp(a); -#ifdef WOLFSSL_MONT_RED_NCT +#ifndef WOLFSSL_MONT_RED_CT /* if A >= m then A = A - m */ if (fp_cmp_mag (a, m) != FP_LT) { s_fp_sub (a, m, a); } + (void)ct; #else if (ct) { fp_submod_ct(a, m, m, a); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index cf17af746..4ecd617b7 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -18260,7 +18260,7 @@ done: #endif #ifdef HAVE_ECC_CDH -static int ecc_test_cdh_vectors(void) +static int ecc_test_cdh_vectors(WC_RNG* rng) { int ret; ecc_key pub_key, priv_key; @@ -18292,6 +18292,16 @@ static int ecc_test_cdh_vectors(void) if (ret != 0) goto done; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&priv_key, rng); + if (ret != 0) + goto done; +#else + (void)rng; +#endif + /* compute ECC Cofactor shared secret */ x = sizeof(sharedA); do { @@ -18517,6 +18527,14 @@ static int ecc_test_make_pub(WC_RNG* rng) } TEST_SLEEP(); +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&key, rng); + if (ret != 0) + goto done; +#endif + x = sizeof(exportBuf); do { #if defined(WOLFSSL_ASYNC_CRYPT) @@ -18766,6 +18784,17 @@ static int ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerifyCount, } #ifdef HAVE_ECC_DHE +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&userA, rng); + if (ret != 0) + goto done; + ret = wc_ecc_set_rng(&userB, rng); + if (ret != 0) + goto done; +#endif + x = ECC_SHARED_SIZE; do { #if defined(WOLFSSL_ASYNC_CRYPT) @@ -19528,7 +19557,7 @@ done: #endif #ifdef HAVE_ECC_DHE -static int ecc_ssh_test(ecc_key* key) +static int ecc_ssh_test(ecc_key* key, WC_RNG* rng) { int ret; byte out[128]; @@ -19548,6 +19577,16 @@ static int ecc_ssh_test(ecc_key* key) if (ret != BAD_FUNC_ARG) return -9747; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(key, rng); + if (ret != 0) + return -9748; +#else + (void)rng; +#endif + /* Use API. */ ret = 0; do { @@ -19558,7 +19597,7 @@ static int ecc_ssh_test(ecc_key* key) ret = wc_ecc_shared_secret_ssh(key, &key->pubkey, out, &outLen); } while (ret == WC_PENDING_E); if (ret != 0) - return -9748; + return -9749; TEST_SLEEP(); return 0; } @@ -19613,7 +19652,7 @@ static int ecc_def_curve_test(WC_RNG *rng) goto done; #endif #ifdef HAVE_ECC_DHE - ret = ecc_ssh_test(&key); + ret = ecc_ssh_test(&key, rng); if (ret < 0) goto done; #endif @@ -20667,7 +20706,7 @@ int ecc_test(void) } #endif #ifdef HAVE_ECC_CDH - ret = ecc_test_cdh_vectors(); + ret = ecc_test_cdh_vectors(&rng); if (ret != 0) { printf("ecc_test_cdh_vectors failed! %d\n", ret); goto done; @@ -20773,6 +20812,19 @@ int ecc_encrypt_test(void) for (i = 0; i < (int)sizeof(msg); i++) msg[i] = i; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&userA, &rng); + if (ret != 0) { + ret = -10011; goto done; + } + ret = wc_ecc_set_rng(&userB, &rng); + if (ret != 0) { + ret = -10012; goto done; + } +#endif + /* encrypt msg to B */ ret = wc_ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz, NULL); if (ret != 0) { @@ -20923,6 +20975,15 @@ int ecc_test_buffers(void) { if (ret != 0) return -10015; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&cliKey, &rng); + if (ret != 0) { + return -10023; + } +#endif + #if defined(HAVE_ECC_ENCRYPT) && defined(HAVE_HKDF) { word32 y; @@ -24856,6 +24917,7 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, byte enveloped[2048]; byte decoded[2048]; PKCS7* pkcs7; + WC_RNG rng; #ifdef PKCS7_OUTPUT_TEST_BUNDLES XFILE pkcs7File; #endif @@ -25012,6 +25074,17 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, testSz = sizeof(testVectors) / sizeof(pkcs7EnvelopedVector); +#ifdef ECC_TIMING_RESISTANT +#ifndef HAVE_FIPS + ret = wc_InitRng_ex(&rng, HEAP_HINT, devId); +#else + ret = wc_InitRng(&rng); +#endif + if (ret != 0) { + return -11760; + } +#endif + for (i = 0; i < testSz; i++) { pkcs7 = wc_PKCS7_New(HEAP_HINT, #ifdef WOLFSSL_ASYNC_CRYPT @@ -25172,6 +25245,9 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, } } +#ifdef ECC_TIMING_RESISTANT + pkcs7->rng = &rng; +#endif /* encode envelopedData */ envelopedSz = wc_PKCS7_EncodeEnvelopedData(pkcs7, enveloped, sizeof(enveloped)); @@ -25233,6 +25309,10 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, pkcs7 = NULL; } +#ifdef ECC_TIMING_RESISTANT + wc_FreeRng(&rng); +#endif + (void)eccCert; (void)eccCertSz; (void)eccPrivKey; @@ -25633,8 +25713,6 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, wc_FreeRng(&rng); return -11806; } - - wc_FreeRng(&rng); } for (i = 0; i < testSz; i++) { @@ -25808,6 +25886,10 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, } } +#ifdef ECC_TIMING_RESISTANT + pkcs7->rng = &rng; +#endif + /* encode envelopedData */ envelopedSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, sizeof(enveloped)); @@ -25869,6 +25951,8 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, pkcs7 = NULL; } + wc_FreeRng(&rng); + #if !defined(HAVE_ECC) || defined(NO_AES) (void)eccCert; (void)eccCertSz; diff --git a/wolfssl/test.h b/wolfssl/test.h index 129ee7c05..34c045a33 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -2673,6 +2673,13 @@ static WC_INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey, ret = BAD_FUNC_ARG; } +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(privKey, wolfSSL_GetRNG(ssl)); + } +#endif + /* generate shared secret and return it */ if (ret == 0) { ret = wc_ecc_shared_secret(privKey, pubKey, out, outlen); diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index fe9bb489a..a63894bae 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -431,6 +431,9 @@ struct ecc_key { #ifdef WOLFSSL_DSP remote_handle64 handle; #endif +#ifdef ECC_TIMING_RESISTANT + WC_RNG* rng; +#endif #ifdef WC_ECC_NONBLOCK ecc_nb_ctx_t* nb_ctx; #endif @@ -476,6 +479,8 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id); WOLFSSL_API int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut); WOLFSSL_API +int wc_ecc_make_pub_ex(ecc_key* key, ecc_point* pubOut, WC_RNG* rng); +WOLFSSL_API int wc_ecc_check_key(ecc_key* key); WOLFSSL_API int wc_ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime); @@ -545,6 +550,10 @@ WOLFSSL_API void wc_ecc_fp_free(void); WOLFSSL_LOCAL void wc_ecc_fp_init(void); +#ifdef ECC_TIMING_RESISTANT +WOLFSSL_API +int wc_ecc_set_rng(ecc_key* key, WC_RNG* rng); +#endif WOLFSSL_API int wc_ecc_set_curve(ecc_key* key, int keysize, int curve_id); @@ -602,7 +611,8 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, mp_int* modulus, int map, void* heap); WOLFSSL_LOCAL int wc_ecc_mulmod_ex2(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, - mp_int* modulus, mp_int* order, int map, void* heap); + mp_int* modulus, mp_int* order, WC_RNG* rng, int map, + void* heap); #endif /* !WOLFSSL_ATECC508A */