Cleanup ECC point import/export code. Added new API `wc_ecc_import_unsigned` to allow importing public x/y and optional private as unsigned char. Cleanup `wc_ecc_sign_hash` to move the hardware crypto code into a separate function. Added missing tests for `wc_ecc_export_public_raw`, `wc_ecc_export_private_raw` and new test for `wc_ecc_import_unsigned`.

This commit is contained in:
David Garske 2018-03-19 13:28:57 -07:00
parent cb8f8a953b
commit 59aa893260
3 changed files with 208 additions and 98 deletions

View File

@ -3531,6 +3531,68 @@ int wc_ecc_set_flags(ecc_key* key, word32 flags)
#ifdef HAVE_ECC_SIGN
#ifndef NO_ASN
#if defined(WOLFSSL_ATECC508A) || defined(PLUTON_CRYPTO_ECC)
static int wc_ecc_sign_hash_hw(const byte* in, word32 inlen,
mp_int* r, mp_int* s, byte* out, word32 *outlen, WC_RNG* rng,
ecc_key* key)
{
int err;
#ifdef PLUTON_CRYPTO_ECC
if (key->devId != INVALID_DEVID) /* use hardware */
#endif
{
int keysize = key->dp->size;
/* Check args */
if (keysize > ECC_MAX_CRYPTO_HW_SIZE || inlen != keysize ||
*outlen < keysize*2) {
return ECC_BAD_ARG_E;
}
#if defined(WOLFSSL_ATECC508A)
/* 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;
}
#elif defined(PLUTON_CRYPTO_ECC)
{
/* perform ECC sign */
word32 raw_sig_size = *outlen;
err = Crypto_EccSign(in, inlen, out, &raw_sig_size);
if (err != CRYPTO_RES_SUCCESS || raw_sig_size != keysize*2){
return BAD_COND_E;
}
}
#endif
/* Load R and S */
err = mp_read_unsigned_bin(r, &out[0], keysize);
if (err != MP_OKAY) {
return err;
}
err = mp_read_unsigned_bin(s, &out[keysize], keysize);
if (err != MP_OKAY) {
return err;
}
/* Check for zeros */
if (mp_iszero(r) || mp_iszero(s)) {
return MP_ZERO_E;
}
}
#ifdef PLUTON_CRYPTO_ECC
else {
err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s);
}
#endif
return err;
}
#endif /* WOLFSSL_ATECC508A || PLUTON_CRYPTO_ECC */
/**
Sign a message digest
in The message digest to sign
@ -3571,56 +3633,7 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
/* hardware crypto */
#if defined(WOLFSSL_ATECC508A) || defined(PLUTON_CRYPTO_ECC)
#ifdef PLUTON_CRYPTO_ECC
if (key->devId != INVALID_DEVID) /* use hardware */
#endif
{
/* Check args */
if ( inlen != ECC_MAX_CRYPTO_HW_SIZE ||
*outlen < ECC_MAX_CRYPTO_HW_SIZE*2) {
return ECC_BAD_ARG_E;
}
#if defined(WOLFSSL_ATECC508A)
/* 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;
}
#elif defined(PLUTON_CRYPTO_ECC)
{
/* perform ECC sign */
word32 raw_sig_size = *outlen;
err = Crypto_EccSign(in, inlen, out, &raw_sig_size);
if (err != CRYPTO_RES_SUCCESS ||
raw_sig_size != ECC_MAX_CRYPTO_HW_SIZE*2) {
return BAD_COND_E;
}
}
#endif
/* Load R and S */
err = mp_read_unsigned_bin(r, &out[0], ECC_MAX_CRYPTO_HW_SIZE);
if (err != MP_OKAY) {
return err;
}
err = mp_read_unsigned_bin(s, &out[ECC_MAX_CRYPTO_HW_SIZE],
ECC_MAX_CRYPTO_HW_SIZE);
if (err != MP_OKAY) {
return err;
}
/* Check for zeros */
if (mp_iszero(r) || mp_iszero(s)) {
return MP_ZERO_E;
}
}
#ifdef PLUTON_CRYPTO_ECC
else {
err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s);
}
#endif
err = wc_ecc_sign_hash_hw(in, inlen, r, s, out, outlen, rng, key);
#else
err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s);
#endif
@ -3657,6 +3670,7 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
default:
err = BAD_STATE_E;
break;
}
/* if async pending then return and skip done cleanup below */
@ -4552,6 +4566,8 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx,
{
int err = 0;
int compressed = 0;
int keysize;
byte pointType;
if (in == NULL || point == NULL || (curve_idx < 0) ||
(wc_ecc_is_valid_idx(curve_idx) == 0))
@ -4576,12 +4592,14 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx,
if (err != MP_OKAY)
return MEMORY_E;
/* check for 4, 2, or 3 */
if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) {
/* check for point type (4, 2, or 3) */
pointType = in[0];
if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN &&
pointType != ECC_POINT_COMP_ODD) {
err = ASN_PARSE_E;
}
if (in[0] == 0x02 || in[0] == 0x03) {
if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) {
#ifdef HAVE_COMP_KEY
compressed = 1;
#else
@ -4589,14 +4607,21 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx,
#endif
}
/* adjust to skip first byte */
inLen -= 1;
in += 1;
/* calculate key size based on inLen / 2 */
keysize = inLen>>1;
#ifdef WOLFSSL_ATECC508A
/* populate key->pubkey_raw */
XMEMCPY(key->pubkey_raw, (byte*)in+1, PUB_KEY_SIZE);
XMEMCPY(key->pubkey_raw, (byte*)in, PUB_KEY_SIZE);
#endif
/* read data */
if (err == MP_OKAY)
err = mp_read_unsigned_bin(point->x, (byte*)in+1, (inLen-1)>>1);
err = mp_read_unsigned_bin(point->x, (byte*)in, keysize);
#ifdef HAVE_COMP_KEY
if (err == MP_OKAY && compressed == 1) { /* build y */
@ -4638,8 +4663,8 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx,
/* adjust y */
if (err == MP_OKAY) {
if ((mp_isodd(&t2) == MP_YES && in[0] == 0x03) ||
(mp_isodd(&t2) == MP_NO && in[0] == 0x02)) {
if ((mp_isodd(&t2) == MP_YES && pointType == ECC_POINT_COMP_ODD) ||
(mp_isodd(&t2) == MP_NO && pointType == ECC_POINT_COMP_EVEN)) {
err = mp_mod(&t2, curve->prime, point->y);
}
else {
@ -4654,14 +4679,13 @@ int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx,
wc_ecc_curve_free(curve);
#else
sp_ecc_uncompress_256(point->x, in[0], point->y);
sp_ecc_uncompress_256(point->x, pointType, point->y);
#endif
}
#endif
if (err == MP_OKAY && compressed == 0)
err = mp_read_unsigned_bin(point->y,
(byte*)in+1+((inLen-1)>>1), (inLen-1)>>1);
err = mp_read_unsigned_bin(point->y, (byte*)in + keysize, keysize);
if (err == MP_OKAY)
err = mp_set(point->z, 1);
@ -4717,8 +4741,8 @@ int wc_ecc_export_point_der(const int curve_idx, ecc_point* point, byte* out,
#else
/* store byte 0x04 */
out[0] = 0x04;
/* store byte point type */
out[0] = ECC_POINT_UNCOMP;
#ifdef WOLFSSL_SMALL_STACK
buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER);
@ -4798,8 +4822,8 @@ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen)
return BUFFER_E;
}
/* store byte 0x04 */
out[0] = 0x04;
/* store byte point type */
out[0] = ECC_POINT_UNCOMP;
#ifdef WOLFSSL_SMALL_STACK
buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER);
@ -5188,6 +5212,8 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
{
int err = MP_OKAY;
int compressed = 0;
int keysize = 0;
byte pointType;
if (in == NULL || key == NULL)
return BAD_FUNC_ARG;
@ -5216,12 +5242,14 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
if (err != MP_OKAY)
return MEMORY_E;
/* check for 4, 2, or 3 */
if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) {
/* check for point type (4, 2, or 3) */
pointType = in[0];
if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN &&
pointType != ECC_POINT_COMP_ODD) {
err = ASN_PARSE_E;
}
if (in[0] == 0x02 || in[0] == 0x03) {
if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) {
#ifdef HAVE_COMP_KEY
compressed = 1;
#else
@ -5229,23 +5257,26 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
#endif
}
/* adjust to skip first byte */
inLen -= 1;
in += 1;
if (err == MP_OKAY) {
int keysize;
#ifdef HAVE_COMP_KEY
/* adjust inLen if compressed */
if (compressed)
inLen = (inLen-1)*2 + 1; /* used uncompressed len */
inLen = inLen*2 + 1; /* used uncompressed len */
#endif
/* determine key size */
keysize = ((inLen-1)>>1);
keysize = (inLen>>1);
err = wc_ecc_set_curve(key, keysize, curve_id);
key->type = ECC_PUBLICKEY;
}
/* read data */
if (err == MP_OKAY)
err = mp_read_unsigned_bin(key->pubkey.x, (byte*)in+1, (inLen-1)>>1);
err = mp_read_unsigned_bin(key->pubkey.x, (byte*)in, keysize);
#ifdef HAVE_COMP_KEY
if (err == MP_OKAY && compressed == 1) { /* build y */
@ -5288,8 +5319,8 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
/* adjust y */
if (err == MP_OKAY) {
if ((mp_isodd(&t2) == MP_YES && in[0] == 0x03) ||
(mp_isodd(&t2) == MP_NO && in[0] == 0x02)) {
if ((mp_isodd(&t2) == MP_YES && pointType == ECC_POINT_COMP_ODD) ||
(mp_isodd(&t2) == MP_NO && pointType == ECC_POINT_COMP_EVEN)) {
err = mp_mod(&t2, curve->prime, &t2);
}
else {
@ -5306,14 +5337,13 @@ int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
wc_ecc_curve_free(curve);
#else
sp_ecc_uncompress_256(key->pubkey.x, in[0], key->pubkey.y);
sp_ecc_uncompress_256(key->pubkey.x, pointType, key->pubkey.y);
#endif
}
#endif /* HAVE_COMP_KEY */
if (err == MP_OKAY && compressed == 0)
err = mp_read_unsigned_bin(key->pubkey.y, (byte*)in+1+((inLen-1)>>1),
(inLen-1)>>1);
err = mp_read_unsigned_bin(key->pubkey.y, (byte*)in + keysize, keysize);
if (err == MP_OKAY)
err = mp_set(key->pubkey.z, 1);
@ -5679,7 +5709,7 @@ int wc_ecc_sig_to_rs(const byte* sig, word32 sigLen, byte* r, word32* rLen,
#ifdef HAVE_ECC_KEY_IMPORT
static int wc_ecc_import_raw_private(ecc_key* key, const char* qx,
const char* qy, const char* d, int curve_id)
const char* qy, const char* d, int curve_id, int encType)
{
int err = MP_OKAY;
@ -5720,12 +5750,23 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx,
return MEMORY_E;
/* read Qx */
if (err == MP_OKAY)
err = mp_read_radix(key->pubkey.x, qx, MP_RADIX_HEX);
if (err == MP_OKAY) {
if (encType == ECC_TYPE_HEX_STR)
err = mp_read_radix(key->pubkey.x, qx, MP_RADIX_HEX);
else
err = mp_read_unsigned_bin(key->pubkey.x, (const byte*)qx,
key->dp->size);
}
/* read Qy */
if (err == MP_OKAY)
err = mp_read_radix(key->pubkey.y, qy, MP_RADIX_HEX);
if (err == MP_OKAY) {
if (encType == ECC_TYPE_HEX_STR)
err = mp_read_radix(key->pubkey.y, qy, MP_RADIX_HEX);
else
err = mp_read_unsigned_bin(key->pubkey.y, (const byte*)qy,
key->dp->size);
}
if (err == MP_OKAY)
err = mp_set(key->pubkey.z, 1);
@ -5734,7 +5775,13 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx,
if (err == MP_OKAY) {
if (d != NULL) {
key->type = ECC_PRIVATEKEY;
err = mp_read_radix(&key->k, d, MP_RADIX_HEX);
if (encType == ECC_TYPE_HEX_STR)
err = mp_read_radix(&key->k, d, MP_RADIX_HEX);
else
err = mp_read_unsigned_bin(&key->k, (const byte*)d,
key->dp->size);
} else {
key->type = ECC_PUBLICKEY;
}
@ -5769,10 +5816,19 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx,
int wc_ecc_import_raw_ex(ecc_key* key, const char* qx, const char* qy,
const char* d, int curve_id)
{
return wc_ecc_import_raw_private(key, qx, qy, d, curve_id);
return wc_ecc_import_raw_private(key, qx, qy, d, curve_id,
ECC_TYPE_HEX_STR);
}
/* Import x, y and optional private (d) as unsigned binary */
int wc_ecc_import_unsigned(ecc_key* key, byte* qx, byte* qy,
byte* d, int curve_id)
{
return wc_ecc_import_raw_private(key, (const char*)qx, (const char*)qy,
(const char*)d, curve_id, ECC_TYPE_UNSIGNED_BIN);
}
/**
Import raw ECC key
key The destination ecc_key structure
@ -5805,7 +5861,8 @@ int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy,
WOLFSSL_MSG("ecc_set curve name not found");
err = ASN_PARSE_E;
} else {
return wc_ecc_import_raw_private(key, qx, qy, d, ecc_sets[x].id);
return wc_ecc_import_raw_private(key, qx, qy, d, ecc_sets[x].id,
ECC_TYPE_HEX_STR);
}
return err;
@ -8221,7 +8278,7 @@ static int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen
#else
/* store first byte */
out[0] = mp_isodd(key->pubkey.y) == MP_YES ? 0x03 : 0x02;
out[0] = mp_isodd(key->pubkey.y) == MP_YES ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN;
/* pad and store x */
XMEMSET(out+1, 0, numlen);

View File

@ -14450,7 +14450,7 @@ static int ecc_exp_imp_test(ecc_key* key)
byte priv[32];
word32 privLen;
byte pub[65];
word32 pubLen;
word32 pubLen, pubLenX, pubLenY;
const char qx[] = "7a4e287890a1a47ad3457e52f2f76a83"
"ce46cbc947616d0cbaa82323818a793d";
const char qy[] = "eec4084f5b29ebf29c44cce3b3059610"
@ -14492,14 +14492,55 @@ static int ecc_exp_imp_test(ecc_key* key)
wc_ecc_init(&keyImp);
curve_id = wc_ecc_get_curve_id(key->idx);
if (curve_id < 0)
return -6635;
if (curve_id < 0) {
ret = -6635;
goto done;
}
/* test import private only */
ret = wc_ecc_import_private_key_ex(priv, privLen, NULL, 0, &keyImp,
curve_id);
if (ret != 0)
return -6636;
if (ret != 0) {
ret = -6636;
goto done;
}
wc_ecc_free(&keyImp);
wc_ecc_init(&keyImp);
/* test export public raw */
pubLenX = pubLenY = 32;
ret = wc_ecc_export_public_raw(key, pub, &pubLenX, &pub[32], &pubLenY);
if (ret != 0) {
ret = -6637;
goto done;
}
/* test import of public */
ret = wc_ecc_import_unsigned(&keyImp, pub, &pub[32], NULL, ECC_SECP256R1);
if (ret != 0) {
ret = -6638;
goto done;
}
wc_ecc_free(&keyImp);
wc_ecc_init(&keyImp);
/* test export private and public raw */
pubLenX = pubLenY = privLen = 32;
ret = wc_ecc_export_private_raw(key, pub, &pubLenX, &pub[32], &pubLenY,
priv, &privLen);
if (ret != 0) {
ret = -6639;
goto done;
}
/* test import of private and public */
ret = wc_ecc_import_unsigned(&keyImp, pub, &pub[32], priv, ECC_SECP256R1);
if (ret != 0) {
ret = -6640;
goto done;
}
done:
wc_ecc_free(&keyImp);
@ -14538,7 +14579,7 @@ static int ecc_mulmod_test(ecc_key* key1)
ret = wc_ecc_mulmod(&key1->k, &key2.pubkey, &key3.pubkey, &key2.k, &key3.k,
1);
if (ret != 0) {
ret = -6637;
ret = -6641;
goto done;
}
@ -14558,21 +14599,21 @@ static int ecc_ssh_test(ecc_key* key)
/* Parameter Validation testing. */
ret = wc_ecc_shared_secret_ssh(NULL, &key->pubkey, out, &outLen);
if (ret != BAD_FUNC_ARG)
return -6638;
return -6642;
ret = wc_ecc_shared_secret_ssh(key, NULL, out, &outLen);
if (ret != BAD_FUNC_ARG)
return -6639;
return -6643;
ret = wc_ecc_shared_secret_ssh(key, &key->pubkey, NULL, &outLen);
if (ret != BAD_FUNC_ARG)
return -6640;
return -6644;
ret = wc_ecc_shared_secret_ssh(key, &key->pubkey, out, NULL);
if (ret != BAD_FUNC_ARG)
return -6641;
return -6645;
/* Use API. */
ret = wc_ecc_shared_secret_ssh(key, &key->pubkey, out, &outLen);
if (ret != 0)
return -6642;
return -6646;
return 0;
}
#endif
@ -14589,7 +14630,7 @@ static int ecc_def_curve_test(WC_RNG *rng)
ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
#endif
if (ret != 0) {
ret = -6643;
ret = -6647;
goto done;
}
@ -17852,7 +17893,7 @@ int berder_test(void)
0x31, 0x03,
0x06, 0x01, 0x01
};
berDerTestData testData[] = {
{ good1_in, sizeof(good1_in), good1_out, sizeof(good1_out) },
{ good2_in, sizeof(good2_in), good2_out, sizeof(good2_out) },

View File

@ -125,6 +125,15 @@ enum {
#elif defined(PLUTON_CRYPTO_ECC)
ECC_MAX_CRYPTO_HW_SIZE = 32,
#endif
/* point encoding type */
ECC_TYPE_HEX_STR = 1,
ECC_TYPE_UNSIGNED_BIN = 2,
/* point compression type */
ECC_POINT_COMP_EVEN = 0x02,
ECC_POINT_COMP_ODD = 0x03,
ECC_POINT_UNCOMP = 0x04,
};
/* Curve Types */
@ -498,6 +507,9 @@ int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy,
WOLFSSL_API
int wc_ecc_import_raw_ex(ecc_key* key, const char* qx, const char* qy,
const char* d, int curve_id);
WOLFSSL_API
int wc_ecc_import_unsigned(ecc_key* key, byte* qx, byte* qy,
byte* d, int curve_id);
#endif /* HAVE_ECC_KEY_IMPORT */
#ifdef HAVE_ECC_KEY_EXPORT