From 70fb5948734bc346f7237bf21a6c8fa830f6d2f6 Mon Sep 17 00:00:00 2001 From: "kapil.gupta" Date: Thu, 28 May 2020 21:24:56 +0530 Subject: [PATCH 1/3] 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 | 44 +- components/wpa_supplicant/component.mk | 26 +- components/wpa_supplicant/port/include/os.h | 17 +- .../port/include/supplicant_opt.h | 9 +- .../src/crypto/crypto_mbedtls.c | 75 +- .../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 | 8 +- .../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 +- 20 files changed, 1404 insertions(+), 360 deletions(-) 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 c49af5f9fb..12656891c8 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/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) diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index dc319339b7..29212dd64c 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_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 6729f02408..8bdd2d6582 100644 --- a/components/wpa_supplicant/port/include/os.h +++ b/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 */ diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h index 26e4f10a77..a3d4c66620 100644 --- a/components/wpa_supplicant/port/include/supplicant_opt.h +++ b/components/wpa_supplicant/port/include/supplicant_opt.h @@ -19,10 +19,13 @@ #if CONFIG_WPA_MBEDTLS_CRYPTO #define USE_MBEDTLS_CRYPTO 1 -#endif - -#if CONFIG_WPA_TLS_V12 +#else +#define CONFIG_TLS_INTERNAL_CLIENT #define CONFIG_TLSV12 #endif +#if CONFIG_WPA_DEBUG_PRINT +#define DEBUG_PRINT +#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 index 2024b0b89c..6e62bf1d05 100644 --- a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c +++ b/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); +} 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 0000000000..bd6ec7a554 --- /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 0000000000..7d7d34635f --- /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 8483867ff1..0ba1b49163 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 6534408d34..b0f9ce3027 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) - */ -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 + * @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 2f9c992d7d..96dd03a4c6 100644 --- a/components/wpa_supplicant/src/crypto/sha256.h +++ b/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 */ 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 0000000000..196b988977 --- /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 0000000000..d946907c67 --- /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 0000000000..c26ed7a615 --- /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 7e032685ee..1de15542a6 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 983999b51d..a3f42231fe 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 65e08b8fa9..73e9aa2fd6 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 6780f54dc1..d9f038b9a3 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 8ec85f1a91..a4e25e9699 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 4628af8c50..b835ce0fd6 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 a18c69e37c..08a23fbb3e 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); From 1d59af5c8451b1b95e5138e0b7d7b4faffe7a512 Mon Sep 17 00:00:00 2001 From: "kapil.gupta" Date: Sun, 19 Jul 2020 14:07:00 +0530 Subject: [PATCH 2/3] wpa_supplicant: Fix invalid pointer deference and memleak Add following changes as part of this: 1. EAP client will crash during validation of key size when CA certs and keys not present. Add changes to validate it first. 2. Free memory allocated in TLS context --- components/wpa_supplicant/src/crypto/tls_mbedtls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/wpa_supplicant/src/crypto/tls_mbedtls.c b/components/wpa_supplicant/src/crypto/tls_mbedtls.c index c26ed7a615..409281ff92 100644 --- a/components/wpa_supplicant/src/crypto/tls_mbedtls.c +++ b/components/wpa_supplicant/src/crypto/tls_mbedtls.c @@ -384,7 +384,7 @@ static void tls_set_ciphersuite(tls_context_t *tls) 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) { + (tls->cacert_ptr && mbedtls_pk_get_bitlen(&tls->cacert_ptr->pk) > 2048)) { mbedtls_ssl_conf_ciphersuites(&tls->conf, eap_ciphersuite_preference); } } @@ -504,6 +504,7 @@ 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); From d9fa1f6436313186e38b9ea23fed4eae9dd9cc04 Mon Sep 17 00:00:00 2001 From: "kapil.gupta" Date: Thu, 23 Jul 2020 22:42:37 +0530 Subject: [PATCH 3/3] wpa_supplicant: Fix IOT issue with latest freeradius Fix inter operability issue with freeradius version 3.0.21 and openssl 1.1.1f when internal tls client is used which requires extension elements in client hello. closes https://github.com/espressif/esp-idf/issues/5273 closes https://github.com/espressif/esp-idf/issues/5627 --- .../wpa_supplicant/src/tls/tlsv1_client.c | 6 +- .../src/tls/tlsv1_client_read.c | 67 ++++++- .../src/tls/tlsv1_client_write.c | 33 +++- .../wpa_supplicant/src/tls/tlsv1_common.c | 182 ++++++++++++++++++ .../wpa_supplicant/src/tls/tlsv1_common.h | 13 ++ 5 files changed, 292 insertions(+), 9 deletions(-) diff --git a/components/wpa_supplicant/src/tls/tlsv1_client.c b/components/wpa_supplicant/src/tls/tlsv1_client.c index d9f038b9a3..6831410a59 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client.c +++ b/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; diff --git a/components/wpa_supplicant/src/tls/tlsv1_client_read.c b/components/wpa_supplicant/src/tls/tlsv1_client_read.c index a585f20603..ada19464ae 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client_read.c +++ b/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; diff --git a/components/wpa_supplicant/src/tls/tlsv1_client_write.c b/components/wpa_supplicant/src/tls/tlsv1_client_write.c index 53a1b33881..a28ce4fa35 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client_write.c +++ b/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); diff --git a/components/wpa_supplicant/src/tls/tlsv1_common.c b/components/wpa_supplicant/src/tls/tlsv1_common.c index f0ba62f270..ca48b1b8b7 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_common.c +++ b/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; +} diff --git a/components/wpa_supplicant/src/tls/tlsv1_common.h b/components/wpa_supplicant/src/tls/tlsv1_common.h index f28c0cdc47..75a6274d3d 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_common.h +++ b/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 */