#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#include <wolfssl/internal.h>
#ifndef WC_NO_RNG
#include <wolfssl/wolfcrypt/random.h>
#endif
#ifdef HAVE_ECC
#include <wolfssl/wolfcrypt/ecc.h>
#ifdef HAVE_SELFTEST
#define ECC_POINT_COMP_EVEN 0x02
#define ECC_POINT_COMP_ODD 0x03
#define ECC_POINT_UNCOMP 0x04
#endif
#endif
#ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV
#define wc_ecc_key_get_priv(key) (&((key)->k))
#define WOLFSSL_HAVE_ECC_KEY_GET_PRIV
#endif
#if !defined(WOLFSSL_PK_EC_INCLUDED)
#ifndef WOLFSSL_IGNORE_FILE_WARN
#warning pk_ec.c does not need to be compiled separately from ssl.c
#endif
#else
#ifdef HAVE_ECC
#if defined(OPENSSL_EXTRA)
const char* wolfSSL_EC_curve_nid2nist(int nid)
{
const char* name = NULL;
const WOLF_EC_NIST_NAME* nist_name;
for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) {
if (nist_name->nid == nid) {
name = nist_name->name;
break;
}
}
return name;
}
int wolfSSL_EC_curve_nist2nid(const char* name)
{
int nid = 0;
const WOLF_EC_NIST_NAME* nist_name;
for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) {
if (XSTRCMP(nist_name->name, name) == 0) {
nid = nist_name->nid;
break;
}
}
return nid;
}
#endif
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
const WOLFSSL_EC_METHOD* wolfSSL_EC_GROUP_method_of(
const WOLFSSL_EC_GROUP *group)
{
return group;
}
int wolfSSL_EC_METHOD_get_field_type(const WOLFSSL_EC_METHOD *meth)
{
int nid = 0;
if (meth != NULL) {
nid = WC_NID_X9_62_prime_field;
}
return nid;
}
#endif
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
int EccEnumToNID(int n)
{
WOLFSSL_ENTER("EccEnumToNID");
switch(n) {
case ECC_SECP192R1:
return WC_NID_X9_62_prime192v1;
case ECC_PRIME192V2:
return WC_NID_X9_62_prime192v2;
case ECC_PRIME192V3:
return WC_NID_X9_62_prime192v3;
case ECC_PRIME239V1:
return WC_NID_X9_62_prime239v1;
case ECC_PRIME239V2:
return WC_NID_X9_62_prime239v2;
case ECC_PRIME239V3:
return WC_NID_X9_62_prime239v3;
case ECC_SECP256R1:
return WC_NID_X9_62_prime256v1;
case ECC_SECP112R1:
return WC_NID_secp112r1;
case ECC_SECP112R2:
return WC_NID_secp112r2;
case ECC_SECP128R1:
return WC_NID_secp128r1;
case ECC_SECP128R2:
return WC_NID_secp128r2;
case ECC_SECP160R1:
return WC_NID_secp160r1;
case ECC_SECP160R2:
return WC_NID_secp160r2;
case ECC_SECP224R1:
return WC_NID_secp224r1;
case ECC_SECP384R1:
return WC_NID_secp384r1;
case ECC_SECP521R1:
return WC_NID_secp521r1;
case ECC_SECP160K1:
return WC_NID_secp160k1;
case ECC_SECP192K1:
return WC_NID_secp192k1;
case ECC_SECP224K1:
return WC_NID_secp224k1;
case ECC_SECP256K1:
return WC_NID_secp256k1;
case ECC_BRAINPOOLP160R1:
return WC_NID_brainpoolP160r1;
case ECC_BRAINPOOLP192R1:
return WC_NID_brainpoolP192r1;
case ECC_BRAINPOOLP224R1:
return WC_NID_brainpoolP224r1;
case ECC_BRAINPOOLP256R1:
return WC_NID_brainpoolP256r1;
case ECC_BRAINPOOLP320R1:
return WC_NID_brainpoolP320r1;
case ECC_BRAINPOOLP384R1:
return WC_NID_brainpoolP384r1;
case ECC_BRAINPOOLP512R1:
return WC_NID_brainpoolP512r1;
#ifdef WOLFSSL_SM2
case ECC_SM2P256V1:
return WC_NID_sm2;
#endif
default:
WOLFSSL_MSG("NID not found");
return WOLFSSL_FATAL_ERROR;
}
}
#endif
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
int NIDToEccEnum(int nid)
{
int id;
WOLFSSL_ENTER("NIDToEccEnum");
switch (nid) {
case WC_NID_X9_62_prime192v1:
id = ECC_SECP192R1;
break;
case WC_NID_X9_62_prime192v2:
id = ECC_PRIME192V2;
break;
case WC_NID_X9_62_prime192v3:
id = ECC_PRIME192V3;
break;
case WC_NID_X9_62_prime239v1:
id = ECC_PRIME239V1;
break;
case WC_NID_X9_62_prime239v2:
id = ECC_PRIME239V2;
break;
case WC_NID_X9_62_prime239v3:
id = ECC_PRIME239V3;
break;
case WC_NID_X9_62_prime256v1:
id = ECC_SECP256R1;
break;
case WC_NID_secp112r1:
id = ECC_SECP112R1;
break;
case WC_NID_secp112r2:
id = ECC_SECP112R2;
break;
case WC_NID_secp128r1:
id = ECC_SECP128R1;
break;
case WC_NID_secp128r2:
id = ECC_SECP128R2;
break;
case WC_NID_secp160r1:
id = ECC_SECP160R1;
break;
case WC_NID_secp160r2:
id = ECC_SECP160R2;
break;
case WC_NID_secp224r1:
id = ECC_SECP224R1;
break;
case WC_NID_secp384r1:
id = ECC_SECP384R1;
break;
case WC_NID_secp521r1:
id = ECC_SECP521R1;
break;
case WC_NID_secp160k1:
id = ECC_SECP160K1;
break;
case WC_NID_secp192k1:
id = ECC_SECP192K1;
break;
case WC_NID_secp224k1:
id = ECC_SECP224K1;
break;
case WC_NID_secp256k1:
id = ECC_SECP256K1;
break;
case WC_NID_brainpoolP160r1:
id = ECC_BRAINPOOLP160R1;
break;
case WC_NID_brainpoolP192r1:
id = ECC_BRAINPOOLP192R1;
break;
case WC_NID_brainpoolP224r1:
id = ECC_BRAINPOOLP224R1;
break;
case WC_NID_brainpoolP256r1:
id = ECC_BRAINPOOLP256R1;
break;
case WC_NID_brainpoolP320r1:
id = ECC_BRAINPOOLP320R1;
break;
case WC_NID_brainpoolP384r1:
id = ECC_BRAINPOOLP384R1;
break;
case WC_NID_brainpoolP512r1:
id = ECC_BRAINPOOLP512R1;
break;
default:
WOLFSSL_MSG("NID not found");
id = WOLFSSL_FATAL_ERROR;
}
return id;
}
static void ec_group_set_nid(WOLFSSL_EC_GROUP* group, int nid)
{
int eccEnum;
int realNid;
if ((realNid = EccEnumToNID(nid)) != -1) {
eccEnum = nid;
}
else {
realNid = nid;
eccEnum = NIDToEccEnum(nid);
}
group->curve_nid = realNid;
group->curve_idx = -1;
if (eccEnum != -1) {
int i;
for (i = 0; ecc_sets[i].size != 0; i++) {
if (ecc_sets[i].id == eccEnum) {
group->curve_idx = i;
group->curve_oid = (int)ecc_sets[i].oidSum;
break;
}
}
}
}
WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_new_by_curve_name(int nid)
{
int err = 0;
WOLFSSL_EC_GROUP* group;
WOLFSSL_ENTER("wolfSSL_EC_GROUP_new_by_curve_name");
group = (WOLFSSL_EC_GROUP*)XMALLOC(sizeof(WOLFSSL_EC_GROUP), NULL,
DYNAMIC_TYPE_ECC);
if (group == NULL) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_new_by_curve_name malloc failure");
err = 1;
}
if (!err) {
XMEMSET(group, 0, sizeof(WOLFSSL_EC_GROUP));
ec_group_set_nid(group, nid);
}
return group;
}
#endif
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group)
{
WOLFSSL_ENTER("wolfSSL_EC_GROUP_free");
XFREE(group, NULL, DYNAMIC_TYPE_ECC);
}
#endif
#ifdef OPENSSL_EXTRA
#ifndef NO_BIO
static WOLFSSL_EC_GROUP* wolfssl_ec_group_d2i(WOLFSSL_EC_GROUP** group,
const unsigned char** in_pp, long inSz)
{
int err = 0;
WOLFSSL_EC_GROUP* ret = NULL;
word32 idx = 0;
word32 oid = 0;
int id = 0;
const unsigned char* in;
if (in_pp == NULL || *in_pp == NULL)
return NULL;
in = *in_pp;
if ((group != NULL) && (*group != NULL)) {
ret = *group;
}
if (in[0] != ASN_OBJECT_ID) {
WOLFSSL_ERROR_MSG("Invalid or unsupported encoding");
err = 1;
}
if ((!err) && (GetObjectId(in, &idx, &oid, oidCurveType, (word32)inSz) !=
0)) {
err = 1;
}
if (!err) {
id = wc_ecc_get_oid(oid, NULL, NULL);
if (id < 0) {
err = 1;
}
}
if (!err) {
int nid = EccEnumToNID(id);
if (ret == NULL) {
ret = wolfSSL_EC_GROUP_new_by_curve_name(nid);
if (ret == NULL) {
err = 1;
}
}
else {
ec_group_set_nid(ret, nid);
}
}
if ((!err) && (group != NULL)) {
*group = ret;
}
if (err) {
if ((ret != NULL) && (ret != *group)) {
wolfSSL_EC_GROUP_free(ret);
}
ret = NULL;
}
else {
*in_pp += idx;
}
return ret;
}
WOLFSSL_EC_GROUP* wolfSSL_PEM_read_bio_ECPKParameters(WOLFSSL_BIO* bio,
WOLFSSL_EC_GROUP** group, wc_pem_password_cb* cb, void* pass)
{
int err = 0;
WOLFSSL_EC_GROUP* ret = NULL;
DerBuffer* der = NULL;
int keyFormat = 0;
if (bio == NULL) {
err = 1;
}
if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PARAM_TYPE,
&keyFormat, &der) < 0)) {
err = 1;
}
if (!err) {
const byte** p = (const byte**)&der->buffer;
ret = wolfssl_ec_group_d2i(group, p, der->length);
if (ret == NULL) {
WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_GROUP");
}
}
FreeDer(&der);
return ret;
}
WOLFSSL_EC_GROUP *wolfSSL_d2i_ECPKParameters(WOLFSSL_EC_GROUP **out,
const unsigned char **in, long len)
{
return wolfssl_ec_group_d2i(out, in, len);
}
int wolfSSL_i2d_ECPKParameters(const WOLFSSL_EC_GROUP* grp, unsigned char** pp)
{
unsigned char* out = NULL;
int len = 0;
int idx;
const byte* oid = NULL;
word32 oidSz = 0;
if (grp == NULL || !wc_ecc_is_valid_idx(grp->curve_idx) ||
grp->curve_idx < 0)
return WOLFSSL_FATAL_ERROR;
if (wc_ecc_get_oid((word32)grp->curve_oid, &oid, &oidSz) < 0)
return WOLFSSL_FATAL_ERROR;
len = SetObjectId((int)oidSz, NULL) + (int)oidSz;
if (pp == NULL)
return len;
if (*pp == NULL) {
out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1);
if (out == NULL)
return WOLFSSL_FATAL_ERROR;
}
else {
out = *pp;
}
idx = SetObjectId((int)oidSz, out);
XMEMCPY(out + idx, oid, oidSz);
if (*pp == NULL)
*pp = out;
else
*pp += len;
return len;
}
#endif
#if defined(OPENSSL_ALL) && !defined(NO_CERTS)
static int wolfssl_ec_group_copy(WOLFSSL_EC_GROUP* dst,
const WOLFSSL_EC_GROUP* src)
{
dst->curve_idx = src->curve_idx;
dst->curve_nid = src->curve_nid;
dst->curve_oid = src->curve_oid;
return 0;
}
#endif
WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_dup(const WOLFSSL_EC_GROUP *src)
{
WOLFSSL_EC_GROUP* newGroup = NULL;
if (src != NULL) {
newGroup = wolfSSL_EC_GROUP_new_by_curve_name(src->curve_nid);
}
return newGroup;
}
int wolfSSL_EC_GROUP_cmp(const WOLFSSL_EC_GROUP *a, const WOLFSSL_EC_GROUP *b,
WOLFSSL_BN_CTX *ctx)
{
int ret;
(void)ctx;
WOLFSSL_ENTER("wolfSSL_EC_GROUP_cmp");
if ((a == NULL) || (b == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_cmp Bad arguments");
ret = WOLFSSL_FATAL_ERROR;
}
else {
ret = ((a->curve_nid == b->curve_nid) &&
(a->curve_idx == b->curve_idx)) ? 0 : 1;
}
return ret;
}
#ifndef NO_WOLFSSL_STUB
void wolfSSL_EC_GROUP_set_asn1_flag(WOLFSSL_EC_GROUP *group, int flag)
{
(void)group;
(void)flag;
WOLFSSL_ENTER("wolfSSL_EC_GROUP_set_asn1_flag");
WOLFSSL_STUB("EC_GROUP_set_asn1_flag");
}
#endif
int wolfSSL_EC_GROUP_get_curve_name(const WOLFSSL_EC_GROUP *group)
{
int nid = 0;
WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_curve_name");
if (group == NULL) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_get_curve_name Bad arguments");
}
else {
nid = group->curve_nid;
}
return nid;
}
int wolfSSL_EC_GROUP_get_degree(const WOLFSSL_EC_GROUP *group)
{
int degree = 0;
WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_degree");
if (group == NULL) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_get_degree Bad arguments");
}
else {
switch (group->curve_nid) {
case WC_NID_secp112r1:
case WC_NID_secp112r2:
degree = 112;
break;
case WC_NID_secp128r1:
case WC_NID_secp128r2:
degree = 128;
break;
case WC_NID_secp160k1:
case WC_NID_secp160r1:
case WC_NID_secp160r2:
case WC_NID_brainpoolP160r1:
degree = 160;
break;
case WC_NID_secp192k1:
case WC_NID_brainpoolP192r1:
case WC_NID_X9_62_prime192v1:
case WC_NID_X9_62_prime192v2:
case WC_NID_X9_62_prime192v3:
degree = 192;
break;
case WC_NID_secp224k1:
case WC_NID_secp224r1:
case WC_NID_brainpoolP224r1:
degree = 224;
break;
case WC_NID_X9_62_prime239v1:
case WC_NID_X9_62_prime239v2:
case WC_NID_X9_62_prime239v3:
degree = 239;
break;
case WC_NID_secp256k1:
case WC_NID_brainpoolP256r1:
case WC_NID_X9_62_prime256v1:
degree = 256;
break;
case WC_NID_brainpoolP320r1:
degree = 320;
break;
case WC_NID_secp384r1:
case WC_NID_brainpoolP384r1:
degree = 384;
break;
case WC_NID_brainpoolP512r1:
degree = 512;
break;
case WC_NID_secp521r1:
degree = 521;
break;
}
}
return degree;
}
#endif
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
int wolfSSL_EC_GROUP_order_bits(const WOLFSSL_EC_GROUP *group)
{
int ret = 0;
WC_DECLARE_VAR(order, mp_int, 1, 0);
if ((group == NULL) || (group->curve_idx < 0)) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_order_bits NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret == 0) {
order = (mp_int *)XMALLOC(sizeof(*order), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (order == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
}
#endif
if (ret == 0) {
ret = mp_init(order);
}
if (ret == 0) {
ret = mp_read_radix(order, ecc_sets[group->curve_idx].order,
MP_RADIX_HEX);
if (ret == 0) {
ret = mp_count_bits(order);
}
mp_clear(order);
}
WC_FREE_VAR_EX(order, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (ret < 0) {
ret = 0;
}
return ret;
}
#endif
#if defined(OPENSSL_EXTRA)
int wolfSSL_EC_GROUP_get_order(const WOLFSSL_EC_GROUP *group,
WOLFSSL_BIGNUM *order, WOLFSSL_BN_CTX *ctx)
{
int ret = 1;
mp_int* mp = NULL;
(void)ctx;
if ((group == NULL) || (order == NULL) || (order->internal == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order NULL error");
ret = 0;
}
if (ret == 1 &&
(group->curve_idx < 0 || !wc_ecc_is_valid_idx(group->curve_idx))) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order Bad group idx");
ret = 0;
}
if (ret == 1) {
mp = (mp_int*)order->internal;
}
if ((ret == 1) && (mp_init(mp) != MP_OKAY)) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_init failure");
ret = 0;
}
if ((ret == 1) && (mp_read_radix(mp, ecc_sets[group->curve_idx].order,
MP_RADIX_HEX) != MP_OKAY)) {
WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_read order failure");
mp_zero(mp);
ret = 0;
}
return ret;
}
#endif
#if defined(OPENSSL_EXTRA)
static int ec_point_internal_set(WOLFSSL_EC_POINT *p)
{
int ret = 1;
WOLFSSL_ENTER("ec_point_internal_set");
if ((p == NULL) || (p->internal == NULL)) {
WOLFSSL_MSG("ECPoint NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
else {
ecc_point* point = (ecc_point*)p->internal;
if ((p->X != NULL) && (wolfssl_bn_get_value(p->X, point->x) != 1)) {
WOLFSSL_MSG("ecc point X error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (p->Y != NULL) && (wolfssl_bn_get_value(p->Y,
point->y) != 1)) {
WOLFSSL_MSG("ecc point Y error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (p->Z != NULL) && (wolfssl_bn_get_value(p->Z,
point->z) != 1)) {
WOLFSSL_MSG("ecc point Z error");
ret = WOLFSSL_FATAL_ERROR;
}
p->inSet = (ret == 1);
}
return ret;
}
static int ec_point_external_set(WOLFSSL_EC_POINT *p)
{
int ret = 1;
WOLFSSL_ENTER("ec_point_external_set");
if ((p == NULL) || (p->internal == NULL)) {
WOLFSSL_MSG("ECPoint NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
else {
ecc_point* point = (ecc_point*)p->internal;
if (wolfssl_bn_set_value(&p->X, point->x) != 1) {
WOLFSSL_MSG("ecc point X error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (wolfssl_bn_set_value(&p->Y, point->y) != 1)) {
WOLFSSL_MSG("ecc point Y error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (wolfssl_bn_set_value(&p->Z, point->z) != 1)) {
WOLFSSL_MSG("ecc point Z error");
ret = WOLFSSL_FATAL_ERROR;
}
p->exSet = (ret == 1);
}
return ret;
}
static int ec_point_setup(const WOLFSSL_EC_POINT *point) {
int ret = 1;
if (!point->inSet) {
WOLFSSL_MSG("No ECPoint internal set, do it");
if (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1) {
WOLFSSL_MSG("ec_point_internal_set failed");
ret = 0;
}
}
return ret;
}
WOLFSSL_EC_POINT* wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP* group)
{
int err = 0;
WOLFSSL_EC_POINT* point = NULL;
WOLFSSL_ENTER("wolfSSL_EC_POINT_new");
if (group == NULL) {
WOLFSSL_MSG("wolfSSL_EC_POINT_new NULL error");
err = 1;
}
if (!err) {
point = (WOLFSSL_EC_POINT*)XMALLOC(sizeof(WOLFSSL_EC_POINT), NULL,
DYNAMIC_TYPE_ECC);
if (point == NULL) {
WOLFSSL_MSG("wolfSSL_EC_POINT_new malloc ecc point failure");
err = 1;
}
}
if (!err) {
XMEMSET(point, 0, sizeof(WOLFSSL_EC_POINT));
point->internal = wc_ecc_new_point();
if (point->internal == NULL) {
WOLFSSL_MSG("ecc_new_point failure");
err = 1;
}
}
if (err) {
XFREE(point, NULL, DYNAMIC_TYPE_ECC);
point = NULL;
}
return point;
}
#endif
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
void wolfSSL_EC_POINT_free(WOLFSSL_EC_POINT *point)
{
WOLFSSL_ENTER("wolfSSL_EC_POINT_free");
if (point != NULL) {
if (point->internal != NULL) {
wc_ecc_del_point((ecc_point*)point->internal);
point->internal = NULL;
}
wolfSSL_BN_free(point->X);
wolfSSL_BN_free(point->Y);
wolfSSL_BN_free(point->Z);
point->X = NULL;
point->Y = NULL;
point->Z = NULL;
point->inSet = 0;
point->exSet = 0;
XFREE(point, NULL, DYNAMIC_TYPE_ECC);
}
}
#endif
#ifdef OPENSSL_EXTRA
void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *point)
{
WOLFSSL_ENTER("wolfSSL_EC_POINT_clear_free");
if (point != NULL) {
if (point->internal != NULL) {
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
wc_ecc_forcezero_point((ecc_point*)point->internal);
#else
ecc_point* p = (ecc_point*)point->internal;
mp_forcezero(p->x);
mp_forcezero(p->y);
mp_forcezero(p->z);
#endif
wc_ecc_del_point((ecc_point*)point->internal);
point->internal = NULL;
}
wolfSSL_BN_clear_free(point->X);
wolfSSL_BN_clear_free(point->Y);
wolfSSL_BN_clear_free(point->Z);
point->X = NULL;
point->Y = NULL;
point->Z = NULL;
point->inSet = 0;
point->exSet = 0;
XFREE(point, NULL, DYNAMIC_TYPE_ECC);
}
}
void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *point)
{
#if defined(DEBUG_WOLFSSL)
char *num;
WOLFSSL_ENTER("wolfSSL_EC_POINT_dump");
if (WOLFSSL_IS_DEBUG_ON()) {
if (point == NULL) {
WOLFSSL_MSG_EX("%s = NULL\n", msg);
}
else {
WOLFSSL_MSG_EX("%s:\n\tinSet=%d, exSet=%d\n", msg, point->inSet,
point->exSet);
num = wolfSSL_BN_bn2hex(point->X);
WOLFSSL_MSG_EX("\tX = %s\n", num);
XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL);
num = wolfSSL_BN_bn2hex(point->Y);
WOLFSSL_MSG_EX("\tY = %s\n", num);
XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL);
num = wolfSSL_BN_bn2hex(point->Z);
WOLFSSL_MSG_EX("\tZ = %s\n", num);
XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL);
}
}
#else
(void)msg;
(void)point;
#endif
}
char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group,
const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BN_CTX* ctx)
{
static const char* hexDigit = "0123456789ABCDEF";
char* hex = NULL;
int i;
int sz = 0;
int len = 0;
int err = 0;
(void)ctx;
if ((group == NULL) || (point == NULL)) {
err = 1;
}
if ((!err) && (group->curve_idx < 0)) {
err = 1;
}
if (!err) {
int id = wc_ecc_get_curve_id(group->curve_idx);
if ((sz = wc_ecc_get_curve_size_from_id(id)) < 0) {
err = 1;
}
}
if (!err) {
len = sz + 1;
if (form == WC_POINT_CONVERSION_UNCOMPRESSED) {
len += sz;
}
hex = (char*)XMALLOC((size_t)(2 * len + 1), NULL, DYNAMIC_TYPE_ECC);
if (hex == NULL) {
err = 1;
}
}
if (!err) {
XMEMSET(hex, 0, (size_t)(2 * len + 1));
i = sz - mp_unsigned_bin_size((mp_int*)point->X->internal) + 1;
if (mp_to_unsigned_bin((mp_int*)point->X->internal, (byte*)(hex + i)) <
0) {
err = 1;
}
}
if (!err) {
if (form == WC_POINT_CONVERSION_COMPRESSED) {
hex[0] = mp_isodd((mp_int*)point->Y->internal) ?
ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN;
}
else {
hex[0] = ECC_POINT_UNCOMP;
i = 1 + 2 * sz - mp_unsigned_bin_size((mp_int*)point->Y->internal);
if (mp_to_unsigned_bin((mp_int*)point->Y->internal,
(byte*)(hex + i)) < 0) {
err = 1;
}
}
}
if (!err) {
for (i = len-1; i >= 0; i--) {
byte b = (byte)hex[i];
hex[i * 2 + 1] = hexDigit[b & 0xf];
hex[i * 2 ] = hexDigit[b >> 4];
}
}
if (err && (hex != NULL)) {
XFREE(hex, NULL, DYNAMIC_TYPE_ECC);
hex = NULL;
}
return hex;
}
static size_t hex_to_bytes(const char *hex, unsigned char *output, size_t sz)
{
word32 i;
for (i = 0; i < sz; i++) {
signed char ch1, ch2;
ch1 = HexCharToByte(hex[i * 2]);
ch2 = HexCharToByte(hex[i * 2 + 1]);
if ((ch1 < 0) || (ch2 < 0)) {
WOLFSSL_MSG("hex_to_bytes: syntax error");
return 0;
}
output[i] = (unsigned char)((ch1 << 4) + ch2);
}
return sz;
}
WOLFSSL_EC_POINT* wolfSSL_EC_POINT_hex2point(const WOLFSSL_EC_GROUP *group,
const char *hex, WOLFSSL_EC_POINT*p, WOLFSSL_BN_CTX *ctx)
{
size_t str_sz;
WOLFSSL_BIGNUM *Gx = NULL;
WOLFSSL_BIGNUM *Gy = NULL;
char strGx[MAX_ECC_BYTES * 2 + 1];
int key_sz;
byte *octGx = (byte *)strGx;
int p_alloc = 0;
int ret;
WOLFSSL_ENTER("wolfSSL_EC_POINT_hex2point");
if (group == NULL || hex == NULL || ctx == NULL)
return NULL;
if (p == NULL) {
if ((p = wolfSSL_EC_POINT_new(group)) == NULL) {
WOLFSSL_MSG("wolfSSL_EC_POINT_new");
goto err;
}
p_alloc = 1;
}
key_sz = (wolfSSL_EC_GROUP_get_degree(group) + 7) / 8;
if (hex[0] == '0' && hex[1] == '4') {
str_sz = (size_t)key_sz * 2;
XMEMSET(strGx, 0x0, str_sz + 1);
XMEMCPY(strGx, hex + 2, str_sz);
if (wolfSSL_BN_hex2bn(&Gx, strGx) == 0)
goto err;
if (wolfSSL_BN_hex2bn(&Gy, hex + 2 + str_sz) == 0)
goto err;
ret = wolfSSL_EC_POINT_set_affine_coordinates_GFp
(group, p, Gx, Gy, ctx);
if (ret != WOLFSSL_SUCCESS) {
WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp");
goto err;
}
}
else if (hex[0] == '0' && (hex[1] == '2' || hex[1] == '3')) {
size_t sz = XSTRLEN(hex + 2) / 2;
octGx[0] = ECC_POINT_COMP_ODD;
if (hex_to_bytes(hex + 2, octGx + 1, sz) != sz) {
goto err;
}
if (wolfSSL_ECPoint_d2i(octGx, (word32)key_sz + 1, group, p)
!= WOLFSSL_SUCCESS) {
goto err;
}
}
else
goto err;
wolfSSL_BN_free(Gx);
wolfSSL_BN_free(Gy);
return p;
err:
wolfSSL_BN_free(Gx);
wolfSSL_BN_free(Gy);
if (p_alloc) {
wolfSSL_EC_POINT_free(p);
}
return NULL;
}
int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *group,
const WOLFSSL_EC_POINT *point, unsigned char *out, unsigned int *len)
{
int res = 1;
WOLFSSL_ENTER("wolfSSL_ECPoint_i2d");
if ((group == NULL) || (point == NULL) || (len == NULL)) {
WOLFSSL_MSG("wolfSSL_ECPoint_i2d NULL error");
res = 0;
}
if ((res == 1) && (ec_point_setup(point) != 1)) {
res = 0;
}
if ((res == 1) && (out != NULL)) {
wolfSSL_EC_POINT_dump("i2d p", point);
}
if (res == 1) {
int ret = wc_ecc_export_point_der(group->curve_idx,
(ecc_point*)point->internal, out, len);
if ((ret != MP_OKAY) && ((out != NULL) ||
(ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)))) {
WOLFSSL_MSG("wolfSSL_ECPoint_i2d wc_ecc_export_point_der failed");
res = 0;
}
}
return res;
}
int wolfSSL_ECPoint_d2i(const unsigned char *in, unsigned int len,
const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *point)
{
int ret = 1;
WOLFSSL_BIGNUM* x = NULL;
WOLFSSL_BIGNUM* y = NULL;
WOLFSSL_ENTER("wolfSSL_ECPoint_d2i");
if ((in == NULL) || (group == NULL) || (point == NULL) ||
(point->internal == NULL)) {
WOLFSSL_MSG("wolfSSL_ECPoint_d2i NULL error");
ret = 0;
}
if (ret == 1) {
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
if (wc_ecc_import_point_der_ex(in, len, group->curve_idx,
(ecc_point*)point->internal, 0) != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_import_point_der_ex failed");
ret = 0;
}
#else
if (in[0] == 0x04) {
if (wc_ecc_import_point_der((unsigned char *)in, len,
group->curve_idx, (ecc_point*)point->internal) != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_import_point_der failed");
ret = 0;
}
}
else {
WOLFSSL_MSG("Only uncompressed points supported with "
"HAVE_SELFTEST");
ret = 0;
}
#endif
}
if (ret == 1)
point->inSet = 1;
if (ret == 1 && ec_point_external_set(point) != 1) {
WOLFSSL_MSG("ec_point_external_set failed");
ret = 0;
}
if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) {
#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)
x = wolfSSL_BN_new();
y = wolfSSL_BN_new();
if (x == NULL || y == NULL)
ret = 0;
if (ret == 1 && wolfSSL_EC_POINT_get_affine_coordinates_GFp(group,
point, x, y, NULL) != 1) {
WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp failed");
ret = 0;
}
if (ret == 1 && wolfSSL_EC_POINT_set_affine_coordinates_GFp(group,
point, x, y, NULL) != 1) {
WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp failed");
ret = 0;
}
#else
WOLFSSL_MSG("Importing non-affine point. This may cause issues in math "
"operations later on.");
#endif
}
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
if (ret == 1 && wolfSSL_EC_POINT_is_on_curve(group,
(WOLFSSL_EC_POINT *)point, NULL) != 1) {
WOLFSSL_MSG("wolfSSL_ECPoint_d2i: point not on curve");
ret = 0;
}
#endif
if (ret == 1) {
wolfSSL_EC_POINT_dump("d2i p", point);
}
wolfSSL_BN_free(x);
wolfSSL_BN_free(y);
return ret;
}
size_t wolfSSL_EC_POINT_point2oct(const WOLFSSL_EC_GROUP *group,
const WOLFSSL_EC_POINT *point, int form, byte *buf, size_t len,
WOLFSSL_BN_CTX *ctx)
{
int err = 0;
word32 enc_len = (word32)len;
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
int compressed = ((form == WC_POINT_CONVERSION_COMPRESSED) ? 1 : 0);
#endif
WOLFSSL_ENTER("wolfSSL_EC_POINT_point2oct");
(void)ctx;
if ((group == NULL) || (point == NULL)) {
err = 1;
}
if ((!err) && (ec_point_setup(point) != 1)) {
err = 1;
}
if ((!err) && wolfSSL_EC_POINT_is_at_infinity(group, point)) {
enc_len = 1;
if (buf != NULL) {
if (len < 1) {
wolfSSL_ECerr(WOLFSSL_EC_F_EC_GFP_SIMPLE_POINT2OCT, BUFFER_E);
err = 1;
}
else {
buf[0] = 0x00;
}
}
}
else if (!err) {
if (form != WC_POINT_CONVERSION_UNCOMPRESSED
#ifndef HAVE_SELFTEST
&& form != WC_POINT_CONVERSION_COMPRESSED
#endif
) {
WOLFSSL_MSG("Unsupported point form");
err = 1;
}
if (!err) {
int ret;
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
ret = wc_ecc_export_point_der_ex(group->curve_idx,
(ecc_point*)point->internal, buf, &enc_len, compressed);
#else
ret = wc_ecc_export_point_der(group->curve_idx,
(ecc_point*)point->internal, buf, &enc_len);
#endif
if (ret != ((buf != NULL) ? MP_OKAY :
WC_NO_ERR_TRACE(LENGTH_ONLY_E))) {
err = 1;
}
}
}
#if defined(DEBUG_WOLFSSL)
if (!err) {
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_point2oct point", point);
WOLFSSL_MSG("\twolfSSL_EC_POINT_point2oct output:");
WOLFSSL_BUFFER(buf, enc_len);
}
#endif
if (err) {
enc_len = 0;
}
return (size_t)enc_len;
}
int wolfSSL_EC_POINT_oct2point(const WOLFSSL_EC_GROUP *group,
WOLFSSL_EC_POINT *point, const unsigned char *buf, size_t len,
WOLFSSL_BN_CTX *ctx)
{
int ret;
WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point");
(void)ctx;
if ((group == NULL) || (point == NULL)) {
ret = 0;
}
else {
ret = wolfSSL_ECPoint_d2i((unsigned char*)buf, (unsigned int)len, group,
point);
}
return ret;
}
WOLFSSL_BIGNUM *wolfSSL_EC_POINT_point2bn(const WOLFSSL_EC_GROUP* group,
const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BIGNUM* bn,
WOLFSSL_BN_CTX* ctx)
{
int err = 0;
size_t len = 0;
byte *buf = NULL;
WOLFSSL_BIGNUM *ret = NULL;
WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point");
if ((group == NULL) || (point == NULL)) {
err = 1;
}
if ((!err) && ((len = wolfSSL_EC_POINT_point2oct(group, point, form, NULL,
0, ctx)) == 0)) {
err = 1;
}
if ((!err) && ((buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER)) ==
NULL)) {
WOLFSSL_MSG("malloc failed");
err = 1;
}
if ((!err) && (wolfSSL_EC_POINT_point2oct(group, point, form, buf, len,
ctx) != len)) {
err = 1;
}
if (!err) {
ret = wolfSSL_BN_bin2bn(buf, (int)len, bn);
}
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
int wolfSSL_EC_POINT_is_on_curve(const WOLFSSL_EC_GROUP *group,
const WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx)
{
int err = 0;
WOLFSSL_ENTER("wolfSSL_EC_POINT_is_on_curve");
(void)ctx;
if ((group == NULL) || (point == NULL)) {
WOLFSSL_MSG("Invalid arguments");
err = 1;
}
if ((!err) && (!point->inSet) && ec_point_internal_set(
(WOLFSSL_EC_POINT*)point) != 1) {
WOLFSSL_MSG("ec_point_internal_set error");
err = 1;
}
if ((!err) && (wc_ecc_point_is_on_curve((ecc_point*)point->internal,
group->curve_idx) != MP_OKAY)) {
err = 1;
}
return !err;
}
#endif
#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)
int ec_point_convert_to_affine(const WOLFSSL_EC_GROUP *group,
WOLFSSL_EC_POINT *point)
{
int err = 0;
mp_digit mp = 0;
WC_DECLARE_VAR(modulus, mp_int, 1, 0);
WC_ALLOC_VAR_EX(modulus, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, err=1);
if ((!err) && (mp_init(modulus) != MP_OKAY)) {
WOLFSSL_MSG("mp_init failed");
err = 1;
}
if (!err) {
if (mp_read_radix(modulus, ecc_sets[group->curve_idx].prime,
MP_RADIX_HEX) != MP_OKAY) {
WOLFSSL_MSG("mp_read_radix failed");
err = 1;
}
if ((!err) && (mp_montgomery_setup(modulus, &mp) != MP_OKAY)) {
WOLFSSL_MSG("mp_montgomery_setup failed");
err = 1;
}
if ((!err) && (ecc_map((ecc_point*)point->internal, modulus, mp) !=
MP_OKAY)) {
WOLFSSL_MSG("ecc_map failed");
err = 1;
}
if ((!err) && (ec_point_external_set((WOLFSSL_EC_POINT *)point) != 1)) {
WOLFSSL_MSG("ec_point_external_set failed");
err = 1;
}
point->exSet = !err;
mp_clear(modulus);
}
WC_FREE_VAR_EX(modulus, NULL, DYNAMIC_TYPE_BIGINT);
return err;
}
int wolfSSL_EC_POINT_get_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group,
const WOLFSSL_EC_POINT* point, WOLFSSL_BIGNUM* x, WOLFSSL_BIGNUM* y,
WOLFSSL_BN_CTX* ctx)
{
int ret = 1;
(void)ctx;
WOLFSSL_ENTER("wolfSSL_EC_POINT_get_affine_coordinates_GFp");
if ((group == NULL) || (point == NULL) || (point->internal == NULL) ||
(x == NULL) || (y == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp NULL error");
ret = 0;
}
if ((ret == 1) && wolfSSL_EC_POINT_is_at_infinity(group, point)) {
ret = 0;
}
if ((ret == 1) && (ec_point_setup(point) != 1)) {
ret = 0;
}
if ((ret == 1) && (!wolfSSL_BN_is_one(point->Z))) {
if (ec_point_convert_to_affine(group, (WOLFSSL_EC_POINT*)point) == 1) {
ret = 0;
}
}
if ((ret == 1) && (wolfSSL_BN_copy(x, point->X) == NULL)) {
ret = 0;
}
if ((ret == 1) && (wolfSSL_BN_copy(y, point->Y) == NULL)) {
ret = 0;
}
return ret;
}
#endif
int wolfSSL_EC_POINT_set_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group,
WOLFSSL_EC_POINT* point, const WOLFSSL_BIGNUM* x, const WOLFSSL_BIGNUM* y,
WOLFSSL_BN_CTX* ctx)
{
int ret = 1;
(void)ctx;
WOLFSSL_ENTER("wolfSSL_EC_POINT_set_affine_coordinates_GFp");
if ((group == NULL) || (point == NULL) || (point->internal == NULL) ||
(x == NULL) || (y == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp NULL error");
ret = 0;
}
if ((ret == 1) && (point->X == NULL) &&
((point->X = wolfSSL_BN_new()) == NULL)) {
WOLFSSL_MSG("wolfSSL_BN_new failed");
ret = 0;
}
if ((ret == 1) && (point->Y == NULL) &&
((point->Y = wolfSSL_BN_new()) == NULL)) {
WOLFSSL_MSG("wolfSSL_BN_new failed");
ret = 0;
}
if ((ret == 1) && (point->Z == NULL) &&
((point->Z = wolfSSL_BN_new()) == NULL)) {
WOLFSSL_MSG("wolfSSL_BN_new failed");
ret = 0;
}
if ((ret == 1) && ((wolfSSL_BN_copy(point->X, x)) == NULL)) {
WOLFSSL_MSG("wolfSSL_BN_copy failed");
ret = 0;
}
if ((ret == 1) && ((wolfSSL_BN_copy(point->Y, y)) == NULL)) {
WOLFSSL_MSG("wolfSSL_BN_copy failed");
ret = 0;
}
if ((ret == 1) && ((wolfSSL_BN_one(point->Z)) == 0)) {
WOLFSSL_MSG("wolfSSL_BN_one failed");
ret = 0;
}
if ((ret == 1) && (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1)) {
WOLFSSL_MSG("ec_point_internal_set failed");
ret = 0;
}
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
if ((ret == 1) && (wolfSSL_EC_POINT_is_on_curve(group,
(WOLFSSL_EC_POINT *)point, ctx) != 1)) {
WOLFSSL_MSG("EC_POINT_is_on_curve failed");
ret = 0;
}
#endif
return ret;
}
#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
!defined(HAVE_SELFTEST) && !defined(WOLFSSL_SP_MATH) && \
!defined(WOLF_CRYPTO_CB_ONLY_ECC)
static int wolfssl_ec_point_add(int curveIdx, ecc_point* r, ecc_point* p1,
ecc_point* p2)
{
int ret = 1;
#ifdef WOLFSSL_SMALL_STACK
mp_int* a = NULL;
mp_int* prime = NULL;
mp_int* mu = NULL;
#else
mp_int a[1];
mp_int prime[1];
mp_int mu[1];
#endif
mp_digit mp = 0;
ecc_point* montP1 = NULL;
ecc_point* montP2 = NULL;
#ifdef WOLFSSL_SMALL_STACK
if (ret == 1) {
a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT);
if (a == NULL) {
WOLFSSL_MSG("Failed to allocate memory for mp_int a");
ret = 0;
}
}
if (ret == 1) {
prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT);
if (prime == NULL) {
WOLFSSL_MSG("Failed to allocate memory for mp_int prime");
ret = 0;
}
}
if (ret == 1) {
mu = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT);
if (mu == NULL) {
WOLFSSL_MSG("Failed to allocate memory for mp_int mu");
ret = 0;
}
}
if (ret == 1) {
XMEMSET(a, 0, sizeof(mp_int));
XMEMSET(prime, 0, sizeof(mp_int));
XMEMSET(mu, 0, sizeof(mp_int));
}
#endif
if ((ret == 1) && (mp_init_multi(prime, a, mu, NULL, NULL, NULL) !=
MP_OKAY)) {
WOLFSSL_MSG("mp_init_multi error");
ret = 0;
}
if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, MP_RADIX_HEX) !=
MP_OKAY)) {
WOLFSSL_MSG("mp_read_radix a error");
ret = 0;
}
if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime,
MP_RADIX_HEX) != MP_OKAY)) {
WOLFSSL_MSG("mp_read_radix prime error");
ret = 0;
}
if ((ret == 1) && (mp_montgomery_setup(prime, &mp) != MP_OKAY)) {
WOLFSSL_MSG("mp_montgomery_setup nqm error");
ret = 0;
}
if ((ret == 1) && (((montP1 = wc_ecc_new_point_h(NULL)) == NULL) ||
((montP2 = wc_ecc_new_point_h(NULL)) == NULL))) {
WOLFSSL_MSG("wc_ecc_new_point_h nqm error");
ret = 0;
}
if ((ret == 1) && (mp_montgomery_calc_normalization(mu, prime) !=
MP_OKAY)) {
WOLFSSL_MSG("mp_montgomery_calc_normalization error");
ret = 0;
}
if ((ret == 1) && (mp_cmp_d(mu, 1) == MP_EQ)) {
if ((wc_ecc_copy_point(p1, montP1) != MP_OKAY) ||
(wc_ecc_copy_point(p2, montP2) != MP_OKAY)) {
WOLFSSL_MSG("wc_ecc_copy_point error");
ret = 0;
}
}
else if (ret == 1) {
if ((mp_mulmod(p1->x, mu, prime, montP1->x) != MP_OKAY) ||
(mp_mulmod(p1->y, mu, prime, montP1->y) != MP_OKAY) ||
(mp_mulmod(p1->z, mu, prime, montP1->z) != MP_OKAY)) {
WOLFSSL_MSG("mp_mulmod error");
ret = 0;
}
if ((mp_mulmod(p2->x, mu, prime, montP2->x) != MP_OKAY) ||
(mp_mulmod(p2->y, mu, prime, montP2->y) != MP_OKAY) ||
(mp_mulmod(p2->z, mu, prime, montP2->z) != MP_OKAY)) {
WOLFSSL_MSG("mp_mulmod error");
ret = 0;
}
}
if ((ret == 1) && (ecc_projective_add_point(montP1, montP2, r, a, prime,
mp) != MP_OKAY)) {
WOLFSSL_MSG("ecc_projective_add_point error");
ret = 0;
}
if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) {
WOLFSSL_MSG("ecc_map error");
ret = 0;
}
mp_clear(a);
mp_clear(prime);
mp_clear(mu);
wc_ecc_del_point_h(montP1, NULL);
wc_ecc_del_point_h(montP2, NULL);
WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(mu, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
int wolfSSL_EC_POINT_add(const WOLFSSL_EC_GROUP* group, WOLFSSL_EC_POINT* r,
const WOLFSSL_EC_POINT* p1, const WOLFSSL_EC_POINT* p2, WOLFSSL_BN_CTX* ctx)
{
int ret = 1;
(void)ctx;
if ((group == NULL) || (r == NULL) || (p1 == NULL) || (p2 == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_POINT_add error");
ret = 0;
}
if ((ret == 1) && ((ec_point_setup(r) != 1) || (ec_point_setup(p1) != 1) ||
(ec_point_setup(p2) != 1))) {
WOLFSSL_MSG("ec_point_setup error");
ret = 0;
}
#ifdef DEBUG_WOLFSSL
if (ret == 1) {
int nid = wolfSSL_EC_GROUP_get_curve_name(group);
const char* curve = wolfSSL_OBJ_nid2ln(nid);
const char* nistName = wolfSSL_EC_curve_nid2nist(nid);
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p1", p1);
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p2", p2);
if (curve != NULL)
WOLFSSL_MSG_EX("curve name: %s", curve);
if (nistName != NULL)
WOLFSSL_MSG_EX("nist curve name: %s", nistName);
}
#endif
if (ret == 1) {
ret = wolfssl_ec_point_add(group->curve_idx, (ecc_point*)r->internal,
(ecc_point*)p1->internal, (ecc_point*)p2->internal);
}
if ((ret == 1) && (ec_point_external_set(r) != 1)) {
WOLFSSL_MSG("ec_point_external_set error");
ret = 0;
}
#ifdef DEBUG_WOLFSSL
if (ret == 1) {
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add result", r);
}
#endif
return ret;
}
static int ec_mul2add(ecc_point* r, ecc_point* b, mp_int* n, ecc_point* q,
mp_int* m, mp_int* a, mp_int* prime)
{
int ret = 1;
#if defined(ECC_SHAMIR) && !defined(WOLFSSL_KCAPI_ECC)
if (ecc_mul2add(b, n, q, m, r, a, prime, NULL) != MP_OKAY) {
WOLFSSL_MSG("ecc_mul2add error");
ret = 0;
}
#else
ecc_point* tmp = NULL;
mp_digit mp = 0;
if (mp_montgomery_setup(prime, &mp) != MP_OKAY) {
WOLFSSL_MSG("mp_montgomery_setup nqm error");
ret = 0;
}
if ((ret == 1) && ((tmp = wc_ecc_new_point()) == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_POINT_new nqm error");
ret = 0;
}
if ((ret == 1) && (wc_ecc_mulmod(n, b, r, a, prime, 0) !=
MP_OKAY)) {
WOLFSSL_MSG("wc_ecc_mulmod nqm error");
ret = 0;
}
if ((ret == 1) && (wc_ecc_mulmod(m, q, tmp, a, prime, 0) != MP_OKAY)) {
WOLFSSL_MSG("wc_ecc_mulmod nqm error");
ret = 0;
}
if ((ret == 1) && (ecc_projective_add_point(tmp, r, r, a, prime, mp) !=
MP_OKAY)) {
WOLFSSL_MSG("wc_ecc_mulmod nqm error");
ret = 0;
}
if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) {
WOLFSSL_MSG("ecc_map nqm error");
ret = 0;
}
wc_ecc_del_point(tmp);
#endif
return ret;
}
static int wolfssl_ec_point_mul(int curveIdx, ecc_point* r, mp_int* n,
ecc_point* q, mp_int* m)
{
int ret = 1;
#ifdef WOLFSSL_SMALL_STACK
mp_int* a = NULL;
mp_int* prime = NULL;
#else
mp_int a[1], prime[1];
#endif
#ifdef WOLFSSL_SMALL_STACK
a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT);
if (a == NULL) {
ret = 0;
}
if (ret == 1) {
prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT);
if (prime == NULL) {
ret = 0;
}
}
#endif
if ((ret == 1) && (mp_init_multi(prime, a, NULL, NULL, NULL, NULL) !=
MP_OKAY)) {
WOLFSSL_MSG("mp_init_multi error");
ret = 0;
}
if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime,
MP_RADIX_HEX) != MP_OKAY)) {
WOLFSSL_MSG("mp_read_radix prime error");
ret = 0;
}
if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af,
MP_RADIX_HEX) != MP_OKAY)) {
WOLFSSL_MSG("mp_read_radix a error");
ret = 0;
}
if ((ret == 1) && (n != NULL)) {
#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)
if ((ret == 1) && (wc_ecc_get_generator(r, curveIdx) != MP_OKAY)) {
WOLFSSL_MSG("wc_ecc_get_generator error");
ret = 0;
}
#else
if ((ret == 1) && (mp_read_radix(r->x, ecc_sets[curveIdx].Gx,
MP_RADIX_HEX) != MP_OKAY)) {
WOLFSSL_MSG("mp_read_radix Gx error");
ret = 0;
}
if ((ret == 1) && (mp_read_radix(r->y, ecc_sets[curveIdx].Gy,
MP_RADIX_HEX) != MP_OKAY)) {
WOLFSSL_MSG("mp_read_radix Gy error");
ret = 0;
}
if ((ret == 1) && (mp_set(r->z, 1) != MP_OKAY)) {
WOLFSSL_MSG("mp_set Gz error");
ret = 0;
}
#endif
}
if ((ret == 1) && (n != NULL) && (q != NULL) && (m != NULL)) {
ret = ec_mul2add(r, r, n, q, m, a, prime);
}
else if ((ret == 1) && (n != NULL)) {
if (wc_ecc_mulmod(n, r, r, a, prime, 1) != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_mulmod gn error");
ret = 0;
}
}
else if ((ret == 1) && (q != NULL) && (m != NULL)) {
if (wc_ecc_mulmod(m, q, r, a, prime, 1) != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_mulmod qm error");
ret = 0;
}
}
else if (ret == 1) {
mp_zero(r->x);
mp_zero(r->y);
mp_zero(r->z);
}
mp_clear(a);
mp_clear(prime);
WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT);
WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
int wolfSSL_EC_POINT_mul(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *r,
const WOLFSSL_BIGNUM *n, const WOLFSSL_EC_POINT *q, const WOLFSSL_BIGNUM *m,
WOLFSSL_BN_CTX *ctx)
{
int ret = 1;
(void)ctx;
WOLFSSL_ENTER("wolfSSL_EC_POINT_mul");
if ((group == NULL) || (r == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_POINT_mul NULL error");
ret = 0;
}
if ((ret == 1) && (q != NULL) && (ec_point_setup(q) != 1)) {
WOLFSSL_MSG("ec_point_setup error");
ret = 0;
}
#ifdef DEBUG_WOLFSSL
if (ret == 1) {
int nid = wolfSSL_EC_GROUP_get_curve_name(group);
const char* curve = wolfSSL_OBJ_nid2ln(nid);
const char* nistName = wolfSSL_EC_curve_nid2nist(nid);
char* num;
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul input q", q);
num = wolfSSL_BN_bn2hex(n);
WOLFSSL_MSG_EX("\tn = %s", num);
XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL);
num = wolfSSL_BN_bn2hex(m);
WOLFSSL_MSG_EX("\tm = %s", num);
XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL);
if (curve != NULL)
WOLFSSL_MSG_EX("curve name: %s", curve);
if (nistName != NULL)
WOLFSSL_MSG_EX("nist curve name: %s", nistName);
}
#endif
if (ret == 1) {
mp_int* ni = (n != NULL) ? (mp_int*)n->internal : NULL;
ecc_point* qi = (q != NULL) ? (ecc_point*)q->internal : NULL;
mp_int* mi = (m != NULL) ? (mp_int*)m->internal : NULL;
ret = wolfssl_ec_point_mul(group->curve_idx, (ecc_point*)r->internal,
ni, qi, mi);
}
if (r != NULL) {
r->inSet = (ret == 1);
}
if ((ret == 1) && (ec_point_external_set(r) != 1)) {
WOLFSSL_MSG("ec_point_external_set error");
ret = 0;
}
#ifdef DEBUG_WOLFSSL
if (ret == 1) {
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul result", r);
}
#endif
return ret;
}
#endif
static int wolfssl_ec_point_invert(int curveIdx, ecc_point* point)
{
int ret = 1;
WC_DECLARE_VAR(prime, mp_int, 1, 0);
WC_ALLOC_VAR_EX(prime, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, ret=0);
if ((ret == 1) && (mp_init(prime) != MP_OKAY)) {
WOLFSSL_MSG("mp_init_multi error");
ret = 0;
}
if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime,
MP_RADIX_HEX) != MP_OKAY)) {
WOLFSSL_MSG("mp_read_radix prime error");
ret = 0;
}
if ((ret == 1) && (!mp_iszero(point->y)) && (mp_sub(prime, point->y,
point->y) != MP_OKAY)) {
WOLFSSL_MSG("mp_sub error");
ret = 0;
}
mp_free(prime);
WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT);
return ret;
}
int wolfSSL_EC_POINT_invert(const WOLFSSL_EC_GROUP *group,
WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx)
{
int ret = 1;
(void)ctx;
WOLFSSL_ENTER("wolfSSL_EC_POINT_invert");
if ((group == NULL) || (point == NULL) || (point->internal == NULL)) {
ret = 0;
}
if ((ret == 1) && (ec_point_setup(point) != 1)) {
ret = 0;
}
#ifdef DEBUG_WOLFSSL
if (ret == 1) {
int nid = wolfSSL_EC_GROUP_get_curve_name(group);
const char* curve = wolfSSL_OBJ_nid2ln(nid);
const char* nistName = wolfSSL_EC_curve_nid2nist(nid);
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert input", point);
if (curve != NULL)
WOLFSSL_MSG_EX("curve name: %s", curve);
if (nistName != NULL)
WOLFSSL_MSG_EX("nist curve name: %s", nistName);
}
#endif
if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) {
#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)
if (ec_point_convert_to_affine(group, point) != 0)
ret = 0;
#else
WOLFSSL_MSG("wolfSSL_EC_POINT_invert called on non-affine point");
ret = 0;
#endif
}
if (ret == 1) {
ret = wolfssl_ec_point_invert(group->curve_idx,
(ecc_point*)point->internal);
}
if ((ret == 1) && (ec_point_external_set(point) != 1)) {
WOLFSSL_MSG("ec_point_external_set error");
ret = 0;
}
#ifdef DEBUG_WOLFSSL
if (ret == 1) {
wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert result", point);
}
#endif
return ret;
}
#ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN
static int ec_point_cmp_jacobian(const WOLFSSL_EC_GROUP* group,
const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx)
{
int ret = 0;
BIGNUM* at = BN_new();
BIGNUM* bt = BN_new();
BIGNUM* az = BN_new();
BIGNUM* bz = BN_new();
BIGNUM* mod = BN_new();
if ((at == NULL) || (bt == NULL) || (az == NULL) || (bz == NULL) ||
(mod == NULL)) {
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 0) &&
(BN_hex2bn(&mod, ecc_sets[group->curve_idx].prime) != 1)) {
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == 0) {
if (BN_is_one(a->Z)) {
if (BN_copy(bt, b->X) == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
}
else if ((BN_mod_mul(az, a->Z, a->Z, mod, ctx) != 1)) {
ret = WOLFSSL_FATAL_ERROR;
}
else if (BN_mod_mul(bt, b->X, az, mod, ctx) != 1) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 0) {
if (BN_is_one(b->Z)) {
if (BN_copy(at, a->X) == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
}
else if (BN_mod_mul(bz, b->Z, b->Z, mod, ctx) != 1) {
ret = WOLFSSL_FATAL_ERROR;
}
else if (BN_mod_mul(at, a->X, bz, mod, ctx) != 1) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if ((ret == 0) && (BN_cmp(at, bt) != 0)) {
ret = 1;
}
if (ret == 0) {
if (BN_is_one(a->Z)) {
if (BN_copy(bt, b->Y) == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
}
else if ((BN_mod_mul(az, az, a->Z, mod, ctx) != 1)) {
ret = WOLFSSL_FATAL_ERROR;
}
else if (BN_mod_mul(bt, b->Y, az, mod, ctx) != 1) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 0) {
if (BN_is_one(b->Z)) {
if (BN_copy(at, a->Y) == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
}
else if (BN_mod_mul(bz, bz, b->Z, mod, ctx) != 1) {
ret = WOLFSSL_FATAL_ERROR;
}
else if (BN_mod_mul(at, a->Y, bz, mod, ctx) != 1) {
ret = WOLFSSL_FATAL_ERROR;
}
}
if ((ret == 0) && (BN_cmp(at, bt) != 0)) {
ret = 1;
}
BN_free(mod);
BN_free(bz);
BN_free(az);
BN_free(bt);
BN_free(at);
return ret;
}
#endif
int wolfSSL_EC_POINT_cmp(const WOLFSSL_EC_GROUP *group,
const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx)
{
int ret = 0;
WOLFSSL_ENTER("wolfSSL_EC_POINT_cmp");
if ((group == NULL) || (a == NULL) || (a->internal == NULL) ||
(b == NULL) || (b->internal == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_POINT_cmp Bad arguments");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret != -1) {
#ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN
if (BN_cmp(a->Z, b->Z) == 0) {
ret = ((BN_cmp(a->X, b->X) != 0) || (BN_cmp(a->Y, b->Y) != 0));
}
else {
ret = ec_point_cmp_jacobian(group, a, b, ctx);
}
#else
(void)ctx;
ret = (wc_ecc_cmp_point((ecc_point*)a->internal,
(ecc_point*)b->internal) != MP_EQ);
#endif
}
return ret;
}
int wolfSSL_EC_POINT_copy(WOLFSSL_EC_POINT *dest, const WOLFSSL_EC_POINT *src)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_EC_POINT_copy");
if ((dest == NULL) || (src == NULL)) {
ret = 0;
}
if ((ret == 1) && (ec_point_setup(src) != 1)) {
ret = 0;
}
if ((ret == 1) && (wc_ecc_copy_point((ecc_point*)src->internal,
(ecc_point*)dest->internal) != MP_OKAY)) {
ret = 0;
}
if (ret == 1) {
dest->inSet = 1;
if (ec_point_external_set(dest) != 1) {
ret = 0;
}
}
return ret;
}
WOLFSSL_EC_POINT *wolfSSL_EC_POINT_dup(const WOLFSSL_EC_POINT *src,
const WOLFSSL_EC_GROUP *group)
{
WOLFSSL_EC_POINT *dest;
WOLFSSL_ENTER("wolfSSL_EC_POINT_dup");
if ((src == NULL) || (group == NULL)) {
return NULL;
}
dest = wolfSSL_EC_POINT_new(group);
if (dest == NULL) {
return NULL;
}
if (wolfSSL_EC_POINT_copy(dest, src) != 1) {
wolfSSL_EC_POINT_free(dest);
return NULL;
}
return dest;
}
int wolfSSL_EC_POINT_is_at_infinity(const WOLFSSL_EC_GROUP *group,
const WOLFSSL_EC_POINT *point)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_EC_POINT_is_at_infinity");
if ((group == NULL) || (point == NULL) || (point->internal == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_POINT_is_at_infinity NULL error");
ret = 0;
}
if ((ret == 1) && (ec_point_setup(point) != 1)) {
ret = 0;
}
if (ret == 1) {
#ifndef WOLF_CRYPTO_CB_ONLY_ECC
ret = wc_ecc_point_is_at_infinity((ecc_point*)point->internal);
if (ret < 0) {
WOLFSSL_MSG("ecc_point_is_at_infinity failure");
ret = 0;
}
#else
WOLFSSL_MSG("ecc_point_is_at_infinitiy compiled out");
ret = 0;
#endif
}
return ret;
}
#endif
#ifdef OPENSSL_EXTRA
WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_ex(void* heap, int devId)
{
WOLFSSL_EC_KEY *key = NULL;
int err = 0;
WOLFSSL_ENTER("wolfSSL_EC_KEY_new");
key = (WOLFSSL_EC_KEY*)XMALLOC(sizeof(WOLFSSL_EC_KEY), heap,
DYNAMIC_TYPE_ECC);
if (key == NULL) {
WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_KEY failure");
err = 1;
}
if (!err) {
XMEMSET(key, 0, sizeof(WOLFSSL_EC_KEY));
key->heap = heap;
key->form = WC_POINT_CONVERSION_UNCOMPRESSED;
wolfSSL_RefInit(&key->ref, &err);
#ifdef WOLFSSL_REFCNT_ERROR_RETURN
}
if (!err) {
#endif
key->internal = (ecc_key*)XMALLOC(sizeof(ecc_key), heap,
DYNAMIC_TYPE_ECC);
if (key->internal == NULL) {
WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc ecc key failure");
err = 1;
}
}
if (!err) {
if (wc_ecc_init_ex((ecc_key*)key->internal, heap, devId) != 0) {
WOLFSSL_MSG("wolfSSL_EC_KEY_new init ecc key failure");
err = 1;
}
}
if (!err) {
key->group = wolfSSL_EC_GROUP_new_by_curve_name(WC_NID_undef);
if (key->group == NULL) {
WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_GROUP failure");
err = 1;
}
}
if (!err) {
key->pub_key = wolfSSL_EC_POINT_new(key->group);
if (key->pub_key == NULL) {
WOLFSSL_MSG("wolfSSL_EC_POINT_new failure");
err = 1;
}
}
if (!err) {
key->priv_key = wolfSSL_BN_new();
if (key->priv_key == NULL) {
WOLFSSL_MSG("wolfSSL_BN_new failure");
err = 1;
}
}
if (err) {
wolfSSL_EC_KEY_free(key);
key = NULL;
}
return key;
}
WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new(void)
{
return wolfSSL_EC_KEY_new_ex(NULL, INVALID_DEVID);
}
WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_by_curve_name(int nid)
{
WOLFSSL_EC_KEY *key;
int err = 0;
WOLFSSL_ENTER("wolfSSL_EC_KEY_new_by_curve_name");
key = wolfSSL_EC_KEY_new();
if (key == NULL) {
WOLFSSL_MSG("wolfSSL_EC_KEY_new failure");
err = 1;
}
if (!err) {
ec_group_set_nid(key->group, nid);
if (key->group->curve_idx == -1) {
wolfSSL_EC_KEY_free(key);
key = NULL;
}
}
return key;
}
void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key)
{
int doFree = 0;
int err;
(void)err;
WOLFSSL_ENTER("wolfSSL_EC_KEY_free");
if (key != NULL) {
void* heap = key->heap;
wolfSSL_RefDec(&key->ref, &doFree, &err);
if (doFree) {
wolfSSL_RefFree(&key->ref);
wolfSSL_BN_free(key->priv_key);
wolfSSL_EC_POINT_free(key->pub_key);
wolfSSL_EC_GROUP_free(key->group);
if (key->internal != NULL) {
wc_ecc_free((ecc_key*)key->internal);
XFREE(key->internal, heap, DYNAMIC_TYPE_ECC);
}
ForceZero(key, sizeof(*key));
XFREE(key, heap, DYNAMIC_TYPE_ECC);
(void)heap;
}
}
}
int wolfSSL_EC_KEY_up_ref(WOLFSSL_EC_KEY* key)
{
int err = 1;
if (key != NULL) {
wolfSSL_RefInc(&key->ref, &err);
}
return !err;
}
#ifndef NO_CERTS
#if defined(OPENSSL_ALL)
static int wolfssl_ec_key_int_copy(ecc_key* dst, const ecc_key* src)
{
int ret;
#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)
ret = wc_ecc_copy_point(&src->pubkey, &dst->pubkey);
#else
ret = wc_ecc_copy_point((ecc_point*)&src->pubkey, &dst->pubkey);
#endif
if (ret != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_copy_point error");
}
if (ret == 0) {
ret = mp_copy(wc_ecc_key_get_priv((ecc_key*)src),
wc_ecc_key_get_priv(dst));
if (ret != MP_OKAY) {
WOLFSSL_MSG("mp_copy error");
}
}
if (ret == 0) {
if (src->dp) {
ret = wc_ecc_set_curve(dst, 0, src->dp->id);
if (ret != 0) {
WOLFSSL_MSG("wc_ecc_set_curve error");
}
}
}
if (ret == 0) {
dst->type = src->type;
dst->idx = src->idx;
dst->state = src->state;
dst->flags = src->flags;
}
return ret;
}
WOLFSSL_EC_KEY *wolfSSL_EC_KEY_dup(const WOLFSSL_EC_KEY *src)
{
int err = 0;
WOLFSSL_EC_KEY* newKey = NULL;
WOLFSSL_ENTER("wolfSSL_EC_KEY_dup");
if ((src == NULL) || (src->internal == NULL) || (src->group == NULL) ||
(src->pub_key == NULL) || (src->priv_key == NULL)) {
WOLFSSL_MSG("src NULL error");
err = 1;
}
if (!err) {
newKey = wolfSSL_EC_KEY_new();
if (newKey == NULL) {
WOLFSSL_MSG("wolfSSL_EC_KEY_new error");
err = 1;
}
}
if (!err) {
if (wolfssl_ec_key_int_copy((ecc_key*)newKey->internal,
(ecc_key*)src->internal) != 0) {
WOLFSSL_MSG("Copying internal EC key error");
err = 1;
}
}
if (!err) {
newKey->inSet = 1;
err = wolfssl_ec_group_copy(newKey->group, src->group);
}
if ((!err) && (wolfSSL_EC_POINT_copy(newKey->pub_key, src->pub_key) != 1)) {
WOLFSSL_MSG("Copying EC public key error");
err = 1;
}
if (!err) {
newKey->pkcs8HeaderSz = src->pkcs8HeaderSz;
if (wolfSSL_BN_copy(newKey->priv_key, src->priv_key) == NULL) {
WOLFSSL_MSG("Copying EC private key error");
err = 1;
}
}
if (err) {
wolfSSL_EC_KEY_free(newKey);
newKey = NULL;
}
return newKey;
}
#endif
#endif
WOLFSSL_EC_KEY *wolfSSL_o2i_ECPublicKey(WOLFSSL_EC_KEY **key,
const unsigned char **in, long len)
{
int err = 0;
WOLFSSL_EC_KEY* ret = NULL;
WOLFSSL_ENTER("wolfSSL_o2i_ECPublicKey");
if ((key == NULL) || (*key == NULL) || ((*key)->group == NULL) ||
(in == NULL) || (*in == NULL) || (len <= 0)) {
WOLFSSL_MSG("wolfSSL_o2i_ECPublicKey Bad arguments");
err = 1;
}
if (!err) {
ret = *key;
if (wolfSSL_EC_POINT_oct2point(ret->group, ret->pub_key, *in,
(size_t)len, NULL) != 1) {
WOLFSSL_MSG("wolfSSL_EC_POINT_oct2point error");
ret = NULL;
err = 1;
}
}
if (!err) {
*in += len;
}
return ret;
}
int wolfSSL_i2o_ECPublicKey(const WOLFSSL_EC_KEY *key, unsigned char **out)
{
int ret = 1;
size_t len = 0;
int form = WC_POINT_CONVERSION_UNCOMPRESSED;
WOLFSSL_ENTER("wolfSSL_i2o_ECPublicKey");
if (key == NULL) {
WOLFSSL_MSG("wolfSSL_i2o_ECPublicKey Bad arguments");
ret = 0;
}
if ((ret == 1) && (!key->exSet) && (SetECKeyExternal((WOLFSSL_EC_KEY*)
key) != 1)) {
WOLFSSL_MSG("SetECKeyExternal failure");
ret = 0;
}
if (ret == 1) {
#ifdef HAVE_COMP_KEY
form = (key->form == WC_POINT_CONVERSION_UNCOMPRESSED) ?
WC_POINT_CONVERSION_UNCOMPRESSED :
WC_POINT_CONVERSION_COMPRESSED;
#endif
len = wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, form, NULL,
0, NULL);
}
if ((ret == 1) && (len != 0) && (out != NULL)) {
unsigned char *tmp = NULL;
if (*out == NULL) {
tmp = (unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL);
if (tmp == NULL) {
WOLFSSL_MSG("malloc failed");
ret = 0;
}
}
else {
tmp = *out;
}
if ((ret == 1) && (wolfSSL_EC_POINT_point2oct(key->group, key->pub_key,
form, tmp, len, NULL) == 0)) {
ret = 0;
}
if (ret == 1) {
if (*out == NULL) {
*out = tmp;
}
else {
*out += len;
}
}
else if (*out == NULL) {
XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL);
}
}
if (ret == 1) {
ret = (int)len;
}
return ret;
}
#ifdef HAVE_ECC_KEY_IMPORT
WOLFSSL_EC_KEY* wolfSSL_d2i_ECPrivateKey(WOLFSSL_EC_KEY** key,
const unsigned char** in, long len)
{
int err = 0;
word32 idx = 0;
WOLFSSL_EC_KEY* ret = NULL;
WOLFSSL_ENTER("wolfSSL_d2i_ECPrivateKey");
if ((in == NULL) || (*in == NULL) || (len <= 0)) {
WOLFSSL_MSG("wolfSSL_d2i_ECPrivateKey Bad arguments");
err = 1;
}
if ((!err) && ((ret = wolfSSL_EC_KEY_new()) == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_KEY_new error");
err = 1;
}
if ((!err) && (wc_EccPrivateKeyDecode(*in, &idx, (ecc_key*)ret->internal,
(word32)len) != 0)) {
WOLFSSL_MSG("wc_EccPrivateKeyDecode error");
err = 1;
}
if (!err) {
ret->inSet = 1;
if (SetECKeyExternal(ret) != 1) {
WOLFSSL_MSG("SetECKeyExternal error");
err = 1;
}
}
if (!err) {
*in += idx;
if (key) {
*key = ret;
}
}
if (err && (ret != NULL)) {
wolfSSL_EC_KEY_free(ret);
ret = NULL;
}
return ret;
}
#endif
int wolfSSL_i2d_ECPrivateKey(const WOLFSSL_EC_KEY *key, unsigned char **out)
{
int err = 0;
word32 len = 0;
WOLFSSL_ENTER("wolfSSL_i2d_ECPrivateKey");
if (key == NULL) {
WOLFSSL_MSG("wolfSSL_i2d_ECPrivateKey Bad arguments");
err = 1;
}
if ((!err) && (!key->inSet) && (SetECKeyInternal((WOLFSSL_EC_KEY*)key) !=
1)) {
WOLFSSL_MSG("SetECKeyInternal error");
err = 1;
}
if ((!err) && ((int)(len = (word32)wc_EccKeyDerSize((ecc_key*)key->internal,
0)) <= 0)) {
WOLFSSL_MSG("wc_EccKeyDerSize error");
err = 1;
}
if ((!err) && (out != NULL)) {
unsigned char* buf = NULL;
if (*out == NULL) {
buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (buf == NULL) {
err = 1;
len = 0;
}
else {
*out = buf;
}
}
if ((!err) && wc_EccPrivateKeyToDer((ecc_key*)key->internal, *out,
len) < 0) {
WOLFSSL_MSG("wc_EccPrivateKeyToDer error");
err = 1;
}
else if (buf != *out) {
*out += len;
}
if (err && (*out == buf)) {
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
*out = NULL;
}
}
return (int)len;
}
int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf,
int derSz)
{
return wolfSSL_EC_KEY_LoadDer_ex(key, derBuf, derSz,
WOLFSSL_EC_KEY_LOAD_PRIVATE);
}
int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf,
int derSz, int opt)
{
int res = 1;
int ret;
word32 idx = 0;
word32 algId;
WOLFSSL_ENTER("wolfSSL_EC_KEY_LoadDer");
if ((key == NULL) || (key->internal == NULL) || (derBuf == NULL) ||
(derSz <= 0)) {
WOLFSSL_MSG("Bad function arguments");
res = WOLFSSL_FATAL_ERROR;
}
if ((res == 1) && (opt != WOLFSSL_EC_KEY_LOAD_PRIVATE) &&
(opt != WOLFSSL_EC_KEY_LOAD_PUBLIC)) {
res = WOLFSSL_FATAL_ERROR;
}
if (res == 1) {
key->pkcs8HeaderSz = 0;
if ((ret = ToTraditionalInline_ex((const byte*)derBuf, &idx,
(word32)derSz, &algId)) >= 0) {
WOLFSSL_MSG("Found PKCS8 header");
key->pkcs8HeaderSz = (word16)idx;
res = 1;
}
else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) {
WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header");
res = WOLFSSL_FATAL_ERROR;
}
}
if (res == 1) {
if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) {
ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal,
(word32)derSz);
}
else {
ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal,
(word32)derSz);
if (ret < 0) {
ecc_key *tmp = (ecc_key*)XMALLOC(sizeof(ecc_key),
((ecc_key*)key->internal)->heap, DYNAMIC_TYPE_ECC);
if (tmp == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
else {
ret = wc_ecc_init_ex(tmp, ((ecc_key*)key->internal)->heap,
INVALID_DEVID);
if (ret == 0) {
ret = wc_ecc_import_x963(derBuf, (word32)derSz, tmp);
if (ret == 0) {
ecc_key *old = (ecc_key *)key->internal;
key->internal = tmp;
tmp = old;
idx = (word32)derSz;
}
wc_ecc_free(tmp);
}
XFREE(tmp, ((ecc_key*)key->internal)->heap,
DYNAMIC_TYPE_ECC);
}
}
}
if (ret < 0) {
if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) {
WOLFSSL_MSG("wc_EccPrivateKeyDecode failed");
}
else {
WOLFSSL_MSG("wc_EccPublicKeyDecode failed");
}
res = WOLFSSL_FATAL_ERROR;
}
key->inSet = (res == 1);
}
if ((res == 1) && (SetECKeyExternal(key) != 1)) {
WOLFSSL_MSG("SetECKeyExternal failed");
res = WOLFSSL_FATAL_ERROR;
}
return res;
}
#ifndef NO_BIO
WOLFSSL_EC_KEY *wolfSSL_d2i_EC_PUBKEY_bio(WOLFSSL_BIO *bio,
WOLFSSL_EC_KEY **out)
{
char* data = NULL;
int dataSz = 0;
int memAlloced = 0;
WOLFSSL_EC_KEY* ec = NULL;
int err = 0;
WOLFSSL_ENTER("wolfSSL_d2i_EC_PUBKEY_bio");
if (bio == NULL)
return NULL;
if (err == 0 && wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) {
WOLFSSL_ERROR_MSG("wolfssl_read_bio failed");
err = 1;
}
if (err == 0 && (ec = wolfSSL_EC_KEY_new()) == NULL) {
WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_new failed");
err = 1;
}
if (err == 0 && wolfSSL_EC_KEY_LoadDer_ex(ec, (const unsigned char*)data,
dataSz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1) {
WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_LoadDer_ex failed");
err = 1;
}
if (memAlloced)
XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (err) {
wolfSSL_EC_KEY_free(ec);
ec = NULL;
}
else {
if (out != NULL)
*out = ec;
}
return ec;
}
#endif
#ifdef HAVE_ECC_KEY_EXPORT
#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_FILESYSTEM) || !defined(NO_BIO))
static int wolfssl_ec_key_to_pubkey_der(WOLFSSL_EC_KEY* key,
unsigned char** der, void* heap)
{
int sz;
unsigned char* buf = NULL;
(void)heap;
sz = wc_EccPublicKeyDerSize((ecc_key*)key->internal, 1);
if (sz <= 0) {
WOLFSSL_MSG("wc_EccPublicKeyDerSize failed");
sz = 0;
}
if (sz > 0) {
buf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (buf == NULL) {
WOLFSSL_MSG("malloc failed");
sz = 0;
}
}
if (sz > 0) {
sz = wc_EccPublicKeyToDer((ecc_key*)key->internal, buf, (word32)sz, 1);
if (sz < 0) {
WOLFSSL_MSG("wc_EccPublicKeyToDer failed");
sz = 0;
}
}
if (sz > 0) {
*der = buf;
}
else {
XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER);
}
return sz;
}
#endif
#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_KEY_GEN)
int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY* key)
{
int ret = 1;
unsigned char* derBuf = NULL;
int derSz = 0;
WOLFSSL_ENTER("wolfSSL_PEM_write_EC_PUBKEY");
if ((fp == XBADFILE) || (key == NULL)) {
WOLFSSL_MSG("Bad argument.");
return 0;
}
derSz = wolfssl_ec_key_to_pubkey_der(key, &derBuf, key->heap);
if (derSz == 0) {
ret = 0;
}
if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp,
ECC_PUBLICKEY_TYPE, key->heap) != 1)) {
ret = 0;
}
XFREE(derBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_LEAVE("wolfSSL_PEM_write_EC_PUBKEY", ret);
return ret;
}
#endif
#endif
#ifndef NO_BIO
WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_EC_PUBKEY(WOLFSSL_BIO* bio,
WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass)
{
int err = 0;
WOLFSSL_EC_KEY* ec = NULL;
DerBuffer* der = NULL;
int keyFormat = 0;
WOLFSSL_ENTER("wolfSSL_PEM_read_bio_EC_PUBKEY");
if (bio == NULL) {
err = 1;
}
if (!err) {
ec = wolfSSL_EC_KEY_new();
if (ec == NULL) {
err = 1;
}
}
if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PUBLICKEY_TYPE,
&keyFormat, &der) <= 0)) {
err = 1;
}
if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length,
WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1)) {
WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY");
err = 1;
}
FreeDer(&der);
if (err) {
wolfSSL_EC_KEY_free(ec);
ec = NULL;
}
if ((out != NULL) && (ec != NULL)) {
*out = ec;
}
return ec;
}
WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_ECPrivateKey(WOLFSSL_BIO* bio,
WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass)
{
int err = 0;
WOLFSSL_EC_KEY* ec = NULL;
DerBuffer* der = NULL;
int keyFormat = 0;
WOLFSSL_ENTER("wolfSSL_PEM_read_bio_ECPrivateKey");
if (bio == NULL) {
err = 1;
}
if (!err) {
ec = wolfSSL_EC_KEY_new();
if (ec == NULL) {
err = 1;
}
}
if ((!err) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE,
&keyFormat, &der) <= 0)) {
err = 1;
}
if (keyFormat != ECDSAk) {
WOLFSSL_ERROR_MSG("Error not EC key format");
err = 1;
}
if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length,
WOLFSSL_EC_KEY_LOAD_PRIVATE) != 1)) {
WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY");
err = 1;
}
FreeDer(&der);
if (err) {
wolfSSL_EC_KEY_free(ec);
ec = NULL;
}
if ((out != NULL) && (ec != NULL)) {
*out = ec;
}
return ec;
}
#endif
#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ECC_KEY_EXPORT)
#ifndef NO_BIO
int wolfSSL_PEM_write_bio_EC_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec)
{
int ret = 1;
unsigned char* derBuf = NULL;
int derSz = 0;
WOLFSSL_ENTER("wolfSSL_PEM_write_bio_EC_PUBKEY");
if ((bio == NULL) || (ec == NULL)) {
WOLFSSL_MSG("Bad Function Arguments");
return 0;
}
derSz = wolfssl_ec_key_to_pubkey_der(ec, &derBuf, ec->heap);
if (derSz == 0) {
ret = 0;
}
if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio,
ECC_PUBLICKEY_TYPE) != 1)) {
ret = 0;
}
XFREE(derBuf, ec->heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec,
const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz,
wc_pem_password_cb* cb, void* arg)
{
int ret = 1;
unsigned char* pem = NULL;
int pLen = 0;
(void)cb;
(void)arg;
if ((bio == NULL) || (ec == NULL)) {
ret = 0;
}
if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd,
passwdSz, &pem, &pLen) != 1)) {
ret = 0;
}
if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) {
WOLFSSL_ERROR_MSG("EC private key BIO write failed");
ret = 0;
}
XFREE(pem, NULL, DYNAMIC_TYPE_KEY);
return ret;
}
#endif
int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ec,
const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz,
unsigned char **pem, int *pLen)
{
#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)
int ret = 1;
byte* derBuf = NULL;
word32 der_max_len = 0;
int derSz = 0;
WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey");
if ((pem == NULL) || (pLen == NULL) || (ec == NULL) ||
(ec->internal == NULL)) {
WOLFSSL_MSG("Bad function arguments");
ret = 0;
}
if ((ret == 1) && (ec->inSet == 0)) {
WOLFSSL_MSG("No ECC internal set, do it");
if (SetECKeyInternal(ec) != 1) {
WOLFSSL_MSG("SetECKeyInternal failed");
ret = 0;
}
}
if (ret == 1) {
der_max_len = 4 * (word32)wc_ecc_size((ecc_key*)ec->internal) +
WC_AES_BLOCK_SIZE;
derBuf = (byte*)XMALLOC((size_t)der_max_len, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (derBuf == NULL) {
WOLFSSL_MSG("malloc failed");
ret = 0;
}
}
if (ret == 1) {
derSz = wc_EccKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len);
if (derSz < 0) {
WOLFSSL_MSG("wc_EccKeyToDer failed");
XFREE(derBuf, NULL, DYNAMIC_TYPE_DER);
ret = 0;
}
}
if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd,
passwdSz, ECC_PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) {
WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed");
ret = 0;
}
return ret;
#else
(void)ec;
(void)cipher;
(void)passwd;
(void)passwdSz;
(void)pem;
(void)pLen;
return 0;
#endif
}
#ifndef NO_FILESYSTEM
int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ec,
const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz,
wc_pem_password_cb *cb, void *pass)
{
int ret = 1;
byte *pem = NULL;
int pLen = 0;
(void)cb;
(void)pass;
WOLFSSL_MSG("wolfSSL_PEM_write_ECPrivateKey");
if ((fp == XBADFILE) || (ec == NULL) || (ec->internal == NULL)) {
WOLFSSL_MSG("Bad function arguments");
ret = 0;
}
if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd,
passwdSz, &pem, &pLen) != 1)) {
WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey failed");
ret = 0;
}
if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) {
WOLFSSL_MSG("ECC private key file write failed");
ret = 0;
}
XFREE(pem, NULL, DYNAMIC_TYPE_KEY);
return ret;
}
#endif
#endif
#ifndef NO_CERTS
#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \
!defined(NO_STDIO_FILESYSTEM)
int wolfSSL_EC_KEY_print_fp(XFILE fp, WOLFSSL_EC_KEY* key, int indent)
{
int ret = 1;
int bits = 0;
int priv = 0;
WOLFSSL_ENTER("wolfSSL_EC_KEY_print_fp");
if ((fp == XBADFILE) || (key == NULL) || (key->group == NULL) ||
(indent < 0)) {
ret = 0;
}
if (ret == 1) {
bits = wolfSSL_EC_GROUP_order_bits(key->group);
if (bits <= 0) {
WOLFSSL_MSG("Failed to get group order bits.");
ret = 0;
}
}
if (ret == 1) {
const char* keyType;
if ((key->priv_key != NULL) && (!wolfSSL_BN_is_zero(key->priv_key))) {
keyType = "Private-Key";
priv = 1;
}
else {
keyType = "Public-Key";
}
if (XFPRINTF(fp, "%*s%s: (%d bit)\n", indent, "", keyType, bits) < 0) {
ret = 0;
}
}
if ((ret == 1) && priv) {
ret = pk_bn_field_print_fp(fp, indent, "priv", key->priv_key);
}
if ((ret == 1) && (key->pub_key != NULL) && (key->pub_key->exSet)) {
WOLFSSL_BIGNUM* pubBn = wolfSSL_EC_POINT_point2bn(key->group,
key->pub_key, WC_POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
if (pubBn == NULL) {
WOLFSSL_MSG("wolfSSL_EC_POINT_point2bn failed.");
ret = 0;
}
else {
ret = pk_bn_field_print_fp(fp, indent, "pub", pubBn);
wolfSSL_BN_free(pubBn);
}
}
if (ret == 1) {
int nid = wolfSSL_EC_GROUP_get_curve_name(key->group);
if (nid > 0) {
const char* curve = wolfSSL_OBJ_nid2ln(nid);
const char* nistName = wolfSSL_EC_curve_nid2nist(nid);
if ((curve != NULL) &&
(XFPRINTF(fp, "%*sASN1 OID: %s\n", indent, "", curve) < 0)) {
ret = 0;
}
if ((nistName != NULL) &&
(XFPRINTF(fp, "%*sNIST CURVE: %s\n", indent, "",
nistName) < 0)) {
ret = 0;
}
}
}
WOLFSSL_LEAVE("wolfSSL_EC_KEY_print_fp", ret);
return ret;
}
#endif
#endif
int SetECKeyExternal(WOLFSSL_EC_KEY* eckey)
{
int ret = 1;
WOLFSSL_ENTER("SetECKeyExternal");
if ((eckey == NULL) || (eckey->internal == NULL)) {
WOLFSSL_MSG("ec key NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
else {
ecc_key* key = (ecc_key*)eckey->internal;
eckey->group->curve_oid = (int)key->dp->oidSum;
eckey->group->curve_nid = EccEnumToNID(key->dp->id);
eckey->group->curve_idx = key->idx;
if (eckey->pub_key->internal != NULL) {
if (wc_ecc_copy_point(&key->pubkey,
(ecc_point*)eckey->pub_key->internal) != MP_OKAY) {
WOLFSSL_MSG("SetECKeyExternal ecc_copy_point failed");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (ec_point_external_set(eckey->pub_key) != 1)) {
WOLFSSL_MSG("SetECKeyExternal ec_point_external_set failed");
ret = WOLFSSL_FATAL_ERROR;
}
}
if ((ret == 1) && (key->type == ECC_PRIVATEKEY) &&
(wolfssl_bn_set_value(&eckey->priv_key,
wc_ecc_key_get_priv(key)) != 1)) {
WOLFSSL_MSG("ec priv key error");
ret = WOLFSSL_FATAL_ERROR;
}
eckey->exSet = (ret == 1);
}
return ret;
}
int SetECKeyInternal(WOLFSSL_EC_KEY* eckey)
{
int ret = 1;
WOLFSSL_ENTER("SetECKeyInternal");
if ((eckey == NULL) || (eckey->internal == NULL) ||
(eckey->group == NULL)) {
WOLFSSL_MSG("ec key NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
else {
ecc_key* key = (ecc_key*)eckey->internal;
int pubSet = 0;
if ((eckey->group->curve_idx < 0) ||
(wc_ecc_is_valid_idx(eckey->group->curve_idx) == 0)) {
WOLFSSL_MSG("invalid curve idx");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == 1) {
key->idx = eckey->group->curve_idx;
key->dp = &ecc_sets[key->idx];
pubSet = (eckey->pub_key != NULL);
}
if ((ret == 1) && pubSet) {
if (ec_point_internal_set(eckey->pub_key) != 1) {
WOLFSSL_MSG("ec key pub error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (wc_ecc_copy_point(
(ecc_point*)eckey->pub_key->internal, &key->pubkey) !=
MP_OKAY)) {
WOLFSSL_MSG("wc_ecc_copy_point error");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == 1) {
key->type = ECC_PUBLICKEY;
}
}
if ((ret == 1) && (eckey->priv_key != NULL)) {
if (wolfssl_bn_get_value(eckey->priv_key,
wc_ecc_key_get_priv(key)) != 1) {
WOLFSSL_MSG("ec key priv error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (!mp_iszero(wc_ecc_key_get_priv(key)))) {
if (pubSet) {
key->type = ECC_PRIVATEKEY;
}
else {
key->type = ECC_PRIVATEKEY_ONLY;
}
}
}
eckey->inSet = (ret == 1);
}
return ret;
}
wc_point_conversion_form_t wolfSSL_EC_KEY_get_conv_form(
const WOLFSSL_EC_KEY* key)
{
if (key == NULL)
return WOLFSSL_FATAL_ERROR;
return key->form;
}
void wolfSSL_EC_KEY_set_conv_form(WOLFSSL_EC_KEY *key, int form)
{
if (key == NULL) {
WOLFSSL_MSG("Key passed in NULL");
}
else if (form == WC_POINT_CONVERSION_UNCOMPRESSED
#ifdef HAVE_COMP_KEY
|| form == WC_POINT_CONVERSION_COMPRESSED
#endif
) {
key->form = (unsigned char)form;
}
else {
WOLFSSL_MSG("Incorrect form or HAVE_COMP_KEY not compiled in");
}
}
const WOLFSSL_EC_GROUP *wolfSSL_EC_KEY_get0_group(const WOLFSSL_EC_KEY *key)
{
WOLFSSL_EC_GROUP* group = NULL;
WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_group");
if (key != NULL) {
group = key->group;
}
return group;
}
int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_EC_KEY_set_group");
if ((key == NULL) || (group == NULL)) {
ret = 0;
}
if (ret == 1) {
if (key->group != NULL) {
wolfSSL_EC_GROUP_free(key->group);
}
key->group = wolfSSL_EC_GROUP_dup(group);
if (key->group == NULL) {
ret = 0;
}
}
return ret;
}
WOLFSSL_BIGNUM *wolfSSL_EC_KEY_get0_private_key(const WOLFSSL_EC_KEY *key)
{
WOLFSSL_BIGNUM* priv_key = NULL;
WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_private_key");
if (key == NULL) {
WOLFSSL_MSG("wolfSSL_EC_KEY_get0_private_key Bad arguments");
}
else if (!wolfSSL_BN_is_zero(key->priv_key)) {
priv_key = key->priv_key;
}
return priv_key;
}
int wolfSSL_EC_KEY_set_private_key(WOLFSSL_EC_KEY *key,
const WOLFSSL_BIGNUM *priv_key)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_EC_KEY_set_private_key");
if ((key == NULL) || (priv_key == NULL)) {
WOLFSSL_MSG("Bad arguments");
ret = 0;
}
if (wolfSSL_BN_is_negative(priv_key) || wolfSSL_BN_is_zero(priv_key) ||
wolfSSL_BN_is_one(priv_key)) {
WOLFSSL_MSG("Invalid private key value");
ret = 0;
}
if (ret == 1) {
if (key->priv_key != NULL) {
wolfSSL_BN_free(key->priv_key);
}
key->priv_key = wolfSSL_BN_dup(priv_key);
if (key->priv_key == NULL) {
WOLFSSL_MSG("key ecc priv key NULL");
ret = 0;
}
}
if ((ret == 1) && (SetECKeyInternal(key) != 1)) {
WOLFSSL_MSG("SetECKeyInternal failed");
wolfSSL_BN_free(key->priv_key);
key->priv_key = NULL;
ret = 0;
}
return ret;
}
WOLFSSL_EC_POINT* wolfSSL_EC_KEY_get0_public_key(const WOLFSSL_EC_KEY *key)
{
WOLFSSL_EC_POINT* pub_key = NULL;
WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_public_key");
if (key != NULL) {
pub_key = key->pub_key;
}
return pub_key;
}
int wolfSSL_EC_KEY_set_public_key(WOLFSSL_EC_KEY *key,
const WOLFSSL_EC_POINT *pub)
{
int ret = 1;
ecc_point *pub_p = NULL;
ecc_point *key_p = NULL;
WOLFSSL_ENTER("wolfSSL_EC_KEY_set_public_key");
if ((key == NULL) || (key->internal == NULL) || (pub == NULL) ||
(pub->internal == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_KEY_set_public_key Bad arguments");
ret = 0;
}
if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal(key) != 1)) {
WOLFSSL_MSG("SetECKeyInternal failed");
ret = 0;
}
if ((ret == 1) && (ec_point_setup(pub) != 1)) {
ret = 0;
}
if (ret == 1) {
pub_p = (ecc_point*)pub->internal;
key_p = (ecc_point*)key->pub_key->internal;
if (key_p == NULL) {
key_p = wc_ecc_new_point();
key->pub_key->internal = (void*)key_p;
}
if (key_p == NULL) {
WOLFSSL_MSG("key ecc point NULL");
ret = 0;
}
}
if ((ret == 1) && (wc_ecc_copy_point(pub_p, key_p) != MP_OKAY)) {
WOLFSSL_MSG("ecc_copy_point failure");
ret = 0;
}
if ((ret == 1) && (ec_point_external_set(key->pub_key) != 1)) {
WOLFSSL_MSG("SetECKeyInternal failed");
ret = 0;
}
if ((ret == 1) && (SetECKeyInternal(key) != 1)) {
WOLFSSL_MSG("SetECKeyInternal failed");
ret = 0;
}
if (ret == 1) {
wolfSSL_EC_POINT_dump("pub", pub);
wolfSSL_EC_POINT_dump("key->pub_key", key->pub_key);
}
return ret;
}
#ifndef NO_WOLFSSL_STUB
void wolfSSL_EC_KEY_set_asn1_flag(WOLFSSL_EC_KEY *key, int asn1_flag)
{
(void)key;
(void)asn1_flag;
WOLFSSL_ENTER("wolfSSL_EC_KEY_set_asn1_flag");
WOLFSSL_STUB("EC_KEY_set_asn1_flag");
}
#endif
int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key)
{
int res = 1;
int initTmpRng = 0;
WC_RNG* rng = NULL;
WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
WOLFSSL_ENTER("wolfSSL_EC_KEY_generate_key");
if ((key == NULL) || (key->internal == NULL) || (key->group == NULL)) {
WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key Bad arguments");
res = 0;
}
if (res == 1) {
if (key->group->curve_idx < 0) {
#if FIPS_VERSION3_GE(6,0,0)
key->group->curve_idx = ECC_SECP256R1;
#else
key->group->curve_idx = ECC_CURVE_DEF;
#endif
}
rng = wolfssl_make_rng(tmpRng, &initTmpRng);
if (rng == NULL) {
WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG");
res = 0;
}
}
if (res == 1) {
int eccEnum = key->group->curve_nid ?
#if FIPS_VERSION3_GE(6,0,0)
NIDToEccEnum(key->group->curve_nid) : ECC_SECP256R1;
#else
NIDToEccEnum(key->group->curve_nid) : ECC_CURVE_DEF;
#endif
ecc_key* ecKey = (ecc_key*)key->internal;
int ret = 0;
#if FIPS_VERSION3_GE(6,0,0)
if (eccEnum != ECC_SECP256R1 && eccEnum != ECC_SECP224R1 &&
eccEnum != ECC_SECP384R1 && eccEnum != ECC_SECP521R1) {
WOLFSSL_MSG("Unsupported curve selected in FIPS mode");
res = 0;
}
if (res == 1) {
#endif
ret = wc_ecc_make_key_ex(rng, 0, ecKey, eccEnum);
#if FIPS_VERSION3_GE(6,0,0)
}
#endif
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &ecKey->asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0) {
WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key wc_ecc_make_key failed");
res = 0;
}
}
if (initTmpRng) {
wc_FreeRng(rng);
WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG);
}
if ((res == 1) && (SetECKeyExternal(key) != 1)) {
WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key SetECKeyExternal failed");
res = 0;
}
return res;
}
int wolfSSL_EC_KEY_check_key(const WOLFSSL_EC_KEY *key)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_EC_KEY_check_key");
if ((key == NULL) || (key->internal == NULL)) {
WOLFSSL_MSG("Bad parameter");
ret = 0;
}
if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal(
(WOLFSSL_EC_KEY*)key) != 1)) {
WOLFSSL_MSG("SetECKeyInternal failed");
ret = 0;
}
if (ret == 1) {
ret = wc_ecc_check_key((ecc_key*)key->internal) == 0;
}
return ret;
}
#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)
size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *curves,
size_t len)
{
size_t i;
size_t cnt;
#ifdef HAVE_SELFTEST
size_t ecc_sets_count;
for (i = 0; ecc_sets[i].size != 0 && ecc_sets[i].name != NULL; i++) {
}
ecc_sets_count = i;
#endif
cnt = ecc_sets_count;
if ((curves != NULL) && (len != 0)) {
if (cnt > len) {
cnt = len;
}
for (i = 0; i < cnt; i++) {
curves[i].nid = EccEnumToNID(ecc_sets[i].id);
curves[i].comment = wolfSSL_OBJ_nid2sn(curves[i].nid);
}
}
return cnt;
}
#endif
WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_SIG_new(void)
{
int err = 0;
WOLFSSL_ECDSA_SIG *sig;
WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_new");
sig = (WOLFSSL_ECDSA_SIG*)XMALLOC(sizeof(WOLFSSL_ECDSA_SIG), NULL,
DYNAMIC_TYPE_ECC);
if (sig == NULL) {
WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA signature failure");
return NULL;
}
sig->s = NULL;
sig->r = wolfSSL_BN_new();
if (sig->r == NULL) {
WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA r failure");
err = 1;
}
if (!err) {
sig->s = wolfSSL_BN_new();
if (sig->s == NULL) {
WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA s failure");
err = 1;
}
}
if (err) {
wolfSSL_ECDSA_SIG_free(sig);
sig = NULL;
}
return sig;
}
void wolfSSL_ECDSA_SIG_free(WOLFSSL_ECDSA_SIG *sig)
{
WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_free");
if (sig != NULL) {
wolfSSL_BN_free(sig->r);
wolfSSL_BN_free(sig->s);
XFREE(sig, NULL, DYNAMIC_TYPE_ECC);
}
}
WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig,
const unsigned char** pp, long len)
{
int err = 0;
WOLFSSL_ECDSA_SIG *s = NULL;
if (pp == NULL) {
err = 1;
}
if (!err) {
if (sig != NULL) {
s = *sig;
}
if (s == NULL) {
s = wolfSSL_ECDSA_SIG_new();
if (s == NULL) {
err = 1;
}
}
}
if (!err) {
mp_free((mp_int*)s->r->internal);
mp_free((mp_int*)s->s->internal);
if (DecodeECC_DSA_Sig(*pp, (word32)len, (mp_int*)s->r->internal,
(mp_int*)s->s->internal) != MP_OKAY) {
err = 1;
}
}
if (!err) {
*pp += wolfssl_der_length(*pp, (int)len);
if (sig != NULL) {
*sig = s;
}
}
if (err) {
if ((s != NULL) && ((sig == NULL) || (*sig != s))) {
wolfSSL_ECDSA_SIG_free(s);
}
s = NULL;
}
return s;
}
int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig, unsigned char **pp)
{
word32 len = 0;
int update_p = 1;
if (sig != NULL) {
word32 rLen = (word32)(mp_leading_bit((mp_int*)sig->r->internal) +
mp_unsigned_bin_size((mp_int*)sig->r->internal));
word32 sLen = (word32)(mp_leading_bit((mp_int*)sig->s->internal) +
mp_unsigned_bin_size((mp_int*)sig->s->internal));
len = (word32)1 + ASN_LEN_SIZE(rLen) + rLen +
(word32)1 + ASN_LEN_SIZE(sLen) + sLen;
len += (word32)1 + ASN_LEN_SIZE(len);
#ifdef WOLFSSL_I2D_ECDSA_SIG_ALLOC
if ((pp != NULL) && (*pp == NULL)) {
*pp = (unsigned char *)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL);
if (*pp == NULL) {
WOLFSSL_MSG("malloc error");
return 0;
}
update_p = 0;
}
#endif
if ((pp != NULL) && (*pp != NULL)) {
if (StoreECC_DSA_Sig(*pp, &len, (mp_int*)sig->r->internal,
(mp_int*)sig->s->internal) != MP_OKAY) {
len = 0;
}
else if (update_p) {
*pp += len;
}
}
}
return (int)len;
}
void wolfSSL_ECDSA_SIG_get0(const WOLFSSL_ECDSA_SIG* sig,
const WOLFSSL_BIGNUM** r, const WOLFSSL_BIGNUM** s)
{
if (sig != NULL) {
if (r != NULL) {
*r = sig->r;
}
if (s != NULL) {
*s = sig->s;
}
}
}
int wolfSSL_ECDSA_SIG_set0(WOLFSSL_ECDSA_SIG* sig, WOLFSSL_BIGNUM* r,
WOLFSSL_BIGNUM* s)
{
int ret = 1;
if ((sig == NULL) || (r == NULL) || (s == NULL)) {
ret = 0;
}
if (ret == 1) {
wolfSSL_BN_free(sig->r);
wolfSSL_BN_free(sig->s);
sig->r = r;
sig->s = s;
}
return ret;
}
int wolfSSL_ECDSA_size(const WOLFSSL_EC_KEY *key)
{
int err = 0;
int len = 0;
const WOLFSSL_EC_GROUP *group = NULL;
int bits = 0;
if (key == NULL) {
err = 1;
}
if ((!err) && ((group = wolfSSL_EC_KEY_get0_group(key)) == NULL)) {
err = 1;
}
if ((!err) && ((bits = wolfSSL_EC_GROUP_order_bits(group)) == 0)) {
err = 1;
}
if (!err) {
int bytes = (bits + 7) / 8;
len = SIG_HEADER_SZ +
ECC_MAX_PAD_SZ +
bytes + bytes;
}
return len;
}
WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_do_sign(const unsigned char *dgst, int dLen,
WOLFSSL_EC_KEY *key)
{
int err = 0;
WOLFSSL_ECDSA_SIG *sig = NULL;
WC_DECLARE_VAR(out, byte, ECC_BUFSIZE, 0);
unsigned int outLen = ECC_BUFSIZE;
WOLFSSL_ENTER("wolfSSL_ECDSA_do_sign");
if ((dgst == NULL) || (key == NULL) || (key->internal == NULL)) {
WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad arguments");
err = 1;
}
if ((!err) && (key->inSet == 0)) {
WOLFSSL_MSG("wolfSSL_ECDSA_do_sign No EC key internal set, do it");
if (SetECKeyInternal(key) != 1) {
WOLFSSL_MSG("wolfSSL_ECDSA_do_sign SetECKeyInternal failed");
err = 1;
}
}
#ifdef WOLFSSL_SMALL_STACK
if (!err) {
out = (byte*)XMALLOC(outLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (out == NULL) {
err = 1;
}
}
#endif
if ((!err) && (wolfSSL_ECDSA_sign(0, dgst, dLen, out, &outLen, key) != 1)) {
err = 1;
}
if (!err) {
const byte* p = out;
sig = wolfSSL_d2i_ECDSA_SIG(NULL, &p, outLen);
}
WC_FREE_VAR_EX(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return sig;
}
int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen,
const WOLFSSL_ECDSA_SIG *sig, WOLFSSL_EC_KEY *key)
{
int ret = 1;
int verified = 0;
#ifdef WOLF_CRYPTO_CB_ONLY_ECC
byte signature[ECC_MAX_SIG_SIZE];
int signatureLen;
byte* p = signature;
#endif
WOLFSSL_ENTER("wolfSSL_ECDSA_do_verify");
if ((dgst == NULL) || (sig == NULL) || (key == NULL) ||
(key->internal == NULL)) {
WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad arguments");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) &&
((dLen > WC_MAX_DIGEST_SIZE) ||
(dLen < WC_MIN_DIGEST_SIZE))) {
WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad digest size");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (key->inSet == 0)) {
WOLFSSL_MSG("No EC key internal set, do it");
if (SetECKeyInternal(key) != 1) {
WOLFSSL_MSG("SetECKeyInternal failed");
ret = WOLFSSL_FATAL_ERROR;
}
}
if (ret == 1) {
#ifndef WOLF_CRYPTO_CB_ONLY_ECC
if (wc_ecc_verify_hash_ex((mp_int*)sig->r->internal,
(mp_int*)sig->s->internal, dgst, (word32)dLen, &verified,
(ecc_key *)key->internal) != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_verify_hash failed");
ret = WOLFSSL_FATAL_ERROR;
}
else if (verified == 0) {
WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected");
ret = 0;
}
#else
signatureLen = i2d_ECDSA_SIG(sig, &p);
if (signatureLen > 0) {
ret = wc_ecc_verify_hash(signature, signatureLen, dgst,
(word32)dLen, &verified, (ecc_key*)key->internal);
if (ret != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_verify_hash failed");
ret = WOLFSSL_FATAL_ERROR;
}
else if (verified == 0) {
WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected");
ret = 0;
}
}
#endif
}
return ret;
}
int wolfSSL_ECDSA_sign(int type, const unsigned char *digest, int digestSz,
unsigned char *sig, unsigned int *sigSz, WOLFSSL_EC_KEY *key)
{
int ret = 1;
WC_RNG* rng = NULL;
WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
int initTmpRng = 0;
WOLFSSL_ENTER("wolfSSL_ECDSA_sign");
(void)type;
if (key == NULL) {
ret = 0;
}
if (ret == 1) {
rng = wolfssl_make_rng(tmpRng, &initTmpRng);
if (rng == NULL) {
ret = 0;
}
}
if ((ret == 1) && (wc_ecc_sign_hash(digest, (word32)digestSz, sig, sigSz,
rng, (ecc_key*)key->internal) != 0)) {
ret = 0;
}
if (initTmpRng) {
wc_FreeRng(rng);
WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG);
}
return ret;
}
int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz,
const unsigned char *sig, int sigSz, WOLFSSL_EC_KEY *key)
{
int ret = 1;
int verify = 0;
WOLFSSL_ENTER("wolfSSL_ECDSA_verify");
(void)type;
if (key == NULL) {
ret = 0;
}
if ((ret == 1) &&
((digestSz > WC_MAX_DIGEST_SIZE) ||
(digestSz < WC_MIN_DIGEST_SIZE))) {
WOLFSSL_MSG("wolfSSL_ECDSA_verify Bad digest size");
ret = 0;
}
if ((ret == 1) && (wc_ecc_verify_hash(sig, (word32)sigSz, digest,
(word32)digestSz, &verify, (ecc_key*)key->internal) != 0)) {
ret = 0;
}
if ((ret == 1) && (verify != 1)) {
WOLFSSL_MSG("wolfSSL_ECDSA_verify failed");
ret = 0;
}
return ret;
}
#ifndef WOLF_CRYPTO_CB_ONLY_ECC
int wolfSSL_ECDH_compute_key(void *out, size_t outLen,
const WOLFSSL_EC_POINT *pubKey, WOLFSSL_EC_KEY *privKey,
void *(*kdf) (const void *in, size_t inlen, void *out, size_t *outLen))
{
int err = 0;
word32 len = 0;
ecc_key* key = NULL;
#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0))
int setGlobalRNG = 0;
#endif
(void)kdf;
WOLFSSL_ENTER("wolfSSL_ECDH_compute_key");
if ((out == NULL) || (pubKey == NULL) || (pubKey->internal == NULL) ||
(privKey == NULL) || (privKey->internal == NULL)) {
WOLFSSL_MSG("Bad function arguments");
err = 1;
}
if ((!err) && (privKey->inSet == 0)) {
WOLFSSL_MSG("No EC key internal set, do it");
if (SetECKeyInternal(privKey) != 1) {
WOLFSSL_MSG("SetECKeyInternal failed");
err = 1;
}
}
if (!err) {
int ret;
key = (ecc_key*)privKey->internal;
len = (word32)outLen;
#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0))
if (key->rng == NULL) {
key->rng = wolfssl_make_global_rng();
setGlobalRNG = 1;
}
#endif
PRIVATE_KEY_UNLOCK();
ret = wc_ecc_shared_secret_ex(key, (ecc_point*)pubKey->internal,
(byte *)out, &len);
PRIVATE_KEY_LOCK();
if (ret != MP_OKAY) {
WOLFSSL_MSG("wc_ecc_shared_secret failed");
err = 1;
}
}
#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0))
if (setGlobalRNG) {
key->rng = NULL;
}
#endif
if (err) {
len = 0;
}
return (int)len;
}
#endif
#ifndef NO_WOLFSSL_STUB
const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_OpenSSL(void)
{
WOLFSSL_STUB("wolfSSL_EC_KEY_OpenSSL");
return NULL;
}
WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_METHOD_new(
const WOLFSSL_EC_KEY_METHOD *meth)
{
WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_new");
(void)meth;
return NULL;
}
void wolfSSL_EC_KEY_METHOD_free(WOLFSSL_EC_KEY_METHOD *meth)
{
WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_free");
(void)meth;
}
void wolfSSL_EC_KEY_METHOD_set_init(WOLFSSL_EC_KEY_METHOD *meth,
void* a1, void* a2, void* a3, void* a4, void* a5, void* a6)
{
WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_init");
(void)meth;
(void)a1;
(void)a2;
(void)a3;
(void)a4;
(void)a5;
(void)a6;
}
void wolfSSL_EC_KEY_METHOD_set_sign(WOLFSSL_EC_KEY_METHOD *meth,
void* a1, void* a2, void* a3)
{
WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_sign");
(void)meth;
(void)a1;
(void)a2;
(void)a3;
}
const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_get_method(
const WOLFSSL_EC_KEY *key)
{
WOLFSSL_STUB("wolfSSL_EC_KEY_get_method");
(void)key;
return NULL;
}
int wolfSSL_EC_KEY_set_method(WOLFSSL_EC_KEY *key,
const WOLFSSL_EC_KEY_METHOD *meth)
{
WOLFSSL_STUB("wolfSSL_EC_KEY_set_method");
(void)key;
(void)meth;
return 0;
}
#endif
#endif
#endif
#endif