diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index e346e7e15..dc42a443c 100755 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -961,9 +961,12 @@ const ecc_set_type ecc_sets[] = { static int wc_ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen); #endif -#ifndef WOLFSSL_ATECC508A +#ifdef WOLFSSL_ATECC508A + typedef void* ecc_curve_spec; +#else -static int ecc_check_pubkey_order(ecc_key* key, mp_int* a, mp_int* prime, mp_int* order); +static int ecc_check_pubkey_order(ecc_key* key, ecc_point* pubkey, mp_int* a, + 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* a, mp_int* modulus, void* heap); @@ -2986,11 +2989,142 @@ static INLINE void wc_ecc_reset(ecc_key* key) key->state = ECC_STATE_NONE; } + +/* create the public ECC key from a private key + * + * key an initialized private key to generate public part from + * curveIn [in]curve for key, can be NULL + * pubOut [out]ecc_point holding the public key, if NULL then public key part + * is cached in key instead. + * + * Note this function is local to the file because of the argument type + * ecc_curve_spec. Having this argument allows for not having to load the + * curve type multiple times when generating a key with wc_ecc_make_key(). + * + * returns MP_OKAY on success + */ +static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, + ecc_point* pubOut) +{ + int err = MP_OKAY; +#ifndef WOLFSSL_ATECC508A + ecc_point* base = NULL; + DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT) + ecc_point* pub; +#endif + + if (key == NULL) { + return BAD_FUNC_ARG; + } + +#ifndef WOLFSSL_ATECC508A + /* if ecc_point passed in then use it as output for public key point */ + if (pubOut != NULL) { + pub = pubOut; + } + else { + /* caching public key making it a ECC_PRIVATEKEY instead of + ECC_PRIVATEKEY_ONLY */ + pub = &key->pubkey; + key->type = ECC_PRIVATEKEY_ONLY; + } + + /* avoid loading the curve unless it is not passed in */ + if (curveIn != NULL) { + curve = curveIn; + } + else { + /* load curve info */ + if (err == MP_OKAY) + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); + } + + if (err == MP_OKAY) { + #ifndef ALT_ECC_SIZE + err = mp_init_multi(pub->x, pub->y, pub->z, NULL, NULL, NULL); + #else + pub->x = (mp_int*)&pub->xyz[0]; + pub->y = (mp_int*)&pub->xyz[1]; + pub->z = (mp_int*)&pub->xyz[2]; + alt_fp_init(pub->x); + alt_fp_init(pub->y); + alt_fp_init(pub->z); + #endif + } + + if (err == MP_OKAY) { + base = wc_ecc_new_point_h(key->heap); + if (base == NULL) + err = MEMORY_E; + } + + /* read in the x/y for this key */ + if (err == MP_OKAY) + err = mp_copy(curve->Gx, base->x); + if (err == MP_OKAY) + err = mp_copy(curve->Gy, base->y); + if (err == MP_OKAY) + err = mp_set(base->z, 1); + + /* make the public key */ + if (err == MP_OKAY) + err = wc_ecc_mulmod_ex(&key->k, base, pub, + curve->Af, curve->prime, 1, key->heap); + + wc_ecc_del_point_h(base, 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, pub, curve->Af, curve->prime, + curve->order); +#endif /* WOLFSSL_VALIDATE_KEYGEN */ + + if (err != MP_OKAY) { + /* clean up if failed */ + #ifndef ALT_ECC_SIZE + mp_clear(pub->x); + mp_clear(pub->y); + mp_clear(pub->z); + #endif + } + + /* free up local curve */ + if (curveIn == NULL) { + wc_ecc_curve_free(curve); + } + +#endif /* WOLFSSL_ATECC508A */ + + /* change key state if public part is cached */ + if (key->type == ECC_PRIVATEKEY_ONLY && pubOut == NULL) { + key->type = ECC_PRIVATEKEY; + } + + return err; +} + + +/* create the public ECC key from a private key + * + * key an initialized private key to generate public part from + * pubOut [out]ecc_point holding the public key, if NULL then public key part + * is cached in key instead. + * + * + * returns MP_OKAY on success + */ +int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut) +{ + WOLFSSL_ENTER("wc_ecc_make_pub"); + + return wc_ecc_make_pub_ex(key, NULL, pubOut); +} + + 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(ECC_CURVE_FIELD_COUNT) #endif @@ -3036,52 +3170,18 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) /* setup the key variables */ 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 - } - - if (err == MP_OKAY) { - base = wc_ecc_new_point_h(key->heap); - if (base == NULL) - err = MEMORY_E; - } /* load curve info */ if (err == MP_OKAY) 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_copy(curve->Gx, base->x); - if (err == MP_OKAY) - err = mp_copy(curve->Gy, base->y); - if (err == MP_OKAY) - err = mp_set(base->z, 1); - /* generate k */ if (err == MP_OKAY) err = wc_ecc_gen_k(rng, key->dp->size, &key->k, curve->order); - /* make the public key */ + /* generate public key from k */ if (err == MP_OKAY) - 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, curve->Af, curve->prime, curve->order); -#endif /* WOLFSSL_VALIDATE_KEYGEN */ + err = wc_ecc_make_pub_ex(key, curve, NULL); if (err == MP_OKAY) key->type = ECC_PRIVATEKEY; @@ -3089,16 +3189,10 @@ 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 */ - #ifndef 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); wc_ecc_curve_free(curve); #endif /* WOLFSSL_ATECC508A */ @@ -3448,7 +3542,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, return ECC_BAD_ARG_E; /* is this a private key? */ - if (key->type != ECC_PRIVATEKEY) { + if (key->type != ECC_PRIVATEKEY && key->type != ECC_PRIVATEKEY_ONLY) { return ECC_BAD_ARG_E; } @@ -4036,6 +4130,16 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #else + /* checking if private key with no public part */ + if (key->type == ECC_PRIVATEKEY_ONLY) { + WOLFSSL_MSG("Verify called with private key, generating public part"); + err = wc_ecc_make_pub_ex(key, NULL, NULL); + if (err != MP_OKAY) { + WOLFSSL_MSG("Unable to extract public key"); + return err; + } + } + err = mp_init(&e); if (err != MP_OKAY) return MEMORY_E; @@ -4430,6 +4534,9 @@ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) if (key == NULL || out == NULL || outLen == NULL) return ECC_BAD_ARG_E; + if (key->type == ECC_PRIVATEKEY_ONLY) + return ECC_PRIVATEONLY_E; + if (wc_ecc_is_valid_idx(key->idx) == 0) { return ECC_BAD_ARG_E; } @@ -4680,8 +4787,8 @@ static int ecc_check_privkey_gen_helper(ecc_key* key) /* validate order * pubkey = point at infinity, 0 on success */ -static int ecc_check_pubkey_order(ecc_key* key, mp_int* a, mp_int* prime, - mp_int* order) +static int ecc_check_pubkey_order(ecc_key* key, ecc_point* pubkey, mp_int* a, + mp_int* prime, mp_int* order) { ecc_point* inf = NULL; int err; @@ -4693,7 +4800,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, pubkey, inf, a, prime, 1, key->heap); if (err == MP_OKAY && !wc_ecc_point_is_at_infinity(inf)) err = ECC_INF_E; } @@ -4770,7 +4877,8 @@ int wc_ecc_check_key(ecc_key* key) /* 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, &key->pubkey, curve->Af, curve->prime, + curve->order); /* private * base generator must equal pubkey */ if (err == MP_OKAY && key->type == ECC_PRIVATEKEY) @@ -4998,6 +5106,10 @@ static int wc_ecc_export_raw(ecc_key* key, byte* qx, word32* qxLen, return BAD_FUNC_ARG; } + if (key->type == ECC_PRIVATEKEY_ONLY) { + return ECC_PRIVATEONLY_E; + } + if (wc_ecc_is_valid_idx(key->idx) == 0) { return ECC_BAD_ARG_E; } @@ -5053,6 +5165,7 @@ static int wc_ecc_export_raw(ecc_key* key, byte* qx, word32* qxLen, return BAD_COND_E; #else + /* public x component */ err = mp_to_unsigned_bin(key->pubkey.x, qx + (numLen - mp_unsigned_bin_size(key->pubkey.x))); @@ -5104,6 +5217,7 @@ int wc_ecc_import_private_key_ex(const byte* priv, word32 privSz, /* public optional, NULL if only importing private */ if (pub != NULL) { ret = wc_ecc_import_x963_ex(pub, pubSz, key, curve_id); + key->type = ECC_PRIVATEKEY; } else { if (key == NULL || priv == NULL) @@ -5114,12 +5228,12 @@ int wc_ecc_import_private_key_ex(const byte* priv, word32 privSz, /* set key size */ ret = wc_ecc_set_curve(key, privSz, curve_id); + key->type = ECC_PRIVATEKEY_ONLY; } if (ret != 0) return ret; - key->type = ECC_PRIVATEKEY; #ifdef WOLFSSL_ATECC508A /* TODO: Implement equiv call to ATECC508A */ diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index edd06afc6..4d8f32a99 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -428,6 +428,9 @@ const char* wc_GetErrorString(int error) case BAD_OCSP_RESPONDER: return "Invalid OCSP Responder, missing specific key usage extensions"; + case ECC_PRIVATEONLY_E: + return "Invalid use of private only ECC key"; + default: return "unknown error number"; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 3904acbc3..f9cf28c0a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -6230,8 +6230,8 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) /* cert files to be used in rsa cert gen test, check if RSA enabled */ #if defined(WOLFSSL_CERT_GEN) && !defined(NO_RSA) static const char* eccCaCertFile = CERT_ROOT "server-ecc.pem"; - static const char* eccCaKeyFile = CERT_ROOT "ecc-key.der"; #endif + static const char* eccCaKeyFile = CERT_ROOT "ecc-key.der"; #if defined(HAVE_PKCS7) && defined(HAVE_ECC) static const char* eccClientKey = CERT_ROOT "ecc-client-key.der"; static const char* eccClientCert = CERT_ROOT "client-ecc-cert.der"; @@ -10466,6 +10466,141 @@ done: #endif /* HAVE_ECC_CDH */ #endif /* HAVE_ECC_VECTOR_TEST */ +#ifdef HAVE_ECC_KEY_IMPORT +/* returns 0 on success */ +static int ecc_test_make_pub(WC_RNG* rng) +{ + ecc_key key; + unsigned char exportBuf[FOURK_BUF]; + unsigned char tmp[FOURK_BUF]; + unsigned char msg[] = "test wolfSSL ECC public gen"; + word32 x, tmpSz; + int ret = 0; + ecc_point* pubPoint = NULL; + +#ifdef USE_CERT_BUFFERS_256 + XMEMCPY(tmp, ecc_key_der_256, sizeof_ecc_key_der_256); + tmpSz = sizeof_ecc_key_der_256; +#else + FILE* file; + file = fopen(eccCaKeyFile, "rb"); + if (!file) { + ret = -6000; + goto exit_ecc_make_pub; + } + + tmpSz = (word32)fread(tmp, 1, FOURK_BUF, file); + fclose(file); +#endif /* USE_CERT_BUFFERS_256 */ + + wc_ecc_init(&key); + + /* import private only then test with */ + ret = wc_ecc_import_private_key(tmp, tmpSz, NULL, 0, NULL); + if (ret == 0) { + ret = -6001; + goto exit_ecc_make_pub; + } + + ret = wc_ecc_import_private_key(NULL, tmpSz, NULL, 0, &key); + if (ret == 0) { + ret = -6002; + goto exit_ecc_make_pub; + } + + x = 0; + ret = wc_EccPrivateKeyDecode(tmp, &x, &key, tmpSz); + if (ret != 0) + goto exit_ecc_make_pub; + +#ifdef HAVE_ECC_KEY_EXPORT + x = sizeof(exportBuf); + ret = wc_ecc_export_private_only(&key, exportBuf, &x); + if (ret != 0) + goto exit_ecc_make_pub; + + /* make private only key */ + wc_ecc_free(&key); + wc_ecc_init(&key); + ret = wc_ecc_import_private_key(exportBuf, x, NULL, 0, &key); + if (ret != 0) + goto exit_ecc_make_pub; + + x = sizeof(exportBuf); + ret = wc_ecc_export_x963_ex(&key, exportBuf, &x, 0); + if (ret == 0) { + ret = -6003; + goto exit_ecc_make_pub; + } + +#endif /* HAVE_ECC_KEY_EXPORT */ + + ret = wc_ecc_make_pub(NULL, NULL); + if (ret == 0) { + ret = -6004; + goto exit_ecc_make_pub; + } + + pubPoint = wc_ecc_new_point_h(HEAP_HINT); + if (pubPoint == NULL) { + ret = -6005; + goto exit_ecc_make_pub; + } + + ret = wc_ecc_make_pub(&key, pubPoint); + if (ret != 0) + goto exit_ecc_make_pub; + +#ifdef HAVE_ECC_KEY_EXPORT + /* export should still fail, is private only key */ + x = sizeof(exportBuf); + ret = wc_ecc_export_x963_ex(&key, exportBuf, &x, 0); + if (ret == 0) { + ret = -6006; + goto exit_ecc_make_pub; + } +#endif /* HAVE_ECC_KEY_EXPORT */ + +#ifdef HAVE_ECC_SIGN + tmpSz = sizeof(tmp); + ret = wc_ecc_sign_hash(msg, sizeof(msg), tmp, &tmpSz, rng, &key); + if (ret != 0) + goto exit_ecc_make_pub; + +#ifdef HAVE_ECC_VERIFY + { + int res = 0; + /* try verify with private only key */ + ret = wc_ecc_verify_hash(tmp, tmpSz, msg, sizeof(msg), &res, &key); + if (ret != 0) + goto exit_ecc_make_pub; + + if (res != 1) { + ret = -6007; + goto exit_ecc_make_pub; + } + #ifdef HAVE_ECC_KEY_EXPORT + /* exporting the public part should now work */ + x = sizeof(exportBuf); + ret = wc_ecc_export_x963_ex(&key, exportBuf, &x, 0); + if (ret != 0) + goto exit_ecc_make_pub; + #endif /* HAVE_ECC_KEY_EXPORT */ + } +#endif /* HAVE_ECC_VERIFY */ + +#endif /* HAVE_ECC_SIGN */ + +exit_ecc_make_pub: + + wc_ecc_del_point_h(pubPoint, HEAP_HINT); + wc_ecc_free(&key); + + return ret; +} +#endif /* HAVE_ECC_KEY_IMPORT */ + + #ifdef WOLFSSL_KEY_GEN static int ecc_test_key_gen(WC_RNG* rng, int keySize) { @@ -11624,6 +11759,12 @@ int ecc_test(void) } #endif + ret = ecc_test_make_pub(&rng); + if (ret < 0) { + printf("ecc_test_make_pub failed!: %d\n", ret); + return ret; + } + done: wc_FreeRng(&rng); diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index a146d6a53..82d2f5f5d 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -98,8 +98,9 @@ enum { - ECC_PUBLICKEY = 1, - ECC_PRIVATEKEY = 2, + ECC_PUBLICKEY = 1, + ECC_PRIVATEKEY = 2, + ECC_PRIVATEKEY_ONLY = 3, ECC_MAXNAME = 16, /* MAX CURVE NAME LENGTH */ SIG_HEADER_SZ = 6, /* ECC signature header size */ ECC_BUFSIZE = 256, /* for exported keys temp buffer */ @@ -335,6 +336,8 @@ WOLFSSL_API int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id); WOLFSSL_API +int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut); +WOLFSSL_API int wc_ecc_check_key(ecc_key* key); WOLFSSL_API int wc_ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime); diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 99c27d18e..1ff1ae935 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -189,7 +189,9 @@ enum { ASYNC_OP_E = -245, /* Async operation error */ - WC_LAST_E = -245, /* Update this to indicate last error */ + ECC_PRIVATEONLY_E = -246, /* Invalid use of private only ECC key*/ + + WC_LAST_E = -246, /* Update this to indicate last error */ MIN_CODE_E = -300 /* errors -101 - -299 */ /* add new companion error id strings for any new error codes