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 d6c19c99cee..44695c0010e 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 @@ -272,11 +272,28 @@ static void nan_app_clear_one_peer_tks(const uint8_t *peer_nmi) key_rsc, sizeof(key_rsc), NULL, 0, NAN_KEY_ND_GTK); + /* Drop the peer's RX IGTK/BIGTK (BIP-CMAC-128, installed against the + * peer NMI at NDP confirm) so no stale BIP keys linger in the blob. */ + if (ndl->igtk_set) { + esp_wifi_set_nan_key_internal(NAN_WIFI_WPA_ALG_BIP_CMAC_128, + (uint8_t *)peer_nmi, ndl->igtk_keyid, 0, + key_rsc, 6, + NULL, 0, NAN_KEY_ND_IGTK); + } + if (ndl->bigtk_set) { + esp_wifi_set_nan_key_internal(NAN_WIFI_WPA_ALG_BIP_CMAC_128, + (uint8_t *)peer_nmi, ndl->bigtk_keyid, 0, + key_rsc, 6, + NULL, 0, NAN_KEY_ND_BIGTK); + } + forced_memzero(ndl->nd_tk, sizeof(ndl->nd_tk)); forced_memzero(ndl->nd_kck, sizeof(ndl->nd_kck)); forced_memzero(ndl->nd_kek, sizeof(ndl->nd_kek)); forced_memzero(ndl->gtk, sizeof(ndl->gtk)); forced_memzero(ndl->own_gtk, sizeof(ndl->own_gtk)); + forced_memzero(ndl->igtk, sizeof(ndl->igtk)); + forced_memzero(ndl->bigtk, sizeof(ndl->bigtk)); ndl->ptk_set = 0; ndl->tk_len = 0; ndl->kck_len = 0; @@ -285,6 +302,10 @@ static void nan_app_clear_one_peer_tks(const uint8_t *peer_nmi) ndl->own_gtk_set = 0; ndl->gtk_len = 0; ndl->own_gtk_len = 0; + ndl->igtk_set = 0; + ndl->bigtk_set = 0; + ndl->igtk_len = 0; + ndl->bigtk_len = 0; } /* Fallback when no NDL slot tracks peer_ndi yet. */ @@ -1868,6 +1889,13 @@ void esp_nan_action_stop(void) nan_app_clear_paired_peers(); #endif +#ifdef CONFIG_ESP_WIFI_NAN_SECURITY + /* Drop the device-global IGTK/BIGTK so the next start regenerates fresh + * keys instead of re-installing a stale key with IPN/BIPN=0 (which would + * reset the blob's replay counter) — see nan_security_reset_own_group_keys. */ + nan_security_reset_own_group_keys(); +#endif + esp_nan_internal_register_callbacks(NULL); os_event_group_clear_bits(nan_event_group, NAN_STARTED_BIT); os_event_group_set_bits(nan_event_group, NAN_STOPPED_BIT); 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 69b4e997b08..f0e15d4658e 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 @@ -529,6 +529,12 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl, * Call once at NAN start; never per-NDP (would reset the blob's BIPN counter). */ void nan_security_install_own_group_integrity_keys(void); +/* Clear the device-global IGTK/BIGTK state on NAN stop so the next NAN start + * regenerates fresh keys. Prevents re-installing a stale key with IPN/BIPN=0 + * (which resets the blob's monotonic replay counter) and key reuse if the NMI + * is re-randomized on restart. */ +void nan_security_reset_own_group_keys(void); + /* * Match subscriber discovery security to a publisher's params. * NCS-SK: Compare locally derived ND-PMKID (subscriber passphrase, publisher NMI) to 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 e0bbf67f5e3..694cae921a5 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 @@ -765,6 +765,19 @@ void nan_security_install_own_group_integrity_keys(void) } } +void nan_security_reset_own_group_keys(void) +{ + forced_memzero(s_nan_ctx.own_igtk, sizeof(s_nan_ctx.own_igtk)); + memset(s_nan_ctx.own_igtk_ipn, 0, sizeof(s_nan_ctx.own_igtk_ipn)); + s_nan_ctx.own_igtk_keyid = 0; + s_nan_ctx.own_igtk_set = false; + + forced_memzero(s_nan_ctx.own_bigtk, sizeof(s_nan_ctx.own_bigtk)); + memset(s_nan_ctx.own_bigtk_bipn, 0, sizeof(s_nan_ctx.own_bigtk_bipn)); + s_nan_ctx.own_bigtk_keyid = 0; + s_nan_ctx.own_bigtk_set = false; +} + /* NAN KDE header (802.11 Fig 12-34: DD len OUI(3) DataType(1)); mirrors hostap * nan_add_kde_hdr(). data_len excludes the DD/len/OUI/type bytes. */ static uint8_t *nan_kde_put_hdr(uint8_t *p, uint8_t data_type, uint8_t data_len) @@ -962,8 +975,10 @@ static int nan_append_own_group_kdes(struct ndl_info *ndl, uint8_t *key_desc, si key_desc[NAN_KEY_DESC_DATA_LEN_OFF] = (wrapped_len >> 8) & 0xFF; key_desc[NAN_KEY_DESC_DATA_LEN_OFF + 1] = wrapped_len & 0xFF; - /* Key RSC carries the GTK's RSC when a GTK KDE is present (§7.1.3.5). */ - memcpy(&key_desc[NAN_KEY_DESC_RSC_OFF], ndl->own_gtk_rsc, NAN_KEY_RSC_LEN); + /* Key RSC carries the GTK's RSC only when a GTK KDE is present (§7.1.3.5). */ + if (want_gtk) { + memcpy(&key_desc[NAN_KEY_DESC_RSC_OFF], ndl->own_gtk_rsc, NAN_KEY_RSC_LEN); + } ESP_LOGI(TAG, "Group Key Data wrapped: %u plain -> %u wrapped bytes, KDEs=[%s%s%s]", (unsigned)plain_len, (unsigned)wrapped_len,