diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 12978f79f..247de0a1f 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2033,6 +2033,26 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd) sta->last_tk, sta->last_tk_len); } + +static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd, + const char *cmd) +{ + struct sta_info *sta; + u8 addr[ETH_ALEN]; + + if (hwaddr_aton(cmd, addr)) + return -1; + + sta = ap_get_sta(hapd, addr); + if (!sta || !sta->wpa_sm) + return -1; + + wpa_printf(MSG_INFO, + "TESTING: Send group M1 for the same GTK and zero RSC to " + MACSTR, MAC2STR(sta->addr)); + return wpa_auth_resend_group_m1(sta->wpa_sm); +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -2752,6 +2772,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) { if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0) reply_len = -1; + } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) { + if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index a4b8c8c77..163207276 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -4501,3 +4501,58 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm, } #endif /* CONFIG_FILS */ + + +#if CONFIG_TESTING_OPTIONS +int wpa_auth_resend_group_m1(struct wpa_state_machine *sm) +{ + u8 rsc[WPA_KEY_RSC_LEN]; + struct wpa_group *gsm = sm->group; + const u8 *kde; + u8 *kde_buf = NULL, *pos, *opos, hdr[2]; + size_t kde_len; + u8 *gtk; + + /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ + os_memset(rsc, 0, WPA_KEY_RSC_LEN); + /* Use 0 RSC */ + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "sending 1/2 msg of Group Key Handshake (TESTING)"); + + gtk = gsm->GTK[gsm->GN - 1]; + if (sm->wpa == WPA_VERSION_WPA2) { + kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + + ieee80211w_kde_len(sm); + kde_buf = os_malloc(kde_len); + if (kde_buf == NULL) + return -1; + + kde = pos = kde_buf; + hdr[0] = gsm->GN & 0x03; + hdr[1] = 0; + pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, + gtk, gsm->GTK_len); + opos = pos; + pos = ieee80211w_kde_add(sm, pos); + if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) { + opos += 2; /* skip keyid */ + os_memset(opos, 0, 6); /* clear PN */ + } + kde_len = pos - kde; + } else { + kde = gtk; + kde_len = gsm->GTK_len; + } + + wpa_send_eapol(sm->wpa_auth, sm, + WPA_KEY_INFO_SECURE | + (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? + WPA_KEY_INFO_MIC : 0) | + WPA_KEY_INFO_ACK | + (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), + rsc, NULL, kde, kde_len, gsm->GN, 1); + + os_free(kde_buf); + return 0; +} +#endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 902d377d3..ea91eda5b 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -427,4 +427,6 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm, u8 *pos, size_t max_len, const u8 *req_ies, size_t req_ies_len); +int wpa_auth_resend_group_m1(struct wpa_state_machine *sm); + #endif /* WPA_AUTH_H */