diff mbox series

Add support for mbedtls crypto library for STA mode

Message ID 20220424161034.1365496-1-krish271828@gmail.com
State Changes Requested
Headers show
Series Add support for mbedtls crypto library for STA mode | expand

Commit Message

krishna t April 24, 2022, 4:10 p.m. UTC
From: Krishna <krishna.t@nordicsemi.no>

This is ideal for low footprint embedded systems, the patch adds support
for STA mode, the support is minimal, only mandatory stuff is added

  * DH group19 only for SAE
  * OWE, DPP and PASN are not supported as ECDH support is yet to be
    added.
  * EAP-TEAP is not supported yet

This implementation is based on work of ESP team [1], with below changes
  * decouple from esp_wifi
  * avoid any changes to core wpa_supplicant (esp. for WPA3)
  * port to 3.1.0 mbedtls

Tested WPA2/WPA3 associations personal/enterprise. Also, add a
configuration file with mbedtls for build tests.

Code auto-formatted using wpa_supplicant/binder/.clang-format.

[1] - https://github.com/espressif/esp-idf/tree/master/components/wpa_supplicant

Signed-off-by: Krishna <krishna.t@nordicsemi.no>
---
 hostapd/defconfig                             |    1 +
 src/crypto/crypto.h                           |    2 +
 src/crypto/crypto_mbedtls-bignum.c            |  310 +++++
 src/crypto/crypto_mbedtls-ec.c                |  935 +++++++++++++
 src/crypto/crypto_mbedtls.c                   |  910 +++++++++++++
 src/crypto/tls_mbedtls.c                      | 1181 +++++++++++++++++
 .../build-wpa_supplicant-mbedtls-3.1.0.config |   29 +
 tests/build/run-build-tests.sh                |    7 +-
 tests/hwsim/test_suite_b.py                   |    2 +-
 wpa_supplicant/Makefile                       |   83 +-
 wpa_supplicant/defconfig                      |    1 +
 11 files changed, 3454 insertions(+), 7 deletions(-)
 create mode 100644 src/crypto/crypto_mbedtls-bignum.c
 create mode 100644 src/crypto/crypto_mbedtls-ec.c
 create mode 100644 src/crypto/crypto_mbedtls.c
 create mode 100644 src/crypto/tls_mbedtls.c
 create mode 100644 tests/build/build-wpa_supplicant-mbedtls-3.1.0.config

Comments

Jouni Malinen May 1, 2022, 3:42 p.m. UTC | #1
On Sun, Apr 24, 2022 at 09:40:34PM +0530, krish271828@gmail.com wrote:
> This is ideal for low footprint embedded systems, the patch adds support
> for STA mode, the support is minimal, only mandatory stuff is added
> 
>   * DH group19 only for SAE
>   * OWE, DPP and PASN are not supported as ECDH support is yet to be
>     added.
>   * EAP-TEAP is not supported yet
> 
> This implementation is based on work of ESP team [1], with below changes
>   * decouple from esp_wifi
>   * avoid any changes to core wpa_supplicant (esp. for WPA3)
>   * port to 3.1.0 mbedtls
> 
> Tested WPA2/WPA3 associations personal/enterprise. Also, add a
> configuration file with mbedtls for build tests.
> 
> Code auto-formatted using wpa_supplicant/binder/.clang-format.
> 
> [1] - https://github.com/espressif/esp-idf/tree/master/components/wpa_supplicant

> diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
> +int crypto_bignum_bits(const struct crypto_bignum *a);

This does not seem to be used anywhere. I would prefer to separate
crypto.h additions into their own patch to keep things clearer. That
said, if this is not really going to be used anywhere, it does not look
helpful to add this function at this point.

> diff --git a/src/crypto/crypto_mbedtls-bignum.c b/src/crypto/crypto_mbedtls-bignum.c
> +/*
> + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
> + *
> + * SPDX-License-Identifier: Apache-2.0
> + */

Is there particular need for using the Apache license for these new
files? I would prefer to use the same BSD license for all of the
hostap.git implementation and there would need to be strong
justification for using something different.

This patch would seem to make hostap.git contents not comply with the
license requirements ("You must give any other recipients of the Work or
Derivative Works a copy of this License;" and the License text is not
included here), so even if I were to accept a different license to be
used, I could not accept something that would not meet the actual
license requirements.

> +// Lifted from https://stackoverflow.com/a/47117431
> +char *strremove(char *str, const char *sub)
...

> +// 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)
...

Can you please clarify what you mean with "lifted from"? I read this as
"taken without explicit permission and without identifying under which
license this is used". If that is accurate, I cannot accept such
contribution due to unclear license situation.

> diff --git 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-*

These changes are clearly not appropriate. It is fine to add a new test
config, but the test script must not be broken for other uses.

> diff --git 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

How is this connected to this particular patch?

> @@ -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

Why is this needed?

> @@ -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

I'd prefer the build to fail instead of hide the fact that explicitly
enabled build option could not be included, i.e., I would not add this
type of exceptions into Makefile.
krishna t May 1, 2022, 6:28 p.m. UTC | #2
On Sun, May 1, 2022 at 9:12 PM Jouni Malinen <j@w1.fi> wrote:
>
> On Sun, Apr 24, 2022 at 09:40:34PM +0530, krish271828@gmail.com wrote:
> > This is ideal for low footprint embedded systems, the patch adds support
> > for STA mode, the support is minimal, only mandatory stuff is added
> >
> >   * DH group19 only for SAE
> >   * OWE, DPP and PASN are not supported as ECDH support is yet to be
> >     added.
> >   * EAP-TEAP is not supported yet
> >
> > This implementation is based on work of ESP team [1], with below changes
> >   * decouple from esp_wifi
> >   * avoid any changes to core wpa_supplicant (esp. for WPA3)
> >   * port to 3.1.0 mbedtls
> >
> > Tested WPA2/WPA3 associations personal/enterprise. Also, add a
> > configuration file with mbedtls for build tests.
> >
> > Code auto-formatted using wpa_supplicant/binder/.clang-format.
> >
> > [1] - https://github.com/espressif/esp-idf/tree/master/components/wpa_supplicant
>
> > diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
> > +int crypto_bignum_bits(const struct crypto_bignum *a);
>
> This does not seem to be used anywhere. I would prefer to separate
> crypto.h additions into their own patch to keep things clearer. That
> said, if this is not really going to be used anywhere, it does not look
> helpful to add this function at this point.
Yes, this is unused, I can remove this, and as this is the only change
no need for a separate commit.
>
>
> > diff --git a/src/crypto/crypto_mbedtls-bignum.c b/src/crypto/crypto_mbedtls-bignum.c
> > +/*
> > + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
> > + *
> > + * SPDX-License-Identifier: Apache-2.0
> > + */
> Is there particular need for using the Apache license for these new
> files? I would prefer to use the same BSD license for all of the
> hostap.git implementation and there would need to be strong
> justification for using something different.
Sorry, I wasn't too sure about this and have not tried to contact the ESP
team.  As they own the code, I cannot change the license type, and
basic googling suggested that we can use a mix of Apache2.0
and BSD as long as we keep the original license as is. Though some
claim the resulting code has to be Apache2.0 as it is less permissive
than BSD.
>
> This patch would seem to make hostap.git contents not comply with the
> license requirements ("You must give any other recipients of the Work or
> Derivative Works a copy of this License;" and the License text is not
> included here), so even if I were to accept a different license to be
> used, I could not accept something that would not meet the actual
> license requirements.
So, IIUC, using SPDX ID's implies license text, no? I can surely add the
license file if that satisfies the needs. And also, I guess I should add a note
at the top that I have modified these.
>
> > +// Lifted from https://stackoverflow.com/a/47117431
> > +char *strremove(char *str, const char *sub)
> ...
>
> > +// 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)
> ...
>
> Can you please clarify what you mean with "lifted from"? I read this as
> "taken without explicit permission and without identifying under which
> license this is used". If that is accurate, I cannot accept such
> contribution due to unclear license situation.
Yes, this is copied as is, and that post is licensed under
https://creativecommons.org/licenses/by-sa/4.0/ (mentioned in the share link)
 and mentioning the source should satisfy the license IIUC. I can change
"Lifted from" to "original source" and move them to a separate file with SPDX
ID for those two functions?
And anyways, these changes are not strictly needed, they were made
to pass the hwsim tests.So, can use a simple switch case and avoid this
algother.
>
> > diff --git 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-*
>
> These changes are clearly not appropriate. It is fine to add a new test
> config, but the test script must not be broken for other uses.
Sorry, these are local changes, will be removed.
>
> > diff --git 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
>
> How is this connected to this particular patch?
Sorry, I was preparing another patch, spilled into here, will be removed.
>
> > @@ -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
>
> Why is this needed?
Sorry, these are local changes, will be removed.
> > @@ -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
>
> I'd prefer the build to fail instead of hide the fact that explicitly
> enabled build option could not be included, i.e., I would not add this
> type of exceptions into Makefile.
Okay. I will use $(error) as we do for other checks.
> --
> Jouni Malinen                                            PGP id EFC895FA
Krishna Chaitanya Aug. 24, 2023, 8:26 p.m. UTC | #3
On Mon, May 2, 2022 at 12:05 AM krishna t <krish271828@gmail.com> wrote:
>
> On Sun, May 1, 2022 at 9:12 PM Jouni Malinen <j@w1.fi> wrote:
> >
> > On Sun, Apr 24, 2022 at 09:40:34PM +0530, krish271828@gmail.com wrote:
> > > This is ideal for low footprint embedded systems, the patch adds support
> > > for STA mode, the support is minimal, only mandatory stuff is added
> > >
> > >   * DH group19 only for SAE
> > >   * OWE, DPP and PASN are not supported as ECDH support is yet to be
> > >     added.
> > >   * EAP-TEAP is not supported yet
> > >
> > > This implementation is based on work of ESP team [1], with below changes
> > >   * decouple from esp_wifi
> > >   * avoid any changes to core wpa_supplicant (esp. for WPA3)
> > >   * port to 3.1.0 mbedtls
> > >
> > > Tested WPA2/WPA3 associations personal/enterprise. Also, add a
> > > configuration file with mbedtls for build tests.
> > >
> > > Code auto-formatted using wpa_supplicant/binder/.clang-format.
> > >
> > > [1] - https://github.com/espressif/esp-idf/tree/master/components/wpa_supplicant
> >
> > > diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
> > > +int crypto_bignum_bits(const struct crypto_bignum *a);
> >
> > This does not seem to be used anywhere. I would prefer to separate
> > crypto.h additions into their own patch to keep things clearer. That
> > said, if this is not really going to be used anywhere, it does not look
> > helpful to add this function at this point.
> Yes, this is unused, I can remove this, and as this is the only change
> no need for a separate commit.
> >
> >
> > > diff --git a/src/crypto/crypto_mbedtls-bignum.c b/src/crypto/crypto_mbedtls-bignum.c
> > > +/*
> > > + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
> > > + *
> > > + * SPDX-License-Identifier: Apache-2.0
> > > + */
> > Is there particular need for using the Apache license for these new
> > files? I would prefer to use the same BSD license for all of the
> > hostap.git implementation and there would need to be strong
> > justification for using something different.
> Sorry, I wasn't too sure about this and have not tried to contact the ESP
> team.  As they own the code, I cannot change the license type, and
> basic googling suggested that we can use a mix of Apache2.0
> and BSD as long as we keep the original license as is. Though some
> claim the resulting code has to be Apache2.0 as it is less permissive
> than BSD.
> >
> > This patch would seem to make hostap.git contents not comply with the
> > license requirements ("You must give any other recipients of the Work or
> > Derivative Works a copy of this License;" and the License text is not
> > included here), so even if I were to accept a different license to be
> > used, I could not accept something that would not meet the actual
> > license requirements.
> So, IIUC, using SPDX ID's implies license text, no? I can surely add the
> license file if that satisfies the needs. And also, I guess I should add a note
> at the top that I have modified these.
> >
> > > +// Lifted from https://stackoverflow.com/a/47117431
> > > +char *strremove(char *str, const char *sub)
> > ...
> >
> > > +// 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)
> > ...
> >
> > Can you please clarify what you mean with "lifted from"? I read this as
> > "taken without explicit permission and without identifying under which
> > license this is used". If that is accurate, I cannot accept such
> > contribution due to unclear license situation.
> Yes, this is copied as is, and that post is licensed under
> https://creativecommons.org/licenses/by-sa/4.0/ (mentioned in the share link)
>  and mentioning the source should satisfy the license IIUC. I can change
> "Lifted from" to "original source" and move them to a separate file with SPDX
> ID for those two functions?
> And anyways, these changes are not strictly needed, they were made
> to pass the hwsim tests.So, can use a simple switch case and avoid this
> algother.
> >
> > > diff --git 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-*
> >
> > These changes are clearly not appropriate. It is fine to add a new test
> > config, but the test script must not be broken for other uses.
> Sorry, these are local changes, will be removed.
> >
> > > diff --git 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
> >
> > How is this connected to this particular patch?
> Sorry, I was preparing another patch, spilled into here, will be removed.
> >
> > > @@ -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
> >
> > Why is this needed?
> Sorry, these are local changes, will be removed.
> > > @@ -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
> >
> > I'd prefer the build to fail instead of hide the fact that explicitly
> > enabled build option could not be included, i.e., I would not add this
> > type of exceptions into Makefile.
> Okay. I will use $(error) as we do for other checks.
I was waiting for you ACK on licensing before submitting a new patch with
fixes for the others, sorry if that wasn't obvious. Else, I can submit a new
patch right away. Please suggest.
diff mbox series

Patch

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