From 3d5ca7ee6e6f6aba16e00fda125bee0999ca7d16 Mon Sep 17 00:00:00 2001 From: "kapil.gupta" Date: Mon, 27 Jul 2020 14:41:40 +0530 Subject: [PATCH] wpa_supplicant: Add support for FT psk --- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 4 - components/esp_wifi/include/esp_wifi_types.h | 3 +- components/esp_wifi/lib | 2 +- components/wpa_supplicant/CMakeLists.txt | 25 +- components/wpa_supplicant/Kconfig | 10 +- .../esp_supplicant/src/esp_common.c | 282 +++++- .../esp_supplicant/src/esp_common_i.h | 38 +- .../esp_supplicant/src/esp_scan.c | 7 +- .../esp_supplicant/src/esp_wifi_driver.h | 11 +- .../esp_supplicant/src/esp_wpa_main.c | 29 +- .../wpa_supplicant/include/utils/wpa_debug.h | 4 +- .../port/include/supplicant_opt.h | 22 +- components/wpa_supplicant/src/ap/wpa_auth.c | 89 +- components/wpa_supplicant/src/ap/wpa_auth_i.h | 27 +- .../wpa_supplicant/src/ap/wpa_auth_ie.c | 24 +- components/wpa_supplicant/src/common/bss.h | 1 + components/wpa_supplicant/src/common/dpp.h | 1 - .../src/common/ieee802_11_common.c | 24 +- .../src/common/ieee802_11_common.h | 1 + components/wpa_supplicant/src/common/scan.c | 2 + .../wpa_supplicant/src/common/wpa_common.c | 546 ++++++++++- .../wpa_supplicant/src/common/wpa_common.h | 62 +- .../src/common/wpa_supplicant_i.h | 12 +- components/wpa_supplicant/src/rsn_supp/wpa.c | 114 ++- components/wpa_supplicant/src/rsn_supp/wpa.h | 158 ++- .../wpa_supplicant/src/rsn_supp/wpa_ft.c | 900 ++++++++++++++++++ .../wpa_supplicant/src/rsn_supp/wpa_i.h | 57 +- components/wpa_supplicant/src/utils/common.h | 2 + examples/wifi/roaming/main/roaming_example.c | 1 + examples/wifi/roaming/sdkconfig.defaults | 1 + tools/ci/check_copyright_ignore.txt | 1 - 31 files changed, 2112 insertions(+), 348 deletions(-) create mode 100644 components/wpa_supplicant/src/rsn_supp/wpa_ft.c diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 5e568a805bd..1ec1ed78057 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -2010,7 +2010,6 @@ dbg_hmac_rxtx_statis_dump = 0x40001e84; dbg_hmac_statis_dump = 0x40001e88; ieee80211_send_action_vendor_spec = 0x40001e8c; ieee80211_send_mgmt = 0x40001e90; -ieee80211_auth_construct = 0x40001e94; ieee80211_vnd_lora_ie_size = 0x40001ea0; ieee80211_vnd_ie_size = 0x40001ea4; ieee80211_add_ssid = 0x40001ea8; @@ -2032,7 +2031,6 @@ cnx_coexist_timeout = 0x40001ee8; sta_recv_mgmt = 0x40001eec; ieee80211_send_setup = 0x40001ef0; ieee80211_send_probereq = 0x40001ef4; -sta_auth_open = 0x40001ef8; sta_auth_shared = 0x40001efc; sta_auth_sae = 0x40001f00; cnx_coexist_timeout_process = 0x40001f04; @@ -2046,7 +2044,6 @@ ieee80211_add_csa = 0x40001f20; ieee80211_add_extcap = 0x40001f24; ieee80211_regdomain_get_country = 0x40001f28; ieee80211_add_countryie = 0x40001f2c; -ieee80211_alloc_proberesp = 0x40001f30; ieee80211_amsdu_adjust_head = 0x40001f34; ieee80211_amsdu_adjust_last_length = 0x40001f38; ieee80211_amsdu_send_check = 0x40001f3c; @@ -2078,7 +2075,6 @@ ieee80211_set_max_rate = 0x40001fa4; ic_set_sta = 0x40001fa8; ieee80211_match_security = 0x40001fac; ieee80211_parse_wpa = 0x40001fb0; -ieee80211_parse_rsn = 0x40001fb4; ieee80211_add_assoc_req_ies = 0x40001fb8; ieee80211_add_probe_req_ies = 0x40001fbc; /* Data (.data, .bss, .rodata) */ diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 654b64fe906..c1c5da08a50 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -249,7 +249,8 @@ typedef struct { uint32_t rm_enabled:1; /**< Whether Radio Measurements are enabled for the connection */ uint32_t btm_enabled:1; /**< Whether BSS Transition Management is enabled for the connection */ uint32_t mbo_enabled:1; /**< Whether MBO is enabled for the connection */ - uint32_t reserved:29; /**< Reserved for future feature set */ + uint32_t ft_enabled:1; /**< Whether FT is enabled for the connection */ + uint32_t reserved:28; /**< Reserved for future feature set */ } wifi_sta_config_t; /** @brief Configuration data for ESP32 AP or STA. diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 39fd190dfaa..3298902a408 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 39fd190dfaa5b41f564bdb3b86519bea7b7255f9 +Subproject commit 3298902a408a9c57a1c3d94d38d7641c7b872d42 diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index f4137e3666f..d2e71fad6ef 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -58,6 +58,7 @@ set(srcs "port/os_xtensa.c" set(esp_srcs "esp_supplicant/src/esp_wpa2.c" "esp_supplicant/src/esp_wpa_main.c" "esp_supplicant/src/esp_wpas_glue.c" + "esp_supplicant/src/esp_common.c" "esp_supplicant/src/esp_wps.c" "esp_supplicant/src/esp_wpa3.c") if(CONFIG_ESP_WIFI_SOFTAP_SUPPORT) @@ -147,16 +148,18 @@ else() "src/crypto/sha256.c") endif() -if(CONFIG_WPA_11KV_SUPPORT) +if(CONFIG_WPA_11KV_SUPPORT OR CONFIG_WPA_11R_SUPPORT) set(roaming_src - "src/common/rrm.c" - "src/common/wnm_sta.c" "src/common/bss.c" "src/common/scan.c" "src/common/ieee802_11_common.c" - "esp_supplicant/src/esp_common.c" - "esp_supplicant/src/esp_scan.c" - ) + "esp_supplicant/src/esp_scan.c") + if(CONFIG_WPA_11KV_SUPPORT) + set(roaming_src ${roaming_src} "src/common/rrm.c" "src/common/wnm_sta.c") + endif() + if(CONFIG_WPA_11R_SUPPORT) + set(roaming_src ${roaming_src} "src/rsn_supp/wpa_ft.c") + endif() else() set(roaming_src "") endif() @@ -180,7 +183,7 @@ idf_component_register(SRCS "${srcs}" ${esp_srcs} "${tls_src}" "${roaming_src}" PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src PRIV_REQUIRES mbedtls esp_timer) -target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing -Wno-write-strings) +target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing -Wno-write-strings -Werror) target_compile_definitions(${COMPONENT_LIB} PRIVATE __ets__ ESP_SUPPLICANT @@ -200,7 +203,6 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_ECC CONFIG_IEEE80211W CONFIG_SHA256 - CONFIG_WNM ) if(CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE) @@ -221,11 +223,16 @@ endif() if(CONFIG_ESP_WIFI_GMAC_SUPPORT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_GMAC) endif() - if(CONFIG_WPA_MBO_SUPPORT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_MBO) endif() if(CONFIG_WPA_DPP_SUPPORT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_DPP) endif() +if(CONFIG_WPA_11KV_SUPPORT) + target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_SUPPLICANT_TASK CONFIG_WNM CONFIG_RRM) +endif() +if(CONFIG_WPA_11R_SUPPORT) + target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_IEEE80211R) +endif() set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3) diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig index 1536a508cfa..b36fbf45ea9 100644 --- a/components/wpa_supplicant/Kconfig +++ b/components/wpa_supplicant/Kconfig @@ -53,7 +53,7 @@ menu "Supplicant" Enabling this may cause inter operability issues with some APs. config WPA_11KV_SUPPORT - bool "Enable 802.11k, 802.11v APIs handling" + bool "Enable 802.11k, 802.11v APIs Support" default n help Select this option to enable 802.11k 802.11v APIs(RRM and BTM support). @@ -77,7 +77,7 @@ menu "Supplicant" will be flushed immediately. config WPA_MBO_SUPPORT - bool "Enable MBO support" + bool "Enable Multi Band Operation Certification Support" default n select WPA_11KV_SUPPORT select WPA_SCAN_CACHE @@ -91,4 +91,10 @@ menu "Supplicant" help Select this option to enable WiFi Easy Connect Support. + config WPA_11R_SUPPORT + bool "Enable 802.11R (Fast Transition)" + default n + help + Select this option to enable WiFi Fast Transition Support. + endmenu diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_common.c b/components/wpa_supplicant/esp_supplicant/src/esp_common.c index 01a0cc1eab3..105ca37aa83 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_common.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_common.c @@ -20,9 +20,13 @@ #include "common/ieee802_11_common.h" #include "esp_rrm.h" #include "esp_wnm.h" +#include "rsn_supp/wpa_i.h" +#include "rsn_supp/wpa.h" +#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) struct wpa_supplicant g_wpa_supp; +#ifdef CONFIG_SUPPLICANT_TASK static TaskHandle_t s_supplicant_task_hdl = NULL; static void *s_supplicant_evt_queue = NULL; static void *s_supplicant_api_lock = NULL; @@ -50,7 +54,9 @@ static int handle_action_frm(u8 *frame, size_t len, return 0; } +#endif +#if defined(CONFIG_WPA_11KV_SUPPORT) static void handle_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender, u8 *payload, size_t len, u32 rssi) { @@ -68,7 +74,7 @@ static void handle_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender, } } -static int mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi) +static int mgmt_rx_action(u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel) { u8 category; u8 bssid[ETH_ALEN]; @@ -80,17 +86,19 @@ static int mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 r return -1; } - category = *payload++; + category = *frame++; len--; if (category == WLAN_ACTION_WNM) { - ieee802_11_rx_wnm_action(wpa_s, sender, payload, len); + ieee802_11_rx_wnm_action(wpa_s, sender, frame, len); } else if (category == WLAN_ACTION_RADIO_MEASUREMENT) { - handle_rrm_frame(wpa_s, sender, payload, len, rssi); + handle_rrm_frame(wpa_s, sender, frame, len, rssi); } return 0; } +#endif +#ifdef CONFIG_SUPPLICANT_TASK static void btm_rrm_task(void *pvParameters) { supplicant_event_t *evt; @@ -110,7 +118,7 @@ static void btm_rrm_task(void *pvParameters) case SIG_SUPPLICANT_RX_ACTION: { struct ieee_mgmt_frame *frm = (struct ieee_mgmt_frame *)evt->data; - mgmt_rx_action(frm->sender, frm->payload, frm->len, frm->channel, frm->rssi); + mgmt_rx_action(frm->payload, frm->len, frm->sender, frm->rssi, frm->channel); os_free(frm); break; } @@ -142,6 +150,7 @@ static void btm_rrm_task(void *pvParameters) /* At this point, we completed */ vTaskDelete(NULL); } +#endif static void clear_bssid_flag(struct wpa_supplicant *wpa_s) { @@ -165,12 +174,13 @@ static void clear_bssid_flag(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "cleared bssid flag"); } -static void register_action_frame(struct wpa_supplicant *wpa_s) +static void register_mgmt_frames(struct wpa_supplicant *wpa_s) { wpa_s->type &= ~(1 << WLAN_FC_STYPE_ACTION); /* subtype is defined only for action frame */ wpa_s->subtype = 0; +#ifdef CONFIG_WPA_11KV_SUPPORT /* current supported features in supplicant: rrm and btm */ if (esp_wifi_is_rm_enabled_internal(WIFI_IF_STA)) wpa_s->subtype = 1 << WLAN_ACTION_RADIO_MEASUREMENT; @@ -179,7 +189,15 @@ static void register_action_frame(struct wpa_supplicant *wpa_s) if (wpa_s->subtype) wpa_s->type |= 1 << WLAN_FC_STYPE_ACTION; +#endif +#ifdef CONFIG_IEEE80211R + /* register auth/assoc frames if FT is enabled */ + if (esp_wifi_is_ft_enabled_internal(ESP_IF_WIFI_STA)) + wpa_s->type |= (1 << WLAN_FC_STYPE_AUTH) | + (1 << WLAN_FC_STYPE_ASSOC_RESP) | + (1 << WLAN_FC_STYPE_REASSOC_RESP); +#endif esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype); } @@ -204,8 +222,8 @@ static void supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base, ie += sizeof(struct wpa_bss); ieee802_11_parse_elems(wpa_s, ie, bss->ie_len); wpa_bss_flush(wpa_s); - /* Register for action frames */ - register_action_frame(wpa_s); + /* Register for mgmt frames */ + register_mgmt_frames(wpa_s); /* clear set bssid flag */ clear_bssid_flag(wpa_s); } @@ -216,7 +234,10 @@ static void supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_bas struct wpa_supplicant *wpa_s = &g_wpa_supp; wifi_event_sta_disconnected_t *disconn = event_data; +#ifdef CONFIG_WPA_11KV_SUPPORT wpas_rrm_reset(wpa_s); + wpas_clear_beacon_rep_data(wpa_s); +#endif if (wpa_s->current_bss) { wpa_s->current_bss = NULL; } @@ -226,23 +247,79 @@ static void supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_bas } } +#ifdef CONFIG_IEEE80211R +static int handle_auth_frame(u8 *frame, size_t len, + u8 *sender, u32 rssi, u8 channel) +{ + if (gWpaSm.key_mgmt == WPA_KEY_MGMT_FT_PSK) { + if (gWpaSm.ft_protocol) { + if (wpa_ft_process_response(&gWpaSm, frame + 6, + len - 6, 0, sender, NULL, 0) < 0) { + wpa_sm_set_ft_params(&gWpaSm, NULL, 0); + return -1; + } + } + } + return 0; +} + +static int handle_assoc_frame(u8 *frame, size_t len, + u8 *sender, u32 rssi, u8 channel) +{ + if (gWpaSm.key_mgmt == WPA_KEY_MGMT_FT_PSK) { + if (gWpaSm.ft_protocol) { + if (wpa_ft_validate_reassoc_resp(&gWpaSm, frame + 6, len - 6, sender)) { + wpa_sm_set_ft_params(&gWpaSm, NULL, 0); + return -1; + } + } + wpa_sm_set_ft_params(&gWpaSm, frame + 6, len - 6); + } + return 0; +} +#endif + static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf) { - if (type == WLAN_FC_STYPE_BEACON || type == WLAN_FC_STYPE_PROBE_RESP) { - return esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf); - } else if (type == WLAN_FC_STYPE_ACTION) { - return handle_action_frm(frame, len, sender, rssi, channel); + int ret = 0; + + switch (type) { + case WLAN_FC_STYPE_BEACON: + case WLAN_FC_STYPE_PROBE_RESP: + ret = esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf); + break; +#ifdef CONFIG_IEEE80211R + case WLAN_FC_STYPE_AUTH: + ret = handle_auth_frame(frame, len, sender, rssi, channel); + break; + case WLAN_FC_STYPE_ASSOC_RESP: + case WLAN_FC_STYPE_REASSOC_RESP: + ret = handle_assoc_frame(frame, len, sender, rssi, channel); + break; +#endif +#if defined(CONFIG_WPA_11KV_SUPPORT) + case WLAN_FC_STYPE_ACTION: +#ifdef CONFIG_SUPPLICANT_TASK + ret = handle_action_frm(frame, len, sender, rssi, channel); +#else + ret = mgmt_rx_action(frame, len, sender, rssi, channel); +#endif + break; +#endif + default: + ret = -1; + break; } - return -1; + return ret; } #ifdef CONFIG_MBO -static bool bss_profile_match(u8 *sender) +bool mbo_bss_profile_match(u8 *bssid) { /* Incase supplicant wants drivers to skip this BSS, return false */ - struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, sender); + struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, bssid); if (!bss) { return true; } @@ -266,8 +343,9 @@ static bool bss_profile_match(u8 *sender) int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) { struct wpa_supplicant *wpa_s = &g_wpa_supp; - int ret; + int ret = 0; +#ifdef CONFIG_SUPPLICANT_TASK s_supplicant_api_lock = xSemaphoreCreateRecursiveMutex(); if (!s_supplicant_api_lock) { wpa_printf(MSG_ERROR, "%s: failed to create Supplicant API lock", __func__); @@ -288,10 +366,12 @@ int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) ret = -1; goto err; } - - esp_scan_init(wpa_s); +#endif +#ifdef CONFIG_WPA_11KV_SUPPORT wpas_rrm_reset(wpa_s); wpas_clear_beacon_rep_data(wpa_s); +#endif + esp_scan_init(wpa_s); esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &supplicant_sta_conn_handler, NULL); @@ -300,14 +380,16 @@ int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) wpa_s->type = 0; wpa_s->subtype = 0; - esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype); +#ifdef CONFIG_IEEE80211R + wpa_s->type |= (1 << WLAN_FC_STYPE_ASSOC_RESP) | (1 << WLAN_FC_STYPE_REASSOC_RESP) | (1 << WLAN_FC_STYPE_AUTH); +#endif + if (esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype) != ESP_OK) { + ret = -1; + goto err; + } wpa_cb->wpa_sta_rx_mgmt = ieee80211_handle_rx_frm; - /* Matching is done only for MBO at the moment, this can be extended for other features*/ #ifdef CONFIG_MBO - wpa_cb->wpa_sta_profile_match = bss_profile_match; dl_list_init(&wpa_s->bss_tmp_disallowed); -#else - wpa_cb->wpa_sta_profile_match = NULL; #endif return 0; err: @@ -320,8 +402,10 @@ void esp_supplicant_common_deinit(void) struct wpa_supplicant *wpa_s = &g_wpa_supp; esp_scan_deinit(wpa_s); +#ifdef CONFIG_WPA_11KV_SUPPORT wpas_rrm_reset(wpa_s); wpas_clear_beacon_rep_data(wpa_s); +#endif esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &supplicant_sta_conn_handler); esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, @@ -330,6 +414,7 @@ void esp_supplicant_common_deinit(void) wpa_s->type = 0; esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype); } +#ifdef CONFIG_SUPPLICANT_TASK if (!s_supplicant_task_hdl && esp_supplicant_post_evt(SIG_SUPPLICANT_DEL_TASK, 0) != 0) { if (s_supplicant_evt_queue) { vQueueDelete(s_supplicant_evt_queue); @@ -339,10 +424,11 @@ void esp_supplicant_common_deinit(void) vSemaphoreDelete(s_supplicant_api_lock); s_supplicant_api_lock = NULL; } - wpa_printf(MSG_ERROR, "failed to send task delete event"); } +#endif } +#ifdef CONFIG_WPA_11KV_SUPPORT int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb, void *cb_ctx) { @@ -365,9 +451,6 @@ int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason, int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan) { int ret = wpas_mbo_update_non_pref_chan(&g_wpa_supp, non_pref_chan); - if (ret == 0) { - esp_set_assoc_ie(); - } return ret; } @@ -455,6 +538,24 @@ static size_t get_mbo_oce_assoc_ie(uint8_t *ie, size_t len) return mbo_ie_len; } + +static uint8_t get_operating_class_ie(uint8_t *ie, size_t len) +{ + uint8_t op_class_ie[4] = {0}; + uint8_t op_class_ie_len = 2; + uint8_t *pos = op_class_ie; + + *pos++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES; + *pos++ = op_class_ie_len; +#define OPER_CLASS 0x51 + /* Current Operating Class */ + *pos++ = OPER_CLASS; +#undef OPER_CLASS + *pos = 0; + os_memcpy(ie, op_class_ie, sizeof(op_class_ie)); + + return op_class_ie_len + 2; +} #endif static uint8_t get_extended_caps_ie(uint8_t *ie, size_t len) @@ -479,27 +580,11 @@ static uint8_t get_extended_caps_ie(uint8_t *ie, size_t len) return ext_caps_ie_len + 2; } - -static uint8_t get_operating_class_ie(uint8_t *ie, size_t len) -{ - uint8_t op_class_ie[4] = {0}; - uint8_t op_class_ie_len = 2; - uint8_t *pos = op_class_ie; - - *pos++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES; - *pos++ = op_class_ie_len; -#define OPER_CLASS 0x51 - /* Current Operating Class */ - *pos++ = OPER_CLASS; -#undef OPER_CLASS - *pos = 0; - os_memcpy(ie, op_class_ie, sizeof(op_class_ie)); - - return op_class_ie_len + 2; -} +#endif void esp_set_scan_ie(void) { +#ifdef CONFIG_WPA_11KV_SUPPORT #define SCAN_IE_LEN 64 uint8_t *ie, *pos; size_t len = SCAN_IE_LEN, ie_len; @@ -522,40 +607,107 @@ void esp_set_scan_ie(void) esp_wifi_set_appie_internal(WIFI_APPIE_PROBEREQ, ie, SCAN_IE_LEN - len, 0); os_free(ie); #undef SCAN_IE_LEN +#endif } -void esp_set_assoc_ie(void) +#ifdef CONFIG_IEEE80211R +static size_t add_mdie(uint8_t *bssid, uint8_t *ie, size_t len) +{ + size_t mdie_len = 0; + struct wpa_sm *sm = &gWpaSm; + + /* Return if MBO IE is not enabled in driver */ + if (!esp_wifi_is_ft_enabled_internal(WIFI_IF_STA)) { + return 0; + } + + struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, bssid); + if (bss && wpa_key_mgmt_ft(sm->key_mgmt)) { + const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); + + if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) { + const u8 *md = mdie + 2; + const u8 *wpa_md = wpa_sm_get_ft_md(sm); + + if (os_memcmp(md, wpa_md, + MOBILITY_DOMAIN_ID_LEN) == 0) { + /* Add mobility domain IE */ + mdie_len = wpa_ft_add_mdie( + sm, ie, + len, mdie); + } + } + } + + return mdie_len; +} +#endif + +void esp_set_assoc_ie(uint8_t *bssid, const u8 *ies, size_t ies_len, bool mdie) { #define ASSOC_IE_LEN 128 uint8_t *ie, *pos; size_t len = ASSOC_IE_LEN, ie_len; - ie = os_malloc(ASSOC_IE_LEN); + ie = os_malloc(ASSOC_IE_LEN + ies_len); if (!ie) { wpa_printf(MSG_ERROR, "failed to allocate ie"); return; } pos = ie; +#ifdef CONFIG_WPA_11KV_SUPPORT ie_len = get_extended_caps_ie(pos, len); pos += ie_len; len -= ie_len; - ie_len = get_operating_class_ie(pos, len); - pos += ie_len; - len -= ie_len; ie_len = get_rm_enabled_ie(pos, len); pos += ie_len; len -= ie_len; #ifdef CONFIG_MBO + ie_len = get_operating_class_ie(pos, len); + pos += ie_len; + len -= ie_len; ie_len = get_mbo_oce_assoc_ie(pos, len); pos += ie_len; len -= ie_len; #endif - esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ); +#endif +#ifdef CONFIG_IEEE80211R + if (mdie) { + ie_len = add_mdie(bssid, pos, len); + pos += ie_len; + len -= ie_len; + } +#endif + if (ies_len) { + os_memcpy(pos, ies, ies_len); + pos += ies_len; + len -= ies_len; + } esp_wifi_set_appie_internal(WIFI_APPIE_ASSOC_REQ, ie, ASSOC_IE_LEN - len, 0); os_free(ie); #undef ASSOC_IE_LEN } +#ifdef CONFIG_IEEE80211R +int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md, + const u8 *ies, size_t ies_len, bool auth_ie) +{ + wpa_printf(MSG_INFO, "Updating FT IEs (len=%d)", ies_len); + if (os_memcmp(sm->mobility_domain, md, MOBILITY_DOMAIN_ID_LEN) != 0) { + return 0; + } + /* Update auth IEs to be used in FT association */ + if (auth_ie) { + esp_wifi_set_appie_internal(WIFI_APPIE_RAM_STA_AUTH, (u8 *)ies, ies_len, 0); + } else { + esp_set_assoc_ie(sm->bssid, ies, ies_len, false); + } + wpa_printf(MSG_INFO, "Updated FT IEs (len=%d) auth_ie=%d", ies_len, auth_ie); + + return 0; +} +#endif + void esp_get_tx_power(uint8_t *tx_power) { #define DEFAULT_MAX_TX_POWER 19 /* max tx power is 19.5 dbm */ @@ -605,6 +757,7 @@ int wpa_drv_send_action(struct wpa_supplicant *wpa_s, return ret; } +#ifdef CONFIG_SUPPLICANT_TASK int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data) { supplicant_event_t *evt = os_zalloc(sizeof(supplicant_event_t)); @@ -631,3 +784,30 @@ int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data) } return 0; } +#endif +#else +int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb, + void *cb_ctx) +{ + return -1; +} + +int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason, + const char *btm_candidates, + int cand_list) +{ + return -1; +} + +int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan) +{ + return -1; +} +void esp_set_scan_ie(void) { } +void esp_set_assoc_ie(uint8_t *bssid, const u8 *ies, size_t ies_len, bool mdie) { } +int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) +{ + return 0; +} +void esp_supplicant_common_deinit(void) { } +#endif diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h index 30e15991278..66624c20d67 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_common_i.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,8 +10,9 @@ #include "utils/includes.h" struct wpa_funcs; +extern struct wpa_supplicant g_wpa_supp; -#ifdef ROAMING_SUPPORT +#ifdef CONFIG_WPA_11KV_SUPPORT struct ieee_mgmt_frame { u8 sender[ETH_ALEN]; u8 channel; @@ -38,35 +39,12 @@ enum SIG_SUPPLICANT { int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data); void esp_get_tx_power(uint8_t *tx_power); +#ifdef CONFIG_MBO +bool mbo_bss_profile_match(u8 *bssid); +#endif +#endif int esp_supplicant_common_init(struct wpa_funcs *wpa_cb); void esp_supplicant_common_deinit(void); void esp_set_scan_ie(void); -void esp_set_assoc_ie(void); -#else - -#include "esp_rrm.h" -#include "esp_wnm.h" -#include "esp_mbo.h" - -static inline void esp_set_scan_ie(void) { } -static inline void esp_set_assoc_ie(void) { } - -int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb, - void *cb_ctx) -{ - return -1; -} - -int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason, - const char *btm_candidates, - int cand_list) -{ - return -1; -} - -int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan) -{ - return -1; -} -#endif +void esp_set_assoc_ie(uint8_t *bssid, const u8 *ies, size_t ies_len, bool add_mdie); #endif diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_scan.c b/components/wpa_supplicant/esp_supplicant/src/esp_scan.c index 7a3a0d6f24d..443ebbcd47a 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_scan.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_scan.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "common/rrm.h" #include "common/ieee802_11_common.h" #include "esp_common_i.h" +#include "esp_scan_i.h" #include "common/wnm_sta.h" #include "esp_scan_i.h" @@ -36,6 +37,7 @@ static void scan_done_event_handler(void *arg, STATUS status) esp_supplicant_handle_scan_done_evt(); } +#if defined(CONFIG_WPA_11KV_SUPPORT) static void handle_wnm_scan_done(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss = wpa_bss_get_next_bss(wpa_s, wpa_s->current_bss); @@ -53,6 +55,7 @@ static void handle_wnm_scan_done(struct wpa_supplicant *wpa_s) } } } +#endif static void scan_done_cleanup(struct wpa_supplicant *wpa_s) { @@ -70,12 +73,14 @@ void esp_supplicant_handle_scan_done_evt(void) struct wpa_supplicant *wpa_s = &g_wpa_supp; wpa_printf(MSG_INFO, "scan done received"); +#if defined(CONFIG_WPA_11KV_SUPPORT) /* Check which module started this, call the respective function */ if (wpa_s->scan_reason == REASON_RRM_BEACON_REPORT) { wpas_beacon_rep_scan_process(wpa_s, wpa_s->scan_start_tsf); } else if (wpa_s->scan_reason == REASON_WNM_BSS_TRANS_REQ) { handle_wnm_scan_done(wpa_s); } +#endif if (wpa_s->scanning) { scan_done_cleanup(wpa_s); } diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 544007a89d6..7ea25d9a6d9 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -49,7 +49,11 @@ typedef enum { /* wifi_appie_t is in rom code and can't be changed anymore, use wifi_appie_ram_t for new app IEs */ typedef enum { - WIFI_APPIE_RAM_MAX = WIFI_APPIE_MAX, + WIFI_APPIE_RAM_BEACON = WIFI_APPIE_MAX, + WIFI_APPIE_RAM_PROBE_RSP, + WIFI_APPIE_RAM_STA_AUTH, + WIFI_APPIE_RAM_AP_AUTH, + WIFI_APPIE_RAM_MAX } wifi_appie_ram_t; enum { @@ -66,7 +70,8 @@ enum { WAPI_AUTH_PSK = 0x0b, WAPI_AUTH_CERT = 0x0c, WPA2_AUTH_ENT_SHA384_SUITE_B = 0x0d, - WPA2_AUTH_INVALID = 0x0e, + WPA2_AUTH_FT_PSK = 0x0e, + WPA2_AUTH_INVALID }; typedef enum { @@ -129,7 +134,6 @@ struct wpa_funcs { int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status); int (*wpa_sta_rx_mgmt)(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf); void (*wpa_config_done)(void); - bool (*wpa_sta_profile_match)(u8 *bssid); }; struct wpa2_funcs { @@ -269,5 +273,6 @@ esp_err_t esp_wifi_remain_on_channel(uint8_t ifx, uint8_t type, uint8_t channel, uint32_t wait_time_ms, wifi_action_rx_cb_t rx_cb); bool esp_wifi_is_mbo_enabled_internal(uint8_t if_index); void esp_wifi_get_pmf_config_internal(wifi_pmf_config_t *pmf_cfg, uint8_t ifx); +bool esp_wifi_is_ft_enabled_internal(uint8_t if_index); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 4c4ba2bda89..19509e751fe 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -66,8 +66,10 @@ void wpa_deauthenticate(u8 reason_code) esp_wifi_deauthenticate_internal(reason_code); } -int wpa_config_profile(void) +int wpa_config_profile(uint8_t *bssid) { + int ret = 0; + 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() || esp_wifi_sta_prof_is_wpa3_internal()) { @@ -75,10 +77,10 @@ int wpa_config_profile(void) } else if (esp_wifi_sta_prof_is_wapi_internal()) { wpa_set_profile(WPA_PROTO_WAPI, esp_wifi_sta_get_prof_authmode_internal()); } else { - /* do nothing */ - return -1; + ret = -1; } - return 0; + + return ret; } int wpa_config_bss(uint8_t *bssid) @@ -116,7 +118,6 @@ bool wpa_attach(void) ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK); } esp_set_scan_ie(); - esp_set_assoc_ie(); return ret; } @@ -169,7 +170,7 @@ int wpa_sta_connect(uint8_t *bssid) { /* use this API to set AP specific IEs during connection */ int ret = 0; - ret = wpa_config_profile(); + ret = wpa_config_profile(bssid); if (ret == 0) { ret = wpa_config_bss(bssid); if (ret) { @@ -184,7 +185,6 @@ int wpa_sta_connect(uint8_t *bssid) void wpa_config_done(void) { /* used in future for setting scan and assoc IEs */ - esp_set_assoc_ie(); } int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data) @@ -225,19 +225,6 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) } } -#ifndef ROAMING_SUPPORT -static inline int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) -{ - wpa_cb->wpa_sta_rx_mgmt = NULL; - wpa_cb->wpa_sta_profile_match = NULL; - - return 0; -} -static inline void esp_supplicant_common_deinit(void) -{ -} -#endif - int esp_supplicant_init(void) { int ret = ESP_OK; diff --git a/components/wpa_supplicant/include/utils/wpa_debug.h b/components/wpa_supplicant/include/utils/wpa_debug.h index c6ac189c228..855f23a579c 100644 --- a/components/wpa_supplicant/include/utils/wpa_debug.h +++ b/components/wpa_supplicant/include/utils/wpa_debug.h @@ -159,8 +159,8 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, #define wpa_dbg(...) do {} while(0) #endif -#define wpa_auth_logger -#define wpa_auth_vlogger +#define wpa_auth_logger(...) do {} while(0) +#define wpa_auth_vlogger(...) do {} while(0) /** * wpa_msg - Conditional printf for default target and ctrl_iface monitors diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h index 59b428d5462..3de8c9cc86b 100644 --- a/components/wpa_supplicant/port/include/supplicant_opt.h +++ b/components/wpa_supplicant/port/include/supplicant_opt.h @@ -1,16 +1,8 @@ -// 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. +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef _SUPPLICANT_OPT_H #define _SUPPLICANT_OPT_H @@ -29,10 +21,6 @@ #define DEBUG_PRINT #endif -#if CONFIG_WPA_11KV_SUPPORT -#define ROAMING_SUPPORT 1 -#endif - #if CONFIG_WPA_SCAN_CACHE #define SCAN_CACHE_SUPPORTED #endif diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index dd31225a833..7b86d57a8d2 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -39,12 +39,12 @@ static int wpa_sm_step(struct wpa_state_machine *sm); static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data, size_t data_len); static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, - struct wpa_group *group); + struct wpa_group *group); static void wpa_request_new_ptk(struct wpa_state_machine *sm); static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, - struct wpa_group *group); + struct wpa_group *group); static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, - struct wpa_group *group); + struct wpa_group *group); static const u32 dot11RSNAConfigGroupUpdateCount = 4; static const u32 dot11RSNAConfigPairwiseUpdateCount = 4; @@ -221,7 +221,7 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, static int wpa_use_aes_cmac(struct wpa_state_machine *sm) { int ret = 0; -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) ret = 1; #endif /* CONFIG_IEEE80211R */ @@ -365,7 +365,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, return NULL; } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init(); if (wpa_auth->ft_pmk_cache == NULL) { wpa_printf( MSG_ERROR, "FT PMK cache initialization failed."); @@ -374,7 +374,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, os_free(wpa_auth); return NULL; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ return wpa_auth; } @@ -402,14 +402,14 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) return -1; -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (sm->ft_completed) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "FT authentication already completed - do not " "start 4-way handshake"); return 0; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ if (sm->started) { memset(&sm->key_replay, 0, sizeof(sm->key_replay)); @@ -447,9 +447,10 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) sm->group->GKeyDoneStations--; sm->GUpdateStationKeys = FALSE; } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP os_free(sm->assoc_resp_ftie); -#endif /* CONFIG_IEEE80211R */ + wpabuf_free(sm->ft_pending_req_ies); +#endif /* CONFIG_IEEE80211R_AP */ wpa_printf( MSG_DEBUG, "wpa_free_sta_sm: free eapol=%p\n", sm->last_rx_eapol_key); os_free(sm->last_rx_eapol_key); os_free(sm->wpa_ie); @@ -513,7 +514,7 @@ static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr, } } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP static int ICACHE_FLASH_ATTR ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, struct wpa_eapol_ie_parse *kde) @@ -560,7 +561,7 @@ static int ICACHE_FLASH_ATTR ft_check_msg_2_of_4(struct wpa_authenticator *wpa_a return 0; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int group) @@ -786,12 +787,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *s wpa_sta_disconnect(wpa_auth, sm->addr); return; } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { wpa_sta_disconnect(wpa_auth, sm->addr); return; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ break; case PAIRWISE_4: if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || @@ -1095,25 +1096,28 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, buf, key_data_len); if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { - if (aes_wrap(sm->PTK.kek, 16, (key_data_len - 8) / 8, buf, + if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, (key_data_len - 8) / 8, buf, (u8 *) (key + 1))) { os_free(hdr); os_free(buf); return; } WPA_PUT_BE16(key->key_data_length, key_data_len); - } else { + } else if (sm->PTK.kek_len == 16) { u8 ek[32]; memcpy(key->key_iv, sm->group->Counter + WPA_NONCE_LEN - 16, 16); inc_byte_array(sm->group->Counter, WPA_NONCE_LEN); memcpy(ek, key->key_iv, 16); - memcpy(ek + 16, sm->PTK.kek, 16); + memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len); memcpy(key + 1, buf, key_data_len); rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len); WPA_PUT_BE16(key->key_data_length, key_data_len); + } else { + os_free(buf); + os_free(hdr); + return; } - os_free(buf); } if (key_info & WPA_KEY_INFO_MIC) { @@ -1280,7 +1284,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) sm->ReAuthenticationRequest = TRUE; break; case WPA_ASSOC_FT: -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP wpa_printf( MSG_DEBUG, "FT: Retry PTK configuration " "after association"); wpa_ft_install_ptk(sm); @@ -1288,14 +1292,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) /* Using FT protocol, not WPA auth state machine */ sm->ft_completed = 1; return 0; -#else /* CONFIG_IEEE80211R */ +#else /* CONFIG_IEEE80211R_AP */ break; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP sm->ft_completed = 0; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_IEEE80211W if (sm->mgmt_frame_prot && event == WPA_AUTH) @@ -1438,20 +1442,20 @@ SM_STATE(WPA_PTK, INITPMK) size_t len = 2 * PMK_LEN; SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk); -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP sm->xxkey_len = 0; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) { wpa_printf( MSG_DEBUG, "WPA: PMK from EAPOL state machine " "(len=%lu)", (unsigned long) len); memcpy(sm->PMK, msk, PMK_LEN); -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (len >= 2 * PMK_LEN) { memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN); sm->xxkey_len = PMK_LEN; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ } else { wpa_printf( MSG_DEBUG, "WPA: Could not get PMK"); } @@ -1476,10 +1480,10 @@ SM_STATE(WPA_PTK, INITPSK) psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL); if (psk) { memcpy(sm->PMK, psk, PMK_LEN); -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP memcpy(sm->xxkey, psk, PMK_LEN); sm->xxkey_len = PMK_LEN; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ } sm->req_replay_counter_used = 0; } @@ -1532,12 +1536,13 @@ SM_STATE(WPA_PTK, PTKSTART) static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, struct wpa_ptk *ptk) { -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64; + size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64; if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) - return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len); -#endif /* CONFIG_IEEE80211R */ + return wpa_auth_derive_ptk_ft(sm, pmk, ptk); +#endif /* CONFIG_IEEE80211R_AP */ return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion", sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce, @@ -1592,7 +1597,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) return; } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { /* * Verify that PMKR1Name from EAPOL-Key message 2/4 matches @@ -1608,7 +1613,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) return; } } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); @@ -1763,12 +1768,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) kde_len = wpa_ie_len + ieee80211w_kde_len(sm); if (gtk) kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */ kde_len += 300; /* FTIE + 2 * TIE */ } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ kde = (u8 *)os_malloc(kde_len); if (kde == NULL) return; @@ -1776,7 +1781,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) pos = kde; memcpy(pos, wpa_ie, wpa_ie_len); pos += wpa_ie_len; -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name); if (res < 0) { @@ -1787,7 +1792,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } pos += res; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ if (gtk) { u8 hdr[2]; hdr[0] = keyidx & 0x03; @@ -1797,7 +1802,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } pos = ieee80211w_kde_add(sm, pos); -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { int res; struct wpa_auth_config *conf; @@ -1829,7 +1834,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60); pos += 4; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ wpa_send_eapol(sm->wpa_auth, sm, (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC | @@ -1889,9 +1894,9 @@ SM_STATE(WPA_PTK, PTKINITDONE) { esp_wifi_wpa_ptk_init_done_internal(sm->addr); } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr); -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ } diff --git a/components/wpa_supplicant/src/ap/wpa_auth_i.h b/components/wpa_supplicant/src/ap/wpa_auth_i.h index fba036732eb..4364da3cfe0 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth_i.h +++ b/components/wpa_supplicant/src/ap/wpa_auth_i.h @@ -1,6 +1,6 @@ /* * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2015, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -83,7 +83,7 @@ struct wpa_state_machine { unsigned int mgmt_frame_prot:1; unsigned int rx_eapol_key_secure:1; unsigned int update_snonce:1; -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP unsigned int ft_completed:1; unsigned int pmk_r1_name_valid:1; #endif /* CONFIG_IEEE80211R */ @@ -103,9 +103,12 @@ struct wpa_state_machine { int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */ -#ifdef CONFIG_IEEE80211R - u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ +#ifdef CONFIG_IEEE80211R_AP + u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the + * first 384 bits of MSK */ size_t xxkey_len; + u8 pmk_r1[PMK_LEN_MAX]; + unsigned int pmk_r1_len; u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth * Request */ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */ @@ -113,7 +116,17 @@ struct wpa_state_machine { u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key * message 2/4 */ u8 *assoc_resp_ftie; -#endif /* CONFIG_IEEE80211R */ + + void (*ft_pending_cb)(void *ctx, const u8 *dst, const u8 *bssid, + u16 auth_transaction, u16 status, + const u8 *ies, size_t ies_len); + void *ft_pending_cb_ctx; + struct wpabuf *ft_pending_req_ies; + u8 ft_pending_pull_nonce[FT_RRB_NONCE_LEN]; + u8 ft_pending_auth_transaction; + u8 ft_pending_current_ap[ETH_ALEN]; + int ft_pending_pull_left_retries; +#endif /* CONFIG_IEEE80211R_AP */ int pending_1_of_4_timeout; u32 index; @@ -165,6 +178,10 @@ struct wpa_authenticator { size_t wpa_ie_len; u8 addr[ETH_ALEN]; +#ifdef CONFIG_IEEE80211R + struct rsn_pmksa_cache *pmksa; + struct wpa_ft_pmk_cache *ft_pmk_cache; +#endif }; diff --git a/components/wpa_supplicant/src/ap/wpa_auth_ie.c b/components/wpa_supplicant/src/ap/wpa_auth_ie.c index 532127c8e54..9534d5a3b0e 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth_ie.c +++ b/components/wpa_supplicant/src/ap/wpa_auth_ie.c @@ -160,7 +160,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, pos += RSN_SELECTOR_LEN; num_suites++; } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); pos += RSN_SELECTOR_LEN; @@ -171,7 +171,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, pos += RSN_SELECTOR_LEN; num_suites++; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_IEEE80211W if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); @@ -314,7 +314,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) return res; pos += res; } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) { res = wpa_write_mdie(&wpa_auth->conf, pos, buf + sizeof(buf) - pos); @@ -322,7 +322,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) return res; pos += res; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { res = wpa_write_wpa_ie(&wpa_auth->conf, pos, buf + sizeof(buf) - pos); @@ -392,12 +392,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; if (0) { } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) selector = RSN_AUTH_KEY_MGMT_FT_802_1X; else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) selector = RSN_AUTH_KEY_MGMT_FT_PSK; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_IEEE80211W else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; @@ -467,12 +467,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } if (0) { } -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_IEEE80211W else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; @@ -542,7 +542,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, sm->mgmt_frame_prot = 1; #endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { wpa_printf( MSG_DEBUG, "RSN: Trying to use FT, but " @@ -556,7 +556,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, return WPA_INVALID_MDIE; } } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ if (ciphers & WPA_CIPHER_CCMP) sm->pairwise = WPA_CIPHER_CCMP; @@ -700,14 +700,14 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) if (*pos == WLAN_EID_RSN) { ie->rsn_ie = pos; ie->rsn_ie_len = pos[1] + 2; -#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_IEEE80211R_AP } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { ie->mdie = pos; ie->mdie_len = pos[1] + 2; } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { ie->ftie = pos; ie->ftie_len = pos[1] + 2; -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R_AP */ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, end, ie); if (ret < 0) diff --git a/components/wpa_supplicant/src/common/bss.h b/components/wpa_supplicant/src/common/bss.h index 9e6f47e2057..7a7003c45e3 100644 --- a/components/wpa_supplicant/src/common/bss.h +++ b/components/wpa_supplicant/src/common/bss.h @@ -10,6 +10,7 @@ #define BSS_H struct wpa_scan_res; +struct wpa_supplicant; /** * struct wpa_bss - BSS table diff --git a/components/wpa_supplicant/src/common/dpp.h b/components/wpa_supplicant/src/common/dpp.h index e56bc642a42..2c44dff2ca1 100644 --- a/components/wpa_supplicant/src/common/dpp.h +++ b/components/wpa_supplicant/src/common/dpp.h @@ -25,7 +25,6 @@ struct dpp_global; #define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */ #define DPP_TCP_PORT 7871 -#define SSID_MAX_LEN 32 #define PMKID_LEN 16 #define PMK_LEN 32 #define PMK_LEN_SUITE_B_192 48 diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.c b/components/wpa_supplicant/src/common/ieee802_11_common.c index 14f426aafa2..8c1af162b38 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.c +++ b/components/wpa_supplicant/src/common/ieee802_11_common.c @@ -6,9 +6,9 @@ * See README for more details. */ -#include "utils/includes.h" +#include "includes.h" -#include "utils/common.h" +#include "common.h" #include "defs.h" #include "ieee802_11_defs.h" #include "ieee802_11_common.h" @@ -37,6 +37,22 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid) return NULL; } +int ieee802_11_ie_count(const u8 *ies, size_t ies_len) +{ + const struct element *elem; + int count = 0; + + if (ies == NULL) + return 0; + + for_each_element(elem, ies, ies_len) + count++; + + return count; +} + + + const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type) { const struct element *elem; @@ -50,6 +66,7 @@ const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type) return NULL; } + size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) { /* @@ -184,6 +201,7 @@ int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, */ int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len) { +#ifdef CONFIG_RRM const struct element *elem; if (!start) @@ -192,7 +210,6 @@ int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t for_each_element(elem, start, len) { u8 id = elem->id; const u8 *pos = elem->data; - switch (id) { case WLAN_EID_RRM_ENABLED_CAPABILITIES: os_memcpy(wpa_s->rrm_ie, pos, 5); @@ -207,6 +224,7 @@ int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t } } +#endif return 0; } diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.h b/components/wpa_supplicant/src/common/ieee802_11_common.h index 0786d3e68cc..c210562c440 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.h +++ b/components/wpa_supplicant/src/common/ieee802_11_common.h @@ -42,4 +42,5 @@ int ieee802_11_ext_capab(const u8 *ie, unsigned int capab); const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type); size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); u8 get_operating_class(u8 chan, int sec_channel); +int ieee802_11_ie_count(const u8 *ies, size_t ies_len); #endif /* IEEE802_11_COMMON_H */ diff --git a/components/wpa_supplicant/src/common/scan.c b/components/wpa_supplicant/src/common/scan.c index dac96e3b808..1a2e1dd15e6 100644 --- a/components/wpa_supplicant/src/common/scan.c +++ b/components/wpa_supplicant/src/common/scan.c @@ -46,12 +46,14 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) wpa_printf(MSG_ERROR, "Memory allocation failed"); return; } +#ifdef CONFIG_WNM if (wpa_s->wnm_mode) { /* Use the same memory */ params->ssids[0].ssid = wpa_s->current_bss->ssid; params->ssids[0].ssid_len = wpa_s->current_bss->ssid_len; params->num_ssids = 1; } +#endif if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) { /* Use the same memory */ params->bssid = wpa_s->next_scan_bssid; diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index 070ba0887ef..4c155fbf0af 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -1,15 +1,9 @@ /* * WPA/RSN - Shared functions for supplicant and authenticator - * Copyright (c) 2002-2008, Jouni Malinen + * Copyright (c) 2002-2018, 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. */ #ifdef ESP_SUPPLICANT @@ -25,8 +19,221 @@ #include "crypto/md5.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" +#include "crypto/crypto.h" #define MD5_MAC_LEN 16 +#ifdef CONFIG_IEEE80211R +int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, + const u8 *ap_addr, u8 transaction_seqnum, + const u8 *mdie, size_t mdie_len, + const u8 *ftie, size_t ftie_len, + const u8 *rsnie, size_t rsnie_len, + const u8 *ric, size_t ric_len, u8 *mic) +{ + u8 *buf, *pos; + size_t buf_len; + + if (kck_len != 16) { + wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u", + (unsigned int) kck_len); + return -1; + } + + buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; + buf = os_malloc(buf_len); + if (buf == NULL) + return -1; + + pos = buf; + os_memcpy(pos, sta_addr, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, ap_addr, ETH_ALEN); + pos += ETH_ALEN; + *pos++ = transaction_seqnum; + if (rsnie) { + os_memcpy(pos, rsnie, rsnie_len); + pos += rsnie_len; + } + if (mdie) { + os_memcpy(pos, mdie, mdie_len); + pos += mdie_len; + } + if (ftie) { + struct rsn_ftie *_ftie; + os_memcpy(pos, ftie, ftie_len); + if (ftie_len < 2 + sizeof(*_ftie)) { + os_free(buf); + return -1; + } + _ftie = (struct rsn_ftie *) (pos + 2); + os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); + pos += ftie_len; + } + if (ric) { + os_memcpy(pos, ric, ric_len); + pos += ric_len; + } + + wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); + if (omac1_aes_128(kck, buf, pos - buf, mic)) { + os_free(buf); + return -1; + } + + os_free(buf); + + return 0; +} + + +static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, + struct wpa_ft_ies *parse) +{ + const u8 *end, *pos; + + parse->ftie = ie; + parse->ftie_len = ie_len; + + pos = ie + sizeof(struct rsn_ftie); + end = ie + ie_len; + + while (pos + 2 <= end && pos + 2 + pos[1] <= end) { + switch (pos[0]) { + case FTIE_SUBELEM_R1KH_ID: + if (pos[1] != FT_R1KH_ID_LEN) { + wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " + "length in FTIE: %d", pos[1]); + return -1; + } + parse->r1kh_id = pos + 2; + break; + case FTIE_SUBELEM_GTK: + parse->gtk = pos + 2; + parse->gtk_len = pos[1]; + break; + case FTIE_SUBELEM_R0KH_ID: + if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { + wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " + "length in FTIE: %d", pos[1]); + return -1; + } + parse->r0kh_id = pos + 2; + parse->r0kh_id_len = pos[1]; + break; +#ifdef CONFIG_IEEE80211W + case FTIE_SUBELEM_IGTK: + parse->igtk = pos + 2; + parse->igtk_len = pos[1]; + break; +#endif /* CONFIG_IEEE80211W */ + } + + pos += 2 + pos[1]; + } + + return 0; +} + + +int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, + struct wpa_ft_ies *parse) +{ + const u8 *end, *pos; + struct wpa_ie_data data; + int ret; + const struct rsn_ftie *ftie; + int prot_ie_count = 0; + + os_memset(parse, 0, sizeof(*parse)); + if (ies == NULL) + return 0; + + pos = ies; + end = ies + ies_len; + while (pos + 2 <= end && pos + 2 + pos[1] <= end) { + switch (pos[0]) { + case WLAN_EID_RSN: + parse->rsn = pos + 2; + parse->rsn_len = pos[1]; + ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, + parse->rsn_len + 2, + &data); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "FT: Failed to parse " + "RSN IE: %d", ret); + return -1; + } + if (data.num_pmkid == 1 && data.pmkid) + parse->rsn_pmkid = data.pmkid; + break; + case WLAN_EID_MOBILITY_DOMAIN: + parse->mdie = pos + 2; + parse->mdie_len = pos[1]; + break; + case WLAN_EID_FAST_BSS_TRANSITION: + if (pos[1] < sizeof(*ftie)) + return -1; + ftie = (const struct rsn_ftie *) (pos + 2); + prot_ie_count = ftie->mic_control[1]; + if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) + return -1; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + parse->tie = pos + 2; + parse->tie_len = pos[1]; + break; + case WLAN_EID_RIC_DATA: + if (parse->ric == NULL) + parse->ric = pos; + break; + } + + pos += 2 + pos[1]; + } + + if (prot_ie_count == 0) + return 0; /* no MIC */ + + /* + * Check that the protected IE count matches with IEs included in the + * frame. + */ + if (parse->rsn) + prot_ie_count--; + if (parse->mdie) + prot_ie_count--; + if (parse->ftie) + prot_ie_count--; + if (prot_ie_count < 0) { + wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " + "the protected IE count"); + return -1; + } + + if (prot_ie_count == 0 && parse->ric) { + wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " + "included in protected IE count"); + return -1; + } + + /* Determine the end of the RIC IE(s) */ + pos = parse->ric; + while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && + prot_ie_count) { + prot_ie_count--; + pos += 2 + pos[1]; + } + parse->ric_len = pos - parse->ric; + if (prot_ie_count) { + wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " + "frame", (int) prot_ie_count); + return -1; + } + + return 0; +} +#endif /* CONFIG_IEEE80211R */ + static unsigned int wpa_kck_len(int akmp) { @@ -113,6 +320,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192) return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; #endif +#ifdef CONFIG_WPA3_SAE + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE) + return WPA_KEY_MGMT_SAE; +#endif /* CONFIG_WPA3_SAE */ return 0; } @@ -164,7 +375,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, int left; int i, count; - memset(data, 0, sizeof(*data)); + os_memset(data, 0, sizeof(*data)); data->proto = WPA_PROTO_RSN; data->pairwise_cipher = WPA_CIPHER_CCMP; data->group_cipher = WPA_CIPHER_CCMP; @@ -181,10 +392,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, } if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { - #ifdef DEBUG_PRINT +#ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", __func__, (unsigned long) rsn_ie_len); - #endif +#endif return -1; } @@ -193,10 +404,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, if (hdr->elem_id != WLAN_EID_RSN || hdr->len != rsn_ie_len - 2 || WPA_GET_LE16(hdr->version) != RSN_VERSION) { - #ifdef DEBUG_PRINT +#ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", __func__); - #endif +#endif return -2; } @@ -208,10 +419,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } else if (left > 0) { - #ifdef DEBUG_PRINT +#ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", __func__, left); - #endif +#endif return -3; } @@ -423,6 +634,194 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, return 0; } +#ifdef CONFIG_IEEE80211R + +/** + * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name + * + * IEEE Std 802.11r-2008 - 8.5.1.5.3 + */ +void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, + const u8 *ssid, size_t ssid_len, + const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, + const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) +{ + u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + + FT_R0KH_ID_MAX_LEN + ETH_ALEN]; + u8 *pos, r0_key_data[48], hash[32]; + const u8 *addr[2]; + size_t len[2]; + + /* + * R0-Key-Data = KDF-384(XXKey, "FT-R0", + * SSIDlength || SSID || MDID || R0KHlength || + * R0KH-ID || S0KH-ID) + * XXKey is either the second 256 bits of MSK or PSK. + * PMK-R0 = L(R0-Key-Data, 0, 256) + * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) + */ + if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) + return; + pos = buf; + *pos++ = ssid_len; + os_memcpy(pos, ssid, ssid_len); + pos += ssid_len; + os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); + pos += MOBILITY_DOMAIN_ID_LEN; + *pos++ = r0kh_id_len; + os_memcpy(pos, r0kh_id, r0kh_id_len); + pos += r0kh_id_len; + os_memcpy(pos, s0kh_id, ETH_ALEN); + pos += ETH_ALEN; + + sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, + r0_key_data, sizeof(r0_key_data)); + os_memcpy(pmk_r0, r0_key_data, PMK_LEN); + + /* + * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) + */ + addr[0] = (const u8 *) "FT-R0N"; + len[0] = 6; + addr[1] = r0_key_data + PMK_LEN; + len[1] = 16; + + sha256_vector(2, addr, len, hash); + os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); +} + + +/** + * wpa_derive_pmk_r1_name - Derive PMKR1Name + * + * IEEE Std 802.11r-2008 - 8.5.1.5.4 + */ +void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, + const u8 *s1kh_id, u8 *pmk_r1_name) +{ + u8 hash[32]; + const u8 *addr[4]; + size_t len[4]; + + /* + * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || + * R1KH-ID || S1KH-ID)) + */ + addr[0] = (const u8 *) "FT-R1N"; + len[0] = 6; + addr[1] = pmk_r0_name; + len[1] = WPA_PMK_NAME_LEN; + addr[2] = r1kh_id; + len[2] = FT_R1KH_ID_LEN; + addr[3] = s1kh_id; + len[3] = ETH_ALEN; + + sha256_vector(4, addr, len, hash); + os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); +} + + +/** + * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 + * + * IEEE Std 802.11r-2008 - 8.5.1.5.4 + */ +void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, + const u8 *r1kh_id, const u8 *s1kh_id, + u8 *pmk_r1, u8 *pmk_r1_name) +{ + u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; + u8 *pos; + + /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ + pos = buf; + os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); + pos += FT_R1KH_ID_LEN; + os_memcpy(pos, s1kh_id, ETH_ALEN); + pos += ETH_ALEN; + + sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); + + wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); +} + + +/** + * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 + * + * IEEE Std 802.11r-2008 - 8.5.1.5.5 + */ +int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, + const u8 *sta_addr, const u8 *bssid, + const u8 *pmk_r1_name, + struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher) +{ + u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; + u8 *pos, hash[32]; + const u8 *addr[6]; + size_t len[6]; + u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; + size_t ptk_len; + + /* + * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || + * BSSID || STA-ADDR) + */ + pos = buf; + os_memcpy(pos, snonce, WPA_NONCE_LEN); + pos += WPA_NONCE_LEN; + os_memcpy(pos, anonce, WPA_NONCE_LEN); + pos += WPA_NONCE_LEN; + os_memcpy(pos, bssid, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, sta_addr, ETH_ALEN); + pos += ETH_ALEN; + + ptk->kck_len = wpa_kck_len(akmp); + ptk->kek_len = wpa_kek_len(akmp); + ptk->tk_len = wpa_cipher_key_len(cipher); + ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len; + + sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len); + + /* + * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || + * ANonce || BSSID || STA-ADDR)) + */ + addr[0] = pmk_r1_name; + len[0] = WPA_PMK_NAME_LEN; + addr[1] = (const u8 *) "FT-PTKN"; + len[1] = 7; + addr[2] = snonce; + len[2] = WPA_NONCE_LEN; + addr[3] = anonce; + len[3] = WPA_NONCE_LEN; + addr[4] = bssid; + len[4] = ETH_ALEN; + addr[5] = sta_addr; + len[5] = ETH_ALEN; + + sha256_vector(6, addr, len, hash); + os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); + + os_memcpy(ptk->kck, tmp, ptk->kck_len); + os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); + os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); + + wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len); + wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len); + wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len); + wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); + + os_memset(tmp, 0, sizeof(tmp)); + + return 0; +} + +#endif /* CONFIG_IEEE80211R */ + + + /** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) @@ -500,7 +899,7 @@ int wpa_compare_rsn_ie(int ft_initial_assoc, if (ie1 == NULL || ie2 == NULL) return -1; - if (ie1len == ie2len && memcmp(ie1, ie2, ie1len) == 0) + if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) return 0; /* identical IEs */ #ifdef CONFIG_IEEE80211R @@ -751,6 +1150,108 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, memcpy(pmkid, hash, PMKID_LEN); } + +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid) +{ + u8 *start, *end, *rpos, *rend; + int added = 0; + + start = ies; + end = ies + *ies_len; + + while (start < end) { + if (*start == WLAN_EID_RSN) + break; + start += 2 + start[1]; + } + if (start >= end) { + wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data"); + return -1; + } + wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification", + start, 2 + start[1]); + + /* Find start of PMKID-Count */ + rpos = start + 2; + rend = rpos + start[1]; + + /* Skip Version and Group Data Cipher Suite */ + rpos += 2 + 4; + /* Skip Pairwise Cipher Suite Count and List */ + rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; + /* Skip AKM Suite Count and List */ + rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; + + if (rpos == rend) { + /* Add RSN Capabilities */ + os_memmove(rpos + 2, rpos, end - rpos); + *rpos++ = 0; + *rpos++ = 0; + added += 2; + start[1] += 2; + rend = rpos; + } else { + /* Skip RSN Capabilities */ + rpos += 2; + if (rpos > rend) { + wpa_printf(MSG_ERROR, + "RSN: Could not parse RSNE in IEs data"); + return -1; + } + } + + if (rpos == rend) { + /* No PMKID-Count field included; add it */ + os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos); + WPA_PUT_LE16(rpos, 1); + rpos += 2; + os_memcpy(rpos, pmkid, PMKID_LEN); + added += 2 + PMKID_LEN; + start[1] += 2 + PMKID_LEN; + } else { + u16 num_pmkid; + + if (rend - rpos < 2) + return -1; + num_pmkid = WPA_GET_LE16(rpos); + /* PMKID-Count was included; use it */ + if (num_pmkid != 0) { + u8 *after; + + if (num_pmkid * PMKID_LEN > rend - rpos - 2) + return -1; + /* + * PMKID may have been included in RSN IE in + * (Re)Association Request frame, so remove the old + * PMKID(s) first before adding the new one. + */ + wpa_printf(MSG_DEBUG, + "RSN: Remove %u old PMKID(s) from RSNE", + num_pmkid); + after = rpos + 2 + num_pmkid * PMKID_LEN; + os_memmove(rpos + 2, after, end - after); + start[1] -= num_pmkid * PMKID_LEN; + added -= num_pmkid * PMKID_LEN; + } + WPA_PUT_LE16(rpos, 1); + rpos += 2; + os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos); + os_memcpy(rpos, pmkid, PMKID_LEN); + added += PMKID_LEN; + start[1] += PMKID_LEN; + } + + wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)", + start, 2 + start[1]); + + *ies_len += added; + + return 0; +} + + + + int wpa_cipher_key_len(int cipher) { switch (cipher) { @@ -813,6 +1314,17 @@ int wpa_cipher_to_alg(int cipher) return WIFI_WPA_ALG_NONE; } + +int wpa_cipher_valid_pairwise(int cipher) +{ + return cipher == WPA_CIPHER_GCMP_256 || + cipher == WPA_CIPHER_CCMP || + cipher == WPA_CIPHER_GCMP || + cipher == WPA_CIPHER_TKIP; +} + + + u32 wpa_cipher_to_suite(int proto, int cipher) { if (cipher & WPA_CIPHER_CCMP) diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index da8132e28c2..a3df1c49dc2 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -1,15 +1,9 @@ /* * WPA definitions shared between hostapd and wpa_supplicant - * Copyright (c) 2002-2008, Jouni Malinen + * Copyright (c) 2002-2018, 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 "os.h" @@ -71,7 +65,7 @@ #define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12) #define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \ RSN_SELECTOR(0x00, 0x0f, 0xac, 13) - +#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9) #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) #define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) @@ -332,6 +326,29 @@ struct rsn_rdie { #endif /* CONFIG_IEEE80211R */ + +#ifdef CONFIG_IEEE80211R +int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, + const u8 *ap_addr, u8 transaction_seqnum, + const u8 *mdie, size_t mdie_len, + const u8 *ftie, size_t ftie_len, + const u8 *rsnie, size_t rsnie_len, + const u8 *ric, size_t ric_len, u8 *mic); +void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, + const u8 *ssid, size_t ssid_len, + const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, + const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name); +void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, + const u8 *s1kh_id, u8 *pmk_r1_name); +void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, + const u8 *r1kh_id, const u8 *s1kh_id, + u8 *pmk_r1, u8 *pmk_r1_name); +int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, + const u8 *sta_addr, const u8 *bssid, + const u8 *pmk_r1_name, + struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher); +#endif /* CONFIG_IEEE80211R */ + struct wpa_ie_data { int proto; int pairwise_cipher; @@ -380,6 +397,30 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len); +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid); + +struct wpa_ft_ies { + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; + const u8 *r1kh_id; + const u8 *gtk; + size_t gtk_len; + const u8 *r0kh_id; + size_t r0kh_id_len; + const u8 *rsn; + size_t rsn_len; + const u8 *rsn_pmkid; + const u8 *tie; + size_t tie_len; + const u8 *igtk; + size_t igtk_len; + const u8 *ric; + size_t ric_len; +}; + +int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse); int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, const u8 *buf, size_t len, u8 *mic); @@ -394,6 +435,7 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, int wpa_cipher_key_len(int cipher); int wpa_cipher_rsc_len(int cipher); int wpa_cipher_to_alg(int cipher); +int wpa_cipher_valid_pairwise(int cipher); int wpa_cipher_valid_mgmt_group(int cipher); u32 wpa_cipher_to_suite(int proto, int cipher); diff --git a/components/wpa_supplicant/src/common/wpa_supplicant_i.h b/components/wpa_supplicant/src/common/wpa_supplicant_i.h index e3506c40cb2..890ea7ff7a4 100644 --- a/components/wpa_supplicant/src/common/wpa_supplicant_i.h +++ b/components/wpa_supplicant/src/common/wpa_supplicant_i.h @@ -71,11 +71,6 @@ enum scan_trigger_reason { }; struct wpa_supplicant { - int disable_btm; - unsigned int disable_mbo_oce; - /* rrm ie */ - uint8_t rrm_ie[5]; - u8 extend_caps[8]; int scanning; enum scan_trigger_reason scan_reason; @@ -105,6 +100,9 @@ struct wpa_supplicant { uint32_t type, subtype; u8 next_scan_chan; #ifdef CONFIG_WNM + int disable_btm; + unsigned int disable_mbo_oce; + u8 extend_caps[8]; u8 wnm_dialog_token; u8 wnm_reply; u8 wnm_num_neighbor_report; @@ -136,9 +134,13 @@ struct wpa_supplicant { struct dl_list bss_tmp_disallowed; #endif /* CONFIG_MBO */ #endif /* CONFIG_WNM */ +#ifdef CONFIG_RRM + /* rrm ie */ + uint8_t rrm_ie[5]; struct rrm_data rrm; struct beacon_rep_data beacon_rep_data; struct os_reltime beacon_rep_scan; +#endif }; struct non_pref_chan_s; diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index ae487c03add..916d5f0e146 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -29,6 +29,8 @@ #include "crypto/aes_wrap.h" #include "crypto/ccmp.h" #include "esp_rom_sys.h" +#include "common/bss.h" +#include "esp_common_i.h" /** * eapol_sm_notify_eap_success - Notification of external EAP success trigger @@ -54,12 +56,6 @@ u8 assoc_ie_buf[ASSOC_IE_LEN+2]; void set_assoc_ie(u8 * assoc_buf); -static int wpa_sm_set_key(struct install_key *sm, enum wpa_alg alg, - u8 *addr, int key_idx, int set_tx, - u8 *seq, size_t seq_len, - u8 *key, size_t key_len, - enum key_flag key_flag); - static int wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size_t key_len, enum key_flag key_flag); void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len); @@ -230,8 +226,8 @@ static inline int wpa_sm_ether_send( struct wpa_sm *sm, const u8 *dest, u16 prot * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written */ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, - int ver, const u8 *dest, u16 proto, - u8 *msg, size_t msg_len, u8 *key_mic) + int ver, const u8 *dest, u16 proto, + u8 *msg, size_t msg_len, u8 *key_mic) { if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { /* @@ -542,6 +538,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, size_t mic_len, hdrlen, rlen; struct wpa_eapol_key *reply; struct wpa_eapol_key_192 *reply192; + u8 *rsn_ie_buf = NULL; u8 *rbuf, *key_mic; if (wpa_ie == NULL) { @@ -552,6 +549,43 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, return -1; } +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->key_mgmt)) { + int res; + + wpa_hexdump(MSG_DEBUG, "WPA: WPA IE before FT processing", + wpa_ie, wpa_ie_len); + /* + * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and + * FTIE from (Re)Association Response. + */ + rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN + + sm->assoc_resp_ies_len); + if (rsn_ie_buf == NULL) + return -1; + os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); + res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len, + sm->pmk_r1_name); + if (res < 0) { + os_free(rsn_ie_buf); + return -1; + } + wpa_hexdump(MSG_DEBUG, + "WPA: WPA IE after PMKID[PMKR1Name] addition into RSNE", + rsn_ie_buf, wpa_ie_len); + + if (sm->assoc_resp_ies) { + wpa_hexdump(MSG_DEBUG, "WPA: Add assoc_resp_ies", + sm->assoc_resp_ies, + sm->assoc_resp_ies_len); + os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies, + sm->assoc_resp_ies_len); + wpa_ie_len += sm->assoc_resp_ies_len; + } + + wpa_ie = rsn_ie_buf; + } +#endif /* CONFIG_IEEE80211R */ wpa_hexdump(MSG_MSGDUMP, "WPA: WPA IE for msg 2/4\n", wpa_ie, wpa_ie_len); mic_len = wpa_mic_len(sm->key_mgmt); @@ -560,6 +594,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, NULL, hdrlen + wpa_ie_len, &rlen, (void *) &reply); if (rbuf == NULL) { + os_free(rsn_ie_buf); return -1; } reply192 = (struct wpa_eapol_key_192 *) reply; @@ -585,7 +620,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, os_memcpy(reply + 1, wpa_ie, wpa_ie_len); } - memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); + os_free(rsn_ie_buf); + os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); wpa_printf(MSG_DEBUG, "WPA Send EAPOL-Key 2/4\n"); @@ -599,6 +635,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, struct wpa_ptk *ptk) { +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->key_mgmt)) + return wpa_derive_ptk_ft(sm, src_addr, key, ptk); +#endif /* CONFIG_IEEE80211R */ return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, ptk, sm->key_mgmt, @@ -783,7 +823,13 @@ void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, * the target AP. */ } - +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->key_mgmt)) { + /* Prepare for the next transition */ + wpa_ft_prepare_auth_request(sm, NULL); + sm->ft_protocol = 1; + } +#endif /* CONFIG_IEEE80211R */ } static int wpa_supplicant_install_gtk(struct wpa_sm *sm, @@ -1918,6 +1964,9 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) "allow invalid version for non-CCMP group " "keys"); #endif + } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { + wpa_printf(MSG_DEBUG, + "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used"); } else goto out; } @@ -2178,6 +2227,8 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode) sm->key_mgmt = WPA_KEY_MGMT_WAPI_PSK; /* for WAPI PSK */ } else if (auth_mode == WPA2_AUTH_ENT_SHA384_SUITE_B) { sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; + } else if (auth_mode == WPA2_AUTH_FT_PSK) { + sm->key_mgmt = WPA_KEY_MGMT_FT_PSK; } else { sm->key_mgmt = WPA_KEY_MGMT_PSK; /* fixed to PSK for now */ } @@ -2251,7 +2302,7 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, #ifdef CONFIG_SUITEB192 extern bool g_wpa_suiteb_certification; if (g_wpa_suiteb_certification) { - if (mgmt_cipher != WIFI_CIPHER_TYPE_AES_GMAC256) { + if (sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256) { wpa_printf(MSG_ERROR, "suite-b 192bit certification, only GMAC256 is supported"); return -1; } @@ -2261,13 +2312,46 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, memset(&sm->pmf_cfg, 0, sizeof(sm->pmf_cfg)); sm->mgmt_group_cipher = WPA_CIPHER_NONE; } +#endif +#ifdef CONFIG_IEEE80211R + if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) { + const u8 *ie, *md = NULL; + struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, (uint8_t *)bssid); + if (!bss) { + return -1; + } + ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); + if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) + md = ie + 2; + if (os_memcmp(md, sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { + /* Reset Auth IE here */ + esp_wifi_unset_appie_internal(WIFI_APPIE_RAM_STA_AUTH); + esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ); + sm->ft_protocol = 0; + } + wpa_sm_set_ft_params(sm, ie, ie ? 2 + ie[1] : 0); + } else { + /* Reset FT parameters */ + wpa_sm_set_ft_params(sm, NULL, 0); + esp_wifi_unset_appie_internal(WIFI_APPIE_RAM_STA_AUTH); + esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ); + } #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) return -1; sm->assoc_wpa_ie_len = res; + esp_set_assoc_ie((uint8_t *)bssid, NULL, 0, true); + os_memset(sm->ssid, 0, sizeof(sm->ssid)); + os_memcpy(sm->ssid, ssid, ssid_len); + sm->ssid_len = ssid_len; wpa_set_passphrase(passphrase, ssid, ssid_len); +#ifdef CONFIG_MBO + if (!mbo_bss_profile_match((u8 *)bssid)) + return -1; +#endif + return 0; } @@ -2310,6 +2394,11 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) memcpy(sm->pmk, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN); sm->pmk_len = PMK_LEN; } +#ifdef CONFIG_IEEE80211R + /* Set XXKey to be PSK for FT key derivation */ + sm->xxkey_len = PMK_LEN; + os_memcpy(sm->xxkey, sm->pmk, PMK_LEN); +#endif /* CONFIG_IEEE80211R */ } void @@ -2328,8 +2417,7 @@ set_assoc_ie(u8 * assoc_buf) sm->config_assoc_ie(sm->proto, assoc_buf, sm->assoc_wpa_ie_len); } -static int -wpa_sm_set_key(struct install_key *key_sm, enum wpa_alg alg, +int wpa_sm_set_key(struct install_key *key_sm, enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, size_t seq_len, u8 *key, size_t key_len, diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index bd617ec72d9..40074e0bc56 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -1,15 +1,9 @@ /* * wpa_supplicant - WPA definitions - * Copyright (c) 2003-2007, Jouni Malinen + * Copyright (c) 2003-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 WPA_H @@ -24,12 +18,11 @@ #include "esp_wifi_crypto_types.h" #include "wpa_i.h" +struct wpa_sm; #define WPA_SM_STATE(_sm) ((_sm)->wpa_state) -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); bool wpa_sta_cur_pmksa_matches_akm(void); @@ -42,87 +35,11 @@ struct l2_ethhdr { be16 h_proto; } STRUCT_PACKED; -/** - * set_key - Configure encryption key - * @ifname: Interface name (for multi-SSID/VLAN support) - * @priv: private driver interface data - * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, - * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK); - * %WPA_ALG_NONE clears the key. - * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for - * broadcast/default keys - * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for - * IGTK - * @set_tx: configure this key as the default Tx key (only used when - * driver does not support separate unicast/individual key - * @seq: sequence number/packet number, seq_len octets, the next - * packet number to be used for in replay protection; configured - * for Rx keys (in most cases, this is only used with broadcast - * keys and set to zero for unicast keys) - * @seq_len: length of the seq, depends on the algorithm: - * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets - * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, - * 8-byte Rx Mic Key - * @key_len: length of the key buffer in octets (WEP: 5 or 13, - * TKIP: 32, CCMP: 16, IGTK: 16) - * - * Returns: 0 on success, -1 on failure - * - * Configure the given key for the kernel driver. If the driver - * supports separate individual keys (4 default keys + 1 individual), - * addr can be used to determine whether the key is default or - * individual. If only 4 keys are supported, the default key with key - * index 0 is used as the individual key. STA must be configured to use - * it as the default Tx key (set_tx is set) and accept Rx for all the - * key indexes. In most cases, WPA uses only key indexes 1 and 2 for - * broadcast keys, so key index 0 is available for this kind of - * configuration. - * - * Please note that TKIP keys include separate TX and RX MIC keys and - * some drivers may expect them in different order than wpa_supplicant - * is using. If the TX/RX keys are swapped, all TKIP encrypted packets - * will tricker Michael MIC errors. This can be fixed by changing the - * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key - * in driver_*.c set_key() implementation, see driver_ndis.c for an - * example on how this can be done. - */ - - -/** - * send_eapol - Optional function for sending EAPOL packets - * @priv: private driver interface data - * @dest: Destination MAC address - * @proto: Ethertype - * @data: EAPOL packet starting with IEEE 802.1X header - * @data_len: Size of the EAPOL packet - * - * Returns: 0 on success, -1 on failure - * - * This optional function can be used to override l2_packet operations - * with driver specific functionality. If this function pointer is set, - * l2_packet module is not used at all and the driver interface code is - * responsible for receiving and sending all EAPOL packets. The - * received EAPOL packets are sent to core code with EVENT_EAPOL_RX - * event. The driver interface is required to implement get_mac_addr() - * handler if send_eapol() is used. - */ - -#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5) - -void pp_michael_mic_failure(u16 isunicast); 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, const u8 *pmkid, bool cache_pmksa); -int wpa_hook_init(void); - -bool wpa_hook_deinit(void); - -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(unsigned cipher); @@ -131,4 +48,71 @@ unsigned cipher_type_map_public_to_supp(wifi_cipher_type_t cipher); void wpa_sta_clear_curr_pmksa(void); +int wpa_sm_set_key(struct install_key *sm, enum wpa_alg alg, + u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, + u8 *key, size_t key_len, + enum key_flag key_flag); + +#ifdef CONFIG_IEEE80211R + +int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len); +int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie); +int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len, + const u8 *mdie); +const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm); +int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, + int ft_action, const u8 *target_ap, + const u8 *ric_ies, size_t ric_ies_len); +int wpa_ft_is_completed(struct wpa_sm *sm); +void wpa_reset_ft_completed(struct wpa_sm *sm); +int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, + size_t ies_len, const u8 *src_addr); +int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, + const u8 *mdie); + +#else /* CONFIG_IEEE80211R */ + +static inline int +wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) +{ + return 0; +} + +static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm, + const u8 *mdie) +{ + return 0; +} + +static inline int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len, + const u8 *mdie) +{ + return 0; +} + +static inline int +wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, + int ft_action, const u8 *target_ap) +{ + return 0; +} + +static inline int wpa_ft_is_completed(struct wpa_sm *sm) +{ + return 0; +} + +static inline void wpa_reset_ft_completed(struct wpa_sm *sm) +{ +} + +static inline int +wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len, + const u8 *src_addr) +{ + return -1; +} + +#endif /* CONFIG_IEEE80211R */ #endif /* WPA_H */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ft.c b/components/wpa_supplicant/src/rsn_supp/wpa_ft.c new file mode 100644 index 00000000000..0c4bad9d9c0 --- /dev/null +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ft.c @@ -0,0 +1,900 @@ +/* + * WPA Supplicant - IEEE 802.11r - Fast BSS Transition + * Copyright (c) 2006-2018, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto/aes_wrap.h" +#include "crypto/random.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "wpa.h" +#include "wpa_i.h" + +#ifdef CONFIG_IEEE80211R + +#define DEFAULT_KEK_LEN 16 + +int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, + const struct wpa_eapol_key *key, struct wpa_ptk *ptk) +{ + u8 ptk_name[WPA_PMK_NAME_LEN]; + const u8 *anonce = key->key_nonce; + + if (sm->xxkey_len == 0) { + wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " + "derivation"); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "FT: xxkey", sm->xxkey, sm->xxkey_len); + wpa_hexdump_key(MSG_DEBUG, "FT: ssid", sm->ssid, sm->ssid_len); + wpa_hexdump_key(MSG_DEBUG, "FT: r0kh_id", sm->r0kh_id, sm->r0kh_id_len); + wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid, + sm->ssid_len, sm->mobility_domain, + sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, + sm->pmk_r0, sm->pmk_r0_name); + wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", + sm->pmk_r0_name, WPA_PMK_NAME_LEN); + wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, + sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); + wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, + WPA_PMK_NAME_LEN); + return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, + sm->bssid, sm->pmk_r1_name, ptk, ptk_name, + sm->key_mgmt, sm->pairwise_cipher); +} + + +/** + * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @ies: Association Response IEs or %NULL to clear FT parameters + * @ies_len: Length of ies buffer in octets + * Returns: 0 on success, -1 on failure + */ +int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) +{ + struct wpa_ft_ies ft; + + if (sm == NULL) + return 0; + + if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) { + os_free(sm->assoc_resp_ies); + sm->assoc_resp_ies = NULL; + sm->assoc_resp_ies_len = 0; + os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); + os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN); + sm->r0kh_id_len = 0; + os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); + sm->ft_protocol = 0; + return 0; + } + + if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0) + return -1; + + if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) + return -1; + + wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", + ft.mdie, MOBILITY_DOMAIN_ID_LEN); + os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN); + sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; + wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", + sm->mdie_ft_capab); + + if (ft.r0kh_id) { + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", + ft.r0kh_id, ft.r0kh_id_len); + os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len); + sm->r0kh_id_len = ft.r0kh_id_len; + } else { + /* FIX: When should R0KH-ID be cleared? We need to keep the + * old R0KH-ID in order to be able to use this during FT. */ + /* + * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN); + * sm->r0kh_id_len = 0; + */ + } + + if (ft.r1kh_id) { + wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", + ft.r1kh_id, FT_R1KH_ID_LEN); + os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN); + } else + os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); + + os_free(sm->assoc_resp_ies); + sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2); + if (sm->assoc_resp_ies) { + u8 *pos = sm->assoc_resp_ies; + + os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); + pos += ft.mdie_len + 2; + + if (ft.ftie) { + os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2); + pos += ft.ftie_len + 2; + } + sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies; + wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from " + "(Re)Association Response", + sm->assoc_resp_ies, sm->assoc_resp_ies_len); + } + + return 0; +} + +/** + * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @len: Buffer for returning the length of the IEs + * @anonce: ANonce or %NULL if not yet available + * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List + * @kck: 128-bit KCK for MIC or %NULL if no MIC is used + * @kck_len: KCK length in octet + * @target_ap: Target AP address + * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL + * @ric_ies_len: Length of ric_ies buffer in octets + * @ap_mdie: Mobility Domain IE from the target AP + * Returns: Pointer to buffer with IEs or %NULL on failure + * + * Caller is responsible for freeing the returned buffer with os_free(); + */ +static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, + const u8 *anonce, const u8 *pmk_name, + const u8 *kck, size_t kck_len, + const u8 *target_ap, + const u8 *ric_ies, size_t ric_ies_len, + const u8 *ap_mdie) +{ + size_t buf_len; + u8 *buf, *pos, *ftie_len, *ftie_pos; + struct rsn_mdie *mdie; + struct rsn_ftie *ftie; + struct rsn_ie_hdr *rsnie; + int mdie_len; + u16 capab; + + sm->ft_completed = 0; + + buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + + 2 + sm->r0kh_id_len + ric_ies_len + 100; + buf = os_zalloc(buf_len); + if (buf == NULL) + return NULL; + pos = buf; + + /* RSNIE[PMKR0Name/PMKR1Name] */ + rsnie = (struct rsn_ie_hdr *) pos; + rsnie->elem_id = WLAN_EID_RSN; + WPA_PUT_LE16(rsnie->version, RSN_VERSION); + pos = (u8 *) (rsnie + 1); + + /* Group Suite Selector */ + if (sm->group_cipher != WPA_CIPHER_CCMP && + sm->group_cipher != WPA_CIPHER_GCMP && + sm->group_cipher != WPA_CIPHER_TKIP) { + wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)", + sm->group_cipher); + os_free(buf); + return NULL; + } + RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, + sm->group_cipher)); + pos += RSN_SELECTOR_LEN; + + /* Pairwise Suite Count */ + WPA_PUT_LE16(pos, 1); + pos += 2; + + /* Pairwise Suite List */ + if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { + wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)", + sm->pairwise_cipher); + os_free(buf); + return NULL; + } + RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, + sm->pairwise_cipher)); + pos += RSN_SELECTOR_LEN; + + /* Authenticated Key Management Suite Count */ + WPA_PUT_LE16(pos, 1); + pos += 2; + + /* Authenticated Key Management Suite List */ + if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); + else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); + else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE) + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); + else { + wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", + sm->key_mgmt); + os_free(buf); + return NULL; + } + pos += RSN_SELECTOR_LEN; + + /* RSN Capabilities */ + capab = 0; +#ifdef CONFIG_IEEE80211W + if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) + capab |= WPA_CAPABILITY_MFPC; +#endif /* CONFIG_IEEE80211W */ + WPA_PUT_LE16(pos, capab); + pos += 2; + + /* PMKID Count */ + WPA_PUT_LE16(pos, 1); + pos += 2; + + /* PMKID List [PMKR0Name/PMKR1Name] */ + os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN); + pos += WPA_PMK_NAME_LEN; + +#ifdef CONFIG_IEEE80211W + if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { + /* Management Group Cipher Suite */ + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + pos += RSN_SELECTOR_LEN; + } +#endif /* CONFIG_IEEE80211W */ + + rsnie->len = (pos - (u8 *) rsnie) - 2; + + /* MDIE */ + mdie_len = wpa_ft_add_mdie(sm, pos, buf_len - (pos - buf), ap_mdie); + if (mdie_len <= 0) { + os_free(buf); + return NULL; + } + mdie = (struct rsn_mdie *) (pos + 2); + pos += mdie_len; + + /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */ + ftie_pos = pos; + *pos++ = WLAN_EID_FAST_BSS_TRANSITION; + ftie_len = pos++; + ftie = (struct rsn_ftie *) pos; + pos += sizeof(*ftie); + os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); + if (anonce) + os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); + if (kck) { + /* R1KH-ID sub-element in third FT message */ + *pos++ = FTIE_SUBELEM_R1KH_ID; + *pos++ = FT_R1KH_ID_LEN; + os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN); + pos += FT_R1KH_ID_LEN; + } + /* R0KH-ID sub-element */ + *pos++ = FTIE_SUBELEM_R0KH_ID; + *pos++ = sm->r0kh_id_len; + os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len); + pos += sm->r0kh_id_len; + *ftie_len = pos - ftie_len - 1; + + if (ric_ies) { + /* RIC Request */ + os_memcpy(pos, ric_ies, ric_ies_len); + pos += ric_ies_len; + } + + if (kck) { + /* + * IEEE Std 802.11r-2008, 11A.8.4 + * MIC shall be calculated over: + * non-AP STA MAC address + * Target AP MAC address + * Transaction seq number (5 for ReassocReq, 3 otherwise) + * RSN IE + * MDIE + * FTIE (with MIC field set to 0) + * RIC-Request (if present) + */ + /* Information element count */ + ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies, + ric_ies_len); + if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5, + ((u8 *) mdie) - 2, 2 + sizeof(*mdie), + ftie_pos, 2 + *ftie_len, + (u8 *) rsnie, 2 + rsnie->len, ric_ies, + ric_ies_len, ftie->mic) < 0) { + wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); + os_free(buf); + return NULL; + } + } + + *len = pos - buf; + + return buf; +} + + +static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) +{ + int keylen; + enum wpa_alg alg; + u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 }; + + wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver."); + + if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { + wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d", + sm->pairwise_cipher); + return -1; + } + + alg = wpa_cipher_to_alg(sm->pairwise_cipher); + keylen = wpa_cipher_key_len(sm->pairwise_cipher); + + if (wpa_sm_set_key(&(sm->install_ptk), alg, (u8 *)bssid, 0, 1, null_rsc, + sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE) < 0) { + wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); + return -1; + } + + return 0; +} + + +/** + * wpa_ft_prepare_auth_request - Generate over-the-air auth request + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @mdie: Target AP MDIE + * Returns: 0 on success, -1 on failure + */ +int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) +{ + u8 *ft_ies; + size_t ft_ies_len; + + /* Generate a new SNonce */ + if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { + wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); + return -1; + } + + ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, + NULL, 0, sm->bssid, NULL, 0, mdie); + if (ft_ies) { + wpa_sm_update_ft_ies(sm, sm->mobility_domain, + ft_ies, ft_ies_len, true); + os_free(ft_ies); + } + + return 0; +} + + +int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *buf, size_t buf_len, + const u8 *ap_mdie) +{ + u8 *pos = buf; + struct rsn_mdie *mdie; + + if (buf_len < 2 + sizeof(*mdie)) { + wpa_printf(MSG_INFO, + "FT: Failed to add MDIE: short buffer, length=%zu", + buf_len); + return 0; + } + + *pos++ = WLAN_EID_MOBILITY_DOMAIN; + *pos++ = sizeof(*mdie); + mdie = (struct rsn_mdie *) pos; + os_memcpy(mdie->mobility_domain, sm->mobility_domain, + MOBILITY_DOMAIN_ID_LEN); + mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] : + sm->mdie_ft_capab; + + return 2 + sizeof(*mdie); +} + + +const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm) +{ + return sm->mobility_domain; +} + + +int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, + int ft_action, const u8 *target_ap, + const u8 *ric_ies, size_t ric_ies_len) +{ + u8 *ft_ies; + size_t ft_ies_len; + struct wpa_ft_ies parse; + struct rsn_mdie *mdie; + struct rsn_ftie *ftie; + u8 ptk_name[WPA_PMK_NAME_LEN]; + int ret; + const u8 *bssid; + + wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); + wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); + + if (ft_action) { + if (!sm->over_the_ds_in_progress) { + wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " + "- drop FT Action Response"); + return -1; + } + + if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " + "with this Target AP - drop FT Action " + "Response"); + return -1; + } + } + + if (!wpa_key_mgmt_ft(sm->key_mgmt)) { + wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " + "enabled for this connection"); + return -1; + } + + if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { + wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); + return -1; + } + + mdie = (struct rsn_mdie *) parse.mdie; + if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || + os_memcmp(mdie->mobility_domain, sm->mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); + return -1; + } + + ftie = (struct rsn_ftie *) parse.ftie; + if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { + wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); + return -1; + } + + if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", + ftie->snonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", + sm->snonce, WPA_NONCE_LEN); + return -1; + } + + if (parse.r0kh_id == NULL) { + wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); + return -1; + } + + if (parse.r0kh_id_len != sm->r0kh_id_len || + os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) + { + wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " + "the current R0KH-ID"); + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", + parse.r0kh_id, parse.r0kh_id_len); + wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", + sm->r0kh_id, sm->r0kh_id_len); + return -1; + } + + if (parse.r1kh_id == NULL) { + wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); + return -1; + } + + if (parse.rsn_pmkid == NULL || + os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) + { + wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in " + "RSNIE"); + return -1; + } + + os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN); + wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); + wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN); + os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN); + wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, + sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); + wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", + sm->pmk_r1_name, WPA_PMK_NAME_LEN); + + bssid = target_ap; + + if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, + sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk, + ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0) + return -1; + + ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, + sm->pmk_r1_name, + sm->ptk.kck, sm->ptk.kck_len, bssid, + ric_ies, ric_ies_len, + parse.mdie ? parse.mdie - 2 : NULL); + if (ft_ies) { + wpa_sm_update_ft_ies(sm, sm->mobility_domain, + ft_ies, ft_ies_len, false); + os_free(ft_ies); + } + + wpa_sm_mark_authenticated(sm, bssid); + ret = wpa_ft_install_ptk(sm, bssid); + if (ret) { + /* + * Some drivers do not support key configuration when we are + * not associated with the target AP. Work around this by + * trying again after the following reassociation gets + * completed. + */ + wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to " + "association - try again after reassociation"); + sm->set_ptk_after_assoc = 1; + } else + sm->set_ptk_after_assoc = 0; + + sm->ft_completed = 1; + if (ft_action) { + /* + * The caller is expected trigger re-association with the + * Target AP. + */ + os_memcpy(sm->bssid, target_ap, ETH_ALEN); + } + + return 0; +} + + +int wpa_ft_is_completed(struct wpa_sm *sm) +{ + if (sm == NULL) + return 0; + + if (!wpa_key_mgmt_ft(sm->key_mgmt)) + return 0; + + return sm->ft_completed; +} + + +void wpa_reset_ft_completed(struct wpa_sm *sm) +{ + if (sm != NULL) + sm->ft_completed = 0; +} + + +static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, + size_t gtk_elem_len) +{ + u8 gtk[32]; + int keyidx; + enum wpa_alg alg; + size_t gtk_len, keylen, rsc_len; + + if (gtk_elem == NULL) { + wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE"); + return 0; + } + + wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp", + gtk_elem, gtk_elem_len); + + if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 || + gtk_elem_len - 19 > sizeof(gtk)) { + wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem " + "length %lu", (unsigned long) gtk_elem_len); + return -1; + } + gtk_len = gtk_elem_len - 19; + if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11, gtk)) { + wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " + "decrypt GTK"); + return -1; + } + + keylen = wpa_cipher_key_len(sm->group_cipher); + rsc_len = wpa_cipher_rsc_len(sm->group_cipher); + alg = wpa_cipher_to_alg(sm->group_cipher); + if (alg == WIFI_WPA_ALG_NONE) { + wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d", + sm->group_cipher); + return -1; + } + + if (gtk_len < keylen) { + wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE"); + return -1; + } + + /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */ + + keyidx = WPA_GET_LE16(gtk_elem) & 0x03; + + if (gtk_elem[2] != keylen) { + wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d " + "negotiated %lu", + gtk_elem[2], (unsigned long) keylen); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen); + if (sm->group_cipher == WPA_CIPHER_TKIP) { + /* Swap Tx/Rx keys for Michael MIC */ + u8 tmp[8]; + os_memcpy(tmp, gtk + 16, 8); + os_memcpy(gtk + 16, gtk + 24, 8); + os_memcpy(gtk + 24, tmp, 8); + } + if (wpa_sm_set_key(&(sm->install_gtk), alg, sm->bssid, keyidx, 0, + (u8 *)(gtk_elem + 3), rsc_len, gtk, keylen, KEY_FLAG_GROUP | KEY_FLAG_RX) < 0) { + wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " + "driver."); + return -1; + } + + return 0; +} + + +#ifdef CONFIG_IEEE80211W +static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, + size_t igtk_elem_len) +{ + u8 igtk[WPA_IGTK_LEN]; + + if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) + return 0; + + if (igtk_elem == NULL) { + wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE"); + return 0; + } + + wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp", + igtk_elem, igtk_elem_len); + + if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) { + wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem " + "length %lu", (unsigned long) igtk_elem_len); + return -1; + } + if (igtk_elem[8] != WPA_IGTK_LEN) { + wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length " + "%d", igtk_elem[8]); + return -1; + } + + if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8, + igtk_elem + 9, igtk)) { + wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " + "decrypt IGTK"); + return -1; + } + + /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */ + + wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk, + WPA_IGTK_LEN); +#ifdef ESP_SUPPLICANT + if (esp_wifi_set_igtk_internal(WIFI_IF_STA, (wifi_wpa_igtk_t *)igtk) < 0) { +#else + keyidx = WPA_GET_LE16(igtk_elem); + if (wpa_sm_set_key(&(sm->install_gtk), WIFI_WPA_ALG_IGTK, sm->bssid, keyidx, 0, + (u8 *)(igtk_elem + 2), 6, igtk, WPA_IGTK_LEN, sm->key_entry_valid) < 0) { +#endif + wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the " + "driver."); + return -1; + } + + return 0; +} +#endif /* CONFIG_IEEE80211W */ + + +int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, + size_t ies_len, const u8 *src_addr) +{ + struct wpa_ft_ies parse; + struct rsn_mdie *mdie; + struct rsn_ftie *ftie; + unsigned int count; + u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN]; + + wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); + + if (!wpa_key_mgmt_ft(sm->key_mgmt)) { + wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " + "enabled for this connection"); + return -1; + } + + if (sm->ft_reassoc_completed) { + wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission"); + return 0; + } + + if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { + wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); + return -1; + } + + mdie = (struct rsn_mdie *) parse.mdie; + if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || + os_memcmp(mdie->mobility_domain, sm->mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); + return -1; + } + + ftie = (struct rsn_ftie *) parse.ftie; + if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { + wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); + return -1; + } + + if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", + ftie->snonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", + sm->snonce, WPA_NONCE_LEN); + return -1; + } + + if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", + ftie->anonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", + sm->anonce, WPA_NONCE_LEN); + return -1; + } + + if (parse.r0kh_id == NULL) { + wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); + return -1; + } + + if (parse.r0kh_id_len != sm->r0kh_id_len || + os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) + { + wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " + "the current R0KH-ID"); + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", + parse.r0kh_id, parse.r0kh_id_len); + wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", + sm->r0kh_id, sm->r0kh_id_len); + return -1; + } + + if (parse.r1kh_id == NULL) { + wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); + return -1; + } + + if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " + "ReassocResp"); + return -1; + } + + if (parse.rsn_pmkid == NULL || + os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) + { + wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " + "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); + return -1; + } + + count = 3; + if (parse.ric) + count += ieee802_11_ie_count(parse.ric, parse.ric_len); + if (ftie->mic_control[1] != count) { + wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " + "Control: received %u expected %u", + ftie->mic_control[1], count); + return -1; + } + + if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6, + parse.mdie - 2, parse.mdie_len + 2, + parse.ftie - 2, parse.ftie_len + 2, + parse.rsn - 2, parse.rsn_len + 2, + parse.ric, parse.ric_len, + mic) < 0) { + wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); + return -1; + } + + if (os_memcmp_const(mic, ftie->mic, 16) != 0) { + wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); + wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); + wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); + return -1; + } + + sm->ft_reassoc_completed = 1; + if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) + return -1; + +#ifdef CONFIG_IEEE80211W + if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0) + return -1; +#endif /* CONFIG_IEEE80211W */ + + if (sm->set_ptk_after_assoc) { + wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we " + "are associated"); + if (wpa_ft_install_ptk(sm, src_addr) < 0) + return -1; + sm->set_ptk_after_assoc = 0; + } + + if (parse.ric) { + wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response", + parse.ric, parse.ric_len); + /* TODO: parse response and inform driver about results when + * using wpa_supplicant SME */ + } + + wpa_printf(MSG_DEBUG, "FT: Completed successfully"); + + return 0; +} + + +/** + * wpa_ft_start_over_ds - Generate over-the-DS auth request + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @target_ap: Target AP Address + * @mdie: Mobility Domain IE from the target AP + * Returns: 0 on success, -1 on failure + */ +int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, + const u8 *mdie) +{ + u8 *ft_ies; + size_t ft_ies_len; + + wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR, + MAC2STR(target_ap)); + + /* Generate a new SNonce */ + if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { + wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); + return -1; + } + + ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, + NULL, 0, target_ap, NULL, 0, mdie); + if (ft_ies) { + sm->over_the_ds_in_progress = 1; + os_memcpy(sm->target_ap, target_ap, ETH_ALEN); + wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len); + os_free(ft_ies); + } + + return 0; +} + +#endif /* CONFIG_IEEE80211R */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index f60036dcf09..451861ef98d 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -1,20 +1,15 @@ /* * Internal WPA/RSN supplicant state machine definitions - * Copyright (c) 2004-2010, Jouni Malinen + * Copyright (c) 2004-2018, 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 WPA_I_H #define WPA_I_H +extern struct wpa_sm gWpaSm; struct install_key { int keys_cleared; enum wpa_alg alg; @@ -31,7 +26,6 @@ struct install_key { struct wpa_sm { u8 pmk[PMK_LEN_MAX]; size_t pmk_len; - struct wpa_ptk ptk, tptk; int ptk_set, tptk_set; u8 snonce[WPA_NONCE_LEN]; @@ -42,6 +36,8 @@ struct wpa_sm { u8 request_counter[WPA_REPLAY_COUNTER_LEN]; struct rsn_pmksa_cache *pmksa; /* PMKSA cache */ struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */ + u8 ssid[32]; + size_t ssid_len; unsigned int pairwise_cipher; unsigned int group_cipher; @@ -91,6 +87,27 @@ struct wpa_sm { wifi_pmf_config_t pmf_cfg; u8 eapol1_count; struct rsn_sppamsdu_sup spp_sup; +#ifdef CONFIG_IEEE80211R + u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ + size_t xxkey_len; + u8 pmk_r0[PMK_LEN]; + u8 pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_LEN]; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; + u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; + size_t r0kh_id_len; + u8 r1kh_id[FT_R1KH_ID_LEN]; + unsigned int ft_completed:1; + unsigned int ft_reassoc_completed:1; + unsigned int ft_protocol:1; + int over_the_ds_in_progress; + u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */ + int set_ptk_after_assoc; + u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */ + u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */ + size_t assoc_resp_ies_len; +#endif /* CONFIG_IEEE80211R */ }; /** @@ -141,6 +158,22 @@ struct wpa_sm { typedef void (* WPA_SEND_FUNC)(void *buffer, u16 len); +int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md, + const u8 *ies, size_t ies_len, bool auth_ie); + +static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action, + const u8 *target_ap, + const u8 *ies, size_t ies_len) +{ + return -1; +} + +static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm, + const u8 *target_ap) +{ + return 0; +} + typedef void (* WPA_SET_ASSOC_IE)(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, @@ -152,6 +185,7 @@ typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code); typedef void (*WPA_NEG_COMPLETE)(void); + bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func, \ WPA_SET_ASSOC_IE set_assoc_ie_func, \ WPA_INSTALL_KEY ppinstallkey, \ @@ -168,4 +202,7 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode); 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); + +int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, + const struct wpa_eapol_key *key, struct wpa_ptk *ptk); #endif /* WPA_I_H */ diff --git a/components/wpa_supplicant/src/utils/common.h b/components/wpa_supplicant/src/utils/common.h index 0596b6ab4f3..ab4d3dda61e 100644 --- a/components/wpa_supplicant/src/utils/common.h +++ b/components/wpa_supplicant/src/utils/common.h @@ -370,6 +370,8 @@ typedef u64 __bitwise le64; #endif /* __GNUC__ */ #endif /* __must_check */ +#define SSID_MAX_LEN 32 + 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); diff --git a/examples/wifi/roaming/main/roaming_example.c b/examples/wifi/roaming/main/roaming_example.c index bad74db9d31..88f6672a270 100644 --- a/examples/wifi/roaming/main/roaming_example.c +++ b/examples/wifi/roaming/main/roaming_example.c @@ -383,6 +383,7 @@ static void initialise_wifi(void) .btm_enabled =1, .mbo_enabled =1, .pmf_cfg.capable = 1, + .ft_enabled =1, }, }; diff --git a/examples/wifi/roaming/sdkconfig.defaults b/examples/wifi/roaming/sdkconfig.defaults index 9154040732a..c8ee7db8188 100644 --- a/examples/wifi/roaming/sdkconfig.defaults +++ b/examples/wifi/roaming/sdkconfig.defaults @@ -1,3 +1,4 @@ CONFIG_WPA_11KV_SUPPORT=y CONFIG_WPA_SCAN_CACHE=y CONFIG_WPA_MBO_SUPPORT=y +CONFIG_WPA_11R_SUPPORT=y diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index d8a4ae1131c..26fba03b740 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1679,7 +1679,6 @@ components/wpa_supplicant/include/utils/wpabuf.h components/wpa_supplicant/port/include/byteswap.h components/wpa_supplicant/port/include/endian.h components/wpa_supplicant/port/include/os.h -components/wpa_supplicant/port/include/supplicant_opt.h components/wpa_supplicant/port/os_xtensa.c components/wpa_supplicant/src/ap/ap_config.c components/wpa_supplicant/src/ap/ap_config.h