Add testing functionality for resetting PN/IPN for configured keys
This can be used to test replay protection. The "RESET_PN" command in wpa_supplicant and "RESET_PN <addr>" command in hostapd resets the local counters to zero for the last configured key. For hostapd, the address parameter specifies which STA this operation is for or selects GTK ("ff:ff:ff:ff:ff:ff") or IGTK ("ff:ff:ff:ff:ff:ff IGTK"). This functionality is for testing purposes and included only in builds with CONFIG_TESTING_OPTIONS=y. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
b74f82a4f8
commit
16579769ff
8 changed files with 184 additions and 0 deletions
|
@ -1949,6 +1949,90 @@ static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
|
|||
#endif /* WPA_TRACE_BFD */
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 zero[WPA_TK_MAX_LEN];
|
||||
|
||||
os_memset(zero, 0, sizeof(zero));
|
||||
|
||||
if (hwaddr_aton(cmd, addr))
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
|
||||
if (hapd->last_igtk_alg == WPA_ALG_NONE)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_INFO, "TESTING: Reset IPN for IGTK");
|
||||
|
||||
/* First, use a zero key to avoid any possible duplicate key
|
||||
* avoidance in the driver. */
|
||||
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
|
||||
hapd->last_igtk_alg,
|
||||
broadcast_ether_addr,
|
||||
hapd->last_igtk_key_idx, 1, NULL, 0,
|
||||
zero, hapd->last_igtk_len) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set the previously configured key to reset its TSC */
|
||||
return hostapd_drv_set_key(hapd->conf->iface, hapd,
|
||||
hapd->last_igtk_alg,
|
||||
broadcast_ether_addr,
|
||||
hapd->last_igtk_key_idx, 1, NULL, 0,
|
||||
hapd->last_igtk,
|
||||
hapd->last_igtk_len);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
if (is_broadcast_ether_addr(addr)) {
|
||||
if (hapd->last_gtk_alg == WPA_ALG_NONE)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_INFO, "TESTING: Reset PN for GTK");
|
||||
|
||||
/* First, use a zero key to avoid any possible duplicate key
|
||||
* avoidance in the driver. */
|
||||
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
|
||||
hapd->last_gtk_alg,
|
||||
broadcast_ether_addr,
|
||||
hapd->last_gtk_key_idx, 1, NULL, 0,
|
||||
zero, hapd->last_gtk_len) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set the previously configured key to reset its TSC */
|
||||
return hostapd_drv_set_key(hapd->conf->iface, hapd,
|
||||
hapd->last_gtk_alg,
|
||||
broadcast_ether_addr,
|
||||
hapd->last_gtk_key_idx, 1, NULL, 0,
|
||||
hapd->last_gtk, hapd->last_gtk_len);
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
if (sta->last_tk_alg == WPA_ALG_NONE)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_INFO, "TESTING: Reset PN for " MACSTR,
|
||||
MAC2STR(sta->addr));
|
||||
|
||||
/* First, use a zero key to avoid any possible duplicate key avoidance
|
||||
* in the driver. */
|
||||
if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
|
||||
sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
|
||||
zero, sta->last_tk_len) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set the previously configured key to reset its TSC/RSC */
|
||||
return 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);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
|
||||
|
@ -2665,6 +2749,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
|||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "GET_FAIL") == 0) {
|
||||
reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
|
||||
} else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
|
||||
if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 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))
|
||||
|
|
|
@ -304,6 +304,18 @@ struct hostapd_data {
|
|||
unsigned int ext_eapol_frame_io:1;
|
||||
|
||||
struct l2_packet_data *l2_test;
|
||||
|
||||
enum wpa_alg last_gtk_alg;
|
||||
int last_gtk_key_idx;
|
||||
u8 last_gtk[WPA_GTK_MAX_LEN];
|
||||
size_t last_gtk_len;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
enum wpa_alg last_igtk_alg;
|
||||
int last_igtk_key_idx;
|
||||
u8 last_igtk[WPA_IGTK_MAX_LEN];
|
||||
size_t last_igtk_len;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
|
|
|
@ -250,6 +250,13 @@ struct sta_info {
|
|||
struct crypto_ecdh *owe_ecdh;
|
||||
u16 owe_group;
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
enum wpa_alg last_tk_alg;
|
||||
int last_tk_key_idx;
|
||||
u8 last_tk[WPA_TK_MAX_LEN];
|
||||
size_t last_tk_len;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -349,6 +349,37 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (addr && !is_broadcast_ether_addr(addr)) {
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta) {
|
||||
sta->last_tk_alg = alg;
|
||||
sta->last_tk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(sta->last_tk, key, key_len);
|
||||
sta->last_tk_len = key_len;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
} else if (alg == WPA_CIPHER_AES_128_CMAC ||
|
||||
alg == WPA_CIPHER_BIP_GMAC_128 ||
|
||||
alg == WPA_CIPHER_BIP_GMAC_256 ||
|
||||
alg == WPA_CIPHER_BIP_CMAC_256) {
|
||||
hapd->last_igtk_alg = alg;
|
||||
hapd->last_igtk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(hapd->last_igtk, key, key_len);
|
||||
hapd->last_igtk_len = key_len;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
} else {
|
||||
hapd->last_gtk_alg = alg;
|
||||
hapd->last_gtk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(hapd->last_gtk, key, key_len);
|
||||
hapd->last_gtk_len = key_len;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
|
||||
key, key_len);
|
||||
}
|
||||
|
|
|
@ -8907,6 +8907,30 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
u8 zero[WPA_TK_MAX_LEN];
|
||||
|
||||
if (wpa_s->last_tk_alg == WPA_ALG_NONE)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_INFO, "TESTING: Reset PN");
|
||||
os_memset(zero, 0, sizeof(zero));
|
||||
|
||||
/* First, use a zero key to avoid any possible duplicate key avoidance
|
||||
* in the driver. */
|
||||
if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
|
||||
wpa_s->last_tk_key_idx, 1, zero, 6,
|
||||
zero, wpa_s->last_tk_len) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set the previously configured key to reset its TSC/RSC */
|
||||
return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
|
||||
wpa_s->last_tk_key_idx, 1, zero, 6,
|
||||
wpa_s->last_tk, wpa_s->last_tk_len);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
|
||||
|
@ -10278,6 +10302,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
|||
} else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
|
||||
if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "RESET_PN") == 0) {
|
||||
if (wpas_ctrl_reset_pn(wpa_s) < 0)
|
||||
reply_len = -1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
|
||||
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
|
||||
|
|
|
@ -314,6 +314,11 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
|
|||
|
||||
wpas_rrm_reset(wpa_s);
|
||||
wpa_s->wnmsleep_used = 0;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wpa_s->last_tk_alg = WPA_ALG_NONE;
|
||||
os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1077,6 +1077,11 @@ struct wpa_supplicant {
|
|||
unsigned int ignore_auth_resp:1;
|
||||
unsigned int ignore_assoc_disallow:1;
|
||||
struct wpabuf *sae_commit_override;
|
||||
enum wpa_alg last_tk_alg;
|
||||
u8 last_tk_addr[ETH_ALEN];
|
||||
int last_tk_key_idx;
|
||||
u8 last_tk[WPA_TK_MAX_LEN];
|
||||
size_t last_tk_len;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
|
||||
|
|
|
@ -502,6 +502,16 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
|
|||
wpa_s->last_gtk_len = key_len;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_GET_GTK */
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (addr && !is_broadcast_ether_addr(addr)) {
|
||||
wpa_s->last_tk_alg = alg;
|
||||
os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
|
||||
wpa_s->last_tk_key_idx = key_idx;
|
||||
if (key)
|
||||
os_memcpy(wpa_s->last_tk, key, key_len);
|
||||
wpa_s->last_tk_len = key_len;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
|
||||
key, key_len);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue