[PATCH] Add support for mbedtls crypto library for STA mode
krish271828 at gmail.com
krish271828 at gmail.com
Sun Apr 24 09:10:34 PDT 2022
From: Krishna <krishna.t at 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 at 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
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
--
2.32.0
More information about the Hostap
mailing list