diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index c807cd3a73..c2fe6a2aee 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -1,4 +1,3 @@ - menu "Wi-Fi" visible if (SOC_WIFI_SUPPORTED || SOC_WIRELESS_HOST_SUPPORTED) @@ -308,13 +307,6 @@ menu "Wi-Fi" explicitly configured before attempting connection. Please refer to the Wi-Fi Driver API Guide for details. - config ESP_WIFI_ENABLE_SAE_PK - bool "Enable SAE-PK" - default y - depends on (ESP_WIFI_ENABLE_WPA3_SAE && ESP_WIFI_ENABLE_SAE_H2E) - help - Select this option to enable SAE-PK - config ESP_WIFI_ENABLE_SAE_H2E bool "Enable SAE-H2E" default y @@ -322,6 +314,13 @@ menu "Wi-Fi" help Select this option to enable SAE-H2E + config ESP_WIFI_ENABLE_SAE_PK + bool "Enable SAE-PK" + default y + depends on ESP_WIFI_ENABLE_SAE_H2E + help + Select this option to enable SAE-PK + config ESP_WIFI_SOFTAP_SAE_SUPPORT bool "Enable WPA3 Personal(SAE) SoftAP" default y @@ -340,6 +339,13 @@ menu "Wi-Fi" explicitly configured before attempting connection. Please refer to the Wi-Fi Driver API Guide for details. + config ESP_WIFI_WPA3_COMPATIBLE_SUPPORT + bool "Enable WPA3 Compatible support" + default y + depends on ESP_WIFI_ENABLE_SAE_H2E + help + Select this option to support wpa3_compatible mode for station and AP + config ESP_WIFI_SLP_IRAM_OPT bool "WiFi SLP IRAM speed optimization" select PM_SLP_DEFAULT_PARAMS_OPT diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index fb7e7b6764..1c4bb7b213 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -533,8 +533,10 @@ typedef struct { bool ftm_responder; /**< Enable FTM Responder mode */ wifi_pmf_config_t pmf_cfg; /**< Configuration for Protected Management Frame */ wifi_sae_pwe_method_t sae_pwe_h2e; /**< Configuration for SAE PWE derivation method */ - uint8_t transition_disable; /**< Whether to enable transition disable feature */ - uint8_t sae_ext; /**< Enable SAE EXT feature. SOC_GCMP_SUPPORT is required for this feature. */ + uint8_t transition_disable: 1; /**< Whether to enable transition disable feature */ + uint8_t sae_ext: 1; /**< Enable SAE EXT feature. SOC_GCMP_SUPPORT is required for this feature. */ + uint8_t wpa3_compatible_mode: 1; /**< Enable WPA3 compatible authmode feature. Note: Enabling this will override the AP configuration's authmode and pairwise_cipher. The AP will operate as a WPA2 access point for all stations except for those that support WPA3 compatible mode. Only WPA3 compatibility mode stations will be able to use WPA3-SAE */ + uint8_t reserved: 5; /**< Reserved for future feature set */ wifi_bss_max_idle_config_t bss_max_idle_cfg; /**< Configuration for bss max idle, effective if CONFIG_WIFI_BSS_MAX_IDLE_SUPPORT is enabled */ uint16_t gtk_rekey_interval; /**< GTK rekeying interval in seconds. If set to 0, GTK rekeying is disabled. Range: 60 ~ 65535 including 0. */ } wifi_ap_config_t; @@ -561,7 +563,8 @@ typedef struct { uint32_t ft_enabled: 1; /**< Whether FT is enabled for the connection */ uint32_t owe_enabled: 1; /**< Whether OWE is enabled for the connection */ uint32_t transition_disable: 1; /**< Whether to enable transition disable feature */ - uint32_t reserved1: 26; /**< Reserved for future feature set */ + uint32_t disable_wpa3_compatible_mode: 1; /**< Whether to disable wpa3 compatible authmode feature. Disabling this prevents connecting to WPA3-Personal RSN override (compatibility mode) APs; connection falls back to WPA2 only. */ + uint32_t reserved1: 25; /**< Reserved for future feature set */ wifi_sae_pwe_method_t sae_pwe_h2e; /**< Configuration for SAE PWE derivation method */ wifi_sae_pk_mode_t sae_pk_mode; /**< Configuration for SAE-PK (Public Key) Authentication method */ uint8_t failure_retry_cnt; /**< Number of connection retries station will do before moving to next AP. scan_method should be set as WIFI_ALL_CHANNEL_SCAN to use this config. @@ -578,7 +581,7 @@ typedef struct { uint32_t vht_mu_beamformee_disabled: 1; /**< Whether to disable support for operation as an VHT MU beamformee. */ uint32_t vht_mcs8_enabled: 1; /**< Whether to support VHT-MCS8. The default value is 0. */ uint32_t reserved2: 19; /**< Reserved for future feature set */ - uint8_t sae_h2e_identifier[SAE_H2E_IDENTIFIER_LEN];/**< Password identifier for H2E. this needs to be null terminated string */ + uint8_t sae_h2e_identifier[SAE_H2E_IDENTIFIER_LEN]; /**< Password identifier for H2E. Strings null-terminated (length < SAE_H2E_IDENTIFIER_LEN) or non-null terminated (length = SAE_H2E_IDENTIFIER_LEN) are accepted. Non-null terminated string with 0xFF for full length of SAE_H2E_IDENTIFIER_LEN is not considered a valid identifier */ } wifi_sta_config_t; /** diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 5bcb2be0dd..0e7080ea59 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 5bcb2be0dd10ad0da56cba95e8a1a6f16732c5b3 +Subproject commit 0e7080ea59152258608522876ac91b227e1883e9 diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index cafc14a27b..07d0f9566b 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -287,6 +287,9 @@ endif() if(CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_SAE) endif() +if(CONFIG_ESP_WIFI_WPA3_COMPATIBLE_SUPPORT) + target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPA3_COMPAT) +endif() if(CONFIG_ESP_WIFI_WPS_STRICT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPS_STRICT) endif() diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_common.c b/components/wpa_supplicant/esp_supplicant/src/esp_common.c index 9e7f3656fc..60e5cc0e5c 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_common.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_common.c @@ -322,6 +322,10 @@ void supplicant_sta_conn_handler(uint8_t *bssid) u8 *ie; struct wpa_supplicant *wpa_s = &g_wpa_supp; struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid); +#ifdef CONFIG_RRM + struct ieee802_11_elems elems; +#endif + if (!bss) { wpa_printf(MSG_INFO, "connected bss entry not present in scan cache"); return; @@ -329,7 +333,13 @@ void supplicant_sta_conn_handler(uint8_t *bssid) wpa_s->current_bss = bss; ie = (u8 *)bss; ie += sizeof(struct wpa_bss); - ieee802_11_parse_elems(wpa_s, ie, bss->ie_len); +#ifdef CONFIG_RRM + ieee802_11_parse_elems(ie, bss->ie_len, &elems, 0); + if (elems.rrm_enabled_len > 0 && elems.rrm_enabled != NULL) { + os_memcpy(wpa_s->rrm_ie, elems.rrm_enabled, 5); + wpa_s->rrm.rrm_used = true; + } +#endif wpa_bss_flush(wpa_s); /* Register for mgmt frames */ register_mgmt_frames(wpa_s); diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c index da162f0ee5..007a3e928b 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c @@ -84,7 +84,6 @@ void *hostap_init(void) } hapd->conf->sae_pwe = esp_wifi_get_config_sae_pwe_h2e_internal(WIFI_IF_AP); - auth_conf->sae_pwe = hapd->conf->sae_pwe; auth_conf->wpa_group_rekey = esp_wifi_ap_get_gtk_rekeying_config_internal(); #define MIN_GTK_REKEYING_INTERVAL 60 if (auth_conf->wpa_group_rekey && auth_conf->wpa_group_rekey < MIN_GTK_REKEYING_INTERVAL) { @@ -110,6 +109,20 @@ void *hostap_init(void) } } #endif /* CONFIG_IEEE80211W */ + if (esp_wifi_is_wpa3_compatible_mode_enabled(WIFI_IF_AP)) { +#ifdef CONFIG_WPA3_COMPAT + auth_conf->rsn_override_omit_rsnxe = 1; + hapd->conf->rsn_override_omit_rsnxe = 1; + hapd->conf->rsn_override_key_mgmt = WPA_KEY_MGMT_SAE; + hapd->conf->rsn_override_pairwise = WPA_CIPHER_CCMP; + hapd->conf->rsn_override_mfp = MGMT_FRAME_PROTECTION_REQUIRED; + auth_conf->rsn_override_key_mgmt = WPA_KEY_MGMT_SAE; + auth_conf->rsn_override_pairwise = WPA_CIPHER_CCMP; + auth_conf->rsn_override_mfp = MGMT_FRAME_PROTECTION_REQUIRED; +#else + wpa_printf(MSG_ERROR, "ESP_WIFI_WPA3_COMPATIBLE_SUPPORT disabled, ignoring wpa3_compatible configuration"); +#endif + } /* TKIP is compulsory in WPA Mode */ if (auth_conf->wpa == WPA_PROTO_WPA && pairwise_cipher == WIFI_CIPHER_TYPE_CCMP) { pairwise_cipher = WIFI_CIPHER_TYPE_TKIP_CCMP; @@ -136,6 +149,7 @@ void *hostap_init(void) auth_conf->rsn_pairwise = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; } + auth_conf->sae_pwe = hapd->conf->sae_pwe; auth_conf->wpa_key_mgmt = WPA_KEY_MGMT_PSK; auth_conf->eapol_version = EAPOL_VERSION; @@ -192,7 +206,8 @@ void *hostap_init(void) #ifdef CONFIG_SAE if (authmode == WIFI_AUTH_WPA3_PSK || - authmode == WIFI_AUTH_WPA2_WPA3_PSK) { + authmode == WIFI_AUTH_WPA2_WPA3_PSK || + esp_wifi_is_wpa3_compatible_mode_enabled(WIFI_IF_AP)) { if (wpa3_hostap_auth_init(hapd) != 0) { goto fail; } @@ -203,10 +218,13 @@ void *hostap_init(void) hapd->conf->ssid.wpa_passphrase[WIFI_PASSWORD_LEN_MAX - 1] = '\0'; hapd->conf->max_num_sta = esp_wifi_ap_get_max_sta_conn(); auth_conf->transition_disable = esp_wifi_ap_get_transition_disable_internal(); + if (authmode != WIFI_AUTH_WPA3_PSK && - authmode != WIFI_AUTH_WPA2_WPA3_PSK && auth_conf->transition_disable) { + authmode != WIFI_AUTH_WPA2_WPA3_PSK && + !esp_wifi_is_wpa3_compatible_mode_enabled(WIFI_IF_AP) && + auth_conf->transition_disable) { auth_conf->transition_disable = 0; - wpa_printf(MSG_DEBUG, "overriding transition_disable config with 0 as authmode is not WPA3"); + wpa_printf(MSG_DEBUG, "overriding transition_disable config with 0 as authmode is not WPA3/WPA2-WPA3/compatible"); } #ifdef CONFIG_SAE @@ -396,15 +414,20 @@ uint8_t wpa_status_to_reason_code(int status) } } -bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie, - uint8_t wpa_ie_len, uint8_t *rsnxe, uint16_t rsnxe_len, - bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason) +bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, u8 *wpa_ie, + u8 wpa_ie_len, u8 *rsnxe, uint16_t rsnxe_len, + bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason, uint8_t *rsn_selection_ie) { struct hostapd_data *hapd = (struct hostapd_data*)esp_wifi_get_hostap_private_internal(); enum wpa_validate_result res = WPA_IE_OK; int status = WLAN_STATUS_SUCCESS; bool omit_rsnxe = false; +#ifdef CONFIG_WPA3_COMPAT + uint8_t rsn_selection_variant_len = 0; + uint8_t *rsn_selection_variant_ie = NULL; +#endif + if (!sta || !bssid || !wpa_ie) { return false; } @@ -422,6 +445,16 @@ bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie, goto send_resp; } +#ifdef CONFIG_WPA3_COMPAT +#define RSN_SELECTION_IE_OUI_LEN 4 + if (rsn_selection_ie) { + rsn_selection_variant_len = rsn_selection_ie[1] - RSN_SELECTION_IE_OUI_LEN; + rsn_selection_variant_ie = &rsn_selection_ie[RSN_SELECTION_IE_OUI_LEN + 2]; + } + + wpa_auth_set_rsn_selection(sta->wpa_sm, rsn_selection_variant_ie, rsn_selection_variant_len); +#endif + res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, wpa_ie, wpa_ie_len, rsnxe, rsnxe_len); #ifdef CONFIG_SAE if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae && @@ -438,6 +471,12 @@ send_resp: omit_rsnxe = true; } +#ifdef CONFIG_WPA3_COMPAT + if (hapd->conf->rsn_override_omit_rsnxe) { + omit_rsnxe = false; + } +#endif + if (esp_send_assoc_resp(hapd, bssid, status, omit_rsnxe, subtype) != WLAN_STATUS_SUCCESS) { status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; } 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 e99fd88dab..348a48c500 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -129,7 +129,7 @@ struct wpa_funcs { bool (*wpa_sta_in_4way_handshake)(void); void *(*wpa_ap_init)(void); bool (*wpa_ap_deinit)(void *data); - bool (*wpa_ap_join)(void **sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8* rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher); + bool (*wpa_ap_join)(void **sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8* rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *rsn_selection_ie); bool (*wpa_ap_remove)(u8 *bssid); uint8_t *(*wpa_ap_get_wpa_ie)(uint8_t *len); bool (*wpa_ap_rx_eapol)(void *hapd_data, void *sm, u8 *data, size_t data_len); @@ -302,7 +302,7 @@ bool esp_wifi_ap_notify_node_sae_auth_done(uint8_t *mac); bool esp_wifi_ap_is_sta_sae_reauth_node(uint8_t *mac); uint8_t* esp_wifi_sta_get_sae_identifier_internal(void); bool esp_wifi_eb_tx_status_success_internal(void *eb); -uint8_t* esp_wifi_sta_get_rsnxe(u8 *bssid); +uint8_t* esp_wifi_sta_get_ie(u8 *bssid, uint8_t elem_id); esp_err_t esp_wifi_sta_connect_internal(const uint8_t *bssid); void esp_wifi_enable_sae_pk_only_mode_internal(void); uint8_t esp_wifi_ap_get_transition_disable_internal(void); @@ -310,4 +310,5 @@ int esp_wifi_softap_set_obss_overlap(bool overlap); void esp_wifi_set_sigma_internal(bool flag); void esp_wifi_ap_set_group_mgmt_cipher_internal(wifi_cipher_type_t cipher); uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan, uint8_t max_chan, uint8_t inc, uint8_t bw, channel_bitmap_t *non_pref_channels); +bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c index c9b09881ee..153fc63334 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c @@ -37,7 +37,7 @@ static esp_err_t wpa3_build_sae_commit(u8 *bssid, size_t *sae_msg_len) bool valid_pwd_id = false; #ifdef CONFIG_SAE_H2E uint8_t sae_pwe = esp_wifi_get_config_sae_pwe_h2e_internal(WIFI_IF_STA); - const u8 *rsnxe; + const u8 *rsnxe = NULL; uint8_t use_pt = 0; struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal(); u8 rsnxe_capa = 0; @@ -46,9 +46,19 @@ static esp_err_t wpa3_build_sae_commit(u8 *bssid, size_t *sae_msg_len) use_pt = 1; } - rsnxe = esp_wifi_sta_get_rsnxe(bssid); - if (rsnxe && rsnxe[1] >= 1) { - rsnxe_capa = rsnxe[2]; +#ifdef CONFIG_WPA3_COMPAT + if (esp_wifi_is_wpa3_compatible_mode_enabled(WIFI_IF_STA)) { + rsnxe = esp_wifi_sta_get_ie((u8*)bssid, WFA_RSNXE_OVERRIDE_OUI_TYPE); + if (rsnxe) { + rsnxe_capa = rsnxe[2 + 4]; + } + } +#endif + if (!rsnxe) { + rsnxe = esp_wifi_sta_get_ie((u8*)bssid, WLAN_EID_RSNX); + if (rsnxe) { + rsnxe_capa = rsnxe[2]; + } } #endif /* CONFIG_SAE_H2E */ 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 2490a4003a..f8812b780b 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -113,7 +113,7 @@ int wpa_config_bss(uint8_t *bssid) u8 mac[6]; esp_wifi_get_macaddr_internal(0, mac); - ret = wpa_set_bss((char *)mac, (char *)bssid, esp_wifi_sta_get_pairwise_cipher_internal(), esp_wifi_sta_get_group_cipher_internal(), + ret = wpa_set_bss(mac, bssid, esp_wifi_sta_get_pairwise_cipher_internal(), esp_wifi_sta_get_group_cipher_internal(), (char *)esp_wifi_sta_get_prof_password_internal(), ssid->ssid, ssid->len); return ret; } @@ -345,7 +345,7 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) #ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT #ifdef CONFIG_WPS_REGISTRAR -static int check_n_add_wps_sta(struct hostapd_data *hapd, struct sta_info *sta_info, u8 *ies, u8 ies_len, bool *pmf_enable, int subtype) +static int check_n_add_wps_sta(struct hostapd_data *hapd, struct sta_info *sta_info, const u8 *ies, u8 ies_len, bool *pmf_enable, int subtype) { struct wpabuf *wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA); int wps_type = esp_wifi_get_wps_type_internal(); @@ -377,7 +377,7 @@ static int check_n_add_wps_sta(struct hostapd_data *hapd, struct sta_info *sta_i } #endif -static bool hostap_sta_join(void **sta, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8 *rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher) +static bool hostap_sta_join(void **sta, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, u8 *rsnxe, u16 rsnxe_len, bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *rsn_selection_ie) { struct sta_info *sta_info = NULL; struct hostapd_data *hapd = hostapd_get_hapd_data(); @@ -439,7 +439,7 @@ process_old_sta: goto fail; } #endif - if (hostap_new_assoc_sta(sta_info, bssid, wpa_ie, wpa_ie_len, rsnxe, rsnxe_len, pmf_enable, subtype, pairwise_cipher, &reason)) { + if (hostap_new_assoc_sta(sta_info, bssid, wpa_ie, wpa_ie_len, rsnxe, rsnxe_len, pmf_enable, subtype, pairwise_cipher, &reason, rsn_selection_ie)) { goto done; } else { goto fail; diff --git a/components/wpa_supplicant/src/ap/ap_config.c b/components/wpa_supplicant/src/ap/ap_config.c index 5c613a0d37..de1e392ab6 100644 --- a/components/wpa_supplicant/src/ap/ap_config.c +++ b/components/wpa_supplicant/src/ap/ap_config.c @@ -149,8 +149,12 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf) { #ifdef CONFIG_SAE_H2E struct hostapd_ssid *ssid = &conf->ssid; - if ((conf->sae_pwe == SAE_PWE_HUNT_AND_PECK || - !wpa_key_mgmt_sae(conf->wpa_key_mgmt))) + if (conf->sae_pwe == SAE_PWE_HUNT_AND_PECK || + !wpa_key_mgmt_sae(conf->wpa_key_mgmt +#ifdef CONFIG_WPA3_COMPAT + | conf->rsn_override_key_mgmt +#endif + )) return 0; /* PT not needed */ sae_deinit_pt(ssid->pt); diff --git a/components/wpa_supplicant/src/ap/ap_config.h b/components/wpa_supplicant/src/ap/ap_config.h index 731b1da032..49aa678c82 100644 --- a/components/wpa_supplicant/src/ap/ap_config.h +++ b/components/wpa_supplicant/src/ap/ap_config.h @@ -11,6 +11,7 @@ #include "common/defs.h" #include "common/wpa_common.h" +#include "common/ieee802_11_common.h" #define MAX_STA_COUNT 10 #define MAX_VLAN_ID 4094 @@ -199,8 +200,14 @@ struct hostapd_bss_config { int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ int wpa_key_mgmt; +#ifdef CONFIG_WPA3_COMPAT + int rsn_override_key_mgmt; +#endif #ifdef CONFIG_IEEE80211W enum mfp_options ieee80211w; +#ifdef CONFIG_WPA3_COMPAT + enum mfp_options rsn_override_mfp; +#endif /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ unsigned int assoc_sa_query_max_timeout; /* dot11AssociationSAQueryRetryTimeout (in TUs) */ @@ -219,6 +226,9 @@ struct hostapd_bss_config { int wpa_ptk_rekey; int rsn_pairwise; int rsn_preauth; +#ifdef CONFIG_WPA3_COMPAT + int rsn_override_pairwise; +#endif char *rsn_preauth_interfaces; #ifdef CONFIG_IEEE80211R @@ -306,6 +316,9 @@ struct hostapd_bss_config { int *sae_groups; #define SAE_ANTI_CLOGGING_THRESHOLD 2 /* max number of commit msg allowed to queue without anti-clogging token request */ +#ifdef CONFIG_WPA3_COMPAT + int rsn_override_omit_rsnxe; +#endif }; @@ -382,9 +395,9 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, const u8 *addr, const u8 *prev_psk); int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); struct sta_info; -bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie, - uint8_t wpa_ie_len, uint8_t *rsnxe, uint16_t rsnxe_len, - bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason); +bool hostap_new_assoc_sta(struct sta_info *sta, uint8_t *bssid, u8 *wpa_ie, + u8 wpa_ie_len, u8 *rsnxe, uint16_t rsnxe_len, + bool *pmf_enable, int subtype, uint8_t *pairwise_cipher, uint8_t *reason, uint8_t *rsn_selection_ie); bool wpa_ap_remove(u8* bssid); #endif /* HOSTAPD_CONFIG_H */ diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index d38f6082a2..c7c7212ead 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -22,6 +22,7 @@ #include "ap/ap_config.h" #include "ap/sta_info.h" #include "common/wpa_common.h" +#include "common/ieee802_11_common.h" #include "ap/pmksa_cache_auth.h" #include "crypto/aes.h" @@ -196,6 +197,30 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, return -1; } +#ifdef CONFIG_WPA3_COMPAT +void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie, + size_t len) +{ + if (!sm) + return; + if (sm->rsn_selection) { + os_free(sm->rsn_selection); + sm->rsn_selection = NULL; + } + sm->rsn_selection_len = 0; + sm->rsn_override = false; + if (ie) { + if (len >= 1) { + if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE) + sm->rsn_override = true; + } + sm->rsn_selection = os_memdup(ie, len); + if (sm->rsn_selection) + sm->rsn_selection_len = len; + } +} +#endif + /* fix buf for tx for now */ #define WPA_TX_MSG_BUFF_MAXLEN 200 @@ -501,6 +526,9 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) os_free(sm->last_rx_eapol_key); os_free(sm->wpa_ie); os_free(sm->rsnxe); +#ifdef CONFIG_WPA3_COMPAT + os_free(sm->rsn_selection); +#endif os_free(sm); } @@ -958,7 +986,8 @@ continue_processing: sm->EAPOLKeyReceived = TRUE; sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); - memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); + if (msg == PAIRWISE_2) + os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); wpa_sm_step(sm); } @@ -1741,6 +1770,34 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) return; } +#ifdef CONFIG_WPA3_COMPAT + /* Verify RSN Selection element for RSN overriding */ + if (sm->wpa_auth->conf.rsn_override_key_mgmt && + ((rsn_is_snonce_cookie(sm->SNonce) && !kde.rsn_selection) || + (!rsn_is_snonce_cookie(sm->SNonce) && kde.rsn_selection) || + (sm->rsn_selection && !kde.rsn_selection) || + (!sm->rsn_selection && kde.rsn_selection) || + (sm->rsn_selection && kde.rsn_selection && + (sm->rsn_selection_len != kde.rsn_selection_len || + os_memcmp(sm->rsn_selection, kde.rsn_selection, + sm->rsn_selection_len) != 0)))) { + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, + "RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4"); + wpa_printf(MSG_DEBUG, + "SNonce cookie for RSN overriding %sused", + rsn_is_snonce_cookie(sm->SNonce) ? "" : "not "); + wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq", + sm->rsn_selection, sm->rsn_selection_len); + wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4", + kde.rsn_selection, kde.rsn_selection_len); + /* MLME-DEAUTHENTICATE.request */ + wpa_sta_disconnect(sm->wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + + } +#endif + sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(resend_eapol_handle, (void*)(sm->index), NULL); @@ -1832,11 +1889,15 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) SM_STATE(WPA_PTK, PTKINITNEGOTIATING) { - u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32]; + u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32]; size_t gtk_len, kde_len; struct wpa_group *gsm = sm->group; u8 *wpa_ie; int wpa_ie_len, secure, keyidx, encr = 0; +#ifdef CONFIG_WPA3_COMPAT + u8 *wpa_ie_buf3 = NULL; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; +#endif SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = FALSE; @@ -1865,6 +1926,40 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) wpa_ie = wpa_ie + wpa_ie[1] + 2; wpa_ie_len = wpa_ie[1] + 2; } +#ifdef CONFIG_WPA3_COMPAT + if (conf->rsn_override_key_mgmt && + !rsn_is_snonce_cookie(sm->SNonce)) { + u8 *ie; + size_t ie_len; + u32 ids[] = { + RSNE_OVERRIDE_IE_VENDOR_TYPE, + RSNXE_OVERRIDE_IE_VENDOR_TYPE, + 0 + }; + int i; + + wpa_printf(MSG_DEBUG, + "RSN: Remove RSNE/RSNXE override elements"); + wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs before edits", + wpa_ie, wpa_ie_len); + wpa_ie_buf3 = os_memdup(wpa_ie, wpa_ie_len); + if (!wpa_ie_buf3) + goto done; + wpa_ie = wpa_ie_buf3; + + for (i = 0; ids[i]; i++) { + ie = (u8 *) get_vendor_ie(wpa_ie, wpa_ie_len, ids[i]); + if (ie) { + ie_len = 2 + ie[1]; + os_memmove(ie, ie + ie_len, + wpa_ie_len - (ie + ie_len - wpa_ie)); + wpa_ie_len -= ie_len; + } + } + wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs after edits", + wpa_ie, wpa_ie_len); + } +#endif if (sm->wpa == WPA_VERSION_WPA2) { /* WPA2 send GTK in the 4-way handshake */ secure = 1; @@ -1876,7 +1971,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) * of GTK in the BSS. */ if (os_get_random(dummy_gtk, gtk_len) < 0) - return; + goto done; gtk = dummy_gtk; } keyidx = gsm->GN; @@ -1916,8 +2011,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } #endif /* CONFIG_IEEE80211R_AP */ kde = (u8 *)os_malloc(kde_len); - if (kde == NULL) - return; + if (!kde) + goto done; pos = kde; memcpy(pos, wpa_ie, wpa_ie_len); @@ -1928,8 +2023,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) if (res < 0) { wpa_printf( MSG_ERROR, "FT: Failed to insert " "PMKR1Name into RSN IE in EAPOL-Key data"); - os_free(kde); - return; + goto done; } pos += res; } @@ -1959,8 +2053,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) if (res < 0) { wpa_printf( MSG_ERROR, "FT: Failed to insert FTIE " "into EAPOL-Key Key Data"); - os_free(kde); - return; + goto done; } pos += res; @@ -1985,7 +2078,11 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_KEY_TYPE, _rsc, sm->ANonce, kde, pos - kde, keyidx, encr); +done: os_free(kde); +#ifdef CONFIG_WPA3_COMPAT + os_free(wpa_ie_buf3); +#endif } @@ -2296,7 +2393,7 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, group->GTK[group->GN - 1], group->GTK_len); #ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { + if (wpa_auth_pmf_enabled(&wpa_auth->conf)) { len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); inc_byte_array(group->Counter, WPA_NONCE_LEN); @@ -2492,7 +2589,7 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, ret = -1; #ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION && + if (wpa_auth_pmf_enabled(&wpa_auth->conf) && wpa_auth_set_key(wpa_auth, group->vlan_id, WIFI_WPA_ALG_IGTK, broadcast_ether_addr, group->GN_igtk, group->IGTK[group->GN_igtk - 4], diff --git a/components/wpa_supplicant/src/ap/wpa_auth.h b/components/wpa_supplicant/src/ap/wpa_auth.h index e2886a9fee..34ae7bc54d 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.h +++ b/components/wpa_supplicant/src/ap/wpa_auth.h @@ -127,6 +127,9 @@ struct ft_remote_r1kh { struct wpa_auth_config { int wpa; int wpa_key_mgmt; +#ifdef CONFIG_WPA3_COMPAT + int rsn_override_key_mgmt; +#endif int wpa_pairwise; int wpa_group; int wpa_group_rekey; @@ -134,6 +137,9 @@ struct wpa_auth_config { int wpa_gmk_rekey; int wpa_ptk_rekey; int rsn_pairwise; +#ifdef CONFIG_WPA3_COMPAT + int rsn_override_pairwise; +#endif int rsn_preauth; int eapol_version; int wmm_enabled; @@ -143,6 +149,9 @@ struct wpa_auth_config { int tx_status; #ifdef CONFIG_IEEE80211W enum mfp_options ieee80211w; +#ifdef CONFIG_WPA3_COMPAT + enum mfp_options rsn_override_mfp; +#endif #endif /* CONFIG_IEEE80211W */ int group_mgmt_cipher; #ifdef CONFIG_SAE @@ -168,6 +177,9 @@ struct wpa_auth_config { enum sae_pwe sae_pwe; struct rsn_sppamsdu_sup spp_sup; u8 transition_disable; +#ifdef CONFIG_WPA3_COMPAT + int rsn_override_omit_rsnxe; +#endif }; typedef enum { @@ -304,5 +316,16 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid); void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, const u8 *sta_addr); +void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie, + size_t len); +static inline bool wpa_auth_pmf_enabled(struct wpa_auth_config *conf) +{ +#ifdef CONFIG_WPA3_COMPAT + return conf->ieee80211w != NO_MGMT_FRAME_PROTECTION || + conf->rsn_override_mfp != NO_MGMT_FRAME_PROTECTION; +#else + return conf->ieee80211w != NO_MGMT_FRAME_PROTECTION; +#endif +} #endif /* WPA_AUTH_H */ diff --git a/components/wpa_supplicant/src/ap/wpa_auth_i.h b/components/wpa_supplicant/src/ap/wpa_auth_i.h index 09b254ca2d..c66428b1c3 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth_i.h +++ b/components/wpa_supplicant/src/ap/wpa_auth_i.h @@ -100,6 +100,10 @@ struct wpa_state_machine { size_t wpa_ie_len; u8 *rsnxe; size_t rsnxe_len; +#ifdef CONFIG_WPA3_COMPAT + u8 *rsn_selection; + size_t rsn_selection_len; +#endif enum { WPA_VERSION_NO_WPA = 0 /* WPA not used */, @@ -110,6 +114,10 @@ struct wpa_state_machine { int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */ struct rsn_pmksa_cache_entry *pmksa; +#ifdef CONFIG_WPA3_COMPAT + bool rsn_override; +#endif + #ifdef CONFIG_IEEE80211R_AP u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the * first 384 bits of MSK */ @@ -195,7 +203,7 @@ struct wpa_authenticator { int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, - const u8 *pmkid, int group_mgmt_cipher); + const u8 *pmkid); int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len); void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int key_info, diff --git a/components/wpa_supplicant/src/ap/wpa_auth_ie.c b/components/wpa_supplicant/src/ap/wpa_auth_ie.c index 9453aa710d..7d01d002ef 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth_ie.c +++ b/components/wpa_supplicant/src/ap/wpa_auth_ie.c @@ -85,25 +85,57 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) } -int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, - const u8 *pmkid, int group_mgmt_cipher) +static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf, + enum mfp_options mfp) +{ + u16 capab = 0; + + if (conf->rsn_preauth) + capab |= WPA_CAPABILITY_PREAUTH; + if (conf->wmm_enabled) { + /* 4 PTKSA replay counters when using WMM */ + capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); + } + + if (conf->spp_sup.capable) { + capab |= WPA_CAPABILITY_SPP_CAPABLE; + } + + if (conf->spp_sup.require) { + capab |= WPA_CAPABILITY_SPP_REQUIRED; + } + + if (mfp != NO_MGMT_FRAME_PROTECTION) { + capab |= WPA_CAPABILITY_MFPC; + if (mfp == MGMT_FRAME_PROTECTION_REQUIRED) + capab |= WPA_CAPABILITY_MFPR; + } +#ifdef CONFIG_OCV + if (conf->ocv) + capab |= WPA_CAPABILITY_OCVC; +#endif /* CONFIG_OCV */ +#ifdef CONFIG_RSN_TESTING + if (rsn_testing) + capab |= BIT(8) | BIT(15); +#endif /* CONFIG_RSN_TESTING */ + + return capab; +} + + +static u8 * rsne_write_data(u8 *buf, size_t len, u8 *pos, int group, + int pairwise, int key_mgmt, u16 rsn_capab, + const u8 *pmkid, enum mfp_options mfp, + int group_mgmt_cipher) { - struct rsn_ie_hdr *hdr; int num_suites, res; - u8 *pos, *count; - u16 capab; + u8 *count; u32 suite; - hdr = (struct rsn_ie_hdr *) buf; - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, RSN_VERSION); - pos = (u8 *) (hdr + 1); - - suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group); + suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group); if (suite == 0) { - wpa_printf( MSG_DEBUG, "Invalid group cipher (%d).", - conf->wpa_group); - return -1; + wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", group); + return NULL; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; @@ -120,7 +152,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } #endif /* CONFIG_RSN_TESTING */ - res = rsn_cipher_put_suites(pos, conf->rsn_pairwise); + res = rsn_cipher_put_suites(pos, pairwise); num_suites += res; pos += res * RSN_SELECTOR_LEN; @@ -134,8 +166,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, if (num_suites == 0) { wpa_printf( MSG_DEBUG, "Invalid pairwise cipher (%d).", - conf->rsn_pairwise); - return -1; + pairwise); + return NULL; } WPA_PUT_LE16(count, num_suites); @@ -151,52 +183,52 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } #endif /* CONFIG_RSN_TESTING */ - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { + if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { + if (key_mgmt & WPA_KEY_MGMT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } #ifdef CONFIG_IEEE80211R_AP - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { + if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { + if (key_mgmt & WPA_KEY_MGMT_FT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_IEEE80211W - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { + if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); pos += RSN_SELECTOR_LEN; num_suites++; } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { + if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { + if (key_mgmt & WPA_KEY_MGMT_SAE) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); pos += RSN_SELECTOR_LEN; num_suites++; } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { - RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY); - pos += RSN_SELECTOR_LEN; - num_suites++; + if (key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY); + pos += RSN_SELECTOR_LEN; + num_suites++; } - if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { + if (key_mgmt & WPA_KEY_MGMT_FT_SAE) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); pos += RSN_SELECTOR_LEN; num_suites++; @@ -212,46 +244,19 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, #endif /* CONFIG_RSN_TESTING */ if (num_suites == 0) { - wpa_printf( MSG_DEBUG, "Invalid key management type (%d).", - conf->wpa_key_mgmt); - return -1; + wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", + key_mgmt); + return NULL; } WPA_PUT_LE16(count, num_suites); /* RSN Capabilities */ - capab = 0; - if (conf->rsn_preauth) - capab |= WPA_CAPABILITY_PREAUTH; - if (conf->wmm_enabled) { - /* 4 PTKSA replay counters when using WMM */ - capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); - } - - if (conf->spp_sup.capable) { - capab |= WPA_CAPABILITY_SPP_CAPABLE; - } - - if (conf->spp_sup.require) { - capab |= WPA_CAPABILITY_SPP_REQUIRED; - } - -#ifdef CONFIG_IEEE80211W - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { - capab |= WPA_CAPABILITY_MFPC; - if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) - capab |= WPA_CAPABILITY_MFPR; - } -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_RSN_TESTING - if (rsn_testing) - capab |= BIT(8) | BIT(14) | BIT(15); -#endif /* CONFIG_RSN_TESTING */ - WPA_PUT_LE16(pos, capab); + WPA_PUT_LE16(pos, rsn_capab); pos += 2; if (pmkid) { if (pos + 2 + PMKID_LEN > buf + len) - return -1; + return NULL; /* PMKID Count */ WPA_PUT_LE16(pos, 1); pos += 2; @@ -260,9 +265,9 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } #ifdef CONFIG_IEEE80211W - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + if (mfp != NO_MGMT_FRAME_PROTECTION) { if (pos + 2 + 4 > buf + len) - return -1; + return NULL; if (pmkid == NULL) { /* PMKID Count */ WPA_PUT_LE16(pos, 0); @@ -281,7 +286,10 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256); break; default: - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + wpa_printf(MSG_DEBUG, + "Invalid group management cipher (0x%x)", + group_mgmt_cipher); + return NULL; } pos += RSN_SELECTOR_LEN; } @@ -294,12 +302,12 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, * the element. */ int pmkid_count_set = pmkid != NULL; - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) + if (mfp != NO_MGMT_FRAME_PROTECTION) pmkid_count_set = 1; /* PMKID Count */ WPA_PUT_LE16(pos, 0); pos += 2; - if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { + if (mfp == NO_MGMT_FRAME_PROTECTION) { /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; @@ -309,6 +317,27 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, pos += 17; } #endif /* CONFIG_RSN_TESTING */ + return pos; +} + + +int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, + const u8 *pmkid) +{ + struct rsn_ie_hdr *hdr; + u8 *pos; + + hdr = (struct rsn_ie_hdr *) buf; + hdr->elem_id = WLAN_EID_RSN; + WPA_PUT_LE16(hdr->version, RSN_VERSION); + pos = (u8 *) (hdr + 1); + + pos = rsne_write_data(buf, len, pos, conf->wpa_group, + conf->rsn_pairwise, conf->wpa_key_mgmt, + wpa_own_rsn_capab(conf, conf->ieee80211w), pmkid, + conf->ieee80211w, conf->group_mgmt_cipher); + if (!pos) + return -1; hdr->len = (pos - buf) - 2; @@ -316,32 +345,118 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } -int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len) -{ - u8 *pos = buf; - u16 capab = 0; - size_t flen; - if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) && +#ifdef CONFIG_WPA3_COMPAT +static int wpa_write_rsne_override(struct wpa_auth_config *conf, u8 *buf, + size_t len) +{ + u8 *pos, *len_pos; + + pos = buf; + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + len_pos = pos++; + + WPA_PUT_BE32(pos, RSNE_OVERRIDE_IE_VENDOR_TYPE); + pos += 4; + + WPA_PUT_LE16(pos, RSN_VERSION); + pos += 2; + + pos = rsne_write_data(buf, len, pos, conf->wpa_group, + conf->rsn_override_pairwise, + conf->rsn_override_key_mgmt, + wpa_own_rsn_capab(conf, conf->rsn_override_mfp), + NULL, conf->rsn_override_mfp, + conf->group_mgmt_cipher); + if (!pos) + return -1; + + *len_pos = (pos - buf) - 2; + + return pos - buf; +} +#endif + + +static u32 rsnxe_capab(struct wpa_auth_config *conf, int key_mgmt) +{ + u32 capab = 0; + + if (wpa_key_mgmt_sae(key_mgmt) && (conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || conf->sae_pwe == SAE_PWE_BOTH)) { capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); } - flen = 1; + return capab; +} + +int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len) +{ + u8 *pos = buf; + u32 capab = 0, tmp; + size_t flen; + + capab = rsnxe_capab(conf, conf->wpa_key_mgmt); + if (!capab) return 0; /* no supported extended RSN capabilities */ + tmp = capab; + flen = 0; + while (tmp) { + flen++; + tmp >>= 8; + } if (len < 2 + flen) return -1; capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ *pos++ = WLAN_EID_RSNX; *pos++ = flen; - *pos++ = capab & 0x00ff; + while (capab) { + *pos++ = capab & 0xff; + capab >>= 8; + } return pos - buf; } +#ifdef CONFIG_WPA3_COMPAT +static int wpa_write_rsnxe_override(struct wpa_auth_config *conf, u8 *buf, + size_t len) +{ + u8 *pos = buf; + u32 capab, tmp; + size_t flen; + + capab = rsnxe_capab(conf, conf->rsn_override_key_mgmt); + + if (!capab) + return 0; /* no supported extended RSN capabilities */ + tmp = capab; + flen = 0; + while (tmp) { + flen++; + tmp >>= 8; + } + if (len < 2 + flen) + return -1; + capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 4 + flen; + WPA_PUT_BE32(pos, RSNXE_OVERRIDE_IE_VENDOR_TYPE); + pos += 4; + + while (capab) { + *pos++ = capab & 0xff; + capab >>= 8; + } + + return pos - buf; +} +#endif + int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) { @@ -352,12 +467,19 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { res = wpa_write_rsn_ie(&wpa_auth->conf, - pos, buf + sizeof(buf) - pos, NULL, wpa_auth->conf.group_mgmt_cipher); + pos, buf + sizeof(buf) - pos, NULL); if (res < 0) return res; pos += res; - res = wpa_write_rsnxe(&wpa_auth->conf, pos, - buf + sizeof(buf) - pos); + +#ifdef CONFIG_WPA3_COMPAT + if (wpa_auth->conf.rsn_override_omit_rsnxe) + res = 0; + else +#endif + res = wpa_write_rsnxe(&wpa_auth->conf, pos, + buf + sizeof(buf) - pos); + if (res < 0) return res; pos += res; @@ -379,6 +501,26 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) pos += res; } +#ifdef CONFIG_WPA3_COMPAT + if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) && + wpa_auth->conf.rsn_override_key_mgmt) { + res = wpa_write_rsne_override(&wpa_auth->conf, + pos, buf + sizeof(buf) - pos); + if (res < 0) + return res; + pos += res; + } + + if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) && + (wpa_auth->conf.rsn_override_key_mgmt)) { + res = wpa_write_rsnxe_override(&wpa_auth->conf, pos, + buf + sizeof(buf) - pos); + if (res < 0) + return res; + pos += res; + } +#endif + os_free(wpa_auth->wpa_ie); wpa_auth->wpa_ie = os_malloc(pos - buf); if (wpa_auth->wpa_ie == NULL) @@ -460,8 +602,8 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_SAE else if (data.key_mgmt & WPA_KEY_MGMT_SAE) selector = RSN_AUTH_KEY_MGMT_SAE; - else if (data.key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) - selector = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; + else if (data.key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) + selector = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) selector = RSN_AUTH_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ @@ -514,12 +656,18 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, return WPA_INVALID_GROUP; } - key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; +#ifdef CONFIG_WPA3_COMPAT + if (sm->rsn_override) + key_mgmt = data.key_mgmt & wpa_auth->conf.rsn_override_key_mgmt; + else +#endif + key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; if (!key_mgmt) { - wpa_printf( MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " + wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " MACSTR, data.key_mgmt, MAC2STR(sm->addr)); return WPA_INVALID_AKMP; } + if (0) { } #ifdef CONFIG_IEEE80211R_AP @@ -547,12 +695,18 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, else sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; +#ifdef CONFIG_WPA3_COMPAT + if (version == WPA_PROTO_RSN && sm->rsn_override) + ciphers = data.pairwise_cipher & + wpa_auth->conf.rsn_override_pairwise; + else +#endif if (version == WPA_PROTO_RSN) ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; else ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; if (!ciphers) { - wpa_printf( MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " + wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " "from " MACSTR, version == WPA_PROTO_RSN ? "RSN" : "WPA", data.pairwise_cipher, MAC2STR(sm->addr)); @@ -602,7 +756,7 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #endif /* CONFIG_SAE */ - if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || + if (!wpa_auth_pmf_enabled(&wpa_auth->conf) || !(data.capabilities & WPA_CAPABILITY_MFPC)) sm->mgmt_frame_prot = 0; else @@ -689,124 +843,6 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, return WPA_IE_OK; } -/** - * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs - * @pos: Pointer to the IE header - * @end: Pointer to the end of the Key Data buffer - * @ie: Pointer to parsed IE data - * Returns: 0 on success, 1 if end mark is found, -1 on failure - */ -static int wpa_parse_generic(const u8 *pos, const u8 *end, - struct wpa_eapol_ie_parse *ie) -{ - if (pos[1] == 0) - return 1; - - if (pos[1] >= 6 && - RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && - pos[2 + WPA_SELECTOR_LEN] == 1 && - pos[2 + WPA_SELECTOR_LEN + 1] == 0) { - ie->wpa_ie = pos; - ie->wpa_ie_len = pos[1] + 2; - return 0; - } - - if (pos + 1 + RSN_SELECTOR_LEN < end && - pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { - ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { - ie->gtk = pos + 2 + RSN_SELECTOR_LEN; - ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { - ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; - ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } - -#ifdef CONFIG_IEEE80211W - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { - ie->igtk = pos + 2 + RSN_SELECTOR_LEN; - ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; - return 0; - } -#endif /* CONFIG_IEEE80211W */ - - return 0; -} - - -/** - * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs - * @buf: Pointer to the Key Data buffer - * @len: Key Data Length - * @ie: Pointer to parsed IE data - * Returns: 0 on success, -1 on failure - */ -int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) -{ - const u8 *pos, *end; - int ret = 0; - - memset(ie, 0, sizeof(*ie)); - for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { - if (pos[0] == 0xdd && - ((pos == buf + len - 1) || pos[1] == 0)) { - /* Ignore padding */ - break; - } - if (pos + 2 + pos[1] > end) { - wpa_printf( MSG_DEBUG, "WPA: EAPOL-Key Key Data " - "underflow (ie=%d len=%d pos=%d)", - pos[0], pos[1], (int) (pos - buf)); - wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", - buf, len); - ret = -1; - break; - } - if (*pos == WLAN_EID_RSN) { - ie->rsn_ie = pos; - ie->rsn_ie_len = pos[1] + 2; -#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_AP */ - } else if (*pos == WLAN_EID_RSNX) { - ie->rsnxe = pos; - ie->rsnxe_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key", - ie->rsnxe, ie->rsnxe_len); - } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { - ret = wpa_parse_generic(pos, end, ie); - if (ret < 0) - break; - if (ret > 0) { - ret = 0; - break; - } - } else { - wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " - "Key Data IE", pos, 2 + pos[1]); - } - } - - return ret; -} - - int wpa_auth_uses_mfp(struct wpa_state_machine *sm) { return sm ? sm->mgmt_frame_prot : 0; diff --git a/components/wpa_supplicant/src/ap/wpa_auth_ie.h b/components/wpa_supplicant/src/ap/wpa_auth_ie.h index f342e3dda9..dd44b9efe2 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth_ie.h +++ b/components/wpa_supplicant/src/ap/wpa_auth_ie.h @@ -9,32 +9,6 @@ #ifndef WPA_AUTH_IE_H #define WPA_AUTH_IE_H -struct wpa_eapol_ie_parse { - const u8 *wpa_ie; - size_t wpa_ie_len; - const u8 *rsn_ie; - size_t rsn_ie_len; - const u8 *pmkid; - const u8 *gtk; - size_t gtk_len; - const u8 *mac_addr; - size_t mac_addr_len; -#ifdef CONFIG_IEEE80211W - const u8 *igtk; - size_t igtk_len; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_IEEE80211R - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; -#endif /* CONFIG_IEEE80211R */ - const u8 *rsnxe; - size_t rsnxe_len; -}; - -int wpa_parse_kde_ies(const u8 *buf, size_t len, - struct wpa_eapol_ie_parse *ie); u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, const u8 *data2, size_t data2_len); int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth); diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.c b/components/wpa_supplicant/src/common/ieee802_11_common.c index e4c1f4a52d..6098dd469e 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.c +++ b/components/wpa_supplicant/src/common/ieee802_11_common.c @@ -192,72 +192,152 @@ int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, } #ifdef CONFIG_SAE_PK -static int ieee802_11_parse_vendor_specific(struct wpa_supplicant *wpa_s, const struct element *elem, const u8* pos) +static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, + struct ieee802_11_elems *elems, + int show_errors) { u32 oui; + + /* first 3 bytes in vendor specific information element are the IEEE + * OUI of the vendor. The following byte is used a vendor specific + * sub-type. */ + if (elen < 4) { + if (show_errors) { + wpa_printf(MSG_MSGDUMP, "short vendor specific " + "information element ignored (len=%lu)", + (unsigned long) elen); + } + return -1; + } + oui = WPA_GET_BE24(pos); switch (oui) { case OUI_WFA: switch (pos[3]) { case SAE_PK_OUI_TYPE: - wpa_s->sae_pk_elems.sae_pk_len = elem->datalen - 4; - wpa_s->sae_pk_elems.sae_pk = (u8*)os_zalloc(sizeof(u8)*(elem->datalen-4)); - if (!wpa_s->sae_pk_elems.sae_pk) { - wpa_printf(MSG_EXCESSIVE, "Can not allocate memory for sae_pk"); - return -1; - } - os_memcpy(wpa_s->sae_pk_elems.sae_pk, pos+4, elem->datalen-4); + elems->sae_pk = pos + 4; + elems->sae_pk_len = elen - 4; break; default: wpa_printf(MSG_EXCESSIVE, "Unknown WFA " "information element ignored " "(type=%d len=%lu)", - pos[3], (unsigned long) elem->datalen); - return -1; + pos[3], (unsigned long) elen); + //TODO discuss if to ignore it + break; + //return -1; } break; default: - wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " + wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " "information element ignored (vendor OUI " "%02x:%02x:%02x len=%lu)", - pos[0], pos[1], pos[2], (unsigned long) elem->datalen); - return -1; - } - - return 0; -} - -static int ieee802_11_parse_extension(struct wpa_supplicant *wpa_s, const struct element *elem, const u8* pos){ - // do not consider extension_id element len in datalen - if (elem->datalen < 1) { - wpa_printf(MSG_DEBUG, - "short information element (Ext)"); - return -1; - } - u8 ext_id; - ext_id = *pos++; - switch (ext_id) { - case WLAN_EID_EXT_FILS_KEY_CONFIRM: - wpa_s->sae_pk_elems.fils_key_confirm_len = elem->datalen - 1; - wpa_s->sae_pk_elems.fils_key_confirm = (u8*)os_zalloc(sizeof(u8)*(elem->datalen - 1)); - os_memcpy(wpa_s->sae_pk_elems.fils_key_confirm, pos, elem->datalen - 1); + pos[0], pos[1], pos[2], (unsigned long) elen); + //TODO discuss if to ignore it break; - case WLAN_EID_EXT_FILS_PUBLIC_KEY: - wpa_s->sae_pk_elems.fils_pk_len = elem->datalen - 1; - wpa_s->sae_pk_elems.fils_pk = (u8*)os_zalloc(sizeof(u8)*(elem->datalen - 1)); - os_memcpy(wpa_s->sae_pk_elems.fils_pk, pos, elem->datalen - 1); - break; - default: - wpa_printf(MSG_EXCESSIVE, - "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)", - ext_id, (unsigned int) elem->datalen-1); - return -1; + //return -1; } return 0; } #endif /* CONFIG_SAE_PK */ +#ifdef CONFIG_SAE_PK +static int ieee802_11_parse_extension(const u8 *pos, size_t elen, + struct ieee802_11_elems *elems, + const u8 *start, size_t len, + int show_errors) +{ + u8 ext_id; + + if (elen < 1) { + wpa_printf(MSG_DEBUG, + "short information element (Ext)"); + return -1; + } + + ext_id = *pos++; + elen--; + + switch (ext_id) { + case WLAN_EID_EXT_FILS_KEY_CONFIRM: + elems->fils_key_confirm = pos; + elems->fils_key_confirm_len = elen; + break; + case WLAN_EID_EXT_FILS_PUBLIC_KEY: + if (elen < 1) + break; + elems->fils_pk = pos; + elems->fils_pk_len = elen; + break; + default: + wpa_printf(MSG_EXCESSIVE, + "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)", + ext_id, (unsigned int) elen); + //TODO discuss if to ignore it + break; + //return -1; + } + + return 0; +} +#endif /* CONFIG_SAE_PK */ + +#if defined(CONFIG_RRM) || defined(CONFIG_WMM) || defined(CONFIG_SAE_PK) +static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len, + struct ieee802_11_elems *elems, + int show_errors) +{ + const struct element *elem; + u8 unknown = 0; + + if (!start) + return ParseOK; + + for_each_element(elem, start, len) { + u8 id = elem->id, elen = elem->datalen; + const u8 *pos = elem->data; + switch (id) { +#ifdef CONFIG_RRM + case WLAN_EID_RRM_ENABLED_CAPABILITIES: + elems->rrm_enabled = pos; + elems->rrm_enabled_len = elen; + break; +#endif +#ifdef CONFIG_SAE_PK + case WLAN_EID_EXTENSION: + if (ieee802_11_parse_extension(pos, elen, elems, start, + len, show_errors) != 0) { + unknown++; + } + break; + case WLAN_EID_VENDOR_SPECIFIC: + if (ieee802_11_parse_vendor_specific(pos, elen, + elems, + show_errors) != 0) { + unknown++; + } + break; +#endif /*CONFIG_SAE_PK*/ +#ifdef CONFIG_WNM + case WLAN_EID_EXT_CAPAB: + /* extended caps can go beyond 8 octacts but we aren't using them now */ + elems->ext_capab = pos; + elems->ext_capab_len = elen; + break; +#endif + default: + break; + + } + } + if (unknown) + return ParseFailed; + + return ParseOK; +} +#endif + /** * ieee802_11_parse_elems - Parse information elements in management frames * @start: Pointer to the start of IEs @@ -266,54 +346,14 @@ static int ieee802_11_parse_extension(struct wpa_supplicant *wpa_s, const struct * @show_errors: Whether to show parsing errors in debug log * Returns: Parsing result */ -int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len) +#if defined(CONFIG_RRM) || defined(CONFIG_WMM) || defined(CONFIG_SAE_PK) +ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, struct ieee802_11_elems *elems, int show_errors) { -#if defined(CONFIG_RRM) || defined(CONFIG_WNM) || defined(CONFIG_SAE_PK) - const struct element *elem; - u8 unknown = 0; + os_memset(elems, 0, sizeof(*elems)); - if (!start) - return 0; - - for_each_element(elem, start, len) { - u8 id = elem->id; - const u8 *pos = elem->data; - switch (id) { -#ifdef CONFIG_RRM - case WLAN_EID_RRM_ENABLED_CAPABILITIES: - os_memcpy(wpa_s->rrm_ie, pos, 5); - wpa_s->rrm.rrm_used = true; - break; -#endif -#ifdef CONFIG_SAE_PK - case WLAN_EID_EXTENSION: - if(ieee802_11_parse_extension(wpa_s, elem, pos) != 0){ - unknown++; - } - break; - case WLAN_EID_VENDOR_SPECIFIC: - if(ieee802_11_parse_vendor_specific(wpa_s, elem, pos) != 0){ - unknown++; - } - break; -#endif /*CONFIG_SAE_PK*/ -#ifdef CONFIG_WNM - case WLAN_EID_EXT_CAPAB: - /* extended caps can go beyond 8 octacts but we aren't using them now */ - os_memcpy(wpa_s->extend_caps, pos, 5); - break; -#endif - default: - break; - - } - } - if (unknown) - return -1; - -#endif /* defined(CONFIG_RRM) || defined(CONFIG_WNM) || defined(CONFIG_SAE_PK) */ - return 0; + return __ieee802_11_parse_elems(start, len, elems, show_errors); } +#endif struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, u32 oui_type) @@ -379,6 +419,38 @@ const struct oper_class_map global_op_class[] = { size_t global_op_class_size = ARRAY_SIZE(global_op_class); +bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len, + unsigned int capab) +{ + const u8 *end; + size_t flen, i; + u32 capabs = 0; + + if (!rsnxe || rsnxe_len == 0) + return false; + end = rsnxe + rsnxe_len; + flen = (rsnxe[0] & 0x0f) + 1; + if (rsnxe + flen > end) + return false; + if (flen > 4) + flen = 4; + for (i = 0; i < flen; i++) + capabs |= (u32) rsnxe[i] << (8 * i); + + return capabs & BIT(capab); +} + + +bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab) +{ + if (!rsnxe) + return false; + if (rsnxe[0] == WLAN_EID_VENDOR_SPECIFIC && rsnxe[1] >= 4 + 1) + return ieee802_11_rsnx_capab_len(rsnxe + 2 + 4, rsnxe[1] - 4, + capab); + return ieee802_11_rsnx_capab_len(rsnxe + 2, rsnxe[1], capab); +} + u8 get_operating_class(u8 chan, int sec_channel) { u8 op_class = 0; diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.h b/components/wpa_supplicant/src/common/ieee802_11_common.h index 90cae7814d..43e5a0b43b 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.h +++ b/components/wpa_supplicant/src/common/ieee802_11_common.h @@ -48,10 +48,38 @@ struct oper_class_map { extern const struct oper_class_map global_op_class[]; extern size_t global_op_class_size; +/* Parsed Information Elements */ +struct ieee802_11_elems { + const u8 *rsn_ie; + u8 rsn_ie_len; + const u8 *rsnxe; + u8 rsnxe_len; +#ifdef CONFIG_RRM + const u8 *rrm_enabled; + u8 rrm_enabled_len; +#endif +#ifdef CONFIG_WNM + const u8 *ext_capab; + u8 ext_capab_len; +#endif +#ifdef CONFIG_SAE_PK + const u8 *fils_pk; + u8 fils_pk_len; + const u8 *fils_key_confirm; + u8 fils_key_confirm_len; + const u8 *sae_pk; + u8 sae_pk_len; +#endif +}; + +typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; + int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len); const u8 * get_ie(const u8 *ies, size_t len, u8 eid); -int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len); +ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, + struct ieee802_11_elems *elems, + int show_errors); 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); diff --git a/components/wpa_supplicant/src/common/ieee802_11_defs.h b/components/wpa_supplicant/src/common/ieee802_11_defs.h index 958bf5feeb..e8adaeef0c 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_defs.h +++ b/components/wpa_supplicant/src/common/ieee802_11_defs.h @@ -299,8 +299,15 @@ #define WLAN_TIMEOUT_KEY_LIFETIME 2 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3 -#define OUI_WFA 0x506f9a +/* DPP Public Action frame identifiers - OUI_WFA */ #define DPP_OUI_TYPE 0x1A +#define OUI_WFA 0x506f9a +#define WFA_RSNE_OVERRIDE_OUI_TYPE 0x29 +#define WFA_RSNXE_OVERRIDE_OUI_TYPE 0x2b +#define WFA_RSN_SELECTION_OUI_TYPE 0x2c +#define RSNE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a29 +#define RSNXE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a2b +#define RSN_SELECTION_IE_VENDOR_TYPE 0x506f9a2c #ifdef _MSC_VER #pragma pack(push, 1) diff --git a/components/wpa_supplicant/src/common/sae_pk.c b/components/wpa_supplicant/src/common/sae_pk.c index 6361de2aa0..a1d88ac1ba 100644 --- a/components/wpa_supplicant/src/common/sae_pk.c +++ b/components/wpa_supplicant/src/common/sae_pk.c @@ -618,9 +618,7 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len) u8 hash[SAE_MAX_HASH_LEN]; size_t hash_len; int group; - struct wpa_supplicant *wpa_s = &g_wpa_supp; - struct sae_pk_elems elems; - int ret = 0; + struct ieee802_11_elems elems; if (!tmp) { return -1; @@ -644,15 +642,16 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len) } wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len); - ieee802_11_parse_elems(wpa_s, ies, ies_len); - elems = wpa_s->sae_pk_elems; + if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { + wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs"); + return -1; + } if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) { wpa_printf(MSG_INFO, "SAE-PK: Not all mandatory IEs included in confirm"); - ret = -1; - goto done; + return -1; } /* TODO: Fragment reassembly */ @@ -660,8 +659,7 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len) if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) { wpa_printf(MSG_INFO, "SAE-PK: No room for EncryptedModifier in SAE-PK element"); - ret = -1; - goto done; + return -1; } wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier", @@ -672,16 +670,14 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len) 0, NULL, NULL, m) < 0) { wpa_printf(MSG_INFO, "SAE-PK: Failed to decrypt EncryptedModifier"); - ret = -1; - goto done; + return -1; } wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN); if (elems.fils_pk[0] != 2) { wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u", elems.fils_pk[0]); - ret = -1; - goto done; + return -1; } k_ap_len = elems.fils_pk_len - 1; k_ap = elems.fils_pk + 1; @@ -691,15 +687,13 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len) key = crypto_ec_key_parse_pub(k_ap, k_ap_len); if (!key) { wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP"); - ret = -1; - goto done; + return -1; } group = crypto_ec_key_group(key); if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len, group)) { crypto_ec_key_deinit(key); - ret = -1; - goto done; + return -1; } wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth", @@ -709,8 +703,7 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len) if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN, k_ap, k_ap_len, hash) < 0) { crypto_ec_key_deinit(key); - ret = -1; - goto done; + return -1; } res = crypto_ec_key_verify_signature(key, hash, hash_len, @@ -721,25 +714,12 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len) if (res != 1) { wpa_printf(MSG_INFO, "SAE-PK: Invalid or incorrect signature in KeyAuth"); - ret = -1; - goto done; + return -1; } wpa_printf(MSG_DEBUG, "SAE-PK: Valid KeyAuth signature received"); /* TODO: Store validated public key into network profile */ -done: - if (wpa_s->sae_pk_elems.fils_pk) { - os_free(wpa_s->sae_pk_elems.fils_pk); - } - if (wpa_s->sae_pk_elems.sae_pk) { - os_free(wpa_s->sae_pk_elems.sae_pk); - } - if (wpa_s->sae_pk_elems.fils_key_confirm) { - os_free(wpa_s->sae_pk_elems.fils_key_confirm); - } - os_memset(&wpa_s->sae_pk_elems, 0, sizeof(wpa_s->sae_pk_elems)); - - return ret; + return 0; } #endif /* CONFIG_SAE_PK */ diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index 6f9485760b..5e5655cfdd 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -402,7 +402,12 @@ int wpa_parse_wpa_ie_rsnxe(const u8 *rsnxe_ie, size_t rsnxe_ie_len, if (rsnxe_ie_len < 1) { return -1; } - rsnxe_capa = rsnxe_ie[2]; + if (rsnxe_ie && rsnxe_ie[0] == WLAN_EID_VENDOR_SPECIFIC && + rsnxe_ie[1] >= 1 + 4) { + rsnxe_capa = rsnxe_ie[2 + 4]; + } else { + rsnxe_capa = rsnxe_ie[2]; + } if (sae_pwe == 1 && !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))){ wpa_printf(MSG_ERROR, "SAE H2E required, but not supported by the AP"); return -1; @@ -421,7 +426,6 @@ int wpa_parse_wpa_ie_rsnxe(const u8 *rsnxe_ie, size_t rsnxe_ie_len, int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data) { - const struct rsn_ie_hdr *hdr; const u8 *pos; int left; int i, count; @@ -448,19 +452,29 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, return -1; } - hdr = (const struct rsn_ie_hdr *) rsn_ie; + if (rsn_ie_len >= 2 + 4 + 2 && rsn_ie[1] >= 4 + 2 && + rsn_ie[1] == rsn_ie_len - 2 && + (WPA_GET_BE32(&rsn_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE) && + WPA_GET_LE16(&rsn_ie[2 + 4]) == RSN_VERSION) { + pos = rsn_ie + 2 + 4 + 2; + left = rsn_ie_len - 2 - 4 - 2; + } else { + const struct rsn_ie_hdr *hdr; - if (hdr->elem_id != WLAN_EID_RSN || - hdr->len != rsn_ie_len - 2 || - WPA_GET_LE16(hdr->version) != RSN_VERSION) { - wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", - __func__); - return -2; + hdr = (const struct rsn_ie_hdr *) rsn_ie; + + if (hdr->elem_id != WLAN_EID_RSN || + hdr->len != rsn_ie_len - 2 || + WPA_GET_LE16(hdr->version) != RSN_VERSION) { + wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", + __func__); + return -2; + } + + pos = (const u8 *) (hdr + 1); + left = rsn_ie_len - sizeof(*hdr); } - pos = (const u8 *) (hdr + 1); - left = rsn_ie_len - sizeof(*hdr); - if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); pos += RSN_SELECTOR_LEN; @@ -1580,4 +1594,189 @@ int wpa_cipher_put_suites(u8 *pos, int ciphers) return num_suites; } +/** + * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs + * @pos: Pointer to the IE header + * @end: Pointer to the end of the Key Data buffer + * @ie: Pointer to parsed IE data + * Returns: 0 on success, 1 if end mark is found, -1 on failure + */ +static int wpa_parse_generic(const u8 *pos, const u8 *end, + struct wpa_eapol_ie_parse *ie) +{ + u8 len = pos[1]; + size_t dlen = 2 + len; + u32 selector; + const u8 *p; + size_t left; + + if (len == 0) + return 1; + + if (len < RSN_SELECTOR_LEN) + return 2; + + p = pos + 2; + selector = RSN_SELECTOR_GET(p); + p += RSN_SELECTOR_LEN; + left = len - RSN_SELECTOR_LEN; + + if (left >= 2 && selector == WPA_OUI_TYPE && p[0] == 1 && p[1] == 0) { + ie->wpa_ie = pos; + ie->wpa_ie_len = dlen; + wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", + ie->wpa_ie, ie->wpa_ie_len); + return 0; + } + + if (left >= PMKID_LEN && selector == RSN_KEY_DATA_PMKID) { + ie->pmkid = p; + wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", pos, dlen); + return 0; + } + + if (left > 2 && selector == RSN_KEY_DATA_GROUPKEY) { + ie->gtk = p; + ie->gtk_len = left; + wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", pos, dlen); + return 0; + } + + if (left >= ETH_ALEN && selector == RSN_KEY_DATA_MAC_ADDR) { + ie->mac_addr = p; + wpa_printf(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key: " MACSTR, + MAC2STR(ie->mac_addr)); + return 0; + } + +#ifdef CONFIG_IEEE80211W + if (left > 2 && selector == RSN_KEY_DATA_IGTK) { + ie->igtk = p; + ie->igtk_len = left; + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", + pos, dlen); + return 0; + } +#endif /* CONFIG_IEEE80211W */ + + if (left >= 1 && selector == WFA_KEY_DATA_TRANSITION_DISABLE) { + ie->transition_disable = p; + ie->transition_disable_len = left; + wpa_hexdump(MSG_DEBUG, + "WPA: Transition Disable KDE in EAPOL-Key", + pos, dlen); + return 0; + } + +#ifdef CONFIG_WPA3_COMPAT + if (selector == RSNE_OVERRIDE_IE_VENDOR_TYPE) { + ie->rsne_override = pos; + ie->rsne_override_len = dlen; + wpa_hexdump(MSG_DEBUG, + "RSN: RSNE Override element in EAPOL-Key", + ie->rsne_override, ie->rsne_override_len); + return 0; + } + + if (selector == RSNXE_OVERRIDE_IE_VENDOR_TYPE) { + ie->rsnxe_override = pos; + ie->rsnxe_override_len = dlen; + wpa_hexdump(MSG_DEBUG, + "RSN: RSNXE Override element in EAPOL-Key", + ie->rsnxe_override, ie->rsnxe_override_len); + return 0; + } + + if (selector == RSN_SELECTION_IE_VENDOR_TYPE) { + ie->rsn_selection = p; + ie->rsn_selection_len = left; + wpa_hexdump(MSG_DEBUG, + "RSN: RSN Selection element in EAPOL-Key", + ie->rsn_selection, ie->rsn_selection_len); + return 0; + } +#endif + return 2; +} + +/** + * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs + * @buf: Pointer to the Key Data buffer + * @len: Key Data Length + * @ie: Pointer to parsed IE data + * Returns: 0 on success, -1 on failure + */ +int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) +{ + const u8 *pos, *end; + int ret = 0; + + os_memset(ie, 0, sizeof(*ie)); + for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { + if (pos[0] == 0xdd && + ((pos == buf + len - 1) || pos[1] == 0)) { + /* Ignore padding */ + break; + } + if (pos + 2 + pos[1] > end) { + wpa_printf( MSG_DEBUG, "WPA: EAPOL-Key Key Data " + "underflow (ie=%d len=%d pos=%d)", + pos[0], pos[1], (int) (pos - buf)); + wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", + buf, len); + ret = -1; + break; + } + if (*pos == WLAN_EID_RSN) { + ie->rsn_ie = pos; + ie->rsn_ie_len = pos[1] + 2; +#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_AP */ + } else if (*pos == WLAN_EID_RSNX) { + ie->rsnxe = pos; + ie->rsnxe_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key", + ie->rsnxe, ie->rsnxe_len); + } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { + ret = wpa_parse_generic(pos, end, ie); + if (ret < 0) + break; + if (ret > 0) { + ret = 0; + break; + } + } else { + wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " + "Key Data IE", pos, 2 + pos[1]); + } + } + + return ret; +} + +void rsn_set_snonce_cookie(u8 *snonce) +{ + u8 *pos; + + pos = snonce + WPA_NONCE_LEN - 6; + WPA_PUT_BE24(pos, OUI_WFA); + pos += 3; + WPA_PUT_BE24(pos, 0x000029); +} + + +bool rsn_is_snonce_cookie(const u8 *snonce) +{ + const u8 *pos; + + pos = snonce + WPA_NONCE_LEN - 6; + return WPA_GET_BE24(pos) == OUI_WFA && + WPA_GET_BE24(pos + 3) == 0x000029; +} #endif // ESP_SUPPLICANT diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index d4d164db0c..5069ec7730 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -427,6 +427,13 @@ struct wpa_ft_ies { size_t ric_len; }; +/* WPA3 specification - RSN Selection element */ +enum rsn_selection_variant { + RSN_SELECTION_RSNE = 0, + RSN_SELECTION_RSNE_OVERRIDE = 1, +}; + + 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, @@ -439,6 +446,48 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, u8 *pmkid, int akmp); +struct wpa_eapol_ie_parse { + const u8 *wpa_ie; + size_t wpa_ie_len; + const u8 *rsn_ie; + size_t rsn_ie_len; + const u8 *pmkid; + const u8 *gtk; + size_t gtk_len; + const u8 *mac_addr; + size_t mac_addr_len; +#ifdef CONFIG_IEEE80211W + const u8 *igtk; + size_t igtk_len; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; + const u8 *reassoc_deadline; + const u8 *key_lifetime; +#endif /* CONFIG_IEEE80211R */ + const u8 *transition_disable; + size_t transition_disable_len; + const u8 *rsnxe; + size_t rsnxe_len; +#ifdef CONFIG_WPA3_COMPAT + const u8 *rsn_selection; + size_t rsn_selection_len; + const u8 *rsne_override; + size_t rsne_override_len; + const u8 *rsnxe_override; + size_t rsnxe_override_len; +#endif +}; +int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie); +static inline int wpa_supplicant_parse_ies(const u8 *buf, size_t len, + struct wpa_eapol_ie_parse *ie) +{ + return wpa_parse_kde_ies(buf, len, ie); +} + int wpa_cipher_key_len(int cipher); int wpa_cipher_rsc_len(int cipher); int wpa_cipher_to_alg(int cipher); @@ -456,4 +505,7 @@ unsigned int wpa_mic_len(int akmp, size_t pmk_len); int wpa_use_akm_defined(int akmp); int wpa_use_aes_key_wrap(int akmp); +void rsn_set_snonce_cookie(u8 *snonce); +bool rsn_is_snonce_cookie(const u8 *snonce); + #endif /* WPA_COMMON_H */ diff --git a/components/wpa_supplicant/src/common/wpa_supplicant_i.h b/components/wpa_supplicant/src/common/wpa_supplicant_i.h index 581d1c1434..77907842fb 100644 --- a/components/wpa_supplicant/src/common/wpa_supplicant_i.h +++ b/components/wpa_supplicant/src/common/wpa_supplicant_i.h @@ -67,17 +67,6 @@ enum scan_trigger_reason { REASON_WNM_BSS_TRANS_REQ, }; -#ifdef CONFIG_SAE_PK -struct sae_pk_elems { - u8 *fils_pk; - u8 fils_pk_len; - u8 *fils_key_confirm; - u8 fils_key_confirm_len; - u8 *sae_pk; - u8 sae_pk_len; -}; -#endif - struct wpa_supplicant { int scanning; @@ -149,10 +138,6 @@ struct wpa_supplicant { struct beacon_rep_data beacon_rep_data; struct os_reltime beacon_rep_scan; #endif -#ifdef CONFIG_SAE_PK - struct sae_pk_elems sae_pk_elems; -#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 75fe1f5094..ff260dee9e 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -537,6 +537,9 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, struct wpa_eapol_key *reply; struct wpa_eapol_key_192 *reply192; u8 *rsn_ie_buf = NULL; +#ifdef CONFIG_WPA3_COMPAT + u8 *buf2 = NULL; +#endif u8 *rbuf, *key_mic; if (wpa_ie == NULL) { @@ -582,6 +585,36 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, wpa_ie = rsn_ie_buf; } #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_WPA3_COMPAT + if (sm->rsn_override != RSN_OVERRIDE_NOT_USED) { + u8 *pos; + + buf2 = os_malloc(wpa_ie_len + 2 + 4 + 1); + if (!buf2) { + os_free(rsn_ie_buf); + return -1; + } + os_memcpy(buf2, wpa_ie, wpa_ie_len); + pos = buf2 + wpa_ie_len; + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 4 + 1; + WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE); + pos += 4; + if (sm->rsn_override == RSN_OVERRIDE_RSNE) { + *pos++ = RSN_SELECTION_RSNE; + } else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) { + *pos++ = RSN_SELECTION_RSNE_OVERRIDE; + } else { + os_free(rsn_ie_buf); + os_free(buf2); + return -1; + } + + wpa_ie = buf2; + wpa_ie_len += 2 + 4 + 1; + + } +#endif 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, sm->pmk_len); @@ -591,6 +624,9 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, &rlen, (void *) &reply); if (rbuf == NULL) { os_free(rsn_ie_buf); +#ifdef CONFIG_WPA3_COMPAT + os_free(buf2); +#endif return -1; } reply192 = (struct wpa_eapol_key_192 *) reply; @@ -617,6 +653,9 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, } os_free(rsn_ie_buf); +#ifdef CONFIG_WPA3_COMPAT + os_free(buf2); +#endif os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); wpa_printf(MSG_DEBUG, "WPA Send EAPOL-Key 2/4"); @@ -702,7 +741,10 @@ void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, wpa_printf(MSG_DEBUG, "WPA: Failed to get random data for SNonce"); goto failed; } - +#ifdef CONFIG_WPA3_COMPAT + if (wpa_sm_rsn_overriding_supported(sm)) + rsn_set_snonce_cookie(sm->snonce); +#endif sm->renew_snonce = 0; wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", sm->snonce, WPA_NONCE_LEN); @@ -1183,6 +1225,49 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, return -1; } +#ifdef CONFIG_WPA3_COMPAT + if (sm->proto == WPA_PROTO_RSN && wpa_sm_rsn_overriding_supported(sm)) { + if ((sm->ap_rsne_override && !ie->rsne_override) || + (!sm->ap_rsne_override && ie->rsne_override) || + (sm->ap_rsne_override && ie->rsne_override && + (sm->ap_rsne_override_len != ie->rsne_override_len || + os_memcmp(sm->ap_rsne_override, ie->rsne_override, + sm->ap_rsne_override_len) != 0))) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: RSNE Override element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4"); + wpa_hexdump(MSG_INFO, + "RSNE Override element in Beacon/ProbeResp", + sm->ap_rsne_override, + sm->ap_rsne_override_len); + wpa_hexdump(MSG_INFO, + "RSNE Override element in EAPOL-Key msg 3/4", + ie->rsne_override, ie->rsne_override_len); + wpa_sm_deauthenticate(sm, + WLAN_REASON_IE_IN_4WAY_DIFFERS); + return -1; + } + + if ((sm->ap_rsnxe_override && !ie->rsnxe_override) || + (!sm->ap_rsnxe_override && ie->rsnxe_override) || + (sm->ap_rsnxe_override && ie->rsnxe_override && + (sm->ap_rsnxe_override_len != ie->rsnxe_override_len || + os_memcmp(sm->ap_rsnxe_override, ie->rsnxe_override, + sm->ap_rsnxe_override_len) != 0))) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: RSNXE Override element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4"); + wpa_hexdump(MSG_INFO, + "RSNXE Override element in Beacon/ProbeResp", + sm->ap_rsnxe_override, + sm->ap_rsnxe_override_len); + wpa_hexdump(MSG_INFO, + "RSNXE Override element in EAPOL-Key msg 3/4", + ie->rsnxe_override, ie->rsnxe_override_len); + wpa_sm_deauthenticate(sm, + WLAN_REASON_IE_IN_4WAY_DIFFERS); + return -1; + } + } +#endif return 0; } @@ -1276,10 +1361,19 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, key_info = WPA_GET_BE16(key->key_info); - if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) { goto failed; - if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) + } + if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) { goto failed; + } + + if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: ANonce from message 1 of 4-Way Handshake differs from 3 of 4-Way Handshake - drop packet (src=" + MACSTR ")", MAC2STR(sm->bssid)); + goto failed; + } if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { wpa_printf(MSG_DEBUG, "WPA: GTK IE in unencrypted key data"); @@ -1326,10 +1420,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, (sm->gd).gtk_len=0; //used as flag if gtk is installed in callback if (ie.gtk) { wpa_sm_set_seq(sm, key, 0); - if (wpa_supplicant_pairwise_gtk(sm, + if (wpa_supplicant_pairwise_gtk(sm, ie.gtk, ie.gtk_len, key_info) < 0) { - wpa_printf(MSG_DEBUG, "RSN: Failed to configure GTK"); - goto failed; + wpa_printf(MSG_DEBUG, "RSN: Failed to configure GTK"); + goto failed; } } @@ -1388,7 +1482,7 @@ static int wpa_supplicant_activate_ptk(struct wpa_sm *sm) static int wpa_supplicant_send_4_of_4_txcallback(struct wpa_sm *sm) { - u16 key_info=sm->key_info; + u16 key_info = sm->key_info; if (sm->key_install && key_info & WPA_KEY_INFO_INSTALL) { if (sm->use_ext_key_id) { @@ -1447,7 +1541,7 @@ static int wpa_supplicant_send_4_of_4_txcallback(struct wpa_sm *sm) return 0; failed: - return WLAN_REASON_UNSPECIFIED; + return WLAN_REASON_UNSPECIFIED; } static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, @@ -1766,7 +1860,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, *key_data_len -= 8; /* AES-WRAP adds 8 bytes */ /*replaced by xxx to remove malloc*/ buf = ((u8 *) (key+1))+ 8; - /* + /* buf = os_wifi_malloc(keydatalen); if (buf == NULL) { wpa_printf(MSG_DEBUG, "WPA: No memory for " @@ -1873,8 +1967,7 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) hdr = (struct ieee802_1x_hdr *) tmp; key = (struct wpa_eapol_key *) (hdr + 1); - key192 = (struct wpa_eapol_key_192 *) - (tmp + sizeof(struct ieee802_1x_hdr)); + key192 = (struct wpa_eapol_key_192 *)(tmp + sizeof(struct ieee802_1x_hdr)); if (mic_len == 24) key_data = (u8 *) (key192 + 1); else @@ -2089,7 +2182,7 @@ void wpa_sm_set_state(enum wpa_states state) { struct wpa_sm *sm = &gWpaSm; if(WPA_MIC_FAILURE==WPA_SM_STATE(sm)) - eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, NULL, NULL); + eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, NULL, NULL); sm->wpa_state= state; } @@ -2180,14 +2273,75 @@ void wpa_sm_deinit(void) struct wpa_sm *sm = &gWpaSm; pmksa_cache_deinit(sm->pmksa); sm->pmksa = NULL; + os_free(sm->assoc_rsnxe); + sm->assoc_rsnxe = NULL; + os_free(sm->ap_rsn_ie); + sm->ap_rsn_ie = NULL; os_free(sm->ap_rsnxe); sm->ap_rsnxe = NULL; - os_free(sm->assoc_rsnxe); +#ifdef CONFIG_WPA3_COMPAT + os_free(sm->ap_rsne_override); + sm->ap_rsne_override = NULL; + os_free(sm->ap_rsnxe_override); + sm->ap_rsnxe_override = NULL; +#endif wpa_sm_drop_sa(sm); - sm->assoc_rsnxe = NULL; memset(sm, 0, sizeof(*sm)); } +/** + * wpa_sm_set_param - Set WPA state machine parameters + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @param: Parameter field + * @value: Parameter value + * Returns: 0 on success, -1 on failure + */ +#ifdef CONFIG_WPA3_COMPAT +int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, + unsigned int value) +{ + int ret = 0; + + if (sm == NULL) + return -1; + + switch (param) { + case WPA_PARAM_RSN_OVERRIDE: + sm->rsn_override = value; + break; + case WPA_PARAM_RSN_OVERRIDE_SUPPORT: + sm->rsn_override_support = value; + break; + default: + break; + } + return ret; +} +#endif + +#ifdef CONFIG_WPA3_COMPAT +static const u8 * wpa_sm_get_ap_rsne(struct wpa_sm *sm, size_t *len) +{ + if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) { + *len = sm->ap_rsne_override_len; + return sm->ap_rsne_override; + } + *len = sm->ap_rsn_ie_len; + return sm->ap_rsn_ie; +} +#endif + +#ifdef CONFIG_WPA3_COMPAT +bool wpa_sm_rsn_overriding_supported(struct wpa_sm *sm) +{ + const u8 *rsne; + size_t rsne_len; + + rsne = wpa_sm_get_ap_rsne(sm, &rsne_len); + + return sm->rsn_override_support && rsne; +} +#endif #ifdef ESP_SUPPLICANT /** @@ -2320,15 +2474,17 @@ void wpa_set_pmk(uint8_t *pmk, size_t pmk_length, const u8 *pmkid, bool cache_pm } } -int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len) +int wpa_set_bss(uint8_t *macddr, uint8_t *bssid, uint8_t pairwise_cipher, uint8_t group_cipher, char *passphrase, uint8_t *ssid, int ssid_len) { int res = 0; struct wpa_sm *sm = &gWpaSm; bool use_pmk_cache = !esp_wifi_skip_supp_pmkcaching(); - u8 assoc_rsnxe[20]; - size_t assoc_rsnxe_len = sizeof(assoc_rsnxe); + uint8_t assoc_ie[128] = {0}; + uint16_t assoc_ie_len = sizeof(assoc_ie); bool reassoc_same_ess = false; int try_opportunistic = 0; + const u8 *ie = NULL; + uint8_t *pos = NULL; /* Incase AP has changed it's SSID, don't try with PMK caching for SAE connection */ /* Ideally we should use network_ctx for this purpose however currently network profile block @@ -2367,11 +2523,11 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, } } if (wpa_key_mgmt_supports_caching(sm->key_mgmt) && use_pmk_cache) { - if (reassoc_same_ess && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) { + if (reassoc_same_ess && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) { pmksa_cache_set_current(sm, NULL, (const u8*) bssid, (void*)sm->network_ctx, try_opportunistic); - } else { + } else { pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, try_opportunistic); - } + } wpa_sm_set_pmk_from_pmksa(sm); } else { if (pmksa) { @@ -2388,9 +2544,9 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, sm->pmf_cfg = wifi_cfg.sta.pmf_cfg; sm->mgmt_group_cipher = cipher_type_map_public_to_supp(mgmt_cipher); if (sm->mgmt_group_cipher == WPA_CIPHER_NONE) { - wpa_printf(MSG_ERROR, "mgmt_cipher %d not supported", mgmt_cipher); - return -1; - } + wpa_printf(MSG_ERROR, "mgmt_cipher %d not supported", mgmt_cipher); + return -1; + } #ifdef CONFIG_SUITEB192 extern bool g_wpa_suiteb_certification; if (is_wpa2_enterprise_connection() && g_wpa_suiteb_certification) { @@ -2420,7 +2576,7 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, #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); + struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, bssid); if (!bss) { return -1; } @@ -2447,24 +2603,80 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, return -1; sm->assoc_wpa_ie_len = res; - const u8 *rsnxe; - rsnxe = esp_wifi_sta_get_rsnxe((u8*)bssid); - wpa_sm_set_ap_rsnxe(rsnxe, rsnxe ? (rsnxe[1] + 2) : 0); + ie = esp_wifi_sta_get_ie(bssid, WLAN_EID_RSN); + wpa_sm_set_ap_rsn_ie(sm, ie, ie ? (ie[1] + 2) : 0); + ie = esp_wifi_sta_get_ie(bssid, WLAN_EID_RSNX); + wpa_sm_set_ap_rsnxe(sm, ie, ie ? (ie[1] + 2) : 0); - res = wpa_gen_rsnxe(sm, assoc_rsnxe, assoc_rsnxe_len); +#ifdef CONFIG_WPA3_COMPAT + ie = esp_wifi_sta_get_ie(bssid, WFA_RSNE_OVERRIDE_OUI_TYPE); + wpa_sm_set_ap_rsne_override(sm, ie, ie ? (ie[1] + 2) : 0); + ie = esp_wifi_sta_get_ie(bssid, WFA_RSNXE_OVERRIDE_OUI_TYPE); + wpa_sm_set_ap_rsnxe_override(sm, ie, ie ? (ie[1] + 2) : 0); +#endif + + pos = assoc_ie; + res = wpa_gen_rsnxe(sm, pos, assoc_ie_len); if (res < 0) return -1; - assoc_rsnxe_len = res; - res = wpa_sm_set_assoc_rsnxe(sm, assoc_rsnxe, assoc_rsnxe_len); - if (res < 0) + + assoc_ie_len = res; + res = wpa_sm_set_assoc_rsnxe(sm, pos, assoc_ie_len); + if (res < 0) { return -1; - esp_set_assoc_ie((uint8_t *)bssid, assoc_rsnxe, assoc_rsnxe_len, true); + } + pos += assoc_ie_len; + +#ifdef CONFIG_WPA3_COMPAT + wpa_sm_set_param(sm, WPA_PARAM_RSN_OVERRIDE_SUPPORT, + esp_wifi_is_wpa3_compatible_mode_enabled(WIFI_IF_STA)); + wpa_sm_set_param(sm, WPA_PARAM_RSN_OVERRIDE, + RSN_OVERRIDE_NOT_USED); + ie = esp_wifi_sta_get_ie(bssid, WFA_RSNE_OVERRIDE_OUI_TYPE); + + if (esp_wifi_is_wpa3_compatible_mode_enabled(WIFI_IF_STA) && ie) { + enum rsn_selection_variant variant = RSN_SELECTION_RSNE; + + if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) { + u32 type; + + type = WPA_GET_BE32(&ie[2]); + if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) { + variant = RSN_SELECTION_RSNE_OVERRIDE; + wpa_sm_set_param(sm, + WPA_PARAM_RSN_OVERRIDE, + RSN_OVERRIDE_RSNE_OVERRIDE); + } + } + /* Indicate support for RSN overriding */ + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 4 + 1; + WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE); + pos += 4; + *pos = variant; + assoc_ie_len += 2 + 4 + 1; + } +#endif + + wpa_hexdump(MSG_DEBUG, "WPA: ASSOC IE LEN", assoc_ie, assoc_ie_len); + esp_set_assoc_ie(bssid, assoc_ie, assoc_ie_len, true); + + if (sm->ap_rsnxe != NULL) { +#ifdef CONFIG_SAE_PK + const u8 *pw = (const u8 *)esp_wifi_sta_get_prof_password_internal(); + if (esp_wifi_sta_get_config_sae_pk_internal() != WPA3_SAE_PK_MODE_DISABLED && + sae_pk_valid_password((const char*)pw)) { + sm->sae_pk = true; + } +#endif /* CONFIG_SAE_PK */ + } + 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)) + if (!mbo_bss_profile_match(bssid)) return -1; #endif @@ -2477,8 +2689,7 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, /* * Call after set ssid since we calc pmk inside this routine directly */ - void -wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) +void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) { struct wifi_ssid *sta_ssid = esp_wifi_sta_get_prof_ssid_internal(); struct wpa_sm *sm = &gWpaSm; @@ -2511,7 +2722,7 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) } if (sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X) { - /* TODO nothing */ + /* TODO nothing */ } else { memcpy(sm->pmk, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN); sm->pmk_len = PMK_LEN; @@ -2523,18 +2734,17 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len) #endif /* CONFIG_IEEE80211R */ } - void -set_assoc_ie(u8 * assoc_buf) +void set_assoc_ie(u8 * assoc_buf) { struct wpa_sm *sm = &gWpaSm; sm->assoc_wpa_ie = assoc_buf + 2; //wpa_ie insert OUI 4 byte before ver, but RSN have 2 bytes of RSN capability, // so wpa_ie have two more bytes than rsn_ie - if ( sm->proto == WPA_PROTO_WPA) - sm->assoc_wpa_ie_len = ASSOC_IE_LEN; + if (sm->proto == WPA_PROTO_WPA) + sm->assoc_wpa_ie_len = ASSOC_IE_LEN; else - sm->assoc_wpa_ie_len = ASSOC_IE_LEN - 2; + sm->assoc_wpa_ie_len = ASSOC_IE_LEN - 2; wpa_config_assoc_ie(sm->proto, assoc_buf, sm->assoc_wpa_ie_len); } @@ -2616,7 +2826,7 @@ int wpa_michael_mic_failure(u16 isunicast) * Need to wait for completion of request frame. We do not get * any callback for the message completion, so just wait a * short while and hope for the best. */ - os_sleep(0, 10000); + os_sleep(0, 10000); /*deauthenticate AP*/ @@ -2740,13 +2950,57 @@ struct wpa_sm * get_wpa_sm(void) return &gWpaSm; } -int wpa_sm_set_ap_rsnxe(const u8 *ie, size_t len) +/** + * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @ie: Pointer to IE data (starting from id) + * @len: IE length + * Returns: 0 on success, -1 on failure + * + * Inform WPA state machine about the RSN IE used in Beacon / Probe Response + * frame. + */ +int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len) { - struct wpa_sm *sm = &gWpaSm; + if (sm == NULL) + return -1; + + os_free(sm->ap_rsn_ie); + if (ie == NULL || len == 0) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: clearing AP RSN IE"); + sm->ap_rsn_ie = NULL; + sm->ap_rsn_ie_len = 0; + } else { + wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len); + sm->ap_rsn_ie = os_memdup(ie, len); + if (sm->ap_rsn_ie == NULL) + return -1; + + sm->ap_rsn_ie_len = len; + } + + return 0; +} + +/** + * wpa_sm_set_ap_rsnxe - Set AP RSNXE from Beacon/ProbeResp + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @ie: Pointer to IE data (starting from id) + * @len: IE length + * Returns: 0 on success, -1 on failure + * + * Inform WPA state machine about the RSNXE used in Beacon / Probe Response + * frame. + */ +int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len) +{ + if (!sm) + return -1; os_free(sm->ap_rsnxe); if (!ie || len == 0) { - wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len); + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP RSNXE"); sm->ap_rsnxe = NULL; sm->ap_rsnxe_len = 0; } else { @@ -2758,20 +3012,64 @@ int wpa_sm_set_ap_rsnxe(const u8 *ie, size_t len) sm->ap_rsnxe_len = len; } - if (sm->ap_rsnxe != NULL) { - sm->sae_pwe = esp_wifi_get_config_sae_pwe_h2e_internal(WIFI_IF_STA); -#ifdef CONFIG_SAE_PK - const u8 *pw = (const u8 *)esp_wifi_sta_get_prof_password_internal(); - if (esp_wifi_sta_get_config_sae_pk_internal() != WPA3_SAE_PK_MODE_DISABLED && - sae_pk_valid_password((const char*)pw)) { - sm->sae_pk = true; - } -#endif /* CONFIG_SAE_PK */ - } return 0; } +#ifdef CONFIG_WPA3_COMPAT +int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie, size_t len) +{ + if (!sm) + return -1; + + os_free(sm->ap_rsne_override); + if (!ie || len == 0) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Clearing AP RSNE Override element"); + sm->ap_rsne_override = NULL; + sm->ap_rsne_override_len = 0; + } else { + wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNE Override element", + ie, len); + sm->ap_rsne_override = os_memdup(ie, len); + if (!sm->ap_rsne_override) + return -1; + + sm->ap_rsne_override_len = len; + } + + return 0; +} +#endif + + +#ifdef CONFIG_WPA3_COMPAT +int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie, size_t len) +{ + if (!sm) + return -1; + + os_free(sm->ap_rsnxe_override); + if (!ie || len == 0) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Clearing AP RSNXE Override element"); + sm->ap_rsnxe_override = NULL; + sm->ap_rsnxe_override_len = 0; + } else { + wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNXE Override element", + ie, len); + sm->ap_rsnxe_override = os_memdup(ie, len); + if (!sm->ap_rsnxe_override) + return -1; + + sm->ap_rsnxe_override_len = len; + } + + return 0; +} +#endif + + int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len) { if (!sm) diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index 12e0fd7f09..bff1c19216 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -35,6 +35,12 @@ struct l2_ethhdr { be16 h_proto; } STRUCT_PACKED; +#ifdef CONFIG_WPA3_COMPAT +enum wpa_sm_conf_params { + WPA_PARAM_RSN_OVERRIDE, + WPA_PARAM_RSN_OVERRIDE_SUPPORT, +}; +#endif void wpa_sm_set_state(enum wpa_states state); @@ -54,12 +60,24 @@ int wpa_sm_set_key(struct install_key *sm, enum wpa_alg alg, u8 *key, size_t key_len, enum key_flag key_flag); -int wpa_sm_set_ap_rsnxe(const u8 *ie, size_t len); +int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len); + +int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len); + +#ifdef CONFIG_WPA3_COMPAT +int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie, size_t len); + +int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie, size_t len); +#endif int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len); void wpa_sm_drop_sa(struct wpa_sm *sm); +#ifdef CONFIG_WPA3_COMPAT +int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, + unsigned int value); +#endif #ifdef CONFIG_IEEE80211R int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len); diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index b31aeb1e1a..42fcbc2e49 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -22,6 +22,13 @@ struct install_key { u8 key[32]; }; +#ifdef CONFIG_WPA3_COMPAT +enum wpa_rsn_override { + RSN_OVERRIDE_NOT_USED, + RSN_OVERRIDE_RSNE, + RSN_OVERRIDE_RSNE_OVERRIDE, +}; +#endif /** * struct wpa_sm - Internal WPA state machine data */ @@ -76,6 +83,10 @@ struct wpa_sm { u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe; size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len; +#ifdef CONFIG_WPA3_COMPAT + u8 *ap_rsne_override, *ap_rsnxe_override; + size_t ap_rsne_override_len, ap_rsnxe_override_len; +#endif bool key_install; @@ -119,6 +130,10 @@ struct wpa_sm { #endif /* CONFIG_OWE_STA */ int (*wpa_sm_wps_disable)(void); esp_err_t (*wpa_sm_eap_disable)(void); +#ifdef CONFIG_WPA3_COMPAT + bool rsn_override_support; + enum wpa_rsn_override rsn_override; +#endif }; /** @@ -204,10 +219,13 @@ void eapol_txcb(uint8_t *eapol_payload, size_t len, bool tx_failure); 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_set_bss(uint8_t *macddr, uint8_t *bssid, uint8_t pairwise_cipher, uint8_t group_cipher, char *passphrase, uint8_t *ssid, int 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); +#ifdef CONFIG_WPA3_COMPAT +bool wpa_sm_rsn_overriding_supported(struct wpa_sm *sm); +#endif #endif /* WPA_I_H */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index 3b885af4ce..8bafca9653 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -39,6 +39,16 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, return wpa_parse_wpa_ie_rsnxe(wpa_ie, wpa_ie_len, data); } else if (wpa_ie[0] == WLAN_EID_WAPI) { return 0; +#ifdef CONFIG_WPA3_COMPAT + } else if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC && + wpa_ie[1] >= 4 && + WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE) { + return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); + } else if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC && + wpa_ie[1] >= 4 && + WPA_GET_BE32(&wpa_ie[2]) == RSNXE_OVERRIDE_IE_VENDOR_TYPE) { + return wpa_parse_wpa_ie_rsnxe(wpa_ie, wpa_ie_len, data); +#endif } return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); @@ -297,7 +307,7 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len) { u8 *pos = rsnxe; - u16 capab = 0, tmp; + u32 capab = 0, tmp; size_t flen; if (wpa_key_mgmt_sae(sm->key_mgmt) && @@ -326,142 +336,11 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len) *pos++ = WLAN_EID_RSNX; *pos++ = flen; - *pos++ = capab & 0x00ff; - capab >>= 8; - if (capab) - *pos++ = capab; + while (capab) { + *pos++ = capab & 0xff; + capab >>= 8; + } return pos - rsnxe; } - -/** - * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs - * @pos: Pointer to the IE header - * @end: Pointer to the end of the Key Data buffer - * @ie: Pointer to parsed IE data - * Returns: 0 on success, 1 if end mark is found, -1 on failure - */ -static int wpa_parse_generic(const u8 *pos, const u8 *end, - struct wpa_eapol_ie_parse *ie) -{ - if (pos[1] == 0) - return 1; - - if (pos[1] >= 6 && - RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && - pos[2 + WPA_SELECTOR_LEN] == 1 && - pos[2 + WPA_SELECTOR_LEN + 1] == 0) { - ie->wpa_ie = pos; - ie->wpa_ie_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", - ie->wpa_ie, ie->wpa_ie_len); - return 0; - } - - if (pos + 1 + RSN_SELECTOR_LEN < end && - pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { - ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { - ie->gtk = pos + 2 + RSN_SELECTOR_LEN; - ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: GTK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { - ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; - ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } -#ifdef CONFIG_IEEE80211W - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { - ie->igtk = pos + 2 + RSN_SELECTOR_LEN; - ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } -#endif - if (pos[1] >= RSN_SELECTOR_LEN + 1 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) { - ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN; - ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, - "WPA: Transition Disable KDE in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - return 0; -} - - -/** - * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs - * @buf: Pointer to the Key Data buffer - * @len: Key Data Length - * @ie: Pointer to parsed IE data - * Returns: 0 on success, -1 on failure - */ -int wpa_supplicant_parse_ies(const u8 *buf, size_t len, - struct wpa_eapol_ie_parse *ie) -{ - const u8 *pos, *end; - int ret = 0; - - memset(ie, 0, sizeof(*ie)); - for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { - if (pos[0] == 0xdd && - ((pos == buf + len - 1) || pos[1] == 0)) { - /* Ignore padding */ - break; - } - if (pos + 2 + pos[1] > end) { - wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " - "underflow (ie=%d len=%d pos=%d)", - pos[0], pos[1], (int) (pos - buf)); - wpa_hexdump(MSG_DEBUG, "WPA: Key Data", - buf, len); - ret = -1; - break; - } - if (*pos == WLAN_EID_RSN) { - ie->rsn_ie = pos; - ie->rsn_ie_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", - ie->rsn_ie, ie->rsn_ie_len); - } else if (*pos == WLAN_EID_RSNX) { - ie->rsnxe = pos; - ie->rsnxe_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key", - ie->rsnxe, ie->rsnxe_len); - } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { - ret = wpa_parse_generic(pos, end, ie); - if (ret < 0) - break; - if (ret > 0) { - ret = 0; - break; - } - } else { - wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " - "Key Data IE", pos, 2 + pos[1]); - } - } - - return ret; -} - - #endif // ESP_SUPPLICANT diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.h b/components/wpa_supplicant/src/rsn_supp/wpa_ie.h index b799064635..17089b9988 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.h @@ -15,36 +15,6 @@ #ifndef WPA_IE_H #define WPA_IE_H -struct wpa_eapol_ie_parse { - const u8 *wpa_ie; - size_t wpa_ie_len; - const u8 *rsn_ie; - size_t rsn_ie_len; - const u8 *pmkid; - const u8 *gtk; - size_t gtk_len; - const u8 *mac_addr; - size_t mac_addr_len; -#ifdef CONFIG_IEEE80211W - const u8 *igtk; - size_t igtk_len; -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_IEEE80211R - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; - const u8 *reassoc_deadline; - const u8 *key_lifetime; -#endif /* CONFIG_IEEE80211R */ - const u8 *transition_disable; - size_t transition_disable_len; - const u8 *rsnxe; - size_t rsnxe_len; -}; - -int wpa_supplicant_parse_ies(const u8 *buf, size_t len, - struct wpa_eapol_ie_parse *ie); int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len); int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, diff --git a/examples/wifi/getting_started/station/main/station_example_main.c b/examples/wifi/getting_started/station/main/station_example_main.c index d5ed5eb1a1..1cc82b0b83 100644 --- a/examples/wifi/getting_started/station/main/station_example_main.c +++ b/examples/wifi/getting_started/station/main/station_example_main.c @@ -129,6 +129,9 @@ void wifi_init_sta(void) .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD, .sae_pwe_h2e = ESP_WIFI_SAE_MODE, .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER, +#ifdef CONFIG_ESP_WIFI_WPA3_COMPATIBLE_SUPPORT + .disable_wpa3_compatible_mode = 0, +#endif }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );