Browse Source

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.
Sean Parkinson 3 years ago
parent
commit
6467de5a88
12 changed files with 493 additions and 81 deletions
  1. 18 0
      mcapi/crypto.c
  2. 7 1
      src/internal.c
  3. 9 0
      src/tls.c
  4. 39 0
      tests/api.c
  5. 7 0
      wolfcrypt/benchmark/benchmark.c
  6. 261 68
      wolfcrypt/src/ecc.c
  7. 24 0
      wolfcrypt/src/evp.c
  8. 17 3
      wolfcrypt/src/pkcs7.c
  9. 2 1
      wolfcrypt/src/tfm.c
  10. 91 7
      wolfcrypt/test/test.c
  11. 7 0
      wolfssl/test.h
  12. 11 1
      wolfssl/wolfcrypt/ecc.h

+ 18 - 0
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;
 }
 

+ 7 - 1
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 */

+ 9 - 0
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);

+ 39 - 0
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() */
 

+ 7 - 0
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);

+ 261 - 68
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);
+
+   (void)order;
+#endif
+   /* map R back from projective space */
+   if (err == MP_OKAY && map)
+      err = ecc_map(R, modulus, mp);
 
-    return wc_ecc_mulmod_ex(k, G, R, a, modulus, map, heap);
-#endif /* !WOLFSSL_SP_MATH && ECC_TIMING_RESISTANT */
+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,
+                                                        key->rng, 1, key->heap);
+#else
         if (err == MP_OKAY)
             err = wc_ecc_mulmod_ex2(&key->k, base, res, a, prime, curve->order,
-                                                                  1, key->heap);
+                                                            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
 
 

+ 24 - 0
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;

+ 17 - 3
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

+ 2 - 1
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);

+ 91 - 7
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;

+ 7 - 0
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);

+ 11 - 1
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 */