From 2da4ffa2aa99b3b7b9e5cf5e251330a3cd123c81 Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Thu, 19 Sep 2019 16:53:56 +0530 Subject: [PATCH 01/16] wifi: Add PMK caching feature for station WPA2-enterprise 1) Added PMK caching module from wpa_supplicant. 2) Modified wpa_sm to a) Add entry to PMK cache when first time associated to an AP. b) Maintain entry across the associations. c) Clear current PMKSA when deauth happens. d) Search for an entry when re-associating to the same AP and set it as current PMKSA e) Wait for msg 1/4 from AP instead of starting EAP authentication. f) Check PMKID in msg 1 with current PMKSA/cache. g) Use the cached PMK to complete 4-way handshake. 3) Remove config_bss callback as it was redundant and used to cause problems for PMK caching flow. Closes IDF-969 --- components/wpa_supplicant/CMakeLists.txt | 1 + .../wpa_supplicant/include/utils/common.h | 286 +++++++--- components/wpa_supplicant/port/include/os.h | 9 + components/wpa_supplicant/src/common/defs.h | 136 ++++- .../src/esp_supplicant/esp_wifi_driver.h | 2 +- .../src/esp_supplicant/esp_wpa2.c | 21 +- .../src/esp_supplicant/esp_wpa_main.c | 16 +- .../src/esp_supplicant/esp_wpas_glue.c | 2 + .../wpa_supplicant/src/rsn_supp/pmksa_cache.c | 528 ++++++++++++++++++ .../wpa_supplicant/src/rsn_supp/pmksa_cache.h | 134 +++++ components/wpa_supplicant/src/rsn_supp/wpa.c | 277 ++++++++- components/wpa_supplicant/src/rsn_supp/wpa.h | 1 + .../wpa_supplicant/src/rsn_supp/wpa_i.h | 17 +- .../wpa_supplicant/src/rsn_supp/wpa_ie.c | 462 +++++++-------- components/wpa_supplicant/src/utils/common.c | 285 ++++++++-- 15 files changed, 1793 insertions(+), 384 deletions(-) create mode 100644 components/wpa_supplicant/src/rsn_supp/pmksa_cache.c create mode 100644 components/wpa_supplicant/src/rsn_supp/pmksa_cache.h diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index f3cfecc3fe..36dd7a096b 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -46,6 +46,7 @@ set(srcs "port/os_xtensa.c" "src/esp_supplicant/esp_wpa_main.c" "src/esp_supplicant/esp_wpas_glue.c" "src/esp_supplicant/esp_wps.c" + "src/rsn_supp/pmksa_cache.c" "src/rsn_supp/wpa.c" "src/rsn_supp/wpa_ie.c" "src/tls/asn1.c" diff --git a/components/wpa_supplicant/include/utils/common.h b/components/wpa_supplicant/include/utils/common.h index 6fadca049b..c5674254ed 100644 --- a/components/wpa_supplicant/include/utils/common.h +++ b/components/wpa_supplicant/include/utils/common.h @@ -2,14 +2,8 @@ * wpa_supplicant/hostapd / common helper functions, etc. * Copyright (c) 2002-2007, Jouni Malinen * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef COMMON_H @@ -65,6 +59,7 @@ static inline unsigned int wpa_swap_32(unsigned int v) #define be_to_host16(n) wpa_swap_16(n) #define host_to_be16(n) wpa_swap_16(n) #define le_to_host32(n) (n) +#define host_to_le32(n) (n) #define be_to_host32(n) wpa_swap_32(n) #define host_to_be32(n) wpa_swap_32(n) @@ -125,80 +120,122 @@ static inline unsigned int wpa_swap_32(unsigned int v) /* Macros for handling unaligned memory accesses */ -#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) -#define WPA_PUT_BE16(a, val) \ - do { \ - (a)[0] = ((u16) (val)) >> 8; \ - (a)[1] = ((u16) (val)) & 0xff; \ - } while (0) +static inline u16 WPA_GET_BE16(const u8 *a) +{ + return (a[0] << 8) | a[1]; +} -#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) -#define WPA_PUT_LE16(a, val) \ - do { \ - (a)[1] = ((u16) (val)) >> 8; \ - (a)[0] = ((u16) (val)) & 0xff; \ - } while (0) +static inline void WPA_PUT_BE16(u8 *a, u16 val) +{ + a[0] = val >> 8; + a[1] = val & 0xff; +} -#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ - ((u32) (a)[2])) -#define WPA_PUT_BE24(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[2] = (u8) (((u32) (val)) & 0xff); \ - } while (0) +static inline u16 WPA_GET_LE16(const u8 *a) +{ + return (a[1] << 8) | a[0]; +} -#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ - (((u32) (a)[2]) << 8) | ((u32) (a)[3])) -#define WPA_PUT_BE32(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[3] = (u8) (((u32) (val)) & 0xff); \ - } while (0) +static inline void WPA_PUT_LE16(u8 *a, u16 val) +{ + a[1] = val >> 8; + a[0] = val & 0xff; +} -#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ - (((u32) (a)[1]) << 8) | ((u32) (a)[0])) -#define WPA_PUT_LE32(a, val) \ - do { \ - (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[0] = (u8) (((u32) (val)) & 0xff); \ - } while (0) +static inline u32 WPA_GET_BE24(const u8 *a) +{ + return (a[0] << 16) | (a[1] << 8) | a[2]; +} -#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ - (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ - (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ - (((u64) (a)[6]) << 8) | ((u64) (a)[7])) -#define WPA_PUT_BE64(a, val) \ - do { \ - (a)[0] = (u8) (((u64) (val)) >> 56); \ - (a)[1] = (u8) (((u64) (val)) >> 48); \ - (a)[2] = (u8) (((u64) (val)) >> 40); \ - (a)[3] = (u8) (((u64) (val)) >> 32); \ - (a)[4] = (u8) (((u64) (val)) >> 24); \ - (a)[5] = (u8) (((u64) (val)) >> 16); \ - (a)[6] = (u8) (((u64) (val)) >> 8); \ - (a)[7] = (u8) (((u64) (val)) & 0xff); \ - } while (0) +static inline void WPA_PUT_BE24(u8 *a, u32 val) +{ + a[0] = (val >> 16) & 0xff; + a[1] = (val >> 8) & 0xff; + a[2] = val & 0xff; +} -#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ - (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ - (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ - (((u64) (a)[1]) << 8) | ((u64) (a)[0])) +static inline u32 WPA_GET_BE32(const u8 *a) +{ + return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; +} + +static inline void WPA_PUT_BE32(u8 *a, u32 val) +{ + a[0] = (val >> 24) & 0xff; + a[1] = (val >> 16) & 0xff; + a[2] = (val >> 8) & 0xff; + a[3] = val & 0xff; +} + +static inline u32 WPA_GET_LE32(const u8 *a) +{ + return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; +} + +static inline void WPA_PUT_LE32(u8 *a, u32 val) +{ + a[3] = (val >> 24) & 0xff; + a[2] = (val >> 16) & 0xff; + a[1] = (val >> 8) & 0xff; + a[0] = val & 0xff; +} + +static inline u64 WPA_GET_BE64(const u8 *a) +{ + return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) | + (((u64) a[2]) << 40) | (((u64) a[3]) << 32) | + (((u64) a[4]) << 24) | (((u64) a[5]) << 16) | + (((u64) a[6]) << 8) | ((u64) a[7]); +} + +static inline void WPA_PUT_BE64(u8 *a, u64 val) +{ + a[0] = val >> 56; + a[1] = val >> 48; + a[2] = val >> 40; + a[3] = val >> 32; + a[4] = val >> 24; + a[5] = val >> 16; + a[6] = val >> 8; + a[7] = val & 0xff; +} + +static inline u64 WPA_GET_LE64(const u8 *a) +{ + return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) | + (((u64) a[5]) << 40) | (((u64) a[4]) << 32) | + (((u64) a[3]) << 24) | (((u64) a[2]) << 16) | + (((u64) a[1]) << 8) | ((u64) a[0]); +} + +static inline void WPA_PUT_LE64(u8 *a, u64 val) +{ + a[7] = val >> 56; + a[6] = val >> 48; + a[5] = val >> 40; + a[4] = val >> 32; + a[3] = val >> 24; + a[2] = val >> 16; + a[1] = val >> 8; + a[0] = val & 0xff; +} #ifndef ETH_ALEN #define ETH_ALEN 6 #endif -//#ifndef IFNAMSIZ -//#define IFNAMSIZ 16 -//#endif +#ifndef ETH_HLEN +#define ETH_HLEN 14 +#endif +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif #ifndef ETH_P_ALL #define ETH_P_ALL 0x0003 #endif +#ifndef ETH_P_80211_ENCAP +#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ +#endif #ifndef ETH_P_PAE #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ #endif /* ETH_P_PAE */ @@ -221,8 +258,31 @@ static inline unsigned int wpa_swap_32(unsigned int v) #define STRUCT_PACKED #endif + #ifdef CONFIG_ANSI_C_EXTRA +#if !defined(_MSC_VER) || _MSC_VER < 1400 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement + * due to possible buffer overflow; see, e.g., + * http://www.ijs.si/software/snprintf/ for portable implementation of + * snprintf. */ +int snprintf(char *str, size_t size, const char *format, ...); + +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ + +/* getopt - only used in main.c */ +int getopt(int argc, char *const argv[], const char *optstring); +extern char *optarg; +extern int optind; + +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF +#ifndef __socklen_t_defined +typedef int socklen_t; +#endif +#endif + /* inline - define as __inline or just define it to be empty, if needed */ #ifdef CONFIG_NO_INLINE #define inline @@ -258,10 +318,16 @@ void perror(const char *s); #ifndef MAC2STR #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +/* + * Compact form for string representation of MAC address + * To be used, e.g., for constructing dbus paths for P2P Devices + */ +#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x" #endif #ifndef BIT -#define BIT(x) (1 << (x)) +#define BIT(x) (1U << (x)) #endif /* @@ -291,15 +357,31 @@ typedef u64 __bitwise le64; #endif /* __GNUC__ */ #endif /* __must_check */ +#ifndef __maybe_unused +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __maybe_unused __attribute__((unused)) +#else +#define __maybe_unused +#endif /* __GNUC__ */ +#endif /* __must_check */ + int hwaddr_aton(const char *txt, u8 *addr); +int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); +int hwaddr_compact_aton(const char *txt, u8 *addr); int hwaddr_aton2(const char *txt, u8 *addr); +int hex2byte(const char *hex); int hexstr2bin(const char *hex, u8 *buf, size_t len); void inc_byte_array(u8 *counter, size_t len); void wpa_get_ntp_timestamp(u8 *buf); +int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...); +int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, + char sep); int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len); +int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask); + #ifdef CONFIG_NATIVE_WINDOWS void wpa_unicode2ascii_inplace(TCHAR *str); TCHAR * wpa_strdup_tchar(const char *str); @@ -308,21 +390,74 @@ TCHAR * wpa_strdup_tchar(const char *str); #define wpa_strdup_tchar(s) strdup((s)) #endif /* CONFIG_NATIVE_WINDOWS */ +void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len); +size_t printf_decode(u8 *buf, size_t maxlen, const char *str); + const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); + char * wpa_config_parse_string(const char *value, size_t *len); +int is_hex(const u8 *data, size_t len); +size_t merge_byte_arrays(u8 *res, size_t res_len, + const u8 *src1, size_t src1_len, + const u8 *src2, size_t src2_len); +char * dup_binstr(const void *src, size_t len); static inline int is_zero_ether_addr(const u8 *a) { return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); } -extern const struct eth_addr ethbroadcast; -#define broadcast_ether_addr ðbroadcast +static inline int is_broadcast_ether_addr(const u8 *a) +{ + return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; +} + +static inline int is_multicast_ether_addr(const u8 *a) +{ + return a[0] & 0x01; +} + +#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" + -#include "wpabuf.h" #include "wpa_debug.h" +struct wpa_freq_range_list { + struct wpa_freq_range { + unsigned int min; + unsigned int max; + } *range; + unsigned int num; +}; + +int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value); +int freq_range_list_includes(const struct wpa_freq_range_list *list, + unsigned int freq); +char * freq_range_list_str(const struct wpa_freq_range_list *list); + +int int_array_len(const int *a); +void int_array_concat(int **res, const int *a); +void int_array_sort_unique(int *a); +void int_array_add_unique(int **res, int a); + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +void str_clear_free(char *str); +void bin_clear_free(void *bin, size_t len); + +int random_mac_addr(u8 *addr); +int random_mac_addr_keep_oui(u8 *addr); + +const char * cstr_token(const char *str, const char *delim, const char **last); +char * str_token(char *str, const char *delim, char **context); +size_t utf8_escape(const char *inp, size_t in_size, + char *outp, size_t out_size); +size_t utf8_unescape(const char *inp, size_t in_size, + char *outp, size_t out_size); +int is_ctrl_char(char c); + + /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common * networking socket uses that do not really result in a real problem and @@ -335,4 +470,11 @@ extern const struct eth_addr ethbroadcast; void * __hide_aliasing_typecast(void *foo); #define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) +#ifdef CONFIG_VALGRIND +#include +#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) +#else /* CONFIG_VALGRIND */ +#define WPA_MEM_DEFINED(ptr, len) do { } while (0) +#endif /* CONFIG_VALGRIND */ + #endif /* COMMON_H */ diff --git a/components/wpa_supplicant/port/include/os.h b/components/wpa_supplicant/port/include/os.h index ff1ba9bce1..5a17259e59 100644 --- a/components/wpa_supplicant/port/include/os.h +++ b/components/wpa_supplicant/port/include/os.h @@ -228,6 +228,10 @@ char * ets_strdup(const char *s); #ifndef os_memcmp #define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) #endif +#ifndef os_memcmp_const +#define os_memcmp_const(s1, s2, n) memcmp((s1), (s2), (n)) +#endif + #ifndef os_strlen #define os_strlen(s) strlen(s) @@ -274,6 +278,11 @@ char * ets_strdup(const char *s); #endif #endif +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 diff --git a/components/wpa_supplicant/src/common/defs.h b/components/wpa_supplicant/src/common/defs.h index 578604296b..2f4360ba98 100644 --- a/components/wpa_supplicant/src/common/defs.h +++ b/components/wpa_supplicant/src/common/defs.h @@ -1,15 +1,9 @@ /* * WPA Supplicant - Common definitions - * Copyright (c) 2004-2008, Jouni Malinen + * Copyright (c) 2004-2015, Jouni Malinen * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef DEFS_H @@ -41,43 +35,95 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7) #define WPA_KEY_MGMT_PSK_SHA256 BIT(8) #define WPA_KEY_MGMT_WPS BIT(9) +#define WPA_KEY_MGMT_SAE BIT(10) +#define WPA_KEY_MGMT_FT_SAE BIT(11) +#define WPA_KEY_MGMT_WAPI_PSK BIT(12) +#define WPA_KEY_MGMT_WAPI_CERT BIT(13) #define WPA_KEY_MGMT_CCKM BIT(14) +#define WPA_KEY_MGMT_OSEN BIT(15) +#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16) +#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17) static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) { return !!(akm & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_CCKM | - WPA_KEY_MGMT_IEEE8021X_SHA256)); + WPA_KEY_MGMT_OSEN | + WPA_KEY_MGMT_IEEE8021X_SHA256 | + WPA_KEY_MGMT_IEEE8021X_SUITE_B | + WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)); } static inline int wpa_key_mgmt_wpa_psk(int akm) { - return akm == WPA_KEY_MGMT_PSK || - akm == WPA_KEY_MGMT_FT_PSK || - akm == WPA_KEY_MGMT_PSK_SHA256; + return !!(akm & (WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256 | + WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_FT_SAE)); } static inline int wpa_key_mgmt_ft(int akm) { - return akm == WPA_KEY_MGMT_FT_PSK || - akm == WPA_KEY_MGMT_FT_IEEE8021X; + return !!(akm & (WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_FT_IEEE8021X | + WPA_KEY_MGMT_FT_SAE)); +} + +static inline int wpa_key_mgmt_sae(int akm) +{ + return !!(akm & (WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_FT_SAE)); } static inline int wpa_key_mgmt_sha256(int akm) { - return akm == WPA_KEY_MGMT_PSK_SHA256 || - akm == WPA_KEY_MGMT_IEEE8021X_SHA256; + return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 | + WPA_KEY_MGMT_IEEE8021X_SHA256 | + WPA_KEY_MGMT_OSEN | + WPA_KEY_MGMT_IEEE8021X_SUITE_B)); +} + +static inline int wpa_key_mgmt_sha384(int akm) +{ + return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192); +} + +static inline int wpa_key_mgmt_suite_b(int akm) +{ + return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B | + WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)); +} + +static inline int wpa_key_mgmt_wpa(int akm) +{ + return wpa_key_mgmt_wpa_ieee8021x(akm) || + wpa_key_mgmt_wpa_psk(akm) || + wpa_key_mgmt_sae(akm); +} + +static inline int wpa_key_mgmt_wpa_any(int akm) +{ + return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE); +} + +static inline int wpa_key_mgmt_cckm(int akm) +{ + return akm == WPA_KEY_MGMT_CCKM; } #define WPA_PROTO_WPA BIT(0) #define WPA_PROTO_RSN BIT(1) +#define WPA_PROTO_WAPI BIT(2) +#define WPA_PROTO_OSEN BIT(3) #define WPA_AUTH_ALG_OPEN BIT(0) #define WPA_AUTH_ALG_SHARED BIT(1) #define WPA_AUTH_ALG_LEAP BIT(2) #define WPA_AUTH_ALG_FT BIT(3) +#define WPA_AUTH_ALG_SAE BIT(4) enum wifi_key_alg { @@ -147,6 +193,15 @@ enum wpa_states { */ WPA_DISCONNECTED, + /** + * WPA_INTERFACE_DISABLED - Interface disabled + * + * This state is entered if the network interface is disabled, e.g., + * due to rfkill. wpa_supplicant refuses any new operations that would + * use the radio until the interface has been enabled. + */ + WPA_INTERFACE_DISABLED, + /** * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) * @@ -249,6 +304,17 @@ enum wpa_states { #define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 #define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 + +/** + * enum mfp_options - Management frame protection (IEEE 802.11w) options + */ +enum mfp_options { + NO_MGMT_FRAME_PROTECTION = 0, + MGMT_FRAME_PROTECTION_OPTIONAL = 1, + MGMT_FRAME_PROTECTION_REQUIRED = 2, +}; +#define MGMT_FRAME_PROTECTION_DEFAULT 3 + /** * enum hostapd_hw_mode - Hardware mode */ @@ -257,7 +323,43 @@ enum hostapd_hw_mode { HOSTAPD_MODE_IEEE80211G, HOSTAPD_MODE_IEEE80211A, HOSTAPD_MODE_IEEE80211AD, + HOSTAPD_MODE_IEEE80211ANY, NUM_HOSTAPD_MODES }; +/** + * enum wpa_ctrl_req_type - Control interface request types + */ +enum wpa_ctrl_req_type { + WPA_CTRL_REQ_UNKNOWN, + WPA_CTRL_REQ_EAP_IDENTITY, + WPA_CTRL_REQ_EAP_PASSWORD, + WPA_CTRL_REQ_EAP_NEW_PASSWORD, + WPA_CTRL_REQ_EAP_PIN, + WPA_CTRL_REQ_EAP_OTP, + WPA_CTRL_REQ_EAP_PASSPHRASE, + WPA_CTRL_REQ_SIM, + WPA_CTRL_REQ_PSK_PASSPHRASE, + NUM_WPA_CTRL_REQS +}; + +/* Maximum number of EAP methods to store for EAP server user information */ +#define EAP_MAX_METHODS 8 + +enum mesh_plink_state { + PLINK_LISTEN = 1, + PLINK_OPEN_SENT, + PLINK_OPEN_RCVD, + PLINK_CNF_RCVD, + PLINK_ESTAB, + PLINK_HOLDING, + PLINK_BLOCKED, +}; + +enum set_band { + WPA_SETBAND_AUTO, + WPA_SETBAND_5G, + WPA_SETBAND_2G +}; + #endif /* DEFS_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index 62d2d6246e..b4767ef197 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -105,7 +105,7 @@ typedef struct { } wifi_wpa_ie_t; struct wpa_funcs { - void (*wpa_sta_init)(void); + bool (*wpa_sta_init)(void); bool (*wpa_sta_deinit)(void); void (*wpa_sta_connect)(uint8_t *bssid); int (*wpa_sta_rx_eapol)(u8 *src_addr, u8 *buf, u32 len); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c index 584b2acc1b..672955ef9b 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c @@ -58,7 +58,7 @@ static struct eap_sm *gEapSm = NULL; static int eap_peer_sm_init(void); static void eap_peer_sm_deinit(void); -static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid); +static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid); static int wpa2_start_eapol_internal(void); int wpa2_post(uint32_t sig, uint32_t par); @@ -216,7 +216,7 @@ void wpa2_task(void *pvParameters ) struct wpa2_rx_param *param = NULL; while ((param = wpa2_rxq_dequeue()) != NULL){ - wpa2_sm_rx_eapol_internal(param->sa, param->buf, param->len, param->bssid); + eap_sm_rx_eapol_internal(param->sa, param->buf, param->len, param->bssid); os_free(param->buf); os_free(param); } @@ -541,12 +541,11 @@ static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) } #else - return wpa2_sm_rx_eapol_internal(src_addr, buf, len, bssid); + return eap_sm_rx_eapol_internal(src_addr, buf, len, bssid); #endif } - -static int wpa2_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) +static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) { struct eap_sm *sm = gEapSm; u32 plen, data_len; @@ -666,6 +665,18 @@ static int wpa2_start_eapol_internal(void) if (!sm) { return ESP_FAIL; } + if (wpa_sta_is_cur_pmksa_set()) { + if (0) { + wpa_printf(MSG_DEBUG, + "RSN: Timeout on waiting for the AP to initiate 4-way handshake \ + for PMKSA caching or EAP authentication \ + - try to force it to start EAP authentication"); + } else { + wpa_printf(MSG_DEBUG, + "RSN: PMKSA caching - do not send EAPOL-Start"); + return -1; + } + } ret = esp_wifi_get_assoc_bssid_internal(bssid); if (ret != 0) { diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index d0cb7a21b7..74048a28a6 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -106,18 +106,21 @@ void wpa_neg_complete() esp_wifi_auth_done_internal(); } -void wpa_attach(void) +bool wpa_attach(void) { + bool ret = true; #ifndef IOT_SIP_MODE - wpa_register(NULL, wpa_sendto_wrapper, + ret = wpa_sm_init(NULL, wpa_sendto_wrapper, wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); #else u8 *payload = (u8 *)os_malloc(WPA_TX_MSG_BUFF_MAXLEN); - wpa_register(payload, wpa_sendto_wrapper, + ret = wpa_sm_init(payload, wpa_sendto_wrapper, wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); #endif - - esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID); + if(ret) { + ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK); + } + return ret; } uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len) @@ -148,6 +151,7 @@ bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len) bool wpa_deattach(void) { + wpa_sm_deinit(); return true; } @@ -224,7 +228,7 @@ int esp_supplicant_init(void) wpa_cb->wpa_config_parse_string = wpa_config_parse_string; wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper; - wpa_cb->wpa_config_bss = wpa_config_bss; + wpa_cb->wpa_config_bss = NULL;//wpa_config_bss; wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; esp_wifi_register_wpa_cb_internal(wpa_cb); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c index 89c901f802..1e3fc424c7 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c @@ -18,6 +18,7 @@ #include "utils/common.h" #include "common/eapol_common.h" #include "rsn_supp/wpa.h" +#include "rsn_supp/pmksa_cache.h" u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, const void *data, u16 data_len, @@ -65,6 +66,7 @@ void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code) /*only need send deauth frame when associated*/ if (WPA_SM_STATE(sm) >= WPA_ASSOCIATED) { + pmksa_cache_clear_current(sm); sm->wpa_deauthenticate(reason_code); } } diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c new file mode 100644 index 0000000000..6e09d07c19 --- /dev/null +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c @@ -0,0 +1,528 @@ +/* + * WPA Supplicant - RSN PMKSA cache + * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "rsn_supp/wpa.h" +#include "rsn_supp/wpa_i.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "pmksa_cache.h" + +#ifdef IEEE8021X_EAPOL + +static const int pmksa_cache_max_entries = 10; + +struct rsn_pmksa_cache { + struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ + int pmksa_count; /* number of entries in PMKSA cache */ + struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ + + void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, + enum pmksa_free_reason reason); + void *ctx; +}; + + +//static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); + + +static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) +{ + bin_clear_free(entry, sizeof(*entry)); +} + + +static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry, + enum pmksa_free_reason reason) +{ + //wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid); + pmksa->pmksa_count--; + pmksa->free_cb(entry, pmksa->ctx, reason); + _pmksa_cache_free_entry(entry); +} + +#if 0 +static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) +{ + struct rsn_pmksa_cache *pmksa = eloop_ctx; + struct os_reltime now; + + os_get_reltime(&now); + while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { + struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; + pmksa->pmksa = entry->next; + wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " + MACSTR, MAC2STR(entry->aa)); + pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE); + } + + pmksa_cache_set_expiration(pmksa); +} + +static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) +{ + struct rsn_pmksa_cache *pmksa = eloop_ctx; + pmksa->sm->cur_pmksa = NULL; + eapol_sm_request_reauth(pmksa->sm->eapol); +} + +static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) +{ + int sec; + struct rsn_pmksa_cache_entry *entry; + struct os_reltime now; + + eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); + if (pmksa->pmksa == NULL) + return; + os_get_reltime(&now); + sec = pmksa->pmksa->expiration - now.sec; + if (sec < 0) + sec = 0; + eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); + + entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : + pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL); + if (entry) { + sec = pmksa->pmksa->reauth_time - now.sec; + if (sec < 0) + sec = 0; + eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, + NULL); + } +} +#endif + +/** + * pmksa_cache_add - Add a PMKSA cache entry + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @pmk: The new pairwise master key + * @pmk_len: PMK length in bytes, usually PMK_LEN (32) + * @kck: Key confirmation key or %NULL if not yet derived + * @kck_len: KCK length in bytes + * @aa: Authenticator address + * @spa: Supplicant address + * @network_ctx: Network configuration context for this PMK + * @akmp: WPA_KEY_MGMT_* used in key derivation + * Returns: Pointer to the added PMKSA cache entry or %NULL on error + * + * This function create a PMKSA entry for a new PMK and adds it to the PMKSA + * cache. If an old entry is already in the cache for the same Authenticator, + * this entry will be replaced with the new entry. PMKID will be calculated + * based on the PMK and the driver interface is notified of the new PMKID. + */ +struct rsn_pmksa_cache_entry * +pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, + const u8 *kck, size_t kck_len, + const u8 *aa, const u8 *spa, void *network_ctx, int akmp) +{ + struct rsn_pmksa_cache_entry *entry, *pos, *prev; + //struct os_reltime now; + + if (pmk_len > PMK_LEN) + return NULL; + + if (wpa_key_mgmt_suite_b(akmp) && !kck) + return NULL; + + entry = os_zalloc(sizeof(*entry)); + if (entry == NULL) + return NULL; + os_memcpy(entry->pmk, pmk, pmk_len); + entry->pmk_len = pmk_len; + rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, + wpa_key_mgmt_sha256(akmp)); + //os_get_reltime(&now); + //entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; + /*entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * + pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;*/ + entry->akmp = akmp; + os_memcpy(entry->aa, aa, ETH_ALEN); + entry->network_ctx = network_ctx; + + /* Replace an old entry for the same Authenticator (if found) with the + * new entry */ + pos = pmksa->pmksa; + prev = NULL; + while (pos) { + if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { + if (pos->pmk_len == pmk_len && + os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 && + os_memcmp_const(pos->pmkid, entry->pmkid, + PMKID_LEN) == 0) { + wpa_printf(MSG_DEBUG, "WPA: reusing previous " + "PMKSA entry"); + os_free(entry); + return pos; + } + if (prev == NULL) + pmksa->pmksa = pos->next; + else + prev->next = pos->next; + + /* + * If OKC is used, there may be other PMKSA cache + * entries based on the same PMK. These needs to be + * flushed so that a new entry can be created based on + * the new PMK. Only clear other entries if they have a + * matching PMK and this PMK has been used successfully + * with the current AP, i.e., if opportunistic flag has + * been cleared in wpa_supplicant_key_neg_complete(). + */ + wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " + "the current AP and any PMKSA cache entry " + "that was based on the old PMK"); + if (!pos->opportunistic) + pmksa_cache_flush(pmksa, network_ctx, pos->pmk, + pos->pmk_len); + pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); + break; + } + prev = pos; + pos = pos->next; + } + + if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { + /* Remove the oldest entry to make room for the new entry */ + pos = pmksa->pmksa; + + if (pos == pmksa->sm->cur_pmksa) { + /* + * Never remove the current PMKSA cache entry, since + * it's in use, and removing it triggers a needless + * deauthentication. + */ + pos = pos->next; + pmksa->pmksa->next = pos ? pos->next : NULL; + } else + pmksa->pmksa = pos->next; + + if (pos) { + wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle " + "PMKSA cache entry (for " MACSTR ") to " + "make room for new one", + MAC2STR(pos->aa)); + pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE); + } + } + + /* Add the new entry; order by expiration time */ + pos = pmksa->pmksa; + prev = NULL; + while (pos) { + if (pos->expiration > entry->expiration) + break; + prev = pos; + pos = pos->next; + } + if (prev == NULL) { + entry->next = pmksa->pmksa; + pmksa->pmksa = entry; + //pmksa_cache_set_expiration(pmksa); + } else { + entry->next = prev->next; + prev->next = entry; + } + pmksa->pmksa_count++; + wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR + " network_ctx=%p", MAC2STR(entry->aa), network_ctx); + //wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid); + + return entry; +} + + +/** + * pmksa_cache_flush - Flush PMKSA cache entries for a specific network + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @network_ctx: Network configuration context or %NULL to flush all entries + * @pmk: PMK to match for or %NYLL to match all PMKs + * @pmk_len: PMK length + */ +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, + const u8 *pmk, size_t pmk_len) +{ + struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; + int removed = 0; + + entry = pmksa->pmksa; + while (entry) { + if ((entry->network_ctx == network_ctx || + network_ctx == NULL) && + (pmk == NULL || + (pmk_len == entry->pmk_len && + os_memcmp(pmk, entry->pmk, pmk_len) == 0))) { + wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " + "for " MACSTR, MAC2STR(entry->aa)); + if (prev) + prev->next = entry->next; + else + pmksa->pmksa = entry->next; + tmp = entry; + entry = entry->next; + pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE); + removed++; + } else { + prev = entry; + entry = entry->next; + } + } + /*if (removed) + pmksa_cache_set_expiration(pmksa);*/ +} + + +/** + * pmksa_cache_deinit - Free all entries in PMKSA cache + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + */ +void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) +{ + struct rsn_pmksa_cache_entry *entry, *prev; + + if (pmksa == NULL) + return; + + entry = pmksa->pmksa; + pmksa->pmksa = NULL; + while (entry) { + prev = entry; + entry = entry->next; + os_free(prev); + } + //pmksa_cache_set_expiration(pmksa); + os_free(pmksa); +} + + +/** + * pmksa_cache_get - Fetch a PMKSA cache entry + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @aa: Authenticator address or %NULL to match any + * @pmkid: PMKID or %NULL to match any + * @network_ctx: Network context or %NULL to match any + * Returns: Pointer to PMKSA cache entry or %NULL if no match was found + */ +struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, + const u8 *aa, const u8 *pmkid, + const void *network_ctx) +{ + struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; + while (entry) { + if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && + (pmkid == NULL || + os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && + (network_ctx == NULL || network_ctx == entry->network_ctx)) + return entry; + entry = entry->next; + } + return NULL; +} + + +static struct rsn_pmksa_cache_entry * +pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, + const struct rsn_pmksa_cache_entry *old_entry, + const u8 *aa) +{ + struct rsn_pmksa_cache_entry *new_entry; + + new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, + NULL, 0, + aa, pmksa->sm->own_addr, + old_entry->network_ctx, old_entry->akmp); + if (new_entry == NULL) + return NULL; + + /* TODO: reorder entries based on expiration time? */ + new_entry->expiration = old_entry->expiration; + new_entry->opportunistic = 1; + + return new_entry; +} + + +/** + * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @network_ctx: Network configuration context + * @aa: Authenticator address for the new AP + * Returns: Pointer to a new PMKSA cache entry or %NULL if not available + * + * Try to create a new PMKSA cache entry opportunistically by guessing that the + * new AP is sharing the same PMK as another AP that has the same SSID and has + * already an entry in PMKSA cache. + */ +struct rsn_pmksa_cache_entry * +pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, + const u8 *aa) +{ + struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; + + wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa)); + if (network_ctx == NULL) + return NULL; + while (entry) { + if (entry->network_ctx == network_ctx) { + entry = pmksa_cache_clone_entry(pmksa, entry, aa); + if (entry) { + wpa_printf(MSG_DEBUG, "RSN: added " + "opportunistic PMKSA cache entry " + "for " MACSTR, MAC2STR(aa)); + } + return entry; + } + entry = entry->next; + } + return NULL; +} + + +/** + * pmksa_cache_get_current - Get the current used PMKSA entry + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * Returns: Pointer to the current PMKSA cache entry or %NULL if not available + */ +struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) +{ + if (sm == NULL) + return NULL; + return sm->cur_pmksa; +} + + +/** + * pmksa_cache_clear_current - Clear the current PMKSA entry selection + * @sm: Pointer to WPA state machine data from wpa_sm_init() + */ +void pmksa_cache_clear_current(struct wpa_sm *sm) +{ + if (sm == NULL) + return; + sm->cur_pmksa = NULL; +} + + +/** + * pmksa_cache_set_current - Set the current PMKSA entry selection + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @pmkid: PMKID for selecting PMKSA or %NULL if not used + * @bssid: BSSID for PMKSA or %NULL if not used + * @network_ctx: Network configuration context + * @try_opportunistic: Whether to allow opportunistic PMKSA caching + * Returns: 0 if PMKSA was found or -1 if no matching entry was found + */ +int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, + const u8 *bssid, void *network_ctx, + int try_opportunistic) +{ + struct rsn_pmksa_cache *pmksa = sm->pmksa; + wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " + "try_opportunistic=%d", network_ctx, try_opportunistic); + if (pmkid) + wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", + pmkid, PMKID_LEN); + if (bssid) + wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR, + MAC2STR(bssid)); + + sm->cur_pmksa = NULL; + if (pmkid) + sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, + network_ctx); + if (sm->cur_pmksa == NULL && bssid) + sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, + network_ctx); + if (sm->cur_pmksa == NULL && try_opportunistic && bssid) + sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, + network_ctx, + bssid); + if (sm->cur_pmksa) { + wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", + sm->cur_pmksa->pmkid, PMKID_LEN); + return 0; + } + wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found"); + return -1; +} + + +/** + * pmksa_cache_list - Dump text list of entries in PMKSA cache + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @buf: Buffer for the list + * @len: Length of the buffer + * Returns: number of bytes written to buffer + * + * This function is used to generate a text format representation of the + * current PMKSA cache contents for the ctrl_iface PMKSA command. + */ +int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) +{ + int i, ret; + char *pos = buf; + struct rsn_pmksa_cache_entry *entry; + //struct os_reltime now; + + //os_get_reltime(&now); + ret = os_snprintf(pos, buf + len - pos, + "Index / AA / PMKID / expiration (in seconds) / " + "opportunistic\n"); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; + i = 0; + entry = pmksa->pmksa; + while (entry) { + i++; + ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", + i, MAC2STR(entry->aa)); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; + pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, + PMKID_LEN); + ret = os_snprintf(pos, buf + len - pos, " %d %d\n", + (int) (entry->expiration),// - now.sec), + entry->opportunistic); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; + entry = entry->next; + } + return pos - buf; +} + + +/** + * pmksa_cache_init - Initialize PMKSA cache + * @free_cb: Callback function to be called when a PMKSA cache entry is freed + * @ctx: Context pointer for free_cb function + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * Returns: Pointer to PMKSA cache data or %NULL on failure + */ +struct rsn_pmksa_cache * +pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx, enum pmksa_free_reason reason), + void *ctx, struct wpa_sm *sm) +{ + struct rsn_pmksa_cache *pmksa; + + pmksa = os_zalloc(sizeof(*pmksa)); + if (pmksa) { + pmksa->free_cb = free_cb; + pmksa->ctx = ctx; + pmksa->sm = sm; + } + + return pmksa; +} + +#endif /* IEEE8021X_EAPOL */ diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h new file mode 100644 index 0000000000..f8e040e067 --- /dev/null +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h @@ -0,0 +1,134 @@ +/* + * wpa_supplicant - WPA2/RSN PMKSA cache functions + * Copyright (c) 2003-2009, 2011-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef PMKSA_CACHE_H +#define PMKSA_CACHE_H + +/** + * struct rsn_pmksa_cache_entry - PMKSA cache entry + */ +struct rsn_pmksa_cache_entry { + struct rsn_pmksa_cache_entry *next; + u8 pmkid[PMKID_LEN]; + u8 pmk[PMK_LEN]; + size_t pmk_len; + os_time_t expiration; + int akmp; /* WPA_KEY_MGMT_* */ + u8 aa[ETH_ALEN]; + + os_time_t reauth_time; + + /** + * network_ctx - Network configuration context + * + * This field is only used to match PMKSA cache entries to a specific + * network configuration (e.g., a specific SSID and security policy). + * This can be a pointer to the configuration entry, but PMKSA caching + * code does not dereference the value and this could be any kind of + * identifier. + */ + void *network_ctx; + int opportunistic; +}; + +struct rsn_pmksa_cache; + +enum pmksa_free_reason { + PMKSA_FREE, + PMKSA_REPLACE, + PMKSA_EXPIRE, +}; + +#ifdef IEEE8021X_EAPOL + +struct rsn_pmksa_cache * +pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx, enum pmksa_free_reason reason), + void *ctx, struct wpa_sm *sm); +void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); +struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, + const u8 *aa, const u8 *pmkid, + const void *network_ctx); +int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); +struct rsn_pmksa_cache_entry * +pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, + const u8 *kck, size_t kck_len, + const u8 *aa, const u8 *spa, void *network_ctx, int akmp); +struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); +void pmksa_cache_clear_current(struct wpa_sm *sm); +int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, + const u8 *bssid, void *network_ctx, + int try_opportunistic); +struct rsn_pmksa_cache_entry * +pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, + void *network_ctx, const u8 *aa); +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, + const u8 *pmk, size_t pmk_len); + +#else /* IEEE8021X_EAPOL */ + +static inline struct rsn_pmksa_cache * +pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx, enum pmksa_free_reason reason), + void *ctx, struct wpa_sm *sm) +{ + return (void *) -1; +} + +static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) +{ +} + +static inline struct rsn_pmksa_cache_entry * +pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid, + const void *network_ctx) +{ + return NULL; +} + +static inline struct rsn_pmksa_cache_entry * +pmksa_cache_get_current(struct wpa_sm *sm) +{ + return NULL; +} + +static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, + size_t len) +{ + return -1; +} + +static inline struct rsn_pmksa_cache_entry * +pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, + const u8 *kck, size_t kck_len, + const u8 *aa, const u8 *spa, void *network_ctx, int akmp) +{ + return NULL; +} + +static inline void pmksa_cache_clear_current(struct wpa_sm *sm) +{ +} + +static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, + const u8 *bssid, + void *network_ctx, + int try_opportunistic) +{ + return -1; +} + +static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, + void *network_ctx, + const u8 *pmk, size_t pmk_len) +{ +} + +#endif /* IEEE8021X_EAPOL */ + +#endif /* PMKSA_CACHE_H */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 2f01471264..c2d56e6a16 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -16,6 +16,7 @@ #include "utils/common.h" #include "rsn_supp/wpa.h" +#include "rsn_supp/pmksa_cache.h" #include "rsn_supp/wpa_i.h" #include "common/eapol_common.h" #include "common/ieee802_11_defs.h" @@ -45,7 +46,7 @@ /* fix buf for tx for now */ #define WPA_TX_MSG_BUFF_MAXLEN 200 -#define ASSOC_IE_LEN 24 +#define ASSOC_IE_LEN 24 + 2 + PMKID_LEN u8 assoc_ie_buf[ASSOC_IE_LEN+2]; void set_assoc_ie(u8 * assoc_buf); @@ -60,6 +61,7 @@ int wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len); +void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm); static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm) { return sm->wpa_state;; @@ -226,7 +228,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) reply->key_mic : NULL); wpa_sm_free_eapol(rbuf); } - +/* int wpa_supplicant_get_pmk(struct wpa_sm *sm) { if(sm->pmk_len >0) { @@ -235,6 +237,178 @@ int wpa_supplicant_get_pmk(struct wpa_sm *sm) return 1; } } +*/ + + +static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, + void *ctx, enum pmksa_free_reason reason) +{ + struct wpa_sm *sm = ctx; + int deauth = 0; + + wpa_printf( MSG_DEBUG, "RSN: PMKSA cache entry free_cb: " + MACSTR " reason=%d", MAC2STR(entry->aa), reason); + + if (sm->cur_pmksa == entry) { + wpa_printf( MSG_DEBUG, + "RSN: %s current PMKSA entry", + reason == PMKSA_REPLACE ? "replaced" : "removed"); + pmksa_cache_clear_current(sm); + + /* + * If an entry is simply being replaced, there's no need to + * deauthenticate because it will be immediately re-added. + * This happens when EAP authentication is completed again + * (reauth or failed PMKSA caching attempt). + * */ + if (reason != PMKSA_REPLACE) + deauth = 1; + } + + if (reason == PMKSA_EXPIRE && + (sm->pmk_len == entry->pmk_len && + os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) { + wpa_printf( MSG_DEBUG, + "RSN: deauthenticating due to expired PMK"); + pmksa_cache_clear_current(sm); + deauth = 1; + } + + if (deauth) { + os_memset(sm->pmk, 0, sizeof(sm->pmk)); + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); + } +} + + + + + +static int wpa_supplicant_get_pmk(struct wpa_sm *sm, + const unsigned char *src_addr, + const u8 *pmkid) +{ + int abort_cached = 0; + + if (pmkid && !sm->cur_pmksa) { + /* When using drivers that generate RSN IE, wpa_supplicant may + * not have enough time to get the association information + * event before receiving this 1/4 message, so try to find a + * matching PMKSA cache entry here. */ + sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid, + NULL); + if (sm->cur_pmksa) { + wpa_printf(MSG_DEBUG, + "RSN: found matching PMKID from PMKSA cache"); + } else { + wpa_printf( MSG_DEBUG, + "RSN: no matching PMKID found"); + abort_cached = 1; + } + } + + if (pmkid && sm->cur_pmksa && + os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) { + + wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN); + wpa_sm_set_pmk_from_pmksa(sm); + wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache", + sm->pmk, sm->pmk_len); + //eapol_sm_notify_cached(sm->eapol); +#ifdef CONFIG_IEEE80211R + sm->xxkey_len = 0; +#endif /* CONFIG_IEEE80211R */ + } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) { + int res = 0, pmk_len; + pmk_len = PMK_LEN; + /* For ESP_SUPPLICANT this is already set using wpa_set_pmk*/ + //res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN); + + if(!sm->pmk_len) { + res = -1; + } + + if (res == 0) { + struct rsn_pmksa_cache_entry *sa = NULL; + wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " + "machines", sm->pmk, pmk_len); + sm->pmk_len = pmk_len; + //wpa_supplicant_key_mgmt_set_pmk(sm); + if (sm->proto == WPA_PROTO_RSN && + !wpa_key_mgmt_suite_b(sm->key_mgmt) && + !wpa_key_mgmt_ft(sm->key_mgmt)) { + sa = pmksa_cache_add(sm->pmksa, + sm->pmk, pmk_len, + NULL, 0, + src_addr, sm->own_addr, + sm->network_ctx, + sm->key_mgmt); + } + if (!sm->cur_pmksa && pmkid && + pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL)) + { + wpa_printf( MSG_DEBUG, + "RSN: the new PMK matches with the " + "PMKID"); + abort_cached = 0; + } else if (sa && !sm->cur_pmksa && pmkid) { + /* + * It looks like the authentication server + * derived mismatching MSK. This should not + * really happen, but bugs happen.. There is not + * much we can do here without knowing what + * exactly caused the server to misbehave. + */ + wpa_printf( MSG_INFO, + "RSN: PMKID mismatch - authentication server may have derived different MSK?!"); + return -1; + } + + if (!sm->cur_pmksa) + sm->cur_pmksa = sa; + } else { + wpa_printf( MSG_WARNING, + "WPA: Failed to get master session key from " + "EAPOL state machines - key handshake " + "aborted"); + if (sm->cur_pmksa) { + wpa_printf( MSG_DEBUG, + "RSN: Cancelled PMKSA caching " + "attempt"); + sm->cur_pmksa = NULL; + abort_cached = 1; + } else if (!abort_cached) { + return -1; + } + } + } + + if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && + !wpa_key_mgmt_suite_b(sm->key_mgmt) && + !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN) + { + /* Send EAPOL-Start to trigger full EAP authentication. */ + u8 *buf; + size_t buflen; + + wpa_printf( MSG_DEBUG, + "RSN: no PMKSA entry found - trigger " + "full EAP authentication"); + buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, + NULL, 0, &buflen, NULL); + if (buf) { + wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL, + buf, buflen); + os_free(buf); + return -2; + } + + return -1; + } + + return 0; +} + /** * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake @@ -342,9 +516,9 @@ void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, } } #endif /* CONFIG_NO_WPA2 */ - - res = wpa_supplicant_get_pmk(sm); - if (res == -2) { + res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid); + + if (res == -2) { #ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - " "requesting full EAP authentication"); @@ -1699,8 +1873,65 @@ void wpa_sm_set_state(enum wpa_states state) sm->wpa_state= state; } + +/** + * wpa_sm_set_pmk - Set PMK + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @pmk: The new PMK + * @pmk_len: The length of the new PMK in bytes + * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK + * + * Configure the PMK for WPA state machine. + */ +void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, + const u8 *bssid) +{ + if (sm == NULL) + return; + + sm->pmk_len = pmk_len; + os_memcpy(sm->pmk, pmk, pmk_len); + +#ifdef CONFIG_IEEE80211R + /* Set XXKey to be PSK for FT key derivation */ + sm->xxkey_len = pmk_len; + os_memcpy(sm->xxkey, pmk, pmk_len); +#endif /* CONFIG_IEEE80211R */ + + if (bssid) { + pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0, + bssid, sm->own_addr, + sm->network_ctx, sm->key_mgmt); + } +} + + +/** + * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * + * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK + * will be cleared. + */ +void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm) +{ + if (sm == NULL) + return; + + if (sm->cur_pmksa) { + sm->pmk_len = sm->cur_pmksa->pmk_len; + os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len); + } else { + sm->pmk_len = PMK_LEN; + os_memset(sm->pmk, 0, PMK_LEN); + } +} + + + + #ifdef ESP_SUPPLICANT -void wpa_register(char * payload, WPA_SEND_FUNC snd_func, +bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func, WPA_SET_ASSOC_IE set_assoc_ie_func, WPA_INSTALL_KEY ppinstallkey, WPA_GET_KEY ppgetkey, WPA_DEAUTH_FUNC wpa_deauth, WPA_NEG_COMPLETE wpa_neg_complete) { @@ -1716,8 +1947,26 @@ void wpa_register(char * payload, WPA_SEND_FUNC snd_func, sm->key_entry_valid = 0; sm->key_install = false; wpa_sm_set_state(WPA_INACTIVE); + + sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm); + if (sm->pmksa == NULL) { + wpa_printf(MSG_ERROR, + "RSN: PMKSA cache initialization failed"); + return false; + } + return true; } +/** + * * wpa_sm_deinit - Deinitialize WPA state machine + * */ +void wpa_sm_deinit(void) +{ + struct wpa_sm *sm = &gWpaSm; + pmksa_cache_deinit(sm->pmksa); +} + + void wpa_set_profile(u32 wpa_proto, u8 auth_mode) { struct wpa_sm *sm = &gWpaSm; @@ -1751,8 +2000,15 @@ wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, cha memcpy(sm->own_addr, macddr, ETH_ALEN); memcpy(sm->bssid, bssid, ETH_ALEN); sm->ap_notify_completed_rsne = esp_wifi_sta_is_ap_notify_completed_rsne_internal(); - + + if (esp_wifi_sta_prof_is_wpa2_internal() + && esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT) { + pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0); + wpa_sm_set_pmk_from_pmksa(sm); + } + set_assoc_ie(assoc_ie_buf); /* use static buffer */ + wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); //TODO: NEED TO DEBUG!! wpa_set_passphrase(passphrase, ssid, ssid_len); } @@ -1790,8 +2046,8 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) /* TODO nothing */ } else { memcpy(sm->pmk, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN); + sm->pmk_len = PMK_LEN; } - sm->pmk_len = PMK_LEN; } void @@ -1971,5 +2227,10 @@ bool wpa_sta_in_4way_handshake(void) return false; } + +bool wpa_sta_is_cur_pmksa_set(void) { + struct wpa_sm *sm = &gWpaSm; + return (pmksa_cache_get_current(sm) != NULL); +} #endif // ESP_SUPPLICANT diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index c3475eafee..aa81eb1e70 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -28,6 +28,7 @@ struct wpa_sm; int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); +bool wpa_sta_is_cur_pmksa_set(void); bool wpa_sta_in_4way_handshake(void); #define WPA_ASSERT assert diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index 3a09eff1d2..ab99145af3 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -41,11 +41,14 @@ struct wpa_sm { u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; int rx_replay_counter_set; u8 request_counter[WPA_REPLAY_COUNTER_LEN]; + struct rsn_pmksa_cache *pmksa; /* PMKSA cache */ + struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */ unsigned int pairwise_cipher; unsigned int group_cipher; unsigned int key_mgmt; unsigned int mgmt_group_cipher; + void *network_ctx; int rsn_enabled; /* Whether RSN is enabled in configuration */ @@ -147,12 +150,14 @@ typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code); typedef void (*WPA_NEG_COMPLETE)(); -void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ - WPA_SET_ASSOC_IE set_assoc_ie_func, \ - WPA_INSTALL_KEY ppinstallkey, \ - WPA_GET_KEY ppgetkey, \ - WPA_DEAUTH_FUNC wpa_deauth, \ - WPA_NEG_COMPLETE wpa_neg_complete); +bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func, \ + WPA_SET_ASSOC_IE set_assoc_ie_func, \ + WPA_INSTALL_KEY ppinstallkey, \ + WPA_GET_KEY ppgetkey, \ + WPA_DEAUTH_FUNC wpa_deauth, \ + WPA_NEG_COMPLETE wpa_neg_complete); + +void wpa_sm_deinit(void); void eapol_txcb(void *eb); diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index ce85191c7c..5559392cab 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -19,6 +19,7 @@ #include "rsn_supp/wpa.h" #include "common/ieee802_11_defs.h" #include "rsn_supp/wpa_ie.h" +#include "rsn_supp/pmksa_cache.h" /** * wpa_parse_wpa_ie - Parse WPA/RSN IE @@ -38,6 +39,246 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); } + +static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, + int pairwise_cipher, int group_cipher, + int key_mgmt) +{ + u8 *pos; + struct wpa_ie_hdr *hdr; + + if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + + 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) + return -1; + + hdr = (struct wpa_ie_hdr *) wpa_ie; + hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; + RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); + WPA_PUT_LE16(hdr->version, WPA_VERSION); + pos = (u8 *) (hdr + 1); + + if (group_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); + } else if (group_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); + } else if (group_cipher == WPA_CIPHER_WEP104) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); + } else if (group_cipher == WPA_CIPHER_WEP40) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); + } else { + wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", + group_cipher); + return -1; + } + pos += WPA_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (pairwise_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); + } else if (pairwise_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); + } else if (pairwise_cipher == WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", + pairwise_cipher); + return -1; + } + pos += WPA_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", + key_mgmt); + return -1; + } + pos += WPA_SELECTOR_LEN; + + /* WPA Capabilities; use defaults, so no need to include it */ + + hdr->len = (pos - wpa_ie) - 2; + + WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); + + return pos - wpa_ie; +} + + +static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, + int pairwise_cipher, int group_cipher, + int key_mgmt, int mgmt_group_cipher, + struct wpa_sm *sm) +{ +#ifndef CONFIG_NO_WPA2 + u8 *pos; + struct rsn_ie_hdr *hdr; + u16 capab; + u8 min_len = 0; + + if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + + (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { + wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", + (unsigned long) rsn_ie_len); + return -1; + } + + /* For WPA2-PSK, if the RSNE in AP beacon/probe response doesn't specify the + * pairwise cipher or AKM suite, the RSNE IE in association request + * should only contain group cihpher suite, otherwise the WPA2 improvements + * certification will fail. + */ + if ( (sm->ap_notify_completed_rsne == true) || (key_mgmt == WPA_KEY_MGMT_IEEE8021X) ) { + min_len = sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2; + } else { + min_len = sizeof(*hdr) + RSN_SELECTOR_LEN; + } + + if (rsn_ie_len < min_len) { + wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len); + } + + hdr = (struct rsn_ie_hdr *) rsn_ie; + hdr->elem_id = WLAN_EID_RSN; + WPA_PUT_LE16(hdr->version, RSN_VERSION); + pos = (u8 *) (hdr + 1); + + if (group_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + } else if (group_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); + } else if (group_cipher == WPA_CIPHER_WEP104) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); + } else if (group_cipher == WPA_CIPHER_WEP40) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); + } else { + wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", + group_cipher); + return -1; + } + pos += RSN_SELECTOR_LEN; + + if ( (sm->ap_notify_completed_rsne == false) && (key_mgmt != WPA_KEY_MGMT_IEEE8021X) ) { + hdr->len = (pos - rsn_ie) - 2; + return (pos - rsn_ie); + } + + *pos++ = 1; + *pos++ = 0; + if (pairwise_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + } else if (pairwise_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); + } else if (pairwise_cipher == WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", + pairwise_cipher); + return -1; + } + pos += RSN_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); +#ifdef CONFIG_IEEE80211R + } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); + } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); +#endif /* CONFIG_IEEE80211W */ + } else { + wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", + key_mgmt); + return -1; + } + pos += RSN_SELECTOR_LEN; + + /* RSN Capabilities */ + capab = 0; +#ifdef CONFIG_IEEE80211W + if (sm->mfp) + capab |= WPA_CAPABILITY_MFPC; + if (sm->mfp == 2) + capab |= WPA_CAPABILITY_MFPR; +#endif /* CONFIG_IEEE80211W */ + WPA_PUT_LE16(pos, capab); + pos += 2; + + if (sm->cur_pmksa) { + /* PMKID Count (2 octets, little endian) */ + *pos++ = 1; + *pos++ = 0; + /* PMKID */ + os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); + pos += PMKID_LEN; + } + +#ifdef CONFIG_IEEE80211W + if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { + if (!sm->cur_pmksa) { + /* PMKID Count */ + WPA_PUT_LE16(pos, 0); + pos += 2; + } + + /* Management Group Cipher Suite */ + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + pos += RSN_SELECTOR_LEN; + } +#endif /* CONFIG_IEEE80211W */ + + hdr->len = (pos - rsn_ie) - 2; + + WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); + + return pos - rsn_ie; +#else /* CONFIG_NO_WPA2 */ + return -1; +#endif /* CONFIG_NO_WPA2 */ +} + + +/** + * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE + * @wpa_ie_len: Maximum length of the generated WPA/RSN IE + * Returns: Length of the generated WPA/RSN IE or -1 on failure + */ +int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) +{ + if (sm->proto == WPA_PROTO_RSN) + return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, + sm->pairwise_cipher, + sm->group_cipher, + sm->key_mgmt, sm->mgmt_group_cipher, + sm); + else + return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, + sm->pairwise_cipher, + sm->group_cipher, + sm->key_mgmt); +} + + /** * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header @@ -146,226 +387,5 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, } -static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, - int pairwise_cipher, int group_cipher, - int key_mgmt) -{ - u8 *pos; - struct wpa_ie_hdr *hdr; - - if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + - 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) - return -1; - - hdr = (struct wpa_ie_hdr *) wpa_ie; - hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; - RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); - WPA_PUT_LE16(hdr->version, WPA_VERSION); - pos = (u8 *) (hdr + 1); - - if (group_cipher == WPA_CIPHER_CCMP) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); - } else if (group_cipher == WPA_CIPHER_TKIP) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); - } else if (group_cipher == WPA_CIPHER_WEP104) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); - } else if (group_cipher == WPA_CIPHER_WEP40) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); - } else { - wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", - group_cipher); - return -1; - } - pos += WPA_SELECTOR_LEN; - - *pos++ = 1; - *pos++ = 0; - if (pairwise_cipher == WPA_CIPHER_CCMP) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); - } else if (pairwise_cipher == WPA_CIPHER_TKIP) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); - } else if (pairwise_cipher == WPA_CIPHER_NONE) { - RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); - } else { - wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", - pairwise_cipher); - return -1; - } - pos += WPA_SELECTOR_LEN; - - *pos++ = 1; - *pos++ = 0; - if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_PSK) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { - RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); - } else { - wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", - key_mgmt); - return -1; - } - pos += WPA_SELECTOR_LEN; - - /* WPA Capabilities; use defaults, so no need to include it */ - - hdr->len = (pos - wpa_ie) - 2; - - WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); - - return pos - wpa_ie; -} - - -static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, - int pairwise_cipher, int group_cipher, - int key_mgmt, int mgmt_group_cipher, - struct wpa_sm *sm) -{ -#ifndef CONFIG_NO_WPA2 - u8 *pos; - struct rsn_ie_hdr *hdr; - u16 capab; - u8 min_len = 0; - - - /* For WPA2-PSK, if the RSNE in AP beacon/probe response doesn't specify the - * pairwise cipher or AKM suite, the RSNE IE in association request - * should only contain group cihpher suite, otherwise the WPA2 improvements - * certification will fail. - */ - if ( (sm->ap_notify_completed_rsne == true) || (key_mgmt == WPA_KEY_MGMT_IEEE8021X) ) { - min_len = sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2; - } else { - min_len = sizeof(*hdr) + RSN_SELECTOR_LEN; - } - - if (rsn_ie_len < min_len) { - wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len); - } - - hdr = (struct rsn_ie_hdr *) rsn_ie; - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, RSN_VERSION); - pos = (u8 *) (hdr + 1); - - if (group_cipher == WPA_CIPHER_CCMP) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - } else if (group_cipher == WPA_CIPHER_TKIP) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); - } else if (group_cipher == WPA_CIPHER_WEP104) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); - } else if (group_cipher == WPA_CIPHER_WEP40) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); - } else { - wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", - group_cipher); - return -1; - } - pos += RSN_SELECTOR_LEN; - - if ( (sm->ap_notify_completed_rsne == false) && (key_mgmt != WPA_KEY_MGMT_IEEE8021X) ) { - hdr->len = (pos - rsn_ie) - 2; - return (pos - rsn_ie); - } - - *pos++ = 1; - *pos++ = 0; - if (pairwise_cipher == WPA_CIPHER_CCMP) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - } else if (pairwise_cipher == WPA_CIPHER_TKIP) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); - } else if (pairwise_cipher == WPA_CIPHER_NONE) { - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); - } else { - wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", - pairwise_cipher); - return -1; - } - pos += RSN_SELECTOR_LEN; - - *pos++ = 1; - *pos++ = 0; - if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_PSK) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); -#ifdef CONFIG_IEEE80211R - } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); - } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); - } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); -#endif /* CONFIG_IEEE80211W */ - } else { - wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", - key_mgmt); - return -1; - } - pos += RSN_SELECTOR_LEN; - - /* RSN Capabilities */ - capab = 0; -#ifdef CONFIG_IEEE80211W - if (sm->mfp) - capab |= WPA_CAPABILITY_MFPC; - if (sm->mfp == 2) - capab |= WPA_CAPABILITY_MFPR; -#endif /* CONFIG_IEEE80211W */ - WPA_PUT_LE16(pos, capab); - pos += 2; - -#ifdef CONFIG_IEEE80211W - if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { - if (!sm->cur_pmksa) { - /* PMKID Count */ - WPA_PUT_LE16(pos, 0); - pos += 2; - } - - /* Management Group Cipher Suite */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); - pos += RSN_SELECTOR_LEN; - } -#endif /* CONFIG_IEEE80211W */ - - hdr->len = (pos - rsn_ie) - 2; - - WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); - - return pos - rsn_ie; -#else /* CONFIG_NO_WPA2 */ - return -1; -#endif /* CONFIG_NO_WPA2 */ -} - - -/** - * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE - * @wpa_ie_len: Maximum length of the generated WPA/RSN IE - * Returns: Length of the generated WPA/RSN IE or -1 on failure - */ -int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) -{ - if (sm->proto == WPA_PROTO_RSN) - return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, - sm->pairwise_cipher, - sm->group_cipher, - sm->key_mgmt, sm->mgmt_group_cipher, - sm); - else - return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, - sm->pairwise_cipher, - sm->group_cipher, - sm->key_mgmt); -} #endif // ESP_SUPPLICANT diff --git a/components/wpa_supplicant/src/utils/common.c b/components/wpa_supplicant/src/utils/common.c index 7e5ef1be01..5b2f9d7758 100644 --- a/components/wpa_supplicant/src/utils/common.c +++ b/components/wpa_supplicant/src/utils/common.c @@ -2,14 +2,8 @@ * wpa_supplicant/hostapd / common helper functions, etc. * Copyright (c) 2002-2007, Jouni Malinen * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -99,68 +93,263 @@ void wpa_get_ntp_timestamp(u8 *buf) usec = now.usec; usec = 4295 * usec - (usec >> 5) - (usec >> 9); tmp = host_to_be32(sec); - memcpy(buf, (u8 *) &tmp, 4); + os_memcpy(buf, (u8 *) &tmp, 4); tmp = host_to_be32(usec); - memcpy(buf + 4, (u8 *) &tmp, 4); + os_memcpy(buf + 4, (u8 *) &tmp, 4); } +void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) +{ + char *end = txt + maxlen; + size_t i; + + for (i = 0; i < len; i++) { + if (txt + 4 >= end) + break; + + switch (data[i]) { + case '\"': + *txt++ = '\\'; + *txt++ = '\"'; + break; + case '\\': + *txt++ = '\\'; + *txt++ = '\\'; + break; + case '\033': + *txt++ = '\\'; + *txt++ = 'e'; + break; + case '\n': + *txt++ = '\\'; + *txt++ = 'n'; + break; + case '\r': + *txt++ = '\\'; + *txt++ = 'r'; + break; + case '\t': + *txt++ = '\\'; + *txt++ = 't'; + break; + default: + if (data[i] >= 32 && data[i] <= 127) { + *txt++ = data[i]; + } else { + txt += os_snprintf(txt, end - txt, "\\x%02x", + data[i]); + } + break; + } + } + + *txt = '\0'; +} + + +size_t printf_decode(u8 *buf, size_t maxlen, const char *str) +{ + const char *pos = str; + size_t len = 0; + int val; + + while (*pos) { + if (len + 1 >= maxlen) + break; + switch (*pos) { + case '\\': + pos++; + switch (*pos) { + case '\\': + buf[len++] = '\\'; + pos++; + break; + case '"': + buf[len++] = '"'; + pos++; + break; + case 'n': + buf[len++] = '\n'; + pos++; + break; + case 'r': + buf[len++] = '\r'; + pos++; + break; + case 't': + buf[len++] = '\t'; + pos++; + break; + case 'e': + buf[len++] = '\033'; + pos++; + break; + case 'x': + pos++; + val = hex2byte(pos); + if (val < 0) { + val = hex2num(*pos); + if (val < 0) + break; + buf[len++] = val; + pos++; + } else { + buf[len++] = val; + pos += 2; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + val = *pos++ - '0'; + if (*pos >= '0' && *pos <= '7') + val = val * 8 + (*pos++ - '0'); + if (*pos >= '0' && *pos <= '7') + val = val * 8 + (*pos++ - '0'); + buf[len++] = val; + break; + default: + break; + } + break; + default: + buf[len++] = *pos++; + break; + } + } + if (maxlen > len) + buf[len] = '\0'; + + return len; +} + + char * wpa_config_parse_string(const char *value, size_t *len) { - if (*value == '"' && (strlen(value) == 7 || strlen(value) == 15)) { + if (*value == '"') { const char *pos; char *str; value++; - pos = (char *)strrchr(value, '"'); - if (pos == NULL) + pos = os_strrchr(value, '"'); + if (pos == NULL || pos[1] != '\0') return NULL; *len = pos - value; - str = (char *)os_malloc(*len + 1); + str = dup_binstr(value, *len); if (str == NULL) return NULL; - memcpy(str, value, *len); - str[*len] = '\0'; + return str; + } else if (*value == 'P' && value[1] == '"') { + const char *pos; + char *tstr, *str; + size_t tlen; + value += 2; + pos = os_strrchr(value, '"'); + if (pos == NULL || pos[1] != '\0') + return NULL; + tlen = pos - value; + tstr = dup_binstr(value, tlen); + if (tstr == NULL) + return NULL; + + str = os_malloc(tlen + 1); + if (str == NULL) { + os_free(tstr); + return NULL; + } + + *len = printf_decode((u8 *) str, tlen + 1, tstr); + os_free(tstr); + return str; } else { u8 *str; - size_t tlen, hlen = strlen(value); - if (hlen == 5 || hlen == 13) { - *len = hlen; - str = (u8 *)os_malloc(*len + 1); - if (str == NULL) { - return NULL; - } - memcpy(str, value, *len); - str[*len] = '\0'; - } else if (hlen == 10 || hlen == 26) { - tlen = hlen / 2; - str = (u8 *)os_malloc(tlen + 1); - if (str == NULL) - return NULL; - if (hexstr2bin(value, str, tlen)) { - os_free(str); - return NULL; - } - str[tlen] = '\0'; - *len = tlen; - } else { + size_t tlen, hlen = os_strlen(value); + if (hlen & 1) + return NULL; + tlen = hlen / 2; + str = os_malloc(tlen + 1); + if (str == NULL) + return NULL; + if (hexstr2bin(value, str, tlen)) { + os_free(str); return NULL; } + str[tlen] = '\0'; + *len = tlen; return (char *) str; } } -char * dup_binstr(const void *src, size_t len) + +int is_hex(const u8 *data, size_t len) { - char *res; + size_t i; - if (src == NULL) - return NULL; - res = os_malloc(len + 1); - if (res == NULL) - return NULL; - memcpy(res, src, len); - res[len] = '\0'; - - return res; + for (i = 0; i < len; i++) { + if (data[i] < 32 || data[i] >= 127) + return 1; + } + return 0; } + +size_t merge_byte_arrays(u8 *res, size_t res_len, + const u8 *src1, size_t src1_len, + const u8 *src2, size_t src2_len) +{ + size_t len = 0; + + os_memset(res, 0, res_len); + + if (src1) { + if (src1_len >= res_len) { + os_memcpy(res, src1, res_len); + return res_len; + } + + os_memcpy(res, src1, src1_len); + len += src1_len; + } + + if (src2) { + if (len + src2_len >= res_len) { + os_memcpy(res + len, src2, res_len - len); + return res_len; + } + + os_memcpy(res + len, src2, src2_len); + len += src2_len; + } + + return len; +} + + +char * dup_binstr(const void *src, size_t len) +{ + char *res; + + if (src == NULL) + return NULL; + res = os_malloc(len + 1); + if (res == NULL) + return NULL; + os_memcpy(res, src, len); + res[len] = '\0'; + + return res; +} +void bin_clear_free(void *bin, size_t len) +{ + if (bin) { + os_memset(bin, 0, len); + os_free(bin); + } +} + + From 39acf9c4ddcf2b6d61ef45419fff60fd4dcb855d Mon Sep 17 00:00:00 2001 From: Hrudaynath Dhabe Date: Tue, 15 Oct 2019 13:56:07 +0530 Subject: [PATCH 02/16] wifi: Add PMK caching feature for station WPA2-enterprise 4. Pmksa cache expiry after dot11RSNAConfigPMKLifetime timeout. --- .../src/esp_supplicant/esp_wpa2.c | 13 +- .../src/esp_supplicant/esp_wpa_main.c | 6 - .../wpa_supplicant/src/rsn_supp/pmksa_cache.c | 626 +++++++++--------- .../wpa_supplicant/src/rsn_supp/pmksa_cache.h | 106 +-- components/wpa_supplicant/src/rsn_supp/wpa.c | 2 + components/wpa_supplicant/src/utils/common.c | 6 +- .../{include => src}/utils/common.h | 31 +- 7 files changed, 373 insertions(+), 417 deletions(-) rename components/wpa_supplicant/{include => src}/utils/common.h (91%) diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c index 672955ef9b..6f8bd00aee 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c @@ -666,16 +666,9 @@ static int wpa2_start_eapol_internal(void) return ESP_FAIL; } if (wpa_sta_is_cur_pmksa_set()) { - if (0) { - wpa_printf(MSG_DEBUG, - "RSN: Timeout on waiting for the AP to initiate 4-way handshake \ - for PMKSA caching or EAP authentication \ - - try to force it to start EAP authentication"); - } else { - wpa_printf(MSG_DEBUG, - "RSN: PMKSA caching - do not send EAPOL-Start"); - return -1; - } + wpa_printf(MSG_DEBUG, + "RSN: PMKSA caching - do not send EAPOL-Start"); + return ESP_FAIL; } ret = esp_wifi_get_assoc_bssid_internal(bssid); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index 74048a28a6..c576982213 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -109,14 +109,8 @@ void wpa_neg_complete() bool wpa_attach(void) { bool ret = true; -#ifndef IOT_SIP_MODE ret = wpa_sm_init(NULL, wpa_sendto_wrapper, wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); -#else - u8 *payload = (u8 *)os_malloc(WPA_TX_MSG_BUFF_MAXLEN); - ret = wpa_sm_init(payload, wpa_sendto_wrapper, - wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); -#endif if(ret) { ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK); } diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c index 6e09d07c19..a23233f2a7 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c @@ -13,92 +13,75 @@ #include "common/eapol_common.h" #include "common/ieee802_11_defs.h" #include "pmksa_cache.h" +#include "esp_timer.h" #ifdef IEEE8021X_EAPOL static const int pmksa_cache_max_entries = 10; +static const int dot11RSNAConfigPMKLifetime = 43200; +static const int dot11RSNAConfigPMKReauthThreshold = 70; struct rsn_pmksa_cache { - struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ - int pmksa_count; /* number of entries in PMKSA cache */ - struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ + struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ + int pmksa_count; /* number of entries in PMKSA cache */ + struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ + esp_timer_handle_t cache_timeout_timer; - void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, - enum pmksa_free_reason reason); - void *ctx; + void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, + enum pmksa_free_reason reason); + void *ctx; }; -//static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); +static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) { - bin_clear_free(entry, sizeof(*entry)); + wpa_bin_clear_free(entry, sizeof(*entry)); } static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, - struct rsn_pmksa_cache_entry *entry, - enum pmksa_free_reason reason) + struct rsn_pmksa_cache_entry *entry, + enum pmksa_free_reason reason) { - //wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid); - pmksa->pmksa_count--; - pmksa->free_cb(entry, pmksa->ctx, reason); - _pmksa_cache_free_entry(entry); + pmksa->pmksa_count--; + pmksa->free_cb(entry, pmksa->ctx, reason); + _pmksa_cache_free_entry(entry); } -#if 0 -static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) + +static void pmksa_cache_expire(void *eloop_ctx) { - struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_reltime now; + struct rsn_pmksa_cache *pmksa = eloop_ctx; + int64_t now_sec = esp_timer_get_time() / 1e6; - os_get_reltime(&now); - while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { - struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; - pmksa->pmksa = entry->next; - wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " - MACSTR, MAC2STR(entry->aa)); - pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE); - } + while (pmksa->pmksa && pmksa->pmksa->expiration <= now_sec) { + struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; + pmksa->pmksa = entry->next; + wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " + MACSTR, MAC2STR(entry->aa)); + pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE); + } - pmksa_cache_set_expiration(pmksa); -} - -static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) -{ - struct rsn_pmksa_cache *pmksa = eloop_ctx; - pmksa->sm->cur_pmksa = NULL; - eapol_sm_request_reauth(pmksa->sm->eapol); + pmksa_cache_set_expiration(pmksa); } static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) { - int sec; - struct rsn_pmksa_cache_entry *entry; - struct os_reltime now; + int sec; + int64_t now_sec = esp_timer_get_time() / 1e6; - eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); - if (pmksa->pmksa == NULL) - return; - os_get_reltime(&now); - sec = pmksa->pmksa->expiration - now.sec; - if (sec < 0) - sec = 0; - eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); + esp_timer_stop(pmksa->cache_timeout_timer); + if (pmksa->pmksa == NULL) + return; + sec = pmksa->pmksa->expiration - now_sec; + if (sec < 0) + sec = 0; - entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : - pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL); - if (entry) { - sec = pmksa->pmksa->reauth_time - now.sec; - if (sec < 0) - sec = 0; - eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, - NULL); - } + esp_timer_start_once(pmksa->cache_timeout_timer, (sec + 1) * 1e6); } -#endif /** * pmksa_cache_add - Add a PMKSA cache entry @@ -120,122 +103,120 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) */ struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, - const u8 *aa, const u8 *spa, void *network_ctx, int akmp) + const u8 *kck, size_t kck_len, + const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { - struct rsn_pmksa_cache_entry *entry, *pos, *prev; - //struct os_reltime now; + struct rsn_pmksa_cache_entry *entry, *pos, *prev; + int64_t now_sec = esp_timer_get_time() / 1e6; - if (pmk_len > PMK_LEN) - return NULL; + if (pmk_len > PMK_LEN) + return NULL; - if (wpa_key_mgmt_suite_b(akmp) && !kck) - return NULL; + if (wpa_key_mgmt_suite_b(akmp) && !kck) + return NULL; - entry = os_zalloc(sizeof(*entry)); - if (entry == NULL) - return NULL; - os_memcpy(entry->pmk, pmk, pmk_len); - entry->pmk_len = pmk_len; + entry = os_zalloc(sizeof(*entry)); + if (entry == NULL) + return NULL; + os_memcpy(entry->pmk, pmk, pmk_len); + entry->pmk_len = pmk_len; rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, - wpa_key_mgmt_sha256(akmp)); - //os_get_reltime(&now); - //entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; - /*entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * - pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;*/ - entry->akmp = akmp; - os_memcpy(entry->aa, aa, ETH_ALEN); - entry->network_ctx = network_ctx; + wpa_key_mgmt_sha256(akmp)); + entry->expiration = now_sec + dot11RSNAConfigPMKLifetime; + entry->reauth_time = now_sec + dot11RSNAConfigPMKLifetime * + dot11RSNAConfigPMKReauthThreshold / 100; + entry->akmp = akmp; + os_memcpy(entry->aa, aa, ETH_ALEN); + entry->network_ctx = network_ctx; - /* Replace an old entry for the same Authenticator (if found) with the - * new entry */ - pos = pmksa->pmksa; - prev = NULL; - while (pos) { - if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { - if (pos->pmk_len == pmk_len && - os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 && - os_memcmp_const(pos->pmkid, entry->pmkid, - PMKID_LEN) == 0) { - wpa_printf(MSG_DEBUG, "WPA: reusing previous " - "PMKSA entry"); - os_free(entry); - return pos; - } - if (prev == NULL) - pmksa->pmksa = pos->next; - else - prev->next = pos->next; + /* Replace an old entry for the same Authenticator (if found) with the + * new entry */ + pos = pmksa->pmksa; + prev = NULL; + while (pos) { + if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { + if (pos->pmk_len == pmk_len && + os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 && + os_memcmp_const(pos->pmkid, entry->pmkid, + PMKID_LEN) == 0) { + wpa_printf(MSG_DEBUG, "WPA: reusing previous " + "PMKSA entry"); + os_free(entry); + return pos; + } + if (prev == NULL) + pmksa->pmksa = pos->next; + else + prev->next = pos->next; - /* - * If OKC is used, there may be other PMKSA cache - * entries based on the same PMK. These needs to be - * flushed so that a new entry can be created based on - * the new PMK. Only clear other entries if they have a - * matching PMK and this PMK has been used successfully - * with the current AP, i.e., if opportunistic flag has - * been cleared in wpa_supplicant_key_neg_complete(). - */ - wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " - "the current AP and any PMKSA cache entry " - "that was based on the old PMK"); - if (!pos->opportunistic) - pmksa_cache_flush(pmksa, network_ctx, pos->pmk, - pos->pmk_len); - pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); - break; - } - prev = pos; - pos = pos->next; - } + /* + * If OKC is used, there may be other PMKSA cache + * entries based on the same PMK. These needs to be + * flushed so that a new entry can be created based on + * the new PMK. Only clear other entries if they have a + * matching PMK and this PMK has been used successfully + * with the current AP, i.e., if opportunistic flag has + * been cleared in wpa_supplicant_key_neg_complete(). + */ + wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " + "the current AP and any PMKSA cache entry " + "that was based on the old PMK"); + if (!pos->opportunistic) + pmksa_cache_flush(pmksa, network_ctx, pos->pmk, + pos->pmk_len); + pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); + break; + } + prev = pos; + pos = pos->next; + } - if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { - /* Remove the oldest entry to make room for the new entry */ - pos = pmksa->pmksa; + if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { + /* Remove the oldest entry to make room for the new entry */ + pos = pmksa->pmksa; - if (pos == pmksa->sm->cur_pmksa) { - /* - * Never remove the current PMKSA cache entry, since - * it's in use, and removing it triggers a needless - * deauthentication. - */ - pos = pos->next; - pmksa->pmksa->next = pos ? pos->next : NULL; - } else - pmksa->pmksa = pos->next; + if (pos == pmksa->sm->cur_pmksa) { + /* + * Never remove the current PMKSA cache entry, since + * it's in use, and removing it triggers a needless + * deauthentication. + */ + pos = pos->next; + pmksa->pmksa->next = pos ? pos->next : NULL; + } else + pmksa->pmksa = pos->next; - if (pos) { - wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle " - "PMKSA cache entry (for " MACSTR ") to " - "make room for new one", - MAC2STR(pos->aa)); - pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE); - } - } + if (pos) { + wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle " + "PMKSA cache entry (for " MACSTR ") to " + "make room for new one", + MAC2STR(pos->aa)); + pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE); + } + } - /* Add the new entry; order by expiration time */ - pos = pmksa->pmksa; - prev = NULL; - while (pos) { - if (pos->expiration > entry->expiration) - break; - prev = pos; - pos = pos->next; - } - if (prev == NULL) { - entry->next = pmksa->pmksa; - pmksa->pmksa = entry; - //pmksa_cache_set_expiration(pmksa); - } else { - entry->next = prev->next; - prev->next = entry; - } - pmksa->pmksa_count++; - wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR - " network_ctx=%p", MAC2STR(entry->aa), network_ctx); - //wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid); + /* Add the new entry; order by expiration time */ + pos = pmksa->pmksa; + prev = NULL; + while (pos) { + if (pos->expiration > entry->expiration) + break; + prev = pos; + pos = pos->next; + } + if (prev == NULL) { + entry->next = pmksa->pmksa; + pmksa->pmksa = entry; + pmksa_cache_set_expiration(pmksa); + } else { + entry->next = prev->next; + prev->next = entry; + } + pmksa->pmksa_count++; + wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR + " network_ctx=%p", MAC2STR(entry->aa), network_ctx); - return entry; + return entry; } @@ -247,35 +228,35 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, * @pmk_len: PMK length */ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *pmk, size_t pmk_len) + const u8 *pmk, size_t pmk_len) { - struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; - int removed = 0; + struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; + int removed = 0; - entry = pmksa->pmksa; - while (entry) { - if ((entry->network_ctx == network_ctx || - network_ctx == NULL) && - (pmk == NULL || - (pmk_len == entry->pmk_len && - os_memcmp(pmk, entry->pmk, pmk_len) == 0))) { - wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " - "for " MACSTR, MAC2STR(entry->aa)); - if (prev) - prev->next = entry->next; - else - pmksa->pmksa = entry->next; - tmp = entry; - entry = entry->next; - pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE); - removed++; - } else { - prev = entry; - entry = entry->next; - } - } - /*if (removed) - pmksa_cache_set_expiration(pmksa);*/ + entry = pmksa->pmksa; + while (entry) { + if ((entry->network_ctx == network_ctx || + network_ctx == NULL) && + (pmk == NULL || + (pmk_len == entry->pmk_len && + os_memcmp(pmk, entry->pmk, pmk_len) == 0))) { + wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " + "for " MACSTR, MAC2STR(entry->aa)); + if (prev) + prev->next = entry->next; + else + pmksa->pmksa = entry->next; + tmp = entry; + entry = entry->next; + pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE); + removed++; + } else { + prev = entry; + entry = entry->next; + } + } + /*if (removed) + pmksa_cache_set_expiration(pmksa);*/ } @@ -285,20 +266,21 @@ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, */ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) { - struct rsn_pmksa_cache_entry *entry, *prev; + struct rsn_pmksa_cache_entry *entry, *prev; - if (pmksa == NULL) - return; + if (pmksa == NULL) + return; - entry = pmksa->pmksa; - pmksa->pmksa = NULL; - while (entry) { - prev = entry; - entry = entry->next; - os_free(prev); - } - //pmksa_cache_set_expiration(pmksa); - os_free(pmksa); + entry = pmksa->pmksa; + pmksa->pmksa = NULL; + while (entry) { + prev = entry; + entry = entry->next; + os_free(prev); + } + pmksa_cache_set_expiration(pmksa); + os_free(pmksa); + esp_timer_stop(pmksa->cache_timeout_timer); } @@ -311,41 +293,41 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) * Returns: Pointer to PMKSA cache entry or %NULL if no match was found */ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, - const void *network_ctx) + const u8 *aa, const u8 *pmkid, + const void *network_ctx) { - struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; - while (entry) { - if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && - (pmkid == NULL || - os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && - (network_ctx == NULL || network_ctx == entry->network_ctx)) - return entry; - entry = entry->next; - } - return NULL; + struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; + while (entry) { + if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && + (pmkid == NULL || + os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && + (network_ctx == NULL || network_ctx == entry->network_ctx)) + return entry; + entry = entry->next; + } + return NULL; } static struct rsn_pmksa_cache_entry * pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, - const struct rsn_pmksa_cache_entry *old_entry, - const u8 *aa) + const struct rsn_pmksa_cache_entry *old_entry, + const u8 *aa) { - struct rsn_pmksa_cache_entry *new_entry; + struct rsn_pmksa_cache_entry *new_entry; - new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, - NULL, 0, - aa, pmksa->sm->own_addr, - old_entry->network_ctx, old_entry->akmp); - if (new_entry == NULL) - return NULL; + new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, + NULL, 0, + aa, pmksa->sm->own_addr, + old_entry->network_ctx, old_entry->akmp); + if (new_entry == NULL) + return NULL; - /* TODO: reorder entries based on expiration time? */ - new_entry->expiration = old_entry->expiration; - new_entry->opportunistic = 1; + /* TODO: reorder entries based on expiration time? */ + new_entry->expiration = old_entry->expiration; + new_entry->opportunistic = 1; - return new_entry; + return new_entry; } @@ -362,26 +344,26 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, */ struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *aa) + const u8 *aa) { - struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; + struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; - wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa)); - if (network_ctx == NULL) - return NULL; - while (entry) { - if (entry->network_ctx == network_ctx) { - entry = pmksa_cache_clone_entry(pmksa, entry, aa); - if (entry) { - wpa_printf(MSG_DEBUG, "RSN: added " - "opportunistic PMKSA cache entry " - "for " MACSTR, MAC2STR(aa)); - } - return entry; - } - entry = entry->next; - } - return NULL; + wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa)); + if (network_ctx == NULL) + return NULL; + while (entry) { + if (entry->network_ctx == network_ctx) { + entry = pmksa_cache_clone_entry(pmksa, entry, aa); + if (entry) { + wpa_printf(MSG_DEBUG, "RSN: added " + "opportunistic PMKSA cache entry " + "for " MACSTR, MAC2STR(aa)); + } + return entry; + } + entry = entry->next; + } + return NULL; } @@ -392,9 +374,9 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, */ struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) { - if (sm == NULL) - return NULL; - return sm->cur_pmksa; + if (sm == NULL) + return NULL; + return sm->cur_pmksa; } @@ -404,9 +386,9 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) */ void pmksa_cache_clear_current(struct wpa_sm *sm) { - if (sm == NULL) - return; - sm->cur_pmksa = NULL; + if (sm == NULL) + return; + sm->cur_pmksa = NULL; } @@ -420,37 +402,37 @@ void pmksa_cache_clear_current(struct wpa_sm *sm) * Returns: 0 if PMKSA was found or -1 if no matching entry was found */ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, - const u8 *bssid, void *network_ctx, - int try_opportunistic) + const u8 *bssid, void *network_ctx, + int try_opportunistic) { - struct rsn_pmksa_cache *pmksa = sm->pmksa; - wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " - "try_opportunistic=%d", network_ctx, try_opportunistic); - if (pmkid) - wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", - pmkid, PMKID_LEN); - if (bssid) - wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR, - MAC2STR(bssid)); + struct rsn_pmksa_cache *pmksa = sm->pmksa; + wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " + "try_opportunistic=%d", network_ctx, try_opportunistic); + if (pmkid) + wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", + pmkid, PMKID_LEN); + if (bssid) + wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR, + MAC2STR(bssid)); - sm->cur_pmksa = NULL; - if (pmkid) - sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, - network_ctx); - if (sm->cur_pmksa == NULL && bssid) - sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, - network_ctx); - if (sm->cur_pmksa == NULL && try_opportunistic && bssid) - sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, - network_ctx, - bssid); - if (sm->cur_pmksa) { - wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", - sm->cur_pmksa->pmkid, PMKID_LEN); - return 0; - } - wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found"); - return -1; + sm->cur_pmksa = NULL; + if (pmkid) + sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, + network_ctx); + if (sm->cur_pmksa == NULL && bssid) + sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, + network_ctx); + if (sm->cur_pmksa == NULL && try_opportunistic && bssid) + sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, + network_ctx, + bssid); + if (sm->cur_pmksa) { + wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", + sm->cur_pmksa->pmkid, PMKID_LEN); + return 0; + } + wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found"); + return -1; } @@ -466,38 +448,36 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, */ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) { - int i, ret; - char *pos = buf; - struct rsn_pmksa_cache_entry *entry; - //struct os_reltime now; - - //os_get_reltime(&now); - ret = os_snprintf(pos, buf + len - pos, - "Index / AA / PMKID / expiration (in seconds) / " - "opportunistic\n"); - if (os_snprintf_error(buf + len - pos, ret)) - return pos - buf; - pos += ret; - i = 0; - entry = pmksa->pmksa; - while (entry) { - i++; - ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", - i, MAC2STR(entry->aa)); - if (os_snprintf_error(buf + len - pos, ret)) - return pos - buf; - pos += ret; - pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, - PMKID_LEN); - ret = os_snprintf(pos, buf + len - pos, " %d %d\n", - (int) (entry->expiration),// - now.sec), - entry->opportunistic); - if (os_snprintf_error(buf + len - pos, ret)) - return pos - buf; - pos += ret; - entry = entry->next; - } - return pos - buf; + int i, ret; + char *pos = buf; + struct rsn_pmksa_cache_entry *entry; + int64_t now_sec = esp_timer_get_time() / 1e6; + ret = os_snprintf(pos, buf + len - pos, + "Index / AA / PMKID / expiration (in seconds) / " + "opportunistic\n"); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; + i = 0; + entry = pmksa->pmksa; + while (entry) { + i++; + ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", + i, MAC2STR(entry->aa)); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; + pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, + PMKID_LEN); + ret = os_snprintf(pos, buf + len - pos, " %d %d\n", + (int) (entry->expiration - now_sec), + entry->opportunistic); + if (os_snprintf_error(buf + len - pos, ret)) + return pos - buf; + pos += ret; + entry = entry->next; + } + return pos - buf; } @@ -510,19 +490,29 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) */ struct rsn_pmksa_cache * pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason), - void *ctx, struct wpa_sm *sm) + void *ctx, enum pmksa_free_reason reason), + void *ctx, struct wpa_sm *sm) { - struct rsn_pmksa_cache *pmksa; + struct rsn_pmksa_cache *pmksa; - pmksa = os_zalloc(sizeof(*pmksa)); - if (pmksa) { - pmksa->free_cb = free_cb; - pmksa->ctx = ctx; - pmksa->sm = sm; - } + pmksa = os_zalloc(sizeof(*pmksa)); + if (pmksa) { + pmksa->free_cb = free_cb; + pmksa->ctx = ctx; + pmksa->sm = sm; + pmksa->pmksa_count = 0; + pmksa->pmksa = NULL; - return pmksa; + esp_timer_create_args_t pmksa_cache_timeout_timer_create = { + .callback = &pmksa_cache_expire, + .arg = pmksa, + .dispatch_method = ESP_TIMER_TASK, + .name = "pmksa_timeout_timer" + }; + esp_timer_create(&pmksa_cache_timeout_timer_create, &(pmksa->cache_timeout_timer)); + } + + return pmksa; } #endif /* IEEE8021X_EAPOL */ diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h index f8e040e067..6e314385ca 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h @@ -13,102 +13,102 @@ * struct rsn_pmksa_cache_entry - PMKSA cache entry */ struct rsn_pmksa_cache_entry { - struct rsn_pmksa_cache_entry *next; - u8 pmkid[PMKID_LEN]; - u8 pmk[PMK_LEN]; - size_t pmk_len; - os_time_t expiration; - int akmp; /* WPA_KEY_MGMT_* */ - u8 aa[ETH_ALEN]; + struct rsn_pmksa_cache_entry *next; + u8 pmkid[PMKID_LEN]; + u8 pmk[PMK_LEN]; + size_t pmk_len; + os_time_t expiration; + int akmp; /* WPA_KEY_MGMT_* */ + u8 aa[ETH_ALEN]; - os_time_t reauth_time; + os_time_t reauth_time; - /** - * network_ctx - Network configuration context - * - * This field is only used to match PMKSA cache entries to a specific - * network configuration (e.g., a specific SSID and security policy). - * This can be a pointer to the configuration entry, but PMKSA caching - * code does not dereference the value and this could be any kind of - * identifier. - */ - void *network_ctx; - int opportunistic; + /** + * network_ctx - Network configuration context + * + * This field is only used to match PMKSA cache entries to a specific + * network configuration (e.g., a specific SSID and security policy). + * This can be a pointer to the configuration entry, but PMKSA caching + * code does not dereference the value and this could be any kind of + * identifier. + */ + void *network_ctx; + int opportunistic; }; struct rsn_pmksa_cache; enum pmksa_free_reason { - PMKSA_FREE, - PMKSA_REPLACE, - PMKSA_EXPIRE, + PMKSA_FREE, + PMKSA_REPLACE, + PMKSA_EXPIRE, }; #ifdef IEEE8021X_EAPOL struct rsn_pmksa_cache * pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason), - void *ctx, struct wpa_sm *sm); + void *ctx, enum pmksa_free_reason reason), + void *ctx, struct wpa_sm *sm); void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, - const void *network_ctx); + const u8 *aa, const u8 *pmkid, + const void *network_ctx); int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, - const u8 *aa, const u8 *spa, void *network_ctx, int akmp); + const u8 *kck, size_t kck_len, + const u8 *aa, const u8 *spa, void *network_ctx, int akmp); struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); void pmksa_cache_clear_current(struct wpa_sm *sm); int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, - const u8 *bssid, void *network_ctx, - int try_opportunistic); + const u8 *bssid, void *network_ctx, + int try_opportunistic); struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, - void *network_ctx, const u8 *aa); + void *network_ctx, const u8 *aa); void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *pmk, size_t pmk_len); + const u8 *pmk, size_t pmk_len); #else /* IEEE8021X_EAPOL */ -static inline struct rsn_pmksa_cache * + static inline struct rsn_pmksa_cache * pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason), - void *ctx, struct wpa_sm *sm) + void *ctx, enum pmksa_free_reason reason), + void *ctx, struct wpa_sm *sm) { - return (void *) -1; + return (void *) -1; } static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) { } -static inline struct rsn_pmksa_cache_entry * + static inline struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid, - const void *network_ctx) + const void *network_ctx) { - return NULL; + return NULL; } -static inline struct rsn_pmksa_cache_entry * + static inline struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) { - return NULL; + return NULL; } static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, - size_t len) + size_t len) { - return -1; + return -1; } -static inline struct rsn_pmksa_cache_entry * + static inline struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, - const u8 *aa, const u8 *spa, void *network_ctx, int akmp) + const u8 *kck, size_t kck_len, + const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { - return NULL; + return NULL; } static inline void pmksa_cache_clear_current(struct wpa_sm *sm) @@ -116,16 +116,16 @@ static inline void pmksa_cache_clear_current(struct wpa_sm *sm) } static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, - const u8 *bssid, - void *network_ctx, - int try_opportunistic) + const u8 *bssid, + void *network_ctx, + int try_opportunistic) { - return -1; + return -1; } static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, - void *network_ctx, - const u8 *pmk, size_t pmk_len) + void *network_ctx, + const u8 *pmk, size_t pmk_len) { } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index c2d56e6a16..bc68cf2b2a 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -528,6 +528,8 @@ void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, if (res) goto failed; + pmksa_cache_set_current(sm, NULL, sm->bssid, 0, 0); + if (sm->renew_snonce) { if (os_get_random(sm->snonce, WPA_NONCE_LEN)) { #ifdef DEBUG_PRINT diff --git a/components/wpa_supplicant/src/utils/common.c b/components/wpa_supplicant/src/utils/common.c index 5b2f9d7758..12d703ec9f 100644 --- a/components/wpa_supplicant/src/utils/common.c +++ b/components/wpa_supplicant/src/utils/common.c @@ -286,7 +286,7 @@ char * wpa_config_parse_string(const char *value, size_t *len) } -int is_hex(const u8 *data, size_t len) +int wpa_is_hex(const u8 *data, size_t len) { size_t i; @@ -298,7 +298,7 @@ int is_hex(const u8 *data, size_t len) } -size_t merge_byte_arrays(u8 *res, size_t res_len, +size_t wpa_merge_byte_arrays(u8 *res, size_t res_len, const u8 *src1, size_t src1_len, const u8 *src2, size_t src2_len) { @@ -344,7 +344,7 @@ char * dup_binstr(const void *src, size_t len) return res; } -void bin_clear_free(void *bin, size_t len) +void wpa_bin_clear_free(void *bin, size_t len) { if (bin) { os_memset(bin, 0, len); diff --git a/components/wpa_supplicant/include/utils/common.h b/components/wpa_supplicant/src/utils/common.h similarity index 91% rename from components/wpa_supplicant/include/utils/common.h rename to components/wpa_supplicant/src/utils/common.h index c5674254ed..7a44beda8a 100644 --- a/components/wpa_supplicant/include/utils/common.h +++ b/components/wpa_supplicant/src/utils/common.h @@ -396,8 +396,8 @@ size_t printf_decode(u8 *buf, size_t maxlen, const char *str); const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); char * wpa_config_parse_string(const char *value, size_t *len); -int is_hex(const u8 *data, size_t len); -size_t merge_byte_arrays(u8 *res, size_t res_len, +int wpa_is_hex(const u8 *data, size_t len); +size_t wpa_merge_byte_arrays(u8 *res, size_t res_len, const u8 *src1, size_t src1_len, const u8 *src2, size_t src2_len); char * dup_binstr(const void *src, size_t len); @@ -420,7 +420,7 @@ static inline int is_multicast_ether_addr(const u8 *a) #define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" -#include "wpa_debug.h" +#include "utils/wpa_debug.h" struct wpa_freq_range_list { @@ -431,32 +431,9 @@ struct wpa_freq_range_list { unsigned int num; }; -int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value); -int freq_range_list_includes(const struct wpa_freq_range_list *list, - unsigned int freq); -char * freq_range_list_str(const struct wpa_freq_range_list *list); - -int int_array_len(const int *a); -void int_array_concat(int **res, const int *a); -void int_array_sort_unique(int *a); -void int_array_add_unique(int **res, int a); - #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -void str_clear_free(char *str); -void bin_clear_free(void *bin, size_t len); - -int random_mac_addr(u8 *addr); -int random_mac_addr_keep_oui(u8 *addr); - -const char * cstr_token(const char *str, const char *delim, const char **last); -char * str_token(char *str, const char *delim, char **context); -size_t utf8_escape(const char *inp, size_t in_size, - char *outp, size_t out_size); -size_t utf8_unescape(const char *inp, size_t in_size, - char *outp, size_t out_size); -int is_ctrl_char(char c); - +void wpa_bin_clear_free(void *bin, size_t len); /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common From 19e840aa53507ead0e295036dba40dbdc77a5453 Mon Sep 17 00:00:00 2001 From: Hrudaynath Dhabe Date: Mon, 11 Nov 2019 23:22:14 +0800 Subject: [PATCH 03/16] wpa_supplicant: Set assoc_ie_len based on generated RSN/WPA IE --- .../src/esp_supplicant/esp_wpa_main.c | 9 +++++--- components/wpa_supplicant/src/rsn_supp/wpa.c | 21 ++++++++++++------- .../wpa_supplicant/src/rsn_supp/wpa_i.h | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index c576982213..af6ef8ae3b 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -83,13 +83,14 @@ void wpa_config_profile() int wpa_config_bss(uint8_t *bssid) { + int ret = 0; struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal(); u8 mac[6]; esp_wifi_get_macaddr_internal(0, mac); - wpa_set_bss((char *)mac, (char *)bssid, esp_wifi_sta_get_pairwise_cipher_internal(), esp_wifi_sta_get_group_cipher_internal(), + ret = wpa_set_bss((char *)mac, (char *)bssid, esp_wifi_sta_get_pairwise_cipher_internal(), esp_wifi_sta_get_group_cipher_internal(), (char *)esp_wifi_sta_get_prof_password_internal(), ssid->ssid, ssid->len); - return ESP_OK; + return ret; } void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len) @@ -151,8 +152,10 @@ bool wpa_deattach(void) void wpa_sta_connect(uint8_t *bssid) { + int ret = 0; wpa_config_profile(); - wpa_config_bss(bssid); + ret = wpa_config_bss(bssid); + WPA_ASSERT(ret == 0); } int cipher_type_map(int wpa_cipher) diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index bc68cf2b2a..cb9220fb74 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -528,7 +528,10 @@ void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, if (res) goto failed; - pmksa_cache_set_current(sm, NULL, sm->bssid, 0, 0); + if (esp_wifi_sta_prof_is_wpa2_internal() + && esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT) { + pmksa_cache_set_current(sm, NULL, sm->bssid, 0, 0); + } if (sm->renew_snonce) { if (os_get_random(sm->snonce, WPA_NONCE_LEN)) { @@ -1988,9 +1991,9 @@ void wpa_set_pmk(uint8_t *pmk) sm->pmk_len = PMK_LEN; } -void -wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len) +int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len) { + int res = 0; struct wpa_sm *sm = &gWpaSm; sm->pairwise_cipher = BIT(pairwise_cipher); @@ -2008,11 +2011,13 @@ wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, cha pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0); wpa_sm_set_pmk_from_pmksa(sm); } - set_assoc_ie(assoc_ie_buf); /* use static buffer */ - - wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); //TODO: NEED TO DEBUG!! + res = wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); + if (res < 0) + return -1; + sm->assoc_wpa_ie_len = res; wpa_set_passphrase(passphrase, ssid, ssid_len); + return 0; } /* @@ -2063,8 +2068,8 @@ set_assoc_ie(u8 * assoc_buf) if ( sm->proto == WPA_PROTO_WPA) sm->assoc_wpa_ie_len = ASSOC_IE_LEN; else - sm->assoc_wpa_ie_len = ASSOC_IE_LEN - 2; - + sm->assoc_wpa_ie_len = ASSOC_IE_LEN - 2; + sm->config_assoc_ie(sm->proto, assoc_buf, sm->assoc_wpa_ie_len); } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index ab99145af3..51ce03aa2f 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -163,7 +163,7 @@ void eapol_txcb(void *eb); void wpa_set_profile(u32 wpa_proto, u8 auth_mode); -void wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); +int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); #endif /* WPA_I_H */ From 8cd210b38b01c64cd9518cbca9c41691fa3f87e4 Mon Sep 17 00:00:00 2001 From: liu zhifu Date: Wed, 11 Dec 2019 14:36:28 +0800 Subject: [PATCH 04/16] esp_wifi/supplicant: fix some WiFi stop memory leak --- components/wpa_supplicant/src/rsn_supp/pmksa_cache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c index a23233f2a7..0f42eb4040 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c @@ -279,8 +279,9 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) os_free(prev); } pmksa_cache_set_expiration(pmksa); - os_free(pmksa); esp_timer_stop(pmksa->cache_timeout_timer); + esp_timer_delete(pmksa->cache_timeout_timer); + os_free(pmksa); } From b7dc47108fb00169b7a92a6da779b87083d8fc56 Mon Sep 17 00:00:00 2001 From: Hrudaynath Dhabe Date: Wed, 6 May 2020 10:18:41 +0530 Subject: [PATCH 05/16] wifi: Add code required to backport PMK Caching --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 5d75af46c1..b44a2991e9 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 5d75af46c1be2e663f504d10615d7ea9d20a8d2e +Subproject commit b44a2991e9499868bdf99619f2c7c16036ad038a From 1b7f3fee5c3cce1bf28bab0a8a118908f4bea86f Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Thu, 30 Apr 2020 18:47:02 +0530 Subject: [PATCH 06/16] Add support for PMF configuration and negotiation 1. Add APIs for configuring PMF through set config. 2. Map Supplicant and Wifi Cipher types. 3. Add support for PMF negotiation while generating RSN IE. --- components/esp_wifi/include/esp_wifi_types.h | 8 ++ components/wpa_supplicant/CMakeLists.txt | 1 + components/wpa_supplicant/component.mk | 2 +- components/wpa_supplicant/src/common/defs.h | 3 +- .../src/esp_supplicant/esp_wifi_driver.h | 5 +- .../src/esp_supplicant/esp_wpa_main.c | 32 +------ components/wpa_supplicant/src/rsn_supp/wpa.c | 93 ++++++++++++++++++- components/wpa_supplicant/src/rsn_supp/wpa.h | 5 + .../wpa_supplicant/src/rsn_supp/wpa_i.h | 1 + .../wpa_supplicant/src/rsn_supp/wpa_ie.c | 18 ++-- 10 files changed, 122 insertions(+), 46 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 0f9d9643ea..a07cfde080 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -134,6 +134,7 @@ typedef enum { WIFI_CIPHER_TYPE_TKIP, /**< the cipher type is TKIP */ WIFI_CIPHER_TYPE_CCMP, /**< the cipher type is CCMP */ WIFI_CIPHER_TYPE_TKIP_CCMP, /**< the cipher type is TKIP and CCMP */ + WIFI_CIPHER_TYPE_AES_CMAC128,/**< the cipher type is AES-CMAC-128 */ WIFI_CIPHER_TYPE_UNKNOWN, /**< the cipher type is unknown */ } wifi_cipher_type_t; @@ -199,6 +200,12 @@ typedef enum { WIFI_BW_HT40, /* Bandwidth is HT40 */ } wifi_bandwidth_t; +/** Configuration structure for Protected Management Frame */ +typedef struct { + bool capable; /**< Advertizes support for Protected Management Frame. Device will prefer to connect in PMF mode if other device also advertizes PMF capability. */ + bool required; /**< Advertizes that Protected Management Frame is required. Device will not associate to non-PMF capable devices. */ +} wifi_pmf_config_t; + /** @brief Soft-AP configuration settings for the ESP32 */ typedef struct { uint8_t ssid[32]; /**< SSID of ESP32 soft-AP. If ssid_len field is 0, this must be a Null terminated string. Otherwise, length is set according to ssid_len. */ @@ -222,6 +229,7 @@ typedef struct { uint16_t listen_interval; /**< Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. */ wifi_sort_method_t sort_method; /**< sort the connect AP in the list by rssi or security mode */ wifi_scan_threshold_t threshold; /**< When sort_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */ + wifi_pmf_config_t pmf_cfg; /**< Configuration for Protected Management Frame. Will be advertized in RSN Capabilities in RSN IE. */ } wifi_sta_config_t; /** @brief Configuration data for ESP32 AP or STA. diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 36dd7a096b..b7764b48b3 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -106,4 +106,5 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_ECC CONFIG_TLSV12 CONFIG_SHA256 + CONFIG_IEEE80211W ) diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index e85e9979fb..8553cedc87 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -2,4 +2,4 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant 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 -CFLAGS += -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 +CFLAGS += -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/src/common/defs.h b/components/wpa_supplicant/src/common/defs.h index 2f4360ba98..f2fd1f6172 100644 --- a/components/wpa_supplicant/src/common/defs.h +++ b/components/wpa_supplicant/src/common/defs.h @@ -22,7 +22,7 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_CIPHER_WEP104 BIT(8) #define WPA_CIPHER_TKIP BIT(1) #define WPA_CIPHER_CCMP BIT(3) -#define WPA_CIPHER_AES_128_CMAC BIT(2) +#define WPA_CIPHER_AES_128_CMAC BIT(5) #define WPA_CIPHER_GCMP BIT(6) #define WPA_KEY_MGMT_IEEE8021X BIT(0) @@ -304,7 +304,6 @@ enum wpa_states { #define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 #define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 - /** * enum mfp_options - Management frame protection (IEEE 802.11w) options */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index b4767ef197..08d1efdfb4 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -63,7 +63,8 @@ enum { WPA2_AUTH_PSK = 0x05, WPA_AUTH_CCKM = 0x06, WPA2_AUTH_CCKM = 0x07, - WPA2_AUTH_INVALID = 0x08, + WPA2_AUTH_PSK_SHA256= 0x08, + WPA2_AUTH_INVALID = 0x09, }; typedef enum { @@ -218,5 +219,7 @@ esp_err_t esp_wifi_internal_supplicant_header_md5_check(const char *md5); int esp_wifi_sta_update_ap_info_internal(void); uint8_t *esp_wifi_sta_get_ap_info_prof_pmk_internal(void); esp_err_t esp_wifi_set_wps_start_flag_internal(bool start); +uint16_t esp_wifi_sta_pmf_enabled(void); +wifi_cipher_type_t esp_wifi_sta_get_mgmt_group_cipher(void); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index af6ef8ae3b..434b666b48 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -158,32 +158,6 @@ void wpa_sta_connect(uint8_t *bssid) WPA_ASSERT(ret == 0); } -int cipher_type_map(int wpa_cipher) -{ - switch (wpa_cipher) { - case WPA_CIPHER_NONE: - return WIFI_CIPHER_TYPE_NONE; - - case WPA_CIPHER_WEP40: - return WIFI_CIPHER_TYPE_WEP40; - - case WPA_CIPHER_WEP104: - return WIFI_CIPHER_TYPE_WEP104; - - case WPA_CIPHER_TKIP: - return WIFI_CIPHER_TYPE_TKIP; - - case WPA_CIPHER_CCMP: - return WIFI_CIPHER_TYPE_CCMP; - - case WPA_CIPHER_CCMP|WPA_CIPHER_TKIP: - return WIFI_CIPHER_TYPE_TKIP_CCMP; - - default: - return WIFI_CIPHER_TYPE_UNKNOWN; - } -} - int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data) { struct wpa_ie_data ie; @@ -191,12 +165,12 @@ int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t ret = wpa_parse_wpa_ie(wpa_ie, wpa_ie_len, &ie); data->proto = ie.proto; - data->pairwise_cipher = cipher_type_map(ie.pairwise_cipher); - data->group_cipher = cipher_type_map(ie.group_cipher); + data->pairwise_cipher = cipher_type_map_supp_to_public(ie.pairwise_cipher); + data->group_cipher = cipher_type_map_supp_to_public(ie.group_cipher); data->key_mgmt = ie.key_mgmt; data->capabilities = ie.capabilities; data->pmkid = ie.pmkid; - data->mgmt_group_cipher = cipher_type_map(ie.mgmt_group_cipher); + data->mgmt_group_cipher = cipher_type_map_supp_to_public(ie.mgmt_group_cipher); return ret; } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index cb9220fb74..ec8406e1c2 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -46,7 +46,7 @@ /* fix buf for tx for now */ #define WPA_TX_MSG_BUFF_MAXLEN 200 -#define ASSOC_IE_LEN 24 + 2 + PMKID_LEN +#define ASSOC_IE_LEN 24 + 2 + PMKID_LEN + RSN_SELECTOR_LEN u8 assoc_ie_buf[ASSOC_IE_LEN+2]; void set_assoc_ie(u8 * assoc_buf); @@ -76,6 +76,65 @@ void eapol_sm_notify_eap_success(Boolean success) { } + +wifi_cipher_type_t cipher_type_map_supp_to_public(uint32_t wpa_cipher) +{ + switch (wpa_cipher) { + case WPA_CIPHER_NONE: + return WIFI_CIPHER_TYPE_NONE; + + case WPA_CIPHER_WEP40: + return WIFI_CIPHER_TYPE_WEP40; + + case WPA_CIPHER_WEP104: + return WIFI_CIPHER_TYPE_WEP104; + + case WPA_CIPHER_TKIP: + return WIFI_CIPHER_TYPE_TKIP; + + case WPA_CIPHER_CCMP: + return WIFI_CIPHER_TYPE_CCMP; + + case WPA_CIPHER_CCMP|WPA_CIPHER_TKIP: + return WIFI_CIPHER_TYPE_TKIP_CCMP; + + case WPA_CIPHER_AES_128_CMAC: + return WIFI_CIPHER_TYPE_AES_CMAC128; + + default: + return WIFI_CIPHER_TYPE_UNKNOWN; + } +} + +uint32_t cipher_type_map_public_to_supp(wifi_cipher_type_t cipher) +{ + switch (cipher) { + case WIFI_CIPHER_TYPE_NONE: + return WPA_CIPHER_NONE; + + case WIFI_CIPHER_TYPE_WEP40: + return WPA_CIPHER_WEP40; + + case WIFI_CIPHER_TYPE_WEP104: + return WPA_CIPHER_WEP104; + + case WIFI_CIPHER_TYPE_TKIP: + return WPA_CIPHER_TKIP; + + case WIFI_CIPHER_TYPE_CCMP: + return WPA_CIPHER_CCMP; + + case WIFI_CIPHER_TYPE_TKIP_CCMP: + return WPA_CIPHER_CCMP|WPA_CIPHER_TKIP; + + case WIFI_CIPHER_TYPE_AES_CMAC128: + return WPA_CIPHER_AES_128_CMAC; + + default: + return WPA_CIPHER_NONE; + } +} + /** * get_bssid - Get the current BSSID * @priv: private driver interface data @@ -1169,7 +1228,7 @@ int ieee80211w_set_keys(struct wpa_sm *sm, } } - if (ieee80211w_set_keys(sm, &ie) < 0) { + if (sm->pmf_cfg.capable && ieee80211w_set_keys(sm, &ie) < 0) { #ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "RSN: Failed to configure IGTK"); #endif @@ -1746,7 +1805,11 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) } key_info = WPA_GET_BE16(key->key_info); ver = key_info & WPA_KEY_INFO_TYPE_MASK; + if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && +#ifdef CONFIG_IEEE80211W + ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && +#endif ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { #ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "WPA: Unsupported EAPOL-Key descriptor " @@ -1755,6 +1818,14 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) goto out; } +#ifdef CONFIG_IEEE80211W + if (wpa_key_mgmt_sha256(sm->key_mgmt)) { + if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { + goto out; + } + } else +#endif + if (sm->pairwise_cipher == WPA_CIPHER_CCMP && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { #ifdef DEBUG_PRINT @@ -1977,10 +2048,13 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode) struct wpa_sm *sm = &gWpaSm; sm->proto = wpa_proto; - if (auth_mode == WPA2_AUTH_ENT) + if (auth_mode == WPA2_AUTH_ENT) { sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X; /* for wpa2 enterprise */ - else + } else if (auth_mode == WPA2_AUTH_PSK) { sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */ + } else if (auth_mode == WPA2_AUTH_PSK_SHA256) { + sm->key_mgmt = WPA_KEY_MGMT_PSK_SHA256; + } } void wpa_set_pmk(uint8_t *pmk) @@ -2011,6 +2085,17 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0); wpa_sm_set_pmk_from_pmksa(sm); } + +#ifdef CONFIG_IEEE80211W + if (esp_wifi_sta_pmf_enabled()) { + wifi_config_t wifi_cfg; + + esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg); + sm->pmf_cfg = wifi_cfg.sta.pmf_cfg; + sm->mgmt_group_cipher = cipher_type_map_public_to_supp(esp_wifi_sta_get_mgmt_group_cipher()); + } +#endif + set_assoc_ie(assoc_ie_buf); /* use static buffer */ res = wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); if (res < 0) diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index aa81eb1e70..81aa28b547 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -19,6 +19,7 @@ #include "utils/common.h" #include "common/defs.h" #include "common/wpa_common.h" +#include "esp_wifi_types.h" #include "esp_wifi_crypto_types.h" #include "wpa_i.h" @@ -122,5 +123,9 @@ char * dup_binstr(const void *src, size_t len); int wpa_michael_mic_failure(u16 isunicast); +wifi_cipher_type_t cipher_type_map_supp_to_public(uint32_t wpa_cipher); + +uint32_t cipher_type_map_supp_to_public(wifi_cipher_type_t cipher); + #endif /* WPA_H */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index 51ce03aa2f..e0242fbcb7 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -89,6 +89,7 @@ struct wpa_sm { u16 key_info; //used for txcallback param u16 txcb_flags; bool ap_notify_completed_rsne; + wifi_pmf_config_t pmf_cfg; }; /** diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index 5559392cab..77ef60c07b 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -214,10 +214,12 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, /* RSN Capabilities */ capab = 0; #ifdef CONFIG_IEEE80211W - if (sm->mfp) + if (sm->pmf_cfg.capable) { capab |= WPA_CAPABILITY_MFPC; - if (sm->mfp == 2) - capab |= WPA_CAPABILITY_MFPR; + if (sm->pmf_cfg.required) { + capab |= WPA_CAPABILITY_MFPR; + } + } #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(pos, capab); pos += 2; @@ -229,16 +231,14 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, /* PMKID */ os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); pos += PMKID_LEN; + } else { + /* 0 PMKID Count */ + WPA_PUT_LE16(pos, 0); + pos += 2; } #ifdef CONFIG_IEEE80211W if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { - if (!sm->cur_pmksa) { - /* PMKID Count */ - WPA_PUT_LE16(pos, 0); - pos += 2; - } - /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; From 5c5ae96be23d0db21b831cd87f00a0b5069115c2 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Wed, 29 Apr 2020 18:29:39 +0530 Subject: [PATCH 07/16] Add encryption/decryption support for PMF 1. Add CCMP, AES crypto modules for unicast protected Mgmt frames 2. Add support for computing SHA256 MIC on Bcast Mgmt frames 3. Add support for storing iGTK during 4-way handshake. 4. Provide APIs to MLME for utilizing the SW crypto modules --- .../esp_wifi/include/esp_wifi_crypto_types.h | 44 +++ components/wpa_supplicant/CMakeLists.txt | 3 + .../wpa_supplicant/src/common/wpa_common.c | 5 + .../wpa_supplicant/src/crypto/aes-ccm.c | 215 +++++++++++ .../wpa_supplicant/src/crypto/aes-omac1.c | 169 +++++++++ components/wpa_supplicant/src/crypto/aes.h | 9 + components/wpa_supplicant/src/crypto/ccmp.c | 354 ++++++++++++++++++ components/wpa_supplicant/src/crypto/ccmp.h | 28 ++ .../wpa_supplicant/src/crypto/crypto_ops.c | 6 +- .../src/esp_supplicant/esp_wifi_driver.h | 8 + components/wpa_supplicant/src/rsn_supp/wpa.c | 27 +- .../wpa_supplicant/src/rsn_supp/wpa_ie.c | 20 +- 12 files changed, 881 insertions(+), 7 deletions(-) create mode 100644 components/wpa_supplicant/src/crypto/aes-ccm.c create mode 100644 components/wpa_supplicant/src/crypto/aes-omac1.c create mode 100644 components/wpa_supplicant/src/crypto/ccmp.c create mode 100644 components/wpa_supplicant/src/crypto/ccmp.h diff --git a/components/esp_wifi/include/esp_wifi_crypto_types.h b/components/esp_wifi/include/esp_wifi_crypto_types.h index df2388259b..b626845c67 100644 --- a/components/esp_wifi/include/esp_wifi_crypto_types.h +++ b/components/esp_wifi/include/esp_wifi_crypto_types.h @@ -315,6 +315,47 @@ typedef void * (*esp_aes_decrypt_init_t)(const unsigned char *key, unsigned int */ typedef void (*esp_aes_decrypt_deinit_t)(void *ctx); +/** + * @brief One-Key CBC MAC (OMAC1) hash with AES-128 for MIC computation + * + * @key: 128-bit key for the hash operation + * @data: Data buffer for which a MIC is computed + * @data_len: Length of data buffer in bytes + * @mic: Buffer for MIC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + */ +typedef int (*esp_omac1_aes_128_t)(const uint8_t *key, const uint8_t *data, size_t data_len, + uint8_t *mic); + +/** + * @brief Decrypt data using CCMP (Counter Mode CBC-MAC Protocol OR + * Counter Mode Cipher Block Chaining Message Authentication + * Code Protocol) which is used in IEEE 802.11i RSN standard. + * @tk: 128-bit Temporal Key for obtained during 4-way handshake + * @hdr: Pointer to IEEE802.11 frame headeri needed for AAD + * @data: Pointer to encrypted data buffer + * @data_len: Encrypted data length in bytes + * @decrypted_len: Length of decrypted data + * Returns: Pointer to decrypted data on success, NULL on failure + */ +typedef uint8_t * (*esp_ccmp_decrypt_t)(const uint8_t *tk, const uint8_t *ieee80211_hdr, + const uint8_t *data, size_t data_len, size_t *decrypted_len); + +/** + * @brief Encrypt data using CCMP (Counter Mode CBC-MAC Protocol OR + * Counter Mode Cipher Block Chaining Message Authentication + * Code Protocol) which is used in IEEE 802.11i RSN standard. + * @tk: 128-bit Temporal Key for obtained during 4-way handshake + * @frame: Pointer to IEEE802.11 frame including header + * @len: Length of the frame including header + * @hdrlen: Length of the header + * @pn: Packet Number counter + * @keyid: Key ID to be mentioned in CCMP Vector + * @encrypted_len: Length of the encrypted frame including header + */ +typedef uint8_t * (*esp_ccmp_encrypt_t)(const uint8_t *tk, uint8_t *frame, size_t len, size_t hdrlen, + uint8_t *pn, int keyid, size_t *encrypted_len); + /** * @brief The crypto callback function structure used when do station security connect. * The structure can be set as software crypto or the crypto optimized by ESP32 @@ -342,6 +383,9 @@ typedef struct { esp_aes_decrypt_t aes_decrypt; esp_aes_decrypt_init_t aes_decrypt_init; esp_aes_decrypt_deinit_t aes_decrypt_deinit; + esp_omac1_aes_128_t omac1_aes_128; + esp_ccmp_decrypt_t ccmp_decrypt; + esp_ccmp_encrypt_t ccmp_encrypt; }wpa_crypto_funcs_t; /** diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index b7764b48b3..5692955f9c 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -5,13 +5,16 @@ set(srcs "port/os_xtensa.c" "src/ap/wpa_auth_ie.c" "src/common/wpa_common.c" "src/crypto/aes-cbc.c" + "src/crypto/aes-ccm.c" "src/crypto/aes-internal-dec.c" "src/crypto/aes-internal-enc.c" "src/crypto/aes-internal.c" + "src/crypto/aes-omac1.c" "src/crypto/aes-unwrap.c" "src/crypto/aes-wrap.c" "src/crypto/sha256-tlsprf.c" "src/crypto/bignum.c" + "src/crypto/ccmp.c" "src/crypto/crypto_mbedtls.c" "src/crypto/crypto_ops.c" "src/crypto/crypto_internal-cipher.c" diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index c04307052d..1eee98a0cf 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -22,6 +22,7 @@ #include "crypto/sha1.h" #include "crypto/sha256.h" #include "crypto/md5.h" +#include "crypto/aes.h" #define MD5_MAC_LEN 16 @@ -388,6 +389,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, return -1; memcpy(mic, hash, MD5_MAC_LEN); break; +#ifdef CONFIG_IEEE80211W + case WPA_KEY_INFO_TYPE_AES_128_CMAC: + return omac1_aes_128(key, buf, len, mic); +#endif default: return -1; } diff --git a/components/wpa_supplicant/src/crypto/aes-ccm.c b/components/wpa_supplicant/src/crypto/aes-ccm.c new file mode 100644 index 0000000000..ca3acc26e9 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-ccm.c @@ -0,0 +1,215 @@ +/* + * Counter with CBC-MAC (CCM) with AES + * + * Copyright (c) 2010-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef CONFIG_IEEE80211W + +#include "utils/includes.h" + +#include "utils/common.h" +#include "aes.h" +#include "aes_wrap.h" + + +static void xor_aes_block(u8 *dst, const u8 *src) +{ + u32 *d = (u32 *) dst; + u32 *s = (u32 *) src; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; +} + + +static void aes_ccm_auth_start(void *aes, size_t M, size_t L, const u8 *nonce, + const u8 *aad, size_t aad_len, size_t plain_len, + u8 *x) +{ + u8 aad_buf[2 * AES_BLOCK_SIZE]; + u8 b[AES_BLOCK_SIZE]; + + /* Authentication */ + /* B_0: Flags | Nonce N | l(m) */ + b[0] = aad_len ? 0x40 : 0 /* Adata */; + b[0] |= (((M - 2) / 2) /* M' */ << 3); + b[0] |= (L - 1) /* L' */; + os_memcpy(&b[1], nonce, 15 - L); + WPA_PUT_BE16(&b[AES_BLOCK_SIZE - L], plain_len); + + wpa_hexdump_key(MSG_DEBUG, "CCM B_0", b, AES_BLOCK_SIZE); + aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */ + + if (!aad_len) + return; + + WPA_PUT_BE16(aad_buf, aad_len); + os_memcpy(aad_buf + 2, aad, aad_len); + os_memset(aad_buf + 2 + aad_len, 0, sizeof(aad_buf) - 2 - aad_len); + + xor_aes_block(aad_buf, x); + aes_encrypt(aes, aad_buf, x); /* X_2 = E(K, X_1 XOR B_1) */ + + if (aad_len > AES_BLOCK_SIZE - 2) { + xor_aes_block(&aad_buf[AES_BLOCK_SIZE], x); + /* X_3 = E(K, X_2 XOR B_2) */ + aes_encrypt(aes, &aad_buf[AES_BLOCK_SIZE], x); + } +} + + +static void aes_ccm_auth(void *aes, const u8 *data, size_t len, u8 *x) +{ + size_t last = len % AES_BLOCK_SIZE; + size_t i; + + for (i = 0; i < len / AES_BLOCK_SIZE; i++) { + /* X_i+1 = E(K, X_i XOR B_i) */ + xor_aes_block(x, data); + data += AES_BLOCK_SIZE; + aes_encrypt(aes, x, x); + } + if (last) { + /* XOR zero-padded last block */ + for (i = 0; i < last; i++) + x[i] ^= *data++; + aes_encrypt(aes, x, x); + } +} + + +static void aes_ccm_encr_start(size_t L, const u8 *nonce, u8 *a) +{ + /* A_i = Flags | Nonce N | Counter i */ + a[0] = L - 1; /* Flags = L' */ + os_memcpy(&a[1], nonce, 15 - L); +} + + +static void aes_ccm_encr(void *aes, size_t L, const u8 *in, size_t len, u8 *out, + u8 *a) +{ + size_t last = len % AES_BLOCK_SIZE; + size_t i; + + /* crypt = msg XOR (S_1 | S_2 | ... | S_n) */ + for (i = 1; i <= len / AES_BLOCK_SIZE; i++) { + WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + /* S_i = E(K, A_i) */ + aes_encrypt(aes, a, out); + xor_aes_block(out, in); + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + } + if (last) { + WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + aes_encrypt(aes, a, out); + /* XOR zero-padded last block */ + for (i = 0; i < last; i++) + *out++ ^= *in++; + } +} + + +static void aes_ccm_encr_auth(void *aes, size_t M, u8 *x, u8 *a, u8 *auth) +{ + size_t i; + u8 tmp[AES_BLOCK_SIZE]; + + wpa_hexdump_key(MSG_DEBUG, "CCM T", x, M); + /* U = T XOR S_0; S_0 = E(K, A_0) */ + WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0); + aes_encrypt(aes, a, tmp); + for (i = 0; i < M; i++) + auth[i] = x[i] ^ tmp[i]; + wpa_hexdump_key(MSG_DEBUG, "CCM U", auth, M); +} + + +static void aes_ccm_decr_auth(void *aes, size_t M, u8 *a, const u8 *auth, u8 *t) +{ + size_t i; + u8 tmp[AES_BLOCK_SIZE]; + + wpa_hexdump_key(MSG_DEBUG, "CCM U", auth, M); + /* U = T XOR S_0; S_0 = E(K, A_0) */ + WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0); + aes_encrypt(aes, a, tmp); + for (i = 0; i < M; i++) + t[i] = auth[i] ^ tmp[i]; + wpa_hexdump_key(MSG_DEBUG, "CCM T", t, M); +} + + +/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */ +int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce, + size_t M, const u8 *plain, size_t plain_len, + const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth) +{ + const size_t L = 2; + void *aes; + u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE]; + + if (aad_len > 30 || M > AES_BLOCK_SIZE) + return -1; + + aes = aes_encrypt_init(key, key_len); + if (aes == NULL) + return -1; + + aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, plain_len, x); + aes_ccm_auth(aes, plain, plain_len, x); + + /* Encryption */ + aes_ccm_encr_start(L, nonce, a); + aes_ccm_encr(aes, L, plain, plain_len, crypt, a); + aes_ccm_encr_auth(aes, M, x, a, auth); + + aes_encrypt_deinit(aes); + + return 0; +} + + +/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */ +int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce, + size_t M, const u8 *crypt, size_t crypt_len, + const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain) +{ + const size_t L = 2; + void *aes; + u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE]; + u8 t[AES_BLOCK_SIZE]; + + if (aad_len > 30 || M > AES_BLOCK_SIZE) + return -1; + + aes = aes_encrypt_init(key, key_len); + if (aes == NULL) + return -1; + + /* Decryption */ + aes_ccm_encr_start(L, nonce, a); + aes_ccm_decr_auth(aes, M, a, auth, t); + + /* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */ + aes_ccm_encr(aes, L, crypt, crypt_len, plain, a); + + aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x); + aes_ccm_auth(aes, plain, crypt_len, x); + + aes_encrypt_deinit(aes); + + if (os_memcmp(x, t, M) != 0) { + wpa_printf(MSG_DEBUG, "CCM: Auth mismatch"); + return -1; + } + + return 0; +} +#endif /* CONFIG_IEEE80211W */ diff --git a/components/wpa_supplicant/src/crypto/aes-omac1.c b/components/wpa_supplicant/src/crypto/aes-omac1.c new file mode 100644 index 0000000000..415b7955b3 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-omac1.c @@ -0,0 +1,169 @@ +/* + * One-key CBC MAC (OMAC1) hash with AES + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + + +#include "utils/common.h" +#include "crypto/aes.h" +#include "crypto/aes_wrap.h" + +static void gf_mulx(u8 *pad) +{ + int i, carry; + + carry = pad[0] & 0x80; + for (i = 0; i < AES_BLOCK_SIZE - 1; i++) + pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); + pad[AES_BLOCK_SIZE - 1] <<= 1; + if (carry) + pad[AES_BLOCK_SIZE - 1] ^= 0x87; +} + + +/** + * omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES + * @key: Key for the hash operation + * @key_len: Key length in octets + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ +int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; + const u8 *pos, *end; + size_t i, e, left, total_len; + + ctx = aes_encrypt_init(key, key_len); + if (ctx == NULL) + return -1; + os_memset(cbc, 0, AES_BLOCK_SIZE); + + total_len = 0; + for (e = 0; e < num_elem; e++) + total_len += len[e]; + left = total_len; + + e = 0; + pos = addr[0]; + end = pos + len[0]; + + while (left >= AES_BLOCK_SIZE) { + for (i = 0; i < AES_BLOCK_SIZE; i++) { + cbc[i] ^= *pos++; + if (pos >= end) { + /* + * Stop if there are no more bytes to process + * since there are no more entries in the array. + */ + if (i + 1 == AES_BLOCK_SIZE && + left == AES_BLOCK_SIZE) + break; + e++; + pos = addr[e]; + end = pos + len[e]; + } + } + if (left > AES_BLOCK_SIZE) + aes_encrypt(ctx, cbc, cbc); + left -= AES_BLOCK_SIZE; + } + + os_memset(pad, 0, AES_BLOCK_SIZE); + aes_encrypt(ctx, pad, pad); + gf_mulx(pad); + + if (left || total_len == 0) { + for (i = 0; i < left; i++) { + cbc[i] ^= *pos++; + if (pos >= end) { + /* + * Stop if there are no more bytes to process + * since there are no more entries in the array. + */ + if (i + 1 == left) + break; + e++; + pos = addr[e]; + end = pos + len[e]; + } + } + cbc[left] ^= 0x80; + gf_mulx(pad); + } + + for (i = 0; i < AES_BLOCK_SIZE; i++) + pad[i] ^= cbc[i]; + aes_encrypt(ctx, pad, mac); + aes_encrypt_deinit(ctx); + return 0; +} + + +/** + * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 + * @key: 128-bit key for the hash operation + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ +int omac1_aes_128_vector(const u8 *key, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return omac1_aes_vector(key, 16, num_elem, addr, len, mac); +} + + +/** + * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) + * @key: 128-bit key for the hash operation + * @data: Data buffer for which a MAC is determined + * @data_len: Length of data buffer in bytes + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ +int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_128_vector(key, 1, &data, &data_len, mac); +} + + +/** + * omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC) + * @key: 256-bit key for the hash operation + * @data: Data buffer for which a MAC is determined + * @data_len: Length of data buffer in bytes + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ +int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_vector(key, 32, 1, &data, &data_len, mac); +} diff --git a/components/wpa_supplicant/src/crypto/aes.h b/components/wpa_supplicant/src/crypto/aes.h index ba384a9dae..309d24dbac 100644 --- a/components/wpa_supplicant/src/crypto/aes.h +++ b/components/wpa_supplicant/src/crypto/aes.h @@ -24,4 +24,13 @@ void * aes_decrypt_init(const u8 *key, size_t len); void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); void aes_decrypt_deinit(void *ctx); +int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac); + +int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce, + size_t M, const u8 *plain, size_t plain_len, + const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth); +int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce, + size_t M, const u8 *crypt, size_t crypt_len, + const u8 *aad, size_t aad_len, const u8 *auth, + u8 *plain); #endif /* AES_H */ diff --git a/components/wpa_supplicant/src/crypto/ccmp.c b/components/wpa_supplicant/src/crypto/ccmp.c new file mode 100644 index 0000000000..f5814a7844 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/ccmp.c @@ -0,0 +1,354 @@ +/* + * CTR with CBC-MAC Protocol (CCMP) + * Copyright (c) 2010-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef CONFIG_IEEE80211W + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "aes.h" +#include "aes_wrap.h" + +static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data, + u8 *aad, size_t *aad_len, u8 *nonce) +{ + u16 fc, stype, seq; + int qos = 0, addr4 = 0; + u8 *pos; + + nonce[0] = 0; + + fc = le_to_host16(hdr->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == + (WLAN_FC_TODS | WLAN_FC_FROMDS)) + addr4 = 1; + + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { + fc &= ~0x0070; /* Mask subtype bits */ + if (stype & 0x08) { + const u8 *qc; + qos = 1; + fc &= ~WLAN_FC_ORDER; + qc = (const u8 *) (hdr + 1); + if (addr4) + qc += ETH_ALEN; + nonce[0] = qc[0] & 0x0f; + } + } else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) + nonce[0] |= 0x10; /* Management */ + + fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA); + fc |= WLAN_FC_ISWEP; + WPA_PUT_LE16(aad, fc); + pos = aad + 2; + os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN); + pos += 3 * ETH_ALEN; + seq = le_to_host16(hdr->seq_ctrl); + seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */ + WPA_PUT_LE16(pos, seq); + pos += 2; + + os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2); + pos += addr4 * ETH_ALEN; + if (qos) { + pos[0] &= ~0x70; + if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */) + pos[0] &= ~0x80; + pos++; + *pos++ = 0x00; + } + + *aad_len = pos - aad; + + os_memcpy(nonce + 1, hdr->addr2, ETH_ALEN); + nonce[7] = data[7]; /* PN5 */ + nonce[8] = data[6]; /* PN4 */ + nonce[9] = data[5]; /* PN3 */ + nonce[10] = data[4]; /* PN2 */ + nonce[11] = data[1]; /* PN1 */ + nonce[12] = data[0]; /* PN0 */ +} + + +static void ccmp_aad_nonce_pv1(const u8 *hdr, const u8 *a1, const u8 *a2, + const u8 *a3, const u8 *pn, + u8 *aad, size_t *aad_len, u8 *nonce) +{ + u16 fc, type; + u8 *pos; + + nonce[0] = BIT(5); /* PV1 */ + /* TODO: Priority for QMF; 0 is used for Data frames */ + + fc = WPA_GET_LE16(hdr); + type = (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2; + + if (type == 1) + nonce[0] |= 0x10; /* Management */ + + fc &= ~(BIT(10) | BIT(11) | BIT(13) | BIT(14) | BIT(15)); + fc |= BIT(12); + WPA_PUT_LE16(aad, fc); + pos = aad + 2; + if (type == 0 || type == 3) { + const u8 *sc; + + os_memcpy(pos, a1, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, a2, ETH_ALEN); + pos += ETH_ALEN; + + if (type == 0) { + /* Either A1 or A2 contains SID */ + sc = hdr + 2 + 2 + ETH_ALEN; + } else { + /* Both A1 and A2 contain full addresses */ + sc = hdr + 2 + 2 * ETH_ALEN; + } + /* SC with Sequence Number subfield (bits 4-15 of the Sequence + * Control field) masked to 0. */ + *pos++ = *sc & 0x0f; + *pos++ = 0; + + if (a3) { + os_memcpy(pos, a3, ETH_ALEN); + pos += ETH_ALEN; + } + } + + *aad_len = pos - aad; + + os_memcpy(nonce + 1, a2, ETH_ALEN); + nonce[7] = pn[5]; /* PN5 */ + nonce[8] = pn[4]; /* PN4 */ + nonce[9] = pn[3]; /* PN3 */ + nonce[10] = pn[2]; /* PN2 */ + nonce[11] = pn[1]; /* PN1 */ + nonce[12] = pn[0]; /* PN0 */ +} + + +u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data, + size_t data_len, size_t *decrypted_len) +{ + u8 aad[30], nonce[13]; + size_t aad_len; + size_t mlen; + u8 *plain; + + if (data_len < 8 + 8) + return NULL; + + plain = os_malloc(data_len + AES_BLOCK_SIZE); + if (plain == NULL) + return NULL; + + mlen = data_len - 8 - 8; + + os_memset(aad, 0, sizeof(aad)); + ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce); + //wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len); + //wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13); + + if (aes_ccm_ad(tk, 16, nonce, 8, data + 8, mlen, aad, aad_len, + data + 8 + mlen, plain) < 0) { + os_free(plain); + return NULL; + } + //wpa_hexdump(MSG_DEBUG, "CCMP decrypted", plain, mlen); + + *decrypted_len = mlen; + return plain; +} + + +void ccmp_get_pn(u8 *pn, const u8 *data) +{ + pn[0] = data[7]; /* PN5 */ + pn[1] = data[6]; /* PN4 */ + pn[2] = data[5]; /* PN3 */ + pn[3] = data[4]; /* PN2 */ + pn[4] = data[1]; /* PN1 */ + pn[5] = data[0]; /* PN0 */ +} + + +u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, + u8 *pn, int keyid, size_t *encrypted_len) +{ + u8 aad[30], nonce[13]; + size_t aad_len, plen; + u8 *crypt, *pos; + struct ieee80211_hdr *hdr; + + if (len < hdrlen || hdrlen < 24) + return NULL; + plen = len - hdrlen; + + crypt = os_malloc(hdrlen + 8 + plen + 8 + AES_BLOCK_SIZE); + if (crypt == NULL) + return NULL; + + os_memcpy(crypt, frame, hdrlen); + hdr = (struct ieee80211_hdr *) crypt; + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); + pos = crypt + hdrlen; + *pos++ = pn[5]; /* PN0 */ + *pos++ = pn[4]; /* PN1 */ + *pos++ = 0x00; /* Rsvd */ + *pos++ = 0x20 | (keyid << 6); + *pos++ = pn[3]; /* PN2 */ + *pos++ = pn[2]; /* PN3 */ + *pos++ = pn[1]; /* PN4 */ + *pos++ = pn[0]; /* PN5 */ + + os_memset(aad, 0, sizeof(aad)); + ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce); + wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len); + wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13); + + if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len, + pos, pos + plen) < 0) { + os_free(crypt); + return NULL; + } + + wpa_hexdump(MSG_DEBUG, "CCMP encrypted", crypt + hdrlen + 8, plen); + + *encrypted_len = hdrlen + 8 + plen + 8; + + return crypt; +} + + +u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3, + const u8 *frame, size_t len, + size_t hdrlen, const u8 *pn, int keyid, + size_t *encrypted_len) +{ + u8 aad[24], nonce[13]; + size_t aad_len, plen; + u8 *crypt, *pos; + struct ieee80211_hdr *hdr; + + if (len < hdrlen || hdrlen < 12) + return NULL; + plen = len - hdrlen; + + crypt = os_malloc(hdrlen + plen + 8 + AES_BLOCK_SIZE); + if (crypt == NULL) + return NULL; + + os_memcpy(crypt, frame, hdrlen); + hdr = (struct ieee80211_hdr *) crypt; + hdr->frame_control |= host_to_le16(BIT(12)); /* Protected Frame */ + pos = crypt + hdrlen; + + os_memset(aad, 0, sizeof(aad)); + ccmp_aad_nonce_pv1(crypt, a1, a2, a3, pn, aad, &aad_len, nonce); + wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len); + wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, sizeof(nonce)); + + if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len, + pos, pos + plen) < 0) { + os_free(crypt); + return NULL; + } + + wpa_hexdump(MSG_DEBUG, "CCMP encrypted", crypt + hdrlen, plen); + + *encrypted_len = hdrlen + plen + 8; + + return crypt; +} + + +u8 * ccmp_256_decrypt(const u8 *tk, const u8 *hdr, const u8 *data, + size_t data_len, size_t *decrypted_len) +{ + u8 aad[30], nonce[13]; + size_t aad_len; + size_t mlen; + u8 *plain; + + if (data_len < 8 + 16) + return NULL; + + plain = os_malloc(data_len + AES_BLOCK_SIZE); + if (plain == NULL) + return NULL; + + mlen = data_len - 8 - 16; + + os_memset(aad, 0, sizeof(aad)); + ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce); + wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len); + wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13); + + if (aes_ccm_ad(tk, 32, nonce, 16, data + 8, mlen, aad, aad_len, + data + 8 + mlen, plain) < 0) { + os_free(plain); + return NULL; + } + wpa_hexdump(MSG_DEBUG, "CCMP-256 decrypted", plain, mlen); + + *decrypted_len = mlen; + return plain; +} + + +u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, + u8 *pn, int keyid, size_t *encrypted_len) +{ + u8 aad[30], nonce[13]; + size_t aad_len, plen; + u8 *crypt, *pos; + struct ieee80211_hdr *hdr; + + if (len < hdrlen || hdrlen < 24) + return NULL; + plen = len - hdrlen; + + crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE); + if (crypt == NULL) + return NULL; + + os_memcpy(crypt, frame, hdrlen); + hdr = (struct ieee80211_hdr *) crypt; + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); + pos = crypt + hdrlen; + *pos++ = pn[5]; /* PN0 */ + *pos++ = pn[4]; /* PN1 */ + *pos++ = 0x00; /* Rsvd */ + *pos++ = 0x20 | (keyid << 6); + *pos++ = pn[3]; /* PN2 */ + *pos++ = pn[2]; /* PN3 */ + *pos++ = pn[1]; /* PN4 */ + *pos++ = pn[0]; /* PN5 */ + + os_memset(aad, 0, sizeof(aad)); + ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce); + wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len); + wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13); + + if (aes_ccm_ae(tk, 32, nonce, 16, frame + hdrlen, plen, aad, aad_len, + pos, pos + plen) < 0) { + os_free(crypt); + return NULL; + } + + wpa_hexdump(MSG_DEBUG, "CCMP-256 encrypted", crypt + hdrlen + 8, + plen); + + *encrypted_len = hdrlen + 8 + plen + 16; + + return crypt; +} +#endif /* CONFIG_IEEE80211W */ diff --git a/components/wpa_supplicant/src/crypto/ccmp.h b/components/wpa_supplicant/src/crypto/ccmp.h new file mode 100644 index 0000000000..aeca06022e --- /dev/null +++ b/components/wpa_supplicant/src/crypto/ccmp.h @@ -0,0 +1,28 @@ +/* + * wlantest - IEEE 802.11 protocol monitoring and testing tool + * Copyright (c) 2010-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef CONFIG_IEEE80211W +#ifndef CCMP_H +#define CCMP_H + +u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data, + size_t data_len, size_t *decrypted_len); +u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, + u8 *pn, int keyid, size_t *encrypted_len); +u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3, + const u8 *frame, size_t len, + size_t hdrlen, const u8 *pn, int keyid, + size_t *encrypted_len); +void ccmp_get_pn(u8 *pn, const u8 *data); +u8 * ccmp_256_decrypt(const u8 *tk, const u8 *hdr, const u8 *data, + size_t data_len, size_t *decrypted_len); +u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, + u8 *pn, int keyid, size_t *encrypted_len); + +#endif /* CCMP_H */ +#endif /* CONFIG_IEEE80211W */ diff --git a/components/wpa_supplicant/src/crypto/crypto_ops.c b/components/wpa_supplicant/src/crypto/crypto_ops.c index f46d823dfe..ee1aee9401 100644 --- a/components/wpa_supplicant/src/crypto/crypto_ops.c +++ b/components/wpa_supplicant/src/crypto/crypto_ops.c @@ -20,6 +20,7 @@ #include "sha1.h" #include "aes.h" #include "esp_wpa.h" +#include "ccmp.h" /* * This structure is used to set the cyrpto callback function for station to connect when in security mode. @@ -48,7 +49,10 @@ const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = { .aes_encrypt_deinit = (esp_aes_encrypt_deinit_t)aes_encrypt_deinit, .aes_decrypt = (esp_aes_decrypt_t)aes_decrypt, .aes_decrypt_init = (esp_aes_decrypt_init_t)aes_decrypt_init, - .aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit + .aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit, + .omac1_aes_128 = (esp_omac1_aes_128_t)omac1_aes_128, + .ccmp_decrypt = (esp_ccmp_decrypt_t)ccmp_decrypt, + .ccmp_encrypt = (esp_ccmp_encrypt_t)ccmp_encrypt }; const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs = { diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index 08d1efdfb4..c081a2b7f9 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -164,6 +164,13 @@ typedef struct { uint32_t arg_size; } wifi_ipc_config_t; +#define WPA_IGTK_LEN 16 +typedef struct { + uint8_t keyid[2]; + uint8_t pn[6]; + uint8_t igtk[WPA_IGTK_LEN]; +} wifi_wpa_igtk_t; + uint8_t *esp_wifi_ap_get_prof_pmk_internal(void); struct wifi_ssid *esp_wifi_ap_get_prof_ap_ssid_internal(void); uint8_t esp_wifi_ap_get_prof_authmode_internal(void); @@ -221,5 +228,6 @@ uint8_t *esp_wifi_sta_get_ap_info_prof_pmk_internal(void); esp_err_t esp_wifi_set_wps_start_flag_internal(bool start); uint16_t esp_wifi_sta_pmf_enabled(void); wifi_cipher_type_t esp_wifi_sta_get_mgmt_group_cipher(void); +int esp_wifi_set_igtk_internal(uint8_t if_index, const wifi_wpa_igtk_t *igtk); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index ec8406e1c2..12d4fbb66e 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -27,6 +27,7 @@ #include "crypto/crypto.h" #include "crypto/sha1.h" #include "crypto/aes_wrap.h" +#include "crypto/ccmp.h" /** * eapol_sm_notify_eap_success - Notification of external EAP success trigger @@ -681,7 +682,7 @@ int wpa_supplicant_install_ptk(struct wpa_sm *sm) #endif return -1; } - + if (sm->wpa_ptk_rekey) { eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, @@ -991,7 +992,29 @@ void wpa_report_ie_mismatch(struct wpa_sm *sm, const u8 *src_addr, int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie) { +#ifdef CONFIG_IEEE80211W + if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { + return -1; + } + + if (ie->igtk) { + const wifi_wpa_igtk_t *igtk; + uint16_t keyidx; + + if (ie->igtk_len != sizeof(*igtk)) { + return -1; + } + igtk = (const wifi_wpa_igtk_t*)ie->igtk; + keyidx = WPA_GET_LE16(igtk->keyid); + if (keyidx > 4095) { + return -1; + } + return esp_wifi_set_igtk_internal(ESP_IF_WIFI_STA, igtk); + } + return 0; +#else return 0; +#endif } int wpa_supplicant_validate_ie(struct wpa_sm *sm, @@ -2319,10 +2342,10 @@ bool wpa_sta_in_4way_handshake(void) return false; } - bool wpa_sta_is_cur_pmksa_set(void) { struct wpa_sm *sm = &gWpaSm; return (pmksa_cache_get_current(sm) != NULL); } + #endif // ESP_SUPPLICANT diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index 77ef60c07b..dc1a1616bc 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -231,14 +231,16 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, /* PMKID */ os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); pos += PMKID_LEN; - } else { - /* 0 PMKID Count */ - WPA_PUT_LE16(pos, 0); - pos += 2; } #ifdef CONFIG_IEEE80211W if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { + if (!sm->cur_pmksa) { + /* 0 PMKID Count */ + WPA_PUT_LE16(pos, 0); + pos += 2; + } + /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; @@ -329,6 +331,16 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, pos, pos[1] + 2); return 0; } +#ifdef CONFIG_IEEE80211W + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { + ie->igtk = pos + 2 + RSN_SELECTOR_LEN; + ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } +#endif return 0; } From 8f5f828ad6403888cc455929d6da937c32b6c773 Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Wed, 29 Apr 2020 18:44:10 +0530 Subject: [PATCH 08/16] wpa_supplicant: Adding SAE modules with testcase This change ports SAE(Simultaneous Authentication of Equals) feature from wpa_supplicant and makes it work with mbedtls crypto APIs. Currently only group 19 is supported. A sample SAE handshake is included in the testcase. Other minor changes for DH groups are also included. --- .../esp_wifi/include/esp_wifi_crypto_types.h | 4 +- components/wpa_supplicant/CMakeLists.txt | 2 + .../src/common/ieee802_11_defs.h | 18 + components/wpa_supplicant/src/common/sae.c | 1280 +++++++++++++++++ components/wpa_supplicant/src/common/sae.h | 85 ++ .../src/crypto/crypto_mbedtls.c | 6 +- .../wpa_supplicant/src/crypto/dh_groups.c | 682 ++++++++- .../wpa_supplicant/src/crypto/dh_groups.h | 3 + components/wpa_supplicant/src/crypto/sha256.c | 78 +- components/wpa_supplicant/src/crypto/sha256.h | 7 +- components/wpa_supplicant/src/utils/common.h | 2 + components/wpa_supplicant/test/CMakeLists.txt | 1 + components/wpa_supplicant/test/component.mk | 2 +- components/wpa_supplicant/test/test_sae.c | 270 ++++ 14 files changed, 2399 insertions(+), 41 deletions(-) create mode 100644 components/wpa_supplicant/src/common/sae.c create mode 100644 components/wpa_supplicant/src/common/sae.h create mode 100644 components/wpa_supplicant/test/test_sae.c diff --git a/components/esp_wifi/include/esp_wifi_crypto_types.h b/components/esp_wifi/include/esp_wifi_crypto_types.h index b626845c67..47620802e0 100644 --- a/components/esp_wifi/include/esp_wifi_crypto_types.h +++ b/components/esp_wifi/include/esp_wifi_crypto_types.h @@ -116,7 +116,7 @@ typedef int (*esp_aes_unwrap_t)(const unsigned char *kek, int n, const unsigned * @param mac Buffer for the hash (32 bytes). * */ -typedef void (*esp_hmac_sha256_vector_t)(const unsigned char *key, int key_len, int num_elem, +typedef int (*esp_hmac_sha256_vector_t)(const unsigned char *key, int key_len, int num_elem, const unsigned char *addr[], const int *len, unsigned char *mac); /** @@ -131,7 +131,7 @@ typedef void (*esp_hmac_sha256_vector_t)(const unsigned char *key, int key_len, * @param buf_len Number of bytes of key to generate. * */ -typedef void (*esp_sha256_prf_t)(const unsigned char *key, int key_len, const char *label, +typedef int (*esp_sha256_prf_t)(const unsigned char *key, int key_len, const char *label, const unsigned char *data, int data_len, unsigned char *buf, int buf_len); /** diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 5692955f9c..eed582d851 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -3,6 +3,7 @@ set(srcs "port/os_xtensa.c" "src/ap/ieee802_1x.c" "src/ap/wpa_auth.c" "src/ap/wpa_auth_ie.c" + "src/common/sae.c" "src/common/wpa_common.c" "src/crypto/aes-cbc.c" "src/crypto/aes-ccm.c" @@ -110,4 +111,5 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_TLSV12 CONFIG_SHA256 CONFIG_IEEE80211W + CONFIG_WPA3_SAE ) diff --git a/components/wpa_supplicant/src/common/ieee802_11_defs.h b/components/wpa_supplicant/src/common/ieee802_11_defs.h index 4881e39a01..209ae93622 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_defs.h +++ b/components/wpa_supplicant/src/common/ieee802_11_defs.h @@ -141,6 +141,24 @@ #define WLAN_STATUS_INVALID_PMKID 53 #define WLAN_STATUS_INVALID_MDIE 54 #define WLAN_STATUS_INVALID_FTIE 55 +#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59 +#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60 +#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61 +#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62 +#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63 +#define WLAN_STATUS_REQ_REFUSED_HOME 64 +#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65 +#define WLAN_STATUS_REQ_REFUSED_SSPN 67 +#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68 +#define WLAN_STATUS_INVALID_RSNIE 72 +#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76 +#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77 +#define WLAN_STATUS_TRANSMISSION_FAILURE 79 +#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82 +#define WLAN_STATUS_PENDING_ADMITTING_FST_SESSION 86 +#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95 +#define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99 +#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ #define WLAN_REASON_UNSPECIFIED 1 diff --git a/components/wpa_supplicant/src/common/sae.c b/components/wpa_supplicant/src/common/sae.c new file mode 100644 index 0000000000..ebae4c41ee --- /dev/null +++ b/components/wpa_supplicant/src/common/sae.c @@ -0,0 +1,1280 @@ +/* + * Simultaneous authentication of equals + * Copyright (c) 2012-2016, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef CONFIG_WPA3_SAE + +#include "utils/includes.h" +#include "utils/common.h" +#include "crypto/crypto.h" +#include "crypto/sha256.h" +#include "crypto/random.h" +#include "crypto/dh_groups.h" +#include "ieee802_11_defs.h" +#include "sae.h" +#include "esp_wifi_crypto_types.h" + +/*TBD Move the this api to proper files once they are taken out of lib*/ +void wpabuf_clear_free(struct wpabuf *buf) +{ + if (buf) { + os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf)); + wpabuf_free(buf); + } +} + +void bin_clear_free(void *bin, size_t len) +{ + if (bin) { + os_memset(bin, 0, len); + os_free(bin); + } +} + +int sae_set_group(struct sae_data *sae, u16 group) +{ + struct sae_temporary_data *tmp; + + sae_clear_data(sae); + tmp = sae->tmp = os_zalloc(sizeof(*tmp)); + if (tmp == NULL) + return -1; + + /* First, check if this is an ECC group */ + tmp->ec = crypto_ec_init(group); + if (tmp->ec) { + sae->group = group; + tmp->prime_len = crypto_ec_prime_len(tmp->ec); + tmp->prime = crypto_ec_get_prime(tmp->ec); + tmp->order = crypto_ec_get_order(tmp->ec); + return 0; + } + + /* Not an ECC group, check FFC */ + tmp->dh = dh_groups_get(group); + if (tmp->dh) { + sae->group = group; + tmp->prime_len = tmp->dh->prime_len; + if (tmp->prime_len > SAE_MAX_PRIME_LEN) { + sae_clear_data(sae); + return -1; + } + + tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime, + tmp->prime_len); + if (tmp->prime_buf == NULL) { + sae_clear_data(sae); + return -1; + } + tmp->prime = tmp->prime_buf; + + tmp->order_buf = crypto_bignum_init_set(tmp->dh->order, + tmp->dh->order_len); + if (tmp->order_buf == NULL) { + sae_clear_data(sae); + return -1; + } + tmp->order = tmp->order_buf; + + return 0; + } + + /* Unsupported group */ + return -1; +} + +void sae_clear_temp_data(struct sae_data *sae) +{ + struct sae_temporary_data *tmp; + if (sae == NULL || sae->tmp == NULL) + return; + tmp = sae->tmp; + crypto_ec_deinit(tmp->ec); + crypto_bignum_deinit(tmp->prime_buf, 0); + crypto_bignum_deinit(tmp->order_buf, 0); + crypto_bignum_deinit(tmp->sae_rand, 1); + crypto_bignum_deinit(tmp->pwe_ffc, 1); + crypto_bignum_deinit(tmp->own_commit_scalar, 0); + crypto_bignum_deinit(tmp->own_commit_element_ffc, 0); + crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0); + crypto_ec_point_deinit(tmp->pwe_ecc, 1); + crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0); + crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0); + wpabuf_free(tmp->anti_clogging_token); + bin_clear_free(tmp, sizeof(*tmp)); + sae->tmp = NULL; +} + +void sae_clear_data(struct sae_data *sae) +{ + if (sae == NULL) + return; + sae_clear_temp_data(sae); + crypto_bignum_deinit(sae->peer_commit_scalar, 0); + os_memset(sae, 0, sizeof(*sae)); +} + +static void buf_shift_right(u8 *buf, size_t len, size_t bits) +{ + size_t i; + for (i = len - 1; i > 0; i--) + buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits); + buf[0] >>= bits; +} + +static struct crypto_bignum * sae_get_rand(struct sae_data *sae) +{ + u8 val[SAE_MAX_PRIME_LEN]; + int iter = 0; + struct crypto_bignum *bn = NULL; + int order_len_bits = crypto_bignum_bits(sae->tmp->order); + size_t order_len = (order_len_bits + 7) / 8; + + if (order_len > sizeof(val)) + return NULL; + + for (;;) { + if (iter++ > 100 || random_get_bytes(val, order_len) < 0) + return NULL; + if (order_len_bits % 8) + buf_shift_right(val, order_len, 8 - order_len_bits % 8); + bn = crypto_bignum_init_set(val, order_len); + if (bn == NULL) + return NULL; + if (crypto_bignum_is_zero(bn) || + crypto_bignum_is_one(bn) || + crypto_bignum_cmp(bn, sae->tmp->order) >= 0) { + crypto_bignum_deinit(bn, 0); + continue; + } + break; + } + + os_memset(val, 0, order_len); + return bn; +} + +static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae) +{ + crypto_bignum_deinit(sae->tmp->sae_rand, 1); + sae->tmp->sae_rand = sae_get_rand(sae); + if (sae->tmp->sae_rand == NULL) + return NULL; + return sae_get_rand(sae); +} + +static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key) +{ + wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR + " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2)); + if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) { + os_memcpy(key, addr1, ETH_ALEN); + os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN); + } else { + os_memcpy(key, addr2, ETH_ALEN); + os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN); + } +} + +static struct crypto_bignum * +get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits, + int *r_odd) +{ + for (;;) { + struct crypto_bignum *r; + u8 tmp[SAE_MAX_ECC_PRIME_LEN]; + + if (random_get_bytes(tmp, prime_len) < 0) + break; + if (prime_bits % 8) + buf_shift_right(tmp, prime_len, 8 - prime_bits % 8); + if (os_memcmp(tmp, prime, prime_len) >= 0) + continue; + r = crypto_bignum_init_set(tmp, prime_len); + if (!r) + break; + if (crypto_bignum_is_zero(r)) { + crypto_bignum_deinit(r, 0); + continue; + } + + *r_odd = tmp[prime_len - 1] & 0x01; + return r; + } + + return NULL; +} + +static int is_quadratic_residue_blind(struct sae_data *sae, + const u8 *prime, size_t bits, + const struct crypto_bignum *qr, + const struct crypto_bignum *qnr, + const struct crypto_bignum *y_sqr) +{ + struct crypto_bignum *r, *num; + int r_odd, check, res = -1; + + /* + * Use the blinding technique to mask y_sqr while determining + * whether it is a quadratic residue modulo p to avoid leaking + * timing information while determining the Legendre symbol. + * + * v = y_sqr + * r = a random number between 1 and p-1, inclusive + * num = (v * r * r) modulo p + */ + r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd); + if (!r) + return -1; + + num = crypto_bignum_init(); + if (!num || + crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 || + crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0) + goto fail; + + if (r_odd) { + /* + * num = (num * qr) module p + * LGR(num, p) = 1 ==> quadratic residue + */ + if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0) + goto fail; + check = 1; + } else { + /* + * num = (num * qnr) module p + * LGR(num, p) = -1 ==> quadratic residue + */ + if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0) + goto fail; + check = -1; + } + + res = crypto_bignum_legendre(num, sae->tmp->prime); + if (res == -2) { + res = -1; + goto fail; + } + res = res == check; +fail: + crypto_bignum_deinit(num, 1); + crypto_bignum_deinit(r, 1); + return res; +} + +static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, + const u8 *prime, + const struct crypto_bignum *qr, + const struct crypto_bignum *qnr, + struct crypto_bignum **ret_x_cand) +{ + u8 pwd_value[SAE_MAX_ECC_PRIME_LEN]; + struct crypto_bignum *y_sqr, *x_cand; + int res; + size_t bits; + + *ret_x_cand = NULL; + + wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); + + /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ + bits = crypto_ec_prime_len_bits(sae->tmp->ec); + if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", + prime, sae->tmp->prime_len, pwd_value, bits) < 0) + return -1; + if (bits % 8) + buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); + wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", + pwd_value, sae->tmp->prime_len); + + if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0) + return 0; + + x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); + if (!x_cand) + return -1; + y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand); + if (!y_sqr) { + crypto_bignum_deinit(x_cand, 1); + return -1; + } + + res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr); + crypto_bignum_deinit(y_sqr, 1); + if (res <= 0) { + crypto_bignum_deinit(x_cand, 1); + return res; + } + + *ret_x_cand = x_cand; + return 1; +} + +static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, + struct crypto_bignum *pwe) +{ + u8 pwd_value[SAE_MAX_PRIME_LEN]; + size_t bits = sae->tmp->prime_len * 8; + u8 exp[1]; + struct crypto_bignum *a, *b; + int res; + + wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); + + /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ + if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", + sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value, + bits) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, + sae->tmp->prime_len); + + if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0) + { + wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p"); + return 0; + } + + /* PWE = pwd-value^((p-1)/r) modulo p */ + + a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); + + if (sae->tmp->dh->safe_prime) { + /* + * r = (p-1)/2 for the group used here, so this becomes: + * PWE = pwd-value^2 modulo p + */ + exp[0] = 2; + b = crypto_bignum_init_set(exp, sizeof(exp)); + } else { + /* Calculate exponent: (p-1)/r */ + exp[0] = 1; + b = crypto_bignum_init_set(exp, sizeof(exp)); + if (b == NULL || + crypto_bignum_sub(sae->tmp->prime, b, b) < 0 || + crypto_bignum_div(b, sae->tmp->order, b) < 0) { + crypto_bignum_deinit(b, 0); + b = NULL; + } + } + + if (a == NULL || b == NULL) + res = -1; + else + res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe); + + crypto_bignum_deinit(a, 0); + crypto_bignum_deinit(b, 0); + + if (res < 0) { + wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE"); + return -1; + } + + /* if (PWE > 1) --> found */ + if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) { + wpa_printf(MSG_DEBUG, "SAE: PWE <= 1"); + return 0; + } + + wpa_printf(MSG_DEBUG, "SAE: PWE found"); + return 1; +} + +static int get_random_qr_qnr(const u8 *prime, size_t prime_len, + const struct crypto_bignum *prime_bn, + size_t prime_bits, struct crypto_bignum **qr, + struct crypto_bignum **qnr) +{ + *qr = NULL; + *qnr = NULL; + + while (!(*qr) || !(*qnr)) { + u8 tmp[SAE_MAX_ECC_PRIME_LEN]; + struct crypto_bignum *q; + int res; + + if (random_get_bytes(tmp, prime_len) < 0) + break; + if (prime_bits % 8) + buf_shift_right(tmp, prime_len, 8 - prime_bits % 8); + if (os_memcmp(tmp, prime, prime_len) >= 0) + continue; + q = crypto_bignum_init_set(tmp, prime_len); + if (!q) + break; + res = crypto_bignum_legendre(q, prime_bn); + + if (res == 1 && !(*qr)) + *qr = q; + else if (res == -1 && !(*qnr)) + *qnr = q; + else + crypto_bignum_deinit(q, 0); + } + + return (*qr && *qnr) ? 0 : -1; +} + +static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, + const u8 *addr2, const u8 *password, + size_t password_len) +{ + u8 counter, k = 40; + u8 addrs[2 * ETH_ALEN]; + const u8 *addr[2]; + size_t len[2]; + u8 dummy_password[32]; + size_t dummy_password_len; + int pwd_seed_odd = 0; + u8 prime[SAE_MAX_ECC_PRIME_LEN]; + size_t prime_len; + struct crypto_bignum *x = NULL, *qr, *qnr; + size_t bits; + int res; + + dummy_password_len = password_len; + if (dummy_password_len > sizeof(dummy_password)) + dummy_password_len = sizeof(dummy_password); + if (random_get_bytes(dummy_password, dummy_password_len) < 0) + return -1; + + prime_len = sae->tmp->prime_len; + if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), + prime_len) < 0) + return -1; + bits = crypto_ec_prime_len_bits(sae->tmp->ec); + + /* + * Create a random quadratic residue (qr) and quadratic non-residue + * (qnr) modulo p for blinding purposes during the loop. + */ + if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits, + &qr, &qnr) < 0) + return -1; + + wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", + password, password_len); + + /* + * H(salt, ikm) = HMAC-SHA256(salt, ikm) + * base = password + * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), + * base || counter) + */ + sae_pwd_seed_key(addr1, addr2, addrs); + + addr[0] = password; + len[0] = password_len; + addr[1] = &counter; + len[1] = sizeof(counter); + + /* + * Continue for at least k iterations to protect against side-channel + * attacks that attempt to determine the number of iterations required + * in the loop. + */ + for (counter = 1; counter <= k || !x; counter++) { + u8 pwd_seed[SHA256_MAC_LEN]; + struct crypto_bignum *x_cand; + + if (counter > 200) { + /* This should not happen in practice */ + wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE"); + break; + } + + wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); + if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, + pwd_seed) < 0) + break; + + res = sae_test_pwd_seed_ecc(sae, pwd_seed, + prime, qr, qnr, &x_cand); + if (res < 0) + goto fail; + if (res > 0 && !x) { + wpa_printf(MSG_DEBUG, + "SAE: Selected pwd-seed with counter %u", + counter); + x = x_cand; + pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01; + os_memset(pwd_seed, 0, sizeof(pwd_seed)); + + /* + * Use a dummy password for the following rounds, if + * any. + */ + addr[0] = dummy_password; + len[0] = dummy_password_len; + } else if (res > 0) { + crypto_bignum_deinit(x_cand, 1); + } + } + + if (!x) { + wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE"); + res = -1; + goto fail; + } + + if (!sae->tmp->pwe_ecc) + sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec); + if (!sae->tmp->pwe_ecc) + res = -1; + else + res = crypto_ec_point_solve_y_coord(sae->tmp->ec, + sae->tmp->pwe_ecc, x, + pwd_seed_odd); + crypto_bignum_deinit(x, 1); + if (res < 0) { + /* + * This should not happen since we already checked that there + * is a result. + */ + wpa_printf(MSG_DEBUG, "SAE: Could not solve y"); + } + +fail: + crypto_bignum_deinit(qr, 0); + crypto_bignum_deinit(qnr, 0); + + return res; +} + +static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, + const u8 *addr2, const u8 *password, + size_t password_len) +{ + u8 counter; + u8 addrs[2 * ETH_ALEN]; + const u8 *addr[2]; + size_t len[2]; + int found = 0; + + if (sae->tmp->pwe_ffc == NULL) { + sae->tmp->pwe_ffc = crypto_bignum_init(); + if (sae->tmp->pwe_ffc == NULL) + return -1; + } + + wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", + password, password_len); + + /* + * H(salt, ikm) = HMAC-SHA256(salt, ikm) + * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), + * password || counter) + */ + sae_pwd_seed_key(addr1, addr2, addrs); + + addr[0] = password; + len[0] = password_len; + addr[1] = &counter; + len[1] = sizeof(counter); + + for (counter = 1; !found; counter++) { + u8 pwd_seed[SHA256_MAC_LEN]; + int res; + + if (counter > 200) { + /* This should not happen in practice */ + wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE"); + break; + } + + wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); + if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, + pwd_seed) < 0) + break; + res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc); + if (res < 0) + break; + if (res > 0) { + wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); + found = 1; + } + } + + return found ? 0 : -1; +} + +static int sae_derive_commit_element_ecc(struct sae_data *sae, + struct crypto_bignum *mask) +{ + /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */ + if (!sae->tmp->own_commit_element_ecc) { + sae->tmp->own_commit_element_ecc = + crypto_ec_point_init(sae->tmp->ec); + if (!sae->tmp->own_commit_element_ecc) + return -1; + } + + if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask, + sae->tmp->own_commit_element_ecc) < 0 || + crypto_ec_point_invert(sae->tmp->ec, + sae->tmp->own_commit_element_ecc) < 0) { + wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); + return -1; + } + + return 0; +} + +static int sae_derive_commit_element_ffc(struct sae_data *sae, + struct crypto_bignum *mask) +{ + /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */ + if (!sae->tmp->own_commit_element_ffc) { + sae->tmp->own_commit_element_ffc = crypto_bignum_init(); + if (!sae->tmp->own_commit_element_ffc) + return -1; + } + + if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime, + sae->tmp->own_commit_element_ffc) < 0 || + crypto_bignum_inverse(sae->tmp->own_commit_element_ffc, + sae->tmp->prime, + sae->tmp->own_commit_element_ffc) < 0) { + wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); + return -1; + } + + return 0; +} + +static int sae_derive_commit(struct sae_data *sae) +{ + struct crypto_bignum *mask; + int ret = -1; + unsigned int counter = 0; + + do { + counter++; + if (counter > 100) { + /* + * This cannot really happen in practice if the random + * number generator is working. Anyway, to avoid even a + * theoretical infinite loop, break out after 100 + * attemps. + */ + return -1; + } + + mask = sae_get_rand_and_mask(sae); + if (mask == NULL) { + wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask"); + return -1; + } + + /* commit-scalar = (rand + mask) modulo r */ + if (!sae->tmp->own_commit_scalar) { + sae->tmp->own_commit_scalar = crypto_bignum_init(); + if (!sae->tmp->own_commit_scalar) + goto fail; + } + crypto_bignum_add(sae->tmp->sae_rand, mask, + sae->tmp->own_commit_scalar); + crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order, + sae->tmp->own_commit_scalar); + } while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) || + crypto_bignum_is_one(sae->tmp->own_commit_scalar)); + + if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) || + (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)) + goto fail; + + ret = 0; +fail: + crypto_bignum_deinit(mask, 1); + return ret; +} + +int sae_prepare_commit(const u8 *addr1, const u8 *addr2, + const u8 *password, size_t password_len, + struct sae_data *sae) +{ + if (sae->tmp == NULL || + (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password, + password_len) < 0) || + (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password, + password_len) < 0) || + sae_derive_commit(sae) < 0) + return -1; + return 0; +} + +static int sae_derive_k_ecc(struct sae_data *sae, u8 *k) +{ + struct crypto_ec_point *K; + int ret = -1; + + K = crypto_ec_point_init(sae->tmp->ec); + if (K == NULL) + goto fail; + + /* + * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE), + * PEER-COMMIT-ELEMENT))) + * If K is identity element (point-at-infinity), reject + * k = F(K) (= x coordinate) + */ + + if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, + sae->peer_commit_scalar, K) < 0 || + crypto_ec_point_add(sae->tmp->ec, K, + sae->tmp->peer_commit_element_ecc, K) < 0 || + crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 || + crypto_ec_point_is_at_infinity(sae->tmp->ec, K) || + crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) { + wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k"); + goto fail; + } + + wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len); + + ret = 0; +fail: + crypto_ec_point_deinit(K, 1); + return ret; +} + +static int sae_derive_k_ffc(struct sae_data *sae, u8 *k) +{ + struct crypto_bignum *K; + int ret = -1; + + K = crypto_bignum_init(); + if (K == NULL) + goto fail; + + /* + * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE), + * PEER-COMMIT-ELEMENT))) + * If K is identity element (one), reject. + * k = F(K) (= x coordinate) + */ + + if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar, + sae->tmp->prime, K) < 0 || + crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc, + sae->tmp->prime, K) < 0 || + crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0 + || + crypto_bignum_is_one(K) || + crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) < + 0) { + wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k"); + goto fail; + } + + wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len); + + ret = 0; +fail: + crypto_bignum_deinit(K, 1); + return ret; +} + +static int sae_derive_keys(struct sae_data *sae, const u8 *k) +{ + u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN]; + u8 keyseed[SHA256_MAC_LEN]; + u8 keys[SAE_KCK_LEN + SAE_PMK_LEN]; + struct crypto_bignum *tmp; + int ret = -1; + + tmp = crypto_bignum_init(); + if (tmp == NULL) + goto fail; + + /* keyseed = H(<0>32, k) + * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK", + * (commit-scalar + peer-commit-scalar) modulo r) + * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128) + */ + + os_memset(null_key, 0, sizeof(null_key)); + hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len, + keyseed); + wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed)); + + crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar, + tmp); + crypto_bignum_mod(tmp, sae->tmp->order, tmp); + crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len); + wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN); + if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK", + val, sae->tmp->prime_len, keys, sizeof(keys)) < 0) + goto fail; + os_memset(keyseed, 0, sizeof(keyseed)); + os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN); + os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN); + os_memcpy(sae->pmkid, val, SAE_PMKID_LEN); + os_memset(keys, 0, sizeof(keys)); + wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN); + wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN); + + ret = 0; +fail: + crypto_bignum_deinit(tmp, 0); + return ret; +} + +int sae_process_commit(struct sae_data *sae) +{ + u8 k[SAE_MAX_PRIME_LEN]; + if (sae->tmp == NULL || + (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) || + (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) || + sae_derive_keys(sae, k) < 0) + return -1; + return 0; +} + +void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, + const struct wpabuf *token) +{ + u8 *pos; + + if (sae->tmp == NULL) + return; + + wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */ + if (token) { + wpabuf_put_buf(buf, token); + wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token", + wpabuf_head(token), wpabuf_len(token)); + } + pos = wpabuf_put(buf, sae->tmp->prime_len); + crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, + sae->tmp->prime_len, sae->tmp->prime_len); + wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar", + pos, sae->tmp->prime_len); + if (sae->tmp->ec) { + pos = wpabuf_put(buf, 2 * sae->tmp->prime_len); + crypto_ec_point_to_bin(sae->tmp->ec, + sae->tmp->own_commit_element_ecc, + pos, pos + sae->tmp->prime_len); + wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)", + pos, sae->tmp->prime_len); + wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)", + pos + sae->tmp->prime_len, sae->tmp->prime_len); + } else { + pos = wpabuf_put(buf, sae->tmp->prime_len); + crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, + sae->tmp->prime_len, sae->tmp->prime_len); + wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", + pos, sae->tmp->prime_len); + } +} + +u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group) +{ + if (allowed_groups) { + int i; + for (i = 0; allowed_groups[i] > 0; i++) { + if (allowed_groups[i] == group) + break; + } + if (allowed_groups[i] != group) { + wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not " + "enabled in the current configuration", + group); + return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + } + } + + if (sae->state == SAE_COMMITTED && group != sae->group) { + wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed"); + return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + } + + if (group != sae->group && sae_set_group(sae, group) < 0) { + wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u", + group); + return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + } + + if (sae->tmp == NULL) { + wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + if (sae->tmp->dh && !allowed_groups) { + wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without " + "explicit configuration enabling it", group); + return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + } + + return WLAN_STATUS_SUCCESS; +} + +static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, + const u8 *end, const u8 **token, + size_t *token_len) +{ + if ((sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end - *pos) { + size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) * + sae->tmp->prime_len); + wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen); + if (token) + *token = *pos; + if (token_len) + *token_len = tlen; + *pos += tlen; + } else { + if (token) + *token = NULL; + if (token_len) + *token_len = 0; + } +} + +static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, + const u8 *end) +{ + struct crypto_bignum *peer_scalar; + + if (sae->tmp->prime_len > end - *pos) { + wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len); + if (peer_scalar == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + /* + * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for + * the peer and it is in Authenticated state, the new Commit Message + * shall be dropped if the peer-scalar is identical to the one used in + * the existing protocol instance. + */ + if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar && + crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) { + wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous " + "peer-commit-scalar"); + crypto_bignum_deinit(peer_scalar, 0); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + /* 1 < scalar < r */ + if (crypto_bignum_is_zero(peer_scalar) || + crypto_bignum_is_one(peer_scalar) || + crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) { + wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar"); + crypto_bignum_deinit(peer_scalar, 0); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + + crypto_bignum_deinit(sae->peer_commit_scalar, 0); + sae->peer_commit_scalar = peer_scalar; + wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar", + *pos, sae->tmp->prime_len); + *pos += sae->tmp->prime_len; + + return WLAN_STATUS_SUCCESS; +} + +static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, + const u8 *end) +{ + u8 prime[SAE_MAX_ECC_PRIME_LEN]; + + if (2 * sae->tmp->prime_len > end - pos) { + wpa_printf(MSG_DEBUG, "SAE: Not enough data for " + "commit-element"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), + sae->tmp->prime_len) < 0) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + /* element x and y coordinates < p */ + if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 || + os_memcmp(pos + sae->tmp->prime_len, prime, + sae->tmp->prime_len) >= 0) { + wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer " + "element"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)", + pos, sae->tmp->prime_len); + wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)", + pos + sae->tmp->prime_len, sae->tmp->prime_len); + + crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0); + sae->tmp->peer_commit_element_ecc = + crypto_ec_point_from_bin(sae->tmp->ec, pos); + if (sae->tmp->peer_commit_element_ecc == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + if (!crypto_ec_point_is_on_curve(sae->tmp->ec, + sae->tmp->peer_commit_element_ecc)) { + wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + return WLAN_STATUS_SUCCESS; +} + +static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos, + const u8 *end) +{ + struct crypto_bignum *res, *one; + const u8 one_bin[1] = { 0x01 }; + + if (sae->tmp->prime_len > end - pos) { + wpa_printf(MSG_DEBUG, "SAE: Not enough data for " + "commit-element"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos, + sae->tmp->prime_len); + + crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0); + sae->tmp->peer_commit_element_ffc = + crypto_bignum_init_set(pos, sae->tmp->prime_len); + if (sae->tmp->peer_commit_element_ffc == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + /* 1 < element < p - 1 */ + res = crypto_bignum_init(); + one = crypto_bignum_init_set(one_bin, sizeof(one_bin)); + if (!res || !one || + crypto_bignum_sub(sae->tmp->prime, one, res) || + crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) || + crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) || + crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) { + crypto_bignum_deinit(res, 0); + crypto_bignum_deinit(one, 0); + wpa_printf(MSG_DEBUG, "SAE: Invalid peer element"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + crypto_bignum_deinit(one, 0); + + /* scalar-op(r, ELEMENT) = 1 modulo p */ + if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc, + sae->tmp->order, sae->tmp->prime, res) < 0 || + !crypto_bignum_is_one(res)) { + wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)"); + crypto_bignum_deinit(res, 0); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + crypto_bignum_deinit(res, 0); + + return WLAN_STATUS_SUCCESS; +} + +static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos, + const u8 *end) +{ + if (sae->tmp->dh) + return sae_parse_commit_element_ffc(sae, pos, end); + return sae_parse_commit_element_ecc(sae, pos, end); +} + +u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, + const u8 **token, size_t *token_len, int *allowed_groups) +{ + const u8 *pos = data, *end = data + len; + u16 res; + + /* Check Finite Cyclic Group */ + if (end - pos < 2) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos)); + if (res != WLAN_STATUS_SUCCESS) + return res; + pos += 2; + + /* Optional Anti-Clogging Token */ + sae_parse_commit_token(sae, &pos, end, token, token_len); + + /* commit-scalar */ + res = sae_parse_commit_scalar(sae, &pos, end); + if (res != WLAN_STATUS_SUCCESS) + return res; + + /* commit-element */ + res = sae_parse_commit_element(sae, pos, end); + if (res != WLAN_STATUS_SUCCESS) + return res; + + /* + * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as + * the values we sent which would be evidence of a reflection attack. + */ + if (!sae->tmp->own_commit_scalar || + crypto_bignum_cmp(sae->tmp->own_commit_scalar, + sae->peer_commit_scalar) != 0 || + (sae->tmp->dh && + (!sae->tmp->own_commit_element_ffc || + crypto_bignum_cmp(sae->tmp->own_commit_element_ffc, + sae->tmp->peer_commit_element_ffc) != 0)) || + (sae->tmp->ec && + (!sae->tmp->own_commit_element_ecc || + crypto_ec_point_cmp(sae->tmp->ec, + sae->tmp->own_commit_element_ecc, + sae->tmp->peer_commit_element_ecc) != 0))) + return WLAN_STATUS_SUCCESS; /* scalars/elements are different */ + + /* + * This is a reflection attack - return special value to trigger caller + * to silently discard the frame instead of replying with a specific + * status code. + */ + return SAE_SILENTLY_DISCARD; +} + +static void sae_cn_confirm(struct sae_data *sae, const u8 *sc, + const struct crypto_bignum *scalar1, + const u8 *element1, size_t element1_len, + const struct crypto_bignum *scalar2, + const u8 *element2, size_t element2_len, + u8 *confirm) +{ + const u8 *addr[5]; + size_t len[5]; + u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN]; + + /* Confirm + * CN(key, X, Y, Z, ...) = + * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...) + * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT, + * peer-commit-scalar, PEER-COMMIT-ELEMENT) + * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar, + * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT) + */ + addr[0] = sc; + len[0] = 2; + crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1), + sae->tmp->prime_len); + addr[1] = scalar_b1; + len[1] = sae->tmp->prime_len; + addr[2] = element1; + len[2] = element1_len; + crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2), + sae->tmp->prime_len); + addr[3] = scalar_b2; + len[3] = sae->tmp->prime_len; + addr[4] = element2; + len[4] = element2_len; + hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len, + confirm); +} + +static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, + const struct crypto_bignum *scalar1, + const struct crypto_ec_point *element1, + const struct crypto_bignum *scalar2, + const struct crypto_ec_point *element2, + u8 *confirm) +{ + u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN]; + u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN]; + + crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1, + element_b1 + sae->tmp->prime_len); + crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2, + element_b2 + sae->tmp->prime_len); + + sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len, + scalar2, element_b2, 2 * sae->tmp->prime_len, confirm); +} + +static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc, + const struct crypto_bignum *scalar1, + const struct crypto_bignum *element1, + const struct crypto_bignum *scalar2, + const struct crypto_bignum *element2, + u8 *confirm) +{ + u8 element_b1[SAE_MAX_PRIME_LEN]; + u8 element_b2[SAE_MAX_PRIME_LEN]; + + crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1), + sae->tmp->prime_len); + crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2), + sae->tmp->prime_len); + + sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len, + scalar2, element_b2, sae->tmp->prime_len, confirm); +} + +void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) +{ + const u8 *sc; + + if (sae->tmp == NULL) + return; + + /* Send-Confirm */ + sc = wpabuf_put(buf, 0); + wpabuf_put_le16(buf, sae->send_confirm); + sae->send_confirm++; + + if (sae->tmp->ec) + sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ecc, + sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ecc, + wpabuf_put(buf, SHA256_MAC_LEN)); + else + sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ffc, + sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ffc, + wpabuf_put(buf, SHA256_MAC_LEN)); +} + +int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) +{ + u8 verifier[SHA256_MAC_LEN]; + + if (len < 2 + SHA256_MAC_LEN) { + wpa_printf(MSG_DEBUG, "SAE: Too short confirm message"); + return -1; + } + + wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data)); + + if (sae->tmp == NULL) { + wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available"); + return -1; + } + + if (sae->tmp->ec) + sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ecc, + sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ecc, + verifier); + else + sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ffc, + sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ffc, + verifier); + + if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) { + wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); + wpa_hexdump(MSG_DEBUG, "SAE: Received confirm", + data + 2, SHA256_MAC_LEN); + wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier", + verifier, SHA256_MAC_LEN); + return -1; + } + + return 0; +} + +#endif /* CONFIG_WPA3_SAE */ diff --git a/components/wpa_supplicant/src/common/sae.h b/components/wpa_supplicant/src/common/sae.h new file mode 100644 index 0000000000..41c7ac0cb4 --- /dev/null +++ b/components/wpa_supplicant/src/common/sae.h @@ -0,0 +1,85 @@ +/* + * Simultaneous authentication of equals + * Copyright (c) 2012-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef CONFIG_WPA3_SAE + +#ifndef SAE_H +#define SAE_H + +#include "esp_err.h" + +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" + +#define SAE_KCK_LEN 32 +#define SAE_PMK_LEN 32 +#define SAE_PMKID_LEN 16 +#define SAE_KEYSEED_KEY_LEN 32 +#define SAE_MAX_PRIME_LEN 512 +#define SAE_MAX_ECC_PRIME_LEN 66 +#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN) +#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN) + +/* Special value returned by sae_parse_commit() */ +#define SAE_SILENTLY_DISCARD 65535 + +struct sae_temporary_data { + u8 kck[SAE_KCK_LEN]; + struct crypto_bignum *own_commit_scalar; + struct crypto_bignum *own_commit_element_ffc; + struct crypto_ec_point *own_commit_element_ecc; + struct crypto_bignum *peer_commit_element_ffc; + struct crypto_ec_point *peer_commit_element_ecc; + struct crypto_ec_point *pwe_ecc; + struct crypto_bignum *pwe_ffc; + struct crypto_bignum *sae_rand; + struct crypto_ec *ec; + int prime_len; + const struct dh_group *dh; + const struct crypto_bignum *prime; + const struct crypto_bignum *order; + struct crypto_bignum *prime_buf; + struct crypto_bignum *order_buf; + struct wpabuf *anti_clogging_token; +}; + +enum { + SAE_MSG_COMMIT = 1, + SAE_MSG_CONFIRM = 2, +}; + +struct sae_data { + enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state; + u16 send_confirm; + u8 pmk[SAE_PMK_LEN]; + u8 pmkid[SAE_PMKID_LEN]; + struct crypto_bignum *peer_commit_scalar; + u16 group; + int sync; + struct sae_temporary_data *tmp; +}; + +int sae_set_group(struct sae_data *sae, u16 group); +void sae_clear_temp_data(struct sae_data *sae); +void sae_clear_data(struct sae_data *sae); + +int sae_prepare_commit(const u8 *addr1, const u8 *addr2, + const u8 *password, size_t password_len, + struct sae_data *sae); +int sae_process_commit(struct sae_data *sae); +void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, + const struct wpabuf *token); +u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, + const u8 **token, size_t *token_len, int *allowed_groups); +void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); +int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len); +u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group); + +#endif /* SAE_H */ +#endif /* CONFIG_WPA3_SAE */ diff --git a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c index fbbab1a9e9..88c0e732a9 100644 --- a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -25,10 +25,6 @@ #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" - - -#define IANA_SECP256R1 19 - #ifdef ESP_PLATFORM int crypto_get_random(void *buf, size_t len) { @@ -497,6 +493,8 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e, if (y_bit) { MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y)); } + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&((mbedtls_ecp_point* )p)->X, (const mbedtls_mpi*) x)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&((mbedtls_ecp_point *)p)->Z, 1)); } else { ret = 1; } diff --git a/components/wpa_supplicant/src/crypto/dh_groups.c b/components/wpa_supplicant/src/crypto/dh_groups.c index 6f699d9be6..3d872d3b4e 100644 --- a/components/wpa_supplicant/src/crypto/dh_groups.c +++ b/components/wpa_supplicant/src/crypto/dh_groups.c @@ -44,6 +44,21 @@ static const u8 dh_group1_prime[96] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group1_order[96] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1D, 0x1B, 0x10, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + /* RFC 4306, B.2. Group 2 - 1024 Bit MODP * Generator: 2 * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } @@ -68,6 +83,25 @@ static const u8 dh_group2_prime[128] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group2_order[128] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, + 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, + 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, + 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, + 0x24, 0x94, 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + #endif /* ALL_DH_GROUPS */ /* RFC 3526, 2. Group 5 - 1536 Bit MODP @@ -102,6 +136,33 @@ static const u8 dh_group5_prime[192] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group5_order[192] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, + 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, + 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, + 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, + 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, + 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, + 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, + 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, + 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, + 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, + 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, + 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, + 0x78, 0xBA, 0x36, 0x04, 0x65, 0x11, 0xB9, 0x93, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + #ifdef ALL_DH_GROUPS /* RFC 3526, 3. Group 14 - 2048 Bit MODP @@ -144,6 +205,41 @@ static const u8 dh_group14_prime[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group14_order[256] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, + 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, + 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, + 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, + 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, + 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, + 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, + 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, + 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, + 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, + 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, + 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, + 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, + 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, + 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, + 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, + 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, + 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, + 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, + 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, + 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x56, 0x55, 0x34, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + /* RFC 3526, 4. Group 15 - 3072 Bit MODP * Generator: 2 * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } @@ -200,6 +296,57 @@ static const u8 dh_group15_prime[384] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group15_order[384] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, + 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, + 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, + 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, + 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, + 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, + 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, + 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, + 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, + 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, + 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, + 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, + 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, + 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, + 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, + 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, + 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, + 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, + 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, + 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, + 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, + 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, + 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, + 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, + 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, + 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, + 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, + 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, + 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, + 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, + 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, + 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, + 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, + 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, + 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, + 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, + 0x25, 0xC1, 0x68, 0x90, 0x54, 0x9D, 0x69, 0x65, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + /* RFC 3526, 5. Group 16 - 4096 Bit MODP * Generator: 2 * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } @@ -272,6 +419,73 @@ static const u8 dh_group16_prime[512] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group16_order[512] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, + 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, + 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, + 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, + 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, + 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, + 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, + 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, + 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, + 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, + 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, + 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, + 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, + 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, + 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, + 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, + 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, + 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, + 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, + 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, + 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, + 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, + 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, + 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, + 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, + 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, + 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, + 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, + 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, + 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, + 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, + 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, + 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, + 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, + 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, + 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, + 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00, + 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, + 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93, + 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E, + 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED, + 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74, + 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C, + 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53, + 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, + 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1, + 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6, + 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7, + 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E, + 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54, + 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0, + 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, + 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x03, 0x18, 0xCC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + /* RFC 3526, 6. Group 17 - 6144 Bit MODP * Generator: 2 * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } @@ -376,6 +590,105 @@ static const u8 dh_group17_prime[768] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group17_order[768] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, + 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, + 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, + 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, + 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, + 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, + 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, + 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, + 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, + 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, + 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, + 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, + 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, + 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, + 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, + 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, + 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, + 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, + 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, + 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, + 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, + 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, + 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, + 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, + 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, + 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, + 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, + 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, + 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, + 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, + 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, + 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, + 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, + 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, + 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, + 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, + 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00, + 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, + 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93, + 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E, + 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED, + 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74, + 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C, + 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53, + 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, + 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1, + 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6, + 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7, + 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E, + 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54, + 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0, + 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, + 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49, + 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13, + 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F, + 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE, + 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87, + 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7, + 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18, + 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C, + 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76, + 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D, + 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5, + 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1, + 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F, + 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76, + 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81, + 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B, + 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41, + 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F, + 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79, + 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F, + 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62, + 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55, + 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC, + 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0, + 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94, + 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B, + 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8, + 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE, + 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19, + 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34, + 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77, + 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B, + 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xE6, 0x20, 0x12, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + /* RFC 3526, 7. Group 18 - 8192 Bit MODP * Generator: 2 * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } @@ -512,24 +825,362 @@ static const u8 dh_group18_prime[1024] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 dh_group18_order[1024] = { + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A, + 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68, + 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A, + 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91, + 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E, + 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D, + 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B, + 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22, + 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63, + 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5, + 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6, + 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2, + 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3, + 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E, + 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82, + 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD, + 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF, + 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB, + 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D, + 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36, + 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02, + 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE, + 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D, + 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01, + 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47, + 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64, + 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C, + 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72, + 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88, + 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16, + 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19, + 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32, + 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85, + 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E, + 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63, + 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB, + 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE, + 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35, + 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32, + 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32, + 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06, + 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6, + 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71, + 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98, + 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47, + 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00, + 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B, + 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93, + 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E, + 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED, + 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74, + 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C, + 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53, + 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E, + 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1, + 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6, + 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7, + 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E, + 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54, + 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0, + 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47, + 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49, + 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13, + 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F, + 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE, + 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87, + 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7, + 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18, + 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C, + 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76, + 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D, + 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5, + 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1, + 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F, + 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76, + 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81, + 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B, + 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41, + 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F, + 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79, + 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F, + 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62, + 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55, + 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC, + 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0, + 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94, + 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B, + 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8, + 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE, + 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19, + 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34, + 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77, + 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B, + 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xDF, 0x08, 0xAC, + 0xBA, 0x51, 0xC9, 0x37, 0x89, 0x7F, 0x72, 0xF2, + 0x1C, 0x3B, 0xBE, 0x5B, 0x54, 0x99, 0x6F, 0xC6, + 0x6C, 0x5F, 0x62, 0x68, 0x39, 0xDC, 0x98, 0xDD, + 0x1D, 0xE4, 0x19, 0x5B, 0x46, 0xCE, 0xE9, 0x80, + 0x3A, 0x0F, 0xD3, 0xDF, 0xC5, 0x7E, 0x23, 0xF6, + 0x92, 0xBB, 0x7B, 0x49, 0xB5, 0xD2, 0x12, 0x33, + 0x1D, 0x55, 0xB1, 0xCE, 0x2D, 0x72, 0x7A, 0xB4, + 0x1A, 0x11, 0xDA, 0x3A, 0x15, 0xF8, 0xE4, 0xBC, + 0x11, 0xC7, 0x8B, 0x65, 0xF1, 0xCE, 0xB2, 0x96, + 0xF1, 0xFE, 0xDC, 0x5F, 0x7E, 0x42, 0x45, 0x6C, + 0x91, 0x11, 0x17, 0x02, 0x52, 0x01, 0xBE, 0x03, + 0x89, 0xF5, 0xAB, 0xD4, 0x0D, 0x11, 0xF8, 0x63, + 0x9A, 0x39, 0xFE, 0x32, 0x36, 0x75, 0x18, 0x35, + 0xA5, 0xE5, 0xE4, 0x43, 0x17, 0xC1, 0xC2, 0xEE, + 0xFD, 0x4E, 0xA5, 0xBF, 0xD1, 0x60, 0x43, 0xF4, + 0x3C, 0xB4, 0x19, 0x81, 0xF6, 0xAD, 0xEE, 0x9D, + 0x03, 0x15, 0x9E, 0x7A, 0xD9, 0xD1, 0x3C, 0x53, + 0x36, 0x95, 0x09, 0xFC, 0x1F, 0xA2, 0x7C, 0x16, + 0xEF, 0x98, 0x87, 0x70, 0x3A, 0x55, 0xB5, 0x1B, + 0x22, 0xCB, 0xF4, 0x4C, 0xD0, 0x12, 0xAE, 0xE0, + 0xB2, 0x79, 0x8E, 0x62, 0x84, 0x23, 0x42, 0x8E, + 0xFC, 0xD5, 0xA4, 0x0C, 0xAE, 0xF6, 0xBF, 0x50, + 0xD8, 0xEA, 0x88, 0x5E, 0xBF, 0x73, 0xA6, 0xB9, + 0xFD, 0x79, 0xB5, 0xE1, 0x8F, 0x67, 0xD1, 0x34, + 0x1A, 0xC8, 0x23, 0x7A, 0x75, 0xC3, 0xCF, 0xC9, + 0x20, 0x04, 0xA1, 0xC5, 0xA4, 0x0E, 0x36, 0x6B, + 0xC4, 0x4D, 0x00, 0x17, 0x6A, 0xF7, 0x1C, 0x15, + 0xE4, 0x8C, 0x86, 0xD3, 0x7E, 0x01, 0x37, 0x23, + 0xCA, 0xAC, 0x72, 0x23, 0xAB, 0x3B, 0xF4, 0xD5, + 0x4F, 0x18, 0x28, 0x71, 0x3B, 0x2B, 0x4A, 0x6F, + 0xE4, 0x0F, 0xAB, 0x74, 0x40, 0x5C, 0xB7, 0x38, + 0xB0, 0x64, 0xC0, 0x6E, 0xCC, 0x76, 0xE9, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* + * RFC 5114, 2.1. + * Group 22 - 1024-bit MODP Group with 160-bit Prime Order Subgroup + */ +static const u8 dh_group22_generator[] = { + 0xA4, 0xD1, 0xCB, 0xD5, 0xC3, 0xFD, 0x34, 0x12, + 0x67, 0x65, 0xA4, 0x42, 0xEF, 0xB9, 0x99, 0x05, + 0xF8, 0x10, 0x4D, 0xD2, 0x58, 0xAC, 0x50, 0x7F, + 0xD6, 0x40, 0x6C, 0xFF, 0x14, 0x26, 0x6D, 0x31, + 0x26, 0x6F, 0xEA, 0x1E, 0x5C, 0x41, 0x56, 0x4B, + 0x77, 0x7E, 0x69, 0x0F, 0x55, 0x04, 0xF2, 0x13, + 0x16, 0x02, 0x17, 0xB4, 0xB0, 0x1B, 0x88, 0x6A, + 0x5E, 0x91, 0x54, 0x7F, 0x9E, 0x27, 0x49, 0xF4, + 0xD7, 0xFB, 0xD7, 0xD3, 0xB9, 0xA9, 0x2E, 0xE1, + 0x90, 0x9D, 0x0D, 0x22, 0x63, 0xF8, 0x0A, 0x76, + 0xA6, 0xA2, 0x4C, 0x08, 0x7A, 0x09, 0x1F, 0x53, + 0x1D, 0xBF, 0x0A, 0x01, 0x69, 0xB6, 0xA2, 0x8A, + 0xD6, 0x62, 0xA4, 0xD1, 0x8E, 0x73, 0xAF, 0xA3, + 0x2D, 0x77, 0x9D, 0x59, 0x18, 0xD0, 0x8B, 0xC8, + 0x85, 0x8F, 0x4D, 0xCE, 0xF9, 0x7C, 0x2A, 0x24, + 0x85, 0x5E, 0x6E, 0xEB, 0x22, 0xB3, 0xB2, 0xE5 +}; +static const u8 dh_group22_prime[] = { + 0xB1, 0x0B, 0x8F, 0x96, 0xA0, 0x80, 0xE0, 0x1D, + 0xDE, 0x92, 0xDE, 0x5E, 0xAE, 0x5D, 0x54, 0xEC, + 0x52, 0xC9, 0x9F, 0xBC, 0xFB, 0x06, 0xA3, 0xC6, + 0x9A, 0x6A, 0x9D, 0xCA, 0x52, 0xD2, 0x3B, 0x61, + 0x60, 0x73, 0xE2, 0x86, 0x75, 0xA2, 0x3D, 0x18, + 0x98, 0x38, 0xEF, 0x1E, 0x2E, 0xE6, 0x52, 0xC0, + 0x13, 0xEC, 0xB4, 0xAE, 0xA9, 0x06, 0x11, 0x23, + 0x24, 0x97, 0x5C, 0x3C, 0xD4, 0x9B, 0x83, 0xBF, + 0xAC, 0xCB, 0xDD, 0x7D, 0x90, 0xC4, 0xBD, 0x70, + 0x98, 0x48, 0x8E, 0x9C, 0x21, 0x9A, 0x73, 0x72, + 0x4E, 0xFF, 0xD6, 0xFA, 0xE5, 0x64, 0x47, 0x38, + 0xFA, 0xA3, 0x1A, 0x4F, 0xF5, 0x5B, 0xCC, 0xC0, + 0xA1, 0x51, 0xAF, 0x5F, 0x0D, 0xC8, 0xB4, 0xBD, + 0x45, 0xBF, 0x37, 0xDF, 0x36, 0x5C, 0x1A, 0x65, + 0xE6, 0x8C, 0xFD, 0xA7, 0x6D, 0x4D, 0xA7, 0x08, + 0xDF, 0x1F, 0xB2, 0xBC, 0x2E, 0x4A, 0x43, 0x71 +}; +static const u8 dh_group22_order[] = { + 0xF5, 0x18, 0xAA, 0x87, 0x81, 0xA8, 0xDF, 0x27, + 0x8A, 0xBA, 0x4E, 0x7D, 0x64, 0xB7, 0xCB, 0x9D, + 0x49, 0x46, 0x23, 0x53 +}; + +/* + * RFC 5114, 2.2. + * Group 23 - 2048-bit MODP Group with 224-bit Prime Order Subgroup + */ +static const u8 dh_group23_generator[] = { + 0xAC, 0x40, 0x32, 0xEF, 0x4F, 0x2D, 0x9A, 0xE3, + 0x9D, 0xF3, 0x0B, 0x5C, 0x8F, 0xFD, 0xAC, 0x50, + 0x6C, 0xDE, 0xBE, 0x7B, 0x89, 0x99, 0x8C, 0xAF, + 0x74, 0x86, 0x6A, 0x08, 0xCF, 0xE4, 0xFF, 0xE3, + 0xA6, 0x82, 0x4A, 0x4E, 0x10, 0xB9, 0xA6, 0xF0, + 0xDD, 0x92, 0x1F, 0x01, 0xA7, 0x0C, 0x4A, 0xFA, + 0xAB, 0x73, 0x9D, 0x77, 0x00, 0xC2, 0x9F, 0x52, + 0xC5, 0x7D, 0xB1, 0x7C, 0x62, 0x0A, 0x86, 0x52, + 0xBE, 0x5E, 0x90, 0x01, 0xA8, 0xD6, 0x6A, 0xD7, + 0xC1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4A, + 0xF4, 0xD0, 0x27, 0x27, 0x5A, 0xC1, 0x34, 0x8B, + 0xB8, 0xA7, 0x62, 0xD0, 0x52, 0x1B, 0xC9, 0x8A, + 0xE2, 0x47, 0x15, 0x04, 0x22, 0xEA, 0x1E, 0xD4, + 0x09, 0x93, 0x9D, 0x54, 0xDA, 0x74, 0x60, 0xCD, + 0xB5, 0xF6, 0xC6, 0xB2, 0x50, 0x71, 0x7C, 0xBE, + 0xF1, 0x80, 0xEB, 0x34, 0x11, 0x8E, 0x98, 0xD1, + 0x19, 0x52, 0x9A, 0x45, 0xD6, 0xF8, 0x34, 0x56, + 0x6E, 0x30, 0x25, 0xE3, 0x16, 0xA3, 0x30, 0xEF, + 0xBB, 0x77, 0xA8, 0x6F, 0x0C, 0x1A, 0xB1, 0x5B, + 0x05, 0x1A, 0xE3, 0xD4, 0x28, 0xC8, 0xF8, 0xAC, + 0xB7, 0x0A, 0x81, 0x37, 0x15, 0x0B, 0x8E, 0xEB, + 0x10, 0xE1, 0x83, 0xED, 0xD1, 0x99, 0x63, 0xDD, + 0xD9, 0xE2, 0x63, 0xE4, 0x77, 0x05, 0x89, 0xEF, + 0x6A, 0xA2, 0x1E, 0x7F, 0x5F, 0x2F, 0xF3, 0x81, + 0xB5, 0x39, 0xCC, 0xE3, 0x40, 0x9D, 0x13, 0xCD, + 0x56, 0x6A, 0xFB, 0xB4, 0x8D, 0x6C, 0x01, 0x91, + 0x81, 0xE1, 0xBC, 0xFE, 0x94, 0xB3, 0x02, 0x69, + 0xED, 0xFE, 0x72, 0xFE, 0x9B, 0x6A, 0xA4, 0xBD, + 0x7B, 0x5A, 0x0F, 0x1C, 0x71, 0xCF, 0xFF, 0x4C, + 0x19, 0xC4, 0x18, 0xE1, 0xF6, 0xEC, 0x01, 0x79, + 0x81, 0xBC, 0x08, 0x7F, 0x2A, 0x70, 0x65, 0xB3, + 0x84, 0xB8, 0x90, 0xD3, 0x19, 0x1F, 0x2B, 0xFA +}; +static const u8 dh_group23_prime[] = { + 0xAD, 0x10, 0x7E, 0x1E, 0x91, 0x23, 0xA9, 0xD0, + 0xD6, 0x60, 0xFA, 0xA7, 0x95, 0x59, 0xC5, 0x1F, + 0xA2, 0x0D, 0x64, 0xE5, 0x68, 0x3B, 0x9F, 0xD1, + 0xB5, 0x4B, 0x15, 0x97, 0xB6, 0x1D, 0x0A, 0x75, + 0xE6, 0xFA, 0x14, 0x1D, 0xF9, 0x5A, 0x56, 0xDB, + 0xAF, 0x9A, 0x3C, 0x40, 0x7B, 0xA1, 0xDF, 0x15, + 0xEB, 0x3D, 0x68, 0x8A, 0x30, 0x9C, 0x18, 0x0E, + 0x1D, 0xE6, 0xB8, 0x5A, 0x12, 0x74, 0xA0, 0xA6, + 0x6D, 0x3F, 0x81, 0x52, 0xAD, 0x6A, 0xC2, 0x12, + 0x90, 0x37, 0xC9, 0xED, 0xEF, 0xDA, 0x4D, 0xF8, + 0xD9, 0x1E, 0x8F, 0xEF, 0x55, 0xB7, 0x39, 0x4B, + 0x7A, 0xD5, 0xB7, 0xD0, 0xB6, 0xC1, 0x22, 0x07, + 0xC9, 0xF9, 0x8D, 0x11, 0xED, 0x34, 0xDB, 0xF6, + 0xC6, 0xBA, 0x0B, 0x2C, 0x8B, 0xBC, 0x27, 0xBE, + 0x6A, 0x00, 0xE0, 0xA0, 0xB9, 0xC4, 0x97, 0x08, + 0xB3, 0xBF, 0x8A, 0x31, 0x70, 0x91, 0x88, 0x36, + 0x81, 0x28, 0x61, 0x30, 0xBC, 0x89, 0x85, 0xDB, + 0x16, 0x02, 0xE7, 0x14, 0x41, 0x5D, 0x93, 0x30, + 0x27, 0x82, 0x73, 0xC7, 0xDE, 0x31, 0xEF, 0xDC, + 0x73, 0x10, 0xF7, 0x12, 0x1F, 0xD5, 0xA0, 0x74, + 0x15, 0x98, 0x7D, 0x9A, 0xDC, 0x0A, 0x48, 0x6D, + 0xCD, 0xF9, 0x3A, 0xCC, 0x44, 0x32, 0x83, 0x87, + 0x31, 0x5D, 0x75, 0xE1, 0x98, 0xC6, 0x41, 0xA4, + 0x80, 0xCD, 0x86, 0xA1, 0xB9, 0xE5, 0x87, 0xE8, + 0xBE, 0x60, 0xE6, 0x9C, 0xC9, 0x28, 0xB2, 0xB9, + 0xC5, 0x21, 0x72, 0xE4, 0x13, 0x04, 0x2E, 0x9B, + 0x23, 0xF1, 0x0B, 0x0E, 0x16, 0xE7, 0x97, 0x63, + 0xC9, 0xB5, 0x3D, 0xCF, 0x4B, 0xA8, 0x0A, 0x29, + 0xE3, 0xFB, 0x73, 0xC1, 0x6B, 0x8E, 0x75, 0xB9, + 0x7E, 0xF3, 0x63, 0xE2, 0xFF, 0xA3, 0x1F, 0x71, + 0xCF, 0x9D, 0xE5, 0x38, 0x4E, 0x71, 0xB8, 0x1C, + 0x0A, 0xC4, 0xDF, 0xFE, 0x0C, 0x10, 0xE6, 0x4F +}; +static const u8 dh_group23_order[] = { + 0x80, 0x1C, 0x0D, 0x34, 0xC5, 0x8D, 0x93, 0xFE, + 0x99, 0x71, 0x77, 0x10, 0x1F, 0x80, 0x53, 0x5A, + 0x47, 0x38, 0xCE, 0xBC, 0xBF, 0x38, 0x9A, 0x99, + 0xB3, 0x63, 0x71, 0xEB +}; + +/* + * RFC 5114, 2.3. + * Group 24 - 2048-bit MODP Group with 256-bit Prime Order Subgroup + */ +static const u8 dh_group24_generator[] = { + 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B, + 0x2E, 0x77, 0x50, 0x66, 0x60, 0xED, 0xBD, 0x48, + 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54, + 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25, + 0x10, 0xDB, 0xC1, 0x50, 0x77, 0xBE, 0x46, 0x3F, + 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55, + 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1, + 0xBC, 0x37, 0x73, 0xBF, 0x7E, 0x8C, 0x6F, 0x62, + 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18, + 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65, + 0x01, 0x96, 0xF9, 0x31, 0xC7, 0x7A, 0x57, 0xF2, + 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B, + 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62, + 0x8A, 0xC3, 0x76, 0xD2, 0x82, 0xD6, 0xED, 0x38, + 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83, + 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93, + 0xB5, 0x04, 0x5A, 0xF2, 0x76, 0x71, 0x64, 0xE1, + 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55, + 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80, + 0xD0, 0x52, 0xB9, 0x85, 0xD1, 0x82, 0xEA, 0x0A, + 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14, + 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9, + 0xB7, 0xD2, 0xBB, 0xD2, 0xDF, 0x01, 0x61, 0x99, + 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15, + 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37, + 0x7F, 0xD0, 0x28, 0x37, 0x0D, 0xF9, 0x2B, 0x52, + 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6, + 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3, + 0x2F, 0x63, 0x07, 0x84, 0x90, 0xF0, 0x0E, 0xF8, + 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51, + 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82, + 0x66, 0x4B, 0x4C, 0x0F, 0x6C, 0xC4, 0x16, 0x59 +}; +static const u8 dh_group24_prime[] = { + 0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C, + 0xFF, 0xBB, 0xD1, 0x9C, 0x65, 0x19, 0x59, 0x99, + 0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2, + 0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00, + 0xE0, 0x0D, 0xF8, 0xF1, 0xD6, 0x19, 0x57, 0xD4, + 0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30, + 0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA, + 0x3B, 0xF4, 0x29, 0x6D, 0x83, 0x0E, 0x9A, 0x7C, + 0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD, + 0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED, + 0x91, 0xF9, 0xE6, 0x72, 0x5B, 0x47, 0x58, 0xC0, + 0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B, + 0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88, + 0xB9, 0x41, 0xF5, 0x4E, 0xB1, 0xE5, 0x9B, 0xB8, + 0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C, + 0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76, + 0xB6, 0x3A, 0xCA, 0xE1, 0xCA, 0xA6, 0xB7, 0x90, + 0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E, + 0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB, + 0x3A, 0xD8, 0x34, 0x77, 0x96, 0x52, 0x4D, 0x8E, + 0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9, + 0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25, + 0x1C, 0xCA, 0xCB, 0x83, 0xE6, 0xB4, 0x86, 0xF6, + 0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26, + 0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56, + 0xDE, 0xD4, 0x01, 0x0A, 0xBD, 0x0B, 0xE6, 0x21, + 0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3, + 0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03, + 0xA4, 0xB5, 0x43, 0x30, 0xC1, 0x98, 0xAF, 0x12, + 0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F, + 0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA, + 0xDB, 0x09, 0x4A, 0xE9, 0x1E, 0x1A, 0x15, 0x97 +}; + +static const u8 dh_group24_order[] = { + 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97, + 0xB4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9D, 0xA2, + 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B, + 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3 +}; + #endif /* ALL_DH_GROUPS */ - -#define DH_GROUP(id) \ +#define DH_GROUP(id,safe) \ { id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \ -dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) } - +dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \ +dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe } -static struct dh_group dh_groups[] = { - DH_GROUP(5), +static const struct dh_group dh_groups[] = { + DH_GROUP(5, 1), #ifdef ALL_DH_GROUPS - DH_GROUP(1), - DH_GROUP(2), - DH_GROUP(14), - DH_GROUP(15), - DH_GROUP(16), - DH_GROUP(17), - DH_GROUP(18) + DH_GROUP(1, 1), + DH_GROUP(2, 1), + DH_GROUP(14, 1), + DH_GROUP(15, 1), + DH_GROUP(16, 1), + DH_GROUP(17, 1), + DH_GROUP(18, 1), + DH_GROUP(22, 0), + DH_GROUP(23, 0), + DH_GROUP(24, 0) #endif /* ALL_DH_GROUPS */ }; @@ -583,8 +1234,11 @@ dh_init(const struct dh_group *dh, struct wpabuf **priv) pv_len = dh->prime_len; pv = wpabuf_alloc(pv_len); - if (pv == NULL) + if (pv == NULL) { + wpabuf_free(*priv); + *priv = NULL; return NULL; + } if (crypto_mod_exp(dh->generator, dh->generator_len, wpabuf_head(*priv), wpabuf_len(*priv), diff --git a/components/wpa_supplicant/src/crypto/dh_groups.h b/components/wpa_supplicant/src/crypto/dh_groups.h index 5c61539b70..6ce4a2a185 100644 --- a/components/wpa_supplicant/src/crypto/dh_groups.h +++ b/components/wpa_supplicant/src/crypto/dh_groups.h @@ -21,6 +21,9 @@ struct dh_group { size_t generator_len; const u8 *prime; size_t prime_len; + const u8 *order; + size_t order_len; + unsigned int safe_prime:1; }; const struct dh_group * dh_groups_get(int id); diff --git a/components/wpa_supplicant/src/crypto/sha256.c b/components/wpa_supplicant/src/crypto/sha256.c index 3e955b4d47..6534408d34 100644 --- a/components/wpa_supplicant/src/crypto/sha256.c +++ b/components/wpa_supplicant/src/crypto/sha256.c @@ -42,10 +42,10 @@ * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (32 bytes) + * Returns: 0 on success, -1 on failure */ -void -hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) +int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) { unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ unsigned char tk[32]; @@ -57,12 +57,13 @@ hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ - return; + return -1; } /* if key is longer than 64 bytes reset it to key = SHA256(key) */ if (key_len > 64) { - sha256_vector(1, &key, &key_len, tk); + if (sha256_vector(1, &key, &key_len, tk) < 0) + return -1; key = tk; key_len = 32; } @@ -90,7 +91,8 @@ hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } - sha256_vector(1 + num_elem, _addr, _len, mac); + if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0) + return -1; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); @@ -103,10 +105,9 @@ hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, _len[0] = 64; _addr[1] = mac; _len[1] = SHA256_MAC_LEN; - sha256_vector(2, _addr, _len, mac); + return sha256_vector(2, _addr, _len, mac); } - /** * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) * @key: Key for HMAC operations @@ -115,14 +116,13 @@ hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, * @data_len: Length of the data area * @mac: Buffer for the hash (20 bytes) */ -void +void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, - size_t data_len, u8 *mac) + size_t data_len, u8 *mac) { - hmac_sha256_vector(key, key_len, 1, &data, &data_len, 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 @@ -132,13 +132,37 @@ hmac_sha256(const u8 *key, size_t key_len, const u8 *data, * @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. */ -void -sha256_prf(const u8 *key, size_t key_len, const char *label, +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; @@ -146,6 +170,7 @@ sha256_prf(const u8 *key, size_t key_len, const char *label, 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; @@ -156,20 +181,37 @@ sha256_prf(const u8 *key, size_t key_len, const char *label, addr[3] = length_le; len[3] = sizeof(length_le); - WPA_PUT_LE16(length_le, buf_len * 8); + 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) { - hmac_sha256_vector(key, key_len, 4, addr, len, - &buf[pos]); + if (hmac_sha256_vector(key, key_len, 4, addr, len, + &buf[pos]) < 0) + return -1; pos += SHA256_MAC_LEN; } else { - hmac_sha256_vector(key, key_len, 4, addr, len, hash); + 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.h b/components/wpa_supplicant/src/crypto/sha256.h index 0515e24095..aad9434df9 100644 --- a/components/wpa_supplicant/src/crypto/sha256.h +++ b/components/wpa_supplicant/src/crypto/sha256.h @@ -17,12 +17,15 @@ #define SHA256_MAC_LEN 32 -void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, +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, size_t data_len, u8 *mac); -void sha256_prf(const u8 *key, size_t key_len, const char *label, +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, const char *label, const u8 *seed, size_t seed_len, diff --git a/components/wpa_supplicant/src/utils/common.h b/components/wpa_supplicant/src/utils/common.h index 7a44beda8a..57f3d3c297 100644 --- a/components/wpa_supplicant/src/utils/common.h +++ b/components/wpa_supplicant/src/utils/common.h @@ -454,4 +454,6 @@ void * __hide_aliasing_typecast(void *foo); #define WPA_MEM_DEFINED(ptr, len) do { } while (0) #endif /* CONFIG_VALGRIND */ +#define IANA_SECP256R1 19 + #endif /* COMMON_H */ diff --git a/components/wpa_supplicant/test/CMakeLists.txt b/components/wpa_supplicant/test/CMakeLists.txt index 0fd0a625ce..e64539d3e0 100644 --- a/components/wpa_supplicant/test/CMakeLists.txt +++ b/components/wpa_supplicant/test/CMakeLists.txt @@ -10,3 +10,4 @@ file(MD5 ${esp_supplicant_dir}/src/esp_supplicant/esp_wifi_driver.h WIFI_SUPPLIC string(SUBSTRING "${WIFI_SUPPLICANT_MD5}" 0 7 WIFI_SUPPLICANT_MD5) add_definitions(-DWIFI_SUPPLICANT_MD5=\"${WIFI_SUPPLICANT_MD5}\") +add_definitions(-DCONFIG_WPA3_SAE) diff --git a/components/wpa_supplicant/test/component.mk b/components/wpa_supplicant/test/component.mk index cfec44f292..21e03c8dbe 100644 --- a/components/wpa_supplicant/test/component.mk +++ b/components/wpa_supplicant/test/component.mk @@ -8,4 +8,4 @@ COMPONENT_SRCDIRS := . COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive WIFI_SUPPLICANT_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h | cut -c 1-7)\" -CFLAGS+=-DWIFI_SUPPLICANT_MD5=$(WIFI_SUPPLICANT_MD5_VAL) +CFLAGS+=-DWIFI_SUPPLICANT_MD5=$(WIFI_SUPPLICANT_MD5_VAL) -DCONFIG_WPA3_SAE diff --git a/components/wpa_supplicant/test/test_sae.c b/components/wpa_supplicant/test/test_sae.c new file mode 100644 index 0000000000..b87783d5fc --- /dev/null +++ b/components/wpa_supplicant/test/test_sae.c @@ -0,0 +1,270 @@ +// 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. + +#ifdef CONFIG_WPA3_SAE + +#include +#include +#include +#include +#include +#include "unity.h" +#include +#include "crypto/crypto.h" +#include "../src/common/sae.h" +#include "utils/wpabuf.h" + +typedef struct crypto_bignum crypto_bignum; + +static struct wpabuf *wpabuf_alloc2(size_t len) +{ + struct wpabuf *buf = (struct wpabuf *)os_zalloc(sizeof(struct wpabuf) + len); + if (buf == NULL) + return NULL; + buf->size = len; + return buf; +} + +/** + * * wpabuf_free - Free a wpabuf + * * @buf: wpabuf buffer + * */ +void wpabuf_free2(struct wpabuf *buf) +{ + if (buf == NULL) + return; + os_free(buf->ext_data); + os_free(buf); +} + + + + +TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") +{ + ESP_LOGI("SAE Test", "### Beginning SAE init and deinit ###"); + { + /* Test init and deinit*/ + struct sae_data sae; + memset(&sae, 0, sizeof(sae)); + TEST_ASSERT(sae_set_group(&sae, IANA_SECP256R1) == 0); + sae_clear_temp_data(&sae); + sae_clear_data(&sae); + + } + ESP_LOGI("SAE Test", "=========== Complete ============"); + + ESP_LOGI("SAE Test", "### Beginning SAE commit msg formation and parsing ###"); + { + /* Test SAE commit msg formation and parsing*/ + struct sae_data sae; + u8 addr1[ETH_ALEN] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11}; + u8 addr2[ETH_ALEN] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + u8 pwd[] = "ESP32-WPA3"; + struct wpabuf *buf; + int default_groups[] = { IANA_SECP256R1, 0 }; + + memset(&sae, 0, sizeof(sae)); + + TEST_ASSERT(sae_set_group(&sae, IANA_SECP256R1) == 0); + + TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd, strlen((const char *)pwd), NULL, &sae) == 0); + + buf = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + + TEST_ASSERT( buf != NULL); + + sae_write_commit(&sae, buf, NULL);// No anti-clogging token + + /* Parsing commit created by self will be detected as reflection attack*/ + TEST_ASSERT(sae_parse_commit(&sae, + wpabuf_mhead(buf), buf->used, NULL, 0, default_groups) == SAE_SILENTLY_DISCARD); + + wpabuf_free2(buf); + sae_clear_temp_data(&sae); + sae_clear_data(&sae); + + } + ESP_LOGI("SAE Test", "=========== Complete ============"); + + ESP_LOGI("SAE Test", "### Beginning SAE handshake ###"); + { + /* SAE handshake*/ + struct sae_data sae1; // STA1 data + struct sae_data sae2; // STA2 data + u8 addr1[ETH_ALEN] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11}; + u8 addr2[ETH_ALEN] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + u8 pwd[] = "ESP32-WPA3"; + + memset(&sae1, 0, sizeof(sae1)); + memset(&sae2, 0, sizeof(sae2)); + + struct wpabuf *buf1, *buf2, *buf3, *buf4; + int default_groups[] = { IANA_SECP256R1, 0 }; + + TEST_ASSERT(sae_set_group(&sae1, IANA_SECP256R1) == 0); + TEST_ASSERT(sae_set_group(&sae2, IANA_SECP256R1) == 0); + + /* STA1 prepares for commit*/ + TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd, strlen((const char *)pwd), NULL, &sae1) == 0); + + /* STA2 prepares for commit*/ + TEST_ASSERT(sae_prepare_commit(addr2, addr1, pwd, strlen((const char *)pwd), NULL, &sae2) == 0); + + /* STA1 creates commit msg buffer*/ + buf1 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf1 != NULL); + sae_write_commit(&sae1, buf1, NULL);// No anti-clogging token + ESP_LOG_BUFFER_HEXDUMP("SAE: Commit1", wpabuf_mhead_u8(buf1), wpabuf_len(buf1), ESP_LOG_INFO); + + + /* STA2 creates commit msg buffer*/ + buf2 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf2 != NULL); + sae_write_commit(&sae2, buf2, NULL);// No anti-clogging token + ESP_LOG_BUFFER_HEXDUMP("SAE: Commit2", wpabuf_mhead_u8(buf2), wpabuf_len(buf2), ESP_LOG_INFO); + + sae1.state = SAE_COMMITTED; + sae2.state = SAE_COMMITTED; + + /* STA1 parses STA2 commit*/ + TEST_ASSERT(sae_parse_commit(&sae1, + wpabuf_mhead(buf2), buf2->used, NULL, 0, default_groups) == 0); + + /* STA2 parses STA1 commit*/ + TEST_ASSERT(sae_parse_commit(&sae2, + wpabuf_mhead(buf1), buf1->used, NULL, 0, default_groups) == 0); + + /* STA1 processes commit*/ + TEST_ASSERT(sae_process_commit(&sae1) == 0); + + /* STA2 processes commit*/ + TEST_ASSERT(sae_process_commit(&sae2) == 0); + + /* STA1 creates confirm msg buffer*/ + buf3 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf3 != NULL); + sae_write_confirm(&sae1, buf3); + ESP_LOG_BUFFER_HEXDUMP("SAE: Confirm1", wpabuf_mhead_u8(buf3), wpabuf_len(buf3), ESP_LOG_INFO); + + /* STA2 creates confirm msg buffer*/ + buf4 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf3 != NULL); + sae_write_confirm(&sae2, buf4); + ESP_LOG_BUFFER_HEXDUMP("SAE: Confirm2", wpabuf_mhead_u8(buf4), wpabuf_len(buf4), ESP_LOG_INFO); + + /* STA1 checks confirm from STA2*/ + TEST_ASSERT(sae_check_confirm(&sae1, wpabuf_mhead(buf4), buf4->used) == 0); + + /* STA2 checks confirm from STA1*/ + TEST_ASSERT(sae_check_confirm(&sae2, wpabuf_mhead(buf3), buf3->used) == 0); + + ESP_LOG_BUFFER_HEXDUMP("SAE: PMK1", sae1.pmk, SAE_PMK_LEN, ESP_LOG_INFO); + ESP_LOG_BUFFER_HEXDUMP("SAE: PMK2", sae2.pmk, SAE_PMK_LEN, ESP_LOG_INFO); + + wpabuf_free2(buf1); + wpabuf_free2(buf2); + wpabuf_free2(buf3); + wpabuf_free2(buf4); + sae_clear_temp_data(&sae1); + sae_clear_temp_data(&sae2); + sae_clear_data(&sae1); + sae_clear_data(&sae2); + + } + ESP_LOGI("SAE Test", "=========== Complete ============"); + + ESP_LOGI("SAE Test", "### SAE handshake negative testcase. ###"); + { + /* SAE handshake failure when different passwords are used.*/ + struct sae_data sae1; // STA1 data + struct sae_data sae2; // STA2 data + u8 addr1[ETH_ALEN] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11}; + u8 addr2[ETH_ALEN] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + u8 pwd1[] = "abcd1234"; + u8 pwd2[] = "wxyz5678"; + + memset(&sae1, 0, sizeof(sae1)); + memset(&sae2, 0, sizeof(sae2)); + + struct wpabuf *buf1, *buf2, *buf3, *buf4; + int default_groups[] = { IANA_SECP256R1, 0 }; + + TEST_ASSERT(sae_set_group(&sae1, IANA_SECP256R1) == 0); + TEST_ASSERT(sae_set_group(&sae2, IANA_SECP256R1) == 0); + + /* STA1 prepares for commit*/ + TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd1, strlen((const char *)pwd), NULL, &sae1) == 0); + + /* STA2 prepares for commit*/ + TEST_ASSERT(sae_prepare_commit(addr2, addr1, pwd2, strlen((const char *)pwd), NULL, &sae2) == 0); + + /* STA1 creates commit msg buffer*/ + buf1 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf1 != NULL); + sae_write_commit(&sae1, buf1, NULL);// No anti-clogging token + + /* STA2 creates commit msg buffer*/ + buf2 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf2 != NULL); + sae_write_commit(&sae2, buf2, NULL);// No anti-clogging token + + sae1.state = SAE_COMMITTED; + sae2.state = SAE_COMMITTED; + + /* STA1 parses STA2 commit*/ + TEST_ASSERT(sae_parse_commit(&sae1, + wpabuf_mhead(buf2), buf2->used, NULL, 0, default_groups) == 0); + + /* STA2 parses STA1 commit*/ + TEST_ASSERT(sae_parse_commit(&sae2, + wpabuf_mhead(buf1), buf1->used, NULL, 0, default_groups) == 0); + + /* STA1 processes commit*/ + TEST_ASSERT(sae_process_commit(&sae1) == 0); + + /* STA2 processes commit*/ + TEST_ASSERT(sae_process_commit(&sae2) == 0); + + /* STA1 creates confirm msg buffer*/ + buf3 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf3 != NULL); + sae_write_confirm(&sae1, buf3); + + /* STA2 creates confirm msg buffer*/ + buf4 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); + TEST_ASSERT( buf3 != NULL); + sae_write_confirm(&sae2, buf4); + + /* STA1 checks confirm from STA2 and the check fails*/ + TEST_ASSERT(sae_check_confirm(&sae1, wpabuf_mhead(buf4), buf4->used) != 0); + + /* STA2 checks confirm from STA1 and the check fails*/ + TEST_ASSERT(sae_check_confirm(&sae2, wpabuf_mhead(buf3), buf3->used) != 0); + + wpabuf_free2(buf1); + wpabuf_free2(buf2); + wpabuf_free2(buf3); + wpabuf_free2(buf4); + sae_clear_temp_data(&sae1); + sae_clear_temp_data(&sae2); + sae_clear_data(&sae1); + sae_clear_data(&sae2); + + } + ESP_LOGI("SAE Test", "=========== Complete ============"); + +} + +#endif /* CONFIG_WPA3_SAE */ From 6b76228fcbc7c6a828cf972edb68aa36dcd4330c Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Wed, 29 Apr 2020 18:45:29 +0530 Subject: [PATCH 09/16] wpa_supplicant: Add SAE handshake support for WPA3-PSK Under WPA3-Personal, SAE authentication is used to derive PMK which is more secure and immune to offline dictionary attacks. 1. Add modules to generate SAE commit/confirm for the handshake 2. Add modules that build and parse SAE data in Auth frames 3. Add WPA3 association and key mgmt definitions 4. Invert y-bit while solving for ECC co-ordinate - Once an X co-ordinate is obtained, solving for Y co-ordinate using an elliptical curve equation results in 2 possible values, Y and (P - Y), where p is the prime number. The co-ordinates are used for deriving keys in SAE handshake. As par the 802.11 spec if LSB of X is same as LSB of Y then Y is chosen, (P - Y) otherwise. This is not what is implemented, so fix this behavior to obtain the correct Y co-ordinate. --- components/esp_wifi/include/esp_wifi_types.h | 1 + components/wpa_supplicant/CMakeLists.txt | 1 + .../src/common/ieee802_11_defs.h | 27 ++ components/wpa_supplicant/src/common/sae.c | 259 ++++++++++++++---- components/wpa_supplicant/src/common/sae.h | 21 +- .../wpa_supplicant/src/common/wpa_common.c | 4 + .../wpa_supplicant/src/common/wpa_common.h | 1 + .../src/crypto/crypto_mbedtls.c | 10 +- .../src/esp_supplicant/esp_wifi_driver.h | 8 +- .../src/esp_supplicant/esp_wpa3.c | 165 +++++++++++ .../src/esp_supplicant/esp_wpa3_i.h | 23 ++ .../src/esp_supplicant/esp_wpa_main.c | 6 +- components/wpa_supplicant/src/rsn_supp/wpa.c | 6 + .../wpa_supplicant/src/rsn_supp/wpa_ie.c | 4 + 14 files changed, 464 insertions(+), 72 deletions(-) create mode 100644 components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c create mode 100644 components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index a07cfde080..cdffd6a901 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -56,6 +56,7 @@ typedef enum { WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */ WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */ WIFI_AUTH_WPA2_ENTERPRISE, /**< authenticate mode : WPA2_ENTERPRISE */ + WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */ WIFI_AUTH_MAX } wifi_auth_mode_t; diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index eed582d851..9092825281 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -50,6 +50,7 @@ set(srcs "port/os_xtensa.c" "src/esp_supplicant/esp_wpa_main.c" "src/esp_supplicant/esp_wpas_glue.c" "src/esp_supplicant/esp_wps.c" + "src/esp_supplicant/esp_wpa3.c" "src/rsn_supp/pmksa_cache.c" "src/rsn_supp/wpa.c" "src/rsn_supp/wpa_ie.c" diff --git a/components/wpa_supplicant/src/common/ieee802_11_defs.h b/components/wpa_supplicant/src/common/ieee802_11_defs.h index 209ae93622..9260d22f0b 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_defs.h +++ b/components/wpa_supplicant/src/common/ieee802_11_defs.h @@ -159,6 +159,7 @@ #define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95 #define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99 #define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104 +#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ #define WLAN_REASON_UNSPECIFIED 1 @@ -225,6 +226,32 @@ #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 #define WLAN_EID_MMIE 76 #define WLAN_EID_VENDOR_SPECIFIC 221 +#define WLAN_EID_CAG_NUMBER 237 +#define WLAN_EID_AP_CSN 239 +#define WLAN_EID_FILS_INDICATION 240 +#define WLAN_EID_DILS 241 +#define WLAN_EID_FRAGMENT 242 +#define WLAN_EID_EXTENSION 255 + +/* Element ID Extension (EID 255) values */ +#define WLAN_EID_EXT_ASSOC_DELAY_INFO 1 +#define WLAN_EID_EXT_FILS_REQ_PARAMS 2 +#define WLAN_EID_EXT_FILS_KEY_CONFIRM 3 +#define WLAN_EID_EXT_FILS_SESSION 4 +#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5 +#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6 +#define WLAN_EID_EXT_KEY_DELIVERY 7 +#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8 +#define WLAN_EID_EXT_FTM_SYNC_INFO 9 +#define WLAN_EID_EXT_EXTENDED_REQUEST 10 +#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11 +#define WLAN_EID_EXT_FILS_PUBLIC_KEY 12 +#define WLAN_EID_EXT_FILS_NONCE 13 +#define WLAN_EID_EXT_FUTURE_CHANNEL_GUIDANCE 14 +#define WLAN_EID_EXT_OWE_DH_PARAM 32 +#define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33 +#define WLAN_EID_EXT_HE_CAPABILITIES 35 +#define WLAN_EID_EXT_HE_OPERATION 36 /* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ diff --git a/components/wpa_supplicant/src/common/sae.c b/components/wpa_supplicant/src/common/sae.c index ebae4c41ee..3283c334fe 100644 --- a/components/wpa_supplicant/src/common/sae.c +++ b/components/wpa_supplicant/src/common/sae.c @@ -35,18 +35,20 @@ void bin_clear_free(void *bin, size_t len) } } -int sae_set_group(struct sae_data *sae, u16 group) +int sae_set_group(struct sae_data *sae, int group) { - struct sae_temporary_data *tmp; + struct sae_temporary_data *tmp; - sae_clear_data(sae); - tmp = sae->tmp = os_zalloc(sizeof(*tmp)); - if (tmp == NULL) - return -1; + sae_clear_data(sae); + tmp = sae->tmp = os_zalloc(sizeof(*tmp)); + if (tmp == NULL) + return -1; - /* First, check if this is an ECC group */ + /* First, check if this is an ECC group */ tmp->ec = crypto_ec_init(group); if (tmp->ec) { + wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d", + group); sae->group = group; tmp->prime_len = crypto_ec_prime_len(tmp->ec); tmp->prime = crypto_ec_get_prime(tmp->ec); @@ -57,6 +59,8 @@ int sae_set_group(struct sae_data *sae, u16 group) /* Not an ECC group, check FFC */ tmp->dh = dh_groups_get(group); if (tmp->dh) { + wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d", + group); sae->group = group; tmp->prime_len = tmp->dh->prime_len; if (tmp->prime_len > SAE_MAX_PRIME_LEN) { @@ -84,6 +88,8 @@ int sae_set_group(struct sae_data *sae, u16 group) } /* Unsupported group */ + wpa_printf(MSG_DEBUG, + "SAE: Group %d not supported by the crypto library", group); return -1; } @@ -105,6 +111,7 @@ void sae_clear_temp_data(struct sae_data *sae) crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0); crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0); wpabuf_free(tmp->anti_clogging_token); + os_free(tmp->pw_id); bin_clear_free(tmp, sizeof(*tmp)); sae->tmp = NULL; } @@ -423,12 +430,13 @@ static int get_random_qr_qnr(const u8 *prime, size_t prime_len, static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, const u8 *addr2, const u8 *password, - size_t password_len) + size_t password_len, const char *identifier) { u8 counter, k = 40; u8 addrs[2 * ETH_ALEN]; - const u8 *addr[2]; - size_t len[2]; + const u8 *addr[3]; + size_t len[3]; + size_t num_elem; u8 dummy_password[32]; size_t dummy_password_len; int pwd_seed_odd = 0; @@ -460,10 +468,13 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", password, password_len); + if (identifier) + wpa_printf(MSG_DEBUG, "SAE: password identifier: %s", + identifier); /* * H(salt, ikm) = HMAC-SHA256(salt, ikm) - * base = password + * base = password [|| identifier] * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), * base || counter) */ @@ -471,8 +482,15 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, addr[0] = password; len[0] = password_len; - addr[1] = &counter; - len[1] = sizeof(counter); + num_elem = 1; + if (identifier) { + addr[num_elem] = (const u8 *) identifier; + len[num_elem] = os_strlen(identifier); + num_elem++; + } + addr[num_elem] = &counter; + len[num_elem] = sizeof(counter); + num_elem++; /* * Continue for at least k iterations to protect against side-channel @@ -490,8 +508,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, } wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); - if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, - pwd_seed) < 0) + if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, + addr, len, pwd_seed) < 0) break; res = sae_test_pwd_seed_ecc(sae, pwd_seed, @@ -516,7 +534,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, crypto_bignum_deinit(x_cand, 1); } } - + if (!x) { wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE"); res = -1; @@ -549,12 +567,13 @@ fail: static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, const u8 *addr2, const u8 *password, - size_t password_len) + size_t password_len, const char *identifier) { u8 counter; u8 addrs[2 * ETH_ALEN]; - const u8 *addr[2]; - size_t len[2]; + const u8 *addr[3]; + size_t len[3]; + size_t num_elem; int found = 0; if (sae->tmp->pwe_ffc == NULL) { @@ -569,14 +588,21 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, /* * H(salt, ikm) = HMAC-SHA256(salt, ikm) * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), - * password || counter) + * password [|| identifier] || counter) */ sae_pwd_seed_key(addr1, addr2, addrs); addr[0] = password; len[0] = password_len; - addr[1] = &counter; - len[1] = sizeof(counter); + num_elem = 1; + if (identifier) { + addr[num_elem] = (const u8 *) identifier; + len[num_elem] = os_strlen(identifier); + num_elem++; + } + addr[num_elem] = &counter; + len[num_elem] = sizeof(counter); + num_elem++; for (counter = 1; !found; counter++) { u8 pwd_seed[SHA256_MAC_LEN]; @@ -589,8 +615,8 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, } wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); - if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, - pwd_seed) < 0) + if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, + addr, len, pwd_seed) < 0) break; res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc); if (res < 0) @@ -697,13 +723,15 @@ fail: int sae_prepare_commit(const u8 *addr1, const u8 *addr2, const u8 *password, size_t password_len, - struct sae_data *sae) + const char *identifier, struct sae_data *sae) { if (sae->tmp == NULL || (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password, - password_len) < 0) || + password_len, + identifier) < 0) || (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password, - password_len) < 0) || + password_len, + identifier) < 0) || sae_derive_commit(sae) < 0) return -1; return 0; @@ -838,7 +866,7 @@ int sae_process_commit(struct sae_data *sae) } void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token) + const struct wpabuf *token, const char *identifier) { u8 *pos; @@ -872,6 +900,16 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", pos, sae->tmp->prime_len); } + + if (identifier) { + /* Password Identifier element */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + os_strlen(identifier)); + wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER); + wpabuf_put_str(buf, identifier); + wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s", + identifier); + } } u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group) @@ -915,25 +953,71 @@ u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group) return WLAN_STATUS_SUCCESS; } +static int sae_is_password_id_elem(const u8 *pos, const u8 *end) +{ + int ret = end - pos >= 3 && + pos[0] == WLAN_EID_EXTENSION && + pos[1] >= 1 && + end - pos - 2 >= pos[1] && + pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER; + + return ret; +} + static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, const u8 *end, const u8 **token, size_t *token_len) { - if ((sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end - *pos) { - size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) * - sae->tmp->prime_len); - wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen); - if (token) - *token = *pos; - if (token_len) - *token_len = tlen; - *pos += tlen; - } else { - if (token) - *token = NULL; - if (token_len) - *token_len = 0; + size_t scalar_elem_len, tlen; + const u8 *elem; + + if (token) + *token = NULL; + if (token_len) + *token_len = 0; + + scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len; + if (scalar_elem_len >= (size_t) (end - *pos)) + return; /* No extra data beyond peer scalar and element */ + + /* It is a bit difficult to parse this now that there is an + * optional variable length Anti-Clogging Token field and + * optional variable length Password Identifier element in the + * frame. We are sending out fixed length Anti-Clogging Token + * fields, so use that length as a requirement for the received + * token and check for the presence of possible Password + * Identifier element based on the element header information. + */ + tlen = end - (*pos + scalar_elem_len); + + if (tlen < SHA256_MAC_LEN) { + wpa_printf(MSG_DEBUG, + "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token", + (unsigned int) tlen); + return; } + + elem = *pos + scalar_elem_len; + if (sae_is_password_id_elem(elem, end)) { + /* Password Identifier element takes out all available + * extra octets, so there can be no Anti-Clogging token in + * this frame. */ + return; + } + + elem += SHA256_MAC_LEN; + if (sae_is_password_id_elem(elem, end)) { + /* Password Identifier element is included in the end, so + * remove its length from the Anti-Clogging token field. */ + tlen -= 2 + elem[1]; + } + + wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen); + if (token) + *token = *pos; + if (token_len) + *token_len = tlen; + *pos += tlen; } static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, @@ -973,7 +1057,6 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, return WLAN_STATUS_UNSPECIFIED_FAILURE; } - crypto_bignum_deinit(sae->peer_commit_scalar, 0); sae->peer_commit_scalar = peer_scalar; wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar", @@ -983,12 +1066,12 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, return WLAN_STATUS_SUCCESS; } -static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, +static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos, const u8 *end) { u8 prime[SAE_MAX_ECC_PRIME_LEN]; - if (2 * sae->tmp->prime_len > end - pos) { + if (2 * sae->tmp->prime_len > end - *pos) { wpa_printf(MSG_DEBUG, "SAE: Not enough data for " "commit-element"); return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -999,8 +1082,8 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, return WLAN_STATUS_UNSPECIFIED_FAILURE; /* element x and y coordinates < p */ - if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 || - os_memcmp(pos + sae->tmp->prime_len, prime, + if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 || + os_memcmp(*pos + sae->tmp->prime_len, prime, sae->tmp->prime_len) >= 0) { wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer " "element"); @@ -1008,13 +1091,13 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, } wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)", - pos, sae->tmp->prime_len); + *pos, sae->tmp->prime_len); wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)", - pos + sae->tmp->prime_len, sae->tmp->prime_len); + *pos + sae->tmp->prime_len, sae->tmp->prime_len); crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0); sae->tmp->peer_commit_element_ecc = - crypto_ec_point_from_bin(sae->tmp->ec, pos); + crypto_ec_point_from_bin(sae->tmp->ec, *pos); if (sae->tmp->peer_commit_element_ecc == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -1024,26 +1107,28 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, return WLAN_STATUS_UNSPECIFIED_FAILURE; } + *pos += 2 * sae->tmp->prime_len; + return WLAN_STATUS_SUCCESS; } -static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos, +static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos, const u8 *end) { struct crypto_bignum *res, *one; const u8 one_bin[1] = { 0x01 }; - if (sae->tmp->prime_len > end - pos) { + if (sae->tmp->prime_len > end - *pos) { wpa_printf(MSG_DEBUG, "SAE: Not enough data for " "commit-element"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } - wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos, + wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos, sae->tmp->prime_len); crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0); sae->tmp->peer_commit_element_ffc = - crypto_bignum_init_set(pos, sae->tmp->prime_len); + crypto_bignum_init_set(*pos, sae->tmp->prime_len); if (sae->tmp->peer_commit_element_ffc == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; /* 1 < element < p - 1 */ @@ -1071,10 +1156,12 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos, } crypto_bignum_deinit(res, 0); + *pos += sae->tmp->prime_len; + return WLAN_STATUS_SUCCESS; } -static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos, +static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos, const u8 *end) { if (sae->tmp->dh) @@ -1082,12 +1169,47 @@ static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos, return sae_parse_commit_element_ecc(sae, pos, end); } +static int sae_parse_password_identifier(struct sae_data *sae, + const u8 *pos, const u8 *end) +{ + wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame", + pos, end - pos); + if (!sae_is_password_id_elem(pos, end)) { + if (sae->tmp->pw_id) { + wpa_printf(MSG_DEBUG, + "SAE: No Password Identifier included, but expected one (%s)", + sae->tmp->pw_id); + return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER; + } + os_free(sae->tmp->pw_id); + sae->tmp->pw_id = NULL; + return WLAN_STATUS_SUCCESS; /* No Password Identifier */ + } + + if (sae->tmp->pw_id && + (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) || + os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) { + wpa_printf(MSG_DEBUG, + "SAE: The included Password Identifier does not match the expected one (%s)", + sae->tmp->pw_id); + return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER; + } + + os_free(sae->tmp->pw_id); + sae->tmp->pw_id = os_malloc(pos[1]); + if (!sae->tmp->pw_id) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1); + sae->tmp->pw_id[pos[1] - 1] = '\0'; + return WLAN_STATUS_SUCCESS; +} + u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups) { const u8 *pos = data, *end = data + len; u16 res; - + /* Check Finite Cyclic Group */ if (end - pos < 2) return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -1105,7 +1227,12 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, return res; /* commit-element */ - res = sae_parse_commit_element(sae, pos, end); + res = sae_parse_commit_element(sae, &pos, end); + if (res != WLAN_STATUS_SUCCESS) + return res; + + /* Optional Password Identifier element */ + res = sae_parse_password_identifier(sae, pos, end); if (res != WLAN_STATUS_SUCCESS) return res; @@ -1220,7 +1347,8 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) /* Send-Confirm */ sc = wpabuf_put(buf, 0); wpabuf_put_le16(buf, sae->send_confirm); - sae->send_confirm++; + if (sae->send_confirm < 0xffff) + sae->send_confirm++; if (sae->tmp->ec) sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, @@ -1277,4 +1405,19 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) return 0; } +const char * sae_state_txt(enum sae_state state) +{ + switch (state) { + case SAE_NOTHING: + return "Nothing"; + case SAE_COMMITTED: + return "Committed"; + case SAE_CONFIRMED: + return "Confirmed"; + case SAE_ACCEPTED: + return "Accepted"; + } + return "?"; +} + #endif /* CONFIG_WPA3_SAE */ diff --git a/components/wpa_supplicant/src/common/sae.h b/components/wpa_supplicant/src/common/sae.h index 41c7ac0cb4..b0160c458b 100644 --- a/components/wpa_supplicant/src/common/sae.h +++ b/components/wpa_supplicant/src/common/sae.h @@ -5,14 +5,12 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ - #ifdef CONFIG_WPA3_SAE #ifndef SAE_H #define SAE_H #include "esp_err.h" - #include "utils/includes.h" #include "utils/common.h" #include "utils/wpa_debug.h" @@ -47,6 +45,7 @@ struct sae_temporary_data { struct crypto_bignum *prime_buf; struct crypto_bignum *order_buf; struct wpabuf *anti_clogging_token; + char *pw_id; }; enum { @@ -54,32 +53,38 @@ enum { SAE_MSG_CONFIRM = 2, }; +enum sae_state { + SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED +}; + struct sae_data { - enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state; + enum sae_state state; u16 send_confirm; u8 pmk[SAE_PMK_LEN]; u8 pmkid[SAE_PMKID_LEN]; struct crypto_bignum *peer_commit_scalar; - u16 group; - int sync; + int group; + unsigned int sync; /* protocol instance variable: Sync */ + u16 rc; /* protocol instance variable: Rc (received send-confirm) */ struct sae_temporary_data *tmp; }; -int sae_set_group(struct sae_data *sae, u16 group); +int sae_set_group(struct sae_data *sae, int group); void sae_clear_temp_data(struct sae_data *sae); void sae_clear_data(struct sae_data *sae); int sae_prepare_commit(const u8 *addr1, const u8 *addr2, const u8 *password, size_t password_len, - struct sae_data *sae); + const char *identifier, struct sae_data *sae); int sae_process_commit(struct sae_data *sae); void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token); + const struct wpabuf *token, const char *identifier); u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups); void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len); u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group); +const char * sae_state_txt(enum sae_state state); #endif /* SAE_H */ #endif /* CONFIG_WPA3_SAE */ diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index 1eee98a0cf..765590042d 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -58,6 +58,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) return WPA_KEY_MGMT_FT_PSK; #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_WPA3_SAE + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE) + return WPA_KEY_MGMT_SAE; +#endif /* CONFIG_WPA3_SAE */ #ifdef CONFIG_IEEE80211W if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) return WPA_KEY_MGMT_IEEE8021X_SHA256; diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index 07d549aac2..12a13e1a08 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -54,6 +54,7 @@ #endif /* CONFIG_IEEE80211R */ #define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) #define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6) +#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8) #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) diff --git a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c index 88c0e732a9..0f50cd8d09 100644 --- a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -478,9 +478,11 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e, * such that p ≡ 3 (mod 4) * y_ = (y2 ^ ((p+1)/4)) mod p * - * if y_bit: y = p-y_ - * else y = y_` + * if LSB of both x and y are same: y = y_ + * else y = p - y_ + * y_bit is LSB of x */ + y_bit = (y_bit != 0); y_sqr = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, x); @@ -490,9 +492,9 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e, MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(&temp, NULL, &temp, 4)); MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(y, y_sqr, &temp, &e->group.P, NULL)); - if (y_bit) { + if (y_bit != mbedtls_mpi_get_bit(y, 0)) MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y)); - } + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&((mbedtls_ecp_point* )p)->X, (const mbedtls_mpi*) x)); MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&((mbedtls_ecp_point *)p)->Z, 1)); } else { diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index c081a2b7f9..b542ac9408 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -64,7 +64,8 @@ enum { WPA_AUTH_CCKM = 0x06, WPA2_AUTH_CCKM = 0x07, WPA2_AUTH_PSK_SHA256= 0x08, - WPA2_AUTH_INVALID = 0x09, + WPA3_AUTH_PSK = 0x09, + WPA2_AUTH_INVALID = 0x0a, }; typedef enum { @@ -121,6 +122,10 @@ struct wpa_funcs { int (*wpa_parse_wpa_ie)(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data); int (*wpa_config_bss)(u8 *bssid); int (*wpa_michael_mic_failure)(u16 is_unicast); +#ifdef CONFIG_WPA3_SAE + u8 *(*wpa3_build_sae_msg)(u8 *bssid, u32 type, u32 *len); + int (*wpa3_parse_sae_msg)(u8 *buf, u32 len, u32 type); +#endif }; struct wpa2_funcs { @@ -209,6 +214,7 @@ int esp_wifi_ipc_internal(wifi_ipc_config_t *cfg, bool sync); int esp_wifi_register_wpa2_cb_internal(struct wpa2_funcs *cb); int esp_wifi_unregister_wpa2_cb_internal(void); bool esp_wifi_sta_prof_is_wpa2_internal(void); +bool esp_wifi_sta_prof_is_wpa3_internal(void); esp_err_t esp_wifi_sta_wpa2_ent_disable_internal(wifi_wpa2_param_t *param); esp_err_t esp_wifi_sta_wpa2_ent_enable_internal(wifi_wpa2_param_t *param); esp_err_t esp_wifi_set_wpa2_ent_state_internal(wpa2_ent_eap_state_t state); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c new file mode 100644 index 0000000000..d98436a1b7 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c @@ -0,0 +1,165 @@ +// Copyright 2019 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 CONFIG_WPA3_SAE + +#include "../common/sae.h" +#include "esp_wifi_driver.h" +#include "rsn_supp/wpa.h" + +static struct sae_data g_sae_data; + +int g_allowed_groups[] = { IANA_SECP256R1, 0 }; + +static struct wpabuf *wpa3_build_sae_commit(u8 *bssid) +{ + int default_group = IANA_SECP256R1; + struct wpabuf *buf; + u8 own_addr[ETH_ALEN]; + const u8 *pw; + memset(&g_sae_data, 0, sizeof(g_sae_data)); + + if (sae_set_group(&g_sae_data, default_group)) { + wpa_printf(MSG_ERROR, "wpa3: could not set SAE group %d", default_group); + return NULL; + } + + esp_wifi_get_macaddr_internal(WIFI_IF_STA, own_addr); + if (!bssid) { + wpa_printf(MSG_ERROR, "wpa3: cannot prepare SAE commit with no BSSID!"); + return NULL; + } + + pw = (const u8 *)esp_wifi_sta_get_prof_password_internal(); + if (sae_prepare_commit(own_addr, bssid, pw, strlen((const char *)pw), NULL, &g_sae_data) < 0) { + wpa_printf(MSG_ERROR, "wpa3: failed to prepare SAE commit!"); + return NULL; + } + + // For reuse PWE after retry case + // memcpy(g_sae_data.tmp->bssid, bssid, ETH_ALEN); + + buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); + sae_write_commit(&g_sae_data, buf, NULL, NULL); //no token + g_sae_data.state = SAE_COMMITTED; + + return buf; +} + +static struct wpabuf *wpa3_build_sae_confirm(void) +{ + struct wpabuf *buf; + + if (g_sae_data.state != SAE_COMMITTED) + return NULL; + + buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); + sae_write_confirm(&g_sae_data, buf); + g_sae_data.state = SAE_CONFIRMED; + + return buf; +} + +static u8 *wpa3_build_sae_msg(u8 *bssid, u32 sae_msg_type, u32 *sae_msg_len) +{ + struct wpabuf *buf = NULL; + + switch (sae_msg_type) { + case SAE_MSG_COMMIT: + buf = wpa3_build_sae_commit(bssid); + break; + case SAE_MSG_CONFIRM: + buf = wpa3_build_sae_confirm(); + break; + default: + break; + } + + if (buf) { + *sae_msg_len = (u32)wpabuf_len(buf); + return wpabuf_mhead_u8(buf); + } else + return NULL; +} + +static int wpa3_parse_sae_commit(u8 *buf, u32 len) +{ + int ret; + + if (g_sae_data.state != SAE_COMMITTED) { + wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", + g_sae_data.state); + return -1; + } + + ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups); + if (ret) { + wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret); + return -1; + } + + ret = sae_process_commit(&g_sae_data); + if (ret) { + wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret); + return -1; + } + + return 0; +} + +static int wpa3_parse_sae_confirm(u8 *buf, u32 len) +{ + if (g_sae_data.state != SAE_CONFIRMED) { + wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", + g_sae_data.state); + return -1; + } + + sae_check_confirm(&g_sae_data, buf, len); + g_sae_data.state = SAE_ACCEPTED; + + wpa_set_pmk(g_sae_data.pmk); + memcpy(esp_wifi_sta_get_ap_info_prof_pmk_internal(), g_sae_data.pmk, PMK_LEN); + + return 0; +} + +static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type) +{ + int ret = 0; + + switch (sae_msg_type) { + case SAE_MSG_COMMIT: + ret = wpa3_parse_sae_commit(buf, len); + break; + case SAE_MSG_CONFIRM: + ret = wpa3_parse_sae_confirm(buf, len); + break; + default: + wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%d)!", + sae_msg_type); + ret = -1; + break; + } + + return ret; +} + +void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb) +{ + wpa_cb->wpa3_build_sae_msg = wpa3_build_sae_msg; + wpa_cb->wpa3_parse_sae_msg = wpa3_parse_sae_msg; +} + +#endif /* CONFIG_WPA3_SAE */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h new file mode 100644 index 0000000000..99c9d84f06 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h @@ -0,0 +1,23 @@ + +// Copyright 2019 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. + +#ifndef ESP_WPA3_H +#define ESP_WPA3_H + +#include "esp_wifi_driver.h" + +void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb); + +#endif /* ESP_WPA3_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index 434b666b48..fd160738e1 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -32,6 +32,7 @@ #include "esp_wifi_driver.h" #include "esp_private/wifi.h" +#include "esp_wpa3_i.h" void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid) @@ -74,7 +75,7 @@ void wpa_config_profile() { if (esp_wifi_sta_prof_is_wpa_internal()) { wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal()); - } else if (esp_wifi_sta_prof_is_wpa2_internal()) { + } else if (esp_wifi_sta_prof_is_wpa2_internal() || esp_wifi_sta_prof_is_wpa3_internal()) { wpa_set_profile(WPA_PROTO_RSN, esp_wifi_sta_get_prof_authmode_internal()); } else { WPA_ASSERT(0); @@ -201,6 +202,9 @@ int esp_supplicant_init(void) wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper; wpa_cb->wpa_config_bss = NULL;//wpa_config_bss; wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; +#ifdef CONFIG_WPA3_SAE + esp_wifi_register_wpa3_cb(wpa_cb); +#endif /* CONFIG_WPA3_SAE */ esp_wifi_register_wpa_cb_internal(wpa_cb); diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 12d4fbb66e..97fe59bf05 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -2077,6 +2077,10 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode) sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */ } else if (auth_mode == WPA2_AUTH_PSK_SHA256) { sm->key_mgmt = WPA_KEY_MGMT_PSK_SHA256; + } else if (auth_mode == WPA3_AUTH_PSK) { + sm->key_mgmt = WPA_KEY_MGMT_SAE; /* for WPA3 PSK */ + } else { + sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */ } } @@ -2143,6 +2147,8 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) * Here only handle passphrase string. Need extra step to handle 32B, 64Hex raw * PMK. */ + if (sm->key_mgmt == WPA_KEY_MGMT_SAE) + return; /* This is really SLOW, so just re cacl while reset param */ if (esp_wifi_sta_get_reset_param_internal() != 0) { diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index dc1a1616bc..9aaf3bc4ae 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -204,6 +204,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_WPA3_SAE + } else if (key_mgmt == WPA_KEY_MGMT_SAE) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); +#endif /* CONFIG_WPA3_SAE */ } else { wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", key_mgmt); From d36663b79884d864e80ddd57d90c6e0c18468362 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Wed, 29 Apr 2020 18:47:23 +0530 Subject: [PATCH 10/16] wpa_supplicant: Support WPA3 4-way handshake, add config option 1. Add changes in 4-way handshake path to allow SAE key mgmt. 2. Support for configuring WAP3 at init time, added Kconfig option. 3. Handle and propagate error conditions properly. --- components/esp_wifi/Kconfig | 8 + components/esp_wifi/include/esp_wifi.h | 5 + components/esp_wifi/src/wifi_init.c | 7 + components/wpa_supplicant/component.mk | 2 +- components/wpa_supplicant/src/common/defs.h | 2 + components/wpa_supplicant/src/common/sae.c | 211 +++++++++++------- components/wpa_supplicant/src/common/sae.h | 4 +- .../wpa_supplicant/src/common/wpa_common.c | 5 +- .../wpa_supplicant/src/common/wpa_common.h | 1 + .../wpa_supplicant/src/crypto/aes_wrap.h | 5 + .../src/esp_supplicant/esp_wpa3.c | 48 ++-- components/wpa_supplicant/src/rsn_supp/wpa.c | 16 +- components/wpa_supplicant/test/test_sae.c | 14 +- 13 files changed, 210 insertions(+), 118 deletions(-) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 306dfc8f0c..0dd122d611 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -295,6 +295,14 @@ menu "Wi-Fi" When this option is disabled, more than 17Kbytes of IRAM memory will be saved but Wi-Fi performance will be reduced. + config ESP32_WIFI_ENABLE_WPA3_SAE + bool "Enable WPA3-Personal" + default n + help + Select this option to allow the device to establish a WPA3-Personal connection with eligible AP's. + PMF (Protected Management Frames) is a prerequisite feature for a WPA3 connection, it needs to be + explicitly configured before attempting connection. Please refer to the Wi-Fi Driver API Guide for details. + endmenu # Wi-Fi menu "PHY" diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index be481ee27c..05dd7df568 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -110,6 +110,7 @@ typedef struct { int wifi_task_core_id; /**< WiFi Task Core ID */ int beacon_max_len; /**< WiFi softAP maximum length of the beacon */ int mgmt_sbuf_num; /**< WiFi management short buffer number, the minimum value is 6, the maximum value is 32 */ + uint64_t feature_caps; /**< Enables additional WiFi features and capabilities */ int magic; /**< WiFi init magic number, it should be the last field */ } wifi_init_config_t; @@ -156,6 +157,7 @@ typedef struct { #endif extern const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs; +extern uint64_t g_wifi_feature_caps; #define WIFI_INIT_CONFIG_MAGIC 0x1F2F3F4F @@ -189,6 +191,8 @@ extern const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs; #define WIFI_MGMT_SBUF_NUM 32 #endif +#define CONFIG_FEATURE_WPA3_SAE_BIT (1<<0) + #define WIFI_INIT_CONFIG_DEFAULT() { \ .event_handler = &esp_event_send, \ .osi_funcs = &g_wifi_osi_funcs, \ @@ -208,6 +212,7 @@ extern const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs; .wifi_task_core_id = WIFI_TASK_CORE_ID,\ .beacon_max_len = WIFI_SOFTAP_BEACON_MAX_LEN, \ .mgmt_sbuf_num = WIFI_MGMT_SBUF_NUM, \ + .feature_caps = g_wifi_feature_caps, \ .magic = WIFI_INIT_CONFIG_MAGIC\ }; diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 610dbff458..6e54e523b9 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -37,6 +37,13 @@ static esp_pm_lock_handle_t s_wifi_modem_sleep_lock; /* Callback function to update WiFi MAC time */ wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb = NULL; +/* Set additional WiFi features and capabilities */ +uint64_t g_wifi_feature_caps = +#if CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE + CONFIG_FEATURE_WPA3_SAE_BIT | +#endif +0; + static const char* TAG = "wifi_init"; static void __attribute__((constructor)) s_set_default_wifi_log_level() diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index 8553cedc87..dc319339b7 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -2,4 +2,4 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant 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 -CFLAGS += -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 +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/src/common/defs.h b/components/wpa_supplicant/src/common/defs.h index f2fd1f6172..ec4e69ab05 100644 --- a/components/wpa_supplicant/src/common/defs.h +++ b/components/wpa_supplicant/src/common/defs.h @@ -50,6 +50,7 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_CCKM | WPA_KEY_MGMT_OSEN | + WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_IEEE8021X_SUITE_B | WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)); @@ -82,6 +83,7 @@ static inline int wpa_key_mgmt_sha256(int akm) return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_OSEN | + WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_IEEE8021X_SUITE_B)); } diff --git a/components/wpa_supplicant/src/common/sae.c b/components/wpa_supplicant/src/common/sae.c index 3283c334fe..66f5f3fed2 100644 --- a/components/wpa_supplicant/src/common/sae.c +++ b/components/wpa_supplicant/src/common/sae.c @@ -42,7 +42,7 @@ int sae_set_group(struct sae_data *sae, int group) sae_clear_data(sae); tmp = sae->tmp = os_zalloc(sizeof(*tmp)); if (tmp == NULL) - return -1; + return ESP_FAIL; /* First, check if this is an ECC group */ tmp->ec = crypto_ec_init(group); @@ -53,7 +53,7 @@ int sae_set_group(struct sae_data *sae, int group) tmp->prime_len = crypto_ec_prime_len(tmp->ec); tmp->prime = crypto_ec_get_prime(tmp->ec); tmp->order = crypto_ec_get_order(tmp->ec); - return 0; + return ESP_OK; } /* Not an ECC group, check FFC */ @@ -65,14 +65,14 @@ int sae_set_group(struct sae_data *sae, int group) tmp->prime_len = tmp->dh->prime_len; if (tmp->prime_len > SAE_MAX_PRIME_LEN) { sae_clear_data(sae); - return -1; + return ESP_FAIL; } tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime, tmp->prime_len); if (tmp->prime_buf == NULL) { sae_clear_data(sae); - return -1; + return ESP_FAIL; } tmp->prime = tmp->prime_buf; @@ -80,17 +80,17 @@ int sae_set_group(struct sae_data *sae, int group) tmp->dh->order_len); if (tmp->order_buf == NULL) { sae_clear_data(sae); - return -1; + return ESP_FAIL; } tmp->order = tmp->order_buf; - return 0; + return ESP_OK; } /* Unsupported group */ wpa_printf(MSG_DEBUG, "SAE: Group %d not supported by the crypto library", group); - return -1; + return ESP_FAIL; } void sae_clear_temp_data(struct sae_data *sae) @@ -236,7 +236,7 @@ static int is_quadratic_residue_blind(struct sae_data *sae, */ r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd); if (!r) - return -1; + return ESP_FAIL; num = crypto_bignum_init(); if (!num || @@ -293,22 +293,22 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, bits = crypto_ec_prime_len_bits(sae->tmp->ec); if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", prime, sae->tmp->prime_len, pwd_value, bits) < 0) - return -1; + return ESP_FAIL; if (bits % 8) buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, sae->tmp->prime_len); if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0) - return 0; + return ESP_OK; x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); if (!x_cand) - return -1; + return ESP_FAIL; y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand); if (!y_sqr) { crypto_bignum_deinit(x_cand, 1); - return -1; + return ESP_FAIL; } res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr); @@ -337,14 +337,14 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value, bits) < 0) - return -1; + return ESP_FAIL; wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, sae->tmp->prime_len); if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0) { wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p"); - return 0; + return ESP_OK; } /* PWE = pwd-value^((p-1)/r) modulo p */ @@ -380,13 +380,13 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, if (res < 0) { wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE"); - return -1; + return ESP_FAIL; } /* if (PWE > 1) --> found */ if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) { wpa_printf(MSG_DEBUG, "SAE: PWE <= 1"); - return 0; + return ESP_OK; } wpa_printf(MSG_DEBUG, "SAE: PWE found"); @@ -450,12 +450,12 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, if (dummy_password_len > sizeof(dummy_password)) dummy_password_len = sizeof(dummy_password); if (random_get_bytes(dummy_password, dummy_password_len) < 0) - return -1; + return ESP_FAIL; prime_len = sae->tmp->prime_len; if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), prime_len) < 0) - return -1; + return ESP_FAIL; bits = crypto_ec_prime_len_bits(sae->tmp->ec); /* @@ -464,7 +464,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, */ if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits, &qr, &qnr) < 0) - return -1; + return ESP_FAIL; wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", password, password_len); @@ -579,7 +579,7 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, if (sae->tmp->pwe_ffc == NULL) { sae->tmp->pwe_ffc = crypto_bignum_init(); if (sae->tmp->pwe_ffc == NULL) - return -1; + return ESP_FAIL; } wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", @@ -638,7 +638,7 @@ static int sae_derive_commit_element_ecc(struct sae_data *sae, sae->tmp->own_commit_element_ecc = crypto_ec_point_init(sae->tmp->ec); if (!sae->tmp->own_commit_element_ecc) - return -1; + return ESP_FAIL; } if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask, @@ -646,10 +646,10 @@ static int sae_derive_commit_element_ecc(struct sae_data *sae, crypto_ec_point_invert(sae->tmp->ec, sae->tmp->own_commit_element_ecc) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } static int sae_derive_commit_element_ffc(struct sae_data *sae, @@ -659,7 +659,7 @@ static int sae_derive_commit_element_ffc(struct sae_data *sae, if (!sae->tmp->own_commit_element_ffc) { sae->tmp->own_commit_element_ffc = crypto_bignum_init(); if (!sae->tmp->own_commit_element_ffc) - return -1; + return ESP_FAIL; } if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime, @@ -668,10 +668,10 @@ static int sae_derive_commit_element_ffc(struct sae_data *sae, sae->tmp->prime, sae->tmp->own_commit_element_ffc) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } static int sae_derive_commit(struct sae_data *sae) @@ -689,13 +689,13 @@ static int sae_derive_commit(struct sae_data *sae) * theoretical infinite loop, break out after 100 * attemps. */ - return -1; + return ESP_FAIL; } mask = sae_get_rand_and_mask(sae); if (mask == NULL) { wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask"); - return -1; + return ESP_FAIL; } /* commit-scalar = (rand + mask) modulo r */ @@ -733,8 +733,8 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2, password_len, identifier) < 0) || sae_derive_commit(sae) < 0) - return -1; - return 0; + return ESP_FAIL; + return ESP_OK; } static int sae_derive_k_ecc(struct sae_data *sae, u8 *k) @@ -861,17 +861,17 @@ int sae_process_commit(struct sae_data *sae) (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) || (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) || sae_derive_keys(sae, k) < 0) - return -1; - return 0; + return ESP_FAIL; + return ESP_OK; } -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, +int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, const struct wpabuf *token, const char *identifier) { u8 *pos; if (sae->tmp == NULL) - return; + return ESP_FAIL; wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */ if (token) { @@ -880,23 +880,32 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, wpabuf_head(token), wpabuf_len(token)); } pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, - sae->tmp->prime_len, sae->tmp->prime_len); + if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, + sae->tmp->prime_len, sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum operation on own commit scalar"); + return ESP_FAIL; + } wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar", pos, sae->tmp->prime_len); if (sae->tmp->ec) { pos = wpabuf_put(buf, 2 * sae->tmp->prime_len); - crypto_ec_point_to_bin(sae->tmp->ec, - sae->tmp->own_commit_element_ecc, - pos, pos + sae->tmp->prime_len); + if (crypto_ec_point_to_bin(sae->tmp->ec, + sae->tmp->own_commit_element_ecc, + pos, pos + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point"); + return ESP_FAIL; + } wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)", pos, sae->tmp->prime_len); wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)", pos + sae->tmp->prime_len, sae->tmp->prime_len); } else { pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, - sae->tmp->prime_len, sae->tmp->prime_len); + if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, + sae->tmp->prime_len, sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum operation on commit elem ffc"); + return ESP_FAIL; + } wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", pos, sae->tmp->prime_len); } @@ -910,6 +919,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s", identifier); } + return ESP_OK; } u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group) @@ -1299,7 +1309,7 @@ static void sae_cn_confirm(struct sae_data *sae, const u8 *sc, confirm); } -static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, +static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, const struct crypto_bignum *scalar1, const struct crypto_ec_point *element1, const struct crypto_bignum *scalar2, @@ -1309,40 +1319,54 @@ static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN]; u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN]; - crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1, - element_b1 + sae->tmp->prime_len); - crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2, - element_b2 + sae->tmp->prime_len); + if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1, + element_b1 + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point"); + return ESP_FAIL; + } + if (crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2, + element_b2 + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point"); + return ESP_FAIL; + } sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len, scalar2, element_b2, 2 * sae->tmp->prime_len, confirm); + return ESP_OK; } -static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc, - const struct crypto_bignum *scalar1, - const struct crypto_bignum *element1, - const struct crypto_bignum *scalar2, - const struct crypto_bignum *element2, - u8 *confirm) +static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc, + const struct crypto_bignum *scalar1, + const struct crypto_bignum *element1, + const struct crypto_bignum *scalar2, + const struct crypto_bignum *element2, + u8 *confirm) { u8 element_b1[SAE_MAX_PRIME_LEN]; u8 element_b2[SAE_MAX_PRIME_LEN]; - crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1), - sae->tmp->prime_len); - crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2), - sae->tmp->prime_len); + if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1), + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while generating SAE confirm - e1"); + return ESP_FAIL; + } + if (crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2), + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while generating SAE confirm - e2"); + return ESP_FAIL; + } sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len, scalar2, element_b2, sae->tmp->prime_len, confirm); + return ESP_OK; } -void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) +int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) { const u8 *sc; if (sae->tmp == NULL) - return; + return ESP_FAIL; /* Send-Confirm */ sc = wpabuf_put(buf, 0); @@ -1350,18 +1374,26 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) if (sae->send_confirm < 0xffff) sae->send_confirm++; - if (sae->tmp->ec) - sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ecc, - sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ecc, - wpabuf_put(buf, SHA256_MAC_LEN)); - else - sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ffc, - sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ffc, - wpabuf_put(buf, SHA256_MAC_LEN)); + if (sae->tmp->ec) { + if (sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ecc, + sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ecc, + wpabuf_put(buf, SHA256_MAC_LEN))) { + wpa_printf(MSG_ERROR, "SAE: failed generate SAE confirm (ecc)"); + return ESP_FAIL; + } + } else { + if (sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ffc, + sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ffc, + wpabuf_put(buf, SHA256_MAC_LEN))) { + wpa_printf(MSG_ERROR, "SAE: failed generate SAE confirm (ffc)"); + return ESP_FAIL; + } + } + return ESP_OK; } int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) @@ -1370,28 +1402,35 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) if (len < 2 + SHA256_MAC_LEN) { wpa_printf(MSG_DEBUG, "SAE: Too short confirm message"); - return -1; + return ESP_FAIL; } wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data)); if (sae->tmp == NULL) { wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available"); - return -1; + return ESP_FAIL; } - if (sae->tmp->ec) - sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ecc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ecc, - verifier); - else - sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ffc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ffc, - verifier); + if (sae->tmp->ec) { + if (sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ecc, + sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ecc, + verifier)) { + wpa_printf(MSG_ERROR, "SAE: failed to check SAE confirm (ecc)"); + return ESP_FAIL; + } + } else { + if (sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ffc, + sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ffc, + verifier)) { + wpa_printf(MSG_ERROR, "SAE: failed check SAE confirm (ffc)"); + return ESP_FAIL; + } + } if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) { wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); @@ -1399,10 +1438,10 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) data + 2, SHA256_MAC_LEN); wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier", verifier, SHA256_MAC_LEN); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } const char * sae_state_txt(enum sae_state state) diff --git a/components/wpa_supplicant/src/common/sae.h b/components/wpa_supplicant/src/common/sae.h index b0160c458b..6c99a73cec 100644 --- a/components/wpa_supplicant/src/common/sae.h +++ b/components/wpa_supplicant/src/common/sae.h @@ -77,11 +77,11 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2, const u8 *password, size_t password_len, const char *identifier, struct sae_data *sae); int sae_process_commit(struct sae_data *sae); -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, +int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, const struct wpabuf *token, const char *identifier); u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups); -void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); +int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len); u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group); const char * sae_state_txt(enum sae_state state); diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index 765590042d..ba909fee26 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -394,6 +394,9 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, memcpy(mic, hash, MD5_MAC_LEN); break; #ifdef CONFIG_IEEE80211W +#ifdef CONFIG_WPA3_SAE + case WPA_KEY_INFO_TYPE_AKM_DEFINED: +#endif case WPA_KEY_INFO_TYPE_AES_128_CMAC: return omac1_aes_128(key, buf, len, mic); #endif @@ -514,13 +517,11 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, WPA_NONCE_LEN); } -#ifdef CONFIG_IEEE80211W if (use_sha256) { sha256_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); } else -#endif /* CONFIG_IEEE80211W */ { sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); } diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index 12a13e1a08..f88e8a6fac 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -121,6 +121,7 @@ /* IEEE 802.11, 8.5.2 EAPOL-Key frames */ #define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) +#define WPA_KEY_INFO_TYPE_AKM_DEFINED 0 #define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) #define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) #define WPA_KEY_INFO_TYPE_AES_128_CMAC 3 diff --git a/components/wpa_supplicant/src/crypto/aes_wrap.h b/components/wpa_supplicant/src/crypto/aes_wrap.h index e6912054f0..d25d113b44 100644 --- a/components/wpa_supplicant/src/crypto/aes_wrap.h +++ b/components/wpa_supplicant/src/crypto/aes_wrap.h @@ -24,11 +24,16 @@ int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); +int __must_check omac1_aes_vector(const u8 *key, size_t key_len, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac); +int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, + u8 *mac); int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, u8 *data, size_t data_len); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c index d98436a1b7..014cabb0de 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c @@ -14,7 +14,7 @@ #ifdef CONFIG_WPA3_SAE -#include "../common/sae.h" +#include "common/sae.h" #include "esp_wifi_driver.h" #include "rsn_supp/wpa.h" @@ -47,11 +47,17 @@ static struct wpabuf *wpa3_build_sae_commit(u8 *bssid) return NULL; } - // For reuse PWE after retry case - // memcpy(g_sae_data.tmp->bssid, bssid, ETH_ALEN); - buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); - sae_write_commit(&g_sae_data, buf, NULL, NULL); //no token + if (!buf) { + wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for commit msg"); + return NULL; + } + + if (sae_write_commit(&g_sae_data, buf, NULL, NULL) != ESP_OK) { + wpa_printf(MSG_ERROR, "wpa3: failed to write SAE commit msg"); + wpabuf_free(buf); + return NULL; + } g_sae_data.state = SAE_COMMITTED; return buf; @@ -65,7 +71,16 @@ static struct wpabuf *wpa3_build_sae_confirm(void) return NULL; buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); - sae_write_confirm(&g_sae_data, buf); + if (!buf) { + wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for confirm msg"); + return NULL; + } + + if (sae_write_confirm(&g_sae_data, buf) != ESP_OK) { + wpa_printf(MSG_ERROR, "wpa3: failed to write SAE confirm msg"); + wpabuf_free(buf); + return NULL; + } g_sae_data.state = SAE_CONFIRMED; return buf; @@ -100,22 +115,22 @@ static int wpa3_parse_sae_commit(u8 *buf, u32 len) if (g_sae_data.state != SAE_COMMITTED) { wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", g_sae_data.state); - return -1; + return ESP_FAIL; } ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups); if (ret) { wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret); - return -1; + return ESP_FAIL; } ret = sae_process_commit(&g_sae_data); if (ret) { wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } static int wpa3_parse_sae_confirm(u8 *buf, u32 len) @@ -123,21 +138,24 @@ static int wpa3_parse_sae_confirm(u8 *buf, u32 len) if (g_sae_data.state != SAE_CONFIRMED) { wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", g_sae_data.state); - return -1; + return ESP_FAIL; } - sae_check_confirm(&g_sae_data, buf, len); + if (sae_check_confirm(&g_sae_data, buf, len) != ESP_OK) { + wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE confirm"); + return ESP_FAIL; + } g_sae_data.state = SAE_ACCEPTED; wpa_set_pmk(g_sae_data.pmk); memcpy(esp_wifi_sta_get_ap_info_prof_pmk_internal(), g_sae_data.pmk, PMK_LEN); - return 0; + return ESP_OK; } static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type) { - int ret = 0; + int ret = ESP_OK; switch (sae_msg_type) { case SAE_MSG_COMMIT: @@ -149,7 +167,7 @@ static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type) default: wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%d)!", sae_msg_type); - ret = -1; + ret = ESP_FAIL; break; } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 97fe59bf05..91dd50c170 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -245,6 +245,8 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; else if (sm->pairwise_cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; + else if (sm->key_mgmt == WPA_KEY_MGMT_SAE) + ver = 0; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; @@ -1661,7 +1663,8 @@ failed: return -1; } } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { + ver == WPA_KEY_INFO_TYPE_AES_128_CMAC || + sm->key_mgmt == WPA_KEY_MGMT_SAE) { u8 *buf; if (keydatalen % 8) { #ifdef DEBUG_PRINT @@ -1832,6 +1835,9 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && #ifdef CONFIG_IEEE80211W ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && +#ifdef CONFIG_WPA3_SAE + sm->key_mgmt != WPA_KEY_MGMT_SAE && +#endif #endif ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { #ifdef DEBUG_PRINT @@ -1843,14 +1849,16 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) #ifdef CONFIG_IEEE80211W if (wpa_key_mgmt_sha256(sm->key_mgmt)) { - if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { + if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && + sm->key_mgmt != WPA_KEY_MGMT_SAE) { goto out; } } else #endif if (sm->pairwise_cipher == WPA_CIPHER_CCMP && - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && + sm->key_mgmt != WPA_KEY_MGMT_SAE) { #ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "WPA: CCMP is used, but EAPOL-Key " "descriptor version (%d) is not 2.", ver); @@ -2073,8 +2081,6 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode) sm->proto = wpa_proto; if (auth_mode == WPA2_AUTH_ENT) { sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X; /* for wpa2 enterprise */ - } else if (auth_mode == WPA2_AUTH_PSK) { - sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */ } else if (auth_mode == WPA2_AUTH_PSK_SHA256) { sm->key_mgmt = WPA_KEY_MGMT_PSK_SHA256; } else if (auth_mode == WPA3_AUTH_PSK) { diff --git a/components/wpa_supplicant/test/test_sae.c b/components/wpa_supplicant/test/test_sae.c index b87783d5fc..b5d244de72 100644 --- a/components/wpa_supplicant/test/test_sae.c +++ b/components/wpa_supplicant/test/test_sae.c @@ -85,7 +85,7 @@ TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") TEST_ASSERT( buf != NULL); - sae_write_commit(&sae, buf, NULL);// No anti-clogging token + sae_write_commit(&sae, buf, NULL, NULL);// No anti-clogging token /* Parsing commit created by self will be detected as reflection attack*/ TEST_ASSERT(sae_parse_commit(&sae, @@ -125,14 +125,14 @@ TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") /* STA1 creates commit msg buffer*/ buf1 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf1 != NULL); - sae_write_commit(&sae1, buf1, NULL);// No anti-clogging token + sae_write_commit(&sae1, buf1, NULL, NULL);// No anti-clogging token ESP_LOG_BUFFER_HEXDUMP("SAE: Commit1", wpabuf_mhead_u8(buf1), wpabuf_len(buf1), ESP_LOG_INFO); /* STA2 creates commit msg buffer*/ buf2 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf2 != NULL); - sae_write_commit(&sae2, buf2, NULL);// No anti-clogging token + sae_write_commit(&sae2, buf2, NULL, NULL);// No anti-clogging token ESP_LOG_BUFFER_HEXDUMP("SAE: Commit2", wpabuf_mhead_u8(buf2), wpabuf_len(buf2), ESP_LOG_INFO); sae1.state = SAE_COMMITTED; @@ -205,20 +205,20 @@ TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") TEST_ASSERT(sae_set_group(&sae2, IANA_SECP256R1) == 0); /* STA1 prepares for commit*/ - TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd1, strlen((const char *)pwd), NULL, &sae1) == 0); + TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd1, strlen((const char *)pwd1), NULL, &sae1) == 0); /* STA2 prepares for commit*/ - TEST_ASSERT(sae_prepare_commit(addr2, addr1, pwd2, strlen((const char *)pwd), NULL, &sae2) == 0); + TEST_ASSERT(sae_prepare_commit(addr2, addr1, pwd2, strlen((const char *)pwd2), NULL, &sae2) == 0); /* STA1 creates commit msg buffer*/ buf1 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf1 != NULL); - sae_write_commit(&sae1, buf1, NULL);// No anti-clogging token + sae_write_commit(&sae1, buf1, NULL, NULL);// No anti-clogging token /* STA2 creates commit msg buffer*/ buf2 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf2 != NULL); - sae_write_commit(&sae2, buf2, NULL);// No anti-clogging token + sae_write_commit(&sae2, buf2, NULL, NULL);// No anti-clogging token sae1.state = SAE_COMMITTED; sae2.state = SAE_COMMITTED; From 6d6b7b09e835878cf8f88912d74487b6645f6fdc Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Wed, 29 Apr 2020 18:49:39 +0530 Subject: [PATCH 11/16] wifi: Add PMF and WPA3 documentation --- docs/en/api-guides/wifi.rst | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/en/api-guides/wifi.rst b/docs/en/api-guides/wifi.rst index b6afd63779..81a21f0e0c 100644 --- a/docs/en/api-guides/wifi.rst +++ b/docs/en/api-guides/wifi.rst @@ -1393,6 +1393,41 @@ Wi-Fi Vendor IE Configuration By default, all Wi-Fi management frames are processed by the Wi-Fi driver, and the application does not need to care about them. Some applications, however, may have to handle the beacon, probe request, probe response and other management frames. For example, if you insert some vendor-specific IE into the management frames, it is only the management frames which contain this vendor-specific IE that will be processed. In ESP32, esp_wifi_set_vendor_ie() and esp_wifi_set_vendor_ie_cb() are responsible for this kind of tasks. +Wi-Fi Security +------------------------------- + +In addition to traditional security methods (WEP/WPA-TKIP/WPA2-CCMP), ESP32 Wi-Fi now supports state-of-the-art security protocols, namely Protected Management Frames based on 802.11w standard and Wi-Fi Protected Access 3 (WPA3-Personal). Together, PMF and WPA3 provide better privacy and robustness against known attacks in traditional modes. + +Protected Management Frames (PMF) +++++++++++++++++++++++++++++++++++ + +In Wi-Fi, management frames such as beacons, probes, (de)authentication, (dis)association are used by non-AP stations to scan and connect to an AP. Unlike data frames, these frames are sent unencrypted. +An attacker can use eavesdropping and packet injection to send spoofed (de)authentication/(dis)association frames at the right time, leading to following attacks in case of unprotected management frame exchanges. + + - DOS attack on one or all clients in the range of the attacker. + - Tearing down existing association on AP side by sending association request. + - Forcing a client to perform 4-way handshake again in case PSK is compromised in order to get PTK. + - Getting SSID of hidden network from association request. + - Launching man-in-the-middle attack by forcing clients to deauth from legitimate AP and associating to a rogue one. + +PMF provides protection against these attacks by encrypting unicast management frames and providing integrity checks for broadcast management frames. These include deauthentication, disassociation and robust management frames. It also provides Secure Association (SA) teardown mechanism to prevent spoofed association/authentication frames from disconnecting already connected clients. + +ESP32 supports the following three modes of operation with respect to PMF. + + - PMF not supported: In this mode, ESP32 indicates to AP that it is not capable of supporting management protection during association. In effect, security in this mode will be equivalent to that in traditional mode. + - PMF capable, but not required: In this mode, ESP32 indicates to AP that it is capable of supporting PMF. The management protection will be used if AP mandates PMF or is at least capable of supporting PMF. + - PMF capable and required: In this mode, ESP32 will only connect to AP, if AP supports PMF. If not, ESP32 will refuse to connect to the AP. + +:cpp:func:`esp_wifi_set_config` can be used to configure PMF mode by setting appropriate flags in `pmf_cfg` parameter. Currently, PMF is supported only in Station mode. + + +WPA3-Personal ++++++++++++++++++++++++++++++++++ + +Wi-Fi Protected Access-3 (WPA3) is a set of enhancements to Wi-Fi access security intended to replace the current WPA2 standard. In order to provide more robust authentication, WPA3 uses Simultaneous Authentication of Equals (SAE), which is password-authenticated key agreement method based on Diffie-Hellman key exchange. Unlike WPA2, the technology is resistant to offline-dictionary attack, where the attacker attempts to determine shared password based on captured 4-way handshake without any further network interaction. WPA3 also provides forward secrecy, which means the captured data cannot be decrypted even if password is compromised after data transmission. Please refer to `Security `_ section of Wi-Fi Alliance's official website for further details. + +In order to enable WPA3-Personal, "Enable WPA3-Personal" should be selected in menuconfig. If enabled, ESP32 uses SAE for authentication if supported by the AP. Since PMF is a mandatory requirement for WPA3, PMF capability should be at least set to "PMF capable, but not required" for ESP32 to use WPA3 mode. Application developers need not worry about the underlying security mode as highest available is chosen from security standpoint. Note that Wi-Fi stack size requirement will increase approximately by 3k when WPA3 is used. Currently, WPA3 is supported only in Station mode. + ESP32 Wi-Fi Power-saving Mode ----------------------------------- From ab819409822976b719d7b31a9e19fb1698425106 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Thu, 30 Apr 2020 18:52:58 +0530 Subject: [PATCH 12/16] esp_wifi: Additional changes for WPA3 & PMF testcases Added WPA3 Testcases support for - 1. Anti-Clogging Token Request support 2. Return correct status from SAE modules for invalid scenarios 3. Add PMK Caching support for WPA3 wifi lib includes fixes for below PMF Certification issues - 1. Check return status of decrypt operation. Fixes 5.3.3.1. 2. Allow PMF negotiation for WPA2-Enterprise. Fixes 5.3.3.2, 5.3.3.4. 3. Add NULL check on key before encrypting PMF, fixes crash. --- components/esp_wifi/include/esp_wifi_types.h | 2 + components/esp_wifi/lib_esp32 | 2 +- .../include/esp_supplicant/esp_wpa.h | 2 +- components/wpa_supplicant/src/common/defs.h | 1 - components/wpa_supplicant/src/common/sae.c | 1 - components/wpa_supplicant/src/common/sae.h | 1 - .../src/esp_supplicant/esp_wifi_driver.h | 7 ++- .../src/esp_supplicant/esp_wpa2.c | 2 +- .../src/esp_supplicant/esp_wpa3.c | 49 ++++++++++++++----- .../src/esp_supplicant/esp_wpa3_i.h | 11 +++++ .../src/esp_supplicant/esp_wpa_main.c | 22 ++++++++- .../wpa_supplicant/src/rsn_supp/pmksa_cache.c | 13 +++-- .../wpa_supplicant/src/rsn_supp/pmksa_cache.h | 4 +- components/wpa_supplicant/src/rsn_supp/wpa.c | 46 ++++++++++------- components/wpa_supplicant/src/rsn_supp/wpa.h | 4 +- .../wpa_supplicant/src/rsn_supp/wpa_ie.c | 4 +- 16 files changed, 121 insertions(+), 50 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index cdffd6a901..8da6a21bda 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -85,6 +85,8 @@ typedef enum { WIFI_REASON_802_1X_AUTH_FAILED = 23, WIFI_REASON_CIPHER_SUITE_REJECTED = 24, + WIFI_REASON_INVALID_PMKID = 53, + WIFI_REASON_BEACON_TIMEOUT = 200, WIFI_REASON_NO_AP_FOUND = 201, WIFI_REASON_AUTH_FAIL = 202, diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index b44a2991e9..78c0f85ad4 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit b44a2991e9499868bdf99619f2c7c16036ad038a +Subproject commit 78c0f85ad4d9bcd62dbfc787694bac8d4e0c0a19 diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h index a268d9a464..202c907d60 100644 --- a/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h +++ b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h @@ -19,6 +19,7 @@ #include #include "esp_err.h" #include "esp_wifi_crypto_types.h" +#include "esp_wifi_types.h" #ifdef __cplusplus extern "C" { @@ -63,7 +64,6 @@ esp_err_t esp_supplicant_init(void); */ esp_err_t esp_supplicant_deinit(void); - /** * @} */ diff --git a/components/wpa_supplicant/src/common/defs.h b/components/wpa_supplicant/src/common/defs.h index ec4e69ab05..4906ff6123 100644 --- a/components/wpa_supplicant/src/common/defs.h +++ b/components/wpa_supplicant/src/common/defs.h @@ -50,7 +50,6 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_CCKM | WPA_KEY_MGMT_OSEN | - WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_IEEE8021X_SUITE_B | WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)); diff --git a/components/wpa_supplicant/src/common/sae.c b/components/wpa_supplicant/src/common/sae.c index 66f5f3fed2..29a41c4566 100644 --- a/components/wpa_supplicant/src/common/sae.c +++ b/components/wpa_supplicant/src/common/sae.c @@ -110,7 +110,6 @@ void sae_clear_temp_data(struct sae_data *sae) crypto_ec_point_deinit(tmp->pwe_ecc, 1); crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0); crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0); - wpabuf_free(tmp->anti_clogging_token); os_free(tmp->pw_id); bin_clear_free(tmp, sizeof(*tmp)); sae->tmp = NULL; diff --git a/components/wpa_supplicant/src/common/sae.h b/components/wpa_supplicant/src/common/sae.h index 6c99a73cec..24437c0d02 100644 --- a/components/wpa_supplicant/src/common/sae.h +++ b/components/wpa_supplicant/src/common/sae.h @@ -44,7 +44,6 @@ struct sae_temporary_data { const struct crypto_bignum *order; struct crypto_bignum *prime_buf; struct crypto_bignum *order_buf; - struct wpabuf *anti_clogging_token; char *pw_id; }; diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index b542ac9408..b8667c5132 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -110,6 +110,7 @@ struct wpa_funcs { bool (*wpa_sta_init)(void); bool (*wpa_sta_deinit)(void); void (*wpa_sta_connect)(uint8_t *bssid); + void (*wpa_sta_disconnected_cb)(uint8_t reason_code); int (*wpa_sta_rx_eapol)(u8 *src_addr, u8 *buf, u32 len); bool (*wpa_sta_in_4way_handshake)(void); void *(*wpa_ap_init)(void); @@ -122,10 +123,8 @@ struct wpa_funcs { int (*wpa_parse_wpa_ie)(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data); int (*wpa_config_bss)(u8 *bssid); int (*wpa_michael_mic_failure)(u16 is_unicast); -#ifdef CONFIG_WPA3_SAE - u8 *(*wpa3_build_sae_msg)(u8 *bssid, u32 type, u32 *len); - int (*wpa3_parse_sae_msg)(u8 *buf, u32 len, u32 type); -#endif + uint8_t *(*wpa3_build_sae_msg)(uint8_t *bssid, uint32_t type, size_t *len); + int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status); }; struct wpa2_funcs { diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c index 6f8bd00aee..fafba677c2 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c @@ -621,7 +621,7 @@ static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bss break; case EAP_CODE_SUCCESS: if (sm->eapKeyData) { - wpa_set_pmk(sm->eapKeyData); + wpa_set_pmk(sm->eapKeyData, NULL, false); os_free(sm->eapKeyData); sm->eapKeyData = NULL; wpa_printf(MSG_INFO, ">>>>>wpa2 FINISH\n"); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c index 014cabb0de..cdafaf3ab9 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c @@ -15,21 +15,33 @@ #ifdef CONFIG_WPA3_SAE #include "common/sae.h" +#include "common/ieee802_11_defs.h" #include "esp_wifi_driver.h" #include "rsn_supp/wpa.h" static struct sae_data g_sae_data; - +static struct wpabuf *g_sae_token = NULL; int g_allowed_groups[] = { IANA_SECP256R1, 0 }; static struct wpabuf *wpa3_build_sae_commit(u8 *bssid) { int default_group = IANA_SECP256R1; struct wpabuf *buf; + u32 len = 0; u8 own_addr[ETH_ALEN]; const u8 *pw; - memset(&g_sae_data, 0, sizeof(g_sae_data)); + if (wpa_sta_is_cur_pmksa_set()) { + wpa_printf(MSG_INFO, "wpa3: Skip SAE and use cached PMK instead"); + return NULL; + } + + if (g_sae_token) { + len = wpabuf_len(g_sae_token); + goto reuse_data; + } + + memset(&g_sae_data, 0, sizeof(g_sae_data)); if (sae_set_group(&g_sae_data, default_group)) { wpa_printf(MSG_ERROR, "wpa3: could not set SAE group %d", default_group); return NULL; @@ -47,17 +59,24 @@ static struct wpabuf *wpa3_build_sae_commit(u8 *bssid) return NULL; } - buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); +reuse_data: + len += SAE_COMMIT_MAX_LEN; + buf = wpabuf_alloc(len); if (!buf) { wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for commit msg"); return NULL; } - if (sae_write_commit(&g_sae_data, buf, NULL, NULL) != ESP_OK) { + if (sae_write_commit(&g_sae_data, buf, g_sae_token, NULL) != ESP_OK) { wpa_printf(MSG_ERROR, "wpa3: failed to write SAE commit msg"); wpabuf_free(buf); return NULL; } + + if (g_sae_token) { + wpabuf_free(g_sae_token); + g_sae_token = NULL; + } g_sae_data.state = SAE_COMMITTED; return buf; @@ -104,11 +123,12 @@ static u8 *wpa3_build_sae_msg(u8 *bssid, u32 sae_msg_type, u32 *sae_msg_len) if (buf) { *sae_msg_len = (u32)wpabuf_len(buf); return wpabuf_mhead_u8(buf); - } else + } else { return NULL; + } } -static int wpa3_parse_sae_commit(u8 *buf, u32 len) +static int wpa3_parse_sae_commit(u8 *buf, u32 len, u16 status) { int ret; @@ -118,16 +138,23 @@ static int wpa3_parse_sae_commit(u8 *buf, u32 len) return ESP_FAIL; } + if (status == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ) { + if (g_sae_token) + wpabuf_free(g_sae_token); + g_sae_token = wpabuf_alloc_copy(buf + 2, len - 2); + return ESP_OK; + } + ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups); if (ret) { wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret); - return ESP_FAIL; + return ret; } ret = sae_process_commit(&g_sae_data); if (ret) { wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret); - return ESP_FAIL; + return ret; } return ESP_OK; @@ -147,19 +174,19 @@ static int wpa3_parse_sae_confirm(u8 *buf, u32 len) } g_sae_data.state = SAE_ACCEPTED; - wpa_set_pmk(g_sae_data.pmk); + wpa_set_pmk(g_sae_data.pmk, g_sae_data.pmkid, true); memcpy(esp_wifi_sta_get_ap_info_prof_pmk_internal(), g_sae_data.pmk, PMK_LEN); return ESP_OK; } -static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type) +static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type, u16 status) { int ret = ESP_OK; switch (sae_msg_type) { case SAE_MSG_COMMIT: - ret = wpa3_parse_sae_commit(buf, len); + ret = wpa3_parse_sae_commit(buf, len, status); break; case SAE_MSG_CONFIRM: ret = wpa3_parse_sae_confirm(buf, len); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h index 99c9d84f06..ffbb19e6ca 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h @@ -18,6 +18,17 @@ #include "esp_wifi_driver.h" +#ifdef CONFIG_WPA3_SAE + void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb); +#else /* CONFIG_WPA3_SAE */ + +static inline void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb) +{ + wpa_cb->wpa3_build_sae_msg = NULL; + wpa_cb->wpa3_parse_sae_msg = NULL; +} + +#endif /* CONFIG_WPA3_SAE */ #endif /* ESP_WPA3_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index fd160738e1..503c5c5471 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -176,6 +176,25 @@ int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t return ret; } +static void wpa_sta_disconnected_cb(uint8_t reason_code) +{ + switch (reason_code) { + case WIFI_REASON_UNSPECIFIED: + case WIFI_REASON_AUTH_EXPIRE: + case WIFI_REASON_NOT_AUTHED: + case WIFI_REASON_NOT_ASSOCED: + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + case WIFI_REASON_INVALID_PMKID: + case WIFI_REASON_AUTH_FAIL: + case WIFI_REASON_ASSOC_FAIL: + case WIFI_REASON_CONNECTION_FAIL: + wpa_sta_clear_curr_pmksa(); + break; + default: + break; + } +} + int esp_supplicant_init(void) { struct wpa_funcs *wpa_cb; @@ -189,6 +208,7 @@ int esp_supplicant_init(void) wpa_cb->wpa_sta_deinit = wpa_deattach; wpa_cb->wpa_sta_rx_eapol = wpa_sm_rx_eapol; wpa_cb->wpa_sta_connect = wpa_sta_connect; + wpa_cb->wpa_sta_disconnected_cb = wpa_sta_disconnected_cb; wpa_cb->wpa_sta_in_4way_handshake = wpa_sta_in_4way_handshake; wpa_cb->wpa_ap_join = wpa_ap_join; @@ -202,9 +222,7 @@ int esp_supplicant_init(void) wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper; wpa_cb->wpa_config_bss = NULL;//wpa_config_bss; wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; -#ifdef CONFIG_WPA3_SAE esp_wifi_register_wpa3_cb(wpa_cb); -#endif /* CONFIG_WPA3_SAE */ esp_wifi_register_wpa_cb_internal(wpa_cb); diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c index 0f42eb4040..b8ea823d31 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c @@ -103,7 +103,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) */ struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, + const u8 *pmkid, const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { struct rsn_pmksa_cache_entry *entry, *pos, *prev; @@ -120,8 +120,11 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, return NULL; os_memcpy(entry->pmk, pmk, pmk_len); entry->pmk_len = pmk_len; - rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, - wpa_key_mgmt_sha256(akmp)); + if (pmkid) + os_memcpy(entry->pmkid, pmkid, PMKID_LEN); + else + rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, + wpa_key_mgmt_sha256(akmp)); entry->expiration = now_sec + dot11RSNAConfigPMKLifetime; entry->reauth_time = now_sec + dot11RSNAConfigPMKLifetime * dot11RSNAConfigPMKReauthThreshold / 100; @@ -318,7 +321,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *new_entry; new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, - NULL, 0, + NULL, NULL, 0, aa, pmksa->sm->own_addr, old_entry->network_ctx, old_entry->akmp); if (new_entry == NULL) @@ -428,7 +431,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, network_ctx, bssid); if (sm->cur_pmksa) { - wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", + wpa_hexdump(MSG_ERROR, "RSN: PMKSA cache entry found - PMKID", sm->cur_pmksa->pmkid, PMKID_LEN); return 0; } diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h index 6e314385ca..e2c9156a50 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h @@ -57,7 +57,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, + const u8 *pmkid, const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp); struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); void pmksa_cache_clear_current(struct wpa_sm *sm); @@ -105,7 +105,7 @@ static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, static inline struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *kck, size_t kck_len, + const u8 *pmkid, const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { return NULL; diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 91dd50c170..0402315f0e 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -399,12 +399,9 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, if (sm->proto == WPA_PROTO_RSN && !wpa_key_mgmt_suite_b(sm->key_mgmt) && !wpa_key_mgmt_ft(sm->key_mgmt)) { - sa = pmksa_cache_add(sm->pmksa, - sm->pmk, pmk_len, - NULL, 0, - src_addr, sm->own_addr, - sm->network_ctx, - sm->key_mgmt); + sa = pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, + NULL, NULL, 0, src_addr, sm->own_addr, + sm->network_ctx, sm->key_mgmt); } if (!sm->cur_pmksa && pmkid && pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL)) @@ -590,8 +587,8 @@ void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, if (res) goto failed; - if (esp_wifi_sta_prof_is_wpa2_internal() - && esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT) { + if (esp_wifi_sta_prof_is_wpa2_internal() && + esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT) { pmksa_cache_set_current(sm, NULL, sm->bssid, 0, 0); } @@ -1991,7 +1988,7 @@ void wpa_sm_set_state(enum wpa_states state) * Configure the PMK for WPA state machine. */ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, - const u8 *bssid) + const u8 *pmkid, const u8 *bssid) { if (sm == NULL) return; @@ -2006,9 +2003,9 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, #endif /* CONFIG_IEEE80211R */ if (bssid) { - pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0, - bssid, sm->own_addr, - sm->network_ctx, sm->key_mgmt); + pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0, + bssid, sm->own_addr, + sm->network_ctx, sm->key_mgmt); } } @@ -2090,12 +2087,18 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode) } } -void wpa_set_pmk(uint8_t *pmk) +void wpa_set_pmk(uint8_t *pmk, const u8 *pmkid, bool cache_pmksa) { struct wpa_sm *sm = &gWpaSm; memcpy(sm->pmk, pmk, PMK_LEN); sm->pmk_len = PMK_LEN; + + if (cache_pmksa) { + pmksa_cache_add(sm->pmksa, pmk, PMK_LEN, pmkid, NULL, 0, + sm->bssid, sm->own_addr, + sm->network_ctx, sm->key_mgmt); + } } int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len) @@ -2112,9 +2115,10 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, memcpy(sm->own_addr, macddr, ETH_ALEN); memcpy(sm->bssid, bssid, ETH_ALEN); sm->ap_notify_completed_rsne = esp_wifi_sta_is_ap_notify_completed_rsne_internal(); - - if (esp_wifi_sta_prof_is_wpa2_internal() - && esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT) { + + if (sm->key_mgmt == WPA_KEY_MGMT_SAE || + (esp_wifi_sta_prof_is_wpa2_internal() && + esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT)) { pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0); wpa_sm_set_pmk_from_pmksa(sm); } @@ -2154,7 +2158,7 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) * PMK. */ if (sm->key_mgmt == WPA_KEY_MGMT_SAE) - return; + return; /* This is really SLOW, so just re cacl while reset param */ if (esp_wifi_sta_get_reset_param_internal() != 0) { @@ -2359,5 +2363,13 @@ bool wpa_sta_is_cur_pmksa_set(void) { return (pmksa_cache_get_current(sm) != NULL); } +void wpa_sta_clear_curr_pmksa(void) { + struct wpa_sm *sm = &gWpaSm; + + if (sm->pmksa) + pmksa_cache_flush(sm->pmksa, NULL, sm->pmk, sm->pmk_len); + pmksa_cache_clear_current(sm); +} + #endif // ESP_SUPPLICANT diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index 81aa28b547..03ee4707b1 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -113,7 +113,7 @@ void wpa_sm_set_state(enum wpa_states state); char * dup_binstr(const void *src, size_t len); -void wpa_set_pmk(uint8_t *pmk); +void wpa_set_pmk(uint8_t *pmk, const u8 *pmkid, bool cache_pmksa); int wpa_hook_init(void); @@ -127,5 +127,7 @@ wifi_cipher_type_t cipher_type_map_supp_to_public(uint32_t wpa_cipher); uint32_t cipher_type_map_supp_to_public(wifi_cipher_type_t cipher); +void wpa_sta_clear_curr_pmksa(void); + #endif /* WPA_H */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index 9aaf3bc4ae..d648a45429 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -220,9 +220,9 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, #ifdef CONFIG_IEEE80211W if (sm->pmf_cfg.capable) { capab |= WPA_CAPABILITY_MFPC; - if (sm->pmf_cfg.required) { + if (sm->pmf_cfg.required || key_mgmt == WPA_KEY_MGMT_SAE) { capab |= WPA_CAPABILITY_MFPR; - } + } } #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(pos, capab); From bc7a34b49419ce4ce0c771176769141be4b61c7e Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Thu, 30 Apr 2020 11:37:42 +0530 Subject: [PATCH 13/16] wpa_supplicant: Disable TLSv1.2 by default Some Enterprise Authentication Servers do not support TLS v1.2. Move this option to Menuconfig and disable by default. --- components/wpa_supplicant/CMakeLists.txt | 1 - components/wpa_supplicant/Kconfig | 6 ++++++ components/wpa_supplicant/port/include/supplicant_opt.h | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 9092825281..e1bfcc71b7 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -109,7 +109,6 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE ESPRESSIF_USE ESP32_WORKAROUND CONFIG_ECC - CONFIG_TLSV12 CONFIG_SHA256 CONFIG_IEEE80211W CONFIG_WPA3_SAE diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig index 927dc0165a..451bb78fff 100644 --- a/components/wpa_supplicant/Kconfig +++ b/components/wpa_supplicant/Kconfig @@ -6,4 +6,10 @@ menu "Supplicant" help Select this option to use MbedTLS crypto API's which utilize hardware acceleration. + config WPA_TLS_V12 + bool "Enable TLS v1.2" + default n + help + Select this to enable TLS v1.2 for WPA2-Enterprise Authentication. + endmenu diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h index 12d607add3..26e4f10a77 100644 --- a/components/wpa_supplicant/port/include/supplicant_opt.h +++ b/components/wpa_supplicant/port/include/supplicant_opt.h @@ -21,4 +21,8 @@ #define USE_MBEDTLS_CRYPTO 1 #endif +#if CONFIG_WPA_TLS_V12 +#define CONFIG_TLSV12 +#endif + #endif /* _SUPPLICANT_OPT_H */ From 1fc54cfad8e855c49a77a9b0a46a4cbab0007f16 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Sat, 2 May 2020 10:16:48 +0530 Subject: [PATCH 14/16] Increase example cmake parallel jobs number --- tools/ci/config/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/config/build.yml b/tools/ci/config/build.yml index 6a950f006d..69e89f7b9f 100644 --- a/tools/ci/config/build.yml +++ b/tools/ci/config/build.yml @@ -155,7 +155,7 @@ build_examples_make: # same as above, but for CMake .build_examples_cmake: &build_examples_cmake extends: .build_template - parallel: 5 + parallel: 8 artifacts: when: always paths: From 5e33a351f1191940dcd33072c39bc569cb7ded11 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Mon, 4 May 2020 11:31:54 +0530 Subject: [PATCH 15/16] esp_wifi: Enable WPA3 & PMF by default --- components/esp_wifi/Kconfig | 2 +- .../getting_started/station/main/station_example_main.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 0dd122d611..47b548f213 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -297,7 +297,7 @@ menu "Wi-Fi" config ESP32_WIFI_ENABLE_WPA3_SAE bool "Enable WPA3-Personal" - default n + default y help Select this option to allow the device to establish a WPA3-Personal connection with eligible AP's. PMF (Protected Management Frames) is a prerequisite feature for a WPA3 connection, it needs to be diff --git a/examples/wifi/getting_started/station/main/station_example_main.c b/examples/wifi/getting_started/station/main/station_example_main.c index 29ba42fc23..144acc5b92 100644 --- a/examples/wifi/getting_started/station/main/station_example_main.c +++ b/examples/wifi/getting_started/station/main/station_example_main.c @@ -81,7 +81,11 @@ void wifi_init_sta() wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_ESP_WIFI_SSID, - .password = EXAMPLE_ESP_WIFI_PASS + .password = EXAMPLE_ESP_WIFI_PASS, + .pmf_cfg = { + .capable = true, + .required = false + }, }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); From 4557c686b8bedcc6213520bb5f04f460b78d4dc7 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Mon, 4 May 2020 15:09:46 +0530 Subject: [PATCH 16/16] wpa_supplicant: Fix EAP Re-authentication issue EAP reauth frames are dropped at various stages due to current implementation of WPA2 ENT states and EAP SM init/deinit logic. Route EAPOL frames based on EAP pkt type and maintain EAP SM to facilitate EAP re-authentication process. --- components/esp_wifi/lib_esp32 | 2 +- .../src/esp_supplicant/esp_wpa2.c | 34 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 78c0f85ad4..2d738fb92a 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 78c0f85ad4d9bcd62dbfc787694bac8d4e0c0a19 +Subproject commit 2d738fb92a94ac26e6dd38592c7454733fa8a4a9 diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c index fafba677c2..85d8ccd24f 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c @@ -511,7 +511,7 @@ out: return ret; } -static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) +static int eap_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) { struct eap_sm *sm = gEapSm; @@ -545,6 +545,30 @@ static int wpa2_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) #endif } +static int wpa2_ent_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) +{ + struct ieee802_1x_hdr *hdr; + int ret = ESP_OK; + + hdr = (struct ieee802_1x_hdr *) buf; + + switch (hdr->type) { + case IEEE802_1X_TYPE_EAPOL_START: + case IEEE802_1X_TYPE_EAP_PACKET: + case IEEE802_1X_TYPE_EAPOL_LOGOFF: + ret = eap_sm_rx_eapol(src_addr, buf, len, bssid); + break; + case IEEE802_1X_TYPE_EAPOL_KEY: + ret = wpa_sm_rx_eapol(src_addr, buf, len); + break; + default: + wpa_printf(MSG_ERROR, "Unknown EAPOL packet type - %d\n", hdr->type); + break; + } + + return ret; +} + static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid) { struct eap_sm *sm = gEapSm; @@ -613,6 +637,11 @@ static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bss #ifdef EAP_PEER_METHOD switch (ehdr->code) { case EAP_CODE_REQUEST: + /* Handle EAP-reauthentication case */ + if (sm->finish_state == WPA2_ENT_EAP_STATE_SUCCESS) { + wpa_printf(MSG_INFO, ">>>>>wpa2 EAP Re-authentication in progress\n"); + wpa2_set_eap_state(WPA2_ENT_EAP_STATE_IN_PROGRESS); + } req = wpabuf_alloc_copy((u8 *)ehdr, len - sizeof(*hdr)); ret = eap_sm_process_request(sm, req); break; @@ -627,6 +656,7 @@ static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bss wpa_printf(MSG_INFO, ">>>>>wpa2 FINISH\n"); ret = WPA2_ENT_EAP_STATE_SUCCESS; wpa2_set_eap_state(WPA2_ENT_EAP_STATE_SUCCESS); + eap_deinit_prev_method(sm, "EAP Success"); } else { wpa_printf(MSG_INFO, ">>>>>wpa2 FAILED, receive EAP_SUCCESS but pmk is empty, potential attack!\n"); ret = WPA2_ENT_EAP_STATE_FAIL; @@ -825,7 +855,7 @@ esp_err_t esp_wifi_sta_wpa2_ent_enable_fn(void *arg) return ESP_ERR_NO_MEM; } - wpa2_cb->wpa2_sm_rx_eapol = wpa2_sm_rx_eapol; + wpa2_cb->wpa2_sm_rx_eapol = wpa2_ent_rx_eapol; wpa2_cb->wpa2_start = wpa2_start_eapol; wpa2_cb->wpa2_init = eap_peer_sm_init; wpa2_cb->wpa2_deinit = eap_peer_sm_deinit;