diff mbox series

Proposed Patch: Support for wolfSSL

Message ID 35F71B52-8428-4A0E-B14C-20CFF8CBCA65@wolfssl.com
State Accepted
Headers show
Series Proposed Patch: Support for wolfSSL | expand

Commit Message

Sean Parkinson Jan. 18, 2018, 2:26 a.m. UTC
I’ve prepared a new patch with the changes as asked for by Jouni.

This patch was written to allow hostap to be compiled with the wolfSSL cryptography and TLS library.

Thanks,
Sean :-)
—
Sean Parkinson
sean@wolfssl.com
wolfSSL Inc

From b80083836a5896e01eeee2ad108ca3d45de2f919 Mon Sep 17 00:00:00 2001
From: Sean Parkinson <sean@wolfssl.com>
Date: Wed, 17 Jan 2018 16:42:14 +1000
Subject: [PATCH] Add support for wolfSSL cryptographic library

Signed-off-by: Sean Parkinson <sean@wolfssl.com>
---
 hostapd/Makefile                          |   48 +-
 src/crypto/crypto_wolfssl.c               | 1607 ++++++++++++++++++++++
 src/crypto/fips_prf_wolfssl.c             |   85 ++
 src/crypto/tls_wolfssl.c                  | 2057 +++++++++++++++++++++++++++++
 tests/hwsim/example-hostapd.config        |    5 +
 tests/hwsim/example-wpa_supplicant.config |    4 +
 tests/hwsim/test_ap_eap.py                |   50 +-
 wpa_supplicant/Makefile                   |   53 +
 8 files changed, 3896 insertions(+), 13 deletions(-)
 create mode 100644 src/crypto/crypto_wolfssl.c
 create mode 100644 src/crypto/fips_prf_wolfssl.c
 create mode 100644 src/crypto/tls_wolfssl.c

Comments

Jouni Malinen March 3, 2018, 7:19 p.m. UTC | #1
On Thu, Jan 18, 2018 at 12:26:39PM +1000, Sean Parkinson wrote:
> I’ve prepared a new patch with the changes as asked for by Jouni.
> 
> This patch was written to allow hostap to be compiled with the wolfSSL cryptography and TLS library.

Thanks! I'm seeing number of errors in the hwsim test cases, but it
looks like it is easiest to move ahead with this if I push in the
cleaned up version that I've been testing with some fixes to avoid
breaking non-wolfSSL builds. I'd welcome any incremental changes on top
of the current hostap.git master branch snapshot to address things that
I list below or maybe a recommendation on how to configure the wolfSSL
build properly to avoid the issues. I ran my tests with wolfSSL 3.13.0
and ended up adding various configure options until the build went
through cleanly. This ended up with following options:

./configure --prefix=/home/jm/wolfssl/3.13.0 --enable-des3 --enable-md4 --enable-harden --enable-pwdbased --enable-tlsv10 --enable-oldtls --enable-cmac --enable-aeskeywrap --enable-keygen --enable-crl --enable-ocsp --enable-ocspstapling --enable-ocspstapling2 --enable-pkcallbacks --enable-tls13 --enable-fortress --enable-wpas --enable-static=yes --enable-shared=no


These are the notes from my hwsim test runs:

SAE:
- SAE: Could not solve y
- SAE: Could not pick PWE
--> check crypto_ec_point_solve_y_coord() implementation
   (wc_ecc_import_point_der() returns -1)
sae
sae_anti_clogging
sae_anti_clogging_proto
sae_bignum_failure
sae_forced_anti_clogging
sae_group_nego
sae_groups
sae_invalid_anti_clogging_token_req
sae_key_lifetime_in_memory
sae_mixed
sae_mixed_mfp
sae_no_random
sae_oom_wpas
sae_password
sae_password_ecc
sae_password_long
sae_password_short
sae_pmksa_caching
sae_pmksa_caching_disabled
sae_proto_confirm_replay
sae_proto_ecc
sae_pwe_failure
ap_ft_sae
ap_ft_sae_over_ds
sigma_dut_ap_psk_sae
sigma_dut_ap_sae
sigma_dut_ap_sae_group
sigma_dut_ap_sae_password
sigma_dut_sae
sigma_dut_sae_password
wpas_mesh_password_mismatch
mesh_forwarding_secure
ap_mixed_security


TLS interop(?) issue with OpenSSL server:
- OpenSSL server:
  * SSL: SSL3 alert: write (local SSL3 detected an error):fatal:bad record mac
  * SSL: SSL_accept:error in SSLv3 read finished A
  * OpenSSL: openssl_handshake - SSL_connect error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac
ap_hs20_remediation_sql
eap_tls_no_session_resumption_radius
authsrv_testing_options
ap_wpa2_eap_tls_versions


OpenSSL authentication server:
- OpenSSL: openssl_handshake - SSL_connect error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher
ap_wpa2_eap_ttls_dh_params
ap_wpa2_eap_ttls_dh_params_blob
ap_wpa2_eap_ttls_dh_params_dsa


OpenSSL authentication server:
- TLS: Certificate verification failed, error 20 (unable to get local issuer certificate) depth 0 for '/C=FI/O=w1.fi/CN=user.w1.fi'
- SSL: SSL3 alert: write (local SSL3 detected an error):fatal:unknown CA
- OpenSSL: openssl_handshake - SSL_connect error:14089086:SSL routines:ssl3_get_client_certificate:certificate verify failed
ap_wpa2_eap_tls_intermediate_ca
ap_wpa2_eap_tls_intermediate_ca_ocsp_sha1
ap_wpa2_eap_tls_intermediate_ca_ocsp
ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked
ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked_sha1


TLS: tls_verify_cb - preverify_ok=1 err=0 (unknown error number) ca_cert_verify=1 depth=0 buf='/C=FI/O=w1.fi/CN=server.w1.fi'
TLS: altSubjectName match 'EMAIL:noone@example.com;DNS:server.w1.fi;URI:http://example.com/' not found
wlan0: CTRL-EVENT-EAP-TLS-CERT-ERROR reason=6 depth=0 subject='/C=FI/O=w1.fi/CN=server.w1.fi' err='AltSubject mismatch'
ap_wpa2_eap_ttls_pap_subject_match


TLS: tls_verify_cb - preverify_ok=1 err=0 (unknown error number) ca_cert_verify=1 depth=0 buf='/C=FI/O=w1.fi/CN=server.w1.fi'
TLS: altSubjectName match 'EMAIL:noone@example.com;URI:http://example.com/;DNS:server.w1.fi' not found
wlan0: CTRL-EVENT-EAP-TLS-CERT-ERROR reason=6 depth=0 subject='/C=FI/O=w1.fi/CN=server.w1.fi' err='AltSubject mismatch'
ap_wpa2_eap_ttls_chap_altsubject_match


TLS: Certificate verification failed, error -407 (Invalid OCSP Status Error) depth 2 for '/C=FI/O=w1.fi/CN=server.w1.fi'
ap_wpa2_eap_ttls_ocsp_revoked
ap_wpa2_eap_ttls_ocsp_unknown
ap_wpa2_eap_ttls_optional_ocsp_unknown


Missing altsubject in D-Bus output?!
dbus_connect_eap


DH: crypto_dh_derive_secret failed
eap_proto_ikev2


TLS: Certificate verification failed, error -238 (ASN CA path length larger than signer error) depth 2 for '/C=FI/O=w1.fi/CN=sha384.server.w1.fi'
eap_tls_sha384
eap_tls_sha512



GET_FAIL/GET_ALLOC_FAIL failure did not trigger:
radius_mppe_failure
authsrv_oom
Sean Parkinson March 29, 2018, 4:55 a.m. UTC | #2
Jouni,

(Excuse the previous email. This one in plaintext.)

I’ve looked into the failures and made changes as needed.
There were changes to wolfSSL as well.

To reproduce the setup I tested:
 - download wolfSSL latest from master (https://github.com/wolfssl/wolfssl)
 - configure wolfSSL with option -enable-wpas
 - build wolfSSL
 - in wpa_supplicant change .config
   - CONFIG_TLS=wolfssl
   - disable CONFIG_DPP

The proposed new patch is below.

Thanks,
Sean
—
Sean Parkinson
sean@wolfssl.com
wolfSSL Inc


From 80ba12c7fecdd650d7528211e68e6fd7ededd736 Mon Sep 17 00:00:00 2001
From: Sean Parkinson <sparki@wolfssl.com>
Date: Mon, 19 Mar 2018 13:19:08 +1000
Subject: [PATCH] Fixes for wolfSSL integration.

Use new digest namespace.
Changes for memory allocation failure testing.
Use same certificates as used for GnuTLS in tests.
Implement tls_connection_get_eap_fast_key using cryptographic primitives
as wolfSSL implements different spec.
Use a valid key exchange value in test.
Fix loading of client certificate to use 'chain' APIs.

Signed-off-by: Sean Parkinson <sean@wolfssl.com>
---
 hostapd/Makefile              |   2 +
 src/crypto/crypto_wolfssl.c   | 192 +++++++++++++++++++++++++++++++++---------
 src/crypto/fips_prf_wolfssl.c |   3 +-
 src/crypto/tls_wolfssl.c      | 109 ++++++++++++++----------
 tests/hwsim/test_ap_eap.py    |  10 +--
 tests/hwsim/test_eap_proto.py |   2 +-
 wpa_supplicant/Makefile       |   1 +
 7 files changed, 228 insertions(+), 91 deletions(-)

diff --git a/hostapd/Makefile b/hostapd/Makefile
index 98ce115..9f8c6cf 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -899,9 +899,11 @@ AESOBJS += ../src/crypto/aes-encblock.o
 endif
 ifdef NEED_AES_OMAC1
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-omac1.o
 endif
 endif
+endif
 ifdef NEED_AES_UNWRAP
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 90163c4..7e68716 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -11,18 +11,8 @@
 #include "common.h"
 #include "crypto.h"
 
-#define WOLFSSL_AES_DIRECT
-#define HAVE_AESGCM
-#define HAVE_AES_KEYWRAP
-#define WOLFSSL_SHA384
-#define WOLFSSL_SHA512
-#define WOLFSSL_CMAC
-#define HAVE_ECC
-#define USE_FAST_MATH
-#define WOLFSSL_KEY_GEN
-
-#include <wolfssl/options.h>
 /* wolfSSL headers */
+#include <wolfssl/options.h>
 #include <wolfssl/wolfcrypt/md4.h>
 #include <wolfssl/wolfcrypt/md5.h>
 #include <wolfssl/wolfcrypt/sha.h>
@@ -62,7 +52,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 
 int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
-	Md5 md5;
+	wc_Md5 md5;
 	size_t i;
 
 	if (TEST_FAIL())
@@ -83,7 +73,7 @@ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 
 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
-	Sha sha;
+	wc_Sha sha;
 	size_t i;
 
 	if (TEST_FAIL())
@@ -104,7 +94,7 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 		  u8 *mac)
 {
-	Sha256 sha256;
+	wc_Sha256 sha256;
 	size_t i;
 
 	if (TEST_FAIL())
@@ -126,7 +116,7 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 		  u8 *mac)
 {
-	Sha384 sha384;
+	wc_Sha384 sha384;
 	size_t i;
 
 	if (TEST_FAIL())
@@ -148,7 +138,7 @@ int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 		  u8 *mac)
 {
-	Sha512 sha512;
+	wc_Sha512 sha512;
 	size_t i;
 
 	if (TEST_FAIL())
@@ -186,6 +176,7 @@ static int wolfssl_hmac_vector(int type, const u8 *key,
 			return -1;
 	if (wc_HmacFinal(&hmac, mac) != 0)
 		return -1;
+
 	return 0;
 }
 
@@ -195,7 +186,7 @@ static int wolfssl_hmac_vector(int type, const u8 *key,
 int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
 		    const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return wolfssl_hmac_vector(MD5, key, key_len, num_elem, addr, len, mac,
+	return wolfssl_hmac_vector(WC_MD5, key, key_len, num_elem, addr, len, mac,
 				   16);
 }
 
@@ -212,7 +203,7 @@ int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
 int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
 		     const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return wolfssl_hmac_vector(SHA, key, key_len, num_elem, addr, len, mac,
+	return wolfssl_hmac_vector(WC_SHA, key, key_len, num_elem, addr, len, mac,
 				   20);
 }
 
@@ -229,7 +220,7 @@ int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
 int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
 		       const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return wolfssl_hmac_vector(SHA256, key, key_len, num_elem, addr, len,
+	return wolfssl_hmac_vector(WC_SHA256, key, key_len, num_elem, addr, len,
 				   mac, 32);
 }
 
@@ -248,7 +239,7 @@ int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
 int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
 		       const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return wolfssl_hmac_vector(SHA384, key, key_len, num_elem, addr, len,
+	return wolfssl_hmac_vector(WC_SHA384, key, key_len, num_elem, addr, len,
 				   mac, 48);
 }
 
@@ -267,7 +258,7 @@ int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
 int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
 		       const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return wolfssl_hmac_vector(SHA512, key, key_len, num_elem, addr, len,
+	return wolfssl_hmac_vector(WC_SHA512, key, key_len, num_elem, addr, len,
 				   mac, 64);
 }
 
@@ -285,7 +276,7 @@ int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
 		int iterations, u8 *buf, size_t buflen)
 {
 	if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
-		      ssid_len, iterations, buflen, SHA) != 0)
+		      ssid_len, iterations, buflen, WC_SHA) != 0)
 		return -1;
 	return 0;
 }
@@ -423,6 +414,9 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
 {
 	int ret;
 
+	if (TEST_FAIL())
+		return -1;
+
 	ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
 			    NULL);
 	return ret != (n + 1) * 8 ? -1 : 0;
@@ -434,6 +428,9 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
 {
 	int ret;
 
+	if (TEST_FAIL())
+		return -1;
+
 	ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
 			      NULL);
 	return ret != n * 8 ? -1 : 0;
@@ -654,13 +651,13 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 	wpabuf_free(*publ);
 	*publ = NULL;
 
-	dh = os_malloc(sizeof(DhKey));
+	dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
 	if (!dh)
 		return NULL;
 	wc_InitDhKey(dh);
 
 	if (wc_InitRng(&rng) != 0) {
-		os_free(dh);
+		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 		return NULL;
 	}
 
@@ -692,7 +689,7 @@ done:
 	wpabuf_clear_free(privkey);
 	if (dh) {
 		wc_FreeDhKey(dh);
-		os_free(dh);
+		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 	}
 	wc_FreeRng(&rng);
 	return ret;
@@ -706,12 +703,12 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
 	byte *secret;
 	word32 secret_sz;
 
-	dh = os_malloc(sizeof(DhKey));
+	dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
 	if (!dh)
 		return NULL;
 	wc_InitDhKey(dh);
 
-	secret = os_malloc(RFC3526_LEN);
+	secret = XMALLOC(RFC3526_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 	if (!secret)
 		goto done;
 
@@ -734,9 +731,9 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
 done:
 	if (dh) {
 		wc_FreeDhKey(dh);
-		os_free(dh);
+		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 	}
-	os_free(secret);
+	XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 	return ret;
 }
 
@@ -773,7 +770,7 @@ void dh5_free(void *ctx)
 		return;
 
 	wc_FreeDhKey(ctx);
-	os_free(ctx);
+	XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
 }
 
 #endif /* CONFIG_WPS_NFC */
@@ -787,9 +784,6 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
 	DhKey *dh = NULL;
 	word32 priv_sz, pub_sz;
 
-	if (TEST_FAIL())
-		return -1;
-
 	dh = os_malloc(sizeof(DhKey));
 	if (!dh)
 		return -1;
@@ -889,7 +883,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 	struct crypto_hash *hash;
 	int type;
 
-	hash = os_malloc(sizeof(*hash));
+	hash = os_zalloc(sizeof(*hash));
 	if (!hash)
 		goto done;
 
@@ -897,19 +891,19 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 #ifndef NO_MD5
 	case CRYPTO_HASH_ALG_HMAC_MD5:
 		hash->size = 16;
-		type = MD5;
+		type = WC_MD5;
 		break;
 #endif /* NO_MD5 */
 #ifndef NO_SHA
 	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		type = SHA;
+		type = WC_SHA;
 		hash->size = 20;
 		break;
 #endif /* NO_SHA */
 #ifdef CONFIG_SHA256
 #ifndef NO_SHA256
 	case CRYPTO_HASH_ALG_HMAC_SHA256:
-		type = SHA256;
+		type = WC_SHA256;
 		hash->size = 32;
 		break;
 #endif /* NO_SHA256 */
@@ -1597,7 +1591,7 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
 	ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len);
 	if (ret <= 0)
 		return -1;
-	ret = wc_ecc_import_point_der(buf, ret + 1, e->key.idx,
+	ret = wc_ecc_import_point_der(buf, ret * 2 + 1, e->key.idx,
 				      (ecc_point *) p);
 	if (ret != 0)
 		return -1;
@@ -1625,7 +1619,7 @@ crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
 		goto done;
 
 	if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
-	    mp_mulmod((mp_int *) x, &t, &e->prime, y2) != 0 ||
+	    mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
 	    mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
 	    mp_addmod(y2, &t, &e->prime, y2) != 0 ||
 	    mp_addmod(y2, &e->b, &e->prime, y2) != 0)
@@ -1667,4 +1661,124 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
 	return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b);
 }
 
+struct crypto_ecdh {
+	struct crypto_ec *ec;
+};
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+	struct crypto_ecdh *ecdh = NULL;
+	WC_RNG rng;
+	int ret;
+
+	if (wc_InitRng(&rng) != 0)
+		goto fail;
+
+	ecdh = os_zalloc(sizeof(*ecdh));
+	if (!ecdh)
+		goto fail;
+
+	ecdh->ec = crypto_ec_init(group);
+	if (!ecdh->ec)
+		goto fail;
+
+	ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
+				 ecdh->ec->key.dp->id);
+	if (ret < 0)
+		goto fail;
+
+done:
+	wc_FreeRng(&rng);
+
+	return ecdh;
+fail:
+	crypto_ecdh_deinit(ecdh);
+	ecdh = NULL;
+	goto done;
+}
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+	if (ecdh) {
+		crypto_ec_deinit(ecdh->ec);
+		os_free(ecdh);
+	}
+}
+
+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;
+
+	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),
+				   len, len);
+	if (ret < 0)
+		goto fail;
+	if (inc_y) {
+		ret = crypto_bignum_to_bin((struct crypto_bignum *)
+					   ecdh->ec->key.pubkey.y,
+					   wpabuf_put(buf, len), len, len);
+		if (ret < 0)
+			goto fail;
+	}
+
+done:
+	return buf;
+fail:
+	wpabuf_free(buf);
+	buf = NULL;
+	goto done;
+}
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+					const u8 *key, size_t len)
+{
+	int ret;
+	struct wpabuf *pubkey = NULL;
+	struct wpabuf *secret = NULL;
+	word32 key_len = ecdh->ec->key.dp->size;
+	ecc_point *point = NULL;
+
+	pubkey = wpabuf_alloc(key_len + 1);
+	if (!pubkey)
+		goto fail;
+	wpabuf_put_u8(pubkey, inc_y ? 0x04 : 0x02);
+	wpabuf_put_data(pubkey, key, key_len);
+
+	point = wc_ecc_new_point();
+	if (!point)
+		goto fail;
+
+	ret = wc_ecc_import_point_der(wpabuf_put(pubkey, key_len + 1), key_len,
+				      ecdh->ec->key.dp->id, point);
+	if (ret != MP_OKAY)
+		goto fail;
+
+	secret = wpabuf_alloc(key_len);
+	if (!secret)
+		goto fail;
+
+	ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
+				      (byte*)wpabuf_put(secret, key_len),
+				      &key_len);
+	if (ret != MP_OKAY)
+		goto fail;
+
+done:
+	wc_ecc_del_point(point);
+	wpabuf_free(pubkey);
+	return secret;
+fail:
+	wpabuf_free(secret);
+	secret = NULL;
+	goto done;
+}
+
+
 #endif /* CONFIG_ECC */
diff --git a/src/crypto/fips_prf_wolfssl.c b/src/crypto/fips_prf_wolfssl.c
index 1709932..feb39db 100644
--- a/src/crypto/fips_prf_wolfssl.c
+++ b/src/crypto/fips_prf_wolfssl.c
@@ -7,6 +7,7 @@
  */
 
 #include "includes.h"
+#include <wolfssl/options.h>
 #include <wolfssl/wolfcrypt/sha.h>
 
 #include "common.h"
@@ -15,7 +16,7 @@
 
 static void sha1_transform(u32 *state, const u8 data[64])
 {
-	Sha sha;
+	wc_Sha sha;
 
 	os_memset(&sha, 0, sizeof(sha));
 	sha.digest[0] = state[0];
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index b7c452e..82ced39 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -10,24 +10,16 @@
 
 #include "common.h"
 #include "crypto.h"
+#include "sha1.h"
 #include "tls.h"
 
-#define OPENSSL_EXTRA
-#define HAVE_STUNNEL
-#define HAVE_SECRET_CALLBACK
-#define HAVE_SESSION_TICKET
-#define HAVE_OCSP
-#define HAVE_CERTIFICATE_STATUS_REQUEST
-#define HAVE_CERTIFICATE_STATUS_REQUEST_V2
-#ifndef WOLFSSL_DER_LOAD
-#define WOLFSSL_DER_LOAD
-#endif
-#if 0
-/* Enable if a debug build of wolfSSL is installed. */
-#define DEBUG_WOLFSSL
-#endif
+/* sha256.h is a wolfSSL header file. */
+extern void tls_prf_sha256(const u8 *secret, size_t secret_len,
+			   const char *label, const u8 *seed, size_t seed_len,
+			   u8 *out, size_t outlen);
 
 /* wolfSSL includes */
+#include <wolfssl/options.h>
 #include <wolfssl/ssl.h>
 #include <wolfssl/error-ssl.h>
 #include <wolfssl/wolfcrypt/asn.h>
@@ -470,9 +462,9 @@ static int tls_connection_client_cert(struct tls_connection *conn,
 		return 0;
 
 	if (client_cert_blob) {
-		if (wolfSSL_use_certificate_buffer(conn->ssl, client_cert_blob,
-						   blob_len,
-						   SSL_FILETYPE_ASN1) < 0) {
+		if (wolfSSL_use_certificate_chain_buffer_format(conn->ssl,
+			    client_cert_blob, blob_len,
+			    SSL_FILETYPE_ASN1) < 0) {
 			wpa_printf(MSG_INFO,
 				   "SSL: use client cert DER blob failed");
 			return -1;
@@ -482,11 +474,11 @@ static int tls_connection_client_cert(struct tls_connection *conn,
 	}
 
 	if (client_cert) {
-		if (wolfSSL_use_certificate_file(conn->ssl, client_cert,
-						 SSL_FILETYPE_PEM) < 0) {
+		if (wolfSSL_use_certificate_chain_file(conn->ssl,
+						       client_cert) < 0) {
 			wpa_printf(MSG_INFO,
 				   "SSL: use client cert PEM file failed");
-			if (wolfSSL_use_certificate_file(
+			if (wolfSSL_use_certificate_chain_file_format(
 				    conn->ssl, client_cert,
 				    SSL_FILETYPE_ASN1) < 0) {
 				wpa_printf(MSG_INFO,
@@ -577,10 +569,6 @@ static int tls_connection_private_key(void *tls_ctx,
 }
 
 
-#define GEN_EMAIL	1
-#define GEN_DNS		ALT_NAMES_OID
-#define GEN_URI		6
-
 static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
 					   const char *value, size_t len)
 {
@@ -590,7 +578,6 @@ static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
 	int i;
 
 	ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
-
 	for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
 		gen = wolfSSL_sk_value(ext, i);
 		if (gen->type != type)
@@ -893,19 +880,16 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
 		if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
 			break;
 		gen = wolfSSL_sk_value((void *) ext, i);
-#if 0
 		if (gen->type != GEN_EMAIL &&
 		    gen->type != GEN_DNS &&
 		    gen->type != GEN_URI)
 			continue;
-#endif
 
 		pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
 		if (!pos)
 			break;
 		alt_subject[num_alt_subject++] = pos;
 
-#if 0
 		switch (gen->type) {
 		case GEN_EMAIL:
 			os_memcpy(pos, "EMAIL:", 6);
@@ -920,10 +904,6 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
 			pos += 4;
 			break;
 		}
-#else
-		os_memcpy(pos, "DNS:", 4);
-		pos += 4;
-#endif
 
 		os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
 		pos += os_strlen((char *)gen->obj);
@@ -1099,7 +1079,7 @@ static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
 				       TLS_FAIL_SERVER_CHAIN_PROBE);
 	}
 
-#ifdef HAVE_OCSP_OPENSSL
+#ifdef HAVE_OCSP_WOLFSSL
 	if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
 	    preverify_ok) {
 		enum ocsp_result res;
@@ -1123,7 +1103,7 @@ static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
 					       TLS_FAIL_UNSPECIFIED);
 		}
 	}
-#endif /* HAVE_OCSP */
+#endif /* HAVE_OCSP_WOLFSSL */
 	if (depth == 0 && preverify_ok && context->event_cb != NULL)
 		context->event_cb(context->cb_ctx,
 				  TLS_CERT_CHAIN_SUCCESS, NULL);
@@ -1204,7 +1184,6 @@ static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
 			return -1;
 		}
 		wolfSSL_CTX_set_cert_store(ctx, cm);
-		XFREE(cm, NULL, DYNAMIC_TYPE_X509_STORE);
 
 		if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
 		    SSL_SUCCESS) {
@@ -1370,11 +1349,11 @@ static int tls_global_client_cert(void *ssl_ctx, const char *client_cert)
 	if (!client_cert)
 		return 0;
 
-	if (wolfSSL_CTX_use_certificate_file(ctx, client_cert,
-					     SSL_FILETYPE_ASN1) !=
+	if (wolfSSL_CTX_use_certificate_chain_file_format(ctx, client_cert,
+							  SSL_FILETYPE_ASN1) !=
 	    SSL_SUCCESS &&
-	    wolfSSL_CTX_use_certificate_file(ctx, client_cert,
-					     SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+	    wolfSSL_CTX_use_certificate_chain_file(ctx, client_cert) !=
+	    SSL_SUCCESS) {
 		wpa_printf(MSG_INFO, "Failed to load client certificate");
 		return -1;
 	}
@@ -1988,18 +1967,58 @@ int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
 }
 
 
+#define SEED_LEN	(RAN_LEN + RAN_LEN)
+
 int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
 				    u8 *out, size_t out_len)
 {
-	int ret;
+	byte seed[SEED_LEN];
+	int ret = -1;
+	WOLFSSL *ssl;
+	byte *tmp_out = NULL;
+	byte *_out;
+	int skip = 0;
+	byte *master_key;
+	unsigned int master_key_len;
+	byte *server_random;
+	unsigned int server_len;
+	byte *client_random;
+	unsigned int client_len;
 
 	if (!conn || !conn->ssl)
 		return -1;
+	ssl = conn->ssl;
 
-	ret = wolfSSL_make_eap_keys(conn->ssl, out, out_len, "key expansion");
-	if (ret != 0)
+	skip = 2 * (wolfSSL_GetKeySize(ssl) + wolfSSL_GetHmacSize(ssl) +
+		    wolfSSL_GetIVSize(ssl));
+
+	tmp_out = os_malloc(skip + out_len);
+	if (!tmp_out)
 		return -1;
-	return 0;
+	_out = tmp_out;
+
+	wolfSSL_get_keys(ssl, &master_key, &master_key_len, &server_random,
+			 &server_len, &client_random, &client_len);
+	XMEMCPY(seed          , server_random, RAN_LEN);
+	XMEMCPY(seed + RAN_LEN, client_random, RAN_LEN);
+
+	if (wolfSSL_GetVersion(ssl) == WOLFSSL_TLSV1_2) {
+		tls_prf_sha256(master_key, master_key_len,
+			       "key expansion", seed, sizeof(seed),
+			       _out, skip + out_len);
+		ret = 0;
+	} else if (tls_prf_sha1_md5(master_key, master_key_len,
+				    "key expansion", seed, sizeof(seed),
+				    _out, skip + out_len) == 0) {
+		ret = 0;
+	}
+
+	os_memset(master_key, 0, master_key_len);
+	if (ret == 0)
+		os_memcpy(out, _out + skip, out_len);
+	bin_clear_free(tmp_out, skip);
+
+	return ret;
 }
 
 
@@ -2037,14 +2056,14 @@ static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
 				      sizeof(client_random)) == 0 ||
 	    wolfSSL_get_server_random(s, server_random,
 				      sizeof(server_random)) == 0 ||
-	    wolfSSL_get_SessionTicket(s, conn->session_ticket, &ticketLen) != 1)
+	    wolfSSL_get_SessionTicket(s, conn->session_ticket, &ticket_len) != 1)
 		return 1;
 
 	if (ticket_len == 0)
 		return 0;
 
 	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
-				      conn->session_ticket, ticketLen,
+				      conn->session_ticket, ticket_len,
 				      client_random, server_random, secret);
 	if (ret <= 0)
 		return 1;
diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py
index 88041ca..804cbca 100644
--- a/tests/hwsim/test_ap_eap.py
+++ b/tests/hwsim/test_ap_eap.py
@@ -4115,7 +4115,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca(dev, apdev, params):
     params["private_key"] = "auth_serv/iCA-server/server.key"
     hostapd.add_ap(apdev[0], params)
     tls = dev[0].request("GET tls_library")
-    if "GnuTLS" in tls:
+    if "GnuTLS" in tls or "wolfSSL" in tls:
         ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
         client_cert = "auth_serv/iCA-user/user_and_ica.pem"
     else:
@@ -4223,7 +4223,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, md):
     try:
         hostapd.add_ap(apdev[0], params)
         tls = dev[0].request("GET tls_library")
-        if "GnuTLS" in tls:
+        if "GnuTLS" in tls or "wolfSSL" in tls:
             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
         else:
@@ -4258,7 +4258,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked(dev, apdev, params, md):
     try:
         hostapd.add_ap(apdev[0], params)
         tls = dev[0].request("GET tls_library")
-        if "GnuTLS" in tls:
+        if "GnuTLS" in tls or "wolfSSL" in tls:
             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
         else:
@@ -4308,7 +4308,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi_missing_resp(dev, apdev, par
     try:
         hostapd.add_ap(apdev[0], params)
         tls = dev[0].request("GET tls_library")
-        if "GnuTLS" in tls:
+        if "GnuTLS" in tls or "wolfSSL" in tls:
             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
         else:
@@ -4375,7 +4375,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi(dev, apdev, params):
 
         hostapd.add_ap(apdev[0], params)
         tls = dev[0].request("GET tls_library")
-        if "GnuTLS" in tls:
+        if "GnuTLS" in tls or "wolfSSL" in tls:
             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
         else:
diff --git a/tests/hwsim/test_eap_proto.py b/tests/hwsim/test_eap_proto.py
index d97a6f1..2ff6743 100644
--- a/tests/hwsim/test_eap_proto.py
+++ b/tests/hwsim/test_eap_proto.py
@@ -5124,7 +5124,7 @@ def test_eap_proto_ikev2(dev, apdev):
 
         def build_ke(next=0):
             ke = struct.pack(">BBHHH", next, 0, 4 + 4 + 192, 5, 0)
-            ke += 192*'\x00'
+            ke += 191*'\x00'+'\x02'
             return ke
 
         idx += 1
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index c761c22..eca20a9 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1067,6 +1067,7 @@ OBJS_p += ../src/crypto/crypto_wolfssl.o
 ifdef NEED_FIPS186_2_PRF
 OBJS += ../src/crypto/fips_prf_wolfssl.o
 endif
+NEED_TLS_PRF_SHA256=y
 LIBS += -lwolfssl -lm
 LIBS_p += -lwolfssl -lm
 endif
Sean Parkinson March 29, 2018, 11:58 p.m. UTC | #3
Jouni,

Also note that the OCSP is not supported yet.

Thanks,
Sean
—
Sean Parkinson
sean@wolfssl.com
wolfSSL Inc



> On 29 Mar 2018, at 2:55 pm, Sean Parkinson <sean@wolfssl.com> wrote:
> 
> Jouni,
> 
> (Excuse the previous email. This one in plaintext.)
> 
> I’ve looked into the failures and made changes as needed.
> There were changes to wolfSSL as well.
> 
> To reproduce the setup I tested:
> - download wolfSSL latest from master (https://github.com/wolfssl/wolfssl)
> - configure wolfSSL with option -enable-wpas
> - build wolfSSL
> - in wpa_supplicant change .config
>   - CONFIG_TLS=wolfssl
>   - disable CONFIG_DPP
> 
> The proposed new patch is below.
> 
> Thanks,
> Sean
> —
> Sean Parkinson
> sean@wolfssl.com
> wolfSSL Inc
> 
> 
> From 80ba12c7fecdd650d7528211e68e6fd7ededd736 Mon Sep 17 00:00:00 2001
> From: Sean Parkinson <sparki@wolfssl.com>
> Date: Mon, 19 Mar 2018 13:19:08 +1000
> Subject: [PATCH] Fixes for wolfSSL integration.
> 
> Use new digest namespace.
> Changes for memory allocation failure testing.
> Use same certificates as used for GnuTLS in tests.
> Implement tls_connection_get_eap_fast_key using cryptographic primitives
> as wolfSSL implements different spec.
> Use a valid key exchange value in test.
> Fix loading of client certificate to use 'chain' APIs.
> 
> Signed-off-by: Sean Parkinson <sean@wolfssl.com>
> ---
> hostapd/Makefile              |   2 +
> src/crypto/crypto_wolfssl.c   | 192 +++++++++++++++++++++++++++++++++---------
> src/crypto/fips_prf_wolfssl.c |   3 +-
> src/crypto/tls_wolfssl.c      | 109 ++++++++++++++----------
> tests/hwsim/test_ap_eap.py    |  10 +--
> tests/hwsim/test_eap_proto.py |   2 +-
> wpa_supplicant/Makefile       |   1 +
> 7 files changed, 228 insertions(+), 91 deletions(-)
> 
> diff --git a/hostapd/Makefile b/hostapd/Makefile
> index 98ce115..9f8c6cf 100644
> --- a/hostapd/Makefile
> +++ b/hostapd/Makefile
> @@ -899,9 +899,11 @@ AESOBJS += ../src/crypto/aes-encblock.o
> endif
> ifdef NEED_AES_OMAC1
> ifneq ($(CONFIG_TLS), linux)
> +ifneq ($(CONFIG_TLS), wolfssl)
> AESOBJS += ../src/crypto/aes-omac1.o
> endif
> endif
> +endif
> ifdef NEED_AES_UNWRAP
> ifneq ($(CONFIG_TLS), openssl)
> ifneq ($(CONFIG_TLS), linux)
> diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
> index 90163c4..7e68716 100644
> --- a/src/crypto/crypto_wolfssl.c
> +++ b/src/crypto/crypto_wolfssl.c
> @@ -11,18 +11,8 @@
> #include "common.h"
> #include "crypto.h"
> 
> -#define WOLFSSL_AES_DIRECT
> -#define HAVE_AESGCM
> -#define HAVE_AES_KEYWRAP
> -#define WOLFSSL_SHA384
> -#define WOLFSSL_SHA512
> -#define WOLFSSL_CMAC
> -#define HAVE_ECC
> -#define USE_FAST_MATH
> -#define WOLFSSL_KEY_GEN
> -
> -#include <wolfssl/options.h>
> /* wolfSSL headers */
> +#include <wolfssl/options.h>
> #include <wolfssl/wolfcrypt/md4.h>
> #include <wolfssl/wolfcrypt/md5.h>
> #include <wolfssl/wolfcrypt/sha.h>
> @@ -62,7 +52,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
> 
> int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
> {
> -	Md5 md5;
> +	wc_Md5 md5;
> 	size_t i;
> 
> 	if (TEST_FAIL())
> @@ -83,7 +73,7 @@ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
> 
> int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
> {
> -	Sha sha;
> +	wc_Sha sha;
> 	size_t i;
> 
> 	if (TEST_FAIL())
> @@ -104,7 +94,7 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
> int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
> 		  u8 *mac)
> {
> -	Sha256 sha256;
> +	wc_Sha256 sha256;
> 	size_t i;
> 
> 	if (TEST_FAIL())
> @@ -126,7 +116,7 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
> int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
> 		  u8 *mac)
> {
> -	Sha384 sha384;
> +	wc_Sha384 sha384;
> 	size_t i;
> 
> 	if (TEST_FAIL())
> @@ -148,7 +138,7 @@ int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
> int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
> 		  u8 *mac)
> {
> -	Sha512 sha512;
> +	wc_Sha512 sha512;
> 	size_t i;
> 
> 	if (TEST_FAIL())
> @@ -186,6 +176,7 @@ static int wolfssl_hmac_vector(int type, const u8 *key,
> 			return -1;
> 	if (wc_HmacFinal(&hmac, mac) != 0)
> 		return -1;
> +
> 	return 0;
> }
> 
> @@ -195,7 +186,7 @@ static int wolfssl_hmac_vector(int type, const u8 *key,
> int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
> 		    const u8 *addr[], const size_t *len, u8 *mac)
> {
> -	return wolfssl_hmac_vector(MD5, key, key_len, num_elem, addr, len, mac,
> +	return wolfssl_hmac_vector(WC_MD5, key, key_len, num_elem, addr, len, mac,
> 				   16);
> }
> 
> @@ -212,7 +203,7 @@ int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
> int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
> 		     const u8 *addr[], const size_t *len, u8 *mac)
> {
> -	return wolfssl_hmac_vector(SHA, key, key_len, num_elem, addr, len, mac,
> +	return wolfssl_hmac_vector(WC_SHA, key, key_len, num_elem, addr, len, mac,
> 				   20);
> }
> 
> @@ -229,7 +220,7 @@ int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
> int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
> 		       const u8 *addr[], const size_t *len, u8 *mac)
> {
> -	return wolfssl_hmac_vector(SHA256, key, key_len, num_elem, addr, len,
> +	return wolfssl_hmac_vector(WC_SHA256, key, key_len, num_elem, addr, len,
> 				   mac, 32);
> }
> 
> @@ -248,7 +239,7 @@ int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
> int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
> 		       const u8 *addr[], const size_t *len, u8 *mac)
> {
> -	return wolfssl_hmac_vector(SHA384, key, key_len, num_elem, addr, len,
> +	return wolfssl_hmac_vector(WC_SHA384, key, key_len, num_elem, addr, len,
> 				   mac, 48);
> }
> 
> @@ -267,7 +258,7 @@ int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
> int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
> 		       const u8 *addr[], const size_t *len, u8 *mac)
> {
> -	return wolfssl_hmac_vector(SHA512, key, key_len, num_elem, addr, len,
> +	return wolfssl_hmac_vector(WC_SHA512, key, key_len, num_elem, addr, len,
> 				   mac, 64);
> }
> 
> @@ -285,7 +276,7 @@ int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
> 		int iterations, u8 *buf, size_t buflen)
> {
> 	if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
> -		      ssid_len, iterations, buflen, SHA) != 0)
> +		      ssid_len, iterations, buflen, WC_SHA) != 0)
> 		return -1;
> 	return 0;
> }
> @@ -423,6 +414,9 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
> {
> 	int ret;
> 
> +	if (TEST_FAIL())
> +		return -1;
> +
> 	ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
> 			    NULL);
> 	return ret != (n + 1) * 8 ? -1 : 0;
> @@ -434,6 +428,9 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
> {
> 	int ret;
> 
> +	if (TEST_FAIL())
> +		return -1;
> +
> 	ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
> 			      NULL);
> 	return ret != n * 8 ? -1 : 0;
> @@ -654,13 +651,13 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
> 	wpabuf_free(*publ);
> 	*publ = NULL;
> 
> -	dh = os_malloc(sizeof(DhKey));
> +	dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
> 	if (!dh)
> 		return NULL;
> 	wc_InitDhKey(dh);
> 
> 	if (wc_InitRng(&rng) != 0) {
> -		os_free(dh);
> +		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
> 		return NULL;
> 	}
> 
> @@ -692,7 +689,7 @@ done:
> 	wpabuf_clear_free(privkey);
> 	if (dh) {
> 		wc_FreeDhKey(dh);
> -		os_free(dh);
> +		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
> 	}
> 	wc_FreeRng(&rng);
> 	return ret;
> @@ -706,12 +703,12 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
> 	byte *secret;
> 	word32 secret_sz;
> 
> -	dh = os_malloc(sizeof(DhKey));
> +	dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
> 	if (!dh)
> 		return NULL;
> 	wc_InitDhKey(dh);
> 
> -	secret = os_malloc(RFC3526_LEN);
> +	secret = XMALLOC(RFC3526_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
> 	if (!secret)
> 		goto done;
> 
> @@ -734,9 +731,9 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
> done:
> 	if (dh) {
> 		wc_FreeDhKey(dh);
> -		os_free(dh);
> +		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
> 	}
> -	os_free(secret);
> +	XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
> 	return ret;
> }
> 
> @@ -773,7 +770,7 @@ void dh5_free(void *ctx)
> 		return;
> 
> 	wc_FreeDhKey(ctx);
> -	os_free(ctx);
> +	XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
> }
> 
> #endif /* CONFIG_WPS_NFC */
> @@ -787,9 +784,6 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
> 	DhKey *dh = NULL;
> 	word32 priv_sz, pub_sz;
> 
> -	if (TEST_FAIL())
> -		return -1;
> -
> 	dh = os_malloc(sizeof(DhKey));
> 	if (!dh)
> 		return -1;
> @@ -889,7 +883,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
> 	struct crypto_hash *hash;
> 	int type;
> 
> -	hash = os_malloc(sizeof(*hash));
> +	hash = os_zalloc(sizeof(*hash));
> 	if (!hash)
> 		goto done;
> 
> @@ -897,19 +891,19 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
> #ifndef NO_MD5
> 	case CRYPTO_HASH_ALG_HMAC_MD5:
> 		hash->size = 16;
> -		type = MD5;
> +		type = WC_MD5;
> 		break;
> #endif /* NO_MD5 */
> #ifndef NO_SHA
> 	case CRYPTO_HASH_ALG_HMAC_SHA1:
> -		type = SHA;
> +		type = WC_SHA;
> 		hash->size = 20;
> 		break;
> #endif /* NO_SHA */
> #ifdef CONFIG_SHA256
> #ifndef NO_SHA256
> 	case CRYPTO_HASH_ALG_HMAC_SHA256:
> -		type = SHA256;
> +		type = WC_SHA256;
> 		hash->size = 32;
> 		break;
> #endif /* NO_SHA256 */
> @@ -1597,7 +1591,7 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
> 	ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len);
> 	if (ret <= 0)
> 		return -1;
> -	ret = wc_ecc_import_point_der(buf, ret + 1, e->key.idx,
> +	ret = wc_ecc_import_point_der(buf, ret * 2 + 1, e->key.idx,
> 				      (ecc_point *) p);
> 	if (ret != 0)
> 		return -1;
> @@ -1625,7 +1619,7 @@ crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
> 		goto done;
> 
> 	if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
> -	    mp_mulmod((mp_int *) x, &t, &e->prime, y2) != 0 ||
> +	    mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
> 	    mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
> 	    mp_addmod(y2, &t, &e->prime, y2) != 0 ||
> 	    mp_addmod(y2, &e->b, &e->prime, y2) != 0)
> @@ -1667,4 +1661,124 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
> 	return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b);
> }
> 
> +struct crypto_ecdh {
> +	struct crypto_ec *ec;
> +};
> +
> +struct crypto_ecdh * crypto_ecdh_init(int group)
> +{
> +	struct crypto_ecdh *ecdh = NULL;
> +	WC_RNG rng;
> +	int ret;
> +
> +	if (wc_InitRng(&rng) != 0)
> +		goto fail;
> +
> +	ecdh = os_zalloc(sizeof(*ecdh));
> +	if (!ecdh)
> +		goto fail;
> +
> +	ecdh->ec = crypto_ec_init(group);
> +	if (!ecdh->ec)
> +		goto fail;
> +
> +	ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
> +				 ecdh->ec->key.dp->id);
> +	if (ret < 0)
> +		goto fail;
> +
> +done:
> +	wc_FreeRng(&rng);
> +
> +	return ecdh;
> +fail:
> +	crypto_ecdh_deinit(ecdh);
> +	ecdh = NULL;
> +	goto done;
> +}
> +
> +void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
> +{
> +	if (ecdh) {
> +		crypto_ec_deinit(ecdh->ec);
> +		os_free(ecdh);
> +	}
> +}
> +
> +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;
> +
> +	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),
> +				   len, len);
> +	if (ret < 0)
> +		goto fail;
> +	if (inc_y) {
> +		ret = crypto_bignum_to_bin((struct crypto_bignum *)
> +					   ecdh->ec->key.pubkey.y,
> +					   wpabuf_put(buf, len), len, len);
> +		if (ret < 0)
> +			goto fail;
> +	}
> +
> +done:
> +	return buf;
> +fail:
> +	wpabuf_free(buf);
> +	buf = NULL;
> +	goto done;
> +}
> +
> +struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
> +					const u8 *key, size_t len)
> +{
> +	int ret;
> +	struct wpabuf *pubkey = NULL;
> +	struct wpabuf *secret = NULL;
> +	word32 key_len = ecdh->ec->key.dp->size;
> +	ecc_point *point = NULL;
> +
> +	pubkey = wpabuf_alloc(key_len + 1);
> +	if (!pubkey)
> +		goto fail;
> +	wpabuf_put_u8(pubkey, inc_y ? 0x04 : 0x02);
> +	wpabuf_put_data(pubkey, key, key_len);
> +
> +	point = wc_ecc_new_point();
> +	if (!point)
> +		goto fail;
> +
> +	ret = wc_ecc_import_point_der(wpabuf_put(pubkey, key_len + 1), key_len,
> +				      ecdh->ec->key.dp->id, point);
> +	if (ret != MP_OKAY)
> +		goto fail;
> +
> +	secret = wpabuf_alloc(key_len);
> +	if (!secret)
> +		goto fail;
> +
> +	ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
> +				      (byte*)wpabuf_put(secret, key_len),
> +				      &key_len);
> +	if (ret != MP_OKAY)
> +		goto fail;
> +
> +done:
> +	wc_ecc_del_point(point);
> +	wpabuf_free(pubkey);
> +	return secret;
> +fail:
> +	wpabuf_free(secret);
> +	secret = NULL;
> +	goto done;
> +}
> +
> +
> #endif /* CONFIG_ECC */
> diff --git a/src/crypto/fips_prf_wolfssl.c b/src/crypto/fips_prf_wolfssl.c
> index 1709932..feb39db 100644
> --- a/src/crypto/fips_prf_wolfssl.c
> +++ b/src/crypto/fips_prf_wolfssl.c
> @@ -7,6 +7,7 @@
>  */
> 
> #include "includes.h"
> +#include <wolfssl/options.h>
> #include <wolfssl/wolfcrypt/sha.h>
> 
> #include "common.h"
> @@ -15,7 +16,7 @@
> 
> static void sha1_transform(u32 *state, const u8 data[64])
> {
> -	Sha sha;
> +	wc_Sha sha;
> 
> 	os_memset(&sha, 0, sizeof(sha));
> 	sha.digest[0] = state[0];
> diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
> index b7c452e..82ced39 100644
> --- a/src/crypto/tls_wolfssl.c
> +++ b/src/crypto/tls_wolfssl.c
> @@ -10,24 +10,16 @@
> 
> #include "common.h"
> #include "crypto.h"
> +#include "sha1.h"
> #include "tls.h"
> 
> -#define OPENSSL_EXTRA
> -#define HAVE_STUNNEL
> -#define HAVE_SECRET_CALLBACK
> -#define HAVE_SESSION_TICKET
> -#define HAVE_OCSP
> -#define HAVE_CERTIFICATE_STATUS_REQUEST
> -#define HAVE_CERTIFICATE_STATUS_REQUEST_V2
> -#ifndef WOLFSSL_DER_LOAD
> -#define WOLFSSL_DER_LOAD
> -#endif
> -#if 0
> -/* Enable if a debug build of wolfSSL is installed. */
> -#define DEBUG_WOLFSSL
> -#endif
> +/* sha256.h is a wolfSSL header file. */
> +extern void tls_prf_sha256(const u8 *secret, size_t secret_len,
> +			   const char *label, const u8 *seed, size_t seed_len,
> +			   u8 *out, size_t outlen);
> 
> /* wolfSSL includes */
> +#include <wolfssl/options.h>
> #include <wolfssl/ssl.h>
> #include <wolfssl/error-ssl.h>
> #include <wolfssl/wolfcrypt/asn.h>
> @@ -470,9 +462,9 @@ static int tls_connection_client_cert(struct tls_connection *conn,
> 		return 0;
> 
> 	if (client_cert_blob) {
> -		if (wolfSSL_use_certificate_buffer(conn->ssl, client_cert_blob,
> -						   blob_len,
> -						   SSL_FILETYPE_ASN1) < 0) {
> +		if (wolfSSL_use_certificate_chain_buffer_format(conn->ssl,
> +			    client_cert_blob, blob_len,
> +			    SSL_FILETYPE_ASN1) < 0) {
> 			wpa_printf(MSG_INFO,
> 				   "SSL: use client cert DER blob failed");
> 			return -1;
> @@ -482,11 +474,11 @@ static int tls_connection_client_cert(struct tls_connection *conn,
> 	}
> 
> 	if (client_cert) {
> -		if (wolfSSL_use_certificate_file(conn->ssl, client_cert,
> -						 SSL_FILETYPE_PEM) < 0) {
> +		if (wolfSSL_use_certificate_chain_file(conn->ssl,
> +						       client_cert) < 0) {
> 			wpa_printf(MSG_INFO,
> 				   "SSL: use client cert PEM file failed");
> -			if (wolfSSL_use_certificate_file(
> +			if (wolfSSL_use_certificate_chain_file_format(
> 				    conn->ssl, client_cert,
> 				    SSL_FILETYPE_ASN1) < 0) {
> 				wpa_printf(MSG_INFO,
> @@ -577,10 +569,6 @@ static int tls_connection_private_key(void *tls_ctx,
> }
> 
> 
> -#define GEN_EMAIL	1
> -#define GEN_DNS		ALT_NAMES_OID
> -#define GEN_URI		6
> -
> static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
> 					   const char *value, size_t len)
> {
> @@ -590,7 +578,6 @@ static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
> 	int i;
> 
> 	ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
> -
> 	for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
> 		gen = wolfSSL_sk_value(ext, i);
> 		if (gen->type != type)
> @@ -893,19 +880,16 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
> 		if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
> 			break;
> 		gen = wolfSSL_sk_value((void *) ext, i);
> -#if 0
> 		if (gen->type != GEN_EMAIL &&
> 		    gen->type != GEN_DNS &&
> 		    gen->type != GEN_URI)
> 			continue;
> -#endif
> 
> 		pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
> 		if (!pos)
> 			break;
> 		alt_subject[num_alt_subject++] = pos;
> 
> -#if 0
> 		switch (gen->type) {
> 		case GEN_EMAIL:
> 			os_memcpy(pos, "EMAIL:", 6);
> @@ -920,10 +904,6 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
> 			pos += 4;
> 			break;
> 		}
> -#else
> -		os_memcpy(pos, "DNS:", 4);
> -		pos += 4;
> -#endif
> 
> 		os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
> 		pos += os_strlen((char *)gen->obj);
> @@ -1099,7 +1079,7 @@ static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
> 				       TLS_FAIL_SERVER_CHAIN_PROBE);
> 	}
> 
> -#ifdef HAVE_OCSP_OPENSSL
> +#ifdef HAVE_OCSP_WOLFSSL
> 	if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
> 	    preverify_ok) {
> 		enum ocsp_result res;
> @@ -1123,7 +1103,7 @@ static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
> 					       TLS_FAIL_UNSPECIFIED);
> 		}
> 	}
> -#endif /* HAVE_OCSP */
> +#endif /* HAVE_OCSP_WOLFSSL */
> 	if (depth == 0 && preverify_ok && context->event_cb != NULL)
> 		context->event_cb(context->cb_ctx,
> 				  TLS_CERT_CHAIN_SUCCESS, NULL);
> @@ -1204,7 +1184,6 @@ static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
> 			return -1;
> 		}
> 		wolfSSL_CTX_set_cert_store(ctx, cm);
> -		XFREE(cm, NULL, DYNAMIC_TYPE_X509_STORE);
> 
> 		if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
> 		    SSL_SUCCESS) {
> @@ -1370,11 +1349,11 @@ static int tls_global_client_cert(void *ssl_ctx, const char *client_cert)
> 	if (!client_cert)
> 		return 0;
> 
> -	if (wolfSSL_CTX_use_certificate_file(ctx, client_cert,
> -					     SSL_FILETYPE_ASN1) !=
> +	if (wolfSSL_CTX_use_certificate_chain_file_format(ctx, client_cert,
> +							  SSL_FILETYPE_ASN1) !=
> 	    SSL_SUCCESS &&
> -	    wolfSSL_CTX_use_certificate_file(ctx, client_cert,
> -					     SSL_FILETYPE_PEM) != SSL_SUCCESS) {
> +	    wolfSSL_CTX_use_certificate_chain_file(ctx, client_cert) !=
> +	    SSL_SUCCESS) {
> 		wpa_printf(MSG_INFO, "Failed to load client certificate");
> 		return -1;
> 	}
> @@ -1988,18 +1967,58 @@ int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
> }
> 
> 
> +#define SEED_LEN	(RAN_LEN + RAN_LEN)
> +
> int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
> 				    u8 *out, size_t out_len)
> {
> -	int ret;
> +	byte seed[SEED_LEN];
> +	int ret = -1;
> +	WOLFSSL *ssl;
> +	byte *tmp_out = NULL;
> +	byte *_out;
> +	int skip = 0;
> +	byte *master_key;
> +	unsigned int master_key_len;
> +	byte *server_random;
> +	unsigned int server_len;
> +	byte *client_random;
> +	unsigned int client_len;
> 
> 	if (!conn || !conn->ssl)
> 		return -1;
> +	ssl = conn->ssl;
> 
> -	ret = wolfSSL_make_eap_keys(conn->ssl, out, out_len, "key expansion");
> -	if (ret != 0)
> +	skip = 2 * (wolfSSL_GetKeySize(ssl) + wolfSSL_GetHmacSize(ssl) +
> +		    wolfSSL_GetIVSize(ssl));
> +
> +	tmp_out = os_malloc(skip + out_len);
> +	if (!tmp_out)
> 		return -1;
> -	return 0;
> +	_out = tmp_out;
> +
> +	wolfSSL_get_keys(ssl, &master_key, &master_key_len, &server_random,
> +			 &server_len, &client_random, &client_len);
> +	XMEMCPY(seed          , server_random, RAN_LEN);
> +	XMEMCPY(seed + RAN_LEN, client_random, RAN_LEN);
> +
> +	if (wolfSSL_GetVersion(ssl) == WOLFSSL_TLSV1_2) {
> +		tls_prf_sha256(master_key, master_key_len,
> +			       "key expansion", seed, sizeof(seed),
> +			       _out, skip + out_len);
> +		ret = 0;
> +	} else if (tls_prf_sha1_md5(master_key, master_key_len,
> +				    "key expansion", seed, sizeof(seed),
> +				    _out, skip + out_len) == 0) {
> +		ret = 0;
> +	}
> +
> +	os_memset(master_key, 0, master_key_len);
> +	if (ret == 0)
> +		os_memcpy(out, _out + skip, out_len);
> +	bin_clear_free(tmp_out, skip);
> +
> +	return ret;
> }
> 
> 
> @@ -2037,14 +2056,14 @@ static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
> 				      sizeof(client_random)) == 0 ||
> 	    wolfSSL_get_server_random(s, server_random,
> 				      sizeof(server_random)) == 0 ||
> -	    wolfSSL_get_SessionTicket(s, conn->session_ticket, &ticketLen) != 1)
> +	    wolfSSL_get_SessionTicket(s, conn->session_ticket, &ticket_len) != 1)
> 		return 1;
> 
> 	if (ticket_len == 0)
> 		return 0;
> 
> 	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
> -				      conn->session_ticket, ticketLen,
> +				      conn->session_ticket, ticket_len,
> 				      client_random, server_random, secret);
> 	if (ret <= 0)
> 		return 1;
> diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py
> index 88041ca..804cbca 100644
> --- a/tests/hwsim/test_ap_eap.py
> +++ b/tests/hwsim/test_ap_eap.py
> @@ -4115,7 +4115,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca(dev, apdev, params):
>     params["private_key"] = "auth_serv/iCA-server/server.key"
>     hostapd.add_ap(apdev[0], params)
>     tls = dev[0].request("GET tls_library")
> -    if "GnuTLS" in tls:
> +    if "GnuTLS" in tls or "wolfSSL" in tls:
>         ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
>         client_cert = "auth_serv/iCA-user/user_and_ica.pem"
>     else:
> @@ -4223,7 +4223,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, md):
>     try:
>         hostapd.add_ap(apdev[0], params)
>         tls = dev[0].request("GET tls_library")
> -        if "GnuTLS" in tls:
> +        if "GnuTLS" in tls or "wolfSSL" in tls:
>             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
>             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
>         else:
> @@ -4258,7 +4258,7 @@ def run_ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked(dev, apdev, params, md):
>     try:
>         hostapd.add_ap(apdev[0], params)
>         tls = dev[0].request("GET tls_library")
> -        if "GnuTLS" in tls:
> +        if "GnuTLS" in tls or "wolfSSL" in tls:
>             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
>             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
>         else:
> @@ -4308,7 +4308,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi_missing_resp(dev, apdev, par
>     try:
>         hostapd.add_ap(apdev[0], params)
>         tls = dev[0].request("GET tls_library")
> -        if "GnuTLS" in tls:
> +        if "GnuTLS" in tls or "wolfSSL" in tls:
>             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
>             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
>         else:
> @@ -4375,7 +4375,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi(dev, apdev, params):
> 
>         hostapd.add_ap(apdev[0], params)
>         tls = dev[0].request("GET tls_library")
> -        if "GnuTLS" in tls:
> +        if "GnuTLS" in tls or "wolfSSL" in tls:
>             ca_cert = "auth_serv/iCA-user/ca-and-root.pem"
>             client_cert = "auth_serv/iCA-user/user_and_ica.pem"
>         else:
> diff --git a/tests/hwsim/test_eap_proto.py b/tests/hwsim/test_eap_proto.py
> index d97a6f1..2ff6743 100644
> --- a/tests/hwsim/test_eap_proto.py
> +++ b/tests/hwsim/test_eap_proto.py
> @@ -5124,7 +5124,7 @@ def test_eap_proto_ikev2(dev, apdev):
> 
>         def build_ke(next=0):
>             ke = struct.pack(">BBHHH", next, 0, 4 + 4 + 192, 5, 0)
> -            ke += 192*'\x00'
> +            ke += 191*'\x00'+'\x02'
>             return ke
> 
>         idx += 1
> diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
> index c761c22..eca20a9 100644
> --- a/wpa_supplicant/Makefile
> +++ b/wpa_supplicant/Makefile
> @@ -1067,6 +1067,7 @@ OBJS_p += ../src/crypto/crypto_wolfssl.o
> ifdef NEED_FIPS186_2_PRF
> OBJS += ../src/crypto/fips_prf_wolfssl.o
> endif
> +NEED_TLS_PRF_SHA256=y
> LIBS += -lwolfssl -lm
> LIBS_p += -lwolfssl -lm
> endif
> -- 
> 1.9.1
>> On 4 Mar 2018, at 5:19 am, Jouni Malinen <j@w1.fi> wrote:
>> 
>> On Thu, Jan 18, 2018 at 12:26:39PM +1000, Sean Parkinson wrote:
>>> I’ve prepared a new patch with the changes as asked for by Jouni.
>>> 
>>> This patch was written to allow hostap to be compiled with the wolfSSL cryptography and TLS library.
>> 
>> Thanks! I'm seeing number of errors in the hwsim test cases, but it
>> looks like it is easiest to move ahead with this if I push in the
>> cleaned up version that I've been testing with some fixes to avoid
>> breaking non-wolfSSL builds. I'd welcome any incremental changes on top
>> of the current hostap.git master branch snapshot to address things that
>> I list below or maybe a recommendation on how to configure the wolfSSL
>> build properly to avoid the issues. I ran my tests with wolfSSL 3.13.0
>> and ended up adding various configure options until the build went
>> through cleanly. This ended up with following options:
>> 
>> ./configure --prefix=/home/jm/wolfssl/3.13.0 --enable-des3 --enable-md4 --enable-harden --enable-pwdbased --enable-tlsv10 --enable-oldtls --enable-cmac --enable-aeskeywrap --enable-keygen --enable-crl --enable-ocsp --enable-ocspstapling --enable-ocspstapling2 --enable-pkcallbacks --enable-tls13 --enable-fortress --enable-wpas --enable-static=yes --enable-shared=no
>> 
>> 
>> These are the notes from my hwsim test runs:
>> 
>> SAE:
>> - SAE: Could not solve y
>> - SAE: Could not pick PWE
>> --> check crypto_ec_point_solve_y_coord() implementation
>>  (wc_ecc_import_point_der() returns -1)
>> sae
>> sae_anti_clogging
>> sae_anti_clogging_proto
>> sae_bignum_failure
>> sae_forced_anti_clogging
>> sae_group_nego
>> sae_groups
>> sae_invalid_anti_clogging_token_req
>> sae_key_lifetime_in_memory
>> sae_mixed
>> sae_mixed_mfp
>> sae_no_random
>> sae_oom_wpas
>> sae_password
>> sae_password_ecc
>> sae_password_long
>> sae_password_short
>> sae_pmksa_caching
>> sae_pmksa_caching_disabled
>> sae_proto_confirm_replay
>> sae_proto_ecc
>> sae_pwe_failure
>> ap_ft_sae
>> ap_ft_sae_over_ds
>> sigma_dut_ap_psk_sae
>> sigma_dut_ap_sae
>> sigma_dut_ap_sae_group
>> sigma_dut_ap_sae_password
>> sigma_dut_sae
>> sigma_dut_sae_password
>> wpas_mesh_password_mismatch
>> mesh_forwarding_secure
>> ap_mixed_security
>> 
>> 
>> TLS interop(?) issue with OpenSSL server:
>> - OpenSSL server:
>> * SSL: SSL3 alert: write (local SSL3 detected an error):fatal:bad record mac
>> * SSL: SSL_accept:error in SSLv3 read finished A
>> * OpenSSL: openssl_handshake - SSL_connect error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac
>> ap_hs20_remediation_sql
>> eap_tls_no_session_resumption_radius
>> authsrv_testing_options
>> ap_wpa2_eap_tls_versions
>> 
>> 
>> OpenSSL authentication server:
>> - OpenSSL: openssl_handshake - SSL_connect error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher
>> ap_wpa2_eap_ttls_dh_params
>> ap_wpa2_eap_ttls_dh_params_blob
>> ap_wpa2_eap_ttls_dh_params_dsa
>> 
>> 
>> OpenSSL authentication server:
>> - TLS: Certificate verification failed, error 20 (unable to get local issuer certificate) depth 0 for '/C=FI/O=w1.fi/CN=user.w1.fi'
>> - SSL: SSL3 alert: write (local SSL3 detected an error):fatal:unknown CA
>> - OpenSSL: openssl_handshake - SSL_connect error:14089086:SSL routines:ssl3_get_client_certificate:certificate verify failed
>> ap_wpa2_eap_tls_intermediate_ca
>> ap_wpa2_eap_tls_intermediate_ca_ocsp_sha1
>> ap_wpa2_eap_tls_intermediate_ca_ocsp
>> ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked
>> ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked_sha1
>> 
>> 
>> TLS: tls_verify_cb - preverify_ok=1 err=0 (unknown error number) ca_cert_verify=1 depth=0 buf='/C=FI/O=w1.fi/CN=server.w1.fi'
>> TLS: altSubjectName match 'EMAIL:noone@example.com;DNS:server.w1.fi;URI:http://example.com/' not found
>> wlan0: CTRL-EVENT-EAP-TLS-CERT-ERROR reason=6 depth=0 subject='/C=FI/O=w1.fi/CN=server.w1.fi' err='AltSubject mismatch'
>> ap_wpa2_eap_ttls_pap_subject_match
>> 
>> 
>> TLS: tls_verify_cb - preverify_ok=1 err=0 (unknown error number) ca_cert_verify=1 depth=0 buf='/C=FI/O=w1.fi/CN=server.w1.fi'
>> TLS: altSubjectName match 'EMAIL:noone@example.com;URI:http://example.com/;DNS:server.w1.fi' not found
>> wlan0: CTRL-EVENT-EAP-TLS-CERT-ERROR reason=6 depth=0 subject='/C=FI/O=w1.fi/CN=server.w1.fi' err='AltSubject mismatch'
>> ap_wpa2_eap_ttls_chap_altsubject_match
>> 
>> 
>> TLS: Certificate verification failed, error -407 (Invalid OCSP Status Error) depth 2 for '/C=FI/O=w1.fi/CN=server.w1.fi'
>> ap_wpa2_eap_ttls_ocsp_revoked
>> ap_wpa2_eap_ttls_ocsp_unknown
>> ap_wpa2_eap_ttls_optional_ocsp_unknown
>> 
>> 
>> Missing altsubject in D-Bus output?!
>> dbus_connect_eap
>> 
>> 
>> DH: crypto_dh_derive_secret failed
>> eap_proto_ikev2
>> 
>> 
>> TLS: Certificate verification failed, error -238 (ASN CA path length larger than signer error) depth 2 for '/C=FI/O=w1.fi/CN=sha384.server.w1.fi'
>> eap_tls_sha384
>> eap_tls_sha512
>> 
>> 
>> 
>> GET_FAIL/GET_ALLOC_FAIL failure did not trigger:
>> radius_mppe_failure
>> authsrv_oom
>> 
>> 
>> -- 
>> Jouni Malinen                                            PGP id EFC895FA
>> 
>> _______________________________________________
>> Hostap mailing list
>> Hostap@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/hostap
> 
> 
> _______________________________________________
> Hostap mailing list
> Hostap@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/hostap
Jouni Malinen May 2, 2018, 3 p.m. UTC | #4
On Thu, Mar 29, 2018 at 02:55:55PM +1000, Sean Parkinson wrote:
> I’ve looked into the failures and made changes as needed.
> There were changes to wolfSSL as well.
> 
> To reproduce the setup I tested:
>  - download wolfSSL latest from master (https://github.com/wolfssl/wolfssl)
>  - configure wolfSSL with option -enable-wpas
>  - build wolfSSL
>  - in wpa_supplicant change .config
>    - CONFIG_TLS=wolfssl
>    - disable CONFIG_DPP
> 
> The proposed new patch is below.

Thanks. I applied this as number of smaller commits to make it easier to
review and understand. I did some cleanup and couple of fixes while
going through the changes as well.

There are some remaining issues, but it looks like this is a reasonable
step forward, so I included or the changes even though it looks like
there is something wrong with the ECDH wrappers (at least
crypto_ecdh_set_peerkey() fails to work properly).

The crypto_ecdh_set_peerkey() version in the patch you sent was broken,
i.e., it actually ended up causing process termination due to invalid
wpabuf_put() use that hit the buffer bounds checking routine. I fixed
that to use wpabuf_mhead() instead of wpabuf_put() since the
wc_ecc_import_point_der() call was clearly trying to use the already
generated buffer instead of trying to add something more into the
buffer. While this removed the process termination part, something is
still failing.. That wc_ecc_import_point_der() call fails every now and
then and even if it succeeds, the ECDH shared secret from
wc_ecc_shared_secret_ex() does not match the one that the AP derives
(i.e., using crypto_openssl.c on the other end of the connection).

As far as wolfSSL changes for --enable-wpas case are concerned, please
note that I had to revert the GetName() change in wolfcrypt/src/asn.c
(i.e., do not add an extra '=' to make the one-line name output look
like /CN==FI/ instead of /CN=FI/). This was added in wolfssl commit
b325e0ff916aa5989c523e7619f4dbbbeded74a1 ("Fixes for wpa_supplicant")
for some reason, but it results in a failure in one of the hwsim test
cases that verifies the exact contents of the server certificate name.

As far as remaining failures from wpa_supplicant build using current
wolfSSL snapshot against hostapd build using OpenSSL are concerned, I'm
seeing following issues:
- quite a few EAP-FAST test cases are failing
- ap_wpa2_eap_tls_versions is failing since tls_wolfssl.c returns
  "unknown" from tls_get_version() (i.e., wolfSSL_get_version())
- all OWE test cases are failing (that ECDH issue)
- all FILS PFS test cases are failing (ECDH)
- some EAP protocol test case failures

I haven't looked at these in much detail yet, but this is the list of
failing test cases from my tests:

ap_wpa2_eap_fast_binary_pac
ap_wpa2_eap_fast_binary_pac_errors
ap_wpa2_eap_fast_mschapv2_unauth_prov
ap_wpa2_eap_fast_pac_file
ap_wpa2_eap_fast_pac_refresh
ap_wpa2_eap_fast_pac_truncate
ap_wpa2_eap_fast_prov
ap_wpa2_eap_fast_server_oom
ap_wpa2_eap_fast_text_pac_errors
ap_wpa2_eap_ikev2_oom
ap_wpa2_eap_pwd_groups
ap_wpa2_eap_tls_versions
eap_mschapv2_errors
eap_proto_eke_errors
eap_proto_fast_errors
fils_sk_pfs_20
fils_sk_pfs_21
fils_sk_pfs_26
owe
owe_and_psk
owe_group_negotiation
owe_group_negotiation_connect_cmd
owe_groups
owe_limited_group_set
owe_pmksa_caching
owe_pmksa_caching_connect_cmd
owe_transition_mode
owe_transition_mode_connect_cmd
owe_transition_mode_multi_bss
sigma_dut_ap_owe
sigma_dut_ap_owe_ecgroupid
sigma_dut_ap_owe_transition_mode
sigma_dut_ap_owe_transition_mode_2
sigma_dut_owe
Sean Parkinson May 7, 2018, 11:26 p.m. UTC | #5
Hi Jouni,

I’ve been able to fix the ECDH problem and the error tests.
The EAP tests listed are not failing for me.
I’m using Ubuntu 14.04.1 in a virtual machine, with the OpenSSL that comes with it, as recommended in example-setup.txt.
What setup are you testing on?

See below for the patch file.

Sean
—
Sean Parkinson
sean@wolfssl.com
wolfSSL Inc



From 50827b00c8c8330ec03b09e6b51a9e06ac182162 Mon Sep 17 00:00:00 2001
From: Sean Parkinson <sparki@wolfssl.com>
Date: Tue, 8 May 2018 09:20:44 +1000
Subject: [PATCH] Fixes for wolfSSL

Fix for ECDH set peer to use the index when importing point.
Modified DH initialization to call TEST_FAIL() for error tests.

Signed-off-by: Sean Parkinson <sean@wolfssl.com>
---
 src/crypto/crypto_wolfssl.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index fc9a67b..bc4fd6a 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -783,6 +783,9 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
 	DhKey *dh = NULL;
 	word32 priv_sz, pub_sz;
 
+	if (TEST_FAIL())
+		return -1;
+
 	dh = os_malloc(sizeof(DhKey));
 	if (!dh)
 		return -1;
@@ -1762,7 +1765,7 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
 		goto fail;
 
 	ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len,
-				      ecdh->ec->key.dp->id, point);
+				      ecdh->ec->key.idx, point);
 	if (ret != MP_OKAY)
 		goto fail;
Jouni Malinen May 17, 2018, 6:58 p.m. UTC | #6
On Tue, May 08, 2018 at 09:26:45AM +1000, Sean Parkinson wrote:
> I’ve been able to fix the ECDH problem and the error tests.

Thanks, I can see the patch here fixing those in my setup as well.

> The EAP tests listed are not failing for me.
> I’m using Ubuntu 14.04.1 in a virtual machine, with the OpenSSL that comes with it, as recommended in example-setup.txt.
> What setup are you testing on?

I'm using Ubuntu 16.04 with various OpenSSL versions (including the one
from the distro).

I went through the details of the remaining hwsim test case failures and
there is only one real remaining issue (one real issue fixed and another
one depends on build capabilities):


EAP-FAST issues:
- tests needing unauthenticated provisioning (TLS ADH-AES128-SHA cipher
  suite) fail
- tests using authentication provisioning pass (e.g., ap_hs20_eap_fast_gtc)
- OpenSSL-based server:
  OpenSSL: RX ver=0x303 content_type=22 (handshake/client hello)
  SSL: SSL3 alert: write (local SSL3 detected an error):fatal:illegal parameter
  OpenSSL: openssl_handshake - SSL_connect error:1414F178:SSL routines:tls1_set_server_sigalgs:no shared sigature algorithms
  OpenSSL: pending error: error:1408A0E2:SSL routines:ssl3_get_client_hello:clienthello tlsext
- ClientHello from wolfSSL uses the correct cipher suite 0x0034
  * signature_algorithms extension includes one algorithm:
    0x0200 (hash: SHA1, signature: Anonymous)
- ClientHello from OpenSSL does not include signature_algorithms
  extension in this case
- disabling TLS 1.2 with wolfSSL seems to work around this since that
  removes the signature_algorithms extension
- what would the best way of fixing this interop issue?
- impacted hwsim test cases:
ap_wpa2_eap_fast_binary_pac
ap_wpa2_eap_fast_binary_pac_errors
ap_wpa2_eap_fast_mschapv2_unauth_prov
ap_wpa2_eap_fast_pac_file
ap_wpa2_eap_fast_pac_refresh
ap_wpa2_eap_fast_pac_truncate
ap_wpa2_eap_fast_prov
ap_wpa2_eap_fast_server_oom
ap_wpa2_eap_fast_text_pac_errors
eap_proto_fast_errors
eap_mschapv2_errors


EAP-pwd with Group 21 failing: (groups 19, 20, 25, 26 worked)
- looks like OpenSSL and wolfSSL derive a different k values
--> this is a bug in crypto_bignum_rshift() wrapper: need to use
    mp_rshb() instead of mp_rshd()
--> fixing this allows ap_wpa2_eap_pwd_groups to pass against OpenSSL


tls_wolfssl.c returns "unknown" from tls_get_version() (i.e.,
wolfSSL_get_version()):
- fails with ./configure --enable-wpas
- passed with ./configure --enable-wpas --enable-tlsv10
--> does not really need any implementation fixing; could considering
    skipping TLS 1.0 check automatically with builds that do not include
    support for it; kind of interesting to see "unknown" being reported,
    though, instead of just failing the TLS handshake if both TLS 1.1 and
    1.2 are disabled in runtime configuration and the wolfSSL build did
    not include TLS 1.0 or 1.3
- related to hwsim test case ap_wpa2_eap_tls_versions
diff mbox series

Patch

diff --git a/hostapd/Makefile b/hostapd/Makefile
index 418ab95..4a8299d 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -651,6 +651,27 @@  CFLAGS += -DCONFIG_TLSV12
 NEED_SHA256=y
 endif
 
+ifeq ($(CONFIG_TLS), wolfssl)
+CFLAGS += -DCRYPTO_ABSTRACT_API
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_wolfssl.o
+LIBS += -lwolfssl -lm
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+HOBJS += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+NEED_SHA256=y
+NEED_TLS_PRF_SHA256=y
+LIBS += -lwolfssl -lm
+LIBS_h += -lwolfssl -lm
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_h += -ldl
+endif
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_openssl.o
@@ -855,8 +876,10 @@  AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
 endif
 
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-wrap.o
 endif
+endif
 ifdef NEED_AES_EAX
 AESOBJS += ../src/crypto/aes-eax.o
 NEED_AES_CTR=y
@@ -881,19 +904,23 @@  endif
 ifdef NEED_AES_UNWRAP
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 NEED_AES_DEC=y
 AESOBJS += ../src/crypto/aes-unwrap.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_CBC
 NEED_AES_DEC=y
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-cbc.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_DEC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += ../src/crypto/aes-internal-dec.o
@@ -907,10 +934,12 @@  ifdef NEED_SHA1
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1.o
 endif
 endif
 endif
+endif
 SHA1OBJS += ../src/crypto/sha1-prf.o
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += ../src/crypto/sha1-internal.o
@@ -919,8 +948,10 @@  SHA1OBJS += ../src/crypto/fips_prf_internal.o
 endif
 endif
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
 endif
+endif
 ifdef NEED_T_PRF
 SHA1OBJS += ../src/crypto/sha1-tprf.o
 endif
@@ -936,10 +967,12 @@  endif
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/md5.o
 endif
 endif
 endif
+endif
 
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
@@ -955,6 +988,7 @@  endif
 endif
 
 ifdef NEED_DES
+CFLAGS += -DCONFIG_DES
 ifdef CONFIG_INTERNAL_DES
 OBJS += ../src/crypto/des-internal.o
 endif
@@ -977,10 +1011,12 @@  CFLAGS += -DCONFIG_SHA256
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha256.o
 endif
 endif
 endif
+endif
 OBJS += ../src/crypto/sha256-prf.o
 ifdef CONFIG_INTERNAL_SHA256
 OBJS += ../src/crypto/sha256-internal.o
@@ -1003,10 +1039,12 @@  CFLAGS += -DCONFIG_SHA384
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha384.o
 endif
 endif
 endif
+endif
 OBJS += ../src/crypto/sha384-prf.o
 endif
 ifdef NEED_SHA512
@@ -1056,10 +1094,12 @@  HOBJS += ../src/utils/eloop.o
 HOBJS += $(SHA1OBJS)
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 HOBJS += ../src/crypto/md5.o
 endif
 endif
 endif
+endif
 
 ifdef CONFIG_RADIUS_SERVER
 CFLAGS += -DRADIUS_SERVER
@@ -1250,7 +1290,13 @@  endif
 ifdef CONFIG_INTERNAL_MD5
 NOBJS += ../src/crypto/md5-internal.o
 endif
-NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+ifneq ($(CONFIG_TLS), openssl)
+NOBJS += ../src/crypto/crypto_openssl.o
+endif
+ifneq ($(CONFIG_TLS), wolfssl)
+NOBJS += ../src/crypto/crypto_wolfssl.o
+endif
+NOBJS += ../src/utils/os_$(CONFIG_OS).o
 NOBJS += ../src/utils/wpa_debug.o
 NOBJS += ../src/utils/wpabuf.o
 ifdef CONFIG_WPA_TRACE
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
new file mode 100644
index 0000000..ccff47e
--- /dev/null
+++ b/src/crypto/crypto_wolfssl.c
@@ -0,0 +1,1607 @@ 
+/*
+ * WPA Supplicant / wrapper functions for libwolfssl
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+#define WOLFSSL_AES_DIRECT
+#define HAVE_AESGCM
+#define HAVE_AES_KEYWRAP
+#define WOLFSSL_SHA384
+#define WOLFSSL_SHA512
+#define WOLFSSL_CMAC
+#define HAVE_ECC
+#define USE_FAST_MATH
+#define WOLFSSL_KEY_GEN
+
+#include <wolfssl/options.h>
+/* wolfSSL headers */
+#include <wolfssl/wolfcrypt/md4.h>
+#include <wolfssl/wolfcrypt/md5.h>
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/sha256.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/arc4.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/dh.h>
+#include <wolfssl/wolfcrypt/cmac.h>
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/openssl/bn.h>
+
+#ifndef CONFIG_FIPS
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+    Md4    md4;
+    size_t i;
+
+    if (TEST_FAIL())
+        return -1;
+
+    wc_InitMd4(&md4);
+
+    for (i = 0; i < num_elem; i++)
+        wc_Md4Update(&md4, addr[i], len[i]);
+
+    wc_Md4Final(&md4, mac);
+
+    return 0;
+}
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+    Md5    md5;
+    size_t i;
+
+    if (TEST_FAIL())
+        return -1;
+
+    wc_InitMd5(&md5);
+
+    for (i = 0; i < num_elem; i++)
+        wc_Md5Update(&md5, addr[i], len[i]);
+
+    wc_Md5Final(&md5, mac);
+
+    return 0;
+}
+#endif
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+        u8 *mac)
+{
+    Sha    sha;
+    size_t i;
+
+    if (TEST_FAIL())
+        return -1;
+
+    wc_InitSha(&sha);
+
+    for (i = 0; i < num_elem; i++)
+        wc_ShaUpdate(&sha, addr[i], len[i]);
+
+    wc_ShaFinal(&sha, mac);
+
+    return 0;
+}
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+          u8 *mac)
+{
+    Sha256 sha256;
+    size_t i;
+
+    if (TEST_FAIL())
+        return -1;
+
+    wc_InitSha256(&sha256);
+
+    for (i = 0; i < num_elem; i++)
+        wc_Sha256Update(&sha256, addr[i], len[i]);
+
+    wc_Sha256Final(&sha256, mac);
+
+    return 0;
+}
+#endif /* NO_SHA256_WRAPPER */
+
+#ifdef CONFIG_SHA384
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+          u8 *mac)
+{
+    Sha384 sha384;
+    size_t i;
+
+    if (TEST_FAIL())
+        return -1;
+
+    wc_InitSha384(&sha384);
+
+    for (i = 0; i < num_elem; i++)
+        wc_Sha384Update(&sha384, addr[i], len[i]);
+
+    wc_Sha384Final(&sha384, mac);
+
+    return 0;
+}
+#endif /* CONFIG_SHA384 */
+
+static int wolfssl_hmac_vector(int type, const u8 *key,
+                               size_t key_len, size_t num_elem,
+                               const u8 *addr[], const size_t *len, u8 *mac,
+                               unsigned int mdlen)
+{
+    Hmac hmac;
+    int i;
+
+    (void)mdlen;
+
+    if (TEST_FAIL())
+            return -1;
+
+    if (wc_HmacSetKey(&hmac, type, key, (word32)key_len) != 0)
+        return -1;
+    for (i = 0; i < num_elem; i++)
+            if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
+                return -1;
+    if (wc_HmacFinal(&hmac, mac) != 0)
+        return -1;
+    return 0;
+}
+
+#ifndef CONFIG_FIPS
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+                    const u8 *addr[], const size_t *len, u8 *mac)
+{
+    return wolfssl_hmac_vector(MD5, key, key_len, num_elem, addr, len, mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+             u8 *mac)
+{
+    return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+#endif
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+                     const u8 *addr[], const size_t *len, u8 *mac)
+{
+        return wolfssl_hmac_vector(SHA, key, key_len, num_elem, addr,
+                                   len, mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+               u8 *mac)
+{
+        return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+                       const u8 *addr[], const size_t *len, u8 *mac)
+{
+    return wolfssl_hmac_vector(SHA256, key, key_len, num_elem, addr, len, mac,
+                               32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+                size_t data_len, u8 *mac)
+{
+    return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+                       const u8 *addr[], const size_t *len, u8 *mac)
+{
+    return wolfssl_hmac_vector(SHA384, key, key_len, num_elem, addr, len, mac,
+                               48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+                size_t data_len, u8 *mac)
+{
+    return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+                int iterations, u8 *buf, size_t buflen)
+{
+        if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
+                      ssid_len, iterations, buflen, SHA) != 0)
+                return -1;
+        return 0;
+}
+
+
+#ifdef CONFIG_DES
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+    Des des;
+    u8  pkey[8], next, tmp;
+    int i;
+
+    /* Add parity bits to the key */
+    next = 0;
+    for (i = 0; i < 7; i++) {
+        tmp = key[i];
+        pkey[i] = (tmp >> i) | next | 1;
+        next = tmp << (7 - i);
+    }
+    pkey[i] = next | 1;
+
+    wc_Des_SetKey(&des, pkey, NULL, DES_ENCRYPTION);
+    wc_Des_EcbEncrypt(&des, cypher, clear, DES_BLOCK_SIZE);
+
+    return 0;
+}
+#endif
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+    Aes* aes;
+
+    if (TEST_FAIL())
+        return NULL;
+
+    aes = os_malloc(sizeof(Aes));
+    if (aes == NULL)
+        return NULL;
+
+    if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) {
+        os_free(aes);
+        return NULL;
+    }
+
+    return aes;
+}
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+    wc_AesEncryptDirect((Aes*)ctx, crypt, plain);
+    return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+    if (ctx != NULL)
+        os_free(ctx);
+}
+
+
+void* aes_decrypt_init(const u8 *key, size_t len)
+{
+    Aes* aes;
+
+    if (TEST_FAIL())
+        return NULL;
+
+    aes = os_malloc(sizeof(Aes));
+    if (aes == NULL)
+        return NULL;
+
+    if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) {
+        os_free(aes);
+        return NULL;
+    }
+
+    return aes;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+    wc_AesDecryptDirect((Aes*)ctx, plain, crypt);
+    return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+    if (ctx != NULL)
+        os_free(ctx);
+}
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+    Aes aes;
+    int ret;
+
+    if (TEST_FAIL())
+        return -1;
+
+    ret = wc_AesSetKey(&aes, key, 16, iv, AES_ENCRYPTION);
+    if (ret != 0)
+        return -1;
+
+    ret = wc_AesCbcEncrypt(&aes, data, data, data_len);
+    if (ret != 0)
+        return -1;
+    return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+    Aes aes;
+    int ret;
+
+    if (TEST_FAIL())
+        return -1;
+
+    ret = wc_AesSetKey(&aes, key, 16, iv, AES_DECRYPTION);
+    if (ret != 0)
+        return -1;
+
+    ret = wc_AesCbcDecrypt(&aes, data, data, data_len);
+    if (ret != 0)
+        return -1;
+    return 0;
+}
+
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+    int ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
+                            NULL);
+    return ret != (n + 1) * 8 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+               u8 *plain)
+{
+    int ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
+                              NULL);
+    return ret != n * 8 ? -1 : 0;
+}
+
+#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
+#endif /* CONFIG_FIPS */
+
+#ifndef CONFIG_NO_RC4
+int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data,
+             size_t data_len)
+{
+#ifndef NO_RC4
+    Arc4          arc4;
+    unsigned char skip_buf[16];
+
+    wc_Arc4SetKey(&arc4, key, keylen);
+
+    while (skip >= sizeof(skip_buf)) {
+        size_t len = skip;
+        if (len > sizeof(skip_buf))
+            len = sizeof(skip_buf);
+        wc_Arc4Process(&arc4, skip_buf, skip_buf, len);
+        skip -= len;
+    }
+
+    wc_Arc4Process(&arc4, data, data, data_len);
+
+    return 0;
+#else
+    return -1;
+#endif
+}
+#endif /* CONFIG_NO_RC4 */
+
+#if defined(EAP_IKEV2) || defined(EAP_IKEV2_DYNAMIC) \
+                       || defined(EAP_SERVER_IKEV2)
+union wolfssl_cipher
+{
+    Aes aes;
+    Des3 des3;
+    Arc4 arc4;
+};
+
+struct crypto_cipher {
+    enum crypto_cipher_alg alg;
+    union wolfssl_cipher enc;
+    union wolfssl_cipher dec;
+};
+
+struct crypto_cipher* crypto_cipher_init(enum crypto_cipher_alg alg,
+                                          const u8 *iv, const u8 *key,
+                                          size_t key_len)
+{
+    struct crypto_cipher *ctx;
+
+    ctx = os_zalloc(sizeof(*ctx));
+    if (ctx == NULL)
+        return NULL;
+        
+    switch (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);
+            break;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+        case CRYPTO_CIPHER_ALG_AES:
+            switch (key_len) {
+            case 16:
+            case 24:
+            case 32:
+                break;
+            default:
+                os_free(ctx);
+                return NULL;
+            }
+            if (wc_AesSetKey(&ctx->enc.aes, key, key_len, iv, AES_ENCRYPTION) ||
+                wc_AesSetKey(&ctx->dec.aes, key, key_len, iv, AES_DECRYPTION)) {
+                os_free(ctx);
+                return NULL;
+            }
+            break;
+#endif /* NO_AES */
+#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)) {
+                os_free(ctx);
+                return NULL;
+            }
+            break;
+#endif /* NO_DES3 */
+        case CRYPTO_CIPHER_ALG_RC2:
+        case CRYPTO_CIPHER_ALG_DES:
+        default:
+            os_free(ctx);
+            return NULL;
+    }
+
+    ctx->alg = alg;
+
+    return ctx;
+}
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+                          u8 *crypt, size_t len)
+{
+    switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+        case CRYPTO_CIPHER_ALG_RC4:
+            wc_Arc4Process(&ctx->enc.arc4, crypt, plain, len);
+            return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+        case CRYPTO_CIPHER_ALG_AES:
+            if (wc_AesCbcEncrypt(&ctx->enc.aes, crypt, plain, len) != 0)
+                return -1;
+            return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+        case CRYPTO_CIPHER_ALG_3DES:
+            if (wc_Des3_CbcEncrypt(&ctx->enc.des3, crypt, plain, len) != 0)
+                return -1;
+            return 0;
+#endif /* NO_DES3 */
+        default:
+            return -1;
+    }
+    return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+                          u8 *plain, size_t len)
+{
+    switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+        case CRYPTO_CIPHER_ALG_RC4:
+            wc_Arc4Process(&ctx->dec.arc4, plain, crypt, len);
+            return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+        case CRYPTO_CIPHER_ALG_AES:
+            if (wc_AesCbcDecrypt(&ctx->dec.aes, plain, crypt, len) != 0)
+                return -1;
+            return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+        case CRYPTO_CIPHER_ALG_3DES:
+            if (wc_Des3_CbcDecrypt(&ctx->dec.des3, plain, crypt, len) != 0)
+                return -1;
+            return 0;
+#endif /* NO_DES3 */
+        default:
+            return -1;
+    }
+    return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+    if (ctx != NULL)
+        os_free(ctx);
+}
+#endif
+
+#ifdef CONFIG_WPS_NFC
+static const unsigned char RFC3526_PRIME_1536[] = {
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+    0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+    0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+    0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+    0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+    0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+    0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+    0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+    0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+    0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+    0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+    0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+    0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+    0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+    0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+    0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+};
+static const unsigned char RFC3526_GENERATOR_1536[] = {
+    0x02
+};
+
+#define RFC3526_LEN       sizeof(RFC3526_PRIME_1536)
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+    WC_RNG rng;
+    DhKey* ret = NULL;
+    DhKey* dh = NULL;
+    struct wpabuf* privkey = NULL;
+    struct wpabuf* pubkey = NULL;
+    word32 privSz, pubSz;
+
+    *priv = NULL;
+    wpabuf_free(*publ);
+    *publ = NULL;
+
+    dh = os_malloc(sizeof(DhKey));
+    if (dh == NULL)
+        return NULL;
+    wc_InitDhKey(dh);
+
+    if (wc_InitRng(&rng) != 0) {
+        os_free(dh);
+        return NULL;
+    }
+
+    privkey = wpabuf_alloc(RFC3526_LEN);
+    pubkey = wpabuf_alloc(RFC3526_LEN);
+    if (privkey == NULL || pubkey == NULL)
+        goto done;
+
+    if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+                    RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+                    != 0)
+        goto done;
+
+    if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &privSz,
+                             wpabuf_mhead(pubkey), &pubSz) != 0)
+        goto done;
+
+    wpabuf_put(privkey, privSz);
+    wpabuf_put(pubkey, pubSz);
+
+    ret = dh;
+    *priv = privkey;
+    *publ = pubkey;
+    dh = NULL;
+    privkey = NULL;
+    pubkey = NULL;
+done:
+    wpabuf_clear_free(pubkey);
+    wpabuf_clear_free(privkey);
+    if (dh != NULL) {
+        wc_FreeDhKey(dh);
+        os_free(dh);
+    }
+    wc_FreeRng(&rng);
+    return ret;
+}
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+    DhKey* ret = NULL;
+    DhKey* dh;
+    byte*  secret;
+    word32 secretSz;
+
+    dh = os_malloc(sizeof(DhKey));
+    if (dh == NULL)
+        return NULL;
+    wc_InitDhKey(dh);
+
+    secret = os_malloc(RFC3526_LEN);
+    if (secret == NULL)
+        goto done;
+
+    if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+                    RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+                    != 0)
+        goto done;
+
+    if (wc_DhAgree(dh, secret, &secretSz, wpabuf_head(priv), wpabuf_len(priv),
+                   RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536)) != 0)
+        goto done;
+
+    if (secretSz != wpabuf_len(publ) ||
+            os_memcmp(secret, wpabuf_head(publ), secretSz) != 0)
+        goto done;
+
+    ret = dh;
+    dh = NULL;
+done:
+    if (dh != NULL) {
+        wc_FreeDhKey(dh);
+        os_free(dh);
+    }
+    if (secret != NULL)
+        os_free(secret);
+    return ret;
+}
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+                                  const struct wpabuf *own_private)
+{
+    struct wpabuf* ret = NULL;
+    struct wpabuf* secret;
+    word32         secretSz;
+
+    secret = wpabuf_alloc(RFC3526_LEN);
+    if (secret == NULL)
+        goto done;
+
+    if (wc_DhAgree(ctx, wpabuf_mhead(secret), &secretSz,
+                   wpabuf_head(own_private), wpabuf_len(own_private),
+                   wpabuf_head(peer_public), wpabuf_len(peer_public)) != 0)
+        goto done;
+
+    wpabuf_put(secret, secretSz);
+
+    ret = secret;
+    secret = NULL;
+done:
+    wpabuf_clear_free(secret);
+    return ret;
+}
+
+void dh5_free(void *ctx)
+{
+    if (ctx == NULL)
+        return;
+
+    wc_FreeDhKey(ctx);
+    os_free(ctx);
+}
+#endif
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+                   u8 *pubkey)
+{
+    int ret = -1;
+    WC_RNG rng;
+    DhKey* dh = NULL;
+    word32 privSz, pubSz;
+
+    if (TEST_FAIL())
+        return -1;
+
+    dh = os_malloc(sizeof(DhKey));
+    if (dh == NULL)
+        return -1;
+    wc_InitDhKey(dh);
+
+    if (wc_InitRng(&rng) != 0) {
+        os_free(dh);
+        return -1;
+    }
+
+    if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+        goto done;
+
+    if (wc_DhGenerateKeyPair(dh, &rng, privkey, &privSz, pubkey, &pubSz) != 0)
+        goto done;
+
+    if (privSz < prime_len) {
+        size_t padSz = prime_len - privSz;
+        os_memmove(privkey + padSz, privkey, privSz);
+        os_memset(privkey, 0, padSz);
+    }
+
+    if (pubSz < prime_len) {
+        size_t padSz = prime_len - pubSz;
+        os_memmove(pubkey + padSz, pubkey, pubSz);
+        os_memset(pubkey, 0, padSz);
+    }
+    ret = 0;
+done:
+    wc_FreeDhKey(dh);
+    os_free(dh);
+    wc_FreeRng(&rng);
+    return ret;
+}
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+                            const u8 *privkey, size_t privkey_len,
+                            const u8 *pubkey, size_t pubkey_len,
+                            u8 *secret, size_t *len)
+{
+    int ret = -1;
+    DhKey* dh;
+    word32 secretSz;
+
+    dh = os_malloc(sizeof(DhKey));
+    if (dh == NULL)
+        return -1;
+    wc_InitDhKey(dh);
+
+    if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+        goto done;
+
+    if (wc_DhAgree(dh, secret, &secretSz, privkey, privkey_len, pubkey,
+                   pubkey_len) != 0)
+        goto done;
+
+    *len = secretSz;
+    ret = 0;
+done:
+    wc_FreeDhKey(dh);
+    os_free(dh);
+    return ret;
+}
+
+#ifdef CONFIG_FIPS
+int crypto_get_random(void *buf, size_t len)
+{
+    int ret = 0;
+    WC_RNG rng;
+
+    if (wc_InitRng(&rng) != 0)
+        return -1;
+    if (wc_RNG_GenerateBlock(&rng, buf, len) != 0)
+        ret = -1;
+    wc_FreeRng(&rng);
+    return ret;
+}
+#endif
+
+#if defined(EAP_PWD) || defined(EAP_SERVER_PWD)
+struct crypto_hash {
+    Hmac hmac;
+    int  size;
+};
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+                                      size_t key_len)
+{
+    struct crypto_hash* ret = NULL;
+    struct crypto_hash* hash;
+    int type;
+
+    hash = os_malloc(sizeof(*hash));
+    if (hash == NULL)
+        goto done;
+
+    switch (alg) {
+#ifndef NO_MD5
+        case CRYPTO_HASH_ALG_HMAC_MD5:
+            hash->size = 16;
+            type = MD5;
+            break;
+#endif
+#ifndef NO_SHA
+        case CRYPTO_HASH_ALG_HMAC_SHA1:
+            type = SHA;
+            hash->size = 20;
+            break;
+#endif
+#ifdef CONFIG_SHA256
+#ifndef NO_SHA256
+        case CRYPTO_HASH_ALG_HMAC_SHA256:
+            type = SHA256;
+            hash->size = 32;
+            break;
+#endif
+#endif
+        default:
+            goto done;
+    }
+
+    if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+        goto done;
+
+    ret = hash;
+    hash = NULL;
+done:
+    if (hash != NULL)
+        os_free(hash);
+    return ret;
+}
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+     if (ctx == NULL)
+         return;
+     wc_HmacUpdate(&ctx->hmac, data, len);
+}
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+     int ret = 0;
+
+     if (ctx == NULL)
+         return -2;
+
+     if (mac == NULL || len == NULL)
+         goto done;
+
+     if (wc_HmacFinal(&ctx->hmac, mac) != 0) {
+         ret = -1;
+         goto done;
+     }
+
+     *len = ctx->size;
+     ret = 0;
+done:
+     if (ctx != NULL)
+         bin_clear_free(ctx, sizeof(*ctx));
+     return ret;
+}
+#endif
+
+#ifdef CONFIG_WOLFSSL_CMAC
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+                     const u8 *addr[], const size_t *len, u8 *mac)
+{
+    Cmac   cmac;
+    int    i;
+    word32 sz;
+
+    if (TEST_FAIL())
+        return -1;
+
+    if (wc_InitCmac(&cmac, key, key_len, WC_CMAC_AES, NULL) != 0)
+        return -1;
+
+    for (i = 0; i < num_elem; i++)
+        if (wc_CmacUpdate(&cmac, addr[i], len[i]) != 0)
+            return -1;
+
+    sz = AES_BLOCK_SIZE;
+    if (wc_CmacFinal(&cmac, mac, &sz) != 0 || sz != AES_BLOCK_SIZE)
+        return -1;
+
+    return 0;
+}
+
+
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+                         const u8 *addr[], const size_t *len, u8 *mac)
+{
+    return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+    return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+    return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
+#endif
+
+
+struct crypto_bignum* crypto_bignum_init(void)
+{
+    mp_int* a;
+
+    if (TEST_FAIL())
+        return NULL;
+
+    a = os_malloc(sizeof(*a));
+    if (mp_init(a) != MP_OKAY) {
+        os_free(a);
+        a = NULL;
+    }
+
+    return (struct crypto_bignum*)a;
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+    mp_int* a;
+
+    if (TEST_FAIL())
+        return NULL;
+
+    a = (mp_int*)crypto_bignum_init();
+    if (a == NULL)
+        return NULL;
+
+    if (mp_read_unsigned_bin(a, buf, len) != MP_OKAY) {
+        os_free(a);
+        a = NULL;
+    }
+
+    return (struct crypto_bignum*)a;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+    if (n == NULL)
+        return;
+
+    if (clear)
+        mp_forcezero((mp_int*)n);
+    mp_clear((mp_int*)n);
+    os_free((mp_int*)n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+                         u8 *buf, size_t buflen, size_t padlen)
+{
+    int num_bytes, offset;
+
+    if (TEST_FAIL())
+        return -1;
+
+    if (padlen > buflen)
+        return -1;
+
+    num_bytes = (mp_count_bits((mp_int*)a) + 7) / 8;
+    if ((size_t)num_bytes > buflen)
+        return -1;
+    if (padlen > (size_t)num_bytes)
+        offset = padlen - num_bytes;
+    else
+        offset = 0;
+    
+    os_memset(buf, 0, offset);
+    mp_to_unsigned_bin((mp_int*)a, buf + offset);
+    
+    return num_bytes + offset;
+}
+
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+    int ret = 0;
+    WC_RNG rng;
+
+    if (wc_InitRng(&rng) != 0)
+        return -1;
+    if (mp_rand_prime((mp_int*)r, (mp_count_bits((mp_int*)m) + 7) / 8 * 2, &rng,
+                      NULL) != 0) {
+        ret = -1;
+    }
+    if (ret == 0 && mp_mod((mp_int*)r, (mp_int*)m, (mp_int*)r) != 0)
+        ret = -1;
+    wc_FreeRng(&rng);
+    return ret;
+}
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+                      const struct crypto_bignum *b,
+                      struct crypto_bignum *r)
+{
+    return mp_add((mp_int*)a, (mp_int*)b, (mp_int*)r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+                      const struct crypto_bignum *m,
+                      struct crypto_bignum *r)
+{
+    return mp_mod((mp_int*)a, (mp_int*)m, (mp_int*)r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *b,
+                          const struct crypto_bignum *e,
+                          const struct crypto_bignum *m,
+                          struct crypto_bignum *r)
+{
+    int res;
+    
+    if (TEST_FAIL())
+        return -1;
+
+    res = mp_exptmod((mp_int*)b, (mp_int*)e, (mp_int*)m, (mp_int*)r);
+    return res == MP_OKAY ?  0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+                          const struct crypto_bignum *m,
+                          struct crypto_bignum *r)
+{
+    if (TEST_FAIL())
+        return -1;
+    return mp_invmod((mp_int*)a, (mp_int*)m, (mp_int*)r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+                      const struct crypto_bignum *b,
+                      struct crypto_bignum *r)
+{
+    if (TEST_FAIL())
+        return -1;
+    return mp_add((mp_int*)a, (mp_int*)b, (mp_int*)r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+                      const struct crypto_bignum *b,
+                      struct crypto_bignum *d)
+{
+    if (TEST_FAIL())
+        return -1;
+    return mp_div((mp_int*)a, (mp_int*)b, (mp_int*)d, NULL) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+                         const struct crypto_bignum *b,
+                         const struct crypto_bignum *m,
+                         struct crypto_bignum *d)
+{
+    int res;
+
+    if (TEST_FAIL())
+        return -1;
+
+    res = mp_mulmod((mp_int*)a, (mp_int*)b, (mp_int*)m, (mp_int*)d);
+    return res == MP_OKAY ?  0 : -1;
+}
+
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+			 struct crypto_bignum *r)
+{
+    if (mp_copy((mp_int*)a, (mp_int*)r) != MP_OKAY)
+        return -1;
+    mp_rshd((mp_int*)r, n);
+    return 0;
+}
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+                      const struct crypto_bignum *b)
+{
+    return mp_cmp((mp_int*)a, (mp_int*)b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+    return mp_count_bits((mp_int*)a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+    return mp_iszero((mp_int*)a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+    return mp_isone((mp_int*)a);
+}
+
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+    return mp_isodd((mp_int*)a);
+}
+
+
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+                           const struct crypto_bignum *p)
+{
+    mp_int t;
+    int ret;
+    int res = -2;
+
+    if (TEST_FAIL())
+        return -2;
+
+    if (mp_init(&t) != MP_OKAY) {
+        return -2;
+    }
+
+    /* t = (p-1) / 2 */
+    ret = mp_sub_d((mp_int*)p, 1, &t);
+    if (ret == MP_OKAY)
+        mp_rshb(&t, 1);
+    if (ret == MP_OKAY)
+        ret = mp_exptmod((mp_int*)a, &t, (mp_int*)p, &t);
+    if (ret == MP_OKAY) {
+        if (mp_isone(&t))
+            res = 1;
+        else if (mp_iszero(&t))
+            res = 0;
+        else
+            res = -1;
+    }
+
+    mp_clear(&t);
+    return res;
+}
+
+
+#ifdef CONFIG_ECC
+extern int ecc_map(ecc_point*, mp_int*, mp_digit);
+extern 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;
+    mp_int   a;
+    mp_int   prime;
+    mp_int   order;
+    mp_digit montB;
+    mp_int   b;
+};
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+    int built = 0;
+    struct crypto_ec *e;
+    int curve_id;
+
+    /* 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:
+            return NULL;
+    }
+
+    e = os_zalloc(sizeof(*e));
+    if (e == NULL)
+        return NULL;
+
+    if (wc_ecc_init(&e->key) != 0)
+        goto done;
+    if (wc_ecc_set_curve(&e->key, 0, curve_id) != 0)
+        goto done;
+
+    if (mp_init(&e->a) != MP_OKAY)
+        goto done;
+    if (mp_init(&e->prime) != MP_OKAY)
+        goto done;
+    if (mp_init(&e->order) != MP_OKAY)
+        goto done;
+    if (mp_init(&e->b) != MP_OKAY)
+        goto done;
+
+    if (mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY)
+        goto done;
+    if (mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY)
+        goto done;
+    if (mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY)
+        goto done;
+    if (mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY)
+        goto done;
+
+    if (mp_montgomery_setup(&e->prime, &e->montB) != MP_OKAY)
+        goto done;
+
+    built = 1;
+done:
+    if (!built) {
+        crypto_ec_deinit(e);
+        e = NULL;
+    }
+    return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec* e)
+{
+    if (e == NULL)
+        return;
+
+    mp_clear(&e->b);
+    mp_clear(&e->order);
+    mp_clear(&e->prime);
+    mp_clear(&e->a);
+    wc_ecc_free(&e->key);
+    os_free(e);
+}
+
+int crypto_ec_cofactor(struct crypto_ec* e, struct crypto_bignum* cofactor)
+{
+    if (e == NULL || cofactor == NULL)
+        return -1;
+
+    mp_set((mp_int*)cofactor, e->key.dp->cofactor);
+    return 0;
+}
+
+struct crypto_ec_point* crypto_ec_point_init(struct crypto_ec* e)
+{
+    if (TEST_FAIL())
+        return NULL;
+    if (e == NULL)
+        return NULL;
+    return (struct crypto_ec_point*)wc_ecc_new_point();
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+    return (mp_count_bits(&e->prime) + 7) / 8;
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+    return mp_count_bits(&e->prime);
+}
+
+
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+    return (mp_count_bits(&e->order) + 7) / 8;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+    return (const struct crypto_bignum *)&e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+    return (const struct crypto_bignum *)&e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+    ecc_point* point = (ecc_point*)p;
+
+    if (p == NULL)
+        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)
+{
+    return mp_copy(((ecc_point*)p)->x, (mp_int*)x) == MP_OKAY ? 0 : -1;
+}
+
+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;
+
+    if (TEST_FAIL())
+        return -1;
+
+    if (!mp_isone(p->z)) {
+        if (ecc_map(p, &e->prime, e->montB) != MP_OKAY)
+            return -1;
+    }
+
+    if (x != NULL) {
+        if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x,
+                                 e->key.dp->size, e->key.dp->size) <= 0) {
+            return -1;
+        }
+    }
+    if (y != NULL) {
+        if (crypto_bignum_to_bin((struct crypto_bignum *)p->y, y,
+                                 e->key.dp->size, e->key.dp->size) <= 0) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+struct crypto_ec_point* crypto_ec_point_from_bin(struct crypto_ec *e,
+                                                 const u8 *val)
+{
+    ecc_point* point = NULL;
+    int loaded = 0;
+
+    if (TEST_FAIL())
+        return NULL;
+
+    point = wc_ecc_new_point();
+    if (point == NULL)
+        goto done;
+
+    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)
+        goto done;
+    mp_set(point->z, 1);
+
+    loaded = 1;
+done:
+    if (!loaded) {
+        wc_ecc_del_point(point);
+        point = NULL;
+    }
+    return (struct crypto_ec_point*)point;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+                        const struct crypto_ec_point *b,
+                        struct crypto_ec_point *c)
+{
+    mp_int mu;
+    ecc_point *ta = NULL, *tb = NULL;
+    ecc_point *pa = (ecc_point*)a, *pb = (ecc_point*)b;
+    mp_int *modulus = &e->prime;
+    int ret;
+
+    if (TEST_FAIL())
+        return -1;
+
+    if ((ret = mp_init(&mu)) != MP_OKAY) {
+        return -1;
+    }
+    if ((ret = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) {
+        mp_clear(&mu);
+        return -1;
+    }
+
+    if (!mp_isone(&mu)) {
+        ta = wc_ecc_new_point();
+        if (ta == NULL) {
+            mp_clear(&mu);
+            return -1;
+        }
+        tb = wc_ecc_new_point();
+        if (tb == NULL) {
+            wc_ecc_del_point(ta);
+            mp_clear(&mu);
+            return -1;
+        }
+
+        if (mp_mulmod(pa->x, &mu, modulus, ta->x) != MP_OKAY) {
+            ret = -1;
+            goto end;
+        }
+        if (mp_mulmod(pa->y, &mu, modulus, ta->y) != MP_OKAY) {
+            ret = -1;
+            goto end;
+        }
+        if (mp_mulmod(pa->z, &mu, modulus, ta->z) != MP_OKAY) {
+            ret = -1;
+            goto end;
+        }
+        if (mp_mulmod(pb->x, &mu, modulus, tb->x) != MP_OKAY) {
+            ret = -1;
+            goto end;
+        }
+        if (mp_mulmod(pb->y, &mu, modulus, tb->y) != MP_OKAY) {
+            ret = -1;
+            goto end;
+        }
+        if (mp_mulmod(pb->z, &mu, modulus, tb->z) != MP_OKAY) {
+            ret = -1;
+            goto end;
+        }
+        pa = ta;
+        pb = tb;
+    }
+
+    ret = ecc_projective_add_point(pa, pb, (ecc_point*)c, &e->a, &e->prime,
+                                   e->montB);
+    if (ret != 0) {
+        ret = -1;
+        goto end;
+    }
+
+    if (ecc_map((ecc_point*)c, &e->prime, e->montB) != MP_OKAY)
+        ret = -1;
+    else
+        ret = 0;
+end:
+    wc_ecc_del_point(tb);
+    wc_ecc_del_point(ta);
+    mp_clear(&mu);
+    return ret;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+                        const struct crypto_bignum *b,
+                        struct crypto_ec_point *res)
+{
+    int ret;
+
+    if (TEST_FAIL())
+        return -1;
+
+    ret = wc_ecc_mulmod((mp_int*)b, (ecc_point*)p, (ecc_point*)res, &e->a,
+                        &e->prime, 1);
+    return ret == 0 ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+    ecc_point* point = (ecc_point*)p;
+
+    if (TEST_FAIL())
+        return -1;
+
+    if (mp_sub(&e->prime, point->y, point->y) != MP_OKAY)
+        return -1;
+
+    return 0;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+                                  struct crypto_ec_point *p,
+                                  const struct crypto_bignum *x, int y_bit)
+{
+    byte buf[MAX_ECC_BYTES + 1];
+    int ret;
+    int prime_len = crypto_ec_prime_len(e);
+
+    if (TEST_FAIL())
+        return -1;
+
+    buf[0] = 0x2 + (byte)y_bit;
+    ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len);
+    if (ret <= 0) {
+        return -1;
+    }
+    ret = wc_ecc_import_point_der(buf, ret + 1, e->key.idx, (ecc_point*)p);
+    if (ret != 0)
+        return -1;
+
+    return 0;
+}
+
+
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+                              const struct crypto_bignum *x)
+{
+    mp_int* y2 = NULL;
+    mp_int t;
+    int calced = 0;
+
+    if (TEST_FAIL())
+        return NULL;
+
+    if (mp_init(&t) != MP_OKAY)
+        return NULL;
+
+    y2 = (mp_int*)crypto_bignum_init();
+    if (y2 == NULL)
+        goto done;
+
+    if (mp_sqrmod((mp_int*)x, &e->prime, y2) != 0)
+        goto done;
+    if (mp_mulmod((mp_int*)x, &t, &e->prime, y2) != 0)
+        goto done;
+    if (mp_mulmod((mp_int*)x, &e->a, &e->prime, &t) != 0)
+        goto done;
+    if (mp_addmod(y2, &t, &e->prime, y2) != 0)
+        goto done;
+    if (mp_addmod(y2, &e->b, &e->prime, y2) != 0)
+        goto done;
+
+    calced = 1;
+done:
+    if (!calced) {
+        if (y2 != NULL) {
+            mp_clear(y2);
+            os_free(y2);
+        }
+        mp_clear(&t);
+    }
+
+    return (struct crypto_bignum*)y2;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+                                   const struct crypto_ec_point *p)
+{
+    return wc_ecc_point_is_at_infinity((ecc_point*)p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+                                const struct crypto_ec_point *p)
+{
+    return wc_ecc_is_point((ecc_point*)p, &e->a, &e->b, &e->prime) == MP_OKAY;
+}
+
+
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+                        const struct crypto_ec_point *a,
+                        const struct crypto_ec_point *b)
+{
+    return wc_ecc_cmp_point((ecc_point*)a, (ecc_point*)b);
+}
+
+#endif /* CONFIG_ECC */
diff --git a/src/crypto/fips_prf_wolfssl.c b/src/crypto/fips_prf_wolfssl.c
new file mode 100644
index 0000000..becacec
--- /dev/null
+++ b/src/crypto/fips_prf_wolfssl.c
@@ -0,0 +1,85 @@ 
+/*
+ * FIPS 186-2 PRF for libcrypto
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <wolfssl/wolfcrypt/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static void sha1_transform(u32 *state, const u8 data[64])
+{
+	Sha sha;
+	os_memset(&sha, 0, sizeof(sha));
+	sha.digest[0] = state[0];
+	sha.digest[1] = state[1];
+	sha.digest[2] = state[2];
+	sha.digest[3] = state[3];
+	sha.digest[4] = state[4];
+	wc_ShaUpdate(&sha, data, 64);
+	state[0] = sha.digest[0];
+	state[1] = sha.digest[1];
+	state[2] = sha.digest[2];
+	state[3] = sha.digest[3];
+	state[4] = sha.digest[4];
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	u8 xkey[64];
+	u32 t[5], _t[5];
+	int i, j, m, k;
+	u8 *xpos = x;
+	u32 carry;
+
+	if (seed_len < sizeof(xkey))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	t[0] = 0x67452301;
+	t[1] = 0xEFCDAB89;
+	t[2] = 0x98BADCFE;
+	t[3] = 0x10325476;
+	t[4] = 0xC3D2E1F0;
+
+	m = xlen / 40;
+	for (j = 0; j < m; j++) {
+		/* XSEED_j = 0 */
+		for (i = 0; i < 2; i++) {
+			/* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+			/* w_i = G(t, XVAL) */
+			os_memcpy(_t, t, 20);
+			sha1_transform(_t, xkey);
+			WPA_PUT_BE32(xpos, _t[0]);
+			WPA_PUT_BE32(xpos + 4, _t[1]);
+			WPA_PUT_BE32(xpos + 8, _t[2]);
+			WPA_PUT_BE32(xpos + 12, _t[3]);
+			WPA_PUT_BE32(xpos + 16, _t[4]);
+
+			/* XKEY = (1 + XKEY + w_i) mod 2^b */
+			carry = 1;
+			for (k = 19; k >= 0; k--) {
+				carry += xkey[k] + xpos[k];
+				xkey[k] = carry & 0xff;
+				carry >>= 8;
+			}
+
+			xpos += 20;
+		}
+		/* x_j = w_0|w_1 */
+	}
+
+	return 0;
+}
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
new file mode 100644
index 0000000..ecd5db2
--- /dev/null
+++ b/src/crypto/tls_wolfssl.c
@@ -0,0 +1,2057 @@ 
+/*
+ * SSL/TLS interface functions for wolfSSL TLS case
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "tls.h"
+
+#define OPENSSL_EXTRA
+#define HAVE_STUNNEL
+#define HAVE_SECRET_CALLBACK
+#define HAVE_SESSION_TICKET
+#define HAVE_OCSP
+#define HAVE_CERTIFICATE_STATUS_REQUEST
+#define HAVE_CERTIFICATE_STATUS_REQUEST_V2
+#ifndef WOLFSSL_DER_LOAD
+#define WOLFSSL_DER_LOAD
+#endif
+#if 0
+/* Enable if a debug build of wolfSSL is installed. */
+#define DEBUG_WOLFSSL
+#endif
+
+/* wolfSSL includes */
+#include <wolfssl/ssl.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#define HAVE_AESGCM
+#include <wolfssl/wolfcrypt/aes.h>
+#endif
+
+#if !defined(CONFIG_FIPS) &&                             \
+    (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
+     defined(EAP_SERVER_FAST))
+#define WOLFSSL_NEED_EAP_FAST_PRF
+#endif
+
+#define SECRET_LEN          48
+#define RAN_LEN             32
+#define SESSION_TICKET_LEN  256
+
+static int tlsRefCount = 0;
+
+static int tls_ex_idx_session = 0;
+
+
+/* tls input data for wolfSSL Read Callback */
+struct tls_in_data {
+    const struct wpabuf* in_data;
+    size_t consumed;                 /* how many bytes have we used already */
+};
+
+
+/* tls output data for wolfSSL Write Callback */
+struct tls_out_data {
+    struct wpabuf* out_data;
+};
+
+struct tls_context {
+        void (*event_cb)(void *ctx, enum tls_event ev,
+                         union tls_event_data *data);
+        void *cb_ctx;
+        int cert_in_cb;
+        char *ocsp_stapling_response;
+};
+
+static struct tls_context *tls_global = NULL;
+
+/* wolfssl tls_connection */
+struct tls_connection {
+    struct tls_context*   context;
+    WOLFSSL*              ssl;
+    int                   readAlerts;
+    int                   writeAlerts;
+    int                   failed;
+    struct tls_in_data    input;
+    struct tls_out_data   output;
+    char*                 subjectMatch;
+    char*                 altSubjectMatch;
+    char*                 suffixMatch;
+    char*                 domainMatch;
+
+    u8                    srv_cert_hash[32];
+
+    unsigned char         client_random[RAN_LEN];
+    unsigned char         server_random[RAN_LEN];
+    unsigned int          flags;
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+    tls_session_ticket_cb session_ticket_cb;
+    void*                 session_ticket_cb_ctx;
+    byte                  session_ticket[SESSION_TICKET_LEN];
+#endif
+    unsigned int          ca_cert_verify:1;
+    unsigned int          cert_probe:1;
+    unsigned int          server_cert_only:1;
+    unsigned int          success_data:1;
+
+    WOLFSSL_X509*         peer_cert;
+    WOLFSSL_X509*         peer_issuer;
+    WOLFSSL_X509*         peer_issuer_issuer;
+
+};
+
+
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+        struct tls_context *context = os_zalloc(sizeof(*context));
+        if (context == NULL)
+                return NULL;
+        if (conf) {
+                context->event_cb = conf->event_cb;
+                context->cb_ctx = conf->cb_ctx;
+                context->cert_in_cb = conf->cert_in_cb;
+        }
+        return context;
+}
+
+
+static void ResetInData(struct tls_in_data* in, const struct wpabuf* buf)
+{
+    /* old one not owned by us so don't free */
+    in->in_data  = buf;
+    in->consumed = 0;
+}
+
+
+static void ResetOutData(struct tls_out_data* out)
+{
+    /* old one not owned by us so don't free */
+    out->out_data = wpabuf_alloc_copy("", 0);
+}
+
+
+/* wolfSSL I/O Receive CallBack */
+static int wolfsslReceiveCb(WOLFSSL *ssl, char* buf, int sz, void* ctx)
+{
+    size_t get = sz;
+    struct tls_in_data* data = (struct tls_in_data*)ctx;
+
+    if (data == NULL)
+        return -1;
+
+    if (get > (wpabuf_len(data->in_data) - data->consumed))
+        get =  wpabuf_len(data->in_data) - data->consumed;
+
+    os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
+    data->consumed += get;
+
+    if (get == 0)
+        return -2; /* WANT_READ */
+
+    return (int)get;
+}
+
+
+/* wolfSSL I/O Send CallBack */
+static int wolfsslSendCb(WOLFSSL *ssl, char* buf, int sz, void* ctx)
+{
+    struct wpabuf* tmp;
+    struct tls_out_data* data = (struct tls_out_data*)ctx;
+
+    if (data == NULL)
+        return -1;
+
+    wpa_printf(MSG_DEBUG, "SSL: adding %d bytes", sz);
+
+    tmp = wpabuf_alloc_copy(buf, sz);
+    data->out_data = wpabuf_concat(data->out_data, tmp);
+
+    if (data->out_data == NULL)
+            return -1;
+
+    return sz;
+}
+
+static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
+{
+        struct wpabuf *buf;
+
+        buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+        if (!buf)
+                return;
+        wpa_printf(MSG_DEBUG,
+                   "wolfSSL: Free application session data %p (sess %p)",
+                   buf, sess);
+        wpabuf_free(buf);
+
+        wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+void* tls_init(const struct tls_config *conf)
+{
+    WOLFSSL_CTX* sslCtx;
+    struct tls_context *context;
+    const char *ciphers;
+
+#ifdef DEBUG_WOLFSSL
+    wolfSSL_Debugging_ON();
+#endif
+
+    context = tls_context_new(conf);
+    if (context == NULL)
+        return NULL;
+
+    if (tlsRefCount == 0) {
+        tls_global = context;
+
+        if (wolfSSL_Init() < 0)
+            return NULL;
+        /* wolfSSL_Debugging_ON(); */
+    }
+
+    tlsRefCount++;
+
+    sslCtx = wolfSSL_CTX_new(wolfSSLv23_client_method());  /* start as client */
+    if (sslCtx == NULL) {
+        tlsRefCount--;
+        if (context != tls_global)
+            os_free(context);
+        if (tlsRefCount == 0) {
+            os_free(tls_global);
+            tls_global = NULL;
+        }
+    }
+    wolfSSL_SetIORecv(sslCtx, wolfsslReceiveCb);
+    wolfSSL_SetIOSend(sslCtx, wolfsslSendCb);
+    wolfSSL_CTX_set_ex_data(sslCtx, 0, context);
+
+    if (conf->tls_session_lifetime > 0) {
+        wolfSSL_CTX_set_quiet_shutdown(sslCtx, 1);
+        wolfSSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_SERVER);
+        wolfSSL_CTX_set_timeout(sslCtx, conf->tls_session_lifetime);
+        wolfSSL_CTX_sess_set_remove_cb(sslCtx, remove_session_cb);
+    } else {
+        wolfSSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_CLIENT);
+    }
+
+    if (conf && conf->openssl_ciphers)
+        ciphers = conf->openssl_ciphers;
+    else
+        ciphers = "ALL";
+    if (wolfSSL_CTX_set_cipher_list(sslCtx, ciphers) != 1) {
+        wpa_printf(MSG_ERROR,
+                   "wolfSSL: Failed to set cipher string '%s'",
+                   ciphers);
+        tls_deinit(sslCtx);
+        return NULL;
+    }
+
+    return sslCtx;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+    struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+    if (context != tls_global)
+        os_free(context);
+
+    wolfSSL_CTX_free((WOLFSSL_CTX*)ssl_ctx);
+
+    tlsRefCount--;
+    if (tlsRefCount == 0) {
+        wolfSSL_Cleanup();
+        os_free(tls_global);
+        tls_global = NULL;
+    }
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+#ifdef DEBUG_WOLFSSL
+#if 0
+    unsigned long err;
+    err = wolfSSL_ERR_peek_last_error_line(NULL, NULL);
+    if (err != 0) {
+        wpa_printf(MSG_INFO, "TLS - SSL error: %s",
+                   wolfSSL_ERR_error_string(err, NULL));
+        return 1;
+    }
+#endif
+#endif
+    return 0;
+}
+
+
+struct tls_connection* tls_connection_init(void *tls_ctx)
+{
+    WOLFSSL_CTX* sslCtx = (WOLFSSL_CTX*)tls_ctx;
+    struct tls_connection* conn;
+
+    wpa_printf(MSG_DEBUG, "SSL: connection init");
+
+    conn = os_zalloc(sizeof(*conn));
+    if (conn == NULL)
+        return NULL;
+    conn->ssl = wolfSSL_new(sslCtx);
+    if (conn->ssl == NULL) {
+        os_free(conn);
+        return NULL;
+    }
+
+    wolfSSL_SetIOReadCtx(conn->ssl,  &conn->input);
+    wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output);
+    wolfSSL_set_ex_data(conn->ssl, 0, conn);
+    conn->context = wolfSSL_CTX_get_ex_data(sslCtx, 0);
+
+    /* Need randoms post-hanshake for EAP-FAST, export key and deriving session
+     * ID in EAP method in EAP methodss.
+     */
+    wolfSSL_KeepArrays(conn->ssl);
+    wolfSSL_KeepHandshakeResources(conn->ssl);
+    wolfSSL_UseClientSuites(conn->ssl);
+
+    return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+    if (conn == NULL)
+        return;
+
+    wpa_printf(MSG_DEBUG, "SSL: connection deinit");
+
+    /* parts */
+    wolfSSL_free(conn->ssl);
+    os_free(conn->subjectMatch);
+    os_free(conn->altSubjectMatch);
+    os_free(conn->suffixMatch);
+    os_free(conn->domainMatch);
+
+    /* self */
+    os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+    return conn ? wolfSSL_is_init_finished(conn->ssl) : 0;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+    WOLFSSL_SESSION* session;
+
+    if (conn == NULL)
+        return -1;
+
+    wpa_printf(MSG_DEBUG, "SSL: connection shutdown");
+
+    /* Set quiet as OpenSSL does */
+    wolfSSL_set_quiet_shutdown(conn->ssl, 1);
+    wolfSSL_shutdown(conn->ssl);
+
+    session = wolfSSL_get_session(conn->ssl);
+    if (wolfSSL_clear(conn->ssl) != 1)
+        return -1;
+    wolfSSL_set_session(conn->ssl, session);
+
+    return 0;
+}
+
+
+static int tls_connection_set_subject_match(struct tls_connection *conn,
+                                            const char *subjectMatch,
+                                            const char *altSubjectMatch,
+                                            const char *suffixMatch,
+                                            const char *domainMatch)
+{
+        os_free(conn->subjectMatch);
+        conn->subjectMatch = NULL;
+        if (subjectMatch) {
+                conn->subjectMatch = os_strdup(subjectMatch);
+                if (conn->subjectMatch == NULL)
+                        return -1;
+        }
+
+        os_free(conn->altSubjectMatch);
+        conn->altSubjectMatch = NULL;
+        if (altSubjectMatch) {
+                conn->altSubjectMatch = os_strdup(altSubjectMatch);
+                if (conn->altSubjectMatch == NULL)
+                        return -1;
+        }
+
+        os_free(conn->suffixMatch);
+        conn->suffixMatch = NULL;
+        if (suffixMatch) {
+                conn->suffixMatch = os_strdup(suffixMatch);
+                if (conn->suffixMatch == NULL)
+                        return -1;
+        }
+
+        os_free(conn->domainMatch);
+        conn->domainMatch = NULL;
+        if (domainMatch) {
+                conn->domainMatch = os_strdup(domainMatch);
+                if (conn->domainMatch == NULL)
+                        return -1;
+        }
+
+        return 0;
+}
+
+
+static int tls_connection_dh(struct tls_connection* conn, const char* dh_file,
+                             const u8* dh_blob, size_t blob_len)
+{
+    if (dh_file == NULL && dh_blob == NULL)
+        return 0;
+
+    wolfSSL_set_accept_state(conn->ssl);
+
+    if (dh_blob) {
+        if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
+                                   SSL_FILETYPE_ASN1) < 0) {
+            wpa_printf(MSG_INFO, "SSL: use dh der blob failed");
+            return -1;
+        }
+        wpa_printf(MSG_DEBUG, "SSL: use dh blob OK");
+        return 0;
+    }
+
+    if (dh_file) {
+        wpa_printf(MSG_INFO, "SSL: use dh pem file: %s", dh_file);
+        if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file, SSL_FILETYPE_PEM) < 0) {
+            wpa_printf(MSG_INFO, "SSL: use dh pem file failed");
+            if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+                                            SSL_FILETYPE_ASN1) < 0) {
+                wpa_printf(MSG_INFO, "SSL: use dh der file failed");
+                return -1;
+            }
+        }
+        wpa_printf(MSG_DEBUG, "SSL: use dh file OK");
+        return 0;
+    }
+
+    return 0;
+}
+
+
+static int tls_connection_client_cert(struct tls_connection* conn,
+                                      const char* client_cert,
+                                      const u8*   client_cert_blob,
+                                      size_t      blob_len)
+{
+    if (client_cert == NULL && client_cert_blob == NULL)
+        return 0;
+
+    if (client_cert_blob) {
+        if (wolfSSL_use_certificate_buffer(conn->ssl, client_cert_blob, blob_len,
+                                          SSL_FILETYPE_ASN1) < 0) {
+            wpa_printf(MSG_INFO, "SSL: use client cert der blob failed");
+            return -1;
+        }
+        wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
+        return 0;
+    }
+
+    if (client_cert) {
+        if (wolfSSL_use_certificate_file(conn->ssl, client_cert,
+                                        SSL_FILETYPE_PEM) < 0) {
+            wpa_printf(MSG_INFO, "SSL: use client cert pem file failed");
+            if (wolfSSL_use_certificate_file(conn->ssl, client_cert,
+                                            SSL_FILETYPE_ASN1) < 0) {
+                wpa_printf(MSG_INFO, "SSL: use client cert der file failed");
+                return -1;
+            }
+        }
+        wpa_printf(MSG_DEBUG, "SSL: use client cert file OK");
+        return 0;
+    }
+
+    return 0;
+}
+
+
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+    if (password == NULL)
+        return 0;
+    os_strlcpy(buf, (char *) password, size);
+    return os_strlen(buf);
+}
+
+
+static int tls_connection_private_key(void* tls_ctx,
+                                      struct tls_connection *conn,
+                                      const char* private_key,
+                                      const char* private_key_passwd,
+                                      const u8*   private_key_blob,
+                                      size_t      blob_len)
+{
+    WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)tls_ctx;
+    char* passwd = NULL;
+    int   ok = 0;
+
+    if (private_key == NULL && private_key_blob == NULL)
+        return 0;
+
+    if (private_key_passwd) {
+        passwd = os_strdup(private_key_passwd);
+        if (passwd == NULL)
+            return -1;
+    }
+
+    wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+    wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+    if (private_key_blob) {
+        if (wolfSSL_use_PrivateKey_buffer(conn->ssl, private_key_blob, blob_len,
+                                         SSL_FILETYPE_ASN1) < 0) {
+            wpa_printf(MSG_INFO, "SSL: use private der blob failed");
+        }
+        else {
+            wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
+            ok = 1;
+        }
+    }
+
+    if (!ok && private_key) {
+        if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+                                       SSL_FILETYPE_PEM) < 0) {
+            wpa_printf(MSG_INFO, "SSL: use private key pem file failed");
+            if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+                                           SSL_FILETYPE_ASN1) < 0) {
+                wpa_printf(MSG_INFO, "SSL: use private key der file failed");
+            }
+            else
+                ok = 1;
+        }
+        else
+            ok = 1;
+
+        if (ok)
+            wpa_printf(MSG_DEBUG, "SSL: use private key file OK");
+    }
+
+    wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+    os_free(passwd);
+
+    if (!ok)
+        return -1;
+
+    return 0;
+}
+
+#define GEN_EMAIL	1
+#define GEN_DNS		ALT_NAMES_OID
+#define GEN_URI		6
+
+static int tls_match_altSubject_component(WOLFSSL_X509 *cert, int type,
+                                          const char *value, size_t len)
+{
+        WOLFSSL_ASN1_OBJECT *gen;
+        void *ext;
+        int found = 0;
+        int i;
+
+        ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+        for (i = 0; ext && i < wolfSSL_sk_num((void*)ext); i++) {
+                gen = wolfSSL_sk_value((void*)ext, i);
+                if (gen->type != type)
+                        continue;
+                if (os_strlen((char *) gen->obj) == len &&
+                    os_memcmp(value, gen->obj, len) == 0)
+                        found++;
+        }
+
+        wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+        return found;
+}
+
+
+static int tls_match_altSubject(WOLFSSL_X509 *cert, const char *match)
+{
+        int type;
+        const char *pos, *end;
+        size_t len;
+
+        pos = match;
+        do {
+                if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+                        type = GEN_EMAIL;
+                        pos += 6;
+                } else if (os_strncmp(pos, "DNS:", 4) == 0) {
+                        type = GEN_DNS;
+                        pos += 4;
+                } else if (os_strncmp(pos, "URI:", 4) == 0) {
+                        type = GEN_URI;
+                        pos += 4;
+                } else {
+                        wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
+                                   "match '%s'", pos);
+                        return 0;
+                }
+                end = os_strchr(pos, ';');
+                while (end) {
+                        if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+                            os_strncmp(end + 1, "DNS:", 4) == 0 ||
+                            os_strncmp(end + 1, "URI:", 4) == 0)
+                                break;
+                        end = os_strchr(end + 1, ';');
+                }
+                if (end)
+                        len = end - pos;
+                else
+                        len = os_strlen(pos);
+                if (tls_match_altSubject_component(cert, type, pos, len) > 0)
+                        return 1;
+                pos = end + 1;
+        } while (end);
+        return 0;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static int domain_suffix_match(const char *val, size_t len, const char *match,
+                               int full)
+{
+        size_t i, match_len;
+
+        /* Check for embedded nuls that could mess up suffix matching */
+        for (i = 0; i < len; i++) {
+                if (val[i] == '\0') {
+                        wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
+                        return 0;
+                }
+        }
+
+        match_len = os_strlen(match);
+        if (match_len > len || (full && match_len != len))
+                return 0;
+
+        if (os_strncasecmp(val + len - match_len, match,
+                           match_len) != 0)
+                return 0; /* no match */
+
+        if (match_len == len)
+                return 1; /* exact match */
+
+        if (val[len - match_len - 1] == '.')
+                return 1; /* full label match completes suffix match */
+
+        wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+        return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+        /* wincrypt.h has conflicting X509_NAME definition */
+        return -1;
+#else /* CONFIG_NATIVE_WINDOWS */
+        WOLFSSL_ASN1_OBJECT *gen;
+        void *ext;
+        int i;
+        int j;
+        int dns_name = 0;
+        WOLFSSL_X509_NAME *name;
+
+        wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+                   full ? "": "suffix ", match);
+
+        ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+        for (j = 0; ext && j < wolfSSL_sk_num((void*)ext); j++) {
+                gen = wolfSSL_sk_value((void*)ext, j);
+                if (gen->type != ALT_NAMES_OID)
+                        continue;
+                dns_name++;
+                wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
+                                  gen->obj, os_strlen((char *)gen->obj));
+                if (domain_suffix_match((const char*)gen->obj,
+                                        os_strlen((char *)gen->obj), match,
+                                        full) == 1) {
+                        wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+                                   full ? "Match" : "Suffix match");
+                        wolfSSL_sk_ASN1_OBJECT_free(ext);
+                        return 1;
+                }
+        }
+        wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+        if (dns_name) {
+                wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+                return 0;
+        }
+
+        name = wolfSSL_X509_get_subject_name(cert);
+        i = -1;
+        for (;;) {
+                WOLFSSL_X509_NAME_ENTRY *e;
+                WOLFSSL_ASN1_STRING *cn;
+
+                i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
+                                                       i);
+                if (i == -1)
+                        break;
+                e = wolfSSL_X509_NAME_get_entry(name, i);
+                if (e == NULL)
+                        continue;
+                cn = wolfSSL_X509_NAME_ENTRY_get_data(e);
+                if (cn == NULL)
+                        continue;
+                wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
+                                  cn->data, cn->length);
+                if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
+                {
+                        wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+                                   full ? "Match" : "Suffix match");
+                        return 1;
+                }
+        }
+
+        wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+                   full ? "": "suffix ");
+        return 0;
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+static enum tls_fail_reason wolfssl_tls_fail_reason(int err)
+{
+        switch (err) {
+        case X509_V_ERR_CERT_REVOKED:
+                return TLS_FAIL_REVOKED;
+        case ASN_BEFORE_DATE_E:
+        case X509_V_ERR_CERT_NOT_YET_VALID:
+        case X509_V_ERR_CRL_NOT_YET_VALID:
+                return TLS_FAIL_NOT_YET_VALID;
+        case ASN_AFTER_DATE_E:
+        case X509_V_ERR_CERT_HAS_EXPIRED:
+        case X509_V_ERR_CRL_HAS_EXPIRED:
+                return TLS_FAIL_EXPIRED;
+        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+        case X509_V_ERR_UNABLE_TO_GET_CRL:
+        case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+        case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+        case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+        case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+        case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+        case X509_V_ERR_INVALID_CA:
+                return TLS_FAIL_UNTRUSTED;
+        case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+        case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+        case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+        case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+        case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+        case X509_V_ERR_CERT_UNTRUSTED:
+        case X509_V_ERR_CERT_REJECTED:
+                return TLS_FAIL_BAD_CERTIFICATE;
+        default:
+                return TLS_FAIL_UNSPECIFIED;
+        }
+}
+
+static const char* wolfssl_tls_err_string(int err, const char *err_str)
+{
+        switch (err) {
+        case ASN_BEFORE_DATE_E:
+            return "certificate is not yet valid";
+        case ASN_AFTER_DATE_E:
+            return "certificate has expired";
+        default:
+            return err_str;
+        }
+}
+
+static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert)
+{
+        struct wpabuf *buf = NULL;
+        const u8 *data;
+        int cert_len;
+
+        data = wolfSSL_X509_get_der(cert, &cert_len);
+        if (data != NULL)
+            buf = wpabuf_alloc_copy(data, cert_len);
+
+        return buf;
+}
+
+static void wolfssl_tls_fail_event(struct tls_connection *conn,
+                                   WOLFSSL_X509 *err_cert, int err, int depth,
+                                   const char *subject, const char *err_str,
+                                   enum tls_fail_reason reason)
+{
+        union tls_event_data ev;
+        struct wpabuf *cert = NULL;
+        struct tls_context *context = conn->context;
+
+        if (context->event_cb == NULL)
+                return;
+
+        cert = get_x509_cert(err_cert);
+        os_memset(&ev, 0, sizeof(ev));
+        ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+                reason : wolfssl_tls_fail_reason(err);
+        ev.cert_fail.depth = depth;
+        ev.cert_fail.subject = subject;
+        ev.cert_fail.reason_txt = wolfssl_tls_err_string(err, err_str);
+        ev.cert_fail.cert = cert;
+        context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+        wpabuf_free(cert);
+}
+
+
+static void wolfssl_tls_cert_event(struct tls_connection *conn,
+                                   WOLFSSL_X509 *err_cert, int depth,
+                                   const char *subject)
+{
+        struct wpabuf *cert = NULL;
+        union tls_event_data ev;
+        struct tls_context *context = conn->context;
+        char *altSubject[TLS_MAX_ALT_SUBJECT];
+        int alt, num_altSubject = 0;
+        WOLFSSL_ASN1_OBJECT *gen;
+        void *ext;
+        int i;
+#ifdef CONFIG_SHA256
+        u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+        if (context->event_cb == NULL)
+                return;
+
+        os_memset(&ev, 0, sizeof(ev));
+        if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+            context->cert_in_cb) {
+                cert = get_x509_cert(err_cert);
+                ev.peer_cert.cert = cert;
+        }
+#ifdef CONFIG_SHA256
+        if (cert) {
+                const u8 *addr[1];
+                size_t len[1];
+                addr[0] = wpabuf_head(cert);
+                len[0] = wpabuf_len(cert);
+                if (sha256_vector(1, addr, len, hash) == 0) {
+                        ev.peer_cert.hash = hash;
+                        ev.peer_cert.hash_len = sizeof(hash);
+                }
+        }
+#endif /* CONFIG_SHA256 */
+        ev.peer_cert.depth = depth;
+        ev.peer_cert.subject = subject;
+
+        ext = wolfSSL_X509_get_ext_d2i(err_cert, ALT_NAMES_OID, NULL, NULL);
+        for (i = 0; ext && i < wolfSSL_sk_num((void*)ext); i++) {
+                char *pos;
+
+                if (num_altSubject == TLS_MAX_ALT_SUBJECT)
+                        break;
+                gen = wolfSSL_sk_value((void*)ext, i);
+#if 0
+                if (gen->type != GEN_EMAIL &&
+                    gen->type != GEN_DNS &&
+                    gen->type != GEN_URI)
+                        continue;
+#endif
+
+                pos = os_malloc(10 + os_strlen((char *)gen->obj) + 1);
+                if (pos == NULL)
+                        break;
+                altSubject[num_altSubject++] = pos;
+
+#if 0
+                switch (gen->type) {
+                case GEN_EMAIL:
+                        os_memcpy(pos, "EMAIL:", 6);
+                        pos += 6;
+                        break;
+                case GEN_DNS:
+                        os_memcpy(pos, "DNS:", 4);
+                        pos += 4;
+                        break;
+                case GEN_URI:
+                        os_memcpy(pos, "URI:", 4);
+                        pos += 4;
+                        break;
+                }
+#else
+                os_memcpy(pos, "DNS:", 4);
+                pos += 4;
+#endif
+
+                os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
+                pos += os_strlen((char *)gen->obj);
+                *pos = '\0';
+        }
+        wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+        for (alt = 0; alt < num_altSubject; alt++)
+                ev.peer_cert.altsubject[alt] = altSubject[alt];
+        ev.peer_cert.num_altsubject = num_altSubject;
+
+        context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+        wpabuf_free(cert);
+        for (alt = 0; alt < num_altSubject; alt++)
+                os_free(altSubject[alt]);
+}
+
+static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
+{
+        char buf[256];
+        WOLFSSL_X509 *err_cert;
+        int err, depth;
+        WOLFSSL *ssl;
+        struct tls_connection *conn;
+        struct tls_context *context;
+        char *match, *altmatch, *suffix_match, *domain_match;
+        const char *err_str;
+
+        err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
+        if (err_cert == NULL) {
+                wpa_printf(MSG_DEBUG, "wolfSSL: No Cert\n");
+                return 0;
+        }
+
+        err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
+        depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx);
+        ssl = wolfSSL_X509_STORE_CTX_get_ex_data(x509_ctx,
+                                      wolfSSL_get_ex_data_X509_STORE_CTX_idx());
+        wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf,
+                                  sizeof(buf));
+
+        conn = wolfSSL_get_ex_data(ssl, 0);
+        if (conn == NULL) {
+                wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data\n");
+                return 0;
+        }
+
+        if (depth == 0)
+                conn->peer_cert = err_cert;
+        else if (depth == 1)
+                conn->peer_issuer = err_cert;
+        else if (depth == 2)
+                conn->peer_issuer_issuer = err_cert;
+
+        context = conn->context;
+        match = conn->subjectMatch;
+        altmatch = conn->altSubjectMatch;
+        suffix_match = conn->suffixMatch;
+        domain_match = conn->domainMatch;
+
+        if (!preverify_ok && !conn->ca_cert_verify)
+                preverify_ok = 1;
+        if (!preverify_ok && depth > 0 && conn->server_cert_only)
+                preverify_ok = 1;
+        if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+            (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+             err == ASN_AFTER_DATE_E || err == ASN_BEFORE_DATE_E ||
+             err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+                wpa_printf(MSG_DEBUG, "wolfSSL: Ignore certificate validity "
+                           "time mismatch");
+                preverify_ok = 1;
+        }
+
+        err_str = wolfSSL_X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+        /*
+         * Do not require preverify_ok so we can explicity allow otherwise
+         * invalid pinned server certificates.
+         */
+        if (depth == 0 && conn->server_cert_only) {
+                struct wpabuf *cert;
+                cert = get_x509_cert(err_cert);
+                if (!cert) {
+                        wpa_printf(MSG_DEBUG, "wolfSSL: Could not fetch "
+                                   "server certificate data");
+                        preverify_ok = 0;
+                } else {
+                        u8 hash[32];
+                        const u8 *addr[1];
+                        size_t len[1];
+                        addr[0] = wpabuf_head(cert);
+                        len[0] = wpabuf_len(cert);
+                        if (sha256_vector(1, addr, len, hash) < 0 ||
+                            os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
+                                err_str = "Server certificate mismatch";
+                                err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+                                preverify_ok = 0;
+                        } else if (!preverify_ok) {
+                                /*
+                                 * Certificate matches pinned certificate, allow
+                                 * regardless of other problems.
+                                 */
+                                wpa_printf(MSG_DEBUG,
+                                           "wolfSSL: Ignore validation issues for a pinned server certificate");
+                                preverify_ok = 1;
+                        }
+                        wpabuf_free(cert);
+                }
+        }
+#endif /* CONFIG_SHA256 */
+
+        if (!preverify_ok) {
+                wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+                           " error %d (%s) depth %d for '%s'", err, err_str,
+                           depth, buf);
+                wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                       err_str, TLS_FAIL_UNSPECIFIED);
+                return preverify_ok;
+        }
+
+        wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
+                   "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+                   preverify_ok, err, err_str,
+                   conn->ca_cert_verify, depth, buf);
+        if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+                wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+                           "match with '%s'", buf, match);
+                preverify_ok = 0;
+                wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                       "Subject mismatch",
+                                       TLS_FAIL_SUBJECT_MISMATCH);
+        } else if (depth == 0 && altmatch &&
+                   !tls_match_altSubject(err_cert, altmatch)) {
+                wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+                           "'%s' not found", altmatch);
+                preverify_ok = 0;
+                wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                       "AltSubject mismatch",
+                                       TLS_FAIL_ALTSUBJECT_MISMATCH);
+        } else if (depth == 0 && suffix_match &&
+                   !tls_match_suffix(err_cert, suffix_match, 0)) {
+                wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
+                           suffix_match);
+                preverify_ok = 0;
+                wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                       "Domain suffix mismatch",
+                                       TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+        } else if (depth == 0 && domain_match &&
+                   !tls_match_suffix(err_cert, domain_match, 1)) {
+                wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+                           domain_match);
+                preverify_ok = 0;
+                wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                       "Domain mismatch",
+                                       TLS_FAIL_DOMAIN_MISMATCH);
+        } else
+                wolfssl_tls_cert_event(conn, err_cert, depth, buf);
+
+        if (conn->cert_probe && preverify_ok && depth == 0) {
+                wpa_printf(MSG_DEBUG, "wolfSSL: Reject server certificate "
+                           "on probe-only run");
+                preverify_ok = 0;
+                wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                       "Server certificate chain probe",
+                                       TLS_FAIL_SERVER_CHAIN_PROBE);
+        }
+
+#ifdef HAVE_OCSP_OPENSSL
+        if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+            preverify_ok) {
+                enum ocsp_result res;
+
+                res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+                                      conn->peer_issuer,
+                                      conn->peer_issuer_issuer);
+                if (res == OCSP_REVOKED) {
+                        preverify_ok = 0;
+                        wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                               "certificate revoked",
+                                               TLS_FAIL_REVOKED);
+                        if (err == X509_V_OK)
+                                X509_STORE_CTX_set_error(
+                                        x509_ctx, X509_V_ERR_CERT_REVOKED);
+                } else if (res != OCSP_GOOD &&
+                           (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+                        preverify_ok = 0;
+                        wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                               "bad certificate status response",
+                                               TLS_FAIL_UNSPECIFIED);
+                }
+        }
+#endif /* HAVE_OCSP */
+        if (depth == 0 && preverify_ok && context->event_cb != NULL)
+                context->event_cb(context->cb_ctx,
+                                  TLS_CERT_CHAIN_SUCCESS, NULL);
+
+        return preverify_ok;
+}
+
+static int tls_connection_ca_cert(void* tls_ctx, struct tls_connection *conn,
+                                  const char* ca_cert,
+                                  const u8*   ca_cert_blob, size_t blob_len,
+                                  const char *ca_path)
+{
+    WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)tls_ctx;
+
+    wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+    conn->ca_cert_verify = 1;
+
+    if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+        wpa_printf(MSG_DEBUG, "wolfSSL: Probe for server certificate chain");
+        conn->cert_probe = 1;
+        conn->ca_cert_verify = 0;
+        return 0;
+    }
+
+    if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
+#ifdef CONFIG_SHA256
+        const char *pos = ca_cert + 7;
+        if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+            wpa_printf(MSG_DEBUG, "wolfSSL: Unsupported ca_cert "
+                       "hash value '%s'", ca_cert);
+            return -1;
+        }
+        pos += 14;
+        if (os_strlen(pos) != 32 * 2) {
+            wpa_printf(MSG_DEBUG, "wolfSSL: Unexpected SHA256 "
+                       "hash length in ca_cert '%s'", ca_cert);
+            return -1;
+        }
+        if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
+            wpa_printf(MSG_DEBUG, "wolfSSL: Invalid SHA256 hash "
+                       "value in ca_cert '%s'", ca_cert);
+            return -1;
+        }
+        conn->server_cert_only = 1;
+        wpa_printf(MSG_DEBUG, "wolfSSL: Checking only server "
+                   "certificate match");
+        return 0;
+#else /* CONFIG_SHA256 */
+        wpa_printf(MSG_INFO, "No SHA256 included in the build - "
+                   "cannot validate server certificate hash");
+        return -1;
+#endif /* CONFIG_SHA256 */
+    }
+
+    if (ca_cert_blob) {
+        if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len, 
+                                           SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
+            wpa_printf(MSG_INFO, "SSL: failed to load ca blob"); 
+            return -1;
+        }
+        wpa_printf(MSG_DEBUG, "SSL: use ca cert blob OK");
+        return 0;
+
+    }
+
+    if (ca_cert || ca_path) {
+        WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new();
+        if (cm == NULL) {
+            wpa_printf(MSG_INFO, "SSL: failed to create certificate store");
+            return -1;
+        }
+        wolfSSL_CTX_set_cert_store(ctx, cm);
+        XFREE(cm, NULL, DYNAMIC_TYPE_X509_STORE);
+
+        if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path)
+                                            != SSL_SUCCESS) {
+            wpa_printf(MSG_INFO, "SSL: failed to load ca_cert as pem");
+
+            if (ca_cert) {
+                if (wolfSSL_CTX_der_load_verify_locations(ctx, ca_cert, 
+                                           SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
+                    wpa_printf(MSG_INFO, "SSL: failed to load ca_cert as der");
+                    return -1;
+                }
+            }
+            else
+                return -1;
+        }
+        return 0;
+    }
+
+    conn->ca_cert_verify = 0;
+    return 0;
+}
+
+static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
+{
+#ifdef HAVE_SESSION_TICKET
+#if 0
+    if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
+        wolfSSL_UseSessionTicket(ssl);
+#endif
+#endif /* HAVE_SESSION_TICKET */
+
+    if (flags & TLS_CONN_DISABLE_TLSv1_0)
+        wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1);
+    if (flags & TLS_CONN_DISABLE_TLSv1_1)
+        wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+    if (flags & TLS_CONN_DISABLE_TLSv1_2)
+        wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+}
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+                              const struct tls_connection_params *params)
+{
+    wpa_printf(MSG_DEBUG, "SSL: set params");
+
+    if (tls_connection_set_subject_match(conn, params->subject_match,
+                                         params->altsubject_match,
+                                         params->suffix_match,
+                                         params->domain_match) < 0) {
+        wpa_printf(MSG_INFO, "Error setting subject match");
+        return -1;
+    }
+
+    if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+                               params->ca_cert_blob, params->ca_cert_blob_len,
+                               params->ca_path) < 0) {
+        wpa_printf(MSG_INFO, "Error setting ca cert");
+        return -1;
+    }
+
+    if (tls_connection_client_cert(conn, params->client_cert,
+                                   params->client_cert_blob,
+                                   params->client_cert_blob_len) < 0) {
+        wpa_printf(MSG_INFO, "Error setting client cert");
+        return -1;
+    }
+
+    if (tls_connection_private_key(tls_ctx, conn, params->private_key,
+                                   params->private_key_passwd,
+                                   params->private_key_blob,
+                                   params->private_key_blob_len) < 0) {
+        wpa_printf(MSG_INFO, "Error setting private key");
+        return -1;
+    }
+
+    if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
+                          params->dh_blob_len) < 0) {
+        wpa_printf(MSG_INFO, "Error setting dh");
+        return -1;
+    }
+
+    if (params->openssl_ciphers && wolfSSL_set_cipher_list(conn->ssl,
+                                                params->openssl_ciphers) != 1) {
+        wpa_printf(MSG_INFO, "wolfSSL: Failed to set cipher string '%s'",
+                   params->openssl_ciphers);
+        return -1;
+    }
+
+    tls_set_conn_flags(conn->ssl, params->flags);
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+    if (params->flags & TLS_CONN_REQUEST_OCSP) {
+        if (wolfSSL_UseOCSPStapling(conn->ssl, WOLFSSL_CSR_OCSP,
+                                    WOLFSSL_CSR_OCSP_USE_NONCE) != SSL_SUCCESS)
+            return -1;
+        wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+    }
+#endif
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+    if (params->flags & TLS_CONN_REQUEST_OCSP) {
+        if (wolfSSL_UseOCSPStaplingV2(conn->ssl, WOLFSSL_CSR2_OCSP_MULTI, 0)
+                                                               != SSL_SUCCESS) {
+            return -1;
+        }
+        wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+    }
+#endif
+#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
+    !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+#ifdef HAVE_OCSP
+    if (params->flags & TLS_CONN_REQUEST_OCSP) {
+        wolfSSL_CTX_EnableOCSP(ctx, 0);
+    }
+#else /* HAVE_OCSP */
+    if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+        wpa_printf(MSG_INFO,
+                   "wolfSSL: No OCSP support included - reject configuration");
+            return -1;
+    }
+    if (params->flags & TLS_CONN_REQUEST_OCSP) {
+        wpa_printf(MSG_DEBUG,
+                   "wolfSSL: No OCSP support included - allow optional OCSP "
+                   "case to continue");
+        }
+#endif /* HAVE_OCSP */
+#endif /* !HAVE_CERTIFICATE_STATUS_REQUEST &&
+        * !HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+    conn->flags = params->flags;
+
+    return 0;
+}
+
+
+static int tls_global_ca_cert(void* ssl_ctx, const char* ca_cert)
+{
+    WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx;
+
+    if (ca_cert) {
+        if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1) {
+            wpa_printf(MSG_WARNING, "Failed to load root certificates");
+            return -1;
+        }
+
+        wpa_printf(MSG_DEBUG, "TLS: Trusted root certificate(s) loaded");
+    }
+
+    return 0;
+}
+
+
+static int tls_global_client_cert(void* ssl_ctx, const char* client_cert)
+{
+    WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx;
+
+    if (client_cert == NULL)
+        return 0;
+
+    if (wolfSSL_CTX_use_certificate_file(ctx, client_cert,
+                                         SSL_FILETYPE_ASN1) != SSL_SUCCESS &&
+        wolfSSL_CTX_use_certificate_file(ctx, client_cert,
+                                         SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+        wpa_printf(MSG_INFO, "Failed to load client certificate");
+        return -1;
+    }
+    wpa_printf(MSG_DEBUG, "SSL: Loaded global client certificate: %s", client_cert);
+
+    return 0;
+}
+
+
+static int tls_global_private_key(void* ssl_ctx, const char* private_key,
+                                  const char* private_key_passwd)
+{
+    WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx;
+    char* passwd = NULL;
+    int   ret = 0;
+
+    if (private_key == NULL)
+        return 0;
+
+    if (private_key_passwd) {
+        passwd = os_strdup(private_key_passwd);
+        if (passwd == NULL)
+            return -1;
+    }
+
+    wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+    wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+    if (wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+                                        SSL_FILETYPE_ASN1) != 1 &&
+        wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+                                        SSL_FILETYPE_PEM) != 1 ) {
+        wpa_printf(MSG_INFO, "Failed to load private key");
+        ret = -1;
+    }
+    wpa_printf(MSG_DEBUG, "SSL: Loaded global private key");
+
+    os_free(passwd);
+    wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+        
+    return ret;
+}
+
+
+static int tls_global_dh(void* ssl_ctx, const char* dh_file,
+                         const u8* dh_blob, size_t blob_len)
+{
+    WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx;
+
+    if (dh_file == NULL && dh_blob == NULL)
+        return 0;
+
+    if (dh_blob) {
+        if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
+                                       SSL_FILETYPE_ASN1) < 0) {
+            wpa_printf(MSG_INFO, "SSL: global use dh der blob failed");
+            return -1;
+        }
+        wpa_printf(MSG_DEBUG, "SSL: global use dh blob OK");
+        return 0;
+    }
+
+    if (dh_file) {
+        if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) < 0) {
+            wpa_printf(MSG_INFO, "SSL: global use dh pem file failed");
+            if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file,
+                                            SSL_FILETYPE_ASN1) < 0) {
+                wpa_printf(MSG_INFO, "SSL: global use dh der file failed");
+                return -1;
+            }
+        }
+        wpa_printf(MSG_DEBUG, "SSL: global use dh file OK");
+        return 0;
+    }
+
+    return 0;
+}
+
+#ifdef HAVE_OCSP
+int ocsp_status_cb(void* unused, const char* url, int urlSz,
+                   unsigned char* request, int requestSz,
+                   unsigned char** response)
+{
+    size_t len;
+
+    (void)unused;
+
+    if (url == NULL) {
+            wpa_printf(MSG_DEBUG, "wolfSSL: OCSP status callback - no response "
+                                  "configured");
+            *response = NULL;
+            return 0;
+    }
+
+    *response = (unsigned char*)os_readfile(url, &len);
+    if (*response == NULL) {
+        wpa_printf(MSG_DEBUG, "wolfSSL: OCSP status callback - could not read "
+                              "response file");
+        return -1;
+    }
+    wpa_printf(MSG_DEBUG, "wolfSSL: OCSP status callback - send cached "
+                          "response");
+    return len;
+}
+
+void ocsp_resp_free_cb(void* ocsp_stapling_response, unsigned char* response)
+{
+    os_free(response);
+}
+#endif
+
+int tls_global_set_params(void* tls_ctx,
+                                     const struct tls_connection_params* params)
+{
+    wpa_printf(MSG_DEBUG, "SSL: global set params");
+
+    if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
+        wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
+                   params->ca_cert);
+        return -1;
+    }
+
+    if (tls_global_client_cert(tls_ctx, params->client_cert) < 0) {
+        wpa_printf(MSG_INFO, "SSL: Failed to load client cert file '%s'",
+                   params->client_cert);
+        return -1;
+    }
+
+    if (tls_global_private_key(tls_ctx, params->private_key,
+                               params->private_key_passwd) < 0) {
+        wpa_printf(MSG_INFO, "SSL: Failed to load private key file '%s'",
+                   params->private_key);
+        return -1;
+    }
+
+    if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
+                      params->dh_blob_len) < 0) {
+        wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
+                   params->dh_file);
+        return -1;
+    }
+
+    if (params->openssl_ciphers && wolfSSL_CTX_set_cipher_list(tls_ctx,
+                                                params->openssl_ciphers) != 1) {
+        wpa_printf(MSG_INFO, "wolfSSL: Failed to set cipher string '%s'",
+                   params->openssl_ciphers);
+        return -1;
+    }
+
+#ifdef HAVE_SESSION_TICKET
+    /* Session ticket is off by default - can't disable once on. */
+    if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
+        wolfSSL_CTX_UseSessionTicket(tls_ctx);
+#endif
+
+#ifdef HAVE_OCSP
+    if (params->ocsp_stapling_response) {
+        wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx,
+                                        params->ocsp_stapling_response);
+        wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb, ocsp_resp_free_cb,
+                               NULL);
+    }
+#endif
+
+    return 0;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+    wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
+
+    if (check_crl) {
+        /* Hack to Enable CRLs. */
+        wolfSSL_CTX_LoadCRLBuffer((WOLFSSL_CTX*)tls_ctx, NULL, 0,
+                                  SSL_FILETYPE_PEM);
+    }
+    return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+                              int verify_peer, unsigned int flags,
+                              const u8 *session_ctx, size_t session_ctx_len)
+{
+    if (conn == NULL)
+            return -1;
+
+    wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer);
+
+    if (verify_peer) {
+        conn->ca_cert_verify = 1;
+        wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER | 
+                                      SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+                           tls_verify_cb);
+    }
+    else {
+        conn->ca_cert_verify = 0;
+        wolfSSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+    }
+
+    wolfSSL_set_accept_state(conn->ssl);
+
+    /* do we need to fake a session like OpenSSL does here ? */
+
+    return 0;
+}
+
+
+static struct wpabuf* wolfssl_handshake(struct tls_connection *conn,
+                                        const struct wpabuf *in_data,
+                                        int server)
+{
+    int res;
+
+    ResetOutData(&conn->output);
+
+    /* Initiate TLS handshake or continue the existing handshake */
+    if (server) {
+            wolfSSL_set_accept_state(conn->ssl);
+            res = wolfSSL_accept(conn->ssl);
+            wpa_printf(MSG_DEBUG, "SSL: wolfSSL_accept: %d", res);
+    }
+    else {
+            wolfSSL_set_connect_state(conn->ssl);
+            res = wolfSSL_connect(conn->ssl);
+            wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res);
+    }
+    if (res != 1) {
+        int err = wolfSSL_get_error(conn->ssl, res);
+        if (err == SSL_ERROR_WANT_READ)
+            wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect - want more data");
+        else if (err == SSL_ERROR_WANT_WRITE)
+            wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect - want to write");
+        else {
+            char msg[80];
+            wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect - failed %s",
+                       wolfSSL_ERR_error_string(err, msg));
+            conn->failed++;
+        }
+    }
+
+    return conn->output.out_data;
+}
+
+
+static struct wpabuf* wolfssl_get_appl_data(struct tls_connection *conn,
+                                            size_t max_len)
+{
+    int res;
+    struct wpabuf* appl_data = wpabuf_alloc(max_len + 100);
+
+    if (appl_data == NULL)
+        return NULL;
+
+    res = wolfSSL_read(conn->ssl, wpabuf_mhead(appl_data),
+                       wpabuf_size(appl_data));
+    if (res < 0) {
+        int err = wolfSSL_get_error(conn->ssl, res);
+        if (err == SSL_ERROR_WANT_READ ||
+            err == SSL_ERROR_WANT_WRITE) {
+                wpa_printf(MSG_DEBUG, "SSL: No Application Data included");
+        } else {
+            char msg[80];
+            wpa_printf(MSG_DEBUG, "Failed to read possible Application Data %s",
+                       wolfSSL_ERR_error_string(err, msg));
+        }
+
+        wpabuf_free(appl_data);
+        return NULL;
+    }
+
+    wpabuf_put(appl_data, res);
+    wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
+                                     "message", appl_data);
+    return appl_data;
+}
+
+
+
+
+static struct wpabuf* wolfssl_connection_handshake(struct tls_connection* conn,
+            const struct wpabuf* in_data, struct wpabuf** appl_data, int server)
+{
+    struct wpabuf* out_data;
+
+    ResetInData(&conn->input, in_data);
+
+    if (appl_data)
+        *appl_data = NULL;
+
+    out_data = wolfssl_handshake(conn, in_data, server);
+    if (out_data == NULL)
+        return NULL;
+
+    if (wolfSSL_is_init_finished(conn->ssl)) {
+        wpa_printf(MSG_DEBUG, "wolfSSL: Handshake finished - resumed=%d",
+                   tls_connection_resumed(NULL, conn));
+        if (appl_data && in_data)
+            *appl_data = wolfssl_get_appl_data(conn, wpabuf_len(in_data));
+    }
+
+    return out_data;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+                                         struct tls_connection *conn,
+                                         const struct wpabuf *in_data,
+                                         struct wpabuf **appl_data)
+{
+    return wolfssl_connection_handshake(conn, in_data, appl_data, 0);
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+                                                struct tls_connection *conn,
+                                                const struct wpabuf *in_data,
+                                                struct wpabuf **appl_data)
+{
+    return wolfssl_connection_handshake(conn, in_data, appl_data, 1);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+                                       struct tls_connection *conn,
+                                       const struct wpabuf *in_data)
+{
+    int res;
+
+    if (conn == NULL)
+            return NULL;
+
+    wpa_printf(MSG_DEBUG, "SSL: encrypt: %ld bytes", wpabuf_len(in_data));
+
+    ResetOutData(&conn->output);
+
+    res = wolfSSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
+    if (res < 0) {
+    int  err = wolfSSL_get_error(conn->ssl, res);
+    char msg[80];
+            wpa_printf(MSG_INFO, "Encryption failed - SSL_write: %s",
+                         wolfSSL_ERR_error_string(err, msg));
+            return NULL;
+    }
+
+    return conn->output.out_data;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+                                       struct tls_connection *conn,
+                                       const struct wpabuf *in_data)
+{
+    int res;
+    struct wpabuf *buf;
+
+    if (conn == NULL)
+            return NULL;
+
+    wpa_printf(MSG_DEBUG, "SSL: decrypt");
+
+    ResetInData(&conn->input, in_data);
+
+    /* Read decrypted data for further processing */
+    /*
+     * Even though we try to disable TLS compression, it is possible that
+     * this cannot be done with all TLS libraries. Add extra buffer space
+     * to handle the possibility of the decrypted data being longer than
+     * input data.
+     */
+    buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+    if (buf == NULL)
+            return NULL;
+    res = wolfSSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
+    if (res < 0) {
+            wpa_printf(MSG_INFO, "Decryption failed - SSL_read");
+            wpabuf_free(buf);
+            return NULL;
+    }
+    wpabuf_put(buf, res);
+
+    wpa_printf(MSG_DEBUG, "SSL: decrypt: %ld bytes", wpabuf_len(buf));
+
+    return buf;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+    return conn ? wolfSSL_session_reused(conn->ssl) : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *ciphers)
+{
+    char buf[128], *pos, *end;
+    u8 *c;
+    int ret;
+
+    if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
+            return -1;
+
+    buf[0] = '\0';
+    pos = buf;
+    end = pos + sizeof(buf);
+
+    c = ciphers;
+    while (*c != TLS_CIPHER_NONE) {
+            const char *suite;
+
+            switch (*c) {
+            case TLS_CIPHER_RC4_SHA:
+                    suite = "RC4-SHA";
+                    break;
+            case TLS_CIPHER_AES128_SHA:
+                    suite = "AES128-SHA";
+                    break;
+            case TLS_CIPHER_RSA_DHE_AES128_SHA:
+                    suite = "DHE-RSA-AES128-SHA";
+                    break;
+            case TLS_CIPHER_ANON_DH_AES128_SHA:
+                    suite = "ADH-AES128-SHA";
+                    break;
+            case TLS_CIPHER_RSA_DHE_AES256_SHA:
+                    suite = "DHE-RSA-AES256-SHA";
+                    break;
+            case TLS_CIPHER_AES256_SHA:
+                    suite = "AES256-SHA";
+                    break;
+            default:
+                    wpa_printf(MSG_DEBUG, "TLS: Unsupported "
+                               "cipher selection: %d", *c);
+                    return -1;
+            }
+            ret = os_snprintf(pos, end - pos, ":%s", suite);
+            if (ret < 0 || ret >= end - pos)
+                    break;
+            pos += ret;
+
+            c++;
+    }
+
+    wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1);
+
+    if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
+        wpa_printf(MSG_DEBUG, "Cipher suite configuration failed");
+            return -1;
+    }
+
+    return 0;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+                   char *buf, size_t buflen)
+{
+    WOLFSSL_CIPHER* cipher;
+    const char*    name;
+
+    if (conn == NULL || conn->ssl == NULL)
+        return -1;
+
+    cipher = wolfSSL_get_current_cipher(conn->ssl);
+    if (cipher == NULL)
+        return -1;
+
+    name = wolfSSL_CIPHER_get_name(cipher);
+    if (name == NULL)
+        return -1;
+
+    if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0)
+        os_strlcpy(buf, "RC4-SHA", buflen);
+    else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0)
+        os_strlcpy(buf, "AES128-SHA", buflen);
+    else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0)
+        os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen);
+    else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0)
+        os_strlcpy(buf, "ADH-AES128-SHA", buflen);
+    else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0)
+        os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen);
+    else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0)
+        os_strlcpy(buf, "AES256-SHA", buflen);
+    else
+        os_strlcpy(buf, name, buflen);
+
+    return 0;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+                                     struct tls_connection *conn)
+{
+    /* no empty fragments in wolfSSL for now */
+    return 0;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+    if (conn == NULL)
+        return -1;
+
+    return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+    if (conn == NULL)
+        return -1;
+
+    return conn->readAlerts;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+                                    struct tls_connection *conn)
+{
+    if (conn == NULL)
+        return -1;
+
+    return conn->writeAlerts;
+}
+
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+    return os_snprintf(buf, buf_len, "wolfSSL build=%s run=%s", WOLFSSL_VERSION,
+                       wolfSSL_lib_version());
+}
+
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+                    char *buf, size_t buflen)
+{
+    const char *name;
+    if (conn == NULL || conn->ssl == NULL)
+            return -1;
+
+    name = wolfSSL_get_version(conn->ssl);
+    if (name == NULL)
+            return -1;
+
+    os_strlcpy(buf, name, buflen);
+    return 0;
+}
+
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+                              struct tls_random *keys)
+{
+    WOLFSSL *ssl;
+
+    if (conn == NULL || keys == NULL)
+            return -1;
+    ssl = conn->ssl;
+    if (ssl == NULL)
+            return -1;
+
+    os_memset(keys, 0, sizeof(*keys));
+    keys->client_random = conn->client_random;
+    keys->client_random_len = wolfSSL_get_client_random(
+            ssl, conn->client_random, sizeof(conn->client_random));
+    keys->server_random = conn->server_random;
+    keys->server_random_len = wolfSSL_get_server_random(
+            ssl, conn->server_random, sizeof(conn->server_random));
+
+    return 0;
+}
+
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                              const char *label, u8 *out, size_t out_len)
+{
+    if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+            return -1;
+    return 0;
+}
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                    u8 *out, size_t out_len)
+{
+    int ret;
+
+    if (conn == NULL || conn->ssl == NULL)
+        return -1;
+
+    ret = wolfSSL_make_eap_keys(conn->ssl, out, out_len, "key expansion");
+    if (ret != 0)
+        return -1;
+    return 0;
+}
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+                                    int ext_type, const u8 *data,
+                                    size_t data_len)
+{
+    (void)ssl_ctx;
+
+    if (conn == NULL || conn->ssl == NULL || ext_type != 35)
+        return -1;
+
+    if (wolfSSL_set_SessionTicket(conn->ssl, data, (unsigned int)data_len) != 1)
+        return -1;
+
+    return 0;
+}
+
+static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
+{
+    struct tls_connection *conn = arg;
+    int ret;
+    unsigned char client_random[RAN_LEN];
+    unsigned char server_random[RAN_LEN];
+    word32 ticketLen = (word32)sizeof(conn->session_ticket);
+
+    if (conn == NULL || conn->session_ticket_cb == NULL)
+        return 1;
+
+    if (wolfSSL_get_client_random(s, client_random, sizeof(client_random)) == 0)
+        return 1;
+    if (wolfSSL_get_server_random(s, server_random, sizeof(server_random)) == 0)
+        return 1;
+    if (wolfSSL_get_SessionTicket(s, conn->session_ticket, &ticketLen) != 1)
+        return 1;
+
+    if (ticketLen == 0)
+        return 0;
+
+    ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+                                  conn->session_ticket, ticketLen,
+                                  client_random, server_random, secret);
+    if (ret <= 0)
+        return 1;
+
+    *secret_len = SECRET_LEN;
+    return 0;
+}
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+                                         struct tls_connection *conn,
+                                         tls_session_ticket_cb cb,
+                                         void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+    conn->session_ticket_cb = cb;
+    conn->session_ticket_cb_ctx = ctx;
+
+    if (cb) {
+        if (wolfSSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+                                          conn) != 1)
+            return -1;
+    } else {
+        if (wolfSSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+            return -1;
+    }
+
+    return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+    return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+    wpa_printf(MSG_DEBUG, "wolfSSL: Success data accepted for resumed session");
+}
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+    WOLFSSL_SESSION *sess;
+
+    sess = wolfSSL_get_session(conn->ssl);
+    if (!sess)
+        return;
+
+    wolfSSL_SSL_SESSION_set_timeout(sess, 0);
+    wpa_printf(MSG_DEBUG, "wolfSSL: Removed cached session to disable session "
+                          "resumption");
+}
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+                                     struct wpabuf *data)
+{
+    WOLFSSL_SESSION *sess;
+    struct wpabuf *old;
+
+    wpa_printf(MSG_DEBUG, "wolfSSL: Set success data");
+
+    sess = wolfSSL_get_session(conn->ssl);
+    if (sess == NULL) {
+        wpa_printf(MSG_DEBUG, "wolfSSL: No session found for success data");
+        goto fail;
+    }
+    old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+    if (old) {
+        wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p", old);
+        wpabuf_free(old);
+    }
+    if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+        goto fail;
+
+    wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data);
+    conn->success_data = 1;
+    return;
+
+fail:
+    wpa_printf(MSG_INFO, "wolfSSL: Failed to store success data");
+    wpabuf_free(data);
+}
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+    WOLFSSL_SESSION *sess;
+
+    wpa_printf(MSG_DEBUG, "wolfSSL: Get success data");
+
+    if ((sess = wolfSSL_get_session(conn->ssl)) == NULL)
+       return NULL;
+    return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
+
+
diff --git a/tests/hwsim/example-hostapd.config b/tests/hwsim/example-hostapd.config
index 71a2070..2333585 100644
--- a/tests/hwsim/example-hostapd.config
+++ b/tests/hwsim/example-hostapd.config
@@ -1,5 +1,9 @@ 
 #CC=ccache gcc
 
+#CFLAGS += -L/usr/local/include/wolfssl
+#LIBS += -L/usr/local/lib
+
+
 CONFIG_DRIVER_NONE=y
 CONFIG_DRIVER_NL80211=y
 CONFIG_RSN_PREAUTH=y
@@ -8,6 +12,7 @@  CONFIG_RSN_PREAUTH=y
 #CONFIG_INTERNAL_LIBTOMMATH=y
 #CONFIG_INTERNAL_LIBTOMMATH_FAST=y
 CONFIG_TLS=openssl
+#CONFIG_TLS=wolfssl
 
 CONFIG_EAP=y
 CONFIG_ERP=y
diff --git a/tests/hwsim/example-wpa_supplicant.config b/tests/hwsim/example-wpa_supplicant.config
index 4587cf7..a30b7ac 100644
--- a/tests/hwsim/example-wpa_supplicant.config
+++ b/tests/hwsim/example-wpa_supplicant.config
@@ -1,6 +1,10 @@ 
 #CC=ccache gcc
 
+#CFLAGS += -L/usr/local/include/wolfssl
+#LIBS += -L/usr/local/lib
+
 CONFIG_TLS=openssl
+#CONFIG_TLS=wolfssl
 #CONFIG_TLS=internal
 #CONFIG_INTERNAL_LIBTOMMATH=y
 #CONFIG_INTERNAL_LIBTOMMATH_FAST=y
diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py
index 818e341..983a850 100644
--- a/tests/hwsim/test_ap_eap.py
+++ b/tests/hwsim/test_ap_eap.py
@@ -40,12 +40,12 @@  def check_eap_capa(dev, method):
 
 def check_subject_match_support(dev):
     tls = dev.request("GET tls_library")
-    if not tls.startswith("OpenSSL"):
+    if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
         raise HwsimSkip("subject_match not supported with this TLS library: " + tls)
 
 def check_altsubject_match_support(dev):
     tls = dev.request("GET tls_library")
-    if not tls.startswith("OpenSSL"):
+    if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
         raise HwsimSkip("altsubject_match not supported with this TLS library: " + tls)
 
 def check_domain_match(dev):
@@ -60,7 +60,7 @@  def check_domain_suffix_match(dev):
 
 def check_domain_match_full(dev):
     tls = dev.request("GET tls_library")
-    if not tls.startswith("OpenSSL"):
+    if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
         raise HwsimSkip("domain_suffix_match requires full match with this TLS library: " + tls)
 
 def check_cert_probe_support(dev):
@@ -99,6 +99,8 @@  def check_pkcs12_support(dev):
     tls = dev.request("GET tls_library")
     #if tls.startswith("internal"):
     #    raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls)
+    if tls.startswith("wolfSSL"):
+        raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls)
 
 def check_dh_dsa_support(dev):
     tls = dev.request("GET tls_library")
@@ -2906,7 +2908,11 @@  def test_ap_wpa2_eap_ikev2_oom(dev, apdev):
                 time.sleep(0.02)
             dev[0].request("REMOVE_NETWORK all")
 
-    tests = [ (1, "os_get_random;dh_init") ]
+    tls = dev[0].request("GET tls_library")
+    if not tls.startswith("wolfSSL"):
+        tests = [ (1, "os_get_random;dh_init") ]
+    else:
+        tests = [ (1, "crypto_dh_init;dh_init") ]
     for count, func in tests:
         with fail_test(dev[0], count, func):
             dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="IKEV2",
@@ -3620,8 +3626,8 @@  def test_ap_wpa2_eap_fast_cipher_suites(dev, apdev):
     """EAP-FAST and different TLS cipher suites"""
     check_eap_capa(dev[0], "FAST")
     tls = dev[0].request("GET tls_library")
-    if not tls.startswith("OpenSSL"):
-        raise HwsimSkip("TLS library is not OpenSSL: " + tls)
+    if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"):
+        raise HwsimSkip("TLS library is not OpenSSL or wolfSSL: " + tls)
 
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hapd = hostapd.add_ap(apdev[0], params)
@@ -3826,6 +3832,7 @@  def int_eap_server_params():
 def test_ap_wpa2_eap_tls_ocsp_key_id(dev, apdev, params):
     """EAP-TLS and OCSP certificate signed OCSP response using key ID"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     ocsp = os.path.join(params['logdir'], "ocsp-server-cache-key-id.der")
     if not os.path.exists(ocsp):
         raise HwsimSkip("No OCSP response available")
@@ -3841,6 +3848,7 @@  def test_ap_wpa2_eap_tls_ocsp_key_id(dev, apdev, params):
 def test_ap_wpa2_eap_tls_ocsp_ca_signed_good(dev, apdev, params):
     """EAP-TLS and CA signed OCSP response (good)"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed.der")
     if not os.path.exists(ocsp):
         raise HwsimSkip("No OCSP response available")
@@ -3856,6 +3864,7 @@  def test_ap_wpa2_eap_tls_ocsp_ca_signed_good(dev, apdev, params):
 def test_ap_wpa2_eap_tls_ocsp_ca_signed_revoked(dev, apdev, params):
     """EAP-TLS and CA signed OCSP response (revoked)"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed-revoked.der")
     if not os.path.exists(ocsp):
         raise HwsimSkip("No OCSP response available")
@@ -3887,6 +3896,7 @@  def test_ap_wpa2_eap_tls_ocsp_ca_signed_revoked(dev, apdev, params):
 def test_ap_wpa2_eap_tls_ocsp_ca_signed_unknown(dev, apdev, params):
     """EAP-TLS and CA signed OCSP response (unknown)"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed-unknown.der")
     if not os.path.exists(ocsp):
         raise HwsimSkip("No OCSP response available")
@@ -3916,6 +3926,7 @@  def test_ap_wpa2_eap_tls_ocsp_ca_signed_unknown(dev, apdev, params):
 def test_ap_wpa2_eap_tls_ocsp_server_signed(dev, apdev, params):
     """EAP-TLS and server signed OCSP response"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     ocsp = os.path.join(params['logdir'], "ocsp-resp-server-signed.der")
     if not os.path.exists(ocsp):
         raise HwsimSkip("No OCSP response available")
@@ -3945,6 +3956,7 @@  def test_ap_wpa2_eap_tls_ocsp_server_signed(dev, apdev, params):
 def test_ap_wpa2_eap_tls_ocsp_invalid_data(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and invalid OCSP data"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = "auth_serv/ocsp-req.der"
     hostapd.add_ap(apdev[0], params)
@@ -3971,6 +3983,7 @@  def test_ap_wpa2_eap_tls_ocsp_invalid_data(dev, apdev):
 def test_ap_wpa2_eap_tls_ocsp_invalid(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and invalid OCSP response"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = "auth_serv/ocsp-server-cache.der-invalid"
     hostapd.add_ap(apdev[0], params)
@@ -3997,6 +4010,7 @@  def test_ap_wpa2_eap_tls_ocsp_invalid(dev, apdev):
 def test_ap_wpa2_eap_tls_ocsp_unknown_sign(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and unknown OCSP signer"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = "auth_serv/ocsp-server-cache.der-unknown-sign"
     hostapd.add_ap(apdev[0], params)
@@ -4096,7 +4110,7 @@  def test_ap_wpa2_eap_ttls_optional_ocsp_unknown(dev, apdev, params):
 def test_ap_wpa2_eap_tls_intermediate_ca(dev, apdev, params):
     """EAP-TLS with intermediate server/user CA"""
     params = int_eap_server_params()
-    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem"
     params["server_cert"] = "auth_serv/iCA-server/server.pem"
     params["private_key"] = "auth_serv/iCA-server/server.key"
     hostapd.add_ap(apdev[0], params)
@@ -4201,7 +4215,7 @@  def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_sha1(dev, apdev, params):
 
 def run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, md):
     params = int_eap_server_params()
-    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem"
     params["server_cert"] = "auth_serv/iCA-server/server.pem"
     params["private_key"] = "auth_serv/iCA-server/server.key"
     fn = ica_ocsp("server.pem", md)
@@ -4236,7 +4250,7 @@  def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked_sha1(dev, apdev, params):
 
 def run_ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked(dev, apdev, params, md):
     params = int_eap_server_params()
-    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem"
     params["server_cert"] = "auth_serv/iCA-server/server-revoked.pem"
     params["private_key"] = "auth_serv/iCA-server/server-revoked.key"
     fn = ica_ocsp("server-revoked.pem", md)
@@ -4286,7 +4300,7 @@  def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi_missing_resp(dev, apdev, par
     check_ocsp_multi_support(dev[0])
 
     params = int_eap_server_params()
-    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem"
     params["server_cert"] = "auth_serv/iCA-server/server.pem"
     params["private_key"] = "auth_serv/iCA-server/server.key"
     fn = ica_ocsp("server.pem")
@@ -4336,7 +4350,7 @@  def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi(dev, apdev, params):
     check_ocsp_multi_support(dev[0])
 
     params = int_eap_server_params()
-    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem"
     params["server_cert"] = "auth_serv/iCA-server/server.pem"
     params["private_key"] = "auth_serv/iCA-server/server.key"
     fn = ica_ocsp("server.pem")
@@ -4384,6 +4398,7 @@  def test_ap_wpa2_eap_tls_ocsp_multi_revoked(dev, apdev, params):
     """EAP-TLS and CA signed OCSP multi response (revoked)"""
     check_ocsp_support(dev[0])
     check_ocsp_multi_support(dev[0])
+    check_pkcs12_support(dev[0])
 
     ocsp_revoked = os.path.join(params['logdir'],
                                 "ocsp-resp-ca-signed-revoked.der")
@@ -4443,6 +4458,7 @@  def test_ap_wpa2_eap_tls_ocsp_multi_revoked(dev, apdev, params):
 def test_ap_wpa2_eap_tls_domain_suffix_match_cn_full(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain suffix match (CN)"""
     check_domain_match_full(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
@@ -4457,6 +4473,7 @@  def test_ap_wpa2_eap_tls_domain_suffix_match_cn_full(dev, apdev):
 def test_ap_wpa2_eap_tls_domain_match_cn(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domainmatch (CN)"""
     check_domain_match(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
@@ -4471,6 +4488,7 @@  def test_ap_wpa2_eap_tls_domain_match_cn(dev, apdev):
 def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain suffix match (CN)"""
     check_domain_match_full(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
@@ -4485,6 +4503,7 @@  def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev):
 def test_ap_wpa2_eap_tls_domain_suffix_mismatch_cn(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain suffix mismatch (CN)"""
     check_domain_suffix_match(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
@@ -4513,6 +4532,7 @@  def test_ap_wpa2_eap_tls_domain_suffix_mismatch_cn(dev, apdev):
 def test_ap_wpa2_eap_tls_domain_mismatch_cn(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain mismatch (CN)"""
     check_domain_match(dev[0])
+    check_pkcs12_support(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
@@ -5304,6 +5324,11 @@  def test_ap_wpa2_eap_tls_versions(dev, apdev):
             check_tls_ver(dev[0], hapd,
                           "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1",
                           "TLSv1.2")
+    if tls.startswith("wolfSSL"):
+        if "build=3.10.0" in tls and "run=3.10.0" in tls:
+            check_tls_ver(dev[0], hapd,
+                          "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1",
+                          "TLSv1.2")
     elif tls.startswith("internal"):
         check_tls_ver(dev[0], hapd,
                       "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", "TLSv1.2")
@@ -5351,7 +5376,7 @@  def test_rsn_ie_proto_eap_sta(dev, apdev):
 def check_tls_session_resumption_capa(dev, hapd):
     tls = hapd.request("GET tls_library")
     if not tls.startswith("OpenSSL"):
-        raise HwsimSkip("hostapd TLS library is not OpenSSL: " + tls)
+        raise HwsimSkip("hostapd TLS library is not OpenSSL or wolfSSL: " + tls)
 
     tls = dev.request("GET tls_library")
     if not tls.startswith("OpenSSL"):
@@ -5497,6 +5522,7 @@  def test_eap_ttls_no_session_resumption(dev, apdev):
 
 def test_eap_peap_session_resumption(dev, apdev):
     """EAP-PEAP session resumption"""
+    check_eap_capa(dev[0], "MSCHAPV2")
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
     hapd = hostapd.add_ap(apdev[0], params)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 4431755..efa9b90 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -93,8 +93,12 @@  endif
 
 ifdef CONFIG_FIPS
 CONFIG_NO_RANDOM_POOL=
+ifeq ($(CONFIG_TLS), wolfssl)
+CONFIG_WOLFSSL_CMAC=y
+else
 CONFIG_OPENSSL_CMAC=y
 endif
+endif
 
 OBJS = config.o
 OBJS += notify.o
@@ -709,6 +713,9 @@  endif
 
 ifdef CONFIG_EAP_PWD
 CFLAGS += -DEAP_PWD
+ifeq ($(CONFIG_TLS), wolfssl)
+CFLAGS += -DCONFIG_ECC
+endif
 OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
 CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
@@ -1054,6 +1061,22 @@  CFLAGS += -DCONFIG_TLSV12
 NEED_SHA256=y
 endif
 
+ifeq ($(CONFIG_TLS), wolfssl)
+CONFIG_WOLFSSL_CMAC=y
+CFLAGS += -DCRYPTO_ABSTRACT_API
+ifdef TLS_FUNCS
+CFLAGS += -DWOLFSSL_DER_LOAD -I/usr/local/include/wolfssl
+OBJS += ../src/crypto/tls_wolfssl.o
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+OBJS_p += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+LIBS += -lwolfssl -lm
+LIBS_p += -lwolfssl -lm
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 CFLAGS += -DEAP_TLS_OPENSSL
@@ -1274,8 +1297,10 @@  AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o
 endif
 
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 NEED_INTERNAL_AES_WRAP=y
 endif
+endif
 ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP
 # Seems to be needed at least with BoringSSL
 NEED_INTERNAL_AES_WRAP=y
@@ -1314,10 +1339,21 @@  ifdef CONFIG_OPENSSL_CMAC
 CFLAGS += -DCONFIG_OPENSSL_CMAC
 else
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-omac1.o
 endif
 endif
 endif
+ifdef CONFIG_WOLFSSL_CMAC
+CFLAGS += -DCONFIG_WOLFSSL_CMAC
+else
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
+AESOBJS += ../src/crypto/aes-omac1.o
+endif
+endif
+endif
+endif
 ifdef NEED_AES_WRAP
 NEED_AES_ENC=y
 ifdef NEED_INTERNAL_AES_WRAP
@@ -1328,10 +1364,12 @@  ifdef NEED_AES_CBC
 NEED_AES_ENC=y
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-cbc.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_ENC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += ../src/crypto/aes-internal-enc.o
@@ -1345,10 +1383,12 @@  ifdef NEED_SHA1
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1.o
 endif
 endif
 endif
+endif
 SHA1OBJS += ../src/crypto/sha1-prf.o
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += ../src/crypto/sha1-internal.o
@@ -1360,9 +1400,11 @@  ifdef CONFIG_NO_WPA_PASSPHRASE
 CFLAGS += -DCONFIG_NO_PBKDF2
 else
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
 endif
 endif
+endif
 ifdef NEED_T_PRF
 SHA1OBJS += ../src/crypto/sha1-tprf.o
 endif
@@ -1375,11 +1417,13 @@  ifndef CONFIG_FIPS
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 MD5OBJS += ../src/crypto/md5.o
 endif
 endif
 endif
 endif
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += ../src/crypto/md5-internal.o
@@ -1397,6 +1441,9 @@  endif
 
 DESOBJS = # none needed when not internal
 ifdef NEED_DES
+ifndef CONFIG_FIPS
+CFLAGS += -DCONFIG_DES
+endif
 ifdef CONFIG_INTERNAL_DES
 DESOBJS += ../src/crypto/des-internal.o
 endif
@@ -1420,10 +1467,12 @@  CFLAGS += -DCONFIG_SHA256
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA256OBJS += ../src/crypto/sha256.o
 endif
 endif
 endif
+endif
 SHA256OBJS += ../src/crypto/sha256-prf.o
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += ../src/crypto/sha256-internal.o
@@ -1457,10 +1506,12 @@  ifdef NEED_SHA384
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha384.o
 endif
 endif
 endif
+endif
 CFLAGS += -DCONFIG_SHA384
 OBJS += ../src/crypto/sha384-prf.o
 endif
@@ -1668,9 +1719,11 @@  endif
 ifdef CONFIG_FIPS
 CFLAGS += -DCONFIG_FIPS
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 $(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
 endif
 endif
+endif
 
 OBJS += $(SHA1OBJS) $(DESOBJS)