diff --git a/hostapd/defconfig b/hostapd/defconfig
index 666447e4a..fd139eb93 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -269,6 +269,7 @@ CONFIG_IPV6=y
 # gnutls = GnuTLS
 # internal = Internal TLSv1 implementation (experimental)
 # linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
+# mbedtls = Mbed TLS
 # none = Empty template
 #CONFIG_TLS=openssl
 
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index eb600699d..4384fa67a 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -756,6 +756,8 @@ size_t crypto_ec_prime_len(struct crypto_ec *e);
  */
 size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
 
+int crypto_bignum_bits(const struct crypto_bignum *a);
+
 /**
  * crypto_ec_order_len - Get length of the order in octets
  * @e: EC context from crypto_ec_init()
diff --git a/src/crypto/crypto_mbedtls-bignum.c b/src/crypto/crypto_mbedtls-bignum.c
new file mode 100644
index 000000000..e9087b62b
--- /dev/null
+++ b/src/crypto/crypto_mbedtls-bignum.c
@@ -0,0 +1,310 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "crypto.h"
+#include "random.h"
+#include "sha256.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/ctr_drbg.h"
+
+static int f_rng(void *p_rng, unsigned char *buf, size_t len)
+{
+	return random_get_bytes(buf, len);
+}
+
+struct crypto_bignum *crypto_bignum_init(void)
+{
+
+	mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi));
+	if (bn == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate BN\n", __func__);
+		return NULL;
+	}
+
+	mbedtls_mpi_init(bn);
+
+	return (struct crypto_bignum *)bn;
+}
+
+struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+	int ret = 0;
+	mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi));
+	if (bn == NULL) {
+		return NULL;
+	}
+
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(bn, buf, len));
+	return (struct crypto_bignum *)bn;
+
+cleanup:
+	os_free(bn);
+	return NULL;
+}
+
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+	return mbedtls_mpi_random(
+	    (mbedtls_mpi *)r, 0, (mbedtls_mpi *)m, f_rng, NULL);
+}
+
+struct crypto_bignum *crypto_bignum_init_uint(unsigned int val)
+{
+	return crypto_bignum_init_set((const u8 *)&val, sizeof(val));
+}
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+	mbedtls_mpi_free((mbedtls_mpi *)n);
+	os_free((mbedtls_mpi *)n);
+}
+
+int crypto_bignum_to_bin(
+    const struct crypto_bignum *a, u8 *buf, size_t buflen, size_t padlen)
+{
+	int num_bytes, offset;
+	int ret;
+
+	if (padlen > buflen) {
+		return -1;
+	}
+
+	num_bytes = mbedtls_mpi_size((mbedtls_mpi *)a);
+
+	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);
+	MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(
+	    (mbedtls_mpi *)a, buf + offset,
+	    mbedtls_mpi_size((mbedtls_mpi *)a)));
+
+	return num_bytes + offset;
+cleanup:
+	return ret;
+}
+
+int crypto_bignum_add(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    struct crypto_bignum *c)
+{
+	return mbedtls_mpi_add_mpi(
+		   (mbedtls_mpi *)c, (const mbedtls_mpi *)a,
+		   (const mbedtls_mpi *)b)
+		   ? -1
+		   : 0;
+}
+
+int crypto_bignum_mod(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    struct crypto_bignum *c)
+{
+	return mbedtls_mpi_mod_mpi(
+		   (mbedtls_mpi *)c, (const mbedtls_mpi *)a,
+		   (const mbedtls_mpi *)b)
+		   ? -1
+		   : 0;
+}
+
+int crypto_bignum_exptmod(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    const struct crypto_bignum *c, struct crypto_bignum *d)
+{
+	return mbedtls_mpi_exp_mod(
+		   (mbedtls_mpi *)d, (const mbedtls_mpi *)a,
+		   (const mbedtls_mpi *)b, (const mbedtls_mpi *)c, NULL)
+		   ? -1
+		   : 0;
+}
+
+int crypto_bignum_inverse(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    struct crypto_bignum *c)
+{
+	return mbedtls_mpi_inv_mod(
+		   (mbedtls_mpi *)c, (const mbedtls_mpi *)a,
+		   (const mbedtls_mpi *)b)
+		   ? -1
+		   : 0;
+}
+
+int crypto_bignum_sub(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    struct crypto_bignum *c)
+{
+	return mbedtls_mpi_sub_mpi(
+		   (mbedtls_mpi *)c, (const mbedtls_mpi *)a,
+		   (const mbedtls_mpi *)b)
+		   ? -1
+		   : 0;
+}
+
+int crypto_bignum_div(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    struct crypto_bignum *c)
+{
+	return mbedtls_mpi_div_mpi(
+		   (mbedtls_mpi *)c, NULL, (const mbedtls_mpi *)a,
+		   (const mbedtls_mpi *)b)
+		   ? -1
+		   : 0;
+}
+
+int crypto_bignum_mulmod(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    const struct crypto_bignum *c, struct crypto_bignum *d)
+{
+	int res;
+
+	mbedtls_mpi temp;
+	mbedtls_mpi_init(&temp);
+
+	res = mbedtls_mpi_mul_mpi(
+	    &temp, (const mbedtls_mpi *)a, (const mbedtls_mpi *)b);
+	if (res) {
+		return -1;
+	}
+
+	res = mbedtls_mpi_mod_mpi((mbedtls_mpi *)d, &temp, (mbedtls_mpi *)c);
+	mbedtls_mpi_free(&temp);
+#
+	return res ? -1 : 0;
+}
+
+int crypto_bignum_cmp(
+    const struct crypto_bignum *a, const struct crypto_bignum *b)
+{
+	return mbedtls_mpi_cmp_mpi(
+	    (const mbedtls_mpi *)a, (const mbedtls_mpi *)b);
+}
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+	return mbedtls_mpi_bitlen((const mbedtls_mpi *)a);
+}
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+	return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 0) == 0);
+}
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+	return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 1) == 0);
+}
+
+int crypto_bignum_sqrmod(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    struct crypto_bignum *c)
+{
+	return mbedtls_mpi_exp_mod(
+	    (mbedtls_mpi *)c, (mbedtls_mpi *)a, (mbedtls_mpi *)a,
+	    (mbedtls_mpi *)b, NULL);
+}
+
+int crypto_bignum_rshift(
+    const struct crypto_bignum *a, int n, struct crypto_bignum *r)
+{
+
+	if (mbedtls_mpi_copy((mbedtls_mpi *)r, (const mbedtls_mpi *)a)) {
+		return -1;
+	}
+	return mbedtls_mpi_shift_r((mbedtls_mpi *)&r, n);
+}
+
+int crypto_bignum_legendre(
+    const struct crypto_bignum *a, const struct crypto_bignum *p)
+{
+	mbedtls_mpi exp, tmp;
+	int res = -2, ret;
+
+	mbedtls_mpi_init(&exp);
+	mbedtls_mpi_init(&tmp);
+
+	/* exp = (p-1) / 2 */
+	MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *)p, 1));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 1));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(
+	    &tmp, (const mbedtls_mpi *)a, &exp, (const mbedtls_mpi *)p, NULL));
+
+	if (mbedtls_mpi_cmp_int(&tmp, 1) == 0) {
+		res = 1;
+	} else if (
+	    mbedtls_mpi_cmp_int(&tmp, 0) == 0
+	    /* The below check is workaround for the case where HW
+	     * does not behave properly for X ^ A mod M when X is
+	     * power of M. Instead of returning value 0, value M is
+	     * returned.*/
+	    || mbedtls_mpi_cmp_mpi(&tmp, (const mbedtls_mpi *)p) == 0) {
+		res = 0;
+	} else {
+		res = -1;
+	}
+
+cleanup:
+	mbedtls_mpi_free(&tmp);
+	mbedtls_mpi_free(&exp);
+	return res;
+}
+
+int crypto_bignum_to_string(
+    const struct crypto_bignum *a, u8 *buf, size_t buflen, size_t padlen)
+{
+	int num_bytes, offset;
+	size_t outlen;
+
+	if (padlen > buflen) {
+		return -1;
+	}
+
+	num_bytes = mbedtls_mpi_size((mbedtls_mpi *)a);
+
+	if (padlen > (size_t)num_bytes) {
+		offset = padlen - num_bytes;
+	} else {
+		offset = 0;
+	}
+
+	os_memset(buf, 0, offset);
+	mbedtls_mpi_write_string(
+	    (mbedtls_mpi *)a, 16, (char *)(buf + offset),
+	    mbedtls_mpi_size((mbedtls_mpi *)a), &outlen);
+
+	return outlen;
+}
+
+int crypto_bignum_addmod(
+    const struct crypto_bignum *a, const struct crypto_bignum *b,
+    const struct crypto_bignum *c, struct crypto_bignum *d)
+{
+	struct crypto_bignum *tmp = crypto_bignum_init();
+	int ret = -1;
+
+	if (mbedtls_mpi_add_mpi(
+		(mbedtls_mpi *)tmp, (const mbedtls_mpi *)b,
+		(const mbedtls_mpi *)c) < 0)
+		goto fail;
+
+	if (mbedtls_mpi_mod_mpi(
+		(mbedtls_mpi *)a, (const mbedtls_mpi *)tmp,
+		(const mbedtls_mpi *)d) < 0)
+		goto fail;
+
+	ret = 0;
+fail:
+	crypto_bignum_deinit(tmp, 0);
+	return ret;
+}
+
+void crypto_free_buffer(unsigned char *buf) { os_free(buf); }
diff --git a/src/crypto/crypto_mbedtls-ec.c b/src/crypto/crypto_mbedtls-ec.c
new file mode 100644
index 000000000..3c61808f6
--- /dev/null
+++ b/src/crypto/crypto_mbedtls-ec.c
@@ -0,0 +1,935 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "crypto.h"
+#include "sha256.h"
+#include "crypto/random.h"
+
+#include "mbedtls/ecp.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+
+#include "mbedtls/pk.h"
+#include "mbedtls/ecdh.h"
+#include "mbedtls/sha256.h"
+#include "mbedtls/asn1write.h"
+#include "mbedtls/error.h"
+#include "mbedtls/oid.h"
+#define IANA_SECP256R1 19
+#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES
+
+#ifdef CONFIG_ECC
+static int f_rng(void *p_rng, unsigned char *buf, size_t len)
+{
+	return random_get_bytes(buf, len);
+}
+struct crypto_ec
+{
+	mbedtls_ecp_group group;
+};
+
+int crypto_rng_wrapper(void *ctx, unsigned char *buf, size_t len)
+{
+	return random_get_bytes(buf, len);
+}
+
+const struct crypto_bignum *crypto_ec_get_a(struct crypto_ec *e)
+{
+	return (const struct crypto_bignum *)&e->group.A;
+}
+
+const struct crypto_bignum *crypto_ec_get_b(struct crypto_ec *e)
+{
+	return (const struct crypto_bignum *)&e->group.B;
+}
+
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+	return (mbedtls_mpi_bitlen(&e->group.N) + 7) / 8;
+}
+
+struct crypto_ec *crypto_ec_init(int group)
+{
+	struct crypto_ec *e;
+
+	mbedtls_ecp_group_id grp_id;
+
+	/* IANA registry to mbedtls internal mapping*/
+	switch (group) {
+	case IANA_SECP256R1:
+		/* For now just support NIST-P256.
+		 * This is of type "short Weierstrass".
+		 */
+		grp_id = MBEDTLS_ECP_DP_SECP256R1;
+		break;
+	default:
+		return NULL;
+	}
+	e = os_zalloc(sizeof(*e));
+	if (e == NULL) {
+		return NULL;
+	}
+
+	mbedtls_ecp_group_init(&e->group);
+
+	if (mbedtls_ecp_group_load(&e->group, grp_id)) {
+		crypto_ec_deinit(e);
+		e = NULL;
+	}
+
+	return e;
+}
+
+void crypto_ec_deinit(struct crypto_ec *e)
+{
+	if (e == NULL) {
+		return;
+	}
+
+	mbedtls_ecp_group_free(&e->group);
+	os_free(e);
+}
+
+struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e)
+{
+	mbedtls_ecp_point *pt;
+	if (e == NULL) {
+		return NULL;
+	}
+
+	pt = os_zalloc(sizeof(mbedtls_ecp_point));
+
+	if (pt == NULL) {
+		return NULL;
+	}
+
+	mbedtls_ecp_point_init(pt);
+
+	return (struct crypto_ec_point *)pt;
+}
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+	return mbedtls_mpi_size(&e->group.P);
+}
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+	return mbedtls_mpi_bitlen(&e->group.P);
+}
+struct crypto_ec_group *crypto_ec_get_group_byname(const char *name)
+{
+	struct crypto_ec *e;
+	const mbedtls_ecp_curve_info *curve =
+	    mbedtls_ecp_curve_info_from_name(name);
+
+	e = os_zalloc(sizeof(*e));
+	if (e == NULL) {
+		return NULL;
+	}
+
+	mbedtls_ecp_group_init(&e->group);
+
+	if (mbedtls_ecp_group_load(&e->group, curve->MBEDTLS_PRIVATE(grp_id))) {
+		crypto_ec_deinit(e);
+		e = NULL;
+	}
+
+	return (struct crypto_ec_group *)&e->group;
+}
+
+const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e)
+{
+	return (const struct crypto_bignum *)&e->group.P;
+}
+
+const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e)
+{
+	return (const struct crypto_bignum *)&e->group.N;
+}
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+	mbedtls_ecp_point_free((mbedtls_ecp_point *)p);
+	os_free(p);
+}
+
+int crypto_ec_point_to_bin(
+    struct crypto_ec *e, const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+	int len = mbedtls_mpi_size(&e->group.P);
+
+	if (x) {
+		if (crypto_bignum_to_bin(
+			(struct crypto_bignum *)&((mbedtls_ecp_point *)point)
+			    ->MBEDTLS_PRIVATE(X),
+			x, len, len) < 0) {
+			return -1;
+		}
+	}
+
+	if (y) {
+		if (crypto_bignum_to_bin(
+			(struct crypto_bignum *)&((mbedtls_ecp_point *)point)
+			    ->MBEDTLS_PRIVATE(Y),
+			y, len, len) < 0) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int crypto_ec_get_affine_coordinates(
+    struct crypto_ec *e, struct crypto_ec_point *pt, struct crypto_bignum *x,
+    struct crypto_bignum *y)
+{
+	int ret = -1;
+	mbedtls_ecp_point *point = (mbedtls_ecp_point *)pt;
+
+	if (!mbedtls_ecp_is_zero(point) &&
+	    (mbedtls_mpi_cmp_int(&point->MBEDTLS_PRIVATE(Z), 1) == 0)) {
+		// Affine coordinates mean that z should be 1,
+		wpa_printf(MSG_ERROR, "Z coordinate is neither 0 or 1");
+		return -1;
+	}
+
+	if (x) {
+		MBEDTLS_MPI_CHK(mbedtls_mpi_copy(
+		    (mbedtls_mpi *)x,
+		    &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(X)));
+	}
+	if (y) {
+		MBEDTLS_MPI_CHK(mbedtls_mpi_copy(
+		    (mbedtls_mpi *)y,
+		    &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(Y)));
+	}
+	return 0;
+cleanup:
+	return ret;
+}
+
+int crypto_ec_point_x(
+    struct crypto_ec *e, const struct crypto_ec_point *p,
+    struct crypto_bignum *x)
+{
+	int ret;
+
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(
+	    (mbedtls_mpi *)x, &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X)));
+
+	return 0;
+cleanup:
+	return ret;
+}
+
+struct crypto_ec_point *
+crypto_ec_point_from_bin(struct crypto_ec *e, const u8 *val)
+{
+	mbedtls_ecp_point *pt;
+	int len, ret;
+
+	if (e == NULL) {
+		return NULL;
+	}
+
+	len = mbedtls_mpi_size(&e->group.P);
+
+	pt = os_zalloc(sizeof(mbedtls_ecp_point));
+	if (!pt) {
+		return NULL;
+	}
+	mbedtls_ecp_point_init(pt);
+
+	MBEDTLS_MPI_CHK(
+	    mbedtls_mpi_read_binary(&pt->MBEDTLS_PRIVATE(X), val, len));
+	MBEDTLS_MPI_CHK(
+	    mbedtls_mpi_read_binary(&pt->MBEDTLS_PRIVATE(Y), val + len, len));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_lset((&pt->MBEDTLS_PRIVATE(Z)), 1));
+
+	return (struct crypto_ec_point *)pt;
+
+cleanup:
+	mbedtls_ecp_point_free(pt);
+	os_free(pt);
+	return NULL;
+}
+
+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)
+{
+	int ret;
+	mbedtls_mpi one;
+
+	mbedtls_mpi_init(&one);
+
+	MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
+	MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(
+	    &e->group, (mbedtls_ecp_point *)c, &one,
+	    (const mbedtls_ecp_point *)a, &one, (const mbedtls_ecp_point *)b));
+
+cleanup:
+	mbedtls_mpi_free(&one);
+	return ret ? -1 : 0;
+}
+
+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;
+	mbedtls_entropy_context entropy;
+	mbedtls_ctr_drbg_context ctr_drbg;
+
+	mbedtls_entropy_init(&entropy);
+	mbedtls_ctr_drbg_init(&ctr_drbg);
+
+	MBEDTLS_MPI_CHK(mbedtls_ctr_drbg_seed(
+	    &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0));
+
+	MBEDTLS_MPI_CHK(mbedtls_ecp_mul(
+	    &e->group, (mbedtls_ecp_point *)res, (const mbedtls_mpi *)b,
+	    (const mbedtls_ecp_point *)p, mbedtls_ctr_drbg_random, &ctr_drbg));
+cleanup:
+	mbedtls_ctr_drbg_free(&ctr_drbg);
+	mbedtls_entropy_free(&entropy);
+	return ret ? -1 : 0;
+}
+
+/*  Currently mbedtls does not have any function for inverse
+ *  This function calculates inverse of a point.
+ *  Set R = -P
+ */
+static int ecp_opp(
+    const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+    const mbedtls_ecp_point *P)
+{
+	int ret = 0;
+
+	/* Copy */
+	if (R != P) {
+		MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P));
+	}
+
+	/* In-place opposite */
+	if (mbedtls_mpi_cmp_int(&R->MBEDTLS_PRIVATE(Y), 0) != 0) {
+		MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(
+		    &R->MBEDTLS_PRIVATE(Y), &grp->P, &R->MBEDTLS_PRIVATE(Y)));
+	}
+
+cleanup:
+	return (ret);
+}
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+	return ecp_opp(
+		   &e->group, (mbedtls_ecp_point *)p, (mbedtls_ecp_point *)p)
+		   ? -1
+		   : 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)
+{
+	mbedtls_mpi temp;
+	mbedtls_mpi *y_sqr, *y;
+	mbedtls_mpi_init(&temp);
+	int ret = 0;
+
+	y = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y);
+
+	/* Faster way to find sqrt
+	 * Works only with curves having prime p
+	 * such that p ≡ 3 (mod 4)
+	 *  y_ = (y2 ^ ((p+1)/4)) mod p
+	 *
+	 *  if LSB of both x and y are same: y = y_
+	 *   else y = p - y_
+	 * y_bit is LSB of x
+	 */
+	y_bit = (y_bit != 0);
+
+	y_sqr = (mbedtls_mpi *)crypto_ec_point_compute_y_sqr(e, x);
+
+	if (y_sqr) {
+
+		MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&temp, &e->group.P, 1));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(&temp, NULL, &temp, 4));
+		MBEDTLS_MPI_CHK(
+		    mbedtls_mpi_exp_mod(y, y_sqr, &temp, &e->group.P, NULL));
+
+		if (y_bit != mbedtls_mpi_get_bit(y, 0))
+			MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y));
+
+		MBEDTLS_MPI_CHK(mbedtls_mpi_copy(
+		    &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X),
+		    (const mbedtls_mpi *)x));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_lset(
+		    &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Z), 1));
+	} else {
+		ret = 1;
+	}
+cleanup:
+	mbedtls_mpi_free(&temp);
+	mbedtls_mpi_free(y_sqr);
+	os_free(y_sqr);
+	return ret ? -1 : 0;
+}
+
+int crypto_get_order(struct crypto_ec_group *group, struct crypto_bignum *x)
+{
+	return mbedtls_mpi_copy(
+	    (mbedtls_mpi *)x, &((mbedtls_ecp_group *)group)->N);
+}
+
+struct crypto_bignum *crypto_ec_point_compute_y_sqr(
+    struct crypto_ec *e, const struct crypto_bignum *x)
+{
+	mbedtls_mpi temp, temp2, num;
+	int ret = 0;
+
+	mbedtls_mpi *y_sqr = os_zalloc(sizeof(mbedtls_mpi));
+	if (y_sqr == NULL) {
+		return NULL;
+	}
+
+	mbedtls_mpi_init(&temp);
+	mbedtls_mpi_init(&temp2);
+	mbedtls_mpi_init(&num);
+	mbedtls_mpi_init(y_sqr);
+
+	/* y^2 = x^3 + ax + b  mod  P*/
+	/* mbedtls does not have mod-add or mod-mul apis.
+	 *
+	 */
+
+	/* Calculate x^3  mod P*/
+	MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, 3));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(
+	    &temp, (const mbedtls_mpi *)x, &num, &e->group.P, NULL));
+
+	/* Calculate ax  mod P*/
+	MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, -3));
+	MBEDTLS_MPI_CHK(
+	    mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *)x, &num));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P));
+
+	/* Calculate ax + b  mod P. Note that b is already < P*/
+	MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &e->group.B));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P));
+
+	/* Calculate x^3 + ax + b  mod P*/
+	MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &temp));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(y_sqr, &temp2, &e->group.P));
+
+cleanup:
+	mbedtls_mpi_free(&temp);
+	mbedtls_mpi_free(&temp2);
+	mbedtls_mpi_free(&num);
+	if (ret) {
+		mbedtls_mpi_free(y_sqr);
+		os_free(y_sqr);
+		return NULL;
+	} else {
+		return (struct crypto_bignum *)y_sqr;
+	}
+}
+
+int crypto_ec_point_is_at_infinity(
+    struct crypto_ec *e, const struct crypto_ec_point *p)
+{
+	return mbedtls_ecp_is_zero((mbedtls_ecp_point *)p);
+}
+
+int crypto_ec_point_is_on_curve(
+    struct crypto_ec *e, const struct crypto_ec_point *p)
+{
+	mbedtls_mpi y_sqr_lhs, *y_sqr_rhs = NULL, two;
+	int ret = 0, on_curve = 0;
+
+	mbedtls_mpi_init(&y_sqr_lhs);
+	mbedtls_mpi_init(&two);
+
+	/* Calculate y^2  mod P*/
+	MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&two, 2));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(
+	    &y_sqr_lhs, &((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y),
+	    &two, &e->group.P, NULL));
+
+	y_sqr_rhs = (mbedtls_mpi *)crypto_ec_point_compute_y_sqr(
+	    e, (const struct crypto_bignum *)&((const mbedtls_ecp_point *)p)
+		   ->MBEDTLS_PRIVATE(X));
+
+	if (y_sqr_rhs && (mbedtls_mpi_cmp_mpi(y_sqr_rhs, &y_sqr_lhs) == 0)) {
+		on_curve = 1;
+	}
+
+cleanup:
+	mbedtls_mpi_free(&y_sqr_lhs);
+	mbedtls_mpi_free(&two);
+	mbedtls_mpi_free(y_sqr_rhs);
+	os_free(y_sqr_rhs);
+	return (ret == 0) && (on_curve == 1);
+}
+
+int crypto_ec_point_cmp(
+    const struct crypto_ec *e, const struct crypto_ec_point *a,
+    const struct crypto_ec_point *b)
+{
+	return mbedtls_ecp_point_cmp(
+	    (const mbedtls_ecp_point *)a, (const mbedtls_ecp_point *)b);
+}
+
+void crypto_debug_print_point(
+    const char *title, struct crypto_ec *e, const struct crypto_ec_point *point)
+{
+	u8 x[32], y[32];
+
+	if (crypto_ec_point_to_bin(e, point, x, y) < 0) {
+		wpa_printf(MSG_ERROR, "error: failed to get corrdinates\n");
+		return;
+	}
+
+	wpa_hexdump(MSG_ERROR, "x:", x, 32);
+	wpa_hexdump(MSG_ERROR, "y:", y, 32);
+}
+
+static struct crypto_key *crypto_alloc_key(void)
+{
+	mbedtls_pk_context *key = os_malloc(sizeof(*key));
+
+	if (!key) {
+		wpa_printf(
+		    MSG_ERROR, "%s: memory allocation failed\n", __func__);
+		return NULL;
+	}
+	mbedtls_pk_init(key);
+
+	return (struct crypto_key *)key;
+}
+
+void crypto_ec_free_key(struct crypto_key *key)
+{
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
+	mbedtls_pk_free(pkey);
+	os_free(key);
+}
+
+struct crypto_ec_point *crypto_ec_get_public_key(struct crypto_key *key)
+{
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
+
+	return (struct crypto_ec_point *)&mbedtls_pk_ec(*pkey)->MBEDTLS_PRIVATE(
+	    Q);
+}
+
+int crypto_ec_get_priv_key_der(
+    struct crypto_key *key, unsigned char **key_data, int *key_len)
+{
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
+	char der_data[ECP_PRV_DER_MAX_BYTES];
+
+	*key_len = mbedtls_pk_write_key_der(
+	    pkey, (unsigned char *)der_data, ECP_PRV_DER_MAX_BYTES);
+	if (*key_len <= 0)
+		return -1;
+
+	*key_data = os_malloc(*key_len);
+
+	if (!*key_data) {
+		wpa_printf(MSG_ERROR, "memory allocation failed\n");
+		return -1;
+	}
+	os_memcpy(*key_data, der_data, *key_len);
+
+	return 0;
+}
+
+struct crypto_ec_group *crypto_ec_get_group_from_key(struct crypto_key *key)
+{
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
+
+	return (struct crypto_ec_group *)&(
+	    mbedtls_pk_ec(*pkey)->MBEDTLS_PRIVATE(grp));
+}
+
+struct crypto_bignum *crypto_ec_get_private_key(struct crypto_key *key)
+{
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
+
+	return ((struct crypto_bignum *)&(
+	    mbedtls_pk_ec(*pkey)->MBEDTLS_PRIVATE(d)));
+}
+
+int crypto_ec_get_publickey_buf(struct crypto_key *key, u8 *key_buf, int len)
+{
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
+	unsigned char buf[MBEDTLS_MPI_MAX_SIZE + 10]; /* tag, length + MPI */
+	unsigned char *c = buf + sizeof(buf);
+	int pk_len = 0;
+
+	memset(buf, 0, sizeof(buf));
+	pk_len = mbedtls_pk_write_pubkey(&c, buf, pkey);
+
+	if (pk_len < 0)
+		return -1;
+
+	if (len == 0)
+		return pk_len;
+
+	os_memcpy(key_buf, buf + MBEDTLS_MPI_MAX_SIZE + 10 - pk_len, pk_len);
+
+	return pk_len;
+}
+
+int crypto_write_pubkey_der(struct crypto_key *key, unsigned char **key_buf)
+{
+	unsigned char output_buf[1600] = {0};
+	int len = mbedtls_pk_write_pubkey_der(
+	    (mbedtls_pk_context *)key, output_buf, 1600);
+	if (len <= 0)
+		return 0;
+
+	*key_buf = os_malloc(len);
+	if (!*key_buf) {
+		return 0;
+	}
+	os_memcpy(*key_buf, output_buf + 1600 - len, len);
+
+	return len;
+}
+
+struct crypto_key *crypto_ec_get_key(const u8 *privkey, size_t privkey_len)
+{
+	int ret;
+	mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key();
+
+	if (!kctx) {
+		wpa_printf(MSG_ERROR, "memory allocation failed\n");
+		return NULL;
+	}
+	ret = mbedtls_pk_parse_key(
+	    kctx, privkey, privkey_len, NULL, 0, f_rng, NULL);
+
+	if (ret < 0) {
+		// crypto_print_error_string(ret);
+		goto fail;
+	}
+
+	return (struct crypto_key *)kctx;
+
+fail:
+	mbedtls_pk_free(kctx);
+	os_free(kctx);
+	return NULL;
+}
+
+unsigned int crypto_ec_get_mbedtls_to_nist_group_id(int id)
+{
+	unsigned int nist_grpid = 0;
+	switch (id) {
+	case MBEDTLS_ECP_DP_SECP256R1:
+		nist_grpid = 19;
+		break;
+	case MBEDTLS_ECP_DP_SECP384R1:
+		nist_grpid = 20;
+		break;
+	case MBEDTLS_ECP_DP_SECP521R1:
+		nist_grpid = 21;
+		break;
+	case MBEDTLS_ECP_DP_BP256R1:
+		nist_grpid = 28;
+		break;
+	case MBEDTLS_ECP_DP_BP384R1:
+		nist_grpid = 29;
+		break;
+	case MBEDTLS_ECP_DP_BP512R1:
+		nist_grpid = 30;
+		break;
+	default:
+		break;
+	}
+
+	return nist_grpid;
+}
+
+int crypto_ec_get_curve_id(const struct crypto_ec_group *group)
+{
+	mbedtls_ecp_group *grp = (mbedtls_ecp_group *)group;
+	return (crypto_ec_get_mbedtls_to_nist_group_id(grp->id));
+}
+
+int crypto_ecdh(
+    struct crypto_key *key_own, struct crypto_key *key_peer, u8 *secret,
+    size_t *secret_len)
+{
+	mbedtls_ecdh_context *ctx;
+	mbedtls_pk_context *own = (mbedtls_pk_context *)key_own;
+	mbedtls_pk_context *peer = (mbedtls_pk_context *)key_peer;
+
+	int ret = -1;
+
+	*secret_len = 0;
+	ctx = os_malloc(sizeof(*ctx));
+	if (!ctx) {
+		wpa_printf(
+		    MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s", __func__);
+		return -1;
+	}
+
+	mbedtls_ecdh_init(ctx);
+	/* No need to setup, done through mbedtls_ecdh_get_params */
+
+	/* set params from our key */
+	if (mbedtls_ecdh_get_params(
+		ctx, mbedtls_pk_ec(*own), MBEDTLS_ECDH_OURS) < 0) {
+		wpa_printf(MSG_ERROR, "failed to set our ecdh params\n");
+		goto fail;
+	}
+
+#ifndef DPP_MAX_SHARED_SECRET_LEN
+#define DPP_MAX_SHARED_SECRET_LEN 66
+#endif
+	/* set params from peers key */
+	if (mbedtls_ecdh_get_params(
+		ctx, mbedtls_pk_ec(*peer), MBEDTLS_ECDH_THEIRS) < 0) {
+		wpa_printf(MSG_ERROR, "failed to set peer's ecdh params\n");
+		goto fail;
+	}
+
+	if (mbedtls_ecdh_calc_secret(
+		ctx, secret_len, secret, DPP_MAX_SHARED_SECRET_LEN, NULL,
+		NULL) < 0) {
+		wpa_printf(MSG_ERROR, "failed to calculate secret\n");
+		goto fail;
+	}
+
+	if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+		wpa_printf(
+		    MSG_ERROR, "secret len=%ld is too big\n", *secret_len);
+		goto fail;
+	}
+
+	ret = 0;
+
+fail:
+	mbedtls_ecdh_free(ctx);
+	os_free(ctx);
+	return ret;
+}
+
+void crypto_debug_print_ec_key(const char *title, struct crypto_key *key)
+{
+#ifdef DEBUG_PRINT
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
+	mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(*pkey);
+	u8 x[32], y[32], d[32];
+	wpa_printf(
+	    MSG_ERROR, "curve: %s\n",
+	    mbedtls_ecp_curve_info_from_grp_id(ecp->grp.id)->name);
+	int len = mbedtls_mpi_size((mbedtls_mpi *)crypto_ec_get_prime(
+	    (struct crypto_ec *)crypto_ec_get_group_from_key(key)));
+
+	wpa_printf(MSG_ERROR, "prime len is %d\n", len);
+	crypto_ec_point_to_bin(
+	    (struct crypto_ec *)crypto_ec_get_group_from_key(key),
+	    crypto_ec_get_public_key(key), x, y);
+	crypto_bignum_to_bin(crypto_ec_get_private_key(key), d, len, len);
+	wpa_hexdump(MSG_ERROR, "Q_x:", x, 32);
+	wpa_hexdump(MSG_ERROR, "Q_y:", y, 32);
+	wpa_hexdump(MSG_ERROR, "d:     ", d, 32);
+#endif
+}
+
+struct crypto_key *
+crypto_ec_parse_subpub_key(const unsigned char *p, size_t len)
+{
+	int ret;
+	mbedtls_pk_context *pkey = (mbedtls_pk_context *)crypto_alloc_key();
+	ret = mbedtls_pk_parse_subpubkey((unsigned char **)&p, p + len, pkey);
+
+	if (ret < 0) {
+		os_free(pkey);
+		return NULL;
+	}
+
+	return (struct crypto_key *)pkey;
+}
+
+int crypto_is_ec_key(struct crypto_key *key)
+{
+	int ret =
+	    mbedtls_pk_can_do((mbedtls_pk_context *)key, MBEDTLS_PK_ECKEY);
+	return ret;
+}
+
+struct crypto_key *crypto_ec_gen_keypair(u16 ike_group)
+{
+	mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key();
+
+	if (!kctx) {
+		wpa_printf(
+		    MSG_ERROR, "%s: memory allocation failed\n", __func__);
+		return NULL;
+	}
+
+	if (mbedtls_pk_setup(
+		kctx, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) != 0)
+		goto fail;
+
+	mbedtls_ecp_gen_key(
+	    MBEDTLS_ECP_DP_SECP256R1,
+	    mbedtls_pk_ec(*kctx), // get this from argument
+	    crypto_rng_wrapper, NULL);
+
+	return (struct crypto_key *)kctx;
+fail:
+	mbedtls_pk_free(kctx);
+	os_free(kctx);
+	return NULL;
+}
+
+/*
+ * ECParameters ::= CHOICE {
+ *   namedCurve         OBJECT IDENTIFIER
+ * }
+ */
+static int pk_write_ec_param(
+    unsigned char **p, unsigned char *start, mbedtls_ecp_keypair *ec)
+{
+	int ret;
+	size_t len = 0;
+	const char *oid;
+	size_t oid_len;
+
+	if ((ret = mbedtls_oid_get_oid_by_ec_grp(
+		 ec->MBEDTLS_PRIVATE(grp).id, &oid, &oid_len)) != 0)
+		return (ret);
+
+	MBEDTLS_ASN1_CHK_ADD(
+	    len, mbedtls_asn1_write_oid(p, start, oid, oid_len));
+
+	return ((int)len);
+}
+
+static int pk_write_ec_pubkey_formatted(
+    unsigned char **p, unsigned char *start, mbedtls_ecp_keypair *ec,
+    int format)
+{
+	int ret;
+	size_t len = 0;
+	unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN];
+
+	if ((ret = mbedtls_ecp_point_write_binary(
+		 &ec->MBEDTLS_PRIVATE(grp), &ec->MBEDTLS_PRIVATE(Q), format,
+		 &len, buf, sizeof(buf))) != 0) {
+		return (ret);
+	}
+
+	if (*p < start || (size_t)(*p - start) < len)
+		return (MBEDTLS_ERR_ASN1_BUF_TOO_SMALL);
+
+	*p -= len;
+	memcpy(*p, buf, len);
+
+	return ((int)len);
+}
+
+int mbedtls_pk_write_pubkey_formatted(
+    unsigned char **p, unsigned char *start, const mbedtls_pk_context *key,
+    int format)
+{
+	int ret;
+	size_t len = 0;
+
+	if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY)
+		MBEDTLS_ASN1_CHK_ADD(
+		    len, pk_write_ec_pubkey_formatted(
+			     p, start, mbedtls_pk_ec(*key), format));
+	else
+		return (MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE);
+
+	return ((int)len);
+}
+
+int crypto_pk_write_formatted_pubkey_der(
+    mbedtls_pk_context *key, unsigned char *buf, size_t size, int format)
+{
+	int ret;
+	unsigned char *c;
+	size_t len = 0, par_len = 0, oid_len;
+	const char *oid;
+
+	if (size == 0)
+		return (MBEDTLS_ERR_ASN1_BUF_TOO_SMALL);
+
+	c = buf + size;
+
+	MBEDTLS_ASN1_CHK_ADD(
+	    len, mbedtls_pk_write_pubkey_formatted(&c, buf, key, format));
+
+	if (c - buf < 1)
+		return (MBEDTLS_ERR_ASN1_BUF_TOO_SMALL);
+
+	/*
+	 *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
+	 *       algorithm            AlgorithmIdentifier,
+	 *       subjectPublicKey     BIT STRING }
+	 */
+	*--c = 0;
+	len += 1;
+
+	MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
+	MBEDTLS_ASN1_CHK_ADD(
+	    len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_BIT_STRING));
+
+	if ((ret = mbedtls_oid_get_oid_by_pk_alg(
+		 mbedtls_pk_get_type(key), &oid, &oid_len)) != 0) {
+		return (ret);
+	}
+
+	if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) {
+		MBEDTLS_ASN1_CHK_ADD(
+		    par_len, pk_write_ec_param(&c, buf, mbedtls_pk_ec(*key)));
+	}
+
+	MBEDTLS_ASN1_CHK_ADD(
+	    len, mbedtls_asn1_write_algorithm_identifier(
+		     &c, buf, oid, oid_len, par_len));
+
+	MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
+	MBEDTLS_ASN1_CHK_ADD(
+	    len,
+	    mbedtls_asn1_write_tag(
+		&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
+
+	return ((int)len);
+}
+
+int crypto_ec_write_pub_key(struct crypto_key *key, unsigned char **key_buf)
+{
+	unsigned char output_buf[1600] = {0};
+	int len = crypto_pk_write_formatted_pubkey_der(
+	    (mbedtls_pk_context *)key, output_buf, 1600, 1);
+	if (len <= 0)
+		return 0;
+
+	*key_buf = os_malloc(len);
+	if (!*key_buf) {
+		wpa_printf(
+		    MSG_ERROR, "%s: memory allocation failed\n", __func__);
+		return 0;
+	}
+	os_memcpy(*key_buf, output_buf + 1600 - len, len);
+
+	return len;
+}
+#endif /* CONFIG_ECC */
diff --git a/src/crypto/crypto_mbedtls.c b/src/crypto/crypto_mbedtls.c
new file mode 100644
index 000000000..1fa235dea
--- /dev/null
+++ b/src/crypto/crypto_mbedtls.c
@@ -0,0 +1,910 @@
+/*
+ * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "crypto.h"
+#include "random.h"
+#include "sha256.h"
+
+#include "mbedtls/ecp.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/md.h"
+#include "mbedtls/aes.h"
+#include "mbedtls/bignum.h"
+#include "mbedtls/pkcs5.h"
+#include "mbedtls/cmac.h"
+#include "mbedtls/nist_kw.h"
+#include "mbedtls/des.h"
+#include "mbedtls/ccm.h"
+#ifdef MBEDTLS_ARC4_C
+#include "mbedtls/arc4.h"
+#endif
+
+#include "common.h"
+#include "utils/wpabuf.h"
+#include "dh_group5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "md5.h"
+#include "aes_wrap.h"
+#include "crypto.h"
+
+static int digest_vector(
+    mbedtls_md_type_t md_type, size_t num_elem, const u8 *addr[],
+    const size_t *len, u8 *mac)
+{
+	size_t i;
+	const mbedtls_md_info_t *md_info;
+	mbedtls_md_context_t md_ctx;
+	int ret;
+
+	mbedtls_md_init(&md_ctx);
+
+	md_info = mbedtls_md_info_from_type(md_type);
+	if (!md_info) {
+		wpa_printf(MSG_ERROR, "mbedtls_md_info_from_type() failed");
+		return -1;
+	}
+
+	ret = mbedtls_md_setup(&md_ctx, md_info, 0);
+	if (ret != 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_md_setup() returned error");
+		goto cleanup;
+	}
+
+	ret = mbedtls_md_starts(&md_ctx);
+	if (ret != 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_md_starts returned error");
+		goto cleanup;
+	}
+
+	for (i = 0; i < num_elem; i++) {
+		ret = mbedtls_md_update(&md_ctx, addr[i], len[i]);
+		if (ret != 0) {
+			wpa_printf(MSG_ERROR, "mbedtls_md_update ret=%d", ret);
+			goto cleanup;
+		}
+	}
+
+	ret = mbedtls_md_finish(&md_ctx, mac);
+cleanup:
+	mbedtls_md_free(&md_ctx);
+
+	return ret;
+}
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return digest_vector(MBEDTLS_MD_SHA256, num_elem, addr, len, mac);
+}
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return digest_vector(MBEDTLS_MD_SHA384, num_elem, addr, len, mac);
+}
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return digest_vector(MBEDTLS_MD_SHA1, num_elem, addr, len, mac);
+}
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return digest_vector(MBEDTLS_MD_MD5, num_elem, addr, len, mac);
+}
+
+#ifdef MBEDTLS_MD4_C
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return digest_vector(MBEDTLS_MD_MD4, num_elem, addr, len, mac);
+}
+#endif
+
+struct crypto_hash
+{
+	mbedtls_md_context_t ctx;
+};
+
+struct crypto_hash *
+crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len)
+{
+	struct crypto_hash *ctx;
+	mbedtls_md_type_t md_type;
+	const mbedtls_md_info_t *md_info;
+	int ret;
+
+	switch (alg) {
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		md_type = MBEDTLS_MD_MD5;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		md_type = MBEDTLS_MD_SHA1;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		md_type = MBEDTLS_MD_SHA256;
+		break;
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		return NULL;
+	}
+
+	mbedtls_md_init(&ctx->ctx);
+	md_info = mbedtls_md_info_from_type(md_type);
+	if (!md_info) {
+		os_free(ctx);
+		return NULL;
+	}
+	ret = mbedtls_md_setup(&ctx->ctx, md_info, 1);
+	if (ret != 0) {
+		os_free(ctx);
+		return NULL;
+	}
+	mbedtls_md_hmac_starts(&ctx->ctx, key, key_len);
+
+	return ctx;
+}
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL) {
+		return;
+	}
+	mbedtls_md_hmac_update(&ctx->ctx, data, len);
+}
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	if (ctx == NULL) {
+		return -2;
+	}
+
+	if (mac == NULL || len == NULL) {
+		mbedtls_md_free(&ctx->ctx);
+		bin_clear_free(ctx, sizeof(*ctx));
+		return 0;
+	}
+	mbedtls_md_hmac_finish(&ctx->ctx, mac);
+	mbedtls_md_free(&ctx->ctx);
+	bin_clear_free(ctx, sizeof(*ctx));
+
+	return 0;
+}
+
+static int hmac_vector(
+    mbedtls_md_type_t md_type, const u8 *key, size_t key_len, size_t num_elem,
+    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	size_t i;
+	const mbedtls_md_info_t *md_info;
+	mbedtls_md_context_t md_ctx;
+	int ret;
+
+	mbedtls_md_init(&md_ctx);
+
+	md_info = mbedtls_md_info_from_type(md_type);
+	if (!md_info) {
+		return -1;
+	}
+
+	ret = mbedtls_md_setup(&md_ctx, md_info, 1);
+	if (ret != 0) {
+		return (ret);
+	}
+
+	mbedtls_md_hmac_starts(&md_ctx, key, key_len);
+
+	for (i = 0; i < num_elem; i++) {
+		mbedtls_md_hmac_update(&md_ctx, addr[i], len[i]);
+	}
+
+	mbedtls_md_hmac_finish(&md_ctx, mac);
+
+	mbedtls_md_free(&md_ctx);
+
+	return 0;
+}
+
+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 hmac_vector(
+	    MBEDTLS_MD_SHA384, key, key_len, num_elem, addr, len, mac);
+}
+
+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);
+}
+
+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 hmac_vector(
+	    MBEDTLS_MD_SHA256, key, key_len, num_elem, addr, len, mac);
+}
+
+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);
+}
+
+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 hmac_vector(
+	    MBEDTLS_MD_MD5, key, key_len, num_elem, addr, len, mac);
+}
+
+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);
+}
+
+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 hmac_vector(
+	    MBEDTLS_MD_SHA1, key, key_len, num_elem, addr, len, mac);
+}
+
+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);
+}
+
+static void *aes_crypt_init(int mode, const u8 *key, size_t len)
+{
+	int ret = -1;
+	mbedtls_aes_context *aes = os_malloc(sizeof(*aes));
+	if (!aes) {
+		return NULL;
+	}
+	mbedtls_aes_init(aes);
+
+	if (mode == MBEDTLS_AES_ENCRYPT) {
+		ret = mbedtls_aes_setkey_enc(aes, key, len * 8);
+	} else if (mode == MBEDTLS_AES_DECRYPT) {
+		ret = mbedtls_aes_setkey_dec(aes, key, len * 8);
+	}
+	if (ret < 0) {
+		mbedtls_aes_free(aes);
+		os_free(aes);
+		wpa_printf(
+		    MSG_ERROR,
+		    "%s: mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec failed",
+		    __func__);
+		return NULL;
+	}
+
+	return (void *)aes;
+}
+
+static int aes_crypt(void *ctx, int mode, const u8 *in, u8 *out)
+{
+	return mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, mode, in, out);
+}
+
+static void aes_crypt_deinit(void *ctx)
+{
+	mbedtls_aes_free((mbedtls_aes_context *)ctx);
+	os_free(ctx);
+}
+
+void *aes_encrypt_init(const u8 *key, size_t len)
+{
+	return aes_crypt_init(MBEDTLS_AES_ENCRYPT, key, len);
+}
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	return aes_crypt(ctx, MBEDTLS_AES_ENCRYPT, plain, crypt);
+}
+
+void aes_encrypt_deinit(void *ctx) { return aes_crypt_deinit(ctx); }
+
+void *aes_decrypt_init(const u8 *key, size_t len)
+{
+	return aes_crypt_init(MBEDTLS_AES_DECRYPT, key, len);
+}
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	return aes_crypt(ctx, MBEDTLS_AES_DECRYPT, crypt, plain);
+}
+
+void aes_decrypt_deinit(void *ctx) { return aes_crypt_deinit(ctx); }
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	int ret = 0;
+	mbedtls_aes_context ctx;
+	u8 cbc[MBEDTLS_AES_BLOCK_SIZE];
+
+	mbedtls_aes_init(&ctx);
+
+	ret = mbedtls_aes_setkey_enc(&ctx, key, 128);
+	if (ret < 0) {
+		mbedtls_aes_free(&ctx);
+		return ret;
+	}
+
+	os_memcpy(cbc, iv, MBEDTLS_AES_BLOCK_SIZE);
+	ret = mbedtls_aes_crypt_cbc(
+	    &ctx, MBEDTLS_AES_ENCRYPT, data_len, cbc, data, data);
+	mbedtls_aes_free(&ctx);
+
+	return ret;
+}
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	int ret = 0;
+	mbedtls_aes_context ctx;
+	u8 cbc[MBEDTLS_AES_BLOCK_SIZE];
+
+	mbedtls_aes_init(&ctx);
+
+	ret = mbedtls_aes_setkey_dec(&ctx, key, 128);
+	if (ret < 0) {
+		mbedtls_aes_free(&ctx);
+		return ret;
+	}
+
+	os_memcpy(cbc, iv, MBEDTLS_AES_BLOCK_SIZE);
+	ret = mbedtls_aes_crypt_cbc(
+	    &ctx, MBEDTLS_AES_DECRYPT, data_len, cbc, data, data);
+	mbedtls_aes_free(&ctx);
+
+	return ret;
+}
+
+struct crypto_cipher
+{
+	mbedtls_cipher_context_t ctx_enc;
+	mbedtls_cipher_context_t ctx_dec;
+};
+
+static int crypto_init_cipher_ctx(
+    mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info,
+    const u8 *iv, const u8 *key, mbedtls_operation_t operation)
+{
+	mbedtls_cipher_init(ctx);
+	int ret;
+
+	ret = mbedtls_cipher_setup(ctx, cipher_info);
+	if (ret != 0) {
+		return -1;
+	}
+
+	if (mbedtls_cipher_setkey(
+		ctx, key, cipher_info->MBEDTLS_PRIVATE(key_bitlen),
+		operation) != 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_cipher_setkey returned error");
+		return -1;
+	}
+	if (mbedtls_cipher_set_iv(
+		ctx, iv, cipher_info->MBEDTLS_PRIVATE(iv_size)) != 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_cipher_set_iv returned error");
+		return -1;
+	}
+	if (mbedtls_cipher_reset(ctx) != 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_cipher_reset() returned error");
+		return -1;
+	}
+
+	return 0;
+}
+
+static mbedtls_cipher_type_t
+alg_to_mbedtls_cipher(enum crypto_cipher_alg alg, size_t key_len)
+{
+	switch (alg) {
+#ifdef MBEDTLS_ARC4_C
+	case CRYPTO_CIPHER_ALG_RC4:
+		return MBEDTLS_CIPHER_ARC4_128;
+#endif
+	case CRYPTO_CIPHER_ALG_AES:
+		if (key_len == 16) {
+			return MBEDTLS_CIPHER_AES_128_CBC;
+		}
+		if (key_len == 24) {
+			return MBEDTLS_CIPHER_AES_192_CBC;
+		}
+		if (key_len == 32) {
+			return MBEDTLS_CIPHER_AES_256_CBC;
+		}
+		break;
+#ifdef MBEDTLS_DES_C
+	case CRYPTO_CIPHER_ALG_3DES:
+		return MBEDTLS_CIPHER_DES_EDE3_CBC;
+	case CRYPTO_CIPHER_ALG_DES:
+		return MBEDTLS_CIPHER_DES_CBC;
+#endif
+	default:
+		break;
+	}
+
+	return MBEDTLS_CIPHER_NONE;
+}
+
+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;
+	mbedtls_cipher_type_t cipher_type;
+	const mbedtls_cipher_info_t *cipher_info;
+
+	ctx = (struct crypto_cipher *)os_zalloc(sizeof(*ctx));
+	if (!ctx) {
+		return NULL;
+	}
+
+	cipher_type = alg_to_mbedtls_cipher(alg, key_len);
+	if (cipher_type == MBEDTLS_CIPHER_NONE) {
+		goto cleanup;
+	}
+
+	cipher_info = mbedtls_cipher_info_from_type(cipher_type);
+	if (cipher_info == NULL) {
+		goto cleanup;
+	}
+
+	/* Init both ctx encryption/decryption */
+	if (crypto_init_cipher_ctx(
+		&ctx->ctx_enc, cipher_info, iv, key, MBEDTLS_ENCRYPT) < 0) {
+		goto cleanup;
+	}
+
+	if (crypto_init_cipher_ctx(
+		&ctx->ctx_dec, cipher_info, iv, key, MBEDTLS_DECRYPT) < 0) {
+		goto cleanup;
+	}
+
+	return ctx;
+
+cleanup:
+	os_free(ctx);
+	return NULL;
+}
+
+int crypto_cipher_encrypt(
+    struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len)
+{
+	int ret;
+	size_t olen = 1200;
+
+	ret = mbedtls_cipher_update(&ctx->ctx_enc, plain, len, crypt, &olen);
+	if (ret != 0) {
+		return -1;
+	}
+
+	ret = mbedtls_cipher_finish(&ctx->ctx_enc, crypt + olen, &olen);
+	if (ret != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+int crypto_cipher_decrypt(
+    struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len)
+{
+	int ret;
+	size_t olen = 1200;
+
+	ret = mbedtls_cipher_update(&ctx->ctx_dec, crypt, len, plain, &olen);
+	if (ret != 0) {
+		return -1;
+	}
+
+	ret = mbedtls_cipher_finish(&ctx->ctx_dec, plain + olen, &olen);
+	if (ret != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	mbedtls_cipher_free(&ctx->ctx_enc);
+	mbedtls_cipher_free(&ctx->ctx_dec);
+	os_free(ctx);
+}
+
+int aes_ctr_encrypt(
+    const u8 *key, size_t key_len, const u8 *nonce, u8 *data, size_t data_len)
+{
+	int ret;
+	mbedtls_aes_context ctx;
+	uint8_t stream_block[MBEDTLS_AES_BLOCK_SIZE];
+	size_t offset = 0;
+
+	mbedtls_aes_init(&ctx);
+	ret = mbedtls_aes_setkey_enc(&ctx, key, key_len * 8);
+	if (ret < 0) {
+		goto cleanup;
+	}
+	ret = mbedtls_aes_crypt_ctr(
+	    &ctx, data_len, &offset, (u8 *)nonce, stream_block, data, data);
+cleanup:
+	mbedtls_aes_free(&ctx);
+	return ret;
+}
+
+int aes_128_ctr_encrypt(
+    const u8 *key, const u8 *nonce, u8 *data, size_t data_len)
+{
+	return aes_ctr_encrypt(key, 16, nonce, data, data_len);
+}
+
+#ifdef MBEDTLS_NIST_KW_C
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+	mbedtls_nist_kw_context ctx;
+	size_t olen;
+	int ret = 0;
+	mbedtls_nist_kw_init(&ctx);
+
+	ret = mbedtls_nist_kw_setkey(
+	    &ctx, MBEDTLS_CIPHER_ID_AES, kek, kek_len * 8, 1);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = mbedtls_nist_kw_wrap(
+	    &ctx, MBEDTLS_KW_MODE_KW, plain, n * 8, cipher, &olen, (n + 1) * 8);
+
+	mbedtls_nist_kw_free(&ctx);
+	return ret;
+}
+
+int aes_unwrap(
+    const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain)
+{
+	mbedtls_nist_kw_context ctx;
+	size_t olen;
+	int ret = 0;
+	mbedtls_nist_kw_init(&ctx);
+
+	ret = mbedtls_nist_kw_setkey(
+	    &ctx, MBEDTLS_CIPHER_ID_AES, kek, kek_len * 8, 0);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = mbedtls_nist_kw_unwrap(
+	    &ctx, MBEDTLS_KW_MODE_KW, cipher, (n + 1) * 8, plain, &olen,
+	    (n * 8));
+
+	mbedtls_nist_kw_free(&ctx);
+	return ret;
+}
+#endif
+
+int crypto_mod_exp(
+    const uint8_t *base, size_t base_len, const uint8_t *power,
+    size_t power_len, const uint8_t *modulus, size_t modulus_len,
+    uint8_t *result, size_t *result_len)
+{
+	mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result, bn_rinv;
+	int ret = 0;
+
+	mbedtls_mpi_init(&bn_base);
+	mbedtls_mpi_init(&bn_exp);
+	mbedtls_mpi_init(&bn_modulus);
+	mbedtls_mpi_init(&bn_result);
+	mbedtls_mpi_init(&bn_rinv);
+
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&bn_base, base, base_len));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&bn_exp, power, power_len));
+	MBEDTLS_MPI_CHK(
+	    mbedtls_mpi_read_binary(&bn_modulus, modulus, modulus_len));
+
+	MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(
+	    &bn_result, &bn_base, &bn_exp, &bn_modulus, &bn_rinv));
+
+	ret = mbedtls_mpi_write_binary(&bn_result, result, *result_len);
+
+cleanup:
+	mbedtls_mpi_free(&bn_base);
+	mbedtls_mpi_free(&bn_exp);
+	mbedtls_mpi_free(&bn_modulus);
+	mbedtls_mpi_free(&bn_result);
+	mbedtls_mpi_free(&bn_rinv);
+
+	return ret;
+}
+
+int pbkdf2_sha1(
+    const char *passphrase, const u8 *ssid, size_t ssid_len, int iterations,
+    u8 *buf, size_t buflen)
+{
+
+	mbedtls_md_context_t sha1_ctx;
+	const mbedtls_md_info_t *info_sha1;
+	int ret;
+
+	mbedtls_md_init(&sha1_ctx);
+
+	info_sha1 = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+	if (info_sha1 == NULL) {
+		ret = -1;
+		goto cleanup;
+	}
+
+	if ((ret = mbedtls_md_setup(&sha1_ctx, info_sha1, 1)) != 0) {
+		ret = -1;
+		goto cleanup;
+	}
+
+	ret = mbedtls_pkcs5_pbkdf2_hmac(
+	    &sha1_ctx, (const u8 *)passphrase, os_strlen(passphrase), ssid,
+	    ssid_len, iterations, 32, buf);
+	if (ret != 0) {
+		ret = -1;
+		goto cleanup;
+	}
+
+cleanup:
+	mbedtls_md_free(&sha1_ctx);
+	return ret;
+}
+
+#ifdef MBEDTLS_DES_C
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	int ret;
+	mbedtls_des_context 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;
+
+	mbedtls_des_init(&des);
+	ret = mbedtls_des_setkey_enc(&des, pkey);
+	if (ret < 0) {
+		return ret;
+	}
+	ret = mbedtls_des_crypt_ecb(&des, clear, cypher);
+	mbedtls_des_free(&des);
+
+	return ret;
+}
+#endif
+
+/* Only enable this if all other ciphers are using MbedTLS implementation */
+#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_CMAC_C) &&                       \
+    defined(MBEDTLS_NIST_KW_C)
+int aes_ccm_ae(
+    const u8 *key, size_t key_len, const u8 *nonce, size_t M, const u8 *plain,
+    size_t plain_len, const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth)
+{
+	int ret;
+	mbedtls_ccm_context ccm;
+
+	mbedtls_ccm_init(&ccm);
+
+	ret = mbedtls_ccm_setkey(&ccm, MBEDTLS_CIPHER_ID_AES, key, key_len * 8);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_ccm_setkey failed");
+		goto cleanup;
+	}
+
+	ret = mbedtls_ccm_encrypt_and_tag(
+	    &ccm, plain_len, nonce, 13, aad, aad_len, plain, crypt, auth, M);
+
+cleanup:
+	mbedtls_ccm_free(&ccm);
+
+	return ret;
+}
+
+int aes_ccm_ad(
+    const u8 *key, size_t key_len, const u8 *nonce, size_t M, const u8 *crypt,
+    size_t crypt_len, const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain)
+{
+	int ret;
+	mbedtls_ccm_context ccm;
+
+	mbedtls_ccm_init(&ccm);
+
+	ret = mbedtls_ccm_setkey(&ccm, MBEDTLS_CIPHER_ID_AES, key, key_len * 8);
+	if (ret < 0) {
+		goto cleanup;
+		;
+	}
+
+	ret = mbedtls_ccm_star_auth_decrypt(
+	    &ccm, crypt_len, nonce, 13, aad, aad_len, crypt, plain, auth, M);
+
+cleanup:
+	mbedtls_ccm_free(&ccm);
+
+	return ret;
+}
+#endif
+
+#ifdef MBEDTLS_ARC4_C
+int rc4_skip(
+    const u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len)
+{
+	int ret;
+	unsigned char skip_buf_in[16];
+	unsigned char skip_buf_out[16];
+	mbedtls_arc4_context ctx;
+	unsigned char *obuf = os_malloc(data_len);
+
+	if (!obuf) {
+		wpa_printf(MSG_ERROR, "%s:memory allocation failed", __func__);
+		return -1;
+	}
+	mbedtls_arc4_init(&ctx);
+	mbedtls_arc4_setup(&ctx, key, keylen);
+	while (skip >= sizeof(skip_buf_in)) {
+		size_t len = skip;
+		if (len > sizeof(skip_buf_in)) {
+			len = sizeof(skip_buf_in);
+		}
+		if ((ret = mbedtls_arc4_crypt(
+			 &ctx, len, skip_buf_in, skip_buf_out)) != 0) {
+			wpa_printf(MSG_ERROR, "rc4 encryption failed");
+			return -1;
+		}
+		os_memcpy(skip_buf_in, skip_buf_out, 16);
+		skip -= len;
+	}
+
+	mbedtls_arc4_crypt(&ctx, data_len, data, obuf);
+
+	memcpy(data, obuf, data_len);
+	os_free(obuf);
+
+	return 0;
+}
+#endif
+
+#ifdef MBEDTLS_CMAC_C
+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);
+}
+
+int omac1_aes_vector(
+    const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[],
+    const size_t *len, u8 *mac)
+{
+	const mbedtls_cipher_info_t *cipher_info;
+	int i, ret = 0;
+	mbedtls_cipher_type_t cipher_type;
+	mbedtls_cipher_context_t ctx;
+
+	switch (key_len) {
+	case 16:
+		cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
+		break;
+	case 24:
+		cipher_type = MBEDTLS_CIPHER_AES_192_ECB;
+		break;
+	case 32:
+		cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
+		break;
+	default:
+		cipher_type = MBEDTLS_CIPHER_NONE;
+		break;
+	}
+	cipher_info = mbedtls_cipher_info_from_type(cipher_type);
+	if (cipher_info == NULL) {
+		/* Failing at this point must be due to a build issue */
+		ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+		goto cleanup;
+	}
+
+	if (key == NULL || mac == NULL) {
+		return -1;
+	}
+
+	mbedtls_cipher_init(&ctx);
+
+	ret = mbedtls_cipher_setup(&ctx, cipher_info);
+	if (ret != 0) {
+		goto cleanup;
+	}
+
+	ret = mbedtls_cipher_cmac_starts(&ctx, key, key_len * 8);
+	if (ret != 0) {
+		goto cleanup;
+	}
+
+	for (i = 0; i < num_elem; i++) {
+		ret = mbedtls_cipher_cmac_update(&ctx, addr[i], len[i]);
+		if (ret != 0) {
+			goto cleanup;
+		}
+	}
+
+	ret = mbedtls_cipher_cmac_finish(&ctx, mac);
+cleanup:
+	mbedtls_cipher_free(&ctx);
+	return (ret);
+}
+
+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);
+}
+#endif
+
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+	return mbedtls_mpi_get_bit((mbedtls_mpi *)a, 0);
+}
+
+int crypto_dh_derive_secret(
+    u8 generator, const u8 *prime, size_t prime_len, const u8 *order,
+    size_t order_len, const u8 *privkey, size_t privkey_len, const u8 *pubkey,
+    size_t pubkey_len, u8 *secret, size_t *len)
+{
+	return crypto_mod_exp(
+	    prime, prime_len, privkey, privkey_len, pubkey, pubkey_len, secret,
+	    len);
+}
+
+int crypto_dh_init(
+    u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, u8 *pubkey)
+{
+	size_t pubkey_len, pad;
+
+	if (os_get_random(privkey, prime_len) < 0) {
+		return -1;
+	}
+	if (os_memcmp(privkey, prime, prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		privkey[0] = 0;
+	}
+
+	pubkey_len = prime_len;
+	if (crypto_mod_exp(
+		&generator, 1, privkey, prime_len, prime, prime_len, pubkey,
+		&pubkey_len) < 0) {
+		return -1;
+	}
+	if (pubkey_len < prime_len) {
+		pad = prime_len - pubkey_len;
+		os_memmove(pubkey + pad, pubkey, pubkey_len);
+		os_memset(pubkey, 0, pad);
+	}
+
+	return 0;
+}
diff --git a/src/crypto/tls_mbedtls.c b/src/crypto/tls_mbedtls.c
new file mode 100644
index 000000000..be24e1a9d
--- /dev/null
+++ b/src/crypto/tls_mbedtls.c
@@ -0,0 +1,1181 @@
+/*
+ * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+
+#include "tls.h"
+#include "crypto/sha1.h"
+#include "crypto/md5.h"
+#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "random.h"
+#include <mbedtls/ssl.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/debug.h>
+#include <mbedtls/mbedtls_config.h>
+#include <assert.h>
+
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+#define MAX_CIPHERSUITE 32
+
+/* Throw a compilation error if basic requirements in mbedtls are not enabled */
+#if !defined(MBEDTLS_SSL_TLS_C)
+#error "TLS not enabled in mbedtls config"
+#endif
+
+#if !defined(MBEDTLS_SHA256_C)
+#error "SHA256 is disabled in mbedtls config"
+#endif
+
+#if !defined(MBEDTLS_AES_C)
+#error "AES support is disabled in mbedtls config"
+#endif
+
+uint32_t tls_instance_count;
+struct tls_data
+{
+	/* Data for mbedlts */
+	struct wpabuf *in_data;
+	/* Data from mbedtls */
+	struct wpabuf *out_data;
+};
+
+mbedtls_ssl_export_keys_t tls_connection_export_keys_cb;
+
+typedef struct tls_context
+{
+	mbedtls_ssl_context ssl; /*!< TLS/SSL context */
+	mbedtls_entropy_context
+	    entropy; /*!< mbedTLS entropy context structure */
+	mbedtls_ctr_drbg_context
+	    ctr_drbg;		 /*!< mbedTLS ctr drbg context structure */
+	mbedtls_ssl_config conf; /*!< TLS/SSL config to be shared structures */
+	mbedtls_x509_crt cacert; /*!< Container for X.509 CA certificate */
+	mbedtls_x509_crt *cacert_ptr; /*!< Pointer to the cacert being used. */
+	mbedtls_x509_crt
+	    clientcert; /*!< Container for X.509 client certificate */
+	mbedtls_pk_context clientkey; /*!< Private key of client certificate */
+	int ciphersuite[MAX_CIPHERSUITE];
+} tls_context_t;
+
+struct tls_connection
+{
+	tls_context_t *tls;
+	struct tls_data tls_io_data;
+	unsigned char master_secret[TLS_MASTER_SECRET_LEN];
+	unsigned char randbytes[2 * TLS_RANDOM_LEN];
+	mbedtls_tls_prf_types tls_prf_type;
+};
+
+static int f_rng(void *p_rng, unsigned char *buf, size_t len)
+{
+	return random_get_bytes(buf, len);
+}
+
+static void tls_mbedtls_cleanup(tls_context_t *tls)
+{
+	if (!tls) {
+		return;
+	}
+	tls->cacert_ptr = NULL;
+	mbedtls_x509_crt_free(&tls->cacert);
+	mbedtls_x509_crt_free(&tls->clientcert);
+	mbedtls_pk_free(&tls->clientkey);
+	mbedtls_entropy_free(&tls->entropy);
+	mbedtls_ssl_config_free(&tls->conf);
+	mbedtls_ctr_drbg_free(&tls->ctr_drbg);
+	mbedtls_ssl_free(&tls->ssl);
+}
+
+static void tls_mbedtls_conn_delete(tls_context_t *tls)
+{
+	if (tls != NULL) {
+		tls_mbedtls_cleanup(tls);
+	}
+}
+
+static int tls_mbedtls_write(void *ctx, const unsigned char *buf, size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *)ctx;
+	struct tls_data *data = &conn->tls_io_data;
+
+	if (wpabuf_resize(&data->out_data, len) < 0)
+		return 0;
+
+	wpabuf_put_data(data->out_data, buf, len);
+
+	return len;
+}
+
+static int tls_mbedtls_read(void *ctx, unsigned char *buf, size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *)ctx;
+	struct tls_data *data = &conn->tls_io_data;
+	struct wpabuf *local_buf;
+	size_t data_len = len;
+
+	if (data->in_data == NULL) {
+		return MBEDTLS_ERR_SSL_WANT_READ;
+	}
+
+	if (len > wpabuf_len(data->in_data)) {
+		wpa_printf(MSG_ERROR, "don't have suffient data\n");
+		data_len = wpabuf_len(data->in_data);
+	}
+
+	os_memcpy(buf, wpabuf_head(data->in_data), data_len);
+	/* adjust buffer */
+	if (len < wpabuf_len(data->in_data)) {
+		local_buf = wpabuf_alloc_copy(
+		    (char *)wpabuf_head(data->in_data) + data_len,
+		    wpabuf_len(data->in_data) - data_len);
+		wpabuf_free(data->in_data);
+		data->in_data = local_buf;
+	} else {
+		wpabuf_free(data->in_data);
+		data->in_data = NULL;
+	}
+
+	return data_len;
+}
+
+static int
+set_pki_context(tls_context_t *tls, const struct tls_connection_params *cfg)
+{
+	int ret;
+
+	if (cfg->client_cert_blob == NULL || cfg->private_key_blob == NULL) {
+		wpa_printf(MSG_ERROR, "%s: config not correct", __func__);
+		return -1;
+	}
+
+	mbedtls_x509_crt_init(&tls->clientcert);
+	mbedtls_pk_init(&tls->clientkey);
+
+	ret = mbedtls_x509_crt_parse(
+	    &tls->clientcert, cfg->client_cert_blob, cfg->client_cert_blob_len);
+	if (ret < 0) {
+		wpa_printf(
+		    MSG_ERROR, "mbedtls_x509_crt_parse returned -0x%x", -ret);
+		return ret;
+	}
+
+	ret = mbedtls_pk_parse_key(
+	    &tls->clientkey, cfg->private_key_blob, cfg->private_key_blob_len,
+	    (const unsigned char *)cfg->private_key_passwd,
+	    cfg->private_key_passwd ? os_strlen(cfg->private_key_passwd) : 0,
+	    f_rng, NULL);
+	if (ret < 0) {
+		wpa_printf(
+		    MSG_ERROR, "mbedtls_pk_parse_keyfile returned -0x%x", -ret);
+		return ret;
+	}
+
+	ret = mbedtls_ssl_conf_own_cert(
+	    &tls->conf, &tls->clientcert, &tls->clientkey);
+	if (ret < 0) {
+		wpa_printf(
+		    MSG_ERROR, "mbedtls_ssl_conf_own_cert returned -0x%x",
+		    -ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int
+set_ca_cert(tls_context_t *tls, const unsigned char *cacert, size_t cacert_len)
+{
+	tls->cacert_ptr = &tls->cacert;
+	mbedtls_x509_crt_init(tls->cacert_ptr);
+	int ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cacert, cacert_len);
+	if (ret < 0) {
+		wpa_printf(
+		    MSG_ERROR, "mbedtls_x509_crt_parse returned -0x%x", -ret);
+		return ret;
+	}
+	mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+	mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_SUITEB192
+static int tls_sig_hashes_for_suiteb[] = {
+#if defined(MBEDTLS_SHA512_C)
+    MBEDTLS_MD_SHA512, MBEDTLS_MD_SHA384,
+#endif
+    MBEDTLS_MD_NONE};
+
+const mbedtls_x509_crt_profile suiteb_mbedtls_x509_crt_profile = {
+#if defined(MBEDTLS_SHA512_C)
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
+	MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512) |
+#endif
+	0,
+    0xFFFFFFF, /* Any PK alg    */
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1),
+    1024,
+};
+
+static void tls_set_suiteb_config(tls_context_t *tls)
+{
+	const mbedtls_x509_crt_profile *crt_profile =
+	    &suiteb_mbedtls_x509_crt_profile;
+	mbedtls_ssl_conf_cert_profile(&tls->conf, crt_profile);
+	mbedtls_ssl_conf_sig_hashes(&tls->conf, tls_sig_hashes_for_suiteb);
+}
+#endif
+
+static int tls_sig_hashes_for_eap[] = {
+#if defined(MBEDTLS_SHA512_C)
+    MBEDTLS_MD_SHA512, MBEDTLS_MD_SHA384,
+#endif
+#if defined(MBEDTLS_SHA256_C)
+    MBEDTLS_MD_SHA256, MBEDTLS_MD_SHA224,
+#endif
+#if defined(MBEDTLS_SHA1_C)
+    MBEDTLS_MD_SHA1,
+#endif
+    MBEDTLS_MD_NONE};
+
+const mbedtls_x509_crt_profile eap_mbedtls_x509_crt_profile = {
+#if defined(MBEDTLS_SHA1_C)
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
+#endif
+#if defined(MBEDTLS_SHA256_C)
+	MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
+	MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
+#endif
+#if defined(MBEDTLS_SHA512_C)
+	MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
+	MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512) |
+#endif
+	0,
+    0xFFFFFFF, /* Any PK alg    */
+    0xFFFFFFF, /* Any curve     */
+    1024,
+};
+
+static void tls_enable_sha1_config(tls_context_t *tls)
+{
+	const mbedtls_x509_crt_profile *crt_profile =
+	    &eap_mbedtls_x509_crt_profile;
+	mbedtls_ssl_conf_cert_profile(&tls->conf, crt_profile);
+	mbedtls_ssl_conf_sig_hashes(&tls->conf, tls_sig_hashes_for_eap);
+}
+
+static const int eap_ciphersuite_preference[] = {
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)
+#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+#endif
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+    MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+#endif
+
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8,
+#endif
+#endif
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM,
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8,
+
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM,
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+    MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8,
+#endif
+#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_RSA_WITH_AES_256_CCM,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256,
+    MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8,
+#endif
+
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_RSA_WITH_AES_128_CCM,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
+    MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
+#endif
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+    MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+#endif
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+    MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8,
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+    MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+#endif
+/* The PSK suites */
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_PSK_WITH_AES_256_CCM,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384,
+    MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8,
+#endif
+
+#if defined(MBEDTLS_GCM_C)
+    MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_PSK_WITH_AES_128_CCM,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256,
+    MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA,
+#endif
+#if defined(MBEDTLS_CCM_C)
+    MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8,
+#endif
+#endif
+
+#if 0
+	/* 3DES suites */
+	MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+	MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+	MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+	MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+	MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+#endif
+#if defined(MBEDTLS_ARC4_C)
+    /* RC4 suites */
+    MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, MBEDTLS_TLS_RSA_WITH_RC4_128_SHA,
+    MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA,
+    MBEDTLS_TLS_PSK_WITH_RC4_128_SHA,
+#endif
+    0};
+
+#ifdef CONFIG_SUITEB192
+static const int suiteb_rsa_ciphersuite_preference[] = {
+#if defined(MBEDTLS_GCM_C)
+#if defined(MBEDTLS_SHA512_C)
+    MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+#endif
+    0};
+
+static const int suiteb_ecc_ciphersuite_preference[] = {
+#if defined(MBEDTLS_GCM_C)
+#if defined(MBEDTLS_SHA512_C)
+    MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+#endif
+#endif
+    0};
+static const int suiteb_ciphersuite_preference[] = {
+#if defined(MBEDTLS_GCM_C)
+#if defined(MBEDTLS_SHA512_C)
+    MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+    MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+    MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+#endif
+#endif
+    0};
+#endif
+
+static void
+tls_set_ciphersuite(const struct tls_connection_params *cfg, tls_context_t *tls)
+{
+	/* Only set ciphersuite if cert's key length is high or ciphersuites are
+	 * set by user */
+#ifdef CONFIG_SUITEB192
+	if (cfg->flags & TLS_CONN_SUITEB) {
+		/* cipher suites will be set based on certificate */
+		mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(&tls->clientkey);
+		if (pk_alg == MBEDTLS_PK_RSA ||
+		    pk_alg == MBEDTLS_PK_RSASSA_PSS) {
+			mbedtls_ssl_conf_ciphersuites(
+			    &tls->conf, suiteb_rsa_ciphersuite_preference);
+		} else if (
+		    pk_alg == MBEDTLS_PK_ECDSA || pk_alg == MBEDTLS_PK_ECKEY ||
+		    pk_alg == MBEDTLS_PK_ECKEY_DH) {
+			mbedtls_ssl_conf_ciphersuites(
+			    &tls->conf, suiteb_ecc_ciphersuite_preference);
+		} else {
+			mbedtls_ssl_conf_ciphersuites(
+			    &tls->conf, suiteb_ciphersuite_preference);
+		}
+	} else
+#endif
+	    if (tls->ciphersuite[0]) {
+		mbedtls_ssl_conf_ciphersuites(&tls->conf, tls->ciphersuite);
+	} else if (
+	    mbedtls_pk_get_bitlen(&tls->clientkey) > 2048 ||
+	    (tls->cacert_ptr &&
+	     mbedtls_pk_get_bitlen(&tls->cacert_ptr->MBEDTLS_PRIVATE(pk)) >
+		 2048)) {
+		mbedtls_ssl_conf_ciphersuites(
+		    &tls->conf, eap_ciphersuite_preference);
+	}
+}
+
+static int
+parse_certs(const struct tls_connection_params *cfg, tls_context_t *tls)
+{
+	int ret;
+
+#ifdef CONFIG_MBEDTLS_FS_IO
+	if (cfg->ca_cert) {
+		tls->cacert_ptr = &tls->cacert;
+		mbedtls_x509_crt_init(tls->cacert_ptr);
+
+		ret = mbedtls_x509_crt_parse_file(&tls->cacert, cfg->ca_cert);
+		if (ret < 0) {
+			wpa_printf(
+			    MSG_ERROR,
+			    "mbedtls_x509_crt_parse_der failed -0x%x", -ret);
+			return -1;
+		}
+
+		mbedtls_ssl_conf_authmode(
+		    &tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+		mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
+		wpa_printf(MSG_ERROR, "Loaded CA cert: %s\n", cfg->ca_cert);
+
+	} else
+#endif
+	    if (cfg->ca_cert_blob != NULL) {
+		ret =
+		    set_ca_cert(tls, cfg->ca_cert_blob, cfg->ca_cert_blob_len);
+		if (ret != 0) {
+			return ret;
+		}
+		mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
+	} else {
+		mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
+	}
+
+#ifdef CONFIG_MBEDTLS_FS_IO
+	if (cfg->client_cert && cfg->private_key) {
+		mbedtls_x509_crt_init(&tls->clientcert);
+		ret = mbedtls_x509_crt_parse_file(
+		    &tls->clientcert, cfg->client_cert);
+		if (ret < 0) {
+			wpa_printf(
+			    MSG_ERROR,
+			    "mbedtls_x509_crt_parse_der failed -0x%x", -ret);
+			return -1;
+		}
+		wpa_printf(
+		    MSG_ERROR, "Loaded Client cert: %s\n", cfg->client_cert);
+
+		mbedtls_pk_init(&tls->clientkey);
+		ret = mbedtls_pk_parse_keyfile(
+		    &tls->clientkey, cfg->private_key, cfg->private_key_passwd,
+		    f_rng, NULL);
+		if (ret < 0) {
+			wpa_printf(
+			    MSG_ERROR, "mbedtls_pk_parse_key failed -0x%x",
+			    -ret);
+			return -1;
+		}
+		wpa_printf(
+		    MSG_ERROR, "Loaded private key: %s\n", cfg->private_key);
+
+		ret = mbedtls_ssl_conf_own_cert(
+		    &tls->conf, &tls->clientcert, &tls->clientkey);
+		if (ret < 0) {
+			wpa_printf(
+			    MSG_ERROR,
+			    "mbedtls_ssl_conf_own_cert returned -0x%x", -ret);
+			return ret;
+		}
+		wpa_printf(MSG_ERROR, "Loaded client and key\n");
+
+	} else
+#endif
+	    if (cfg->client_cert_blob != NULL &&
+		cfg->private_key_blob != NULL) {
+		ret = set_pki_context(tls, cfg);
+		if (ret != 0) {
+			wpa_printf(
+			    MSG_ERROR, "Failed to set client pki context");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int
+set_client_config(const struct tls_connection_params *cfg, tls_context_t *tls)
+{
+	int ret;
+	int preset = MBEDTLS_SSL_PRESET_DEFAULT;
+	assert(cfg != NULL);
+	assert(tls != NULL);
+
+#ifdef CONFIG_SUITEB192
+	if (cfg->flags & TLS_CONN_SUITEB)
+		preset = MBEDTLS_SSL_PRESET_SUITEB;
+#endif
+	ret = mbedtls_ssl_config_defaults(
+	    &tls->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
+	    preset);
+	if (ret != 0) {
+		wpa_printf(
+		    MSG_ERROR, "mbedtls_ssl_config_defaults returned -0x%x",
+		    -ret);
+		return ret;
+	}
+
+	if (preset != MBEDTLS_SSL_PRESET_SUITEB) {
+		/* Enable SHA1 support since it's not enabled by default in
+		 * mbedtls */
+		tls_enable_sha1_config(tls);
+#ifdef CONFIG_SUITEB192
+	} else {
+		tls_set_suiteb_config(tls);
+#endif
+	}
+	wpa_printf(
+	    MSG_ERROR, ": mbedtls_ssl_config_defaults: ciphersuite: %s\n",
+	    mbedtls_ssl_get_ciphersuite(&tls->ssl));
+
+	wpa_printf(MSG_ERROR, ": CA cert: %s\n", cfg->ca_cert);
+	wpa_printf(MSG_ERROR, ": Client cert: %s\n", cfg->client_cert);
+	wpa_printf(MSG_ERROR, ": Client key: %s\n", cfg->private_key);
+
+	if ((ret = parse_certs(cfg, tls))) {
+		wpa_printf(MSG_ERROR, "Failed to load certs: %d\n", ret);
+		return ret;
+	}
+	wpa_printf(MSG_INFO, "Loaded certs\n");
+
+	/* Usages of default ciphersuites can take a lot of time on low end
+	 * device and can cause watchdog. Enabling the ciphers which are secured
+	 * enough but doesn't take that much processing power */
+	tls_set_ciphersuite(cfg, tls);
+
+	return 0;
+}
+
+static int tls_create_mbedtls_handle(
+    const struct tls_connection_params *params, tls_context_t *tls)
+{
+	int ret;
+
+	assert(params != NULL);
+	assert(tls != NULL);
+
+	mbedtls_ssl_init(&tls->ssl);
+	mbedtls_ctr_drbg_init(&tls->ctr_drbg);
+	mbedtls_ssl_config_init(&tls->conf);
+	mbedtls_entropy_init(&tls->entropy);
+
+	ret = set_client_config(params, tls);
+	if (ret != 0) {
+		wpa_printf(MSG_ERROR, "Failed to set client configurations");
+		goto exit;
+	}
+
+	ret = mbedtls_ctr_drbg_seed(
+	    &tls->ctr_drbg, mbedtls_entropy_func, &tls->entropy, NULL, 0);
+	if (ret != 0) {
+		wpa_printf(
+		    MSG_ERROR, "mbedtls_ctr_drbg_seed returned -0x%x", -ret);
+		goto exit;
+	}
+
+	mbedtls_ssl_conf_rng(
+	    &tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg);
+
+	ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf);
+	if (ret != 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_ssl_setup returned -0x%x", -ret);
+		goto exit;
+	}
+#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
+	/* Disable BEAST attack countermeasures for Windows 2008
+	 * interoperability */
+	mbedtls_ssl_conf_cbc_record_splitting(
+	    &tls->conf, MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED);
+#endif
+
+	return 0;
+
+exit:
+	tls_mbedtls_cleanup(tls);
+	return ret;
+}
+
+void *tls_init(const struct tls_config *conf)
+{
+	tls_instance_count++;
+	return &tls_instance_count;
+}
+
+void tls_deinit(void *tls_ctx) { tls_instance_count--; }
+
+struct tls_connection *tls_connection_init(void *tls_ctx)
+{
+	struct tls_connection *conn = os_zalloc(sizeof(*conn));
+	if (!conn) {
+		wpa_printf(
+		    MSG_ERROR, "TLS: Failed to allocate connection memory");
+		return NULL;
+	}
+
+	return conn;
+}
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+	/* case: tls init failed */
+	if (!conn) {
+		return;
+	}
+	/* Free ssl ctx and data */
+	tls_mbedtls_conn_delete((tls_context_t *)conn->tls);
+	os_free(conn->tls);
+	conn->tls = NULL;
+	/* Data in in ssl ctx, free connection */
+	os_free(conn);
+}
+
+int tls_get_errors(void *tls_ctx) { return 0; }
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+	mbedtls_ssl_context *ssl = &conn->tls->ssl;
+
+	if (ssl->MBEDTLS_PRIVATE(state) == MBEDTLS_SSL_HANDSHAKE_OVER) {
+		return 1;
+	}
+
+	return 0;
+}
+
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
+{
+	wpa_printf(MSG_INFO, "TLS: global settings are not supported");
+	return -1;
+}
+
+int tls_connection_set_verify(
+    void *tls_ctx, struct tls_connection *conn, int verify_peer,
+    unsigned int flags, const u8 *session_ctx, size_t session_ctx_len)
+{
+	wpa_printf(MSG_INFO, "TLS: tls_connection_set_verify not supported");
+	return -1;
+}
+
+struct wpabuf *tls_connection_handshake(
+    void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data,
+    struct wpabuf **appl_data)
+{
+	tls_context_t *tls = conn->tls;
+	int ret = 0;
+
+	/* data freed by sender */
+	conn->tls_io_data.out_data = NULL;
+	if (wpabuf_len(in_data)) {
+		conn->tls_io_data.in_data = wpabuf_dup(in_data);
+	}
+
+	/* Multiple reads */
+	while (tls->ssl.MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
+		ret = mbedtls_ssl_handshake_step(&tls->ssl);
+
+		if (ret < 0)
+			break;
+	}
+	if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ) {
+		wpa_printf(MSG_INFO, "%s: ret is %d", __func__, ret);
+		goto end;
+	}
+
+	if (!conn->tls_io_data.out_data) {
+		wpa_printf(
+		    MSG_INFO,
+		    "application data is null, adding one byte for ack");
+		u8 *dummy = os_zalloc(1);
+		conn->tls_io_data.out_data = wpabuf_alloc_ext_data(dummy, 0);
+	}
+
+end:
+	return conn->tls_io_data.out_data;
+}
+
+struct wpabuf *tls_connection_server_handshake(
+    void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data,
+    struct wpabuf **appl_data)
+{
+	wpa_printf(MSG_ERROR, "%s: not supported %d", __func__, __LINE__);
+	return NULL;
+}
+
+struct wpabuf *tls_connection_encrypt(
+    void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data)
+{
+	/* Reset dangling pointer */
+	conn->tls_io_data.out_data = NULL;
+
+	ssize_t ret = mbedtls_ssl_write(
+	    &conn->tls->ssl, (unsigned char *)wpabuf_head(in_data),
+	    wpabuf_len(in_data));
+
+	if (ret < wpabuf_len(in_data)) {
+		wpa_printf(
+		    MSG_ERROR, "%s:%d, not able to write whole data", __func__,
+		    __LINE__);
+	}
+
+	return conn->tls_io_data.out_data;
+}
+
+struct wpabuf *tls_connection_decrypt(
+    void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data)
+{
+	unsigned char buf[1200];
+	int ret;
+	conn->tls_io_data.in_data = wpabuf_dup(in_data);
+	ret = mbedtls_ssl_read(&conn->tls->ssl, buf, 1200);
+	if (ret < 0) {
+		wpa_printf(
+		    MSG_ERROR, "%s:%d, not able to write whole data", __func__,
+		    __LINE__);
+		return NULL;
+	}
+
+	struct wpabuf *out = wpabuf_alloc_copy(buf, ret);
+
+	return out;
+}
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+	if (conn && conn->tls) {
+		mbedtls_ssl_session *session = NULL;
+
+		// If we have a session, then its resumed
+		mbedtls_ssl_get_session(&conn->tls->ssl, session);
+
+		if (session) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* cipher array should contain cipher number in mbedtls num as per IANA
+ * Please see cipherlist is u8, therefore only initial ones are supported */
+int tls_connection_set_cipher_list(
+    void *tls_ctx, struct tls_connection *conn, u8 *ciphers)
+{
+	int i = 0;
+
+	while (*ciphers != 0 && i < MAX_CIPHERSUITE) {
+		conn->tls->ciphersuite[i] = ciphers[i];
+		i++;
+	}
+	return 0;
+}
+
+int tls_get_version(
+    void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen)
+{
+	const char *name;
+
+	if (conn == NULL) {
+		return -1;
+	}
+
+	name = mbedtls_ssl_get_version(&conn->tls->ssl);
+	if (name == NULL) {
+		return -1;
+	}
+
+	os_strlcpy(buf, name, buflen);
+
+	return 0;
+}
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+
+	return os_snprintf(buf, buf_len, "MbedTLS build=test run=test");
+}
+
+// Lifted from https://stackoverflow.com/a/47117431
+char *strremove(char *str, const char *sub)
+{
+	char *p, *q, *r;
+	if (*sub && (q = r = os_strstr(str, sub)) != NULL) {
+		size_t len = os_strlen(sub);
+		while ((r = os_strstr(p = r + len, sub)) != NULL) {
+			os_memmove(q, p, r - p);
+			q += r - p;
+		}
+		os_memmove(q, p, strlen(p) + 1);
+	}
+	return str;
+}
+
+// Lifted from: https://stackoverflow.com/a/779960
+// You must free the result if result is non-NULL.
+char *str_replace(char *orig, char *rep, char *with)
+{
+	char *result;  // the return string
+	char *ins;     // the next insert point
+	char *tmp;     // varies
+	int len_rep;   // length of rep (the string to remove)
+	int len_with;  // length of with (the string to replace rep with)
+	int len_front; // distance between rep and end of last rep
+	int count;     // number of replacements
+
+	// sanity checks and initialization
+	if (!orig || !rep)
+		return NULL;
+	len_rep = strlen(rep);
+	if (len_rep == 0)
+		return NULL; // empty rep causes infinite loop during count
+	if (!with)
+		with = "";
+	len_with = strlen(with);
+
+	// count the number of replacements needed
+	ins = orig;
+	for (count = 0; (tmp = strstr(ins, rep)); ++count) {
+		ins = tmp + len_rep;
+	}
+
+	tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
+
+	if (!result)
+		return NULL;
+
+	// first time through the loop, all the variable are set correctly
+	// from here on,
+	//    tmp points to the end of the result string
+	//    ins points to the next occurrence of rep in orig
+	//    orig points to the remainder of orig after "end of rep"
+	while (count--) {
+		ins = strstr(orig, rep);
+		len_front = ins - orig;
+		tmp = strncpy(tmp, orig, len_front) + len_front;
+		tmp = strcpy(tmp, with) + len_with;
+		orig += len_front + len_rep; // move to next "end of rep"
+	}
+	strcpy(tmp, orig);
+	return result;
+}
+
+int tls_get_cipher(
+    void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen)
+{
+	const char *name;
+	if (conn == NULL) {
+		return -1;
+	}
+
+	name = mbedtls_ssl_get_ciphersuite(&conn->tls->ssl);
+	if (name == NULL) {
+		return -1;
+	}
+
+	os_strlcpy(buf, name, buflen);
+
+	// Translate to common format for hwsim tests to pass
+	strremove(buf, "TLS-");
+	strremove(buf, "WITH-");
+	char *tmp = str_replace(buf, "AES-", "AES");
+	os_memcpy(buf, tmp, buflen);
+	free(tmp);
+
+	return 0;
+}
+
+int tls_connection_enable_workaround(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+void tls_connection_set_success_data(
+    struct tls_connection *conn, struct wpabuf *data)
+{}
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn) {}
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+	return NULL;
+}
+
+void tls_connection_remove_session(struct tls_connection *conn) {}
+
+char *tls_connection_peer_serial_num(void *tls_ctx, struct tls_connection *conn)
+{
+	return NULL;
+}
+
+int tls_connection_set_params(
+    void *tls_ctx, struct tls_connection *conn,
+    const struct tls_connection_params *params)
+{
+	int ret = 0;
+
+	wpa_printf(
+	    MSG_ERROR, " client_cert 4is %s, %p", params->client_cert, params);
+
+	tls_context_t *tls = (tls_context_t *)os_zalloc(sizeof(tls_context_t));
+
+	if (!tls) {
+		wpa_printf(MSG_ERROR, "failed to allocate tls context");
+		return -1;
+	}
+	if (!params) {
+		wpa_printf(MSG_ERROR, "configuration is null");
+		ret = -1;
+		goto err;
+	}
+	// assert(params->client_cert != NULL);
+
+	ret = tls_create_mbedtls_handle(params, tls);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "failed to create ssl handle");
+		goto err;
+	}
+	mbedtls_ssl_set_bio(
+	    &tls->ssl, conn, tls_mbedtls_write, tls_mbedtls_read, NULL);
+	conn->tls = (tls_context_t *)tls;
+
+	mbedtls_ssl_set_export_keys_cb(
+	    &conn->tls->ssl, tls_connection_export_keys_cb, conn);
+
+	return ret;
+err:
+	os_free(tls);
+	return ret;
+}
+
+int tls_global_set_params(
+    void *tls_ctx, const struct tls_connection_params *params)
+{
+	wpa_printf(MSG_INFO, "TLS: Global parameters not supported");
+	return -1;
+}
+
+int tls_connection_set_session_ticket_cb(
+    void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb,
+    void *ctx)
+{
+	wpa_printf(MSG_ERROR, "TLS: %s not supported", __func__);
+	return -1;
+}
+
+void tls_connection_export_keys_cb(
+    void *p_expkey, mbedtls_ssl_key_export_type secret_type,
+    const unsigned char *secret, size_t secret_len,
+    const unsigned char client_random[32],
+    const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type)
+
+{
+	struct tls_connection *conn = p_expkey;
+
+	os_memcpy(conn->randbytes, client_random, TLS_RANDOM_LEN);
+	os_memcpy(
+	    conn->randbytes + TLS_RANDOM_LEN, server_random, TLS_RANDOM_LEN);
+	os_memcpy(conn->master_secret, secret, secret_len);
+	conn->tls_prf_type = tls_prf_type;
+}
+static int tls_connection_prf(
+    void *tls_ctx, struct tls_connection *conn, const char *label,
+    int server_random_first, u8 *out, size_t out_len)
+{
+	int ret;
+	u8 seed[2 * TLS_RANDOM_LEN];
+	mbedtls_ssl_context *ssl = &conn->tls->ssl;
+
+	if (!ssl || !conn) {
+		wpa_printf(
+		    MSG_ERROR, "TLS: %s, connection  info is null", __func__);
+		return -1;
+	}
+	if (ssl->MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
+		wpa_printf(
+		    MSG_ERROR, "TLS: %s, incorrect tls state=%d", __func__,
+		    ssl->MBEDTLS_PRIVATE(state));
+		return -1;
+	}
+
+	if (server_random_first) {
+		os_memcpy(
+		    seed, conn->randbytes + TLS_RANDOM_LEN, TLS_RANDOM_LEN);
+		os_memcpy(
+		    seed + TLS_RANDOM_LEN, conn->randbytes, TLS_RANDOM_LEN);
+	} else {
+		os_memcpy(seed, conn->randbytes, 2 * TLS_RANDOM_LEN);
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, "random", seed, 2 * TLS_RANDOM_LEN);
+	wpa_hexdump_key(
+	    MSG_MSGDUMP, "master", conn->master_secret, TLS_MASTER_SECRET_LEN);
+
+	if (conn->tls_prf_type == MBEDTLS_SSL_TLS_PRF_SHA384) {
+		ret = tls_prf_sha384(
+		    conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed,
+		    2 * TLS_RANDOM_LEN, out, out_len);
+	} else if (conn->tls_prf_type == MBEDTLS_SSL_TLS_PRF_SHA256) {
+		ret = tls_prf_sha256(
+		    conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed,
+		    2 * TLS_RANDOM_LEN, out, out_len);
+	} else {
+		ret = tls_prf_sha1_md5(
+		    conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed,
+		    2 * TLS_RANDOM_LEN, out, out_len);
+	}
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "prf failed, ret=%d\n", ret);
+	}
+	wpa_hexdump_key(MSG_MSGDUMP, "key", out, out_len);
+
+	return ret;
+}
+
+int tls_connection_export_key(
+    void *tls_ctx, struct tls_connection *conn, const char *label,
+    const u8 *context, size_t context_len, u8 *out, size_t out_len)
+{
+	return tls_connection_prf(tls_ctx, conn, label, 0, out, out_len);
+}
+
+int tls_connection_get_eap_fast_key(
+    void *tls_ctx, struct tls_connection *conn, u8 *out, size_t out_len)
+{
+	wpa_printf(
+	    MSG_INFO, "TLS: tls_connection_get_eap_fast_key not supported, "
+		      "please unset mbedtls crypto and try again");
+	return -1;
+}
+
+int tls_connection_client_hello_ext(
+    void *tls_ctx, struct tls_connection *conn, int ext_type, const u8 *data,
+    size_t data_len)
+{
+	wpa_printf(
+	    MSG_INFO, "TLS: tls_connection_client_hello_ext not supported, "
+		      "please unset mbedtls crypto and try again");
+	return -1;
+}
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+	if (conn->tls_io_data.in_data) {
+		wpabuf_free(conn->tls_io_data.in_data);
+	}
+	conn->tls_io_data.in_data = NULL;
+
+	/* outdata may have dangling pointer */
+	conn->tls_io_data.out_data = NULL;
+
+	return mbedtls_ssl_session_reset(&conn->tls->ssl);
+}
+
+int tls_connection_get_random(
+    void *tls_ctx, struct tls_connection *conn, struct tls_random *data)
+{
+	mbedtls_ssl_context *ssl = &conn->tls->ssl;
+
+	os_memset(data, 0, sizeof(*data));
+	if (ssl->MBEDTLS_PRIVATE(state) == MBEDTLS_SSL_CLIENT_HELLO) {
+		return -1;
+	}
+
+	data->client_random = conn->randbytes;
+	data->client_random_len = TLS_RANDOM_LEN;
+
+	if (ssl->MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_SERVER_HELLO) {
+		data->server_random = conn->randbytes + TLS_RANDOM_LEN;
+		data->server_random_len = TLS_RANDOM_LEN;
+	}
+
+	return 0;
+}
diff --git a/tests/build/build-wpa_supplicant-mbedtls-3.1.0.config b/tests/build/build-wpa_supplicant-mbedtls-3.1.0.config
new file mode 100644
index 000000000..2ccfaef0e
--- /dev/null
+++ b/tests/build/build-wpa_supplicant-mbedtls-3.1.0.config
@@ -0,0 +1,29 @@
+CONFIG_TLS=mbedtls
+INSTALL_DIR=/usr/local/
+CFLAGS += -I$(INSTALL_DIR)/include
+LIBS += -L$(INSTALL_DIR)/lib
+LDFLAGS += -Wl,-rpath=$(INSTALL_DIR)/lib
+CONFIG_TLS_ADD_DL=y
+
+CONFIG_WPS=y
+CONFIG_EAP_TLS=y
+CONFIG_EAP_MSCHAPV2=y
+
+CONFIG_EAP_PSK=y
+CONFIG_EAP_GPSK=y
+CONFIG_EAP_AKA=y
+CONFIG_EAP_SIM=y
+CONFIG_EAP_SAKE=y
+CONFIG_EAP_PAX=y
+CONFIG_EAP_FAST=y
+CONFIG_EAP_IKEV2=y
+
+CONFIG_SAE=y
+CONFIG_FILS=y
+CONFIG_FILS_SK_PFS=y
+CONFIG_OWE=y
+CONFIG_DPP=y
+CONFIG_SUITEB=y
+CONFIG_SUITEB192=y
+
+CFLAGS += -Werror
\ No newline at end of file
diff --git a/tests/build/run-build-tests.sh b/tests/build/run-build-tests.sh
index 347ca39a0..8cc446e90 100755
--- a/tests/build/run-build-tests.sh
+++ b/tests/build/run-build-tests.sh
@@ -8,13 +8,10 @@ popd > /dev/null
 echo "Build test directory: $DIR"
 echo
 
-for i in build-hostapd-*.config; do
-    ./build-hostapd.sh $DIR $i
-done
-
-for i in build-wpa_supplicant-*.config; do
+for i in build-wpa_supplicant-mbedtls-3.1.0.config; do
     ./build-wpa_supplicant.sh $DIR $i
 done
 
 echo
 echo "Build test directory: $DIR"
+cat $DIR/wpa_supplicant-mbedtls-3.1.0.log-*
\ No newline at end of file
diff --git a/tests/hwsim/test_suite_b.py b/tests/hwsim/test_suite_b.py
index 7065b18bd..79f76f580 100644
--- a/tests/hwsim/test_suite_b.py
+++ b/tests/hwsim/test_suite_b.py
@@ -22,7 +22,7 @@ def check_suite_b_capa(dev):
 
 def check_suite_b_tls_lib(dev, dhe=False, level128=False):
     tls = dev[0].request("GET tls_library")
-    if tls.startswith("GnuTLS"):
+    if tls.startswith("GnuTLS")  or tls.startswith("MbedTLS"):
         return
     if not tls.startswith("OpenSSL"):
         raise HwsimSkip("TLS library not supported for Suite B: " + tls)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index ce1c8b2e3..536277c69 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -35,7 +35,7 @@ export INCDIR ?= /usr/local/include
 export BINDIR ?= /usr/local/sbin
 PKG_CONFIG ?= pkg-config
 
-CFLAGS += $(EXTRA_CFLAGS)
+CFLAGS += $(EXTRA_CFLAGS) -Werror
 CFLAGS += -I$(abspath ../src)
 CFLAGS += -I$(abspath ../src/utils)
 
@@ -145,6 +145,7 @@ ifndef CONFIG_ELOOP
 CONFIG_ELOOP=eloop
 endif
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_p += ../src/utils/$(CONFIG_ELOOP).o
 OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
 
 ifndef CONFIG_OSX
@@ -258,9 +259,12 @@ ifdef CONFIG_SAE
 CFLAGS += -DCONFIG_SAE
 OBJS += ../src/common/sae.o
 ifdef CONFIG_SAE_PK
+# NO ECDH support yet
+ifneq ($(CONFIG_TLS), mbedtls)
 CFLAGS += -DCONFIG_SAE_PK
 OBJS += ../src/common/sae_pk.o
 endif
+endif
 NEED_ECC=y
 NEED_DH_GROUPS=y
 NEED_HMAC_SHA256_KDF=y
@@ -271,6 +275,8 @@ endif
 endif
 
 ifdef CONFIG_DPP
+# NO ECDH support yet
+ifneq ($(CONFIG_TLS), mbedtls)
 CFLAGS += -DCONFIG_DPP
 OBJS += ../src/common/dpp.o
 OBJS += ../src/common/dpp_auth.o
@@ -295,8 +301,11 @@ ifdef CONFIG_DPP2
 CFLAGS += -DCONFIG_DPP2
 endif
 endif
+endif
 
 ifdef CONFIG_OWE
+# NO ECDH support yet
+ifneq ($(CONFIG_TLS), mbedtls)
 CFLAGS += -DCONFIG_OWE
 NEED_ECC=y
 NEED_HMAC_SHA256_KDF=y
@@ -305,16 +314,20 @@ NEED_HMAC_SHA512_KDF=y
 NEED_SHA384=y
 NEED_SHA512=y
 endif
+endif
 
 ifdef CONFIG_FILS
 CFLAGS += -DCONFIG_FILS
 NEED_SHA384=y
 NEED_AES_SIV=y
 ifdef CONFIG_FILS_SK_PFS
+# NO ECDH support yet
+ifneq ($(CONFIG_TLS), mbedtls)
 CFLAGS += -DCONFIG_FILS_SK_PFS
 NEED_ECC=y
 endif
 endif
+endif
 
 ifdef CONFIG_MBO
 CONFIG_WNM=y
@@ -396,6 +409,8 @@ endif
 endif
 
 ifdef CONFIG_PASN
+# NO ECDH support yet
+ifneq ($(CONFIG_TLS), mbedtls)
 CFLAGS += -DCONFIG_PASN
 CFLAGS += -DCONFIG_PTKSA_CACHE
 NEED_HMAC_SHA256_KDF=y
@@ -405,6 +420,7 @@ NEED_SHA384=y
 OBJS += ../src/common/ptksa_cache.o
 OBJS += pasn_supplicant.o
 endif
+endif
 
 ifdef CONFIG_HS20
 OBJS += hs20_supplicant.o
@@ -674,6 +690,7 @@ NEED_T_PRF=y
 endif
 
 ifdef CONFIG_EAP_TEAP
+ifneq ($(CONFIG_TLS), mbedtls)
 # EAP-TEAP
 SRC_EAP_TEAP = ../src/eap_peer/eap_teap.c ../src/eap_peer/eap_teap_pac.c
 SRC_EAP_TEAP += ../src/eap_common/eap_teap_common.c
@@ -684,6 +701,7 @@ else
 CFLAGS += -DEAP_TEAP
 OBJS += $(patsubst %.c, %.o, $(SRC_EAP_TEAP))
 endif
+endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
 NEED_T_PRF=y
@@ -972,10 +990,13 @@ OBJS += ../src/ap/wps_hostapd.o
 OBJS += ../src/eap_server/eap_server_wsc.o
 endif
 ifdef CONFIG_DPP
+# NO ECDH support yet
+ifneq ($(CONFIG_TLS), mbedtls)
 OBJS += ../src/ap/dpp_hostapd.o
 OBJS += ../src/ap/gas_query_ap.o
 NEED_AP_GAS_SERV=y
 endif
+endif
 ifdef CONFIG_INTERWORKING
 NEED_AP_GAS_SERV=y
 endif
@@ -1125,6 +1146,41 @@ endif
 CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
 endif
 
+ifeq ($(CONFIG_TLS), mbedtls)
+CFLAGS += -DCONFIG_MBEDTLS_FS_IO
+CFLAGS += -I/usr/local/include/
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_mbedtls.o
+LIBS += -lmbedtls -lmbedx509
+endif
+OBJS += ../src/crypto/crypto_mbedtls.o
+OBJS_p += ../src/crypto/crypto_mbedtls.o
+OBJS_priv += ../src/crypto/crypto_mbedtls.o
+
+OBJS += ../src/crypto/crypto_mbedtls-bignum.o
+OBJS_p += ../src/crypto/crypto_mbedtls-bignum.o
+OBJS_priv += ../src/crypto/crypto_mbedtls-bignum.o
+
+OBJS += ../src/crypto/crypto_mbedtls-ec.o
+OBJS_p += ../src/crypto/crypto_mbedtls-ec.o
+OBJS_priv += ../src/crypto/crypto_mbedtls-ec.o
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+NEED_HMAC_SHA384_KDF=y
+OBJS += ../src/crypto/fips_prf_internal.o
+SHA1OBJS += ../src/crypto/sha1-internal.o
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+CONFIG_INTERNAL_SHA512=y
+LIBS += -lmbedcrypto
+LIBS_p += -lmbedcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
+endif
+
 ifeq ($(CONFIG_TLS), gnutls)
 ifndef CONFIG_CRYPTO
 # default to libgcrypt
@@ -1317,9 +1373,11 @@ endif
 
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 NEED_INTERNAL_AES_WRAP=y
 endif
 endif
+endif
 ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP
 # Seems to be needed at least with BoringSSL
 NEED_INTERNAL_AES_WRAP=y
@@ -1345,8 +1403,10 @@ AESOBJS += ../src/crypto/aes-siv.o
 NEED_AES_CTR=y
 endif
 ifdef NEED_AES_CTR
+ifneq ($(CONFIG_TLS), mbedtls)
 AESOBJS += ../src/crypto/aes-ctr.o
 endif
+endif
 ifdef NEED_AES_ENCBLOCK
 AESOBJS += ../src/crypto/aes-encblock.o
 endif
@@ -1356,10 +1416,12 @@ CFLAGS += -DCONFIG_OPENSSL_CMAC
 else
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 AESOBJS += ../src/crypto/aes-omac1.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_WRAP
 NEED_AES_ENC=y
 ifdef NEED_INTERNAL_AES_WRAP
@@ -1371,11 +1433,13 @@ NEED_AES_ENC=y
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 AESOBJS += ../src/crypto/aes-cbc.o
 endif
 endif
 endif
 endif
+endif
 ifdef NEED_AES_ENC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += ../src/crypto/aes-internal-enc.o
@@ -1390,11 +1454,14 @@ ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 SHA1OBJS += ../src/crypto/sha1.o
 endif
 endif
 endif
 endif
+endif
+
 SHA1OBJS += ../src/crypto/sha1-prf.o
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += ../src/crypto/sha1-internal.o
@@ -1407,10 +1474,12 @@ CFLAGS += -DCONFIG_NO_PBKDF2
 else
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
 endif
 endif
 endif
+endif
 ifdef NEED_T_PRF
 SHA1OBJS += ../src/crypto/sha1-tprf.o
 endif
@@ -1424,12 +1493,14 @@ ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 MD5OBJS += ../src/crypto/md5.o
 endif
 endif
 endif
 endif
 endif
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += ../src/crypto/md5-internal.o
@@ -1473,11 +1544,14 @@ ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 SHA256OBJS += ../src/crypto/sha256.o
 endif
 endif
 endif
 endif
+endif
+
 SHA256OBJS += ../src/crypto/sha256-prf.o
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += ../src/crypto/sha256-internal.o
@@ -1514,11 +1588,13 @@ ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
 ifneq ($(CONFIG_TLS), gnutls)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 OBJS += ../src/crypto/sha384.o
 endif
 endif
 endif
 endif
+endif
 CFLAGS += -DCONFIG_SHA384
 OBJS += ../src/crypto/sha384-prf.o
 endif
@@ -1563,6 +1639,9 @@ ifdef CONFIG_GETRANDOM
 CFLAGS += -DCONFIG_GETRANDOM
 endif
 OBJS += ../src/crypto/random.o
+OBJS_p += ../src/crypto/random.o
+OBJS_priv += ../src/crypto/random.o
+
 endif
 
 ifdef CONFIG_CTRL_IFACE
@@ -1709,10 +1788,12 @@ ifdef CONFIG_FIPS
 CFLAGS += -DCONFIG_FIPS
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), wolfssl)
+ifneq ($(CONFIG_TLS), mbedtls)
 $(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
 endif
 endif
 endif
+endif
 
 OBJS += $(SHA1OBJS) $(DESOBJS)
 
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 708a82385..fabbd69e3 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -318,6 +318,7 @@ CONFIG_BACKEND=file
 # gnutls = GnuTLS
 # internal = Internal TLSv1 implementation (experimental)
 # linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
+# mbedtls = Mbed TLS
 # none = Empty template
 #CONFIG_TLS=openssl
 
