Prevent reinstallation of an already in-use group key
Track the current GTK and IGTK that is in use and when receiving a (possibly retransmitted) Group Message 1 or WNM-Sleep Mode Response, do not install the given key if it is already in use. This prevents an attacker from trying to trick the client into resetting or lowering the sequence counter associated to the group key. Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
This commit is contained in:
parent
0e3bd7ac68
commit
cb5132bb35
3 changed files with 87 additions and 44 deletions
|
@ -221,6 +221,17 @@ struct wpa_ptk {
|
||||||
size_t tk_len;
|
size_t tk_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wpa_gtk {
|
||||||
|
u8 gtk[WPA_GTK_MAX_LEN];
|
||||||
|
size_t gtk_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
struct wpa_igtk {
|
||||||
|
u8 igtk[WPA_IGTK_MAX_LEN];
|
||||||
|
size_t igtk_len;
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
/* WPA IE version 1
|
/* WPA IE version 1
|
||||||
* 00-50-f2:1 (OUI:OUI type)
|
* 00-50-f2:1 (OUI:OUI type)
|
||||||
|
|
|
@ -802,6 +802,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
|
||||||
const u8 *_gtk = gd->gtk;
|
const u8 *_gtk = gd->gtk;
|
||||||
u8 gtk_buf[32];
|
u8 gtk_buf[32];
|
||||||
|
|
||||||
|
/* Detect possible key reinstallation */
|
||||||
|
if (sm->gtk.gtk_len == (size_t) gd->gtk_len &&
|
||||||
|
os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) {
|
||||||
|
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
|
||||||
|
"WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
|
||||||
|
gd->keyidx, gd->tx, gd->gtk_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
|
wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
|
||||||
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
|
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
|
||||||
"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
|
"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
|
||||||
|
@ -836,6 +845,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
|
||||||
}
|
}
|
||||||
os_memset(gtk_buf, 0, sizeof(gtk_buf));
|
os_memset(gtk_buf, 0, sizeof(gtk_buf));
|
||||||
|
|
||||||
|
sm->gtk.gtk_len = gd->gtk_len;
|
||||||
|
os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,27 +954,26 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ieee80211w_set_keys(struct wpa_sm *sm,
|
|
||||||
struct wpa_eapol_ie_parse *ie)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
|
static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
|
||||||
return 0;
|
const struct wpa_igtk_kde *igtk)
|
||||||
|
{
|
||||||
|
size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
|
||||||
|
u16 keyidx = WPA_GET_LE16(igtk->keyid);
|
||||||
|
|
||||||
if (ie->igtk) {
|
/* Detect possible key reinstallation */
|
||||||
size_t len;
|
if (sm->igtk.igtk_len == len &&
|
||||||
const struct wpa_igtk_kde *igtk;
|
os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) {
|
||||||
u16 keyidx;
|
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
|
||||||
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
|
"WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
|
||||||
if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
|
keyidx);
|
||||||
return -1;
|
return 0;
|
||||||
igtk = (const struct wpa_igtk_kde *) ie->igtk;
|
}
|
||||||
keyidx = WPA_GET_LE16(igtk->keyid);
|
|
||||||
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
|
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
|
||||||
"pn %02x%02x%02x%02x%02x%02x",
|
"WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
|
||||||
keyidx, MAC2STR(igtk->pn));
|
keyidx, MAC2STR(igtk->pn));
|
||||||
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
|
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
|
||||||
igtk->igtk, len);
|
|
||||||
if (keyidx > 4095) {
|
if (keyidx > 4095) {
|
||||||
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
|
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
|
||||||
"WPA: Invalid IGTK KeyID %d", keyidx);
|
"WPA: Invalid IGTK KeyID %d", keyidx);
|
||||||
|
@ -976,6 +987,33 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
|
||||||
"WPA: Failed to configure IGTK to the driver");
|
"WPA: Failed to configure IGTK to the driver");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sm->igtk.igtk_len = len;
|
||||||
|
os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
|
|
||||||
|
static int ieee80211w_set_keys(struct wpa_sm *sm,
|
||||||
|
struct wpa_eapol_ie_parse *ie)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ie->igtk) {
|
||||||
|
size_t len;
|
||||||
|
const struct wpa_igtk_kde *igtk;
|
||||||
|
|
||||||
|
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
|
||||||
|
if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
igtk = (const struct wpa_igtk_kde *) ie->igtk;
|
||||||
|
if (wpa_supplicant_install_igtk(sm, igtk) < 0)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2493,7 +2531,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
|
||||||
*/
|
*/
|
||||||
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
|
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
|
||||||
{
|
{
|
||||||
int clear_ptk = 1;
|
int clear_keys = 1;
|
||||||
|
|
||||||
if (sm == NULL)
|
if (sm == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -2519,7 +2557,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
|
||||||
/* Prepare for the next transition */
|
/* Prepare for the next transition */
|
||||||
wpa_ft_prepare_auth_request(sm, NULL);
|
wpa_ft_prepare_auth_request(sm, NULL);
|
||||||
|
|
||||||
clear_ptk = 0;
|
clear_keys = 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
#ifdef CONFIG_FILS
|
#ifdef CONFIG_FILS
|
||||||
|
@ -2529,11 +2567,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
|
||||||
* AUTHENTICATED state to get the EAPOL port Authorized.
|
* AUTHENTICATED state to get the EAPOL port Authorized.
|
||||||
*/
|
*/
|
||||||
wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
|
wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
|
||||||
clear_ptk = 0;
|
clear_keys = 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_FILS */
|
#endif /* CONFIG_FILS */
|
||||||
|
|
||||||
if (clear_ptk) {
|
if (clear_keys) {
|
||||||
/*
|
/*
|
||||||
* IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
|
* IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
|
||||||
* this is not part of a Fast BSS Transition.
|
* this is not part of a Fast BSS Transition.
|
||||||
|
@ -2543,6 +2581,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
|
||||||
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
|
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
|
||||||
sm->tptk_set = 0;
|
sm->tptk_set = 0;
|
||||||
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
|
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
|
||||||
|
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TDLS
|
#ifdef CONFIG_TDLS
|
||||||
|
@ -3119,6 +3161,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
|
||||||
os_memset(sm->pmk, 0, sizeof(sm->pmk));
|
os_memset(sm->pmk, 0, sizeof(sm->pmk));
|
||||||
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
|
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
|
||||||
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
|
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
|
||||||
|
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
#ifdef CONFIG_IEEE80211R
|
#ifdef CONFIG_IEEE80211R
|
||||||
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
|
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
|
||||||
os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
|
os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
|
||||||
|
@ -3191,29 +3237,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
|
||||||
os_memset(&gd, 0, sizeof(gd));
|
os_memset(&gd, 0, sizeof(gd));
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
|
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
|
||||||
struct wpa_igtk_kde igd;
|
const struct wpa_igtk_kde *igtk;
|
||||||
u16 keyidx;
|
|
||||||
|
|
||||||
os_memset(&igd, 0, sizeof(igd));
|
igtk = (const struct wpa_igtk_kde *) (buf + 2);
|
||||||
keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
|
if (wpa_supplicant_install_igtk(sm, igtk) < 0)
|
||||||
os_memcpy(igd.keyid, buf + 2, 2);
|
|
||||||
os_memcpy(igd.pn, buf + 4, 6);
|
|
||||||
|
|
||||||
keyidx = WPA_GET_LE16(igd.keyid);
|
|
||||||
os_memcpy(igd.igtk, buf + 10, keylen);
|
|
||||||
|
|
||||||
wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
|
|
||||||
igd.igtk, keylen);
|
|
||||||
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
|
|
||||||
broadcast_ether_addr,
|
|
||||||
keyidx, 0, igd.pn, sizeof(igd.pn),
|
|
||||||
igd.igtk, keylen) < 0) {
|
|
||||||
wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
|
|
||||||
"WNM mode");
|
|
||||||
os_memset(&igd, 0, sizeof(igd));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
os_memset(&igd, 0, sizeof(igd));
|
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
} else {
|
} else {
|
||||||
wpa_printf(MSG_DEBUG, "Unknown element id");
|
wpa_printf(MSG_DEBUG, "Unknown element id");
|
||||||
|
|
|
@ -31,6 +31,10 @@ struct wpa_sm {
|
||||||
u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||||
int rx_replay_counter_set;
|
int rx_replay_counter_set;
|
||||||
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
|
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
|
||||||
|
struct wpa_gtk gtk;
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
struct wpa_igtk igtk;
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
|
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue