diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 8e6b5371a..b3ef8d34a 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2082,10 +2082,27 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd) } +static void restore_tk(void *ctx1, void *ctx2) +{ + struct hostapd_data *hapd = ctx1; + struct sta_info *sta = ctx2; + + wpa_printf(MSG_INFO, "TESTING: Restore TK for " MACSTR, + MAC2STR(sta->addr)); + /* This does not really restore the TSC properly, so this will result + * in replay protection issues for now since there is no clean way of + * preventing encryption of a single EAPOL frame. */ + hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg, + sta->addr, sta->last_tk_key_idx, 1, NULL, 0, + sta->last_tk, sta->last_tk_len); +} + + static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd) { struct sta_info *sta; u8 addr[ETH_ALEN]; + int plain = os_strstr(cmd, "plaintext") != NULL; if (hwaddr_aton(cmd, addr)) return -1; @@ -2094,9 +2111,20 @@ static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd) if (!sta || !sta->wpa_sm) return -1; + if (plain && sta->last_tk_alg == WPA_ALG_NONE) + plain = 0; /* no need for special processing */ + if (plain) { + wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR, + MAC2STR(sta->addr)); + hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE, + sta->addr, sta->last_tk_key_idx, 0, NULL, 0, + NULL, 0); + } + wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr)); return wpa_auth_resend_m1(sta->wpa_sm, - os_strstr(cmd, "change-anonce") != NULL); + os_strstr(cmd, "change-anonce") != NULL, + plain ? restore_tk : NULL, hapd, sta); } @@ -2104,6 +2132,7 @@ static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd) { struct sta_info *sta; u8 addr[ETH_ALEN]; + int plain = os_strstr(cmd, "plaintext") != NULL; if (hwaddr_aton(cmd, addr)) return -1; @@ -2112,8 +2141,19 @@ static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd) if (!sta || !sta->wpa_sm) return -1; + if (plain && sta->last_tk_alg == WPA_ALG_NONE) + plain = 0; /* no need for special processing */ + if (plain) { + wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR, + MAC2STR(sta->addr)); + hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE, + sta->addr, sta->last_tk_key_idx, 0, NULL, 0, + NULL, 0); + } + wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr)); - return wpa_auth_resend_m3(sta->wpa_sm); + return wpa_auth_resend_m3(sta->wpa_sm, + plain ? restore_tk : NULL, hapd, sta); } @@ -2122,6 +2162,7 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd, { struct sta_info *sta; u8 addr[ETH_ALEN]; + int plain = os_strstr(cmd, "plaintext") != NULL; if (hwaddr_aton(cmd, addr)) return -1; @@ -2130,10 +2171,21 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd, if (!sta || !sta->wpa_sm) return -1; + if (plain && sta->last_tk_alg == WPA_ALG_NONE) + plain = 0; /* no need for special processing */ + if (plain) { + wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR, + MAC2STR(sta->addr)); + hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE, + sta->addr, sta->last_tk_key_idx, 0, NULL, 0, + NULL, 0); + } + 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); + return wpa_auth_resend_group_m1(sta->wpa_sm, + plain ? restore_tk : NULL, hapd, sta); } #endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index aea29b5ea..8265fa1ca 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -4406,6 +4406,14 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, (timeout_ms % 1000) * 1000, wpa_send_eapol_timeout, wpa_auth, sm); } + +#ifdef CONFIG_TESTING_OPTIONS + if (sm->eapol_status_cb) { + sm->eapol_status_cb(sm->eapol_status_cb_ctx1, + sm->eapol_status_cb_ctx2); + sm->eapol_status_cb = NULL; + } +#endif /* CONFIG_TESTING_OPTIONS */ } @@ -4523,7 +4531,9 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm, #if CONFIG_TESTING_OPTIONS -int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce) +int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2) { const u8 *anonce = sm->ANonce; u8 anonce_buf[WPA_NONCE_LEN]; @@ -4543,7 +4553,9 @@ int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce) } -int wpa_auth_resend_m3(struct wpa_state_machine *sm) +int wpa_auth_resend_m3(struct wpa_state_machine *sm, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2) { u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, *opos; size_t gtk_len, kde_len; @@ -4703,7 +4715,9 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm) } -int wpa_auth_resend_group_m1(struct wpa_state_machine *sm) +int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2) { u8 rsc[WPA_KEY_RSC_LEN]; struct wpa_group *gsm = sm->group; @@ -4743,6 +4757,10 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm) kde_len = gsm->GTK_len; } + sm->eapol_status_cb = cb; + sm->eapol_status_cb_ctx1 = ctx1; + sm->eapol_status_cb_ctx2 = ctx2; + wpa_send_eapol(sm->wpa_auth, sm, WPA_KEY_INFO_SECURE | (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index be1a1822c..22f33dd14 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -428,8 +428,14 @@ 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_m1(struct wpa_state_machine *sm, int change_anonce); -int wpa_auth_resend_m3(struct wpa_state_machine *sm); -int wpa_auth_resend_group_m1(struct wpa_state_machine *sm); +int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2); +int wpa_auth_resend_m3(struct wpa_state_machine *sm, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2); +int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, + void (*cb)(void *ctx1, void *ctx2), + void *ctx1, void *ctx2); #endif /* WPA_AUTH_H */ diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index a9fce6c98..befa8007f 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -143,6 +143,12 @@ struct wpa_state_machine { size_t fils_key_auth_len; unsigned int fils_completed:1; #endif /* CONFIG_FILS */ + +#ifdef CONFIG_TESTING_OPTIONS + void (*eapol_status_cb)(void *ctx1, void *ctx2); + void *eapol_status_cb_ctx1; + void *eapol_status_cb_ctx2; +#endif /* CONFIG_TESTING_OPTIONS */ };