diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index f69b4e43388..cdc7a9ad66d 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -232,6 +232,9 @@ struct nan_secure_dp_funcs { * encrypted KDE payload (GTK/IGTK/BIGTK). */ int (*ndp_security_install_get_shared_desc_len)(void); + uint8_t (*get_ndp_resp_num_pmkids)(uint8_t ndp_id, const uint8_t *peer_nmi); + uint32_t (*get_ndp_resp_shared_key_desc_len)(uint8_t ndp_id, const uint8_t *peer_nmi); + /* --- CSIA / SCIA construction. Each writes a complete NAN * attribute (header + body) at @c frm and returns bytes * written, or -1 on error. --- */ diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 91585166ba9..f44b8590de5 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -1669,9 +1669,6 @@ typedef struct { uint32_t cookie; /**< Comeback cookie from responder (0 if none) */ } wifi_event_nan_bootstrap_complete_t; -#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Local reason: peer NIK follow-up not received within timeout. - See Wi-Fi Aware v4.0 §7.6.4.2 for the NIK-exchange procedure. */ - /** * @brief Argument structure for WIFI_EVENT_NAN_PAIRING_CONFIRM event */ 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 46c938bf35f..b748bb9291d 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 @@ -1669,9 +1669,6 @@ typedef struct { uint32_t cookie; /**< Comeback cookie from responder (0 if none) */ } wifi_event_nan_bootstrap_complete_t; -#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Local reason: peer NIK follow-up not received within timeout. - See Wi-Fi Aware v4.0 §7.6.4.2 for the NIK-exchange procedure. */ - /** * @brief Argument structure for WIFI_EVENT_NAN_PAIRING_CONFIRM event */ diff --git a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h index 0870e78883f..243ef96af99 100644 --- a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h +++ b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h @@ -53,6 +53,9 @@ void esp_nan_action_stop(void); #ifdef CONFIG_ESP_WIFI_NAN_PAIRING +#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Local reason: peer NIK follow-up not received within timeout. + See Wi-Fi Aware v4.0 §7.6.4.2 for the NIK-exchange procedure. */ + #ifndef NAN_PAIRING_PINCODE_MIN #define NAN_PAIRING_PINCODE_MIN 0 #endif diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 79ff3b5dc92..9e0dc69212e 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -1375,6 +1375,8 @@ static struct nan_secure_dp_funcs s_nan_secure_dp_funcs = { .get_scia_len = esp_nan_get_scia_len, .get_shared_key_desc_attr_len = esp_nan_get_shared_key_desc_attr_len, .ndp_security_install_get_shared_desc_len = esp_nan_ndp_security_install_get_shared_desc_len, + .get_ndp_resp_num_pmkids = esp_nan_get_ndp_resp_num_pmkids, + .get_ndp_resp_shared_key_desc_len = esp_nan_get_ndp_resp_shared_key_desc_len, /* CSIA / SCIA construction */ .construct_csia = esp_nan_construct_csia, diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index 001bf886f24..342ff87b92f 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -366,6 +366,8 @@ uint32_t esp_nan_get_csia_len(uint16_t own_csid_bitmap, uint16_t peer_csid_bitma uint32_t esp_nan_get_scia_len(uint8_t num_pmkids); uint32_t esp_nan_get_shared_key_desc_attr_len(uint16_t key_data_len); int esp_nan_ndp_security_install_get_shared_desc_len(void); +uint8_t esp_nan_get_ndp_resp_num_pmkids(uint8_t ndp_id, const uint8_t *peer_nmi); +uint32_t esp_nan_get_ndp_resp_shared_key_desc_len(uint8_t ndp_id, const uint8_t *peer_nmi); int esp_nan_construct_csia(uint8_t *frm, uint8_t pub_id, uint16_t own_csid_bitmap, uint16_t peer_csid_bitmap); diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 22f509c79ba..7c20bdfa938 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -510,7 +510,9 @@ static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) #if defined(CONFIG_ESP_WIFI_NAN_SECURITY) nan_app_remove_paired_peer(own->nik_fup_pending_peer_nmi); #endif - esp_nan_complete_pairing(own->svc_id); + struct peer_svc_info *peer = nan_find_peer_svc(own->svc_id, 0, + own->nik_fup_pending_peer_nmi); + esp_nan_complete_pairing(own->svc_id, peer ? peer->svc_id : 0); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); ESP_LOGW(TAG, "Pairing succeeded but NIK caching timed out for peer " MACSTR " (reason=%u)", MAC2STR(own->nik_fup_pending_peer_nmi), evt.reason_code); @@ -811,7 +813,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_nmi); - esp_nan_complete_pairing(own->svc_id); + esp_nan_complete_pairing(own->svc_id, peer->svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); return; } @@ -998,7 +1000,8 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_mac); - esp_nan_complete_pairing(p_peer_svc ? p_peer_svc->own_svc_id : 0); + esp_nan_complete_pairing(p_peer_svc ? p_peer_svc->own_svc_id : 0, + p_peer_svc ? p_peer_svc->svc_id : peer_svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); } diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c index 8e6df442bcc..14dbd6ff34d 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c @@ -427,6 +427,91 @@ static bool nan_security_fill_from_paired_cache(struct ndl_info *ndl, const uint } #endif +static bool nan_ndp_resp_resolve_pmk(struct ndl_info *ndl, const uint8_t *peer_nmi) +{ + static const uint8_t zero_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN] = {0}; + static const uint8_t zero_pmk[ESP_WIFI_NAN_NDP_PMK_LEN] = {0}; + + if (!ndl || !peer_nmi) { + return false; + } + + bool have_peer_pmkid = (memcmp(ndl->security_ctx.nd_pmkid, zero_pmkid, + ESP_WIFI_NAN_NDP_PMKID_LEN) != 0); + bool need_pmk = (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) || + (memcmp(ndl->security_ctx.nd_pmk, zero_pmk, ESP_WIFI_NAN_NDP_PMK_LEN) == 0); + + if (!need_pmk) { + return have_peer_pmkid; + } + +#if defined(CONFIG_ESP_WIFI_NAN_PAIRING) + if (nan_security_fill_from_paired_cache(ndl, peer_nmi)) { + return have_peer_pmkid; + } +#endif + + if (!have_peer_pmkid) { + return false; + } + + struct own_svc_info *p_svc = nan_find_own_svc(ndl->publisher_id); + int matched_idx = p_svc ? nan_match_pmkid(p_svc, ndl->security_ctx.nd_pmkid, + ndl->peer_nmi, ndl->peer_ndi) : -1; + if (matched_idx < 0) { + return false; + } + + ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED; + ndl->security_ctx.csid_bitmap = p_svc->derived_security[matched_idx].csid_bitmap; + memcpy(ndl->security_ctx.nd_pmk, + p_svc->derived_security[matched_idx].nd_pmk, + ESP_WIFI_NAN_NDP_PMK_LEN); + return true; +} + +uint8_t esp_nan_get_ndp_resp_num_pmkids(uint8_t ndp_id, const uint8_t *peer_nmi) +{ + static const uint8_t zero_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN] = {0}; + + if (!peer_nmi) { + return 0; + } + + NAN_DATA_LOCK(); + struct ndl_info *ndl = nan_find_ndl(ndp_id, (uint8_t *)peer_nmi); + if (!ndl) { + ndl = nan_find_ndl(0, (uint8_t *)peer_nmi); + } + uint8_t num = 0; + if (ndl && memcmp(ndl->security_ctx.nd_pmkid, zero_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN) != 0) { + num = 1; + } + NAN_DATA_UNLOCK(); + return num; +} + +uint32_t esp_nan_get_ndp_resp_shared_key_desc_len(uint8_t ndp_id, const uint8_t *peer_nmi) +{ + if (!peer_nmi) { + return 0; + } + + NAN_DATA_LOCK(); + struct ndl_info *ndl = nan_find_ndl(ndp_id, (uint8_t *)peer_nmi); + if (!ndl) { + ndl = nan_find_ndl(0, (uint8_t *)peer_nmi); + } + if (!ndl || ndl->handshake_state != NAN_HANDSHAKE_M1_RCVD || + !nan_ndp_resp_resolve_pmk(ndl, peer_nmi)) { + NAN_DATA_UNLOCK(); + return 0; + } + NAN_DATA_UNLOCK(); + + return esp_nan_get_shared_key_desc_attr_len(0); +} + /* * Build RSNA Key Descriptor payload (95-byte EAPOL-Key layout, see * IEEE 802.11-2020 §12.7.2). NAN carries this body inside the NAN @@ -1134,9 +1219,9 @@ int esp_nan_ndp_security_install_get_shared_desc_len(void) int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len, uint8_t ndp_id, const uint8_t *peer_nmi) { - const uint32_t attr_len = esp_nan_get_shared_key_desc_attr_len(0); + const uint32_t attr_len = esp_nan_get_ndp_resp_shared_key_desc_len(ndp_id, peer_nmi); - if (!buf || buf_len < attr_len || !peer_nmi) { + if (!buf || !peer_nmi || attr_len == 0 || buf_len < attr_len) { return 0; } @@ -1152,50 +1237,10 @@ int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len, uint8_t n ESP_LOGW(TAG, "NDP Resp Key Desc: NDL not in M1_RCVD (state=%d)", ndl->handshake_state); return 0; } - - /* Resolve PMK from publish when: NDL not encrypted, or encrypted but nd_pmk not set */ - { - static const uint8_t zero_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN] = {0}; - static const uint8_t zero_pmk[ESP_WIFI_NAN_NDP_PMK_LEN] = {0}; - bool have_peer_pmkid = (memcmp(ndl->security_ctx.nd_pmkid, zero_pmkid, - ESP_WIFI_NAN_NDP_PMKID_LEN) != 0); - bool need_pmk = (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) || - (memcmp(ndl->security_ctx.nd_pmk, zero_pmk, ESP_WIFI_NAN_NDP_PMK_LEN) == 0); - - bool resolved_from_pairing_cache = false; -#if defined(CONFIG_ESP_WIFI_NAN_PAIRING) - if (need_pmk) { - resolved_from_pairing_cache = nan_security_fill_from_paired_cache(ndl, peer_nmi); - } -#endif - - if (resolved_from_pairing_cache) { - ESP_LOGD(TAG, "NDP Resp Key Desc: resolved PMK from paired-peer cache"); - } else if (need_pmk && have_peer_pmkid) { - struct own_svc_info *p_svc = nan_find_own_svc(ndl->publisher_id); - int matched_idx = p_svc ? nan_match_pmkid(p_svc, ndl->security_ctx.nd_pmkid, - ndl->peer_nmi, ndl->peer_ndi) : -1; - if (matched_idx >= 0) { - ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED; - ndl->security_ctx.csid_bitmap = p_svc->derived_security[matched_idx].csid_bitmap; - memcpy(ndl->security_ctx.nd_pmk, - p_svc->derived_security[matched_idx].nd_pmk, - ESP_WIFI_NAN_NDP_PMK_LEN); - ESP_LOGD(TAG, "NDP Resp Key Desc: resolved PMK from cred slot %d", matched_idx); - } else if (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) { - NAN_DATA_UNLOCK(); - ESP_LOGW(TAG, "NDP Resp Key Desc: NDL not encrypted; send NDP Response without Shared Key Descriptor"); - return 0; - } else { - NAN_DATA_UNLOCK(); - ESP_LOGW(TAG, "NDP Resp Key Desc: no PMK for peer PMKID; ensure matching credential on both devices"); - return 0; - } - } else if (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) { - NAN_DATA_UNLOCK(); - ESP_LOGW(TAG, "NDP Resp Key Desc: NDL not encrypted; send NDP Response without Shared Key Descriptor"); - return 0; - } + if (!nan_ndp_resp_resolve_pmk(ndl, peer_nmi)) { + NAN_DATA_UNLOCK(); + ESP_LOGW(TAG, "NDP Resp Key Desc: no PMK for peer PMKID; ensure matching credential on both devices"); + return 0; } /* Generate SNonce and derive PTK if not yet done */ 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 8040f4c297c..909183f78c5 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -341,7 +341,7 @@ 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); uint8_t esp_wifi_ap_get_owe_config_internal(void); -esp_err_t esp_nan_complete_pairing(uint8_t svc_id); +esp_err_t esp_nan_complete_pairing(uint8_t svc_id, uint8_t peer_svc_id); esp_err_t esp_wifi_nan_load_saved_creds(uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN], bool *own_nik_valid, wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds); esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]);