From f1ead309872c7f919bc1386d51f054a9d2644479 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Dec 2016 11:32:59 -0800 Subject: [PATCH 1/7] New ECC curve cache feature to improve performance. Disabled by default and enabled using ./configure CFALGS="-DECC_CACHE_CURVE" or #define ECC_CACHE_CURVE. Added internal ECC states. Combined wc_ecc_mulmod_ex versions for timing rest / not. Tested with all math, timing, FP variants and NXP LTC and ECC508A hardware. Pulled in from latest async branch. Added new ECC_MAX_SIG_SIZE enum to help with sizing the sign buffer. Performance Increases with ECC_CACHE_CURVE enabled: * Key Gen 4.2% * Key Agree, 4.0% * Sign 6.8% * Verify 5.8% --- wolfcrypt/src/ecc.c | 1325 +++++++++++++++++++++------------------ wolfssl/wolfcrypt/ecc.h | 102 ++- 2 files changed, 768 insertions(+), 659 deletions(-) mode change 100644 => 100755 wolfcrypt/src/ecc.c diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c old mode 100644 new mode 100755 index ecdc408a2..b0e2be0dd --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -42,7 +42,9 @@ Possible ECC enable options: * WOLFSSL_VALIDATE_ECC_IMPORT: Validate ECC key on import default: off * WOLFSSL_CUSTOM_CURVES: Allow non-standard curves. default: off * Includes the curve "a" variable in calculation - * ECC_DUMP_OID: Enables dump of OID encoding and sum default: off + * ECC_DUMP_OID: Enables dump of OID encoding and sum default: off + * ECC_CACHE_CURVE: Enables cache of curve info to improve perofrmance + default: off */ /* @@ -118,6 +120,22 @@ ECC Curve Sizes: #endif +/* internal ECC states */ +enum { + ECC_STATE_NONE = 0, + + ECC_STATE_SHARED_SEC_GEN, + ECC_STATE_SHARED_SEC_RES, + + ECC_STATE_SIGN_DO, + ECC_STATE_SIGN_ENCODE, + + ECC_STATE_VERIFY_DECODE, + ECC_STATE_VERIFY_DO, + ECC_STATE_VERIFY_RES, +}; + + /* map ptmul -> mulmod */ @@ -912,6 +930,7 @@ const ecc_set_type ecc_sets[] = { NULL, 0, 0, 0 } }; +#define ECC_SET_COUNT (sizeof(ecc_sets)/sizeof(ecc_set_type)) #ifdef HAVE_OID_ENCODING /* encoded OID cache */ @@ -919,12 +938,17 @@ const ecc_set_type ecc_sets[] = { word32 oidSz; byte oid[ECC_MAX_OID_LEN]; } oid_cache_t; - static oid_cache_t ecc_oid_cache[sizeof(ecc_sets)/sizeof(ecc_set_type)]; + static oid_cache_t ecc_oid_cache[ECC_SET_COUNT]; #endif -#ifdef HAVE_COMP_KEY -static int wc_ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen); -#endif +#ifdef ECC_CACHE_CURVE + /* cache (mp_int) of the curve parameters */ + static ecc_curve_spec ecc_curve_spec_cache[ECC_SET_COUNT]; + + #define DECLARE_CURVE_SPECS ecc_curve_spec* curve = NULL; +#else + #define DECLARE_CURVE_SPECS ecc_curve_spec curve_lcl; ecc_curve_spec* curve = &curve_lcl; XMEMSET(curve, 0, sizeof(ecc_curve_spec)); +#endif /* ECC_CACHE_CURVE */ #ifndef WOLFSSL_ATECC508A @@ -942,8 +966,106 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, int mp_jacobi(mp_int* a, mp_int* n, int* c); int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret); -#endif /* WOLFSSL_ATECC508A */ +static void wc_ecc_curve_free(ecc_curve_spec* curve) +{ + if (curve == NULL) { + return; + } + + /* don't free cached curves */ + /* don't clear fast math (only normal math uses alloc's) */ +#if !defined(ECC_CACHE_CURVE) && !defined(USE_FAST_MATH) + if (curve->load_mask & ECC_CURVE_FIELD_PRIME) + mp_clear(&curve->prime); + if (curve->load_mask & ECC_CURVE_FIELD_AF) + mp_clear(&curve->Af); + if (curve->load_mask & ECC_CURVE_FIELD_BF) + mp_clear(&curve->Bf); + if (curve->load_mask & ECC_CURVE_FIELD_ORDER) + mp_clear(&curve->order); + if (curve->load_mask & ECC_CURVE_FIELD_GX) + mp_clear(&curve->Gx); + if (curve->load_mask & ECC_CURVE_FIELD_GY) + mp_clear(&curve->Gy); + curve->load_mask = 0; +#endif +} + +static int wc_ecc_curve_load_item(const char* src, mp_int* dst, + ecc_curve_spec* curve, byte mask) +{ + int err = mp_init(dst); + if (err == MP_OKAY) + err = mp_read_radix(dst, src, 16); +#ifdef HAVE_WOLF_BIGINT + if (err == MP_OKAY) + err = wc_mp_to_bigint(dst, &dst->raw); +#endif + if (err == MP_OKAY) + curve->load_mask |= mask; + return err; +} + +static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, + byte load_mask) +{ + int ret = 0, x; + ecc_curve_spec* curve; + byte load_items; /* mask of items to load */ + + if (dp == NULL || pCurve == NULL) + return BAD_FUNC_ARG; + +#ifdef ECC_CACHE_CURVE + /* find ecc_set index based on curve_id */ + for (x = 0; ecc_sets[x].size != 0; x++) { + if (dp->id == ecc_sets[x].id) + break; /* found index */ + } + if (ecc_sets[x].size == 0) + return ECC_BAD_ARG_E; + + /* set curve pointer to cache */ + *pCurve = &ecc_curve_spec_cache[x]; + +#endif /* ECC_CACHE_CURVE */ + curve = *pCurve; + + /* make sure the curve is initialized */ + if (curve->dp != dp) { + curve->load_mask = 0; + } + curve->dp = dp; /* set dp info */ + + /* determine items to load */ + load_items = (~curve->load_mask & load_mask); + + /* load items */ + x = 0; + if (load_items & ECC_CURVE_FIELD_PRIME) + x += wc_ecc_curve_load_item(dp->prime, &curve->prime, curve, ECC_CURVE_FIELD_PRIME); + if (load_items & ECC_CURVE_FIELD_AF) + x += wc_ecc_curve_load_item(dp->Af, &curve->Af, curve, ECC_CURVE_FIELD_AF); + if (load_items & ECC_CURVE_FIELD_BF) + x += wc_ecc_curve_load_item(dp->Bf, &curve->Bf, curve, ECC_CURVE_FIELD_BF); + if (load_items & ECC_CURVE_FIELD_ORDER) + x += wc_ecc_curve_load_item(dp->order, &curve->order, curve, ECC_CURVE_FIELD_ORDER); + if (load_items & ECC_CURVE_FIELD_GX) + x += wc_ecc_curve_load_item(dp->Gx, &curve->Gx, curve, ECC_CURVE_FIELD_GX); + if (load_items & ECC_CURVE_FIELD_GY) + x += wc_ecc_curve_load_item(dp->Gy, &curve->Gy, curve, ECC_CURVE_FIELD_GY); + + /* check for error */ + if (x != 0) { + wc_ecc_curve_free(curve); + ret = MP_READ_E; + } + + return ret; +} + +#endif /* WOLFSSL_ATECC508A */ static int wc_ecc_set_curve(ecc_key* key, int keysize, int curve_id) { @@ -1660,10 +1782,28 @@ done: #if !defined(FREESCALE_LTC_ECC) -#ifndef ECC_TIMING_RESISTANT - -/* size of sliding window, don't change this! */ -#define WINSIZE 4 +#ifndef WC_NO_CACHE_RESISTANT +#if defined(TFM_TIMING_RESISTANT) && defined(USE_FAST_MATH) && \ + !defined(__cplusplus) + /* let's use the one we already have */ + extern const wolfssl_word wc_off_on_addr[2]; +#elif defined(ECC_TIMING_RESISTANT) + static const wolfssl_word wc_off_on_addr[2] = + { + #if defined(WC_64BIT_CPU) + W64LIT(0x0000000000000000), + W64LIT(0xffffffffffffffff) + #elif defined(WC_16BIT_CPU) + 0x0000U, + 0xffffU + #else + /* 32 bit */ + 0x00000000U, + 0xffffffffU + #endif + }; +#endif /* TFM_TIMING_RESISTANT && USE_FAST_MATH */ +#endif /* WC_NO_CACHE_RESISTANT */ /** Perform a point multiplication @@ -1678,22 +1818,33 @@ done: */ #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* a, mp_int* modulus, 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) + mp_int* a, mp_int* modulus, int map, + void* heap) #endif { - ecc_point *tG, *M[8]; - int i, j, err; +#ifndef ECC_TIMING_RESISTANT + /* size of sliding window, don't change this! */ + #define WINSIZE 4 + #define M_POINTS 8 + int first = 1, bitbuf = 0, bitcpy = 0, j; +#else + #define M_POINTS 3 +#endif + + ecc_point *tG, *M[M_POINTS]; + int i, err; mp_int mu; mp_digit mp; mp_digit buf; - int first = 1, bitbuf = 0, bitcpy = 0, bitcnt = 0, mode = 0, - digidx = 0; + int bitcnt = 0, mode = 0, digidx = 0; - if (k == NULL || G == NULL || R == NULL || modulus == NULL) + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { return ECC_BAD_ARG_E; + } /* init variables */ tG = NULL; @@ -1703,25 +1854,25 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { return err; } + if ((err = mp_init(&mu)) != MP_OKAY) { return err; } if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { + #ifndef USE_FAST_MATH mp_clear(&mu); + #endif return err; } /* alloc ram for window temps */ - for (i = 0; i < 8; i++) { + for (i = 0; i < M_POINTS; i++) { M[i] = wc_ecc_new_point_h(heap); if (M[i] == NULL) { - for (j = 0; j < i; j++) { - wc_ecc_del_point_h(M[j], heap); - } #ifndef USE_FAST_MATH mp_clear(&mu); #endif - return MEMORY_E; + err = MEMORY_E; goto exit; } } @@ -1752,6 +1903,8 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_clear(&mu); #endif +#ifndef ECC_TIMING_RESISTANT + /* calc the M tab, which holds kG for k==8..15 */ /* M[0] == 8G */ if (err == MP_OKAY) @@ -1764,7 +1917,8 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, /* now find (8+k)G for k=1..7 */ if (err == MP_OKAY) for (j = 9; j < 16; j++) { - err = ecc_projective_add_point(M[j-9], tG, M[j-8], a, modulus, mp); + err = ecc_projective_add_point(M[j-9], tG, M[j-M_POINTS], a, + modulus, mp); if (err != MP_OKAY) break; } @@ -1812,13 +1966,13 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, /* if this is the first window we do a simple copy */ if (first == 1) { /* R = kG [k = first window] */ - err = mp_copy(M[bitbuf-8]->x, R->x); + err = mp_copy(M[bitbuf-M_POINTS]->x, R->x); if (err != MP_OKAY) break; - err = mp_copy(M[bitbuf-8]->y, R->y); + err = mp_copy(M[bitbuf-M_POINTS]->y, R->y); if (err != MP_OKAY) break; - err = mp_copy(M[bitbuf-8]->z, R->z); + err = mp_copy(M[bitbuf-M_POINTS]->z, R->z); first = 0; } else { /* normal window */ @@ -1831,7 +1985,7 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, if (err != MP_OKAY) break; /* out of first for(;;) */ /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ - err = ecc_projective_add_point(R, M[bitbuf-8], R, a, + err = ecc_projective_add_point(R, M[bitbuf-M_POINTS], R, a, modulus, mp); } if (err != MP_OKAY) break; @@ -1877,127 +2031,10 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, } } - /* map R back from projective space */ - if (err == MP_OKAY && map) - err = ecc_map(R, modulus, mp); - - wc_ecc_del_point_h(tG, heap); - for (i = 0; i < 8; i++) { - wc_ecc_del_point_h(M[i], heap); - } - return err; -} - -#ifndef FP_ECC -int wc_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, - mp_int* modulus, int map) -{ - return wc_ecc_mulmod_ex(k, G, R, a, modulus, map, NULL); -} -#endif /* !FP_ECC */ -#undef WINSIZE + #undef WINSIZE #else /* ECC_TIMING_RESISTANT */ - -#ifndef WC_NO_CACHE_RESISTANT -#if defined(TFM_TIMING_RESISTANT) && defined(USE_FAST_MATH) && \ - !defined(__cplusplus) - /* let's use the one we already have */ - extern const wolfssl_word wc_off_on_addr[2]; -#else - static const wolfssl_word wc_off_on_addr[2] = - { - #if defined(WC_64BIT_CPU) - W64LIT(0x0000000000000000), - W64LIT(0xffffffffffffffff) - #elif defined(WC_16BIT_CPU) - 0x0000U, - 0xffffU - #else - /* 32 bit */ - 0x00000000U, - 0xffffffffU - #endif - }; -#endif /* TFM_TIMING_RESISTANT && USE_FAST_MATH */ -#endif /* WC_NO_CACHE_RESISTANT */ - -/** - Perform a point multiplication (timing resistant) - k The scalar to multiply by - G The base point - R [out] Destination for kG - a ECC curve parameter a - modulus The modulus of the field the ECC curve is in - map Boolean whether to map back to affine or not - (1==map, 0 == leave in projective) - return MP_OKAY on success -*/ -#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) -#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) -#endif -{ - ecc_point *tG, *M[3]; - int i, j, err; - mp_int mu; - mp_digit mp; - mp_digit buf; - int bitcnt = 0, mode = 0, digidx = 0; - - if (k == NULL || G == NULL || R == NULL || modulus == NULL) - return ECC_BAD_ARG_E; - - /* init variables */ - tG = NULL; - XMEMSET(M, 0, sizeof(M)); - - /* init montgomery reduction */ - if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { - return err; - } - if ((err = mp_init(&mu)) != MP_OKAY) { - return err; - } - if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { - mp_clear(&mu); - return err; - } - - /* alloc ram for window temps */ - for (i = 0; i < 3; i++) { - M[i] = wc_ecc_new_point_h(heap); - if (M[i] == NULL) { - for (j = 0; j < i; j++) { - wc_ecc_del_point_h(M[j], heap); - } - mp_clear(&mu); - return MEMORY_E; - } - } - - /* make a copy of G in case R==G */ - tG = wc_ecc_new_point_h(heap); - if (tG == NULL) - err = MEMORY_E; - - /* tG = G and convert to montgomery */ - if (err == MP_OKAY) - err = mp_mulmod(G->x, &mu, modulus, tG->x); - if (err == MP_OKAY) - err = mp_mulmod(G->y, &mu, modulus, tG->y); - if (err == MP_OKAY) - err = mp_mulmod(G->z, &mu, modulus, tG->z); - -#ifndef USE_FAST_MATH - /* done with mu */ - mp_clear(&mu); -#endif - /* calc the M tab */ /* M[0] == G */ if (err == MP_OKAY) @@ -2114,27 +2151,38 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, if (err == MP_OKAY) err = mp_copy(M[0]->z, R->z); +#endif /* ECC_TIMING_RESISTANT */ + /* map R back from projective space */ if (err == MP_OKAY && map) - err = ecc_map(R, modulus, mp); + err = ecc_map(R, modulus, mp); + +exit: /* done */ wc_ecc_del_point_h(tG, heap); - for (i = 0; i < 3; i++) { + for (i = 0; i < M_POINTS; i++) { wc_ecc_del_point_h(M[i], heap); } + return err; } - -#ifndef FP_ECC +/** ECC Fixed Point mulmod global + k The multiplicand + G Base point to multiply + R [out] Destination of product + a ECC curve parameter a + modulus The modulus for the curve + map [boolean] If non-zero maps the point back to affine co-ordinates, + otherwise it's left in jacobian-montgomery form + return MP_OKAY if successful +*/ int wc_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, - mp_int* modulus, int map) + mp_int* modulus, int map) { return wc_ecc_mulmod_ex(k, G, R, a, modulus, map, NULL); } -#endif /* ! FP_ECC */ -#endif /* ECC_TIMING_RESISTANT */ #endif /* !FREESCALE_LTC_ECC */ @@ -2307,13 +2355,7 @@ int wc_ecc_is_valid_idx(int n) int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, word32* outlen) { - int err = 0; -#ifndef WOLFSSL_ATECC508A - word32 x = 0; - ecc_point* result; - mp_int prime; - mp_int a; -#endif /* !WOLFSSL_ATECC508A */ + int err; if (private_key == NULL || public_key == NULL || out == NULL || outlen == NULL) { @@ -2331,8 +2373,8 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, return ECC_BAD_ARG_E; } - /* Verify curve name matches */ - if (XSTRNCMP(private_key->dp->name, public_key->dp->name, ECC_MAXNAME) != 0) { + /* Verify curve id matches */ + if (private_key->dp->id != public_key->dp->id) { return ECC_BAD_ARG_E; } @@ -2362,53 +2404,75 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, *outlen = private_key->dp->size; #else - - /* make new point */ - result = wc_ecc_new_point_h(private_key->heap); - if (result == NULL) { - return MEMORY_E; - } - - if ((err = mp_init_multi(&prime, &a, NULL, NULL, NULL, NULL)) != MP_OKAY) { - wc_ecc_del_point_h(result, private_key->heap); - return err; - } - - /* read in the specs for this curve */ - err = mp_read_radix(&prime, private_key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&a, private_key->dp->Af, 16); - - if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&private_key->k, &public_key->pubkey, result, &a, - &prime, 1, private_key->heap); - - if (err == MP_OKAY) { - x = mp_unsigned_bin_size(&prime); - if (*outlen < x) - err = BUFFER_E; - } - - if (err == MP_OKAY) { - XMEMSET(out, 0, x); - err = mp_to_unsigned_bin(result->x,out + (x - - mp_unsigned_bin_size(result->x))); - *outlen = x; - } - -#ifndef USE_FAST_MATH - mp_clear(&a); - mp_clear(&prime); -#endif - wc_ecc_del_point_h(result, private_key->heap); - + err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, outlen); #endif /* WOLFSSL_ATECC508A */ return err; } + #ifndef WOLFSSL_ATECC508A +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; + ecc_point* result = NULL; + word32 x = 0; + + /* make new point */ + result = wc_ecc_new_point_h(private_key->heap); + if (result == NULL) { + return MEMORY_E; + } + + err = wc_ecc_mulmod_ex(&private_key->k, point, result, + &curve->Af, &curve->prime, 1, private_key->heap); + if (err == MP_OKAY) { + x = mp_unsigned_bin_size(&curve->prime); + if (*outlen < x) { + err = BUFFER_E; + } + } + + if (err == MP_OKAY) { + XMEMSET(out, 0, x); + err = mp_to_unsigned_bin(result->x,out + + (x - mp_unsigned_bin_size(result->x))); + } + *outlen = x; + + wc_ecc_del_point_h(result, private_key->heap); + + return err; +} + + +int wc_ecc_shared_secret_gen(ecc_key* private_key, ecc_point* point, + byte* out, word32 *outlen) +{ + int err; + DECLARE_CURVE_SPECS + + if (private_key == NULL || point == NULL || out == NULL || + outlen == NULL) { + return BAD_FUNC_ARG; + } + + /* load curve info */ + err = wc_ecc_curve_load(private_key->dp, &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF)); + if (err != MP_OKAY) + return err; + + err = wc_ecc_shared_secret_gen_sync(private_key, point, + out, outlen, curve); + + wc_ecc_curve_free(curve); + + return err; +} + /** Create an ECC shared secret between private key and public point private_key The private ECC key (heap hint based on private key) @@ -2418,14 +2482,10 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, outlen [in/out] The max size and resulting size of the shared secret return MP_OKAY if successful */ -int wc_ecc_shared_secret_ssh(ecc_key* private_key, ecc_point* point, - byte* out, word32 *outlen) +int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point, + byte* out, word32 *outlen) { - word32 x = 0; - ecc_point* result; - mp_int prime; - mp_int a; - int err; + int err; if (private_key == NULL || point == NULL || out == NULL || outlen == NULL) { @@ -2441,44 +2501,33 @@ int wc_ecc_shared_secret_ssh(ecc_key* private_key, ecc_point* point, if (wc_ecc_is_valid_idx(private_key->idx) == 0) return ECC_BAD_ARG_E; - /* make new point */ - result = wc_ecc_new_point_h(private_key->heap); - if (result == NULL) { - return MEMORY_E; - } + switch(private_key->state) { + case ECC_STATE_NONE: + case ECC_STATE_SHARED_SEC_GEN: + private_key->state = ECC_STATE_SHARED_SEC_GEN; - if ((err = mp_init_multi(&prime, &a, NULL, NULL, NULL, NULL)) != MP_OKAY) { - wc_ecc_del_point_h(result, private_key->heap); + err = wc_ecc_shared_secret_gen(private_key, point, out, outlen); + if (err < 0) { + break; + } + + /* fall through */ + case ECC_STATE_SHARED_SEC_RES: + private_key->state = ECC_STATE_SHARED_SEC_RES; + err = 0; + break; + + default: + err = BAD_STATE_E; + } /* switch */ + + /* if async pending then return and skip done cleanup below */ + if (err == WC_PENDING_E) { + private_key->state++; return err; } - /* read in the specs for this curve */ - err = mp_read_radix(&prime, private_key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&a, private_key->dp->Af, 16); - - if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&private_key->k, point, result, &a, &prime, 1, - private_key->heap); - - if (err == MP_OKAY) { - x = mp_unsigned_bin_size(&prime); - if (*outlen < x) - err = BUFFER_E; - } - - if (err == MP_OKAY) { - XMEMSET(out, 0, x); - err = mp_to_unsigned_bin(result->x,out + - (x - mp_unsigned_bin_size(result->x))); - *outlen = x; - } - -#ifndef USE_FAST_MATH - mp_clear(&a); - mp_clear(&prime); -#endif - wc_ecc_del_point_h(result, private_key->heap); + private_key->state = ECC_STATE_NONE; return err; } @@ -2498,23 +2547,67 @@ int wc_ecc_point_is_at_infinity(ecc_point* p) return 0; } -#endif /* WOLFSSL_ATECC508A */ +/* generate random and ensure its greater than 0 and less than order */ +static int wc_ecc_gen_k(WC_RNG* rng, int size, mp_int* k, mp_int* order) +{ + int err; +#ifdef WOLFSSL_SMALL_STACK + byte* buf; +#else + byte buf[ECC_MAXSIZE_GEN]; +#endif +#ifdef WOLFSSL_SMALL_STACK + buf = (byte*)XMALLOC(ECC_MAXSIZE_GEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) + return MEMORY_E; +#endif + + /*generate 8 extra bytes to mitigate bias from the modulo operation below*/ + /*see section A.1.2 in 'Suite B Implementor's Guide to FIPS 186-3 (ECDSA)'*/ + size += 8; + + /* make up random string */ + err = wc_RNG_GenerateBlock(rng, buf, size); + + /* load random buffer data into k */ + if (err == 0) + err = mp_read_unsigned_bin(k, (byte*)buf, size); + + /* quick sanity check to make sure we're not dealing with a 0 key */ + if (err == MP_OKAY) { + if (mp_iszero(k) == MP_YES) + err = MP_ZERO_E; + } + + /* the key should be smaller than the order of base point */ + if (err == MP_OKAY) { + if (mp_cmp(k, order) != MP_LT) { + err = mp_mod(k, order, k); + } + } + +#ifdef HAVE_WOLF_BIGINT + if (err == MP_OKAY) + err = wc_mp_to_bigint(k, &k->raw); +#endif /* HAVE_WOLF_BIGINT */ + + ForceZero(buf, ECC_MAXSIZE); +#ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return err; +} +#endif /* !WOLFSSL_ATECC508A */ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) { int err; #ifndef WOLFSSL_ATECC508A ecc_point* base = NULL; - mp_int prime; - mp_int a; - mp_int order; -#ifdef WOLFSSL_SMALL_STACK - byte* buf; -#else - byte buf[ECC_MAXSIZE_GEN]; + DECLARE_CURVE_SPECS #endif -#endif /* !WOLFSSL_ATECC508A */ if (key == NULL || rng == NULL) { return BAD_FUNC_ARG; @@ -2541,7 +2634,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) } #endif } -#endif +#endif /* WOLFSSL_ASYNC_CRYPT */ #ifdef WOLFSSL_ATECC508A key->type = ECC_PRIVATEKEY; @@ -2552,99 +2645,54 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) #else -#ifdef WOLFSSL_SMALL_STACK - buf = (byte*)XMALLOC(ECC_MAXSIZE_GEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) - return MEMORY_E; -#endif - - /*generate 8 extra bytes to mitigate bias from the modulo operation below*/ - /*see section A.1.2 in 'Suite B Implementor's Guide to FIPS 186-3 (ECDSA)'*/ - keysize = key->dp->size + 8; - - /* make up random string */ - err = wc_RNG_GenerateBlock(rng, buf, keysize); - if (err != 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return err; - } - /* setup the key variables */ - err = mp_init_multi(&key->k, &prime, &order, &a, NULL, NULL); - if (err != MP_OKAY) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + err = mp_init(&key->k); + if (err == MP_OKAY) { + #ifndef ALT_ECC_SIZE + err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, + NULL, NULL, NULL); + #else + key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; + key->pubkey.y = (mp_int*)&key->pubkey.xyz[1]; + key->pubkey.z = (mp_int*)&key->pubkey.xyz[2]; + alt_fp_init(key->pubkey.x); + alt_fp_init(key->pubkey.y); + alt_fp_init(key->pubkey.z); #endif - return err; } -#ifndef ALT_ECC_SIZE - err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, - NULL, NULL, NULL); -#else - key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; - key->pubkey.y = (mp_int*)&key->pubkey.xyz[1]; - key->pubkey.z = (mp_int*)&key->pubkey.xyz[2]; - alt_fp_init(key->pubkey.x); - alt_fp_init(key->pubkey.y); - alt_fp_init(key->pubkey.z); -#endif - if (err == MP_OKAY) { base = wc_ecc_new_point_h(key->heap); if (base == NULL) err = MEMORY_E; } - /* read in the specs for this curve */ + /* load curve info */ if (err == MP_OKAY) - err = mp_read_radix(&prime, key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&order, key->dp->order, 16); - if (err == MP_OKAY) - err = mp_read_radix(&a, key->dp->Af, 16); + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); /* read in the x/y for this key */ if (err == MP_OKAY) - err = mp_read_radix(base->x, key->dp->Gx, 16); + err = mp_copy(&curve->Gx, base->x); if (err == MP_OKAY) - err = mp_read_radix(base->y, key->dp->Gy, 16); + err = mp_copy(&curve->Gy, base->y); if (err == MP_OKAY) mp_set(base->z, 1); - /* load random buffer data into k */ + /* generate k */ if (err == MP_OKAY) - err = mp_read_unsigned_bin(&key->k, (byte*)buf, keysize); - - /* quick sanity check to make sure we're not dealing with a 0 key */ - if (err == MP_OKAY) { - if (mp_iszero(&key->k) == MP_YES) - err = MP_ZERO_E; - } - - /* the key should be smaller than the order of base point */ - if (err == MP_OKAY) { - if (mp_cmp(&key->k, &order) != MP_LT) - err = mp_mod(&key->k, &order, &key->k); - } - - /* the key should be smaller than the order of base point */ - if (err == MP_OKAY) { - if (mp_cmp(&key->k, &order) != MP_LT) - err = mp_mod(&key->k, &order, &key->k); - } + err = wc_ecc_gen_k(rng, key->dp->size, &key->k, &curve->order); /* make the public key */ if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&key->k, base, &key->pubkey, &a, &prime, 1, - key->heap); + err = wc_ecc_mulmod_ex(&key->k, base, &key->pubkey, + &curve->Af, &curve->prime, 1, key->heap); #ifdef WOLFSSL_VALIDATE_ECC_KEYGEN /* validate the public key, order * pubkey = point at infinity */ if (err == MP_OKAY) - err = ecc_check_pubkey_order(key, &a, &prime, &order); + err = ecc_check_pubkey_order(key, &curve->Af, &curve->Bf, &curve->prime, + &curve->order); #endif /* WOLFSSL_VALIDATE_KEYGEN */ if (err == MP_OKAY) @@ -2652,24 +2700,19 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) /* cleanup these on failure case only */ if (err != MP_OKAY) { + /* clean up */ + #if !defined(USE_FAST_MATH) && !defined(ALT_ECC_SIZE) mp_clear(key->pubkey.x); mp_clear(key->pubkey.y); mp_clear(key->pubkey.z); + #endif mp_forcezero(&key->k); } /* cleanup allocations */ wc_ecc_del_point_h(base, key->heap); -#ifndef USE_FAST_MATH - mp_clear(&a); - mp_clear(&prime); - mp_clear(&order); -#endif + wc_ecc_curve_free(curve); - ForceZero(buf, ECC_MAXSIZE); -#ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif #endif /* WOLFSSL_ATECC508A */ return err; @@ -2745,6 +2788,23 @@ int wc_ecc_make_key(WC_RNG* rng, int keysize, ecc_key* key) return wc_ecc_make_key_ex(rng, keysize, key, ECC_CURVE_DEF); } +static void wc_ecc_free_rs(ecc_key* key) +{ + if (key->r) { + #ifndef USE_FAST_MATH + mp_clear(key->r); + #endif + XFREE(key->r, key->heap, DYNAMIC_TYPE_BIGINT); + key->r = NULL; + } + if (key->s) { + #ifndef USE_FAST_MATH + mp_clear(key->s); + #endif + XFREE(key->s, key->heap, DYNAMIC_TYPE_BIGINT); + key->s = NULL; + } +} /* Setup dynamic pointers if using normal math for proper freeing */ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) @@ -2755,14 +2815,12 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) return BAD_FUNC_ARG; } - (void)devId; - #ifdef ECC_DUMP_OID wc_ecc_dump_oids(); #endif - key->dp = NULL; - key->idx = 0; + XMEMSET(key, 0, sizeof(ecc_key)); + key->state = ECC_STATE_NONE; #ifdef WOLFSSL_ATECC508A key->slot = atmel_ecc_alloc(); @@ -2770,15 +2828,6 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) return ECC_BAD_ARG_E; } #else - -#ifndef USE_FAST_MATH - key->pubkey.x->dp = NULL; - key->pubkey.y->dp = NULL; - key->pubkey.z->dp = NULL; - - key->k.dp = NULL; -#endif - #ifdef ALT_ECC_SIZE if (mp_init(&key->k) != MP_OKAY) { return MEMORY_E; @@ -2790,8 +2839,7 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) alt_fp_init(key->pubkey.x); alt_fp_init(key->pubkey.y); alt_fp_init(key->pubkey.z); -#endif - +#endif /* ALT_ECC_SIZE */ #endif /* WOLFSSL_ATECC508A */ #ifdef WOLFSSL_HEAP_TEST @@ -2806,6 +2854,8 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) ret = wolfAsync_DevCtxInit(&key->asyncDev, WOLFSSL_ASYNC_MARKER_ECC, devId); } +#else + (void)devId; #endif return ret; @@ -2832,16 +2882,13 @@ int wc_ecc_init(ecc_key* key) int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, WC_RNG* rng, ecc_key* key) { - mp_int r; - mp_int s; - int err; + int err; - if (in == NULL || out == NULL || outlen == NULL || - key == NULL || rng == NULL) { + if (in == NULL || out == NULL || outlen == NULL || key == NULL || + rng == NULL) { return ECC_BAD_ARG_E; } - #ifdef WOLFSSL_ASYNC_CRYPT if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { #ifdef HAVE_CAVIUM @@ -2862,89 +2909,106 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, } #endif - /* is this a private key? */ - if (key->type != ECC_PRIVATEKEY) - return ECC_BAD_ARG_E; + switch(key->state) { + case ECC_STATE_NONE: + case ECC_STATE_SIGN_DO: + key->state = ECC_STATE_SIGN_DO; + if (key->r == NULL) + key->r = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, + DYNAMIC_TYPE_BIGINT); + if (key->s == NULL) + key->s = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, + DYNAMIC_TYPE_BIGINT); + if (key->r == NULL || key->s == NULL) { + err = MEMORY_E; break; + } + XMEMSET(key->r, 0, sizeof(mp_int)); + XMEMSET(key->s, 0, sizeof(mp_int)); - /* is the IDX valid ? */ - if (wc_ecc_is_valid_idx(key->idx) != 1) - return ECC_BAD_ARG_E; + if ((err = mp_init_multi(key->r, key->s, NULL, NULL, NULL, NULL)) + != MP_OKAY) { + break; + } - if ((err = mp_init_multi(&r, &s, NULL, NULL, NULL, NULL)) != MP_OKAY) { + + #ifdef WOLFSSL_ATECC508A + /* Check args */ + if (inlen != ATECC_KEY_SIZE || *outlen < SIGN_RSP_SIZE) { + return ECC_BAD_ARG_E; + } + + /* Sign: Result is 32-bytes of R then 32-bytes of S */ + err = atcatls_sign(key->slot, in, out); + if (err != ATCA_SUCCESS) { + return BAD_COND_E; + } + + /* Load R and S */ + err = mp_read_unsigned_bin(key->r, &out[0], ATECC_KEY_SIZE); + if (err != MP_OKAY) { + return err; + } + err = mp_read_unsigned_bin(key->s, &out[ATECC_KEY_SIZE], ATECC_KEY_SIZE); + if (err != MP_OKAY) { + return err; + } + + /* Check for zeros */ + if (mp_iszero(key->r) || mp_iszero(key->s)) { + return MP_ZERO_E; + } + + #else + + err = wc_ecc_sign_hash_ex(in, inlen, rng, key, key->r, key->s); + if (err < 0) { + break; + } + + #endif /* WOLFSSL_ATECC508A */ + + /* fall through */ + case ECC_STATE_SIGN_ENCODE: + key->state = ECC_STATE_SIGN_ENCODE; + + /* encoded with DSA header */ + err = StoreECC_DSA_Sig(out, outlen, key->r, key->s); + break; + + default: + err = BAD_STATE_E; + } + + /* if async pending then return and skip done cleanup below */ + if (err == WC_PENDING_E) { + key->state++; return err; } -#ifdef WOLFSSL_ATECC508A - /* Check args */ - if (inlen != ATECC_KEY_SIZE || *outlen < SIGN_RSP_SIZE) { - err = ECC_BAD_ARG_E; - goto exit_sign; - } + wc_ecc_free_rs(key); - /* Sign: Result is 32-bytes of R then 32-bytes of S */ - err = atcatls_sign(key->slot, in, out); - if (err != ATCA_SUCCESS) { - err = BAD_COND_E; - goto exit_sign; - } - - /* Load R and S */ - err = mp_read_unsigned_bin(&r, &out[0], ATECC_KEY_SIZE); - if (err != MP_OKAY) { - goto exit_sign; - } - err = mp_read_unsigned_bin(&s, &out[ATECC_KEY_SIZE], ATECC_KEY_SIZE); - if (err != MP_OKAY) { - goto exit_sign; - } - - /* Check for zeros */ - if (mp_iszero(&r) || mp_iszero(&s)) { - err = MP_ZERO_E; - goto exit_sign; - } - -#else - - err = wc_ecc_sign_hash_ex(in, inlen, rng, key, &r, &s); - if (err != MP_OKAY) { - goto exit_sign; - } - - err = StoreECC_DSA_Sig(out, outlen, &r, &s); - -#endif /* WOLFSSL_ATECC508A */ - -exit_sign: - -#ifndef USE_FAST_MATH - mp_clear(&r); - mp_clear(&s); -#endif + key->state = ECC_STATE_NONE; return err; } #endif /* !NO_ASN */ #ifndef WOLFSSL_ATECC508A - /** Sign a message digest in The message digest to sign inlen The length of the digest - out [out] The destination for the signature - outlen [in/out] The max size and resulting size of the signature key A private ECC key r [out] The destination for r component of the signature - s [out] The destination for s component of the signature + s [out] The destination for s component of the signature return MP_OKAY if successful */ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, ecc_key* key, mp_int *r, mp_int *s) { + int err; mp_int e; - mp_int p; - int err; + DECLARE_CURVE_SPECS if (in == NULL || r == NULL || s == NULL || key == NULL || rng == NULL) return ECC_BAD_ARG_E; @@ -2961,18 +3025,21 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, /* get the hash and load it as a bignum into 'e' */ /* init the bignums */ - if ((err = mp_init_multi(&p, &e, NULL, NULL, NULL, NULL)) != MP_OKAY) { + if ((err = mp_init(&e)) != MP_OKAY) { return err; } - err = mp_read_radix(&p, key->dp->order, 16); + /* load curve info */ + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ORDER); + + /* load digest into e */ if (err == MP_OKAY) { /* we may need to truncate if hash is longer than key size */ - word32 orderBits = mp_count_bits(&p); + word32 orderBits = mp_count_bits(&curve->order); /* truncate down to byte size, may be all that's needed */ - if ( (WOLFSSL_BIT_SIZE * inlen) > orderBits) - inlen = (orderBits + WOLFSSL_BIT_SIZE - 1)/WOLFSSL_BIT_SIZE; + if ((WOLFSSL_BIT_SIZE * inlen) > orderBits) + inlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE; err = mp_read_unsigned_bin(&e, (byte*)in, inlen); /* may still need bit truncation too */ @@ -2984,6 +3051,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, if (err == MP_OKAY) { int loop_check = 0; ecc_key pubkey; + if (wc_ecc_init(&pubkey) == MP_OKAY) { for (;;) { if (++loop_check > 64) { @@ -2995,31 +3063,36 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, if (err != MP_OKAY) break; /* find r = x1 mod n */ - err = mp_mod(pubkey.pubkey.x, &p, r); + err = mp_mod(pubkey.pubkey.x, &curve->order, r); if (err != MP_OKAY) break; if (mp_iszero(r) == MP_YES) { + #ifndef USE_FAST_MATH mp_clear(pubkey.pubkey.x); mp_clear(pubkey.pubkey.y); mp_clear(pubkey.pubkey.z); mp_clear(&pubkey.k); + #endif } else { /* find s = (e + xr)/k */ - err = mp_invmod(&pubkey.k, &p, &pubkey.k); + err = mp_invmod(&pubkey.k, &curve->order, &pubkey.k); if (err != MP_OKAY) break; - err = mp_mulmod(&key->k, r, &p, s); /* s = xr */ + /* s = xr */ + err = mp_mulmod(&key->k, r, &curve->order, s); if (err != MP_OKAY) break; - err = mp_add(&e, s, s); /* s = e + xr */ + /* s = e + xr */ + err = mp_add(&e, s, s); if (err != MP_OKAY) break; - err = mp_mod(s, &p, s); /* s = e + xr */ + /* s = e + xr */ + err = mp_mod(s, &curve->order, s); if (err != MP_OKAY) break; - err = mp_mulmod(s, &pubkey.k, &p, s); /* s = (e + xr)/k */ - if (err != MP_OKAY) break; + /* s = (e + xr)/k */ + err = mp_mulmod(s, &pubkey.k, &curve->order, s); if (mp_iszero(s) == MP_NO) break; @@ -3030,13 +3103,13 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, } #ifndef USE_FAST_MATH - mp_clear(&p); mp_clear(&e); #endif + wc_ecc_curve_free(curve); return err; } -#endif /* !WOLFSSL_ATECC508A */ +#endif /* WOLFSSL_ATECC508A */ #endif /* HAVE_ECC_SIGN */ /** @@ -3045,30 +3118,31 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, */ void wc_ecc_free(ecc_key* key) { - if (key == NULL) { - return; - } + if (key == NULL) { + return; + } #ifdef WOLFSSL_ASYNC_CRYPT if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA) { wolfAsync_DevCtxFree(&key->asyncDev); } #endif + wc_ecc_free_rs(key); #ifdef WOLFSSL_ATECC508A atmel_ecc_free(key->slot); key->slot = -1; #else - mp_clear(key->pubkey.x); - mp_clear(key->pubkey.y); - mp_clear(key->pubkey.z); - mp_forcezero(&key->k); -#endif /* !WOLFSSL_ATECC508A */ +#ifndef USE_FAST_MATH + mp_clear(key->pubkey.x); + mp_clear(key->pubkey.y); + mp_clear(key->pubkey.z); +#endif + mp_forcezero(&key->k); +#endif /* WOLFSSL_ATECC508A */ } - -#ifndef WOLFSSL_ATECC508A #ifdef ECC_SHAMIR /** Computes kA*A + kB*B = C using Shamir's Trick @@ -3295,7 +3369,6 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, } #endif /* ECC_SHAMIR */ -#endif /* !WOLFSSL_ATECC508A */ #ifdef HAVE_ECC_VERIFY @@ -3323,20 +3396,12 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, word32 hashlen, int* stat, ecc_key* key) { - mp_int r; - mp_int s; - int err; -#ifdef WOLFSSL_ATECC508A - byte sigRS[ATECC_KEY_SIZE*2]; -#endif + int err; if (sig == NULL || hash == NULL || stat == NULL || key == NULL) { return ECC_BAD_ARG_E; } - /* default to invalid signature */ - *stat = 0; - #ifdef WOLFSSL_ASYNC_CRYPT if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { #ifdef HAVE_CAVIUM @@ -3357,54 +3422,71 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, } #endif - /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s. - * If either of those don't allocate correctly, none of - * the rest of this function will execute, and everything - * gets cleaned up at the end. */ - XMEMSET(&r, 0, sizeof(r)); - XMEMSET(&s, 0, sizeof(s)); + switch(key->state) { + case ECC_STATE_NONE: + case ECC_STATE_VERIFY_DECODE: + key->state = ECC_STATE_VERIFY_DECODE; - err = DecodeECC_DSA_Sig(sig, siglen, &r, &s); - if (err != 0) { - goto exit_verify; + /* default to invalid signature */ + *stat = 0; + + /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s. + * If either of those don't allocate correctly, none of + * the rest of this function will execute, and everything + * gets cleaned up at the end. */ + if (key->r == NULL) + key->r = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, + DYNAMIC_TYPE_BIGINT); + if (key->s == NULL) + key->s = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, + DYNAMIC_TYPE_BIGINT); + if (key->r == NULL || key->s == NULL) { + err = MEMORY_E; break; + } + XMEMSET(key->r, 0, sizeof(mp_int)); + XMEMSET(key->s, 0, sizeof(mp_int)); + + /* decode DSA header */ + err = DecodeECC_DSA_Sig(sig, siglen, key->r, key->s); + if (err < 0) { + break; + } + + /* fall through */ + case ECC_STATE_VERIFY_DO: + key->state = ECC_STATE_VERIFY_DO; + + err = wc_ecc_verify_hash_ex(key->r, key->s, hash, hashlen, stat, + key); + if (err < 0) { + break; + } + + /* fall through */ + case ECC_STATE_VERIFY_RES: + key->state = ECC_STATE_VERIFY_RES; + err = 0; + break; + + default: + err = BAD_STATE_E; } -#ifdef WOLFSSL_ATECC508A - /* Extract R and S */ - err = mp_to_unsigned_bin(&r, &sigRS[0]); - if (err != MP_OKAY) { - goto exit_verify; - } - err = mp_to_unsigned_bin(&s, &sigRS[ATECC_KEY_SIZE]); - if (err != MP_OKAY) { - goto exit_verify; + /* if async pending then return and skip done cleanup below */ + if (err == WC_PENDING_E) { + key->state++; + return err; } - err = atcatls_verify(hash, sigRS, key->pubkey, (bool*)stat); - if (err != ATCA_SUCCESS) { - err = BAD_COND_E; - } + wc_ecc_free_rs(key); -#else - - err = wc_ecc_verify_hash_ex(&r, &s, hash, hashlen, stat, key); - -#endif /* WOLFSSL_ATECC508A */ - -exit_verify: - -#ifndef USE_FAST_MATH - mp_clear(&r); - mp_clear(&s); -#endif + key->state = ECC_STATE_NONE; return err; } #endif /* !NO_ASN */ -#ifndef WOLFSSL_ATECC508A - /** Verify an ECC signature r The signature R component to verify @@ -3418,16 +3500,18 @@ exit_verify: int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, word32 hashlen, int* stat, ecc_key* key) { + int err; +#ifndef WOLFSSL_ATECC508A ecc_point *mG = NULL, *mQ = NULL; mp_int v; mp_int w; mp_int u1; mp_int u2; mp_int e; - mp_int order; - mp_int modulus; - mp_int a; - int err; + DECLARE_CURVE_SPECS +#else + byte sigRS[ATECC_KEY_SIZE*2]; +#endif if (r == NULL || s == NULL || hash == NULL || stat == NULL || key == NULL) return ECC_BAD_ARG_E; @@ -3440,33 +3524,36 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, return ECC_BAD_ARG_E; } - /* allocate ints */ - if ((err = mp_init_multi(&v, &w, &u1, &u2, &order, &e)) != MP_OKAY) { +#ifdef WOLFSSL_ATECC508A + /* Extract R and S */ + err = mp_to_unsigned_bin(r, &sigRS[0]); + if (err != MP_OKAY) { + return err; + } + err = mp_to_unsigned_bin(s, &sigRS[ATECC_KEY_SIZE]); + if (err != MP_OKAY) { + return err; + } + + err = atcatls_verify(hash, sigRS, key->pubkey, (bool*)stat); + if (err != ATCA_SUCCESS) { + return BAD_COND_E; + } + +#else + + err = mp_init(&e); + if (err != MP_OKAY) return MEMORY_E; - } - - if ((err = mp_init_multi(&modulus, &a, NULL, NULL, NULL, NULL)) != MP_OKAY) { - err = MEMORY_E; goto done; - } - - /* allocate points */ - mG = wc_ecc_new_point_h(key->heap); - mQ = wc_ecc_new_point_h(key->heap); - if (mQ == NULL || mG == NULL) - err = MEMORY_E; /* read in the specs for this curve */ - if (err == MP_OKAY) - err = mp_read_radix(&order, key->dp->order, 16); - if (err == MP_OKAY) - err = mp_read_radix(&modulus, key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&a, key->dp->Af, 16); + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); /* check for zero */ if (err == MP_OKAY) { if (mp_iszero(r) == MP_YES || mp_iszero(s) == MP_YES || - mp_cmp(r, &order) != MP_LT || mp_cmp(s, &order) != MP_LT) { + mp_cmp(r, &curve->order) != MP_LT || + mp_cmp(s, &curve->order) != MP_LT) { err = MP_ZERO_E; } } @@ -3474,11 +3561,11 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* read hash */ if (err == MP_OKAY) { /* we may need to truncate if hash is longer than key size */ - unsigned int orderBits = mp_count_bits(&order); + unsigned int orderBits = mp_count_bits(&curve->order); /* truncate down to byte size, may be all that's needed */ if ( (WOLFSSL_BIT_SIZE * hashlen) > orderBits) - hashlen = (orderBits + WOLFSSL_BIT_SIZE - 1)/WOLFSSL_BIT_SIZE; + hashlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE; err = mp_read_unsigned_bin(&e, hash, hashlen); /* may still need bit truncation too */ @@ -3486,24 +3573,36 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, mp_rshb(&e, WOLFSSL_BIT_SIZE - (orderBits & 0x7)); } + /* allocate ints */ + if ((err = mp_init_multi(&v, &w, &u1, &u2, NULL, NULL)) != MP_OKAY) { + err = MEMORY_E; + } + + /* allocate points */ + if (err == MP_OKAY) { + mG = wc_ecc_new_point_h(key->heap); + mQ = wc_ecc_new_point_h(key->heap); + if (mQ == NULL || mG == NULL) + err = MEMORY_E; + } + /* w = s^-1 mod n */ if (err == MP_OKAY) - err = mp_invmod(s, &order, &w); + err = mp_invmod(s, &curve->order, &w); /* u1 = ew */ if (err == MP_OKAY) - err = mp_mulmod(&e, &w, &order, &u1); + err = mp_mulmod(&e, &w, &curve->order, &u1); /* u2 = rw */ if (err == MP_OKAY) - err = mp_mulmod(r, &w, &order, &u2); + err = mp_mulmod(r, &w, &curve->order, &u2); /* find mG and mQ */ if (err == MP_OKAY) - err = mp_read_radix(mG->x, key->dp->Gx, 16); - + err = mp_copy(&curve->Gx, mG->x); if (err == MP_OKAY) - err = mp_read_radix(mG->y, key->dp->Gy, 16); + err = mp_copy(&curve->Gy, mG->y); if (err == MP_OKAY) mp_set(mG->z, 1); @@ -3517,11 +3616,11 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #ifdef FREESCALE_LTC_ECC /* use PKHA to compute u1*mG + u2*mQ */ if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&u1, mG, mG, &a, &modulus, 0, NULL); + err = wc_ecc_mulmod_ex(&u1, mG, mG, &curve->Af, &curve->prime, 0, key->heap); if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&u2, mQ, mQ, &a, &modulus, 0, NULL); + err = wc_ecc_mulmod_ex(&u2, mQ, mQ, &curve->Af, &curve->prime, 0, key->heap); if (err == MP_OKAY) - err = wc_ecc_point_add(mG, mQ, mG, &modulus); + err = wc_ecc_point_add(mG, mQ, mG, &curve->prime); #else /* FREESCALE_LTC_ECC */ #ifndef ECC_SHAMIR { @@ -3529,31 +3628,35 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* compute u1*mG + u2*mQ = mG */ if (err == MP_OKAY) - err = wc_ecc_mulmod(&u1, mG, mG, &a, &modulus, 0); + err = wc_ecc_mulmod(&u1, mG, mG, &curve->Af, &curve->Bf, + &curve->prime, 0); if (err == MP_OKAY) - err = wc_ecc_mulmod(&u2, mQ, mQ, &a, &modulus, 0); + err = wc_ecc_mulmod(&u2, mQ, mQ, &curve->Af, &curve->Bf, + &curve->prime, 0); /* find the montgomery mp */ if (err == MP_OKAY) - err = mp_montgomery_setup(&modulus, &mp); + err = mp_montgomery_setup(&curve->prime, &mp); /* add them */ if (err == MP_OKAY) - err = ecc_projective_add_point(mQ, mG, mG, &a, &modulus, mp); + err = ecc_projective_add_point(mQ, mG, mG, &curve->Af, + &curve->prime, mp); /* reduce */ if (err == MP_OKAY) - err = ecc_map(mG, &modulus, mp); + err = ecc_map(mG, &curve->prime, mp); } #else /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */ if (err == MP_OKAY) - err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &a, &modulus, key->heap); + err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &curve->Af, &curve->prime, + key->heap); #endif /* ECC_SHAMIR */ #endif /* FREESCALE_LTC_ECC */ /* v = X_x1 mod n */ if (err == MP_OKAY) - err = mp_mod(mG->x, &order, &v); + err = mp_mod(mG->x, &curve->order, &v); /* does v == r */ if (err == MP_OKAY) { @@ -3561,25 +3664,22 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, *stat = 1; } -done: /* cleanup */ wc_ecc_del_point_h(mG, key->heap); wc_ecc_del_point_h(mQ, key->heap); #ifndef USE_FAST_MATH + mp_clear(&e); mp_clear(&v); mp_clear(&w); mp_clear(&u1); mp_clear(&u2); - mp_clear(&order); - mp_clear(&e); - mp_clear(&modulus); - mp_clear(&a); #endif +#endif /* WOLFSSL_ATECC508A */ + return err; } -#endif /* !WOLFSSL_ATECC508A */ #endif /* HAVE_ECC_VERIFY */ #ifdef HAVE_ECC_KEY_IMPORT @@ -3790,15 +3890,16 @@ done: /* export public ECC key in ANSI X9.63 format */ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) { - word32 numlen; int ret = MP_OKAY; + word32 numlen; #ifndef WOLFSSL_ATECC508A #ifdef WOLFSSL_SMALL_STACK byte* buf; #else byte buf[ECC_BUFSIZE]; #endif -#endif + word32 pubxlen, pubylen; +#endif /* WOLFSSL_ATECC508A */ /* return length needed only */ if (key != NULL && out == NULL && outLen != NULL) { @@ -3815,6 +3916,7 @@ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) } numlen = key->dp->size; + /* verify room in out buffer */ if (*outLen < (1 + 2*numlen)) { *outLen = 1 + 2*numlen; return BUFFER_E; @@ -3826,6 +3928,14 @@ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) #else + /* verify public key length is less than key size */ + pubxlen = mp_unsigned_bin_size(key->pubkey.x); + pubylen = mp_unsigned_bin_size(key->pubkey.y); + if ((pubxlen > numlen) || (pubylen > numlen)) { + WOLFSSL_MSG("Public key x/y invalid!"); + return BUFFER_E; + } + /* store byte 0x04 */ out[0] = 0x04; @@ -3835,23 +3945,21 @@ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) return MEMORY_E; #endif - /* pad and store x */ - XMEMSET(buf, 0, ECC_BUFSIZE); - ret = mp_to_unsigned_bin(key->pubkey.x, - buf + (numlen - mp_unsigned_bin_size(key->pubkey.x))); - if (ret != MP_OKAY) - goto done; - XMEMCPY(out+1, buf, numlen); + /* pad and store x */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(key->pubkey.x, buf + (numlen - pubxlen)); + if (ret != MP_OKAY) + goto done; + XMEMCPY(out+1, buf, numlen); - /* pad and store y */ - XMEMSET(buf, 0, ECC_BUFSIZE); - ret = mp_to_unsigned_bin(key->pubkey.y, - buf + (numlen - mp_unsigned_bin_size(key->pubkey.y))); - if (ret != MP_OKAY) - goto done; - XMEMCPY(out+1+numlen, buf, numlen); + /* pad and store y */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(key->pubkey.y, buf + (numlen - pubylen)); + if (ret != MP_OKAY) + goto done; + XMEMCPY(out+1+numlen, buf, numlen); - *outLen = 1 + 2*numlen; + *outLen = 1 + 2*numlen; done: #ifdef WOLFSSL_SMALL_STACK @@ -3975,9 +4083,10 @@ static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime) /* validate privkey * generator == pubkey, 0 on success */ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) { - int err = MP_OKAY; + int err = MP_OKAY; ecc_point* base = NULL; ecc_point* res = NULL; + DECLARE_CURVE_SPECS; if (key == NULL) return BAD_FUNC_ARG; @@ -3986,10 +4095,15 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) if (base == NULL) return MEMORY_E; + /* load curve info */ + err = wc_ecc_curve_load(key->dp, &curve, + (ECC_CURVE_FIELD_GX | ECC_CURVE_FIELD_GY)); + /* set up base generator */ - err = mp_read_radix(base->x, key->dp->Gx, 16); if (err == MP_OKAY) - err = mp_read_radix(base->y, key->dp->Gy, 16); + err = mp_copy(&curve->Gx, base->x); + if (err == MP_OKAY) + err = mp_copy(&curve->Gy, base->y); if (err == MP_OKAY) mp_set(base->z, 1); @@ -4011,23 +4125,22 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) } } + wc_ecc_curve_free(curve); wc_ecc_del_point_h(res, key->heap); wc_ecc_del_point_h(base, key->heap); return err; } - #ifdef WOLFSSL_VALIDATE_ECC_IMPORT /* check privkey generator helper, creates prime needed */ static int ecc_check_privkey_gen_helper(ecc_key* key) { - int err = MP_OKAY; + int err; #ifndef WOLFSSL_ATECC508A - mp_int prime; - mp_int a; -#endif /* !WOLFSSL_ATECC508A */ + DECLARE_CURVE_SPECS +#endif if (key == NULL) return BAD_FUNC_ARG; @@ -4038,22 +4151,15 @@ static int ecc_check_privkey_gen_helper(ecc_key* key) #else - err = mp_init_multi(&prime, &a, NULL, NULL, NULL, NULL); - if (err != MP_OKAY) - return err; - - err = mp_read_radix(&prime, key->dp->prime, 16); + /* load curve info */ + err = wc_ecc_curve_load(key->dp, &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF)); if (err == MP_OKAY) - err = mp_read_radix(&a, key->dp->Af, 16); + err = ecc_check_privkey_gen(key, &curve->Af, &curve->prime); - if (err == MP_OKAY) - err = ecc_check_privkey_gen(key, &a, &prime); + wc_ecc_curve_free(curve); -#ifndef USE_FAST_MATH - mp_clear(&prime); - mp_clear(&a); -#endif #endif /* WOLFSSL_ATECC508A */ return err; @@ -4076,8 +4182,7 @@ static int ecc_check_pubkey_order(ecc_key* key, mp_int* a, mp_int* prime, if (inf == NULL) err = MEMORY_E; else { - err = wc_ecc_mulmod_ex(order, &key->pubkey, inf, a, prime, 1, - key->heap); + err = wc_ecc_mulmod_ex(order, &key->pubkey, inf, a, prime, 1, key->heap); if (err == MP_OKAY && !wc_ecc_point_is_at_infinity(inf)) err = ECC_INF_E; } @@ -4093,12 +4198,10 @@ static int ecc_check_pubkey_order(ecc_key* key, mp_int* a, mp_int* prime, /* perform sanity checks on ecc key validity, 0 on success */ int wc_ecc_check_key(ecc_key* key) { - int err = MP_OKAY; + int err; #ifndef WOLFSSL_ATECC508A - mp_int prime; /* used by multiple calls so let's cache */ - mp_int a; - mp_int order; /* other callers have, so let's gen here */ -#endif /* !WOLFSSL_ATECC508A */ + DECLARE_CURVE_SPECS +#endif /* WOLFSSL_ATECC508A */ if (key == NULL) return BAD_FUNC_ARG; @@ -4113,35 +4216,24 @@ int wc_ecc_check_key(ecc_key* key) if (wc_ecc_point_is_at_infinity(&key->pubkey)) return ECC_INF_E; - err = mp_init_multi(&prime, &a, &order, NULL, NULL, NULL); - if (err != MP_OKAY) - return err; - - /* read in the specs for this curve */ - if (err == MP_OKAY) - err = mp_read_radix(&prime, key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&a, key->dp->Af, 16); - if (err == MP_OKAY) - err = mp_read_radix(&order, key->dp->order, 16); + /* load curve info */ + err = wc_ecc_curve_load(key->dp, &curve, (ECC_CURVE_FIELD_PRIME | + ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_BF | ECC_CURVE_FIELD_ORDER)); /* make sure point is actually on curve */ if (err == MP_OKAY) - err = ecc_is_point(key->dp, &key->pubkey, &prime); + err = ecc_is_point(key->dp, &key->pubkey, &curve->prime); /* pubkey * order must be at infinity */ if (err == MP_OKAY) - err = ecc_check_pubkey_order(key, &a, &prime, &order); + err = ecc_check_pubkey_order(key, &curve->Af, &curve->prime, &curve->order); /* private * base generator must equal pubkey */ if (err == MP_OKAY && key->type == ECC_PRIVATEKEY) - err = ecc_check_privkey_gen(key, &a, &prime); + err = ecc_check_privkey_gen(key, &curve->Af, &curve->prime); + + wc_ecc_curve_free(curve); -#ifndef USE_FAST_MATH - mp_clear(&order); - mp_clear(&a); - mp_clear(&prime); -#endif #endif /* WOLFSSL_ATECC508A */ return err; @@ -4218,63 +4310,59 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, #ifdef HAVE_COMP_KEY if (err == MP_OKAY && compressed == 1) { /* build y */ - mp_int t1, t2, prime, a, b; - int did_init = 0; + DECLARE_CURVE_SPECS + mp_int t1, t2; - if (mp_init_multi(&t1, &t2, &prime, &a, &b, NULL) != MP_OKAY) + if (mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL) != MP_OKAY) err = MEMORY_E; else did_init = 1; - /* read in the specs for this curve */ + /* load curve info */ if (err == MP_OKAY) - err = mp_read_radix(&prime, key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&a, key->dp->Af, 16); - if (err == MP_OKAY) - err = mp_read_radix(&b, key->dp->Bf, 16); + err = wc_ecc_curve_load(key->dp, &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF | + ECC_CURVE_FIELD_BF)); /* compute x^3 */ if (err == MP_OKAY) err = mp_sqr(key->pubkey.x, &t1); if (err == MP_OKAY) - err = mp_mulmod(&t1, key->pubkey.x, &prime, &t1); + err = mp_mulmod(&t1, key->pubkey.x, &curve->prime, &t1); /* compute x^3 + a*x */ if (err == MP_OKAY) - err = mp_mulmod(&a, key->pubkey.x, &prime, &t2); + err = mp_mulmod(&curve->Af, key->pubkey.x, &curve->prime, &t2); if (err == MP_OKAY) err = mp_add(&t1, &t2, &t1); /* compute x^3 + a*x + b */ if (err == MP_OKAY) - err = mp_add(&t1, &b, &t1); + err = mp_add(&t1, &curve->Bf, &t1); /* compute sqrt(x^3 + a*x + b) */ if (err == MP_OKAY) - err = mp_sqrtmod_prime(&t1, &prime, &t2); + err = mp_sqrtmod_prime(&t1, &curve->prime, &t2); /* adjust y */ if (err == MP_OKAY) { if ((mp_isodd(&t2) == MP_YES && in[0] == 0x03) || (mp_isodd(&t2) == MP_NO && in[0] == 0x02)) { - err = mp_mod(&t2, &prime, &t2); + err = mp_mod(&t2, &curve->prime, &t2); } else { - err = mp_submod(&prime, &t2, &prime, &t2); + err = mp_submod(&curve->prime, &t2, &curve->prime, &t2); } mp_copy(&t2, key->pubkey.y); } if (did_init) { #ifndef USE_FAST_MATH - mp_clear(&a); - mp_clear(&b); - mp_clear(&prime); - mp_clear(&t2); - mp_clear(&t1); + mp_clear(&t2); + mp_clear(&t1); #endif - } + + wc_ecc_curve_free(curve); } #endif /* HAVE_COMP_KEY */ @@ -5873,7 +5961,6 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, } #endif /* ECC_SHAMIR */ -#if !defined(FREESCALE_LTC_TFM) /** ECC Fixed Point mulmod global k The multiplicand G Base point to multiply @@ -5884,22 +5971,6 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, otherwise it's left in jacobian-montgomery form return MP_OKAY if successful */ -int wc_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, - mp_int* modulus, int map) -{ - return wc_ecc_mulmod_ex(k, G, R, a, modulus, map, NULL); -} -#endif /* !FREESCALE_LTC_TFM */ - -/** ECC Fixed Point mulmod global - k The multiplicand - G Base point to multiply - R [out] Destination of product - modulus The modulus for the curve - map [boolean] If non-zero maps the point back to affine co-ordinates, - otherwise it's left in jacobian-montgomery form - return MP_OKAY if successful -*/ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, mp_int* modulus, int map, void* heap) { diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 060e5f861..96e7d9092 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -47,6 +47,45 @@ extern "C" { #endif + +/* Use this as the key->idx if a custom ecc_set is used for key->dp */ +#define ECC_CUSTOM_IDX (-1) + + +/* Determine max ECC bits based on enabled curves */ +#if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) + #define MAX_ECC_BITS 521 +#elif defined(HAVE_ECC512) + #define MAX_ECC_BITS 512 +#elif defined(HAVE_ECC384) + #define MAX_ECC_BITS 384 +#elif defined(HAVE_ECC320) + #define MAX_ECC_BITS 320 +#elif defined(HAVE_ECC239) + #define MAX_ECC_BITS 239 +#elif defined(HAVE_ECC224) + #define MAX_ECC_BITS 224 +#elif !defined(NO_ECC256) + #define MAX_ECC_BITS 256 +#elif defined(HAVE_ECC192) + #define MAX_ECC_BITS 192 +#elif defined(HAVE_ECC160) + #define MAX_ECC_BITS 160 +#elif defined(HAVE_ECC128) + #define MAX_ECC_BITS 128 +#elif defined(HAVE_ECC112) + #define MAX_ECC_BITS 112 +#endif + +/* calculate max ECC bytes */ +#if ((MAX_ECC_BITS * 2) % 8) == 0 + #define MAX_ECC_BYTES (MAX_ECC_BITS / 8) +#else + /* add byte if not aligned */ + #define MAX_ECC_BYTES ((MAX_ECC_BITS / 8) + 1) +#endif + + enum { ECC_PUBLICKEY = 1, ECC_PRIVATEKEY = 2, @@ -58,6 +97,7 @@ enum { ECC_MAXSIZE_GEN = 74, /* MAX Buffer size required when generating ECC keys*/ ECC_MAX_PAD_SZ = 4, /* ECC maximum padding size */ ECC_MAX_OID_LEN = 16, + ECC_MAX_SIG_SIZE= ((MAX_ECC_BYTES * 2) + SIG_HEADER_SZ) }; /* Curve Types */ @@ -110,7 +150,7 @@ typedef byte ecc_oid_t; #endif /* ECC set type defined a GF(p) curve */ -typedef struct { +typedef struct ecc_set_type { int size; /* The size of the curve in octets */ int id; /* id of this curve */ const char* name; /* name of this curve */ @@ -126,36 +166,29 @@ typedef struct { int cofactor; } ecc_set_type; +typedef struct ecc_curve_spec { + const ecc_set_type* dp; -/* Use this as the key->idx if a custom ecc_set is used for key->dp */ -#define ECC_CUSTOM_IDX (-1) + mp_int prime; + mp_int Af; + mp_int Bf; + mp_int order; + mp_int Gx; + mp_int Gy; + byte load_mask; +} ecc_curve_spec; -/* Determine max ECC bits based on enabled curves */ -#if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) - #define MAX_ECC_BITS 521 -#elif defined(HAVE_ECC512) - #define MAX_ECC_BITS 512 -#elif defined(HAVE_ECC384) - #define MAX_ECC_BITS 384 -#elif defined(HAVE_ECC320) - #define MAX_ECC_BITS 320 -#elif defined(HAVE_ECC239) - #define MAX_ECC_BITS 239 -#elif defined(HAVE_ECC224) - #define MAX_ECC_BITS 224 -#elif !defined(NO_ECC256) - #define MAX_ECC_BITS 256 -#elif defined(HAVE_ECC192) - #define MAX_ECC_BITS 192 -#elif defined(HAVE_ECC160) - #define MAX_ECC_BITS 160 -#elif defined(HAVE_ECC128) - #define MAX_ECC_BITS 128 -#elif defined(HAVE_ECC112) - #define MAX_ECC_BITS 112 -#endif - +enum ecc_curve_load_mask { + ECC_CURVE_FIELD_NONE = 0x00, + ECC_CURVE_FIELD_PRIME = 0x01, + ECC_CURVE_FIELD_AF = 0x02, + ECC_CURVE_FIELD_BF = 0x04, + ECC_CURVE_FIELD_ORDER = 0x08, + ECC_CURVE_FIELD_GX = 0x10, + ECC_CURVE_FIELD_GY = 0x20, + ECC_CURVE_FIELD_ALL = 0xFF +}; #ifdef ALT_ECC_SIZE @@ -238,6 +271,7 @@ typedef struct ecc_key { int idx; /* Index into the ecc_sets[] for the parameters of this curve if -1, this key is using user supplied curve in dp */ + int state; const ecc_set_type* dp; /* domain parameters, either points to NIST curves (idx >= 0) or user supplied */ void* heap; /* heap hint */ @@ -248,6 +282,8 @@ typedef struct ecc_key { ecc_point pubkey; /* public key */ mp_int k; /* private key */ #endif + mp_int* r; /* sign/verify temps */ + mp_int* s; #ifdef WOLFSSL_ASYNC_CRYPT AsyncCryptDev asyncDev; @@ -271,11 +307,13 @@ int wc_ecc_check_key(ecc_key* key); WOLFSSL_API int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, word32* outlen); -#ifndef WOLFSSL_ATECC508A -WOLFSSL_API -int wc_ecc_shared_secret_ssh(ecc_key* private_key, ecc_point* point, +WOLFSSL_LOCAL +int wc_ecc_shared_secret_gen(ecc_key* private_key, ecc_point* point, byte* out, word32 *outlen); -#endif /* !WOLFSSL_ATECC508A */ +WOLFSSL_API +int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point, + byte* out, word32 *outlen); +#define wc_ecc_shared_secret_ssh wc_ecc_shared_secret_ex /* For backwards compat */ #endif /* HAVE_ECC_DHE */ #ifdef HAVE_ECC_SIGN From f990775451e23e4799e1d8c64e997c18ea6478e0 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Dec 2016 11:53:33 -0800 Subject: [PATCH 2/7] Fix issue with ECC_SHAMIR disabled due to curve->b remnant from async branch. --- wolfcrypt/src/ecc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index b0e2be0dd..b138c41a3 100755 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -3628,11 +3628,9 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* compute u1*mG + u2*mQ = mG */ if (err == MP_OKAY) - err = wc_ecc_mulmod(&u1, mG, mG, &curve->Af, &curve->Bf, - &curve->prime, 0); + err = wc_ecc_mulmod(&u1, mG, mG, &curve->Af, &curve->prime, 0); if (err == MP_OKAY) - err = wc_ecc_mulmod(&u2, mQ, mQ, &curve->Af, &curve->Bf, - &curve->prime, 0); + err = wc_ecc_mulmod(&u2, mQ, mQ, &curve->Af, &curve->prime, 0); /* find the montgomery mp */ if (err == MP_OKAY) From 57571cb45ec9732402c0fe27c323e4bf26ec89a1 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Dec 2016 14:20:00 -0800 Subject: [PATCH 3/7] Fix merge issues with ECC HAVE_COMP_KEY after rebase. --- wolfcrypt/src/ecc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index b138c41a3..199265ecb 100755 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -941,6 +941,10 @@ const ecc_set_type ecc_sets[] = { static oid_cache_t ecc_oid_cache[ECC_SET_COUNT]; #endif +#ifdef HAVE_COMP_KEY +static int wc_ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen); +#endif + #ifdef ECC_CACHE_CURVE /* cache (mp_int) of the curve parameters */ static ecc_curve_spec ecc_curve_spec_cache[ECC_SET_COUNT]; @@ -4310,6 +4314,7 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, if (err == MP_OKAY && compressed == 1) { /* build y */ DECLARE_CURVE_SPECS mp_int t1, t2; + int did_init = 0; if (mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL) != MP_OKAY) err = MEMORY_E; @@ -4356,9 +4361,10 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, if (did_init) { #ifndef USE_FAST_MATH - mp_clear(&t2); - mp_clear(&t1); + mp_clear(&t2); + mp_clear(&t1); #endif + } wc_ecc_curve_free(curve); } From 6cc1fd293e70023460fbb28bb97457e1ba488442 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 21 Dec 2016 12:31:02 -0800 Subject: [PATCH 4/7] Fixed issue with stack increase with curve cache disabled. Fixed issue with missing wc_ecc_curve_free() in wc_ecc_verify_hash_ex() causing mem leak. Changed ecc_curve_spec_cache to be allocated per curve. Added new wc_ecc_curve_cache_free() API to release all curve cache memory. Moved ecc_curve_spec struct and ecc_curve_load_mask enum to ecc.c. Add missing wc_ecc_fp_free() to wolfCrypt test. Added ecc.c comment for FP_ECC. --- wolfcrypt/benchmark/benchmark.c | 4 + wolfcrypt/src/ecc.c | 283 ++++++++++++++++++++++---------- wolfcrypt/test/test.c | 6 + wolfssl/wolfcrypt/ecc.h | 28 +--- 4 files changed, 208 insertions(+), 113 deletions(-) diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index ee186aa27..b2c1b66f7 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -447,9 +447,13 @@ int benchmark_test(void *args) #ifdef HAVE_ECC_ENCRYPT bench_eccEncrypt(); #endif + #if defined(FP_ECC) wc_ecc_fp_free(); #endif + #ifdef ECC_CACHE_CURVE + wc_ecc_curve_cache_free(); + #endif #endif #ifdef HAVE_CURVE25519 diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 199265ecb..654769d78 100755 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -45,6 +45,7 @@ Possible ECC enable options: * ECC_DUMP_OID: Enables dump of OID encoding and sum default: off * ECC_CACHE_CURVE: Enables cache of curve info to improve perofrmance default: off + * FP_ECC: ECC Fixed Point Cache default: off */ /* @@ -941,19 +942,11 @@ const ecc_set_type ecc_sets[] = { static oid_cache_t ecc_oid_cache[ECC_SET_COUNT]; #endif + #ifdef HAVE_COMP_KEY static int wc_ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen); #endif -#ifdef ECC_CACHE_CURVE - /* cache (mp_int) of the curve parameters */ - static ecc_curve_spec ecc_curve_spec_cache[ECC_SET_COUNT]; - - #define DECLARE_CURVE_SPECS ecc_curve_spec* curve = NULL; -#else - #define DECLARE_CURVE_SPECS ecc_curve_spec curve_lcl; ecc_curve_spec* curve = &curve_lcl; XMEMSET(curve, 0, sizeof(ecc_curve_spec)); -#endif /* ECC_CACHE_CURVE */ - #ifndef WOLFSSL_ATECC508A int ecc_map(ecc_point*, mp_int*, mp_digit); @@ -971,43 +964,112 @@ int mp_jacobi(mp_int* a, mp_int* n, int* c); int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret); -static void wc_ecc_curve_free(ecc_curve_spec* curve) +/* Curve Specs */ +typedef struct ecc_curve_spec { + const ecc_set_type* dp; + + mp_int* prime; + mp_int* Af; + mp_int* Bf; + mp_int* order; + mp_int* Gx; + mp_int* Gy; + +#ifdef ECC_CACHE_CURVE + mp_int prime_lcl; + mp_int Af_lcl; + mp_int Bf_lcl; + mp_int order_lcl; + mp_int Gx_lcl; + mp_int Gy_lcl; +#else + mp_int* spec_ints; + word32 spec_count; + word32 spec_use; +#endif + + byte load_mask; +} ecc_curve_spec; + +enum ecc_curve_load_mask { + ECC_CURVE_FIELD_NONE = 0x00, + ECC_CURVE_FIELD_PRIME = 0x01, + ECC_CURVE_FIELD_AF = 0x02, + ECC_CURVE_FIELD_BF = 0x04, + ECC_CURVE_FIELD_ORDER = 0x08, + ECC_CURVE_FIELD_GX = 0x10, + ECC_CURVE_FIELD_GY = 0x20, + ECC_CURVE_FIELD_ALL = 0x3F +}; + +#ifdef ECC_CACHE_CURVE + /* cache (mp_int) of the curve parameters */ + static ecc_curve_spec* ecc_curve_spec_cache[ECC_SET_COUNT]; + + #define DECLARE_CURVE_SPECS(intcount) ecc_curve_spec* curve = NULL; +#else + #define DECLARE_CURVE_SPECS(intcount) \ + mp_int spec_ints[(intcount)]; \ + ecc_curve_spec curve_lcl; \ + ecc_curve_spec* curve = &curve_lcl; \ + XMEMSET(curve, 0, sizeof(ecc_curve_spec)); \ + curve->spec_ints = spec_ints; \ + curve->spec_count = intcount; +#endif /* ECC_CACHE_CURVE */ + +static void _wc_ecc_curve_free(ecc_curve_spec* curve) { if (curve == NULL) { return; } - /* don't free cached curves */ /* don't clear fast math (only normal math uses alloc's) */ -#if !defined(ECC_CACHE_CURVE) && !defined(USE_FAST_MATH) +#if !defined(USE_FAST_MATH) if (curve->load_mask & ECC_CURVE_FIELD_PRIME) - mp_clear(&curve->prime); + mp_clear(curve->prime); if (curve->load_mask & ECC_CURVE_FIELD_AF) - mp_clear(&curve->Af); + mp_clear(curve->Af); if (curve->load_mask & ECC_CURVE_FIELD_BF) - mp_clear(&curve->Bf); + mp_clear(curve->Bf); if (curve->load_mask & ECC_CURVE_FIELD_ORDER) - mp_clear(&curve->order); + mp_clear(curve->order); if (curve->load_mask & ECC_CURVE_FIELD_GX) - mp_clear(&curve->Gx); + mp_clear(curve->Gx); if (curve->load_mask & ECC_CURVE_FIELD_GY) - mp_clear(&curve->Gy); - curve->load_mask = 0; + mp_clear(curve->Gy); #endif + curve->load_mask = 0; } -static int wc_ecc_curve_load_item(const char* src, mp_int* dst, +static void wc_ecc_curve_free(ecc_curve_spec* curve) +{ + /* don't free cached curves */ +#ifndef ECC_CACHE_CURVE + _wc_ecc_curve_free(curve); +#endif + (void)curve; +} + +static int wc_ecc_curve_load_item(const char* src, mp_int** dst, ecc_curve_spec* curve, byte mask) { - int err = mp_init(dst); - if (err == MP_OKAY) - err = mp_read_radix(dst, src, 16); -#ifdef HAVE_WOLF_BIGINT - if (err == MP_OKAY) - err = wc_mp_to_bigint(dst, &dst->raw); + int err; + +#ifndef ECC_CACHE_CURVE + /* get mp_int from temp */ + if (curve->spec_use >= curve->spec_count) { + WOLFSSL_MSG("Invalid DECLARE_CURVE_SPECS count"); + return ECC_BAD_ARG_E; + } + *dst = &curve->spec_ints[curve->spec_use++]; #endif - if (err == MP_OKAY) + + err = mp_init(*dst); + if (err == MP_OKAY) { curve->load_mask |= mask; + + err = mp_read_radix(*dst, src, 16); + } return err; } @@ -1030,8 +1092,17 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, if (ecc_sets[x].size == 0) return ECC_BAD_ARG_E; + /* make sure cache has been allocated */ + if (ecc_curve_spec_cache[x] == NULL) { + ecc_curve_spec_cache[x] = (ecc_curve_spec*)XMALLOC( + sizeof(ecc_curve_spec), NULL, DYNAMIC_TYPE_ECC); + if (ecc_curve_spec_cache[x] == NULL) + return MEMORY_E; + XMEMSET(ecc_curve_spec_cache[x], 0, sizeof(ecc_curve_spec)); + } + /* set curve pointer to cache */ - *pCurve = &ecc_curve_spec_cache[x]; + *pCurve = ecc_curve_spec_cache[x]; #endif /* ECC_CACHE_CURVE */ curve = *pCurve; @@ -1039,6 +1110,15 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, /* make sure the curve is initialized */ if (curve->dp != dp) { curve->load_mask = 0; + + #ifdef ECC_CACHE_CURVE + curve->prime = &curve->prime_lcl; + curve->Af = &curve->Af_lcl; + curve->Bf = &curve->Bf_lcl; + curve->order = &curve->order_lcl; + curve->Gx = &curve->Gx_lcl; + curve->Gy = &curve->Gy_lcl; + #endif } curve->dp = dp; /* set dp info */ @@ -1048,17 +1128,23 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, /* load items */ x = 0; if (load_items & ECC_CURVE_FIELD_PRIME) - x += wc_ecc_curve_load_item(dp->prime, &curve->prime, curve, ECC_CURVE_FIELD_PRIME); + x += wc_ecc_curve_load_item(dp->prime, &curve->prime, curve, + ECC_CURVE_FIELD_PRIME); if (load_items & ECC_CURVE_FIELD_AF) - x += wc_ecc_curve_load_item(dp->Af, &curve->Af, curve, ECC_CURVE_FIELD_AF); + x += wc_ecc_curve_load_item(dp->Af, &curve->Af, curve, + ECC_CURVE_FIELD_AF); if (load_items & ECC_CURVE_FIELD_BF) - x += wc_ecc_curve_load_item(dp->Bf, &curve->Bf, curve, ECC_CURVE_FIELD_BF); + x += wc_ecc_curve_load_item(dp->Bf, &curve->Bf, curve, + ECC_CURVE_FIELD_BF); if (load_items & ECC_CURVE_FIELD_ORDER) - x += wc_ecc_curve_load_item(dp->order, &curve->order, curve, ECC_CURVE_FIELD_ORDER); + x += wc_ecc_curve_load_item(dp->order, &curve->order, curve, + ECC_CURVE_FIELD_ORDER); if (load_items & ECC_CURVE_FIELD_GX) - x += wc_ecc_curve_load_item(dp->Gx, &curve->Gx, curve, ECC_CURVE_FIELD_GX); + x += wc_ecc_curve_load_item(dp->Gx, &curve->Gx, curve, + ECC_CURVE_FIELD_GX); if (load_items & ECC_CURVE_FIELD_GY) - x += wc_ecc_curve_load_item(dp->Gy, &curve->Gy, curve, ECC_CURVE_FIELD_GY); + x += wc_ecc_curve_load_item(dp->Gy, &curve->Gy, curve, + ECC_CURVE_FIELD_GY); /* check for error */ if (x != 0) { @@ -1069,8 +1155,25 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, return ret; } +#ifdef ECC_CACHE_CURVE +void wc_ecc_curve_cache_free(void) +{ + int x; + + /* free all ECC curve caches */ + for (x = 0; x < (int)ECC_SET_COUNT; x++) { + if (ecc_curve_spec_cache[x]) { + _wc_ecc_curve_free(ecc_curve_spec_cache[x]); + XFREE(ecc_curve_spec_cache[x], NULL, DYNAMIC_TYPE_ECC); + ecc_curve_spec_cache[x] = NULL; + } + } +} +#endif /* ECC_CACHE_CURVE */ + #endif /* WOLFSSL_ATECC508A */ + static int wc_ecc_set_curve(ecc_key* key, int keysize, int curve_id) { if (keysize <= 0 && curve_id <= 0) { @@ -2431,9 +2534,9 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, } err = wc_ecc_mulmod_ex(&private_key->k, point, result, - &curve->Af, &curve->prime, 1, private_key->heap); + curve->Af, curve->prime, 1, private_key->heap); if (err == MP_OKAY) { - x = mp_unsigned_bin_size(&curve->prime); + x = mp_unsigned_bin_size(curve->prime); if (*outlen < x) { err = BUFFER_E; } @@ -2456,7 +2559,7 @@ int wc_ecc_shared_secret_gen(ecc_key* private_key, ecc_point* point, byte* out, word32 *outlen) { int err; - DECLARE_CURVE_SPECS + DECLARE_CURVE_SPECS(2) if (private_key == NULL || point == NULL || out == NULL || outlen == NULL) { @@ -2610,7 +2713,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) int err; #ifndef WOLFSSL_ATECC508A ecc_point* base = NULL; - DECLARE_CURVE_SPECS + DECLARE_CURVE_SPECS(6) #endif if (key == NULL || rng == NULL) { @@ -2677,26 +2780,26 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) /* read in the x/y for this key */ if (err == MP_OKAY) - err = mp_copy(&curve->Gx, base->x); + err = mp_copy(curve->Gx, base->x); if (err == MP_OKAY) - err = mp_copy(&curve->Gy, base->y); + err = mp_copy(curve->Gy, base->y); if (err == MP_OKAY) mp_set(base->z, 1); /* generate k */ if (err == MP_OKAY) - err = wc_ecc_gen_k(rng, key->dp->size, &key->k, &curve->order); + err = wc_ecc_gen_k(rng, key->dp->size, &key->k, curve->order); /* make the public key */ if (err == MP_OKAY) err = wc_ecc_mulmod_ex(&key->k, base, &key->pubkey, - &curve->Af, &curve->prime, 1, key->heap); + curve->Af, curve->prime, 1, key->heap); #ifdef WOLFSSL_VALIDATE_ECC_KEYGEN /* validate the public key, order * pubkey = point at infinity */ if (err == MP_OKAY) - err = ecc_check_pubkey_order(key, &curve->Af, &curve->Bf, &curve->prime, - &curve->order); + err = ecc_check_pubkey_order(key, curve->Af, curve->Bf, curve->prime, + curve->order); #endif /* WOLFSSL_VALIDATE_KEYGEN */ if (err == MP_OKAY) @@ -3010,9 +3113,9 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, ecc_key* key, mp_int *r, mp_int *s) { - int err; - mp_int e; - DECLARE_CURVE_SPECS + int err; + mp_int e; + DECLARE_CURVE_SPECS(1) if (in == NULL || r == NULL || s == NULL || key == NULL || rng == NULL) return ECC_BAD_ARG_E; @@ -3039,7 +3142,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, /* load digest into e */ if (err == MP_OKAY) { /* we may need to truncate if hash is longer than key size */ - word32 orderBits = mp_count_bits(&curve->order); + word32 orderBits = mp_count_bits(curve->order); /* truncate down to byte size, may be all that's needed */ if ((WOLFSSL_BIT_SIZE * inlen) > orderBits) @@ -3067,7 +3170,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, if (err != MP_OKAY) break; /* find r = x1 mod n */ - err = mp_mod(pubkey.pubkey.x, &curve->order, r); + err = mp_mod(pubkey.pubkey.x, curve->order, r); if (err != MP_OKAY) break; if (mp_iszero(r) == MP_YES) { @@ -3080,11 +3183,11 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, } else { /* find s = (e + xr)/k */ - err = mp_invmod(&pubkey.k, &curve->order, &pubkey.k); + err = mp_invmod(&pubkey.k, curve->order, &pubkey.k); if (err != MP_OKAY) break; /* s = xr */ - err = mp_mulmod(&key->k, r, &curve->order, s); + err = mp_mulmod(&key->k, r, curve->order, s); if (err != MP_OKAY) break; /* s = e + xr */ @@ -3092,11 +3195,11 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, if (err != MP_OKAY) break; /* s = e + xr */ - err = mp_mod(s, &curve->order, s); + err = mp_mod(s, curve->order, s); if (err != MP_OKAY) break; /* s = (e + xr)/k */ - err = mp_mulmod(s, &pubkey.k, &curve->order, s); + err = mp_mulmod(s, &pubkey.k, curve->order, s); if (mp_iszero(s) == MP_NO) break; @@ -3512,7 +3615,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, mp_int u1; mp_int u2; mp_int e; - DECLARE_CURVE_SPECS + DECLARE_CURVE_SPECS(6) #else byte sigRS[ATECC_KEY_SIZE*2]; #endif @@ -3556,8 +3659,8 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* check for zero */ if (err == MP_OKAY) { if (mp_iszero(r) == MP_YES || mp_iszero(s) == MP_YES || - mp_cmp(r, &curve->order) != MP_LT || - mp_cmp(s, &curve->order) != MP_LT) { + mp_cmp(r, curve->order) != MP_LT || + mp_cmp(s, curve->order) != MP_LT) { err = MP_ZERO_E; } } @@ -3565,7 +3668,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* read hash */ if (err == MP_OKAY) { /* we may need to truncate if hash is longer than key size */ - unsigned int orderBits = mp_count_bits(&curve->order); + unsigned int orderBits = mp_count_bits(curve->order); /* truncate down to byte size, may be all that's needed */ if ( (WOLFSSL_BIT_SIZE * hashlen) > orderBits) @@ -3592,21 +3695,21 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* w = s^-1 mod n */ if (err == MP_OKAY) - err = mp_invmod(s, &curve->order, &w); + err = mp_invmod(s, curve->order, &w); /* u1 = ew */ if (err == MP_OKAY) - err = mp_mulmod(&e, &w, &curve->order, &u1); + err = mp_mulmod(&e, &w, curve->order, &u1); /* u2 = rw */ if (err == MP_OKAY) - err = mp_mulmod(r, &w, &curve->order, &u2); + err = mp_mulmod(r, &w, curve->order, &u2); /* find mG and mQ */ if (err == MP_OKAY) - err = mp_copy(&curve->Gx, mG->x); + err = mp_copy(curve->Gx, mG->x); if (err == MP_OKAY) - err = mp_copy(&curve->Gy, mG->y); + err = mp_copy(curve->Gy, mG->y); if (err == MP_OKAY) mp_set(mG->z, 1); @@ -3620,11 +3723,11 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #ifdef FREESCALE_LTC_ECC /* use PKHA to compute u1*mG + u2*mQ */ if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&u1, mG, mG, &curve->Af, &curve->prime, 0, key->heap); + err = wc_ecc_mulmod_ex(&u1, mG, mG, curve->Af, curve->prime, 0, key->heap); if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&u2, mQ, mQ, &curve->Af, &curve->prime, 0, key->heap); + err = wc_ecc_mulmod_ex(&u2, mQ, mQ, curve->Af, curve->prime, 0, key->heap); if (err == MP_OKAY) - err = wc_ecc_point_add(mG, mQ, mG, &curve->prime); + err = wc_ecc_point_add(mG, mQ, mG, curve->prime); #else /* FREESCALE_LTC_ECC */ #ifndef ECC_SHAMIR { @@ -3632,33 +3735,33 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* compute u1*mG + u2*mQ = mG */ if (err == MP_OKAY) - err = wc_ecc_mulmod(&u1, mG, mG, &curve->Af, &curve->prime, 0); + err = wc_ecc_mulmod(&u1, mG, mG, curve->Af, curve->prime, 0); if (err == MP_OKAY) - err = wc_ecc_mulmod(&u2, mQ, mQ, &curve->Af, &curve->prime, 0); + err = wc_ecc_mulmod(&u2, mQ, mQ, curve->Af, curve->prime, 0); /* find the montgomery mp */ if (err == MP_OKAY) - err = mp_montgomery_setup(&curve->prime, &mp); + err = mp_montgomery_setup(curve->prime, &mp); /* add them */ if (err == MP_OKAY) - err = ecc_projective_add_point(mQ, mG, mG, &curve->Af, - &curve->prime, mp); + err = ecc_projective_add_point(mQ, mG, mG, curve->Af, + curve->prime, mp); /* reduce */ if (err == MP_OKAY) - err = ecc_map(mG, &curve->prime, mp); + err = ecc_map(mG, curve->prime, mp); } #else /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */ if (err == MP_OKAY) - err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &curve->Af, &curve->prime, + err = ecc_mul2add(mG, &u1, mQ, &u2, mG, curve->Af, curve->prime, key->heap); #endif /* ECC_SHAMIR */ #endif /* FREESCALE_LTC_ECC */ /* v = X_x1 mod n */ if (err == MP_OKAY) - err = mp_mod(mG->x, &curve->order, &v); + err = mp_mod(mG->x, curve->order, &v); /* does v == r */ if (err == MP_OKAY) { @@ -3678,6 +3781,8 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, mp_clear(&u2); #endif + wc_ecc_curve_free(curve); + #endif /* WOLFSSL_ATECC508A */ return err; @@ -4088,7 +4193,7 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) int err = MP_OKAY; ecc_point* base = NULL; ecc_point* res = NULL; - DECLARE_CURVE_SPECS; + DECLARE_CURVE_SPECS(2) if (key == NULL) return BAD_FUNC_ARG; @@ -4103,9 +4208,9 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) /* set up base generator */ if (err == MP_OKAY) - err = mp_copy(&curve->Gx, base->x); + err = mp_copy(curve->Gx, base->x); if (err == MP_OKAY) - err = mp_copy(&curve->Gy, base->y); + err = mp_copy(curve->Gy, base->y); if (err == MP_OKAY) mp_set(base->z, 1); @@ -4141,7 +4246,7 @@ static int ecc_check_privkey_gen_helper(ecc_key* key) { int err; #ifndef WOLFSSL_ATECC508A - DECLARE_CURVE_SPECS + DECLARE_CURVE_SPECS(2) #endif if (key == NULL) @@ -4158,7 +4263,7 @@ static int ecc_check_privkey_gen_helper(ecc_key* key) (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF)); if (err == MP_OKAY) - err = ecc_check_privkey_gen(key, &curve->Af, &curve->prime); + err = ecc_check_privkey_gen(key, curve->Af, curve->prime); wc_ecc_curve_free(curve); @@ -4202,7 +4307,7 @@ int wc_ecc_check_key(ecc_key* key) { int err; #ifndef WOLFSSL_ATECC508A - DECLARE_CURVE_SPECS + DECLARE_CURVE_SPECS(4) #endif /* WOLFSSL_ATECC508A */ if (key == NULL) @@ -4224,15 +4329,15 @@ int wc_ecc_check_key(ecc_key* key) /* make sure point is actually on curve */ if (err == MP_OKAY) - err = ecc_is_point(key->dp, &key->pubkey, &curve->prime); + err = ecc_is_point(key->dp, &key->pubkey, curve->prime); /* pubkey * order must be at infinity */ if (err == MP_OKAY) - err = ecc_check_pubkey_order(key, &curve->Af, &curve->prime, &curve->order); + err = ecc_check_pubkey_order(key, curve->Af, curve->prime, curve->order); /* private * base generator must equal pubkey */ if (err == MP_OKAY && key->type == ECC_PRIVATEKEY) - err = ecc_check_privkey_gen(key, &curve->Af, &curve->prime); + err = ecc_check_privkey_gen(key, curve->Af, curve->prime); wc_ecc_curve_free(curve); @@ -4312,7 +4417,7 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, #ifdef HAVE_COMP_KEY if (err == MP_OKAY && compressed == 1) { /* build y */ - DECLARE_CURVE_SPECS + DECLARE_CURVE_SPECS(3) mp_int t1, t2; int did_init = 0; @@ -4331,30 +4436,30 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, if (err == MP_OKAY) err = mp_sqr(key->pubkey.x, &t1); if (err == MP_OKAY) - err = mp_mulmod(&t1, key->pubkey.x, &curve->prime, &t1); + err = mp_mulmod(&t1, key->pubkey.x, curve->prime, &t1); /* compute x^3 + a*x */ if (err == MP_OKAY) - err = mp_mulmod(&curve->Af, key->pubkey.x, &curve->prime, &t2); + err = mp_mulmod(curve->Af, key->pubkey.x, curve->prime, &t2); if (err == MP_OKAY) err = mp_add(&t1, &t2, &t1); /* compute x^3 + a*x + b */ if (err == MP_OKAY) - err = mp_add(&t1, &curve->Bf, &t1); + err = mp_add(&t1, curve->Bf, &t1); /* compute sqrt(x^3 + a*x + b) */ if (err == MP_OKAY) - err = mp_sqrtmod_prime(&t1, &curve->prime, &t2); + err = mp_sqrtmod_prime(&t1, curve->prime, &t2); /* adjust y */ if (err == MP_OKAY) { if ((mp_isodd(&t2) == MP_YES && in[0] == 0x03) || (mp_isodd(&t2) == MP_NO && in[0] == 0x02)) { - err = mp_mod(&t2, &curve->prime, &t2); + err = mp_mod(&t2, curve->prime, &t2); } else { - err = mp_submod(&curve->prime, &t2, &curve->prime, &t2); + err = mp_submod(curve->prime, &t2, curve->prime, &t2); } mp_copy(&t2, key->pubkey.y); } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index e3f26f761..ab35ab805 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -668,6 +668,12 @@ int wolfcrypt_test(void* args) else printf( "ECC buffer test passed!\n"); #endif + #if defined(FP_ECC) + wc_ecc_fp_free(); + #endif + #ifdef ECC_CACHE_CURVE + wc_ecc_curve_cache_free(); + #endif #endif #ifdef HAVE_CURVE25519 diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 96e7d9092..9e7c2cc8f 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -166,30 +166,6 @@ typedef struct ecc_set_type { int cofactor; } ecc_set_type; -typedef struct ecc_curve_spec { - const ecc_set_type* dp; - - mp_int prime; - mp_int Af; - mp_int Bf; - mp_int order; - mp_int Gx; - mp_int Gy; - - byte load_mask; -} ecc_curve_spec; - -enum ecc_curve_load_mask { - ECC_CURVE_FIELD_NONE = 0x00, - ECC_CURVE_FIELD_PRIME = 0x01, - ECC_CURVE_FIELD_AF = 0x02, - ECC_CURVE_FIELD_BF = 0x04, - ECC_CURVE_FIELD_ORDER = 0x08, - ECC_CURVE_FIELD_GX = 0x10, - ECC_CURVE_FIELD_GY = 0x20, - ECC_CURVE_FIELD_ALL = 0xFF -}; - #ifdef ALT_ECC_SIZE @@ -501,6 +477,10 @@ WOLFSSL_API int wc_X963_KDF(enum wc_HashType type, const byte* secret, byte* out, word32 outSz); #endif +#ifdef ECC_CACHE_CURVE +WOLFSSL_API void wc_ecc_curve_cache_free(void); +#endif + #ifdef WOLFSSL_ASYNC_CRYPT WOLFSSL_API int wc_ecc_async_handle(ecc_key* key, WOLF_EVENT_QUEUE* queue, WOLF_EVENT* event); From 07ce995b12fb01466b4e944def26f69a6055358b Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 30 Dec 2016 12:24:03 -0800 Subject: [PATCH 5/7] Fix issue with imported key not having a reset key->r, key->s and key->state, which was causing wc_ecc_encrypt to fail. --- wolfcrypt/src/ecc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 654769d78..55c86ddfe 100755 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4364,6 +4364,9 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, return ECC_BAD_ARG_E; } + XMEMSET(key, 0, sizeof(ecc_key)); + key->state = ECC_STATE_NONE; + #ifdef WOLFSSL_ATECC508A /* TODO: Implement equiv call to ATECC508A */ err = BAD_COND_E; From 0722f4d20fab39dad5cb43a3bcffe50f3b7c8c14 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 9 Jan 2017 11:15:13 -0800 Subject: [PATCH 6/7] Fixes to reduce stack usage with ECC_CACHE_CURVE disabled (same as previous code). Added USE_ECC_B_PARAM macro (enabled with ECC_CACHE_CURVE or HAVE_COMP_KEY). Fixed bug with WOLFSSL_VALIDATE_ECC_KEYGEN defined and args to ecc_check_pubkey_order. Fixed counts for DECLARE_CURVE_SPECS(). Fixed wc_ecc_import_point_der to use curve cache. Enhance wc_ecc_check_key to support ECC_CACHE_CURVE for b or load using read_radix. Enhance to expose wc_ecc_is_point with all required mp_int* args directly. --- wolfcrypt/src/ecc.c | 119 ++++++++++++++++++++++++++-------------- wolfssl/wolfcrypt/ecc.h | 10 ++++ 2 files changed, 87 insertions(+), 42 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 55c86ddfe..04a0251d1 100755 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -46,6 +46,8 @@ Possible ECC enable options: * ECC_CACHE_CURVE: Enables cache of curve info to improve perofrmance default: off * FP_ECC: ECC Fixed Point Cache default: off + * USE_ECC_B_PARAM: Enable ECC curve B param default: off + (on for HAVE_COMP_KEY) */ /* @@ -970,7 +972,9 @@ typedef struct ecc_curve_spec { mp_int* prime; mp_int* Af; - mp_int* Bf; + #ifdef USE_ECC_B_PARAM + mp_int* Bf; + #endif mp_int* order; mp_int* Gx; mp_int* Gy; @@ -978,7 +982,9 @@ typedef struct ecc_curve_spec { #ifdef ECC_CACHE_CURVE mp_int prime_lcl; mp_int Af_lcl; - mp_int Bf_lcl; + #ifdef USE_ECC_B_PARAM + mp_int Bf_lcl; + #endif mp_int order_lcl; mp_int Gx_lcl; mp_int Gy_lcl; @@ -995,11 +1001,19 @@ enum ecc_curve_load_mask { ECC_CURVE_FIELD_NONE = 0x00, ECC_CURVE_FIELD_PRIME = 0x01, ECC_CURVE_FIELD_AF = 0x02, +#ifdef USE_ECC_B_PARAM ECC_CURVE_FIELD_BF = 0x04, +#endif ECC_CURVE_FIELD_ORDER = 0x08, ECC_CURVE_FIELD_GX = 0x10, ECC_CURVE_FIELD_GY = 0x20, - ECC_CURVE_FIELD_ALL = 0x3F +#ifdef USE_ECC_B_PARAM + ECC_CURVE_FIELD_ALL = 0x3F, + ECC_CURVE_FIELD_COUNT = 6, +#else + ECC_CURVE_FIELD_ALL = 0x3B, + ECC_CURVE_FIELD_COUNT = 5, +#endif }; #ifdef ECC_CACHE_CURVE @@ -1029,8 +1043,10 @@ static void _wc_ecc_curve_free(ecc_curve_spec* curve) mp_clear(curve->prime); if (curve->load_mask & ECC_CURVE_FIELD_AF) mp_clear(curve->Af); +#ifdef USE_ECC_B_PARAM if (curve->load_mask & ECC_CURVE_FIELD_BF) mp_clear(curve->Bf); +#endif if (curve->load_mask & ECC_CURVE_FIELD_ORDER) mp_clear(curve->order); if (curve->load_mask & ECC_CURVE_FIELD_GX) @@ -1114,7 +1130,9 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, #ifdef ECC_CACHE_CURVE curve->prime = &curve->prime_lcl; curve->Af = &curve->Af_lcl; - curve->Bf = &curve->Bf_lcl; + #ifdef USE_ECC_B_PARAM + curve->Bf = &curve->Bf_lcl; + #endif curve->order = &curve->order_lcl; curve->Gx = &curve->Gx_lcl; curve->Gy = &curve->Gy_lcl; @@ -1133,9 +1151,11 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, if (load_items & ECC_CURVE_FIELD_AF) x += wc_ecc_curve_load_item(dp->Af, &curve->Af, curve, ECC_CURVE_FIELD_AF); +#ifdef USE_ECC_B_PARAM if (load_items & ECC_CURVE_FIELD_BF) x += wc_ecc_curve_load_item(dp->Bf, &curve->Bf, curve, ECC_CURVE_FIELD_BF); +#endif if (load_items & ECC_CURVE_FIELD_ORDER) x += wc_ecc_curve_load_item(dp->order, &curve->order, curve, ECC_CURVE_FIELD_ORDER); @@ -2713,7 +2733,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) int err; #ifndef WOLFSSL_ATECC508A ecc_point* base = NULL; - DECLARE_CURVE_SPECS(6) + DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT) #endif if (key == NULL || rng == NULL) { @@ -2798,8 +2818,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) #ifdef WOLFSSL_VALIDATE_ECC_KEYGEN /* validate the public key, order * pubkey = point at infinity */ if (err == MP_OKAY) - err = ecc_check_pubkey_order(key, curve->Af, curve->Bf, curve->prime, - curve->order); + err = ecc_check_pubkey_order(key, curve->Af, curve->prime, curve->order); #endif /* WOLFSSL_VALIDATE_KEYGEN */ if (err == MP_OKAY) @@ -3615,7 +3634,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, mp_int u1; mp_int u2; mp_int e; - DECLARE_CURVE_SPECS(6) + DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT) #else byte sigRS[ATECC_KEY_SIZE*2]; #endif @@ -3840,61 +3859,58 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx, #ifdef HAVE_COMP_KEY if (err == MP_OKAY && compressed == 1) { /* build y */ - mp_int t1, t2, prime, a, b; + mp_int t1, t2; + DECLARE_CURVE_SPECS(3) + int did_init = 0; - if (mp_init_multi(&t1, &t2, &prime, &a, &b, NULL) != MP_OKAY) + if (mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL) != MP_OKAY) err = MEMORY_E; else did_init = 1; - /* read in the specs for this curve */ - if (err == MP_OKAY) - err = mp_read_radix(&prime, ecc_sets[curve_idx].prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&a, ecc_sets[curve_idx].Af, 16); - if (err == MP_OKAY) - err = mp_read_radix(&b, ecc_sets[curve_idx].Bf, 16); + /* load curve info */ + err = wc_ecc_curve_load(&ecc_sets[curve_idx], &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_BF)); /* compute x^3 */ if (err == MP_OKAY) err = mp_sqr(point->x, &t1); if (err == MP_OKAY) - err = mp_mulmod(&t1, point->x, &prime, &t1); + err = mp_mulmod(&t1, point->x, curve->prime, &t1); /* compute x^3 + a*x */ if (err == MP_OKAY) - err = mp_mulmod(&a, point->x, &prime, &t2); + err = mp_mulmod(curve->Af, point->x, curve->prime, &t2); if (err == MP_OKAY) err = mp_add(&t1, &t2, &t1); /* compute x^3 + a*x + b */ if (err == MP_OKAY) - err = mp_add(&t1, &b, &t1); + err = mp_add(&t1, curve->Bf, &t1); /* compute sqrt(x^3 + a*x + b) */ if (err == MP_OKAY) - err = mp_sqrtmod_prime(&t1, &prime, &t2); + err = mp_sqrtmod_prime(&t1, curve->prime, &t2); /* adjust y */ if (err == MP_OKAY) { if ((mp_isodd(&t2) == MP_YES && in[0] == 0x03) || (mp_isodd(&t2) == MP_NO && in[0] == 0x02)) { - err = mp_mod(&t2, &prime, point->y); + err = mp_mod(&t2, curve->prime, point->y); } else { - err = mp_submod(&prime, &t2, &prime, point->y); + err = mp_submod(curve->prime, &t2, curve->prime, point->y); } } if (did_init) { - #ifndef USE_FAST_MATH - mp_clear(&a); - mp_clear(&b); - mp_clear(&prime); + #ifndef USE_FAST_MATH mp_clear(&t2); mp_clear(&t1); - #endif + #endif + + wc_ecc_curve_free(curve); } } #endif @@ -4098,20 +4114,15 @@ int wc_ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, #ifndef WOLFSSL_ATECC508A /* is ecc point on curve described by dp ? */ -static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime) +int wc_ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime) { - mp_int a, b, t1, t2; int err; + mp_int t1, t2; - if ((err = mp_init_multi(&a, &b, &t1, &t2, NULL, NULL)) != MP_OKAY) { + if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { return err; } - /* read in the specs for this curve */ - err = mp_read_radix(&a, dp->Af, 16); - if (err == MP_OKAY) - err = mp_read_radix(&b, dp->Bf, 16); - /* compute y^2 */ if (err == MP_OKAY) err = mp_sqr(ecp->y, &t1); @@ -4133,7 +4144,7 @@ static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime) if (err == MP_OKAY) { /* Use a and prime to determine if a == 3 */ mp_set(&t2, 0); - err = mp_submod(prime, &a, prime, &t2); + err = mp_submod(prime, a, prime, &t2); } if (err == MP_OKAY && mp_cmp_d(&t2, 3) != MP_EQ) { /* compute y^2 - x^3 + a*x */ @@ -4169,7 +4180,7 @@ static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime) /* compare to b */ if (err == MP_OKAY) { - if (mp_cmp(&t1, &b) != MP_EQ) { + if (mp_cmp(&t1, b) != MP_EQ) { err = MP_VAL; } else { err = MP_OKAY; @@ -4177,8 +4188,6 @@ static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime) } #ifndef USE_FAST_MATH - mp_clear(&a); - mp_clear(&b); mp_clear(&t1); mp_clear(&t2); #endif @@ -4307,7 +4316,15 @@ int wc_ecc_check_key(ecc_key* key) { int err; #ifndef WOLFSSL_ATECC508A + mp_int* b; +#ifdef USE_ECC_B_PARAM DECLARE_CURVE_SPECS(4) +#else + mp_int b_lcl; + DECLARE_CURVE_SPECS(3) + b = &b_lcl; + XMEMSET(b, 0, sizeof(mp_int)); +#endif #endif /* WOLFSSL_ATECC508A */ if (key == NULL) @@ -4325,11 +4342,25 @@ int wc_ecc_check_key(ecc_key* key) /* load curve info */ err = wc_ecc_curve_load(key->dp, &curve, (ECC_CURVE_FIELD_PRIME | - ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_BF | ECC_CURVE_FIELD_ORDER)); + ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_ORDER +#ifdef USE_ECC_B_PARAM + | ECC_CURVE_FIELD_BF +#endif + )); + +#ifndef USE_ECC_B_PARAM + /* load curve b parameter */ + if (err == MP_OKAY) + err = mp_init(b); + if (err == MP_OKAY) + err = mp_read_radix(b, key->dp->Bf, 16); +#else + b = curve->Bf; +#endif /* make sure point is actually on curve */ if (err == MP_OKAY) - err = ecc_is_point(key->dp, &key->pubkey, curve->prime); + err = wc_ecc_is_point(&key->pubkey, curve->Af, b, curve->prime); /* pubkey * order must be at infinity */ if (err == MP_OKAY) @@ -4341,6 +4372,10 @@ int wc_ecc_check_key(ecc_key* key) wc_ecc_curve_free(curve); +#ifndef USE_ECC_B_PARAM + mp_clear(b); +#endif + #endif /* WOLFSSL_ATECC508A */ return err; diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 9e7c2cc8f..c252941bb 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -48,6 +48,14 @@ #endif +/* Enable curve B parameter if needed */ +#if defined(HAVE_COMP_KEY) || defined(ECC_CACHE_CURVE) + #ifndef USE_ECC_B_PARAM /* Allow someone to force enable */ + #define USE_ECC_B_PARAM + #endif +#endif + + /* Use this as the key->idx if a custom ecc_set is used for key->dp */ #define ECC_CUSTOM_IDX (-1) @@ -278,6 +286,8 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id); 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); #ifdef HAVE_ECC_DHE WOLFSSL_API From 3338ea9ef7df8fb53bb31dd753913dca93ccd8fa Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 9 Jan 2017 15:01:17 -0800 Subject: [PATCH 7/7] Added ecc.c documentation for WOLFSSL_VALIDATE_ECC_IMPORT. Note: Add this define to enable checks for Jenkins (after this is merged). --- wolfcrypt/src/ecc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 04a0251d1..56f3bb20e 100755 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -40,6 +40,7 @@ Possible ECC enable options: * ECC_SHAMIR: Enables Shamir calc method default: on * HAVE_COMP_KEY: Enables compressed key default: off * WOLFSSL_VALIDATE_ECC_IMPORT: Validate ECC key on import default: off + * WOLFSSL_VALIDATE_ECC_KEYGEN: Validate ECC key gen default: off * WOLFSSL_CUSTOM_CURVES: Allow non-standard curves. default: off * Includes the curve "a" variable in calculation * ECC_DUMP_OID: Enables dump of OID encoding and sum default: off