123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
- Date: Wed, 12 Jul 2017 16:03:24 +0200
- Subject: [PATCH] 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>
- ---
- --- a/src/common/wpa_common.h
- +++ b/src/common/wpa_common.h
- @@ -207,6 +207,17 @@ struct wpa_ptk {
- 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
- * 00-50-f2:1 (OUI:OUI type)
- --- a/src/rsn_supp/wpa.c
- +++ b/src/rsn_supp/wpa.c
- @@ -785,6 +785,15 @@ static int wpa_supplicant_install_gtk(st
- const u8 *_gtk = gd->gtk;
- 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_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
- @@ -819,6 +828,9 @@ static int wpa_supplicant_install_gtk(st
- }
- 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;
- }
-
- @@ -925,6 +937,48 @@ static int wpa_supplicant_pairwise_gtk(s
- }
-
-
- +#ifdef CONFIG_IEEE80211W
- +static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
- + const struct wpa_igtk_kde *igtk)
- +{
- + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
- + u16 keyidx = WPA_GET_LE16(igtk->keyid);
- +
- + /* Detect possible key reinstallation */
- + if (sm->igtk.igtk_len == len &&
- + os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) {
- + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- + "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
- + keyidx);
- + return 0;
- + }
- +
- + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- + "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
- + keyidx, MAC2STR(igtk->pn));
- + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
- + if (keyidx > 4095) {
- + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- + "WPA: Invalid IGTK KeyID %d", keyidx);
- + return -1;
- + }
- + if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
- + broadcast_ether_addr,
- + keyidx, 0, igtk->pn, sizeof(igtk->pn),
- + igtk->igtk, len) < 0) {
- + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- + "WPA: Failed to configure IGTK to the driver");
- + 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)
- {
- @@ -935,30 +989,14 @@ static int ieee80211w_set_keys(struct wp
- if (ie->igtk) {
- size_t len;
- const struct wpa_igtk_kde *igtk;
- - u16 keyidx;
- +
- 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;
- - keyidx = WPA_GET_LE16(igtk->keyid);
- - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
- - "pn %02x%02x%02x%02x%02x%02x",
- - keyidx, MAC2STR(igtk->pn));
- - wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
- - igtk->igtk, len);
- - if (keyidx > 4095) {
- - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- - "WPA: Invalid IGTK KeyID %d", keyidx);
- + if (wpa_supplicant_install_igtk(sm, igtk) < 0)
- return -1;
- - }
- - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
- - broadcast_ether_addr,
- - keyidx, 0, igtk->pn, sizeof(igtk->pn),
- - igtk->igtk, len) < 0) {
- - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- - "WPA: Failed to configure IGTK to the driver");
- - return -1;
- - }
- }
-
- return 0;
- @@ -2451,7 +2489,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
- */
- void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
- {
- - int clear_ptk = 1;
- + int clear_keys = 1;
-
- if (sm == NULL)
- return;
- @@ -2477,7 +2515,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *
- /* Prepare for the next transition */
- wpa_ft_prepare_auth_request(sm, NULL);
-
- - clear_ptk = 0;
- + clear_keys = 0;
- }
- #endif /* CONFIG_IEEE80211R */
- #ifdef CONFIG_FILS
- @@ -2487,11 +2525,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *
- * AUTHENTICATED state to get the EAPOL port Authorized.
- */
- wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
- - clear_ptk = 0;
- + clear_keys = 0;
- }
- #endif /* CONFIG_FILS */
-
- - if (clear_ptk) {
- + if (clear_keys) {
- /*
- * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
- * this is not part of a Fast BSS Transition.
- @@ -2501,6 +2539,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *
- os_memset(&sm->ptk, 0, sizeof(sm->ptk));
- sm->tptk_set = 0;
- 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
- @@ -3052,6 +3094,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
- os_memset(sm->pmk, 0, sizeof(sm->pmk));
- os_memset(&sm->ptk, 0, sizeof(sm->ptk));
- 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
- os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
- os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
- @@ -3124,29 +3170,11 @@ int wpa_wnmsleep_install_key(struct wpa_
- os_memset(&gd, 0, sizeof(gd));
- #ifdef CONFIG_IEEE80211W
- } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
- - struct wpa_igtk_kde igd;
- - u16 keyidx;
- + const struct wpa_igtk_kde *igtk;
-
- - os_memset(&igd, 0, sizeof(igd));
- - keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
- - 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));
- + igtk = (const struct wpa_igtk_kde *) (buf + 2);
- + if (wpa_supplicant_install_igtk(sm, igtk) < 0)
- return -1;
- - }
- - os_memset(&igd, 0, sizeof(igd));
- #endif /* CONFIG_IEEE80211W */
- } else {
- wpa_printf(MSG_DEBUG, "Unknown element id");
- --- a/src/rsn_supp/wpa_i.h
- +++ b/src/rsn_supp/wpa_i.h
- @@ -31,6 +31,10 @@ struct wpa_sm {
- u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
- int rx_replay_counter_set;
- 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 */
-
|