diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index cebdcb45497..6be8440d231 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -85,6 +85,9 @@ typedef struct { * Strength of authmodes * Personal Networks : OPEN < WEP < WPA_PSK < OWE < WPA2_PSK = WPA_WPA2_PSK < WAPI_PSK < WPA3_PSK = WPA2_WPA3_PSK = DPP * Enterprise Networks : WIFI_AUTH_WPA_ENTERPRISE < WIFI_AUTH_WPA2_ENTERPRISE < WIFI_AUTH_WPA3_ENTERPRISE = WIFI_AUTH_WPA2_WPA3_ENTERPRISE < WIFI_AUTH_WPA3_ENT_192 + * + * @note WIFI_AUTH_UNKNOWN indicates an Access Point with invalid or unparseable security configuration + * detected during scan parsing. */ typedef enum { WIFI_AUTH_OPEN = 0, /**< Authenticate mode : open */ @@ -105,6 +108,7 @@ typedef enum { WIFI_AUTH_WPA3_ENTERPRISE, /**< Authenticate mode : WPA3-Enterprise Only Mode */ WIFI_AUTH_WPA2_WPA3_ENTERPRISE, /**< Authenticate mode : WPA3-Enterprise Transition Mode */ WIFI_AUTH_WPA_ENTERPRISE, /**< Authenticate mode : WPA-Enterprise security */ + WIFI_AUTH_UNKNOWN, /**< Scan parsed authmode: Unknown or invalid security configuration parsed during scan */ WIFI_AUTH_MAX } wifi_auth_mode_t; @@ -335,7 +339,8 @@ typedef struct { uint32_t wps: 1; /**< Bit: 7 flag to identify if WPS is supported or not */ uint32_t ftm_responder: 1; /**< Bit: 8 flag to identify if FTM is supported in responder mode */ uint32_t ftm_initiator: 1; /**< Bit: 9 flag to identify if FTM is supported in initiator mode */ - uint32_t reserved: 22; /**< Bit: 10..31 reserved */ + uint32_t akm_dpp: 1; /**< Bit: 10 flag set when AP supports mixed DPP AKM (e.g., SAE + DPP or WPA2-PSK + DPP) or when AP only supports DPP AKM */ + uint32_t reserved: 21; /**< Bit: 11..31 reserved */ wifi_country_t country; /**< Country information of AP */ wifi_he_ap_info_t he_ap; /**< HE AP info */ wifi_bandwidth_t bandwidth; /**< Bandwidth of AP */ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 9dcdcbae600..77143eec456 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 9dcdcbae600ac58c3cb55071afb895bd5f7674d6 +Subproject commit 77143eec456e1cdcbce3e1dad8d5983cd28a368f diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h index 4b6bb15b336..c509773c0b5 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h @@ -85,6 +85,9 @@ typedef struct { * Strength of authmodes * Personal Networks : OPEN < WEP < WPA_PSK < OWE < WPA2_PSK = WPA_WPA2_PSK < WAPI_PSK < WPA3_PSK = WPA2_WPA3_PSK = DPP * Enterprise Networks : WIFI_AUTH_WPA_ENTERPRISE < WIFI_AUTH_WPA2_ENTERPRISE < WIFI_AUTH_WPA3_ENTERPRISE = WIFI_AUTH_WPA2_WPA3_ENTERPRISE < WIFI_AUTH_WPA3_ENT_192 + * + * @note WIFI_AUTH_UNKNOWN indicates an Access Point with invalid or unparseable security configuration + * detected during scan parsing. */ typedef enum { WIFI_AUTH_OPEN = 0, /**< Authenticate mode : open */ @@ -105,6 +108,7 @@ typedef enum { WIFI_AUTH_WPA3_ENTERPRISE, /**< Authenticate mode : WPA3-Enterprise Only Mode */ WIFI_AUTH_WPA2_WPA3_ENTERPRISE, /**< Authenticate mode : WPA3-Enterprise Transition Mode */ WIFI_AUTH_WPA_ENTERPRISE, /**< Authenticate mode : WPA-Enterprise security */ + WIFI_AUTH_UNKNOWN, /**< Scan parsed authmode: Unknown or invalid security configuration parsed during scan */ WIFI_AUTH_MAX } wifi_auth_mode_t; @@ -335,7 +339,8 @@ typedef struct { uint32_t wps: 1; /**< Bit: 7 flag to identify if WPS is supported or not */ uint32_t ftm_responder: 1; /**< Bit: 8 flag to identify if FTM is supported in responder mode */ uint32_t ftm_initiator: 1; /**< Bit: 9 flag to identify if FTM is supported in initiator mode */ - uint32_t reserved: 22; /**< Bit: 10..31 reserved */ + uint32_t akm_dpp: 1; /**< Bit: 10 flag set when AP supports mixed DPP AKM (e.g., SAE + DPP or WPA2-PSK + DPP) or when AP only supports DPP AKM */ + uint32_t reserved: 21; /**< Bit: 11..31 reserved */ wifi_country_t country; /**< Country information of AP */ wifi_he_ap_info_t he_ap; /**< HE AP info */ wifi_bandwidth_t bandwidth; /**< Bandwidth of AP */ diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_dpp.h b/components/wpa_supplicant/esp_supplicant/include/esp_dpp.h index 2c583efd0c2..1966bbca8a0 100644 --- a/components/wpa_supplicant/esp_supplicant/include/esp_dpp.h +++ b/components/wpa_supplicant/esp_supplicant/include/esp_dpp.h @@ -83,7 +83,9 @@ esp_err_t esp_supp_dpp_deinit(void); * Generates Out Of Band Bootstrap information as an Enrollee which can be * used by a DPP Configurator to provision the Enrollee. * - * @param chan_list List of channels device will be available on for listening (must not be NULL) + * @param chan_list Comma-separated list of channels for listening (must not be NULL). + * A single channel (e.g., "6") is recommended for reliable discovery. + * If using multiple, prefer non-overlapping channels (e.g., "1,6,11"). * @param type Bootstrap method type, only QR Code method is supported for now. * @param key (Optional) 32 byte Raw Private Key for generating a Bootstrapping Public Key * @param info (Optional) Ancillary Device Information like Serial Number diff --git a/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c b/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c index b867040c8d1..4b9603676b7 100644 --- a/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c +++ b/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c @@ -1638,8 +1638,9 @@ struct crypto_ec_key * crypto_ec_key_set_pub(const struct crypto_ec_group *group * uncompressed format (0x04 || X || Y). */ - // Check if buffer has a format prefix (0x04, 0x02, or 0x03) - if (len > 0 && (buf[0] == 0x04 || buf[0] == 0x02 || buf[0] == 0x03)) { + size_t coord_len = PSA_BITS_TO_BYTES(bits); + + if (len > 0 && len != 2 * coord_len && (buf[0] == 0x04 || buf[0] == 0x02 || buf[0] == 0x03)) { // Already has format prefix (0x04, 0x02, or 0x03) key_buf = os_calloc(1, len); if (!key_buf) { diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c b/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c index ce35e65fb28..395d803ff52 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c @@ -309,8 +309,14 @@ static esp_err_t esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t * return ESP_ERR_DPP_INVALID_ATTR; } if (s_dpp_ctx.dpp_auth) { - wpa_printf(MSG_DEBUG, "DPP: Already in DPP authentication exchange - ignore new one"); - return ESP_OK; + if (s_dpp_ctx.dpp_auth->auth_success || !s_dpp_ctx.dpp_auth->waiting_auth_conf) { + wpa_printf(MSG_INFO, "DPP: Cleaning up old completed DPP auth context for new exchange"); + dpp_cancel_auth_gas_eloop_timeouts(); + dpp_deinit_auth(); + } else { + wpa_printf(MSG_DEBUG, "DPP: Already in DPP authentication exchange - ignore new one"); + return ESP_OK; + } } s_dpp_ctx.dpp_auth = dpp_auth_req_rx(NULL, DPP_CAPAB_ENROLLEE, 0, NULL, own_bi, rx_param->channel, @@ -326,7 +332,8 @@ static esp_err_t esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t * } os_memcpy(s_dpp_ctx.dpp_auth->peer_mac_addr, rx_param->sa, ETH_ALEN); - wpa_printf(MSG_INFO, "DPP: Sending authentication response chan(%d)", rx_param->channel); + wpa_printf(MSG_INFO, "DPP: Sending authentication response chan(%d)", + s_dpp_ctx.dpp_auth->curr_chan); eloop_cancel_timeout(esp_dpp_auth_resp_retry_timeout, NULL, NULL); if (eloop_register_timeout(0, 200000, esp_dpp_auth_resp_retry_timeout, NULL, NULL) < 0) { wpa_printf(MSG_ERROR, "DPP: Failed to register auth_resp_retry_timeout"); @@ -334,7 +341,7 @@ static esp_err_t esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t * } esp_err_t err = esp_dpp_send_action_frame(rx_param->sa, wpabuf_head(s_dpp_ctx.dpp_auth->resp_msg), wpabuf_len(s_dpp_ctx.dpp_auth->resp_msg), - rx_param->channel, 1000 + OFFCHAN_TX_WAIT_TIME, + s_dpp_ctx.dpp_auth->curr_chan, 1000 + OFFCHAN_TX_WAIT_TIME, DPP_TX_AUTHENTICATION_RESP); if (err != ESP_OK) { return ESP_ERR_DPP_TX_FAILURE; @@ -365,6 +372,8 @@ static int esp_dpp_rx_auth_conf(struct action_rx_param *rx_param, uint8_t *dpp_d } eloop_cancel_timeout(esp_dpp_auth_conf_wait_timeout, NULL, NULL); + eloop_cancel_timeout(esp_dpp_auth_resp_retry_timeout, NULL, NULL); + eloop_cancel_timeout(esp_dpp_auth_resp_retry, NULL, NULL); if (dpp_auth_conf_rx(auth, (const u8 *)&public_action->v, dpp_data, len) < 0) { @@ -454,6 +463,7 @@ static esp_err_t esp_dpp_rx_peer_disc_resp(struct action_rx_param *rx_param) /* peer_disc_timeout handles timeout in Enrollee role */ eloop_cancel_timeout(peer_disc_timeout, NULL, s_dpp_ctx.dpp_auth); + s_dpp_ctx.peer_disc_resp_received = true; if (!conf->connector || !conf->net_access_key || !conf->c_sign_key) { wpa_printf(MSG_ERROR, "DPP: Incomplete config for network introduction"); @@ -482,11 +492,12 @@ static esp_err_t esp_dpp_rx_peer_disc_resp(struct action_rx_param *rx_param) } os_memcpy(entry->aa, rx_param->sa, ETH_ALEN); + os_memcpy(entry->spa, gWpaSm.own_addr, ETH_ALEN); os_memcpy(entry->pmkid, intro->pmkid, PMKID_LEN); os_memcpy(entry->pmk, intro->pmk, intro->pmk_len); entry->pmk_len = intro->pmk_len; entry->akmp = WPA_KEY_MGMT_DPP; - entry->network_ctx = NULL; + entry->network_ctx = gWpaSm.network_ctx; if (expiry > 0) { struct os_time now; @@ -784,11 +795,25 @@ static void esp_dpp_fill_wifi_cfg_from_config(const esp_dpp_config_data_t *dpp, } } - if (dpp_akm_sae((enum dpp_akm) dpp->akm)) { + if (dpp_akm_sae((enum dpp_akm) dpp->akm) || dpp_akm_dpp((enum dpp_akm) dpp->akm)) { wifi_cfg->sta.pmf_cfg.capable = true; wifi_cfg->sta.pmf_cfg.required = true; } + switch ((enum dpp_akm) dpp->akm) { + case DPP_AKM_DPP: + case DPP_AKM_SAE_DPP: + case DPP_AKM_SAE: + wifi_cfg->sta.threshold.authmode = WIFI_AUTH_WPA3_PSK; + break; + case DPP_AKM_PSK_SAE_DPP: + case DPP_AKM_PSK_SAE: + case DPP_AKM_PSK: + default: + wifi_cfg->sta.threshold.authmode = WIFI_AUTH_WPA2_PSK; + break; + } + if (dpp->curr_chan) { wifi_cfg->sta.channel = dpp->curr_chan; } @@ -886,6 +911,7 @@ static esp_err_t gas_process_complete_resp(struct dpp_authentication *auth, * no Connector is rejected without touching the stored entry. */ dpp_clear_confs(s_dpp_ctx.dpp_config_store->conf); s_dpp_ctx.dpp_config_store->conf = NULL; + esp_wifi_sta_notify_dpp_config_set_internal(false); } } @@ -926,6 +952,7 @@ static esp_err_t gas_process_complete_resp(struct dpp_authentication *auth, } else { dpp_clear_confs(dc->conf); dc->conf = new_conf_pending; + esp_wifi_sta_notify_dpp_config_set_internal(true); } } else { dpp_clear_confs(new_conf_pending); @@ -1574,6 +1601,7 @@ static int esp_dpp_deinit(void *data, void *user_ctx) if (s_dpp_ctx.dpp_config_store) { dpp_config_store_deinit(s_dpp_ctx.dpp_config_store); s_dpp_ctx.dpp_config_store = NULL; + esp_wifi_sta_notify_dpp_config_set_internal(false); } if (s_dpp_ctx.dpp_auth) { dpp_auth_deinit(s_dpp_ctx.dpp_auth); @@ -1810,11 +1838,15 @@ static void tx_status_eloop_handler(void *eloop_ctx, void *event_data) } else if (evt->status == WIFI_ACTION_TX_DONE) { /* Peer discovery sent, wait for response. */ eloop_cancel_timeout(peer_disc_timeout, NULL, auth); - if (eloop_register_timeout(ESP_GAS_TIMEOUT_SECS, 0, peer_disc_timeout, NULL, auth) < 0) { - wpa_printf(MSG_ERROR, "DPP: Failed to register peer_disc_timeout after disc TX"); - dpp_abort_failure_locked(ESP_ERR_DPP_FAILURE); - os_free(evt); - return; + if (!s_dpp_ctx.peer_disc_resp_received) { + if (eloop_register_timeout(ESP_GAS_TIMEOUT_SECS, 0, peer_disc_timeout, NULL, auth) < 0) { + wpa_printf(MSG_ERROR, "DPP: Failed to register peer_disc_timeout after disc TX"); + dpp_abort_failure_locked(ESP_ERR_DPP_FAILURE); + os_free(evt); + return; + } + } else { + wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response already received, skip registering peer_disc_timeout"); } } } else if (type == DPP_TX_AUTHENTICATION_CONF) { @@ -2357,6 +2389,7 @@ init_fail: if (s_dpp_ctx.dpp_config_store) { dpp_config_store_deinit(s_dpp_ctx.dpp_config_store); s_dpp_ctx.dpp_config_store = NULL; + esp_wifi_sta_notify_dpp_config_set_internal(false); } dpp_api_unlock(); return ret; @@ -2428,6 +2461,10 @@ static esp_err_t esp_dpp_start_net_intro_protocol_internal(uint8_t *bssid) } config_store = s_dpp_ctx.dpp_config_store; + if (!config_store) { + wpa_printf(MSG_ERROR, "DPP: config store not initialized"); + return ESP_ERR_INVALID_STATE; + } os_memcpy(config_store->peer_mac_addr, bssid, ETH_ALEN); curr_chan = config->curr_chan; buf = dpp_build_peer_disc_req(config_store, config); @@ -2471,6 +2508,7 @@ esp_err_t esp_dpp_start_net_intro_protocol(uint8_t *bssid) * is reserved for deinit. */ dpp_cancel_auth_gas_eloop_timeouts(); s_dpp_ctx.gas_query_tries = 0; + s_dpp_ctx.peer_disc_resp_received = false; wpa_printf(MSG_INFO, "DPP: Starting Network Introduction to " MACSTR, MAC2STR(bssid)); @@ -2674,28 +2712,33 @@ esp_err_t esp_supp_dpp_set_config(const esp_dpp_config_data_t *config) dc = s_dpp_ctx.dpp_config_store; - if (!config) { - if (dc && dc->conf) { - dpp_clear_confs(dc->conf); - dc->conf = NULL; - } - dpp_api_unlock(); - return ESP_OK; - } - if (!dc) { dpp_api_unlock(); return ESP_ERR_INVALID_STATE; } + if (!config) { + if (dc->conf) { + dpp_clear_confs(dc->conf); + dc->conf = NULL; + } + dpp_api_unlock(); + esp_wifi_sta_notify_dpp_config_set_internal(false); + return ESP_OK; + } + if (esp_dpp_stored_conf_matches_row(dc, config)) { dpp_api_unlock(); + esp_wifi_sta_notify_dpp_config_set_internal(true); return ESP_OK; } err = esp_dpp_conf_alloc_from_config_data(config, &new_conf); if (err != ESP_OK) { + dpp_clear_confs(dc->conf); + dc->conf = NULL; dpp_api_unlock(); + esp_wifi_sta_notify_dpp_config_set_internal(false); return err; } @@ -2703,6 +2746,7 @@ esp_err_t esp_supp_dpp_set_config(const esp_dpp_config_data_t *config) dc->conf = new_conf; dpp_api_unlock(); + esp_wifi_sta_notify_dpp_config_set_internal(true); return ESP_OK; } diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h index c80b60238ad..29026c063e2 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h @@ -59,6 +59,7 @@ struct esp_dpp_context_t { enum dpp_tx_frame_type type; } pending_tx_op; bool pending_tx_op_in_progress; + bool peer_disc_resp_received; unsigned int listen_chan_idx; }; 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 e58fa811542..0b00cad906b 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -327,6 +327,7 @@ uint8_t esp_wifi_sta_get_config_sae_pk_internal(void); void esp_wifi_sta_disable_sae_pk_internal(void); void esp_wifi_sta_disable_wpa2_authmode_internal(void); void esp_wifi_sta_disable_owe_trans_internal(void); +void esp_wifi_sta_notify_dpp_config_set_internal(bool configured); uint8_t esp_wifi_ap_get_max_sta_conn(void); uint8_t esp_wifi_get_config_sae_pwe_h2e_internal(uint8_t ifx); bool esp_wifi_ap_notify_node_sae_auth_done(uint8_t *mac); diff --git a/components/wpa_supplicant/src/common/dpp.c b/components/wpa_supplicant/src/common/dpp.c index 6882c439264..dd29fd523a5 100644 --- a/components/wpa_supplicant/src/common/dpp.c +++ b/components/wpa_supplicant/src/common/dpp.c @@ -1820,12 +1820,14 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, const u8 *i_capab; const u8 *i_bootstrap; const u8 *version; + const u8 *channel; u16 wrapped_data_len; u16 i_proto_len; u16 i_nonce_len; u16 i_capab_len; u16 i_bootstrap_len; u16 version_len; + u16 channel_len; struct dpp_authentication *auth = NULL; #ifdef CONFIG_TESTING_OPTIONS u64 start_us = dpp_time_us(); @@ -1870,37 +1872,30 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, auth->peer_version); } -#if 0 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL, &channel_len); if (channel) { - //int neg_freq; - if (channel_len < 2) { dpp_auth_fail(auth, "Too short Channel attribute"); goto fail; } - neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]); wpa_printf(MSG_DEBUG, - "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d", - channel[0], channel[1], neg_freq); - if (neg_freq < 0) { + "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u", + channel[0], channel[1]); + if (!channel[0] || !channel[1]) { dpp_auth_fail(auth, "Unsupported Channel attribute value"); goto fail; } - if (auth->curr_freq != (unsigned int) neg_freq) { + if (auth->curr_chan != channel[1]) { wpa_printf(MSG_DEBUG, - "DPP: Changing negotiation channel from %u MHz to %u MHz", - freq, neg_freq); - auth->curr_freq = neg_freq; + "DPP: Changing negotiation channel from %u to %u", + auth->curr_chan, channel[1]); } - /* rename it to chan */ - auth->curr_chan = *channel; + auth->curr_chan = channel[1]; } -#endif i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len); diff --git a/examples/wifi/scan/main/scan.c b/examples/wifi/scan/main/scan.c index 2dd34ff907a..0f289c59053 100644 --- a/examples/wifi/scan/main/scan.c +++ b/examples/wifi/scan/main/scan.c @@ -68,6 +68,12 @@ static void print_auth_mode(int authmode) case WIFI_AUTH_WPA3_ENT_192: ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_ENT_192"); break; + case WIFI_AUTH_DPP: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_DPP"); + break; + case WIFI_AUTH_UNKNOWN: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN"); + break; default: ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN"); break; @@ -199,6 +205,9 @@ static void wifi_scan(void) ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid); ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi); print_auth_mode(ap_info[i].authmode); + if (ap_info[i].akm_dpp) { + ESP_LOGI(TAG, "DPP \t\tSupported%s", (ap_info[i].authmode != WIFI_AUTH_DPP) ? " (mixed mode)" : " (DPP-only)"); + } if (ap_info[i].authmode != WIFI_AUTH_WEP) { print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher); }