diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 7012642b9..897d46adf 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -195,6 +195,7 @@ int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* modulus, mp_digit* mp); static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, int map); +static int ecc_check_pubkey_order(ecc_key* key, mp_int* prime, mp_int* order); #ifdef ECC_SHAMIR static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, ecc_point* C, mp_int* modulus); @@ -1519,8 +1520,6 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, } -#ifdef WOLFSSL_VALIDATE_KEYGEN - /* return 1 if point is at infinity, 0 if not, < 0 on error */ static int ecc_point_is_at_infinity(ecc_point* p) { @@ -1533,8 +1532,6 @@ static int ecc_point_is_at_infinity(ecc_point* p) return 0; } -#endif /* WOLFSSL_VALIDATE_KEYGEN */ - int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp); @@ -1652,20 +1649,10 @@ int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp) if (err == MP_OKAY) err = ecc_mulmod(&key->k, base, &key->pubkey, &prime, 1); -#ifdef WOLFSSL_VALIDATE_KEYGEN +#ifdef WOLFSSL_VALIDATE_ECC_KEYGEN /* validate the public key, order * pubkey = point at infinity */ - if (err == MP_OKAY) { - ecc_point* inf = ecc_new_point(); - if (inf == NULL) - err = MEMORY_E; - else { - err = ecc_mulmod(&order, &key->pubkey, inf, &prime, 1); - if (err == MP_OKAY && !ecc_point_is_at_infinity(inf)) - err = MP_NOT_INF_E; - - ecc_del_point(inf); - } - } + if (err == MP_OKAY) + err = ecc_check_pubkey_order(key, &prime, &order); #endif /* WOLFSSL_VALIDATE_KEYGEN */ if (err == MP_OKAY) @@ -2358,32 +2345,30 @@ int wc_ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, int compresse } -/* is pubkey point on curve ? */ -static int ecc_is_point(ecc_key* key) +/* is ec point on curve descriped by dp ? */ +static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime) { - mp_int prime, b, t1, t2; + mp_int b, t1, t2; int err; - if ((err = mp_init_multi(&prime, &b, &t1, &t2, NULL, NULL)) != MP_OKAY) { + if ((err = mp_init_multi(&b, &t1, &t2, NULL, NULL, NULL)) != MP_OKAY) { return err; } - /* load prime and b */ - err = mp_read_radix(&prime, key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&b, key->dp->Bf, 16); + /* load b */ + err = mp_read_radix(&b, dp->Bf, 16); /* compute y^2 */ if (err == MP_OKAY) - err = mp_sqr(key->pubkey.y, &t1); + err = mp_sqr(ecp->y, &t1); /* compute x^3 */ if (err == MP_OKAY) - err = mp_sqr(key->pubkey.x, &t2); + err = mp_sqr(ecp->x, &t2); if (err == MP_OKAY) - err = mp_mod(&t2, &prime, &t2); + err = mp_mod(&t2, prime, &t2); if (err == MP_OKAY) - err = mp_mul(key->pubkey.x, &t2, &t2); + err = mp_mul(ecp->x, &t2, &t2); /* compute y^2 - x^3 */ if (err == MP_OKAY) @@ -2391,19 +2376,19 @@ static int ecc_is_point(ecc_key* key) /* compute y^2 - x^3 + 3x */ if (err == MP_OKAY) - err = mp_add(&t1, key->pubkey.x, &t1); + err = mp_add(&t1, ecp->x, &t1); if (err == MP_OKAY) - err = mp_add(&t1, key->pubkey.x, &t1); + err = mp_add(&t1, ecp->x, &t1); if (err == MP_OKAY) - err = mp_add(&t1, key->pubkey.x, &t1); + err = mp_add(&t1, ecp->x, &t1); if (err == MP_OKAY) - err = mp_mod(&t1, &prime, &t1); + err = mp_mod(&t1, prime, &t1); while (err == MP_OKAY && mp_cmp_d(&t1, 0) == MP_LT) { - err = mp_add(&t1, &prime, &t1); + err = mp_add(&t1, prime, &t1); } - while (err == MP_OKAY && mp_cmp(&t1, &prime) != MP_LT) { - err = mp_sub(&t1, &prime, &t1); + while (err == MP_OKAY && mp_cmp(&t1, prime) != MP_LT) { + err = mp_sub(&t1, prime, &t1); } /* compare to b */ @@ -2415,7 +2400,6 @@ static int ecc_is_point(ecc_key* key) } } - mp_clear(&prime); mp_clear(&b); mp_clear(&t1); mp_clear(&t2); @@ -2424,6 +2408,146 @@ static int ecc_is_point(ecc_key* key) } +/* validate privkey * generator == pubkey, 0 on success */ +static int ecc_check_privkey_gen(ecc_key* key, mp_int* prime) +{ + ecc_point* base = NULL; + ecc_point* res = NULL; + int err; + + if (key == NULL) + return BAD_FUNC_ARG; + + base = ecc_new_point(); + if (base == NULL) + return MEMORY_E; + + /* set up base generator */ + err = mp_read_radix(base->x, (char*)key->dp->Gx, 16); + if (err == MP_OKAY) + err = mp_read_radix(base->y, (char*)key->dp->Gy, 16); + if (err == MP_OKAY) + mp_set(base->z, 1); + + if (err == MP_OKAY) { + res = ecc_new_point(); + if (res == NULL) + err = MEMORY_E; + else { + err = ecc_mulmod(&key->k, base, res, prime, 1); + if (err == MP_OKAY) { + /* compare result to public key */ + if (mp_cmp(res->x, key->pubkey.x) != MP_EQ || + mp_cmp(res->y, key->pubkey.y) != MP_EQ || + mp_cmp(res->z, key->pubkey.z) != MP_EQ) { + /* didn't match */ + err = ECC_PRIV_KEY_E; + } + } + } + } + + ecc_del_point(res); + ecc_del_point(base); + + return err; +} + + +#ifdef WOLFSSL_VALIDATE_ECC_IMPORT + +/* check privkey generator helper, creates prime needed */ +static int ecc_check_privkey_gen_helper(ecc_key* key) +{ + mp_int prime; + int err; + + if (key == NULL) + return BAD_FUNC_ARG; + + err = mp_init(&prime); + if (err != MP_OKAY) + return err; + + err = mp_read_radix(&prime, (char*)key->dp->prime, 16); + + if (err == MP_OKAY); + err = ecc_check_privkey_gen(key, &prime); + + mp_clear(&prime); + + return err; +} + +#endif /* WOLFSSL_VALIDATE_ECC_IMPORT */ + + +/* validate order * pubkey = point at infinity, 0 on success */ +static int ecc_check_pubkey_order(ecc_key* key, mp_int* prime, mp_int* order) +{ + ecc_point* inf = NULL; + int err; + + if (key == NULL) + return BAD_FUNC_ARG; + + inf = ecc_new_point(); + if (inf == NULL) + err = MEMORY_E; + else { + err = ecc_mulmod(order, &key->pubkey, inf, prime, 1); + if (err == MP_OKAY && !ecc_point_is_at_infinity(inf)) + err = ECC_INF_E; + } + + ecc_del_point(inf); + + return err; +} + + +/* perform sanity checks on ec key validity, 0 on success */ +int wc_ecc_check_key(ecc_key* key) +{ + mp_int prime; /* used by multiple calls so let's cache */ + mp_int order; /* other callers have, so let's gen here */ + int err; + + if (key == NULL) + return BAD_FUNC_ARG; + + /* pubkey point cannot be at inifinity */ + if (ecc_point_is_at_infinity(&key->pubkey)) + return ECC_INF_E; + + err = mp_init_multi(&prime, &order, NULL, NULL, NULL, NULL); + if (err != MP_OKAY) + return err; + + err = mp_read_radix(&prime, (char*)key->dp->prime, 16); + + /* make sure point is actually on curve */ + if (err == MP_OKAY) + err = ecc_is_point(key->dp, &key->pubkey, &prime); + + if (err == MP_OKAY) + err = mp_read_radix(&order, (char*)key->dp->order, 16); + + /* pubkey * order must be at infinity */ + if (err == MP_OKAY) + err = ecc_check_pubkey_order(key, &prime, &order); + + /* private * base generator must equal pubkey */ + if (err == MP_OKAY && key->type == ECC_PRIVATEKEY) + err = ecc_check_privkey_gen(key, &prime); + + mp_clear(&order); + mp_clear(&prime); + + return err; +} + + /* import public ECC key in ANSI X9.63 format */ int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) { @@ -2558,11 +2682,10 @@ int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) if (err == MP_OKAY) mp_set(key->pubkey.z, 1); - if (err == MP_OKAY) { - err = ecc_is_point(key); - if (err != MP_OKAY) - err = IS_POINT_E; - } +#ifdef WOLFSSL_VALIDATE_ECC_IMPORT + if (err == MP_OKAY) + err = wc_ecc_check_key(key); +#endif if (err != MP_OKAY) { mp_clear(key->pubkey.x); @@ -2610,7 +2733,14 @@ int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, key->type = ECC_PRIVATEKEY; - return mp_read_unsigned_bin(&key->k, priv, privSz); + ret = mp_read_unsigned_bin(&key->k, priv, privSz); + +#ifdef WOLFSSL_VALIDATE_ECC_IMPORT + if (ret == MP_OKAY) + ret = ecc_check_privkey_gen_helper(key); +#endif + + return ret; } /** @@ -2722,6 +2852,11 @@ int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, err = mp_read_radix(&key->k, d, 16); } +#ifdef WOLFSSL_VALIDATE_ECC_IMPORT + if (err == MP_OKAY) + err = wc_ecc_check_key(key); +#endif + if (err != MP_OKAY) { mp_clear(key->pubkey.x); mp_clear(key->pubkey.y); diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 58a5b4fa0..7d1d5ebe7 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -322,8 +322,11 @@ const char* wc_GetErrorString(int error) case IS_POINT_E: return "ECC is point on curve failed"; - case MP_NOT_INF_E: - return " ECC point expected at infinity error"; + case ECC_INF_E: + return " ECC point at infinity error"; + + case ECC_PRIV_KEY_E: + return " ECC private key is not valid error"; default: return "unknown error number"; diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index 526891772..2c1e86c31 100755 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -2638,10 +2638,9 @@ int mp_read_radix(mp_int *a, const char *str, int radix) } /* fast math conversion */ -int mp_set(fp_int *a, fp_digit b) +void mp_set(fp_int *a, fp_digit b) { fp_set(a,b); - return MP_OKAY; } /* fast math conversion */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ee1990929..cf5dbe56e 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -4888,6 +4888,10 @@ int ecc_test(void) if (ret != 0) return -1014; + ret = wc_ecc_check_key(&userA); + if (ret != 0) + return -1024; + ret = wc_ecc_make_key(&rng, 32, &userB); if (ret != 0) diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 551a6d2ac..447e8d3e2 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -135,6 +135,8 @@ extern const ecc_set_type ecc_sets[]; WOLFSSL_API int wc_ecc_make_key(RNG* rng, int keysize, ecc_key* key); WOLFSSL_API +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); WOLFSSL_API diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 616610cc6..79991fdf4 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -148,7 +148,8 @@ enum { MAC_CMP_FAILED_E = -213, /* MAC comparison failed */ IS_POINT_E = -214, /* ECC is point on curve failed */ - MP_NOT_INF_E = -215, /* ECC point expected at infinity error */ + ECC_INF_E = -215, /* ECC point infinity error */ + ECC_PRIV_KEY_E = -216, /* ECC private key not valid error */ MIN_CODE_E = -300 /* errors -101 - -299 */ }; diff --git a/wolfssl/wolfcrypt/tfm.h b/wolfssl/wolfcrypt/tfm.h index 6c8969307..1b0bbeab9 100644 --- a/wolfssl/wolfcrypt/tfm.h +++ b/wolfssl/wolfcrypt/tfm.h @@ -684,7 +684,7 @@ void mp_rshb(mp_int *a, int x); #ifdef HAVE_ECC int mp_read_radix(mp_int* a, const char* str, int radix); - int mp_set(fp_int *a, fp_digit b); + void mp_set(fp_int *a, fp_digit b); int mp_sqr(fp_int *a, fp_int *b); int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp); int mp_montgomery_setup(fp_int *a, fp_digit *rho);