diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c index 546f12882..88aad3eb2 100644 --- a/src/crypto/crypto_wolfssl.c +++ b/src/crypto/crypto_wolfssl.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -1835,6 +1836,263 @@ 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 */ + /* 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"); + crypto_ec_key_deinit(key); + key = NULL; + } +#endif /* CONFIG_FIPS */ + } + return key; +} + + +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 */ + os_free(key); + } +} + + +struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len) +{ + struct crypto_ec_key *ret; + word32 idx = 0; + + ret = crypto_ec_key_init(); + if (!ret) { + wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed"); + goto fail; + } + + if (wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len) != + 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPrivateKeyDecode failed"); + goto fail; + } + + return ret; +fail: + if (ret) + crypto_ec_key_deinit(ret); + return NULL; +} + + +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__); + return -1; + } + + switch (key->eckey->dp->id) { + case ECC_SECP256R1: + return 19; + case ECC_SECP384R1: + return 20; + case ECC_SECP521R1: + return 21; + case ECC_BRAINPOOLP256R1: + return 28; + case ECC_BRAINPOOLP384R1: + return 29; + case ECC_BRAINPOOLP512R1: + return 30; + } + + wpa_printf(MSG_ERROR, "wolfSSL: Unsupported curve (id=%d) in EC key", + key->eckey->dp->id); + return -1; +} + + +struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key) +{ + byte *der = NULL; + int der_len; + struct wpabuf *ret = NULL; + + if (!key || !key->eckey) { + wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters", + __func__); + goto fail; + } + + der_len = wc_EccPublicKeyDerSize(key->eckey, 1); + if (der_len <= 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDerSize failed"); + goto fail; + } + + der = os_malloc(der_len); + if (!der) + goto fail; + + der_len = wc_EccPublicKeyToDer(key->eckey, der, der_len, 1); + if (der_len <= 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyToDer failed"); + goto fail; + } + + ret = wpabuf_alloc_copy(der, der_len); + os_free(der); + return ret; + +fail: + os_free(der); + return NULL; +} + + +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; + + ret = crypto_ec_key_init(); + if (!ret) { + wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed"); + goto fail; + } + + if (wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len) != 0) + { + wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDecode failed"); + goto fail; + } + + return ret; +fail: + crypto_ec_key_deinit(ret); + return NULL; +} + + +struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, + size_t len) +{ + byte *der = NULL; + int der_len; + 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__); + 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 */ + } + + der_len = wc_ecc_sig_size(key->eckey); + if (der_len <= 0) { + wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sig_size failed"); + goto fail; + } + + der = os_malloc(der_len); + if (!der) + 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"); + goto fail; + } + + 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); + return NULL; +} + + +int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data, + size_t len, const u8 *sig, size_t sig_len) +{ + int res = 0; + + if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) { + wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters", + __func__); + 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"); + return -1; + } + + if (res != 1) + wpa_printf(MSG_DEBUG, + "wolfSSL: crypto_ec_key_verify_signature failed"); + + return res; +} + #endif /* CONFIG_ECC */