[PATCH 10/12] wolfssl: refactor crypto ECC section

Juliusz Sosinowicz juliusz at wolfssl.com
Wed Mar 8 09:18:48 PST 2023


- improve error checking
- improve logging
- use heap allocated objects
- prefer lib functions instead of member access when possible
- add more curves
- check if brainpool support built
- use appropriate functions or direct access when WOLFSSL_OLD_FIPS

Signed-off-by: Juliusz Sosinowicz <juliusz at wolfssl.com>
---
 src/crypto/crypto_wolfssl.c | 610 ++++++++++++++++++++++++------------
 1 file changed, 402 insertions(+), 208 deletions(-)

diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 14576a98d..cacee0c8a 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -37,6 +37,12 @@
 #endif
 #endif
 
+#ifdef CONFIG_FIPS
+#if !defined(HAVE_FIPS_VERSION) || HAVE_FIPS_VERSION <= 2
+#define WOLFSSL_OLD_FIPS
+#endif
+#endif
+
 #define LOG_WOLF_ERROR_VA(msg, ...) \
 	wpa_printf(MSG_ERROR, "wolfSSL: %s:%d " msg, __func__, __LINE__, __VA_ARGS__)
 
@@ -52,6 +58,40 @@
 #define LOG_INVALID_PARAMETERS() \
 	LOG_WOLF_ERROR("invalid input parameters")
 
+/* Helper functions to make type allocation uniform */
+
+static WC_RNG * wc_rng_init(void)
+{
+	WC_RNG * ret;
+	ret = wc_rng_new(NULL, 0, NULL);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_rng_new);
+	}
+	return ret;
+}
+
+static void wc_rng_deinit(WC_RNG * rng)
+{
+	wc_rng_free(rng);
+}
+
+static ecc_key * ecc_key_init(void)
+{
+	ecc_key * ret;
+	ret = wc_ecc_key_new(NULL);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_key_new);
+	}
+	return ret;
+}
+
+static void ecc_key_deinit(ecc_key * key)
+{
+	wc_ecc_key_free(key);
+}
+
+/* end of helper functions */
+
 #ifndef CONFIG_FIPS
 
 int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
@@ -655,7 +695,7 @@ struct crypto_cipher {
 };
 
 struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
+					  const u8 *iv, const u8 *pubkey,
 					  size_t key_len)
 {
 	struct crypto_cipher *ctx;
@@ -668,8 +708,8 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
 #ifndef CONFIG_NO_RC4
 #ifndef NO_RC4
 	case CRYPTO_CIPHER_ALG_RC4:
-		wc_Arc4SetKey(&ctx->enc.arc4, key, key_len);
-		wc_Arc4SetKey(&ctx->dec.arc4, key, key_len);
+		wc_Arc4SetKey(&ctx->enc.arc4, pubkey, key_len);
+		wc_Arc4SetKey(&ctx->dec.arc4, pubkey, key_len);
 		break;
 #endif /* NO_RC4 */
 #endif /* CONFIG_NO_RC4 */
@@ -684,9 +724,9 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
 			os_free(ctx);
 			return NULL;
 		}
-		if (wc_AesSetKey(&ctx->enc.aes, key, key_len, iv,
+		if (wc_AesSetKey(&ctx->enc.aes, pubkey, key_len, iv,
 				 AES_ENCRYPTION) ||
-		    wc_AesSetKey(&ctx->dec.aes, key, key_len, iv,
+		    wc_AesSetKey(&ctx->dec.aes, pubkey, key_len, iv,
 				 AES_DECRYPTION)) {
 			os_free(ctx);
 			return NULL;
@@ -696,8 +736,8 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
 #ifndef NO_DES3
 	case CRYPTO_CIPHER_ALG_3DES:
 		if (key_len != DES3_KEYLEN ||
-		    wc_Des3_SetKey(&ctx->enc.des3, key, iv, DES_ENCRYPTION) ||
-		    wc_Des3_SetKey(&ctx->dec.des3, key, iv, DES_DECRYPTION)) {
+		    wc_Des3_SetKey(&ctx->enc.des3, pubkey, iv, DES_ENCRYPTION) ||
+		    wc_Des3_SetKey(&ctx->dec.des3, pubkey, iv, DES_DECRYPTION)) {
 			os_free(ctx);
 			return NULL;
 		}
@@ -1060,7 +1100,7 @@ struct crypto_hash {
 };
 
 
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *pubkey,
 				      size_t key_len)
 {
 	struct crypto_hash *ret = NULL;
@@ -1097,7 +1137,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 	}
 
 	if (wc_HmacInit(&hash->hmac, NULL, INVALID_DEVID) != 0 ||
-	    wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+	    wc_HmacSetKey(&hash->hmac, type, pubkey, key_len) != 0)
 		goto done;
 
 	ret = hash;
@@ -1479,17 +1519,49 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
 
 #ifdef CONFIG_ECC
 
+static int crypto_ec_group_2_id(int group)
+{
+	switch (group) {
+	case 19:
+		return ECC_SECP256R1;
+	case 20:
+		return ECC_SECP384R1;
+	case 21:
+		return ECC_SECP521R1;
+	case 25:
+		return ECC_SECP192R1;
+	case 26:
+		return ECC_SECP224R1;
+#ifdef HAVE_ECC_BRAINPOOL
+	case 27:
+		return ECC_BRAINPOOLP224R1;
+	case 28:
+		return ECC_BRAINPOOLP256R1;
+	case 29:
+		return ECC_BRAINPOOLP384R1;
+	case 30:
+		return ECC_BRAINPOOLP512R1;
+#endif /* HAVE_ECC_BRAINPOOL */
+	default:
+		LOG_WOLF_ERROR_VA("Unsupported curve (id=%d) in EC key", group);
+		return ECC_CURVE_INVALID;
+	}
+}
+
+
 int ecc_map(ecc_point *, mp_int *, mp_digit);
 int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
 			     mp_int *a, mp_int *modulus, mp_digit mp);
 
 struct crypto_ec {
-	ecc_key key;
+	ecc_key* key;
 	mp_int a;
 	mp_int prime;
 	mp_int order;
-	mp_digit mont_b;
 	mp_int b;
+	mp_digit mont_b;
+	int curve_id;
+	byte ownKey:1; /* Should we free the `key` */
 };
 
 
@@ -1497,59 +1569,63 @@ struct crypto_ec * crypto_ec_init(int group)
 {
 	int built = 0;
 	struct crypto_ec *e;
-	int curve_id;
+	int curve_id = crypto_ec_group_2_id(group);
+	int err;
 
-	/* Map from IANA registry for IKE D-H groups to OpenSSL NID */
-	switch (group) {
-	case 19:
-		curve_id = ECC_SECP256R1;
-		break;
-	case 20:
-		curve_id = ECC_SECP384R1;
-		break;
-	case 21:
-		curve_id = ECC_SECP521R1;
-		break;
-	case 25:
-		curve_id = ECC_SECP192R1;
-		break;
-	case 26:
-		curve_id = ECC_SECP224R1;
-		break;
-#ifdef HAVE_ECC_BRAINPOOL
-	case 27:
-		curve_id = ECC_BRAINPOOLP224R1;
-		break;
-	case 28:
-		curve_id = ECC_BRAINPOOLP256R1;
-		break;
-	case 29:
-		curve_id = ECC_BRAINPOOLP384R1;
-		break;
-	case 30:
-		curve_id = ECC_BRAINPOOLP512R1;
-		break;
-#endif /* HAVE_ECC_BRAINPOOL */
-	default:
+	if (curve_id == ECC_CURVE_INVALID) {
+		LOG_INVALID_PARAMETERS();
 		return NULL;
 	}
 
 	e = os_zalloc(sizeof(*e));
-	if (!e)
+	if (!e) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_zalloc);
 		return NULL;
+	}
 
-	if (wc_ecc_init(&e->key) != 0 ||
-	    wc_ecc_set_curve(&e->key, 0, curve_id) != 0 ||
-	    mp_init(&e->a) != MP_OKAY ||
-	    mp_init(&e->prime) != MP_OKAY ||
-	    mp_init(&e->order) != MP_OKAY ||
-	    mp_init(&e->b) != MP_OKAY ||
-	    mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY ||
-	    mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY ||
-	    mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY ||
-	    mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY ||
-	    mp_montgomery_setup(&e->prime, &e->mont_b) != MP_OKAY)
+	e->curve_id = curve_id;
+	e->ownKey = 1;
+	e->key = ecc_key_init();
+	if (!e->key) {
+		LOG_WOLF_ERROR_FUNC_NULL(ecc_key_init);
 		goto done;
+	}
+
+	err = wc_ecc_set_curve(e->key, 0, curve_id);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_set_curve, err);
+		goto done;
+	}
+	err = mp_init_multi(&e->a, &e->prime, &e->order, &e->b, NULL, NULL);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_init_multi, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->a, e->key->dp->Af, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->b, e->key->dp->Bf, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->prime, e->key->dp->prime, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_read_radix(&e->order, e->key->dp->order, 16);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_read_radix, err);
+		goto done;
+	}
+	err = mp_montgomery_setup(&e->prime, &e->mont_b);
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(mp_montgomery_setup, err);
+		goto done;
+	}
 
 	built = 1;
 done:
@@ -1571,6 +1647,8 @@ void crypto_ec_deinit(struct crypto_ec* e)
 	mp_clear(&e->prime);
 	mp_clear(&e->a);
 	wc_ecc_free(&e->key);
+	if (e->ownKey)
+		ecc_key_deinit(e->key);
 	os_free(e);
 }
 
@@ -1585,6 +1663,20 @@ struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
 }
 
 
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+	ecc_point *point = (ecc_point *) p;
+
+	if (!p)
+		return;
+
+	if (clear) {
+		wc_ecc_forcezero_point(point);
+	}
+	wc_ecc_del_point(point);
+}
+
+
 size_t crypto_ec_prime_len(struct crypto_ec *e)
 {
 	return (mp_count_bits(&e->prime) + 7) / 8;
@@ -1627,22 +1719,6 @@ const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
 }
 
 
-void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
-{
-	ecc_point *point = (ecc_point *) p;
-
-	if (!p)
-		return;
-
-	if (clear) {
-		mp_forcezero(point->x);
-		mp_forcezero(point->y);
-		mp_forcezero(point->z);
-	}
-	wc_ecc_del_point(point);
-}
-
-
 int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
 		      struct crypto_bignum *x)
 {
@@ -1654,27 +1730,41 @@ int crypto_ec_point_to_bin(struct crypto_ec *e,
 			   const struct crypto_ec_point *point, u8 *x, u8 *y)
 {
 	ecc_point *p = (ecc_point *) point;
+	int len;
+	int err;
 
 	if (TEST_FAIL())
 		return -1;
 
 	if (!mp_isone(p->z)) {
-		if (ecc_map(p, &e->prime, e->mont_b) != MP_OKAY)
+		err = ecc_map(p, &e->prime, e->mont_b);
+		if (err != MP_OKAY) {
+			LOG_WOLF_ERROR_FUNC(ecc_map, err);
 			return -1;
+		}
+	}
+
+	len = wc_ecc_get_curve_size_from_id(e->curve_id);
+	if (len <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_get_curve_size_from_id, len);
+		LOG_WOLF_ERROR_VA("wc_ecc_get_curve_size_from_id error for curve_id %d", e->curve_id);
+		return -1;
 	}
 
 	if (x) {
 		if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x,
-					 e->key.dp->size,
-					 e->key.dp->size) <= 0)
+				(size_t)len, (size_t)len) <= 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_bignum_to_bin, -1);
 			return -1;
+		}
 	}
 
 	if (y) {
 		if (crypto_bignum_to_bin((struct crypto_bignum *) p->y, y,
-					 e->key.dp->size,
-					 e->key.dp->size) <= 0)
+				(size_t)len, (size_t)len) <= 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_bignum_to_bin, -1);
 			return -1;
+		}
 	}
 
 	return 0;
@@ -1694,10 +1784,10 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
 	if (!point)
 		goto done;
 
-	if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY)
+	if (mp_read_unsigned_bin(point->x, val, e->key->dp->size) != MP_OKAY)
 		goto done;
-	val += e->key.dp->size;
-	if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY)
+	val += e->key->dp->size;
+	if (mp_read_unsigned_bin(point->y, val, e->key->dp->size) != MP_OKAY)
 		goto done;
 	mp_set(point->z, 1);
 
@@ -1858,50 +1948,115 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
 
 struct crypto_ecdh {
 	struct crypto_ec *ec;
-	WC_RNG rng;
+	WC_RNG* rng;
 };
 
-struct crypto_ecdh * crypto_ecdh_init(int group)
-{
-	struct crypto_ecdh *ecdh = NULL;
-	int ret;
+struct crypto_ec_key {
+	ecc_key *eckey;
+	WC_RNG *rng; /* Needs to be initialized before use.
+	 	 	 	  * *NOT* initialized in crypto_ec_key_init */
+};
 
-	ecdh = os_zalloc(sizeof(*ecdh));
-	if (!ecdh)
-		goto fail;
+static struct crypto_ecdh * _crypto_ecdh_init(int group)
+{
+	struct crypto_ecdh *ret = NULL;
+	int err;
 
-	if (wc_InitRng(&ecdh->rng) != 0)
-		goto fail;
+	ret = os_zalloc(sizeof(struct crypto_ecdh));
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(os_zalloc);
+		return NULL;
+	}
 
-	ecdh->ec = crypto_ec_init(group);
-	if (!ecdh->ec)
+	ret->rng = wc_rng_init();
+	if (!ret->rng) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_rng_init);
 		goto fail;
+	}
 
-	ret = wc_ecc_make_key_ex(&ecdh->rng, ecdh->ec->key.dp->size,
-				 &ecdh->ec->key, ecdh->ec->key.dp->id);
-	if (ret < 0)
+	ret->ec = crypto_ec_init(group);
+	if (!ret->ec) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_init);
 		goto fail;
+	}
 
-#if defined(ECC_TIMING_RESISTANT) && !defined(CONFIG_FIPS)
-	ret = wc_ecc_set_rng(&ecdh->ec->key, &ecdh->rng);
-	if (ret < 0)
+#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS)
+	err = wc_ecc_set_rng(ret->ec->key, ret->rng);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_set_rng, err);
 		goto fail;
-#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */
+	}
+#else
+	(void)err;
+#endif /* ECC_TIMING_RESISTANT && !WOLFSSL_OLD_FIPS */
 
-done:
-	return ecdh;
+	return ret;
 fail:
-	crypto_ecdh_deinit(ecdh);
-	ecdh = NULL;
-	goto done;
+	crypto_ecdh_deinit(ret);
+	return NULL;
 }
 
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+	struct crypto_ecdh *ret = NULL;
+	int err;
+
+	ret = _crypto_ecdh_init(group);
+
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(_crypto_ecdh_init);
+		return NULL;
+	}
+
+	err = wc_ecc_make_key_ex(ret->rng, 0, ret->ec->key,
+			crypto_ec_group_2_id(group));
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_make_key_ex, err);
+		crypto_ecdh_deinit(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key)
+{
+	struct crypto_ecdh *ret = NULL;
+
+	if (!own_key || crypto_ec_key_group(own_key) != group) {
+		LOG_INVALID_PARAMETERS();
+		return NULL;
+	}
+
+	ret = _crypto_ecdh_init(group);
+	if (ret) {
+		/* Already init'ed to the right group. Enough to substitute the key. */
+		ecc_key_deinit(ret->ec->key);
+		ret->ec->key = own_key->eckey;
+		ret->ec->ownKey = 0;
+#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS)
+		if (!ret->ec->key->rng) {
+			int err = wc_ecc_set_rng(ret->ec->key, ret->rng);
+			if (err != 0) {
+				LOG_WOLF_ERROR_FUNC(wc_ecc_set_rng, err);
+			}
+		}
+#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */
+	}
+
+	return ret;
+}
 
 void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
 {
 	if (ecdh) {
+#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS)
+		/* Disassociate the rng */
+		if (ecdh->ec->key->rng == ecdh->rng)
+			(void)wc_ecc_set_rng(ecdh->ec->key, NULL);
+#endif
 		crypto_ec_deinit(ecdh->ec);
-		wc_FreeRng(&ecdh->rng);
+		wc_rng_deinit(ecdh->rng);
 		os_free(ecdh);
 	}
 }
@@ -1911,20 +2066,20 @@ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
 {
 	struct wpabuf *buf = NULL;
 	int ret;
-	int len = ecdh->ec->key.dp->size;
+	int len = ecdh->ec->key->dp->size;
 
 	buf = wpabuf_alloc(inc_y ? 2 * len : len);
 	if (!buf)
 		goto fail;
 
 	ret = crypto_bignum_to_bin((struct crypto_bignum *)
-				   ecdh->ec->key.pubkey.x, wpabuf_put(buf, len),
+				   ecdh->ec->key->pubkey.x, wpabuf_put(buf, len),
 				   len, len);
 	if (ret < 0)
 		goto fail;
 	if (inc_y) {
 		ret = crypto_bignum_to_bin((struct crypto_bignum *)
-					   ecdh->ec->key.pubkey.y,
+					   ecdh->ec->key->pubkey.y,
 					   wpabuf_put(buf, len), len, len);
 		if (ret < 0)
 			goto fail;
@@ -1945,35 +2100,47 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
 	int ret;
 	struct wpabuf *pubkey = NULL;
 	struct wpabuf *secret = NULL;
-	word32 key_len = ecdh->ec->key.dp->size;
+	word32 key_len = ecdh->ec->key->dp->size;
 	ecc_point *point = NULL;
 	size_t need_key_len = inc_y ? 2 * key_len : key_len;
 
-	if (len < need_key_len)
+	if (len < need_key_len) {
+		LOG_WOLF_ERROR("key len too small");
 		goto fail;
+	}
 	pubkey = wpabuf_alloc(1 + 2 * key_len);
-	if (!pubkey)
+	if (!pubkey) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		goto fail;
+	}
 	wpabuf_put_u8(pubkey, inc_y ? ECC_POINT_UNCOMP : ECC_POINT_COMP_EVEN);
 	wpabuf_put_data(pubkey, key, need_key_len);
 
 	point = wc_ecc_new_point();
-	if (!point)
+	if (!point) {
+		LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_new_point);
 		goto fail;
+	}
 
 	ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len,
-				      ecdh->ec->key.idx, point);
-	if (ret != MP_OKAY)
+				      ecdh->ec->key->idx, point);
+	if (ret != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_import_point_der, ret);
 		goto fail;
+	}
 
 	secret = wpabuf_alloc(key_len);
-	if (!secret)
+	if (!secret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		goto fail;
+	}
 
-	ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
+	ret = wc_ecc_shared_secret_ex(ecdh->ec->key, point,
 				      wpabuf_put(secret, key_len), &key_len);
-	if (ret != MP_OKAY)
+	if (ret != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_shared_secret_ex, ret);
 		goto fail;
+	}
 
 done:
 	wc_ecc_del_point(point);
@@ -1991,41 +2158,21 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
 	return crypto_ec_prime_len(ecdh->ec);
 }
 
-
-struct crypto_ec_key {
-	ecc_key *eckey;
-	WC_RNG *rng; /* Needs to be initialized before use.
-		      * *NOT* initialized in crypto_ec_key_init */
-};
-
-
 static struct crypto_ec_key * crypto_ec_key_init(void)
 {
 	struct crypto_ec_key *key;
 
 	key = os_zalloc(sizeof(struct crypto_ec_key));
 	if (key) {
-#ifdef CONFIG_FIPS
-		key->eckey = os_zalloc(sizeof(ecc_key));
-#else /* CONFIG_FIPS */
-		key->eckey = wc_ecc_key_new(NULL);
-#endif /* CONFIG_FIPS */
+		key->eckey = ecc_key_init();
 		/* Omit key->rng initialization because it seeds itself and thus
 		 * consumes entropy that may never be used. Lazy initialize when
 		 * necessary. */
 		if (!key->eckey) {
-			wpa_printf(MSG_ERROR,
-				   "wolfSSL: crypto_ec_key_init() failed");
-			crypto_ec_key_deinit(key);
-			key = NULL;
-		}
-#ifdef CONFIG_FIPS
-		else if (wc_ecc_init_ex(key->eckey, NULL, INVALID_DEVID) != 0) {
-			wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_init_ex failed");
+			LOG_WOLF_ERROR_FUNC_NULL(ecc_key_init);
 			crypto_ec_key_deinit(key);
 			key = NULL;
 		}
-#endif /* CONFIG_FIPS */
 	}
 	return key;
 }
@@ -2034,32 +2181,39 @@ static struct crypto_ec_key * crypto_ec_key_init(void)
 void crypto_ec_key_deinit(struct crypto_ec_key *key)
 {
 	if (key) {
-#ifdef CONFIG_FIPS
-		os_free(key->rng);
-		os_free(key->eckey);
-#else /* CONFIG_FIPS */
-		wc_rng_free(key->rng);
-		wc_ecc_key_free(key->eckey);
-#endif /* CONFIG_FIPS */
+		ecc_key_deinit(key->eckey);
+		wc_rng_deinit(key->rng);
 		os_free(key);
 	}
 }
 
+WC_RNG * crypto_ec_key_init_rng(struct crypto_ec_key *key)
+{
+	if (!key->rng) {
+		/* Lazy init key->rng */
+		key->rng = wc_rng_init();
+		if (!key->rng) {
+			LOG_WOLF_ERROR_FUNC_NULL(wc_rng_init);
+		}
+	}
+	return key->rng;
+}
 
 struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
 {
 	struct crypto_ec_key *ret;
 	word32 idx = 0;
+	int err;
 
 	ret = crypto_ec_key_init();
 	if (!ret) {
-		wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init);
 		goto fail;
 	}
 
-	if (wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len) !=
-	    0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPrivateKeyDecode failed");
+	err = wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPrivateKeyDecode, err);
 		goto fail;
 	}
 
@@ -2075,8 +2229,7 @@ int crypto_ec_key_group(struct crypto_ec_key *key)
 {
 
 	if (!key || !key->eckey || !key->eckey->dp) {
-		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
-			   __func__);
+		LOG_INVALID_PARAMETERS();
 		return -1;
 	}
 
@@ -2087,54 +2240,110 @@ int crypto_ec_key_group(struct crypto_ec_key *key)
 		return 20;
 	case ECC_SECP521R1:
 		return 21;
+	case ECC_SECP192R1:
+		return 25;
+	case ECC_SECP224R1:
+		return 26;
+#ifdef HAVE_ECC_BRAINPOOL
+	case ECC_BRAINPOOLP224R1:
+		return 27;
 	case ECC_BRAINPOOLP256R1:
 		return 28;
 	case ECC_BRAINPOOLP384R1:
 		return 29;
 	case ECC_BRAINPOOLP512R1:
 		return 30;
+#endif /* HAVE_ECC_BRAINPOOL */
 	}
 
-	wpa_printf(MSG_ERROR, "wolfSSL: Unsupported curve (id=%d) in EC key",
+	LOG_WOLF_ERROR_VA("Unsupported curve (id=%d) in EC key",
 		   key->eckey->dp->id);
 	return -1;
 }
 
+static int crypto_ec_key_gen_public_key(struct crypto_ec_key *key)
+{
+	int err;
+
+#ifndef WOLFSSL_OLD_FIPS
+	/* Have wolfSSL generate the public key to make it available for output */
+	if (!crypto_ec_key_init_rng(key)) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng);
+		return -1;
+	}
+#endif
+
+#ifndef WOLFSSL_OLD_FIPS
+	err = wc_ecc_make_pub_ex(key->eckey, NULL, key->rng);
+#else
+	err = wc_ecc_make_pub(key->eckey, NULL);
+#endif
+	if (err != MP_OKAY) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_make_pub_ex, err);
+		return -1;
+	}
+	return 0;
+}
 
 struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
 {
-	byte *der = NULL;
 	int der_len;
 	struct wpabuf *ret = NULL;
+	int err;
 
 	if (!key || !key->eckey) {
-		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
-			   __func__);
+		LOG_INVALID_PARAMETERS();
 		goto fail;
 	}
 
-	der_len = wc_EccPublicKeyDerSize(key->eckey, 1);
-	if (der_len <= 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDerSize failed");
+#ifdef WOLFSSL_OLD_FIPS
+	if (key->eckey->type == ECC_PRIVATEKEY_ONLY) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			goto fail;
+		}
+	}
+#endif
+
+	der_len = err = wc_EccPublicKeyToDer_ex(key->eckey, NULL, 0, 1, 1);
+	if (err == ECC_PRIVATEONLY_E) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			goto fail;
+		}
+		der_len = err = wc_EccPublicKeyToDer_ex(key->eckey, NULL, 0, 1, 1);
+	}
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyDerSize, err);
 		goto fail;
 	}
 
-	der = os_malloc(der_len);
-	if (!der)
+	ret = wpabuf_alloc(der_len);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		goto fail;
+	}
 
-	der_len = wc_EccPublicKeyToDer(key->eckey, der, der_len, 1);
-	if (der_len <= 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyToDer failed");
+	err = wc_EccPublicKeyToDer_ex(key->eckey, wpabuf_mhead(ret), der_len, 1, 1);
+	if (err == ECC_PRIVATEONLY_E) {
+		if (crypto_ec_key_gen_public_key(key) != 0) {
+			LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1);
+			goto fail;
+		}
+		err = wc_EccPublicKeyToDer_ex(key->eckey, wpabuf_mhead(ret), der_len, 1, 1);
+	}
+	if (err <= 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyToDer, err);
 		goto fail;
 	}
+	der_len = err;
+	wpabuf_put(ret, der_len);
 
-	ret = wpabuf_alloc_copy(der, der_len);
-	os_free(der);
 	return ret;
 
 fail:
-	os_free(der);
+	if (ret)
+		wpabuf_free(ret);
 	return NULL;
 }
 
@@ -2143,16 +2352,17 @@ struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
 {
 	word32 idx = 0;
 	struct crypto_ec_key *ret = NULL;
+	int err;
 
 	ret = crypto_ec_key_init();
 	if (!ret) {
-		wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init);
 		goto fail;
 	}
 
-	if (wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len) != 0)
-	{
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDecode failed");
+	err = wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyDecode, err);
 		goto fail;
 	}
 
@@ -2166,60 +2376,46 @@ fail:
 struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
 				   size_t len)
 {
-	byte *der = NULL;
 	int der_len;
+	int err;
 	word32 w32_der_len;
 	struct wpabuf *ret = NULL;
 
 	if (!key || !key->eckey || !data || len == 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
-			   __func__);
+		LOG_INVALID_PARAMETERS();
 		goto fail;
 	}
 
-	if (!key->rng) {
-		/* Lazy init key->rng */
-#ifdef CONFIG_FIPS
-		key->rng = os_zalloc(sizeof(WC_RNG));
-#else /* CONFIG_FIPS */
-		key->rng = wc_rng_new(NULL, 0, NULL);
-#endif /* CONFIG_FIPS */
-		if (!key->rng) {
-			wpa_printf(MSG_ERROR, "wolfSSL: wc_rng_new failed");
-			goto fail;
-		}
-#ifdef CONFIG_FIPS
-		if (wc_InitRng(key->rng) != 0) {
-			wpa_printf(MSG_ERROR, "wolfSSL: wc_InitRng failed");
-			goto fail;
-		}
-#endif /* CONFIG_FIPS */
+	if (!crypto_ec_key_init_rng(key)) {
+		LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng);
+		goto fail;
 	}
 
 	der_len = wc_ecc_sig_size(key->eckey);
 	if (der_len <= 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sig_size failed");
+		LOG_WOLF_ERROR_FUNC(wc_ecc_sig_size, der_len);
 		goto fail;
 	}
 
-	der = os_malloc(der_len);
-	if (!der)
+	ret = wpabuf_alloc(der_len);
+	if (!ret) {
+		LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
 		goto fail;
+	}
 
-	w32_der_len = (word32) der_len;
-	if (wc_ecc_sign_hash(data, len, der, &w32_der_len, key->rng, key->eckey)
-	    != 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sign_hash failed");
+	w32_der_len = (word32)der_len;
+	err = wc_ecc_sign_hash(data, len, wpabuf_mhead(ret), &w32_der_len,
+			key->rng, key->eckey);
+	if (err != 0) {
+		LOG_WOLF_ERROR_FUNC(wc_ecc_sign_hash, err);
 		goto fail;
 	}
+	wpabuf_put(ret, w32_der_len);
 
-	ret = wpabuf_alloc_copy(der, der_len);
-	os_free(der);
-	if (!ret)
-		wpa_printf(MSG_ERROR, "wolfSSL: wpabuf_alloc_copy failed");
 	return ret;
 fail:
-	os_free(der);
+	if (ret)
+		wpabuf_free(ret);
 	return NULL;
 }
 
@@ -2230,20 +2426,18 @@ int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
 	int res = 0;
 
 	if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) {
-		wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
-			   __func__);
+		LOG_INVALID_PARAMETERS();
 		return -1;
 	}
 
 	if (wc_ecc_verify_hash(sig, sig_len, data, len, &res, key->eckey) != 0)
 	{
-		wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_verify_hash failed");
+		LOG_WOLF_ERROR("wc_ecc_verify_hash failed");
 		return -1;
 	}
 
 	if (res != 1)
-		wpa_printf(MSG_DEBUG,
-			   "wolfSSL: crypto_ec_key_verify_signature failed");
+		LOG_WOLF_ERROR("crypto_ec_key_verify_signature failed");
 
 	return res;
 }
-- 
2.25.1




More information about the Hostap mailing list