Extend RESEND_* test commands to allow forcing plaintext TX
This allows hostapd testing functionality to be forced to send out a plaintext EAPOL-Key frame with the RESEND_* command. That can be useful in seeing how the station behaves if an unencrypted EAPOL frame is received when TK is already configured. This is not really perfect since there is no convenient way of sending out a single unencrypted frame in the current nl80211 design. The monitor interface could likely still do this, but that's not really supposed to be used anymore. For now, clear and restore TK during this operation. The restore part is not really working correctly, though, since it ends up clearing the TSC value on the AP side and that shows up as replay protection issues on the station. Anyway, this is sufficient to generate sniffer captures to analyze station behavior. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
4be5bc98a8
commit
3d6953288b
4 changed files with 91 additions and 9 deletions
|
@ -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)
|
static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
|
||||||
{
|
{
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
u8 addr[ETH_ALEN];
|
u8 addr[ETH_ALEN];
|
||||||
|
int plain = os_strstr(cmd, "plaintext") != NULL;
|
||||||
|
|
||||||
if (hwaddr_aton(cmd, addr))
|
if (hwaddr_aton(cmd, addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2094,9 +2111,20 @@ static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
|
||||||
if (!sta || !sta->wpa_sm)
|
if (!sta || !sta->wpa_sm)
|
||||||
return -1;
|
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));
|
wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
|
||||||
return wpa_auth_resend_m1(sta->wpa_sm,
|
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;
|
struct sta_info *sta;
|
||||||
u8 addr[ETH_ALEN];
|
u8 addr[ETH_ALEN];
|
||||||
|
int plain = os_strstr(cmd, "plaintext") != NULL;
|
||||||
|
|
||||||
if (hwaddr_aton(cmd, addr))
|
if (hwaddr_aton(cmd, addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2112,8 +2141,19 @@ static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
|
||||||
if (!sta || !sta->wpa_sm)
|
if (!sta || !sta->wpa_sm)
|
||||||
return -1;
|
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));
|
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;
|
struct sta_info *sta;
|
||||||
u8 addr[ETH_ALEN];
|
u8 addr[ETH_ALEN];
|
||||||
|
int plain = os_strstr(cmd, "plaintext") != NULL;
|
||||||
|
|
||||||
if (hwaddr_aton(cmd, addr))
|
if (hwaddr_aton(cmd, addr))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2130,10 +2171,21 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
|
||||||
if (!sta || !sta->wpa_sm)
|
if (!sta || !sta->wpa_sm)
|
||||||
return -1;
|
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,
|
wpa_printf(MSG_INFO,
|
||||||
"TESTING: Send group M1 for the same GTK and zero RSC to "
|
"TESTING: Send group M1 for the same GTK and zero RSC to "
|
||||||
MACSTR, MAC2STR(sta->addr));
|
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 */
|
#endif /* CONFIG_TESTING_OPTIONS */
|
||||||
|
|
|
@ -4406,6 +4406,14 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||||
(timeout_ms % 1000) * 1000,
|
(timeout_ms % 1000) * 1000,
|
||||||
wpa_send_eapol_timeout, wpa_auth, sm);
|
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
|
#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;
|
const u8 *anonce = sm->ANonce;
|
||||||
u8 anonce_buf[WPA_NONCE_LEN];
|
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;
|
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, *opos;
|
||||||
size_t gtk_len, kde_len;
|
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];
|
u8 rsc[WPA_KEY_RSC_LEN];
|
||||||
struct wpa_group *gsm = sm->group;
|
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;
|
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_send_eapol(sm->wpa_auth, sm,
|
||||||
WPA_KEY_INFO_SECURE |
|
WPA_KEY_INFO_SECURE |
|
||||||
(wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
|
(wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
|
||||||
|
|
|
@ -428,8 +428,14 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
|
||||||
u8 *pos, size_t max_len,
|
u8 *pos, size_t max_len,
|
||||||
const u8 *req_ies, size_t req_ies_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_m1(struct wpa_state_machine *sm, int change_anonce,
|
||||||
int wpa_auth_resend_m3(struct wpa_state_machine *sm);
|
void (*cb)(void *ctx1, void *ctx2),
|
||||||
int wpa_auth_resend_group_m1(struct wpa_state_machine *sm);
|
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 */
|
#endif /* WPA_AUTH_H */
|
||||||
|
|
|
@ -143,6 +143,12 @@ struct wpa_state_machine {
|
||||||
size_t fils_key_auth_len;
|
size_t fils_key_auth_len;
|
||||||
unsigned int fils_completed:1;
|
unsigned int fils_completed:1;
|
||||||
#endif /* CONFIG_FILS */
|
#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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue