From bd2815db100b7566175ae525963cda024a45426f Mon Sep 17 00:00:00 2001 From: "kapil.gupta" Date: Thu, 28 May 2020 21:24:56 +0530 Subject: [PATCH] wpa_supplicant: Support for mbedtls tls handshake Add support for mbedtls based tls handshake, this removes dependency from internal implementation of EAP client. --- components/wpa_supplicant/CMakeLists.txt | 49 +- components/wpa_supplicant/Kconfig | 6 - components/wpa_supplicant/component.mk | 26 +- components/wpa_supplicant/port/include/os.h | 15 +- .../port/include/supplicant_opt.h | 7 +- .../src/crypto/crypto_mbedtls.c | 72 ++ .../wpa_supplicant/src/crypto/sha1-tlsprf.c | 101 ++ .../wpa_supplicant/src/crypto/sha256-prf.c | 108 +++ .../wpa_supplicant/src/crypto/sha256-tlsprf.c | 15 +- components/wpa_supplicant/src/crypto/sha256.c | 105 +-- components/wpa_supplicant/src/crypto/sha256.h | 2 +- .../wpa_supplicant/src/crypto/sha384-tlsprf.c | 71 ++ components/wpa_supplicant/src/crypto/sha384.h | 30 + .../wpa_supplicant/src/crypto/tls_mbedtls.c | 879 ++++++++++++++++++ .../src/eap_peer/eap_tls_common.c | 49 +- components/wpa_supplicant/src/tls/tls.h | 42 +- .../wpa_supplicant/src/tls/tls_internal.c | 165 +--- .../wpa_supplicant/src/tls/tlsv1_client.c | 8 +- .../wpa_supplicant/src/tls/tlsv1_client.h | 2 +- .../wpa_supplicant/src/tls/tlsv1_server.c | 8 +- .../wpa_supplicant/src/tls/tlsv1_server.h | 2 +- 21 files changed, 1410 insertions(+), 352 deletions(-) create mode 100644 components/wpa_supplicant/src/crypto/crypto_mbedtls.c create mode 100644 components/wpa_supplicant/src/crypto/sha1-tlsprf.c create mode 100644 components/wpa_supplicant/src/crypto/sha256-prf.c create mode 100644 components/wpa_supplicant/src/crypto/sha384-tlsprf.c create mode 100644 components/wpa_supplicant/src/crypto/sha384.h create mode 100644 components/wpa_supplicant/src/crypto/tls_mbedtls.c diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index ffade535d..fdf68188d 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -18,9 +18,9 @@ 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" "src/crypto/crypto_mbedtls-bignum.c" "src/crypto/crypto_mbedtls-ec.c" "src/crypto/crypto_ops.c" @@ -42,6 +42,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" @@ -61,23 +65,6 @@ set(srcs "port/os_xtensa.c" "src/rsn_supp/pmksa_cache.c" "src/rsn_supp/wpa.c" "src/rsn_supp/wpa_ie.c" - "src/tls/asn1.c" - "src/tls/bignum.c" - "src/tls/pkcs1.c" - "src/tls/pkcs5.c" - "src/tls/pkcs8.c" - "src/tls/rsa.c" - "src/tls/tls_internal.c" - "src/tls/tlsv1_client.c" - "src/tls/tlsv1_client_read.c" - "src/tls/tlsv1_client_write.c" - "src/tls/tlsv1_common.c" - "src/tls/tlsv1_cred.c" - "src/tls/tlsv1_record.c" - "src/tls/tlsv1_server.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" @@ -95,7 +82,31 @@ set(srcs "port/os_xtensa.c" "src/wps/wps_registrar.c" "src/wps/wps_validate.c") -idf_component_register(SRCS "${srcs}" +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" + "src/tls/pkcs5.c" + "src/tls/pkcs8.c" + "src/tls/rsa.c" + "src/tls/tls_internal.c" + "src/tls/tlsv1_client.c" + "src/tls/tlsv1_client_read.c" + "src/tls/tlsv1_client_write.c" + "src/tls/tlsv1_common.c" + "src/tls/tlsv1_cred.c" + "src/tls/tlsv1_record.c" + "src/tls/tlsv1_server.c" + "src/tls/tlsv1_server_read.c" + "src/tls/tlsv1_server_write.c" + "src/tls/x509v3.c" + ) +endif() + +idf_component_register(SRCS "${srcs}" "${tls_src}" INCLUDE_DIRS include port/include include/esp_supplicant PRIV_INCLUDE_DIRS src PRIV_REQUIRES mbedtls esp_timer) diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig index 88d29476f..591325d84 100644 --- a/components/wpa_supplicant/Kconfig +++ b/components/wpa_supplicant/Kconfig @@ -23,12 +23,6 @@ menu "Supplicant" help Select this to enable unity test for DPP. - config WPA_TLS_V12 - bool "Enable TLS v1.2" - default n - help - Select this to enable TLS v1.2 for WPA2-Enterprise Authentication. - config WPA_WPS_WARS bool "Add WPS Inter operatability Fixes" default n diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index a4fd1f5bc..7a178d879 100644 --- a/components/wpa_supplicant/component.mk +++ b/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_DPP -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 diff --git a/components/wpa_supplicant/port/include/os.h b/components/wpa_supplicant/port/include/os.h index bff8b1468..39fda21c4 100644 --- a/components/wpa_supplicant/port/include/os.h +++ b/components/wpa_supplicant/port/include/os.h @@ -278,6 +278,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 @@ -291,16 +294,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 */ diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h index f58692a18..a3d4c6662 100644 --- a/components/wpa_supplicant/port/include/supplicant_opt.h +++ b/components/wpa_supplicant/port/include/supplicant_opt.h @@ -19,14 +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_DEBUG_PRINT #define DEBUG_PRINT #endif -#if CONFIG_WPA_TLS_V12 -#define CONFIG_TLSV12 -#endif - #endif /* _SUPPLICANT_OPT_H */ diff --git a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c new file mode 100644 index 000000000..b2c2ff569 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -0,0 +1,72 @@ +/** + * 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. + */ + +#ifdef ESP_PLATFORM +#include "esp_system.h" +#endif + +#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" + +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); +} diff --git a/components/wpa_supplicant/src/crypto/sha1-tlsprf.c b/components/wpa_supplicant/src/crypto/sha1-tlsprf.c new file mode 100644 index 000000000..bd6ec7a55 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha1-tlsprf.c @@ -0,0 +1,101 @@ +/* + * TLS PRF (SHA1 + MD5) + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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; +} diff --git a/components/wpa_supplicant/src/crypto/sha256-prf.c b/components/wpa_supplicant/src/crypto/sha256-prf.c new file mode 100644 index 000000000..7d7d34635 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha256-prf.c @@ -0,0 +1,108 @@ +/* + * SHA256-based PRF (IEEE 802.11r) + * Copyright (c) 2003-2016, Jouni Malinen + * + * 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; +} diff --git a/components/wpa_supplicant/src/crypto/sha256-tlsprf.c b/components/wpa_supplicant/src/crypto/sha256-tlsprf.c index 8483867ff..0ba1b4916 100644 --- a/components/wpa_supplicant/src/crypto/sha256-tlsprf.c +++ b/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; } diff --git a/components/wpa_supplicant/src/crypto/sha256.c b/components/wpa_supplicant/src/crypto/sha256.c index 1b1552384..b0f9ce302 100644 --- a/components/wpa_supplicant/src/crypto/sha256.c +++ b/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) - */ -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); -} - -/** - * 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 + * @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. */ -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 hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) { - 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; + return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); } diff --git a/components/wpa_supplicant/src/crypto/sha256.h b/components/wpa_supplicant/src/crypto/sha256.h index 866949b6c..96dd03a4c 100644 --- a/components/wpa_supplicant/src/crypto/sha256.h +++ b/components/wpa_supplicant/src/crypto/sha256.h @@ -26,7 +26,7 @@ int sha256_prf(const u8 *key, size_t key_len, const char *label, 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); diff --git a/components/wpa_supplicant/src/crypto/sha384-tlsprf.c b/components/wpa_supplicant/src/crypto/sha384-tlsprf.c new file mode 100644 index 000000000..196b98897 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha384-tlsprf.c @@ -0,0 +1,71 @@ +/* + * TLS PRF P_SHA384 + * Copyright (c) 2011-2019, Jouni Malinen + * + * 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; +} diff --git a/components/wpa_supplicant/src/crypto/sha384.h b/components/wpa_supplicant/src/crypto/sha384.h new file mode 100644 index 000000000..d946907c6 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha384.h @@ -0,0 +1,30 @@ +/* + * SHA384 hash implementation and interface functions + * Copyright (c) 2015-2017, Jouni Malinen + * + * 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 */ diff --git a/components/wpa_supplicant/src/crypto/tls_mbedtls.c b/components/wpa_supplicant/src/crypto/tls_mbedtls.c new file mode 100644 index 000000000..c26ed7a61 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/tls_mbedtls.c @@ -0,0 +1,879 @@ +/** + * 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 || + 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); + 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; +} diff --git a/components/wpa_supplicant/src/eap_peer/eap_tls_common.c b/components/wpa_supplicant/src/eap_peer/eap_tls_common.c index 7d2c925ca..9c93f6d0c 100644 --- a/components/wpa_supplicant/src/eap_peer/eap_tls_common.c +++ b/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; diff --git a/components/wpa_supplicant/src/tls/tls.h b/components/wpa_supplicant/src/tls/tls.h index 983999b51..a3f42231f 100644 --- a/components/wpa_supplicant/src/tls/tls.h +++ b/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() diff --git a/components/wpa_supplicant/src/tls/tls_internal.c b/components/wpa_supplicant/src/tls/tls_internal.c index 65e08b8fa..73e9aa2fd 100644 --- a/components/wpa_supplicant/src/tls/tls_internal.c +++ b/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; } - -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_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; +} + +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; -} diff --git a/components/wpa_supplicant/src/tls/tlsv1_client.c b/components/wpa_supplicant/src/tls/tlsv1_client.c index 6780f54dc..d9f038b9a 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client.c +++ b/components/wpa_supplicant/src/tls/tlsv1_client.c @@ -729,12 +729,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 +746,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; diff --git a/components/wpa_supplicant/src/tls/tlsv1_client.h b/components/wpa_supplicant/src/tls/tlsv1_client.h index 8ec85f1a9..a4e25e969 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client.h +++ b/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, diff --git a/components/wpa_supplicant/src/tls/tlsv1_server.c b/components/wpa_supplicant/src/tls/tlsv1_server.c index 4628af8c5..b835ce0fd 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_server.c +++ b/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; diff --git a/components/wpa_supplicant/src/tls/tlsv1_server.h b/components/wpa_supplicant/src/tls/tlsv1_server.h index a18c69e37..08a23fbb3 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_server.h +++ b/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);