Parcourir la source

Merge branch 'feature/esp_tls_for_supplicant_v4.1' into 'release/v4.1'

wpa_supplicant: Support for mbedtls tls handshake(backport v4.1)

See merge request espressif/esp-idf!9856
Jiang Jiang Jian il y a 5 ans
Parent
commit
e365d1ff60

+ 27 - 17
components/wpa_supplicant/CMakeLists.txt

@@ -14,7 +14,6 @@ set(srcs "port/os_xtensa.c"
     "src/crypto/aes-unwrap.c"
     "src/crypto/aes-wrap.c"
     "src/crypto/aes-omac1.c"
-    "src/crypto/sha256-tlsprf.c"
     "src/crypto/bignum.c"
     "src/crypto/ccmp.c"
     "src/crypto/crypto_mbedtls.c"
@@ -36,6 +35,10 @@ set(srcs "port/os_xtensa.c"
     "src/crypto/sha1.c"
     "src/crypto/sha256-internal.c"
     "src/crypto/sha256.c"
+    "src/crypto/sha1-tlsprf.c"
+    "src/crypto/sha256-tlsprf.c"
+    "src/crypto/sha384-tlsprf.c"
+    "src/crypto/sha256-prf.c"
     "src/eap_peer/chap.c"
     "src/eap_peer/eap.c"
     "src/eap_peer/eap_common.c"
@@ -55,6 +58,26 @@ set(srcs "port/os_xtensa.c"
     "src/rsn_supp/pmksa_cache.c"
     "src/rsn_supp/wpa.c"
     "src/rsn_supp/wpa_ie.c"
+    "src/utils/base64.c"
+    "src/utils/common.c"
+    "src/utils/ext_password.c"
+    "src/utils/uuid.c"
+    "src/utils/wpabuf.c"
+    "src/utils/wpa_debug.c"
+    "src/wps/wps.c"
+    "src/wps/wps_attr_build.c"
+    "src/wps/wps_attr_parse.c"
+    "src/wps/wps_attr_process.c"
+    "src/wps/wps_common.c"
+    "src/wps/wps_dev_attr.c"
+    "src/wps/wps_enrollee.c"
+    "src/wps/wps_registrar.c"
+    "src/wps/wps_validate.c")
+
+if(CONFIG_WPA_MBEDTLS_CRYPTO)
+    set(tls_src "src/crypto/tls_mbedtls.c")
+else()
+    set(tls_src
     "src/tls/asn1.c"
     "src/tls/bignum.c"
     "src/tls/pkcs1.c"
@@ -72,23 +95,10 @@ set(srcs "port/os_xtensa.c"
     "src/tls/tlsv1_server_read.c"
     "src/tls/tlsv1_server_write.c"
     "src/tls/x509v3.c"
-    "src/utils/base64.c"
-    "src/utils/common.c"
-    "src/utils/ext_password.c"
-    "src/utils/uuid.c"
-    "src/utils/wpabuf.c"
-    "src/utils/wpa_debug.c"
-    "src/wps/wps.c"
-    "src/wps/wps_attr_build.c"
-    "src/wps/wps_attr_parse.c"
-    "src/wps/wps_attr_process.c"
-    "src/wps/wps_common.c"
-    "src/wps/wps_dev_attr.c"
-    "src/wps/wps_enrollee.c"
-    "src/wps/wps_registrar.c"
-    "src/wps/wps_validate.c")
+    )
+endif()
 
-idf_component_register(SRCS "${srcs}"
+idf_component_register(SRCS "${srcs}" "${tls_src}"
                     INCLUDE_DIRS include port/include include/esp_supplicant
                     PRIV_INCLUDE_DIRS src
                     PRIV_REQUIRES mbedtls)

+ 25 - 1
components/wpa_supplicant/component.mk

@@ -1,5 +1,29 @@
-COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant
+# supplicant make file
+
 COMPONENT_PRIV_INCLUDEDIRS := src
 COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/rsn_supp src/tls src/utils src/esp_supplicant src/wps
+COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant
+
+ifeq ($(CONFIG_WPA_MBEDTLS_CRYPTO), y)
+    COMPONENT_OBJEXCLUDE := src/tls/asn1.o \
+    src/tls/bignum.o \
+    src/tls/pkcs1.o \
+    src/tls/pkcs5.o \
+    src/tls/pkcs8.o \
+    src/tls/rsa.o \
+    src/tls/tls_internal.o \
+    src/tls/tlsv1_client.o \
+    src/tls/tlsv1_client_read.o \
+    src/tls/tlsv1_client_write.o \
+    src/tls/tlsv1_common.o \
+    src/tls/tlsv1_cred.o \
+    src/tls/tlsv1_record.o \
+    src/tls/tlsv1_server.o \
+    src/tls/tlsv1_server_read.o \
+    src/tls/tlsv1_server_write.o \
+    src/tls/x509v3.o
+else
+    COMPONENT_OBJEXCLUDE := src/crypto/tls_mbedtls.o
+endif
 
 CFLAGS += -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing

+ 3 - 14
components/wpa_supplicant/port/include/os.h

@@ -268,6 +268,9 @@ char * ets_strdup(const char *s);
 #ifndef os_strstr
 #define os_strstr(h, n) strstr((h), (n))
 #endif
+#ifndef os_strlcpy
+#define os_strlcpy(d, s, n) strlcpy((d), (s), (n))
+#endif
 
 #ifndef os_snprintf
 #ifdef _MSC_VER
@@ -282,18 +285,4 @@ static inline int os_snprintf_error(size_t size, int res)
         return res < 0 || (unsigned int) res >= size;
 }
 
-/**
- * os_strlcpy - Copy a string with size bound and NUL-termination
- * @dest: Destination
- * @src: Source
- * @siz: Size of the target buffer
- * Returns: Total length of the target string (length of src) (not including
- * NUL-termination)
- *
- * This function matches in behavior with the strlcpy(3) function in OpenBSD.
- */
-size_t os_strlcpy(char *dest, const char *src, size_t siz);
-
-
-
 #endif /* OS_H */

+ 5 - 2
components/wpa_supplicant/port/include/supplicant_opt.h

@@ -19,10 +19,13 @@
 
 #if CONFIG_WPA_MBEDTLS_CRYPTO
 #define USE_MBEDTLS_CRYPTO 1
+#else
+#define CONFIG_TLS_INTERNAL_CLIENT
+#define CONFIG_TLSV12
 #endif
 
-#if CONFIG_WPA_TLS_V12
-#define CONFIG_TLSV12
+#if CONFIG_WPA_DEBUG_PRINT
+#define DEBUG_PRINT
 #endif
 
 #endif /* _SUPPLICANT_OPT_H */

+ 61 - 14
components/wpa_supplicant/src/crypto/crypto_mbedtls.c

@@ -1,16 +1,18 @@
-// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifdef ESP_PLATFORM
 #include "esp_system.h"
@@ -20,10 +22,13 @@
 #include "utils/includes.h"
 #include "utils/common.h"
 #include "crypto.h"
-
+#include "sha256.h"
 #include "mbedtls/ecp.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/md.h"
+
 
 #ifdef ESP_PLATFORM
 int crypto_get_random(void *buf, size_t len)
@@ -604,3 +609,45 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
 }
 
 #endif /* CONFIG_ECC */
+
+int mbedtls_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);
+
+	if((md_info = mbedtls_md_info_from_type(md_type)) == NULL )
+		return -1;
+
+	if ((ret = mbedtls_md_setup( &md_ctx, md_info, 1)) != 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 mbedtls_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);
+}

+ 101 - 0
components/wpa_supplicant/src/crypto/sha1-tlsprf.c

@@ -0,0 +1,101 @@
+/*
+ * TLS PRF (SHA1 + MD5)
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "sha1.h"
+#include "md5.h"
+
+
+/**
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+	size_t L_S1, L_S2, i;
+	const u8 *S1, *S2;
+	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
+	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
+	int MD5_pos, SHA1_pos;
+	const u8 *MD5_addr[3];
+	size_t MD5_len[3];
+	const unsigned char *SHA1_addr[3];
+	size_t SHA1_len[3];
+
+	MD5_addr[0] = A_MD5;
+	MD5_len[0] = MD5_MAC_LEN;
+	MD5_addr[1] = (unsigned char *) label;
+	MD5_len[1] = os_strlen(label);
+	MD5_addr[2] = seed;
+	MD5_len[2] = seed_len;
+
+	SHA1_addr[0] = A_SHA1;
+	SHA1_len[0] = SHA1_MAC_LEN;
+	SHA1_addr[1] = (unsigned char *) label;
+	SHA1_len[1] = os_strlen(label);
+	SHA1_addr[2] = seed;
+	SHA1_len[2] = seed_len;
+
+	/* RFC 2246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
+	 */
+
+	L_S1 = L_S2 = (secret_len + 1) / 2;
+	S1 = secret;
+	S2 = secret + L_S1;
+	if (secret_len & 1) {
+		/* The last byte of S1 will be shared with S2 */
+		S2--;
+	}
+
+	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
+	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
+
+	MD5_pos = MD5_MAC_LEN;
+	SHA1_pos = SHA1_MAC_LEN;
+	for (i = 0; i < outlen; i++) {
+		if (MD5_pos == MD5_MAC_LEN) {
+			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
+			MD5_pos = 0;
+			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
+		}
+		if (SHA1_pos == SHA1_MAC_LEN) {
+			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
+					 P_SHA1);
+			SHA1_pos = 0;
+			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
+		}
+
+		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
+
+		MD5_pos++;
+		SHA1_pos++;
+	}
+
+	os_memset(A_MD5, 0, MD5_MAC_LEN);
+	os_memset(P_MD5, 0, MD5_MAC_LEN);
+	os_memset(A_SHA1, 0, SHA1_MAC_LEN);
+	os_memset(P_SHA1, 0, SHA1_MAC_LEN);
+
+	return 0;
+}

+ 108 - 0
components/wpa_supplicant/src/crypto/sha256-prf.c

@@ -0,0 +1,108 @@
+/*
+ * SHA256-based PRF (IEEE 802.11r)
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
+		const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+	return sha256_prf_bits(key, key_len, label, data, data_len, buf,
+			       buf_len * 8);
+}
+
+
+/**
+ * sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key. If the requested buf_len is not divisible by eight, the least
+ * significant 1-7 bits of the last octet in the output are not part of the
+ * requested output.
+ */
+int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+		    const u8 *data, size_t data_len, u8 *buf,
+		    size_t buf_len_bits)
+{
+	u16 counter = 1;
+	size_t pos, plen;
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+	u8 counter_le[2], length_le[2];
+	size_t buf_len = (buf_len_bits + 7) / 8;
+
+	addr[0] = counter_le;
+	len[0] = 2;
+	addr[1] = (u8 *) label;
+	len[1] = os_strlen(label);
+	addr[2] = data;
+	len[2] = data_len;
+	addr[3] = length_le;
+	len[3] = sizeof(length_le);
+
+	WPA_PUT_LE16(length_le, buf_len_bits);
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		WPA_PUT_LE16(counter_le, counter);
+		if (plen >= SHA256_MAC_LEN) {
+			if (hmac_sha256_vector(key, key_len, 4, addr, len,
+					       &buf[pos]) < 0)
+				return -1;
+			pos += SHA256_MAC_LEN;
+		} else {
+			if (hmac_sha256_vector(key, key_len, 4, addr, len,
+					       hash) < 0)
+				return -1;
+			os_memcpy(&buf[pos], hash, plen);
+			pos += plen;
+			break;
+		}
+		counter++;
+	}
+
+	/*
+	 * Mask out unused bits in the last octet if it does not use all the
+	 * bits.
+	 */
+	if (buf_len_bits % 8) {
+		u8 mask = 0xff << (8 - buf_len_bits % 8);
+		buf[pos - 1] &= mask;
+	}
+
+	os_memset(hash, 0, sizeof(hash));
+
+	return 0;
+}

+ 10 - 5
components/wpa_supplicant/src/crypto/sha256-tlsprf.c

@@ -26,8 +26,8 @@
  * This function is used to derive new, cryptographically separate keys from a
  * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
  */
-void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
-		    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+int tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
+		   const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
 {
 	size_t clen;
 	u8 A[SHA256_MAC_LEN];
@@ -50,12 +50,15 @@ void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
 	 * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
 	 */
 
-	hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+	if (hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
+		return -1;
 
 	pos = 0;
 	while (pos < outlen) {
-		hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
-		hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+		if (hmac_sha256_vector(secret, secret_len, 3, addr, len, P) <
+		    0 ||
+		    hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A) < 0)
+			return -1;
 
 		clen = outlen - pos;
 		if (clen > SHA256_MAC_LEN)
@@ -63,4 +66,6 @@ void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
 		os_memcpy(out + pos, P, clen);
 		pos += clen;
 	}
+
+	return 0;
 }

+ 6 - 99
components/wpa_supplicant/src/crypto/sha256.c

@@ -49,8 +49,8 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
 {
 	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[32];
-	const u8 *_addr[6];
-	size_t _len[6], i;
+	const u8 *_addr[11];
+	size_t _len[11], i;
 
 	if (num_elem > 5) {
 		/*
@@ -114,104 +114,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
  * @key_len: Length of the key in bytes
  * @data: Pointers to the data area
  * @data_len: Length of the data area
- * @mac: Buffer for the hash (20 bytes)
- */
-void
-hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
-                 size_t data_len, u8 *mac)
-{
-        hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
-}
-
-/**
- * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
- * @key: Key for PRF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @data: Extra data to bind into the key
- * @data_len: Length of the data
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bytes of key to generate
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key.
- */
-int sha256_prf(const u8 *key, size_t key_len, const char *label,
-		const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
-{
-	return sha256_prf_bits(key, key_len, label, data, data_len, buf,
-			       buf_len * 8);
-}
-
-/**
- * sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function
- * @key: Key for KDF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @data: Extra data to bind into the key
- * @data_len: Length of the data
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bits of key to generate
+ * @mac: Buffer for the hash (32 bytes)
  * Returns: 0 on success, -1 on failure
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key. If the requested buf_len is not divisible by eight, the least
- * significant 1-7 bits of the last octet in the output are not part of the
- * requested output.
  */
-int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
-		    const u8 *data, size_t data_len, u8 *buf,
-		    size_t buf_len_bits)
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
 {
-	u16 counter = 1;
-	size_t pos, plen;
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[4];
-	size_t len[4];
-	u8 counter_le[2], length_le[2];
-	size_t buf_len = (buf_len_bits + 7) / 8;
-
-	addr[0] = counter_le;
-	len[0] = 2;
-	addr[1] = (u8 *) label;
-	len[1] = os_strlen(label);
-	addr[2] = data;
-	len[2] = data_len;
-	addr[3] = length_le;
-	len[3] = sizeof(length_le);
-
-	WPA_PUT_LE16(length_le, buf_len_bits);
-	pos = 0;
-	while (pos < buf_len) {
-		plen = buf_len - pos;
-		WPA_PUT_LE16(counter_le, counter);
-		if (plen >= SHA256_MAC_LEN) {
-			if (hmac_sha256_vector(key, key_len, 4, addr, len,
-					       &buf[pos]) < 0)
-				return -1;
-			pos += SHA256_MAC_LEN;
-		} else {
-			if (hmac_sha256_vector(key, key_len, 4, addr, len,
-					       hash) < 0)
-				return -1;
-			os_memcpy(&buf[pos], hash, plen);
-			pos += plen;
-			break;
-		}
-		counter++;
-	}
-
-	/*
-	 * Mask out unused bits in the last octet if it does not use all the
-	 * bits.
-	 */
-	if (buf_len_bits % 8) {
-		u8 mask = 0xff << (8 - buf_len_bits % 8);
-		buf[pos - 1] &= mask;
-	}
-
-	os_memset(hash, 0, sizeof(hash));
-
-	return 0;
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
 }

+ 6 - 2
components/wpa_supplicant/src/crypto/sha256.h

@@ -19,15 +19,19 @@
 
 int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
 		      const u8 *addr[], const size_t *len, u8 *mac);
-void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
 		 size_t data_len, u8 *mac);
 int sha256_prf(const u8 *key, size_t key_len, const char *label,
 	      const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
 int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
 		    const u8 *data, size_t data_len, u8 *buf,
 		    size_t buf_len_bits);
-void tls_prf_sha256(const u8 *secret, size_t secret_len,
+int tls_prf_sha256(const u8 *secret, size_t secret_len,
                     const char *label, const u8 *seed, size_t seed_len,
                                 u8 *out, size_t outlen);
 
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+            const char *label, const u8 *seed, size_t seed_len,
+            u8 *out, size_t outlen);
+
 #endif /* SHA256_H */

+ 71 - 0
components/wpa_supplicant/src/crypto/sha384-tlsprf.c

@@ -0,0 +1,71 @@
+/*
+ * TLS PRF P_SHA384
+ * Copyright (c) 2011-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "sha384.h"
+
+
+/**
+ * tls_prf_sha384 - Pseudo-Random Function for TLS v1.2 (P_SHA384, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 5246, Chapter 5.
+ */
+int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label,
+		   const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+	size_t clen;
+	u8 A[SHA384_MAC_LEN];
+	u8 P[SHA384_MAC_LEN];
+	size_t pos;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = A;
+	len[0] = SHA384_MAC_LEN;
+	addr[1] = (unsigned char *) label;
+	len[1] = os_strlen(label);
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	/*
+	 * RFC 5246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF(secret, label, seed) = P_SHA384(secret, label + seed)
+	 */
+
+	if (hmac_sha384_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
+		return -1;
+
+	pos = 0;
+	while (pos < outlen) {
+		if (hmac_sha384_vector(secret, secret_len, 3, addr, len, P) <
+		    0 ||
+		    hmac_sha384(secret, secret_len, A, SHA384_MAC_LEN, A) < 0)
+			return -1;
+
+		clen = outlen - pos;
+		if (clen > SHA384_MAC_LEN)
+			clen = SHA384_MAC_LEN;
+		os_memcpy(out + pos, P, clen);
+		pos += clen;
+	}
+
+	return 0;
+}

+ 30 - 0
components/wpa_supplicant/src/crypto/sha384.h

@@ -0,0 +1,30 @@
+/*
+ * SHA384 hash implementation and interface functions
+ * Copyright (c) 2015-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA384_H
+#define SHA384_H
+
+#define SHA384_MAC_LEN 48
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac);
+int sha384_prf(const u8 *key, size_t key_len, const char *label,
+	       const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
+		    const u8 *data, size_t data_len, u8 *buf,
+		    size_t buf_len_bits);
+int tls_prf_sha384(const u8 *secret, size_t secret_len,
+		   const char *label, const u8 *seed, size_t seed_len,
+		   u8 *out, size_t outlen);
+int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
+		    const char *label, const u8 *seed, size_t seed_len,
+		    u8 *out, size_t outlen);
+
+#endif /* SHA384_H */

+ 880 - 0
components/wpa_supplicant/src/crypto/tls_mbedtls.c

@@ -0,0 +1,880 @@
+/**
+ * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+
+#include "tls/tls.h"
+#include "crypto/sha1.h"
+#include "crypto/md5.h"
+#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "mbedtls/ssl_internal.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/debug.h"
+#ifdef ESPRESSIF_USE
+#include "mbedtls/esp_debug.h"
+#include "mbedtls/esp_config.h"
+#else
+#include "mbedtls/config.h"
+#endif
+
+#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;
+};
+
+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 randbytes[2 * TLS_RANDOM_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 (data->out_data) {
+		wpabuf_resize(&data->out_data, len);
+	} else {
+		data->out_data = wpabuf_alloc(len);
+	}
+
+	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 (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(wpabuf_head(data->in_data) + len,
+					      wpabuf_len(data->in_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);
+	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;
+}
+
+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 defined(MBEDTLS_DES_C)
+	/* 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
+};
+
+static void tls_set_ciphersuite(tls_context_t *tls)
+{
+	/* Only set ciphersuite if cert's key length is high or ciphersuites are set by user */
+	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->pk) > 2048)) {
+		mbedtls_ssl_conf_ciphersuites(&tls->conf, eap_ciphersuite_preference);
+	}
+}
+
+static int set_client_config(const struct tls_connection_params *cfg, tls_context_t *tls)
+{
+	int ret;
+	assert(cfg != NULL);
+	assert(tls != NULL);
+
+	ret = mbedtls_ssl_config_defaults(&tls->conf,
+					MBEDTLS_SSL_IS_CLIENT,
+					MBEDTLS_SSL_TRANSPORT_STREAM,
+					MBEDTLS_SSL_PRESET_DEFAULT);
+	if (ret != 0) {
+		wpa_printf(MSG_ERROR, "mbedtls_ssl_config_defaults returned -0x%x", -ret);
+		return ret;
+	}
+
+	/* Enable SHA1 support since it's not enabled by default in mbedtls */
+	tls_enable_sha1_config(tls);
+
+	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);
+	}
+
+	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;
+		}
+	}
+
+	/* 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(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;
+	}
+
+	/* Enable debug prints in case supplicant's prints are enabled */
+#if defined(DEBUG_PRINT) && defined(CONFIG_MBEDTLS_DEBUG) && defined(ESPRESSIF_USE)
+	mbedtls_esp_enable_debug_log(&tls->conf, 2);
+#endif
+	return 0;
+
+exit:
+	tls_mbedtls_cleanup(tls);
+	return ret;
+}
+
+void *tls_init()
+{
+	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)
+{
+	/* 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->state == MBEDTLS_SSL_HANDSHAKE_OVER) {
+		return 1;
+	}
+
+	return 0;
+}
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	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)
+{
+	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);
+	}
+	ret = mbedtls_ssl_handshake_step(&tls->ssl);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s:%d", __func__, __LINE__);
+		goto end;
+	}
+
+	/* Multiple reads */
+	while (conn->tls_io_data.in_data) {
+		ret = mbedtls_ssl_handshake_step(&tls->ssl);
+		if (ret < 0)
+			break;
+	}
+
+	/* State machine just started, get client hello */
+	if (tls->ssl.state == MBEDTLS_SSL_CLIENT_HELLO) {
+		ret = mbedtls_ssl_handshake_step(&tls->ssl);
+	}
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s:%d", __func__, __LINE__);
+		goto end;
+	}
+
+	/* Already read sever data till hello done */
+	if (tls->ssl.state == MBEDTLS_SSL_CLIENT_CERTIFICATE) {
+		/* Read random data before session completes, not present after handshake */
+		if (tls->ssl.handshake) {
+			os_memcpy(conn->randbytes, tls->ssl.handshake->randbytes,
+				  TLS_RANDOM_LEN * 2);
+		}
+
+		/* trigger state machine multiple times to reach till finish */
+		while (tls->ssl.state <= MBEDTLS_SSL_CLIENT_FINISHED) {
+			ret = mbedtls_ssl_handshake_step(&tls->ssl);
+			if (ret < 0) {
+				break;
+			}
+		}
+	}
+
+	/* Trigger state machine till handshake is complete or error occures */
+	if (tls->ssl.state == MBEDTLS_SSL_FLUSH_BUFFERS) {
+		while (tls->ssl.state <= MBEDTLS_SSL_HANDSHAKE_OVER) {
+			ret = mbedtls_ssl_handshake_step(&tls->ssl);
+			if (ret < 0) {
+				break;
+			}
+		}
+	}
+
+	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 && conn->tls->ssl.handshake) {
+		return conn->tls->ssl.handshake->resume;
+	}
+
+	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_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);
+
+	return 0;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	wpa_printf(MSG_ERROR, "%s: not supported %d", __func__, __LINE__);
+	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)
+{
+	wpa_printf(MSG_ERROR, "%s: not supported %d", __func__, __LINE__);
+	return 0;
+}
+
+int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	wpa_printf(MSG_ERROR, "%s: not supported %d", __func__, __LINE__);
+	return 0;
+}
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	int ret = 0;
+	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;
+	}
+
+	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;
+
+	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;
+}
+
+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;
+	mbedtls_ssl_transform *transform = ssl->transform;
+
+	if (!ssl || !transform) {
+		wpa_printf(MSG_ERROR, "TLS: %s, session ingo is null", __func__);
+		return -1;
+	}
+	if (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) {
+		wpa_printf(MSG_ERROR, "TLS: %s, incorrect tls state=%d", __func__, ssl->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", ssl->session->master, TLS_MASTER_SECRET_LEN);
+
+	if (transform->ciphersuite_info->mac == MBEDTLS_MD_SHA384) {
+		ret = tls_prf_sha384(ssl->session->master, TLS_MASTER_SECRET_LEN,
+				label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+	} else if (transform->ciphersuite_info->mac == MBEDTLS_MD_SHA256) {
+		ret = tls_prf_sha256(ssl->session->master, TLS_MASTER_SECRET_LEN,
+				label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+	} else {
+		ret = tls_prf_sha1_md5(ssl->session->master, 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, u8 *out, size_t out_len)
+{
+	return tls_connection_prf(tls_ctx, conn, label, 0, out, out_len);
+}
+
+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->state == MBEDTLS_SSL_CLIENT_HELLO) {
+		return -1;
+	}
+
+	data->client_random = conn->randbytes;
+	data->client_random_len = TLS_RANDOM_LEN;
+
+	if (ssl->state != MBEDTLS_SSL_SERVER_HELLO) {
+		data->server_random = conn->randbytes + TLS_RANDOM_LEN;
+		data->server_random_len = TLS_RANDOM_LEN;
+	}
+
+	return 0;
+}

+ 8 - 41
components/wpa_supplicant/src/eap_peer/eap_tls_common.c

@@ -248,53 +248,21 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 			     const char *label, size_t len)
 {
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
+	u8 *out;
 
 	out = os_malloc(len);
 	if (out == NULL)
 		return NULL;
 
-	/* First, try to use TLS library function for PRF, if available. */
-	if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
-	    == 0)
-		return out;
-
-	/*
-	 * TLS library did not support key generation, so get the needed TLS
-	 * session parameters and use an internal implementation of TLS PRF to
-	 * derive the key.
-	 */
-	if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
-		goto fail;
-
-	if (keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.master_key == NULL)
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
-			     label, rnd, keys.client_random_len +
-			     keys.server_random_len, out, len)) {
-		goto fail;
+	if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out,
+				len)) {
+		os_free(out);
+		return NULL;
 	}
 
-	os_free(rnd);
 	return out;
-
-fail:
-	os_free(out);
-	os_free(rnd);
-	return NULL;
 }
 
-
 /**
  * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
@@ -312,18 +280,17 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
 				    struct eap_ssl_data *data, u8 eap_type,
 				    size_t *len)
 {
-	struct tls_keys keys;
+	struct tls_random keys;
 	u8 *out;
 
 	/*
 	 * TLS library did not support session ID generation,
 	 * so get the needed TLS session parameters
 	 */
-	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+	if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
 		return NULL;
 
-	if (keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.master_key == NULL)
+	if (keys.client_random == NULL || keys.server_random == NULL)
 		return NULL;
 
 	*len = 1 + keys.client_random_len + keys.server_random_len;

+ 10 - 32
components/wpa_supplicant/src/tls/tls.h

@@ -11,9 +11,7 @@
 
 struct tls_connection;
 
-struct tls_keys {
-	const u8 *master_key; /* TLS master secret */
-	size_t master_key_len;
+struct tls_random {
 	const u8 *client_random;
 	size_t client_random_len;
 	const u8 *server_random;
@@ -287,41 +285,31 @@ int __must_check tls_connection_set_verify(void *tls_ctx,
 					   int verify_peer);
 
 /**
- * tls_connection_get_keys - Get master key and random data from TLS connection
+ * tls_connection_get_random - Get random data from TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @keys: Structure of key/random data (filled on success)
  * Returns: 0 on success, -1 on failure
  */
-int __must_check tls_connection_get_keys(void *tls_ctx,
+int __must_check tls_connection_get_random(void *tls_ctx,
 					 struct tls_connection *conn,
-					 struct tls_keys *keys);
+					 struct tls_random *data);
 
 /**
- * tls_connection_prf - Use TLS-PRF to derive keying material
+ * tls_connection_export_key - Derive keying material from a TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
  * @out: Buffer for output data from TLS-PRF
  * @out_len: Length of the output buffer
  * Returns: 0 on success, -1 on failure
  *
- * This function is optional to implement if tls_connection_get_keys() provides
- * access to master secret and server/client random values. If these values are
- * not exported from the TLS library, tls_connection_prf() is required so that
- * further keying material can be derived from the master secret. If not
- * implemented, the function will still need to be defined, but it can just
- * return -1. Example implementation of this function is in tls_prf_sha1_md5()
- * when it is called with seed set to client_random|server_random (or
- * server_random|client_random).
+ * Exports keying material using the mechanism described in RFC 5705.
  */
-int __must_check  tls_connection_prf(void *tls_ctx,
-				     struct tls_connection *conn,
-				     const char *label,
-				     int server_random_first,
-				     u8 *out, size_t out_len);
+int __must_check tls_connection_export_key(void *tls_ctx,
+					   struct tls_connection *conn,
+					   const char *label,
+					   u8 *out, size_t out_len);
 
 /**
  * tls_connection_handshake - Process TLS handshake (client side)
@@ -506,16 +494,6 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
 int tls_connection_get_write_alerts(void *tls_ctx,
 				    struct tls_connection *conn);
 
-/**
- * tls_connection_get_keyblock_size - Get TLS key_block size
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: Size of the key_block for the negotiated cipher suite or -1 on
- * failure
- */
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn);
-
 /**
  * tls_capabilities - Get supported TLS capabilities
  * @tls_ctx: TLS context data from tls_init()

+ 44 - 119
components/wpa_supplicant/src/tls/tls_internal.c

@@ -18,10 +18,6 @@
 #include "tls/tlsv1_client.h"
 #include "tls/tlsv1_server.h"
 
-#ifndef CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_TLS_INTERNAL_CLIENT
-#endif
-
 static int tls_ref_count = 0;
 
 struct tls_global {
@@ -280,43 +276,76 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 	return -1;
 }
 
-
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
+int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_random *data)
 {
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (conn->client)
-		return tlsv1_client_get_keys(conn->client, keys);
+		return tlsv1_client_get_random(conn->client, data);
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
 	if (conn->server)
-		return tlsv1_server_get_keys(conn->server, keys);
+		return tlsv1_server_get_random(conn->server, data);
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return -1;
 }
 
+static int tls_get_keyblock_size(struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keyblock_size(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keyblock_size(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
+static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+			      const char *label, int server_random_first,
+			      int skip_keyblock, u8 *out, size_t out_len)
 {
+	int ret = -1, skip = 0;
+	u8 *tmp_out = NULL;
+	u8 *_out = out;
+
+	if (skip_keyblock) {
+		skip = tls_get_keyblock_size(conn);
+		if (skip < 0)
+			return -1;
+		tmp_out = os_malloc(skip + out_len);
+		if (!tmp_out)
+			return -1;
+		_out = tmp_out;
+	}
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (conn->client) {
-		return tlsv1_client_prf(conn->client, label,
+		ret = tlsv1_client_prf(conn->client, label,
 					server_random_first,
 					out, out_len);
 	}
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
 	if (conn->server) {
-		return tlsv1_server_prf(conn->server, label,
+		ret = tlsv1_server_prf(conn->server, label,
 					server_random_first,
 					out, out_len);
 	}
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
+	if (ret == 0 && skip_keyblock)
+		os_memcpy(out, _out + skip, out_len);
+	wpa_bin_clear_free(tmp_out, skip);
+
+	return ret;
 }
 
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+			      const char *label, u8 *out, size_t out_len)
+{
+	return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len);
+}
 
 struct wpabuf * tls_connection_handshake(void *tls_ctx,
 					 struct tls_connection *conn,
@@ -585,28 +614,11 @@ int tls_connection_get_write_alerts(void *tls_ctx,
 	return 0;
 }
 
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_get_keyblock_size(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_get_keyblock_size(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
 unsigned int tls_capabilities(void *tls_ctx)
 {
 	return 0;
 }
 
-
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
 					 struct tls_connection *conn,
 					 tls_session_ticket_cb cb,
@@ -626,90 +638,3 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return -1;
 }
-
-
-
-/**
- * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
- * @secret: Key for PRF
- * @secret_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @seed: Seed value to bind into the key
- * @seed_len: Length of the seed
- * @out: Buffer for the generated pseudo-random key
- * @outlen: Number of bytes of key to generate
- * Returns: 0 on success, -1 on failure.
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
- */
-int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
-		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
-{
-	size_t L_S1, L_S2, i;
-	const u8 *S1, *S2;
-	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
-	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
-	int MD5_pos, SHA1_pos;
-	const u8 *MD5_addr[3];
-	size_t MD5_len[3];
-	const unsigned char *SHA1_addr[3];
-	size_t SHA1_len[3];
-
-	if (secret_len & 1)
-		return -1;
-
-	MD5_addr[0] = A_MD5;
-	MD5_len[0] = MD5_MAC_LEN;
-	MD5_addr[1] = (unsigned char *) label;
-	MD5_len[1] = os_strlen(label);
-	MD5_addr[2] = seed;
-	MD5_len[2] = seed_len;
-
-	SHA1_addr[0] = A_SHA1;
-	SHA1_len[0] = SHA1_MAC_LEN;
-	SHA1_addr[1] = (unsigned char *) label;
-	SHA1_len[1] = os_strlen(label);
-	SHA1_addr[2] = seed;
-	SHA1_len[2] = seed_len;
-
-	/* RFC 2246, Chapter 5
-	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
-	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
-	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
-	 */
-
-	L_S1 = L_S2 = (secret_len + 1) / 2;
-	S1 = secret;
-	S2 = secret + L_S1;
-	if (secret_len & 1) {
-		/* The last byte of S1 will be shared with S2 */
-		S2--;
-	}
-
-	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
-	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
-
-	MD5_pos = MD5_MAC_LEN;
-	SHA1_pos = SHA1_MAC_LEN;
-	for (i = 0; i < outlen; i++) {
-		if (MD5_pos == MD5_MAC_LEN) {
-			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
-			MD5_pos = 0;
-			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
-		}
-		if (SHA1_pos == SHA1_MAC_LEN) {
-			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
-					 P_SHA1);
-			SHA1_pos = 0;
-			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
-		}
-
-		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
-
-		MD5_pos++;
-		SHA1_pos++;
-	}
-
-	return 0;
-}

+ 5 - 9
components/wpa_supplicant/src/tls/tlsv1_client.c

@@ -706,18 +706,16 @@ int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
 	if (data == NULL || data_len == 0)
 		return 0;
 
-	pos = conn->client_hello_ext = os_malloc(6 + data_len);
+	pos = conn->client_hello_ext = os_malloc(4 + data_len);
 	if (pos == NULL)
 		return -1;
 
-	WPA_PUT_BE16(pos, 4 + data_len);
-	pos += 2;
 	WPA_PUT_BE16(pos, ext_type);
 	pos += 2;
 	WPA_PUT_BE16(pos, data_len);
 	pos += 2;
 	os_memcpy(pos, data, data_len);
-	conn->client_hello_ext_len = 6 + data_len;
+	conn->client_hello_ext_len = 4 + data_len;
 
 	if (ext_type == TLS_EXT_PAC_OPAQUE) {
 		conn->session_ticket_included = 1;
@@ -729,12 +727,12 @@ int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
 
 
 /**
- * tlsv1_client_get_keys - Get master key and random data from TLS connection
+ * tlsv1_client_get_random - Get random data from TLS connection
  * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @keys: Structure of key/random data (filled on success)
+ * @keys: Structure of random data (filled on success)
  * Returns: 0 on success, -1 on failure
  */
-int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
+int tlsv1_client_get_random(struct tlsv1_client *conn, struct tls_random *keys)
 {
 	os_memset(keys, 0, sizeof(*keys));
 	if (conn->state == CLIENT_HELLO)
@@ -746,8 +744,6 @@ int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
 	if (conn->state != SERVER_HELLO) {
 		keys->server_random = conn->server_random;
 		keys->server_random_len = TLS_RANDOM_LEN;
-		keys->master_key = conn->master_secret;
-		keys->master_key_len = TLS_MASTER_SECRET_LEN;
 	}
 
 	return 0;

+ 1 - 1
components/wpa_supplicant/src/tls/tlsv1_client.h

@@ -36,7 +36,7 @@ int tlsv1_client_shutdown(struct tlsv1_client *conn);
 int tlsv1_client_resumed(struct tlsv1_client *conn);
 int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
 			   const u8 *data, size_t data_len);
-int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys);
+int tlsv1_client_get_random(struct tlsv1_client *conn, struct tls_random *data);
 int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
 int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
 int tlsv1_client_set_cred(struct tlsv1_client *conn,

+ 63 - 4
components/wpa_supplicant/src/tls/tlsv1_client_read.c

@@ -409,9 +409,11 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 
 
 static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
-					const u8 *buf, size_t len)
+					const u8 *buf, size_t len,
+					tls_key_exchange key_exchange)
 {
-	const u8 *pos, *end;
+	const u8 *pos, *end, *server_params, *server_params_end;
+	u8 alert;
 
 	tlsv1_client_free_dh(conn);
 
@@ -420,6 +422,7 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 
 	if (end - pos < 3)
 		goto fail;
+	server_params = pos;
 	conn->dh_p_len = WPA_GET_BE16(pos);
 	pos += 2;
 	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
@@ -464,6 +467,60 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 	pos += conn->dh_ys_len;
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
 		    conn->dh_ys, conn->dh_ys_len);
+	server_params_end = pos;
+
+	if (key_exchange == TLS_KEY_X_DHE_RSA) {
+		u8 hash[64];
+		int hlen;
+
+		if (conn->rl.tls_version == TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+			/*
+			 * RFC 5246, 4.7:
+			 * TLS v1.2 adds explicit indication of the used
+			 * signature and hash algorithms.
+			 *
+			 * struct {
+			 *   HashAlgorithm hash;
+			 *   SignatureAlgorithm signature;
+			 * } SignatureAndHashAlgorithm;
+			 */
+			if (end - pos < 2)
+				goto fail;
+			if ((pos[0] != TLS_HASH_ALG_SHA256) ||
+			    pos[1] != TLS_SIGN_ALG_RSA) {
+				wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
+					   pos[0], pos[1]);
+				goto fail;
+			}
+
+			hlen = tlsv12_key_x_server_params_hash(
+				conn->rl.tls_version, pos[0],
+				conn->client_random,
+				conn->server_random, server_params,
+				server_params_end - server_params, hash);
+			pos += 2;
+#else /* CONFIG_TLSV12 */
+			goto fail;
+#endif /* CONFIG_TLSV12 */
+		} else {
+			hlen = tls_key_x_server_params_hash(
+				conn->rl.tls_version, conn->client_random,
+				conn->server_random, server_params,
+				server_params_end - server_params, hash);
+		}
+
+		if (hlen < 0)
+			goto fail;
+		wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
+			    hash, hlen);
+
+		if (tls_verify_signature(conn->rl.tls_version,
+					 conn->server_rsa_key,
+					 hash, hlen, pos, end - pos,
+					 &alert) < 0)
+			goto fail;
+	}
 
 	return 0;
 
@@ -542,8 +599,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 
 	wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
-		if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+	if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon ||
+		      suite->key_exchange == TLS_KEY_X_DHE_RSA)) {
+		if (tlsv1_process_diffie_hellman(conn, pos, len,
+						 suite->key_exchange) < 0) {
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				  TLS_ALERT_DECODE_ERROR);
 			return -1;

+ 32 - 1
components/wpa_supplicant/src/tls/tlsv1_client_write.c

@@ -48,6 +48,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 	u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
 	struct os_time now;
 	size_t len, i;
+	u8 *ext_start;
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
 	*out_len = 0;
@@ -62,7 +63,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
 		    conn->client_random, TLS_RANDOM_LEN);
 
-	len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
+	len = 150 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
 	hello = os_malloc(len);
 	if (hello == NULL)
 		return NULL;
@@ -102,12 +103,42 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 	*pos++ = 1;
 	*pos++ = TLS_COMPRESSION_NULL;
 
+	/* Extension */
+	ext_start = pos;
+	pos += 2;
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * Add signature_algorithms extension since we support only
+		 * SHA256 (and not the default SHA1) with TLSv1.2.
+		 */
+		/* ExtensionsType extension_type = signature_algorithms(13) */
+		WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
+		pos += 2;
+		/* opaque extension_data<0..2^16-1> length */
+		WPA_PUT_BE16(pos, 4);
+		pos += 2;
+		/* supported_signature_algorithms<2..2^16-2> length */
+		WPA_PUT_BE16(pos, 2);
+		pos += 2;
+		/* supported_signature_algorithms */
+		*pos++ = TLS_HASH_ALG_SHA256;
+		*pos++ = TLS_SIGN_ALG_RSA;
+	}
+#endif /* CONFIG_TLSV12 */
+
 	if (conn->client_hello_ext) {
 		os_memcpy(pos, conn->client_hello_ext,
 			  conn->client_hello_ext_len);
 		pos += conn->client_hello_ext_len;
 	}
 
+	if (pos == ext_start + 2)
+		pos -= 2; /* no extensions */
+	else
+		WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 

+ 182 - 0
components/wpa_supplicant/src/tls/tlsv1_common.c

@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "tls/tls.h"
@@ -333,3 +334,184 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
 	return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
 				outlen);
 }
+
+
+#ifdef CONFIG_TLSV12
+int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg,
+				    const u8 *client_random,
+				    const u8 *server_random,
+				    const u8 *server_params,
+				    size_t server_params_len, u8 *hash)
+{
+	size_t hlen;
+	struct crypto_hash *ctx;
+	enum crypto_hash_alg alg;
+
+	switch (hash_alg) {
+	case TLS_HASH_ALG_SHA256:
+		alg = CRYPTO_HASH_ALG_SHA256;
+		hlen = SHA256_MAC_LEN;
+		break;
+	default:
+		return -1;
+	}
+	ctx = crypto_hash_init(alg, NULL, 0);
+	if (ctx == NULL)
+		return -1;
+	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_params, server_params_len);
+	if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+		return -1;
+
+	return hlen;
+}
+#endif /* CONFIG_TLSV12 */
+
+
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+				 const u8 *server_random,
+				 const u8 *server_params,
+				 size_t server_params_len, u8 *hash)
+{
+	u8 *hpos;
+	size_t hlen;
+	struct crypto_hash *ctx;
+
+	hpos = hash;
+
+	ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	if (ctx == NULL)
+		return -1;
+	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_params, server_params_len);
+	hlen = MD5_MAC_LEN;
+	if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+		return -1;
+	hpos += hlen;
+
+	ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	if (ctx == NULL)
+		return -1;
+	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_params, server_params_len);
+	hlen = hash + sizeof(hash) - hpos;
+	if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
+		return -1;
+	hpos += hlen;
+	return hpos - hash;
+}
+
+
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+			 const u8 *data, size_t data_len,
+			 const u8 *pos, size_t len, u8 *alert)
+{
+	u8 *buf;
+	const u8 *end = pos + len;
+	const u8 *decrypted;
+	u16 slen;
+	size_t buflen;
+
+	if (end - pos < 2) {
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+	slen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < slen) {
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+	if (end - pos > slen) {
+		wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
+			    pos + slen, end - pos - slen);
+		end = pos + slen;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+	if (pk == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+
+	buflen = end - pos;
+	buf = os_malloc(end - pos);
+	if (buf == NULL) {
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+	if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
+	    0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+		os_free(buf);
+		*alert = TLS_ALERT_DECRYPT_ERROR;
+		return -1;
+	}
+	decrypted = buf;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+			decrypted, buflen);
+
+#ifdef CONFIG_TLSV12
+	if (tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		if (buflen >= 19 + 32 &&
+		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-256");
+			decrypted = buf + 19;
+			buflen -= 19;
+		} else if (buflen >= 19 + 48 &&
+		    os_memcmp(buf, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01"
+			      "\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-384");
+			decrypted = buf + 19;
+			buflen -= 19;
+		} else if (buflen >= 19 + 64 &&
+		    os_memcmp(buf, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01"
+			      "\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-512");
+			decrypted = buf + 19;
+			buflen -= 19;
+
+		} else {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
+			os_free(buf);
+			*alert = TLS_ALERT_DECRYPT_ERROR;
+			return -1;
+		}
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (buflen != data_len ||
+	    os_memcmp_const(decrypted, data, data_len) != 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
+		os_free(buf);
+		*alert = TLS_ALERT_DECRYPT_ERROR;
+		return -1;
+	}
+
+	os_free(buf);
+
+	return 0;
+}

+ 13 - 0
components/wpa_supplicant/src/tls/tlsv1_common.h

@@ -169,6 +169,7 @@ enum {
 #define TLS_EXT_TRUSTED_CA_KEYS			3 /* RFC 4366 */
 #define TLS_EXT_TRUNCATED_HMAC			4 /* RFC 4366 */
 #define TLS_EXT_STATUS_REQUEST			5 /* RFC 4366 */
+#define TLS_EXT_SIGNATURE_ALGORITHMS		13 /* RFC 5246 */
 #define TLS_EXT_SESSION_TICKET			35 /* RFC 4507 */
 
 #define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
@@ -257,5 +258,17 @@ int tls_version_ok(u16 ver);
 const char * tls_version_str(u16 ver);
 int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
 	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
+int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_Alg,
+				    const u8 *client_random,
+				    const u8 *server_random,
+				    const u8 *server_params,
+				    size_t server_params_len, u8 *hash);
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+				 const u8 *server_random,
+				 const u8 *server_params,
+				 size_t server_params_len, u8 *hash);
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+			 const u8 *data, size_t data_len,
+			 const u8 *pos, size_t len, u8 *alert);
 
 #endif /* TLSV1_COMMON_H */

+ 3 - 5
components/wpa_supplicant/src/tls/tlsv1_server.c

@@ -570,12 +570,12 @@ int tlsv1_server_resumed(struct tlsv1_server *conn)
 
 
 /**
- * tlsv1_server_get_keys - Get master key and random data from TLS connection
+ * tlsv1_server_get_random - Get random data from TLS connection
  * @conn: TLSv1 server connection data from tlsv1_server_init()
- * @keys: Structure of key/random data (filled on success)
+ * @keys: Structure of random data (filled on success)
  * Returns: 0 on success, -1 on failure
  */
-int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
+int tlsv1_server_get_random(struct tlsv1_server *conn, struct tls_random *keys)
 {
 	os_memset(keys, 0, sizeof(*keys));
 	if (conn->state == CLIENT_HELLO)
@@ -587,8 +587,6 @@ int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
 	if (conn->state != SERVER_HELLO) {
 		keys->server_random = conn->server_random;
 		keys->server_random_len = TLS_RANDOM_LEN;
-		keys->master_key = conn->master_secret;
-		keys->master_key_len = TLS_MASTER_SECRET_LEN;
 	}
 
 	return 0;

+ 1 - 1
components/wpa_supplicant/src/tls/tlsv1_server.h

@@ -32,7 +32,7 @@ int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
 			    size_t buflen);
 int tlsv1_server_shutdown(struct tlsv1_server *conn);
 int tlsv1_server_resumed(struct tlsv1_server *conn);
-int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys);
+int tlsv1_server_get_random(struct tlsv1_server *conn, struct tls_random *data);
 int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn);
 int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers);
 int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer);