Fix CVE-2017-{13078,13079,13080,13081,13087,13088}: https://w1.fi/security/2017-1/wpa-packet-number-reuse-with-replayed-messages.txt https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-13078 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-13079 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-13080 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-13081 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-13087 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-13088 These two patches are copied from upstream: https://w1.fi/security/2017-1/rebased-v2.6-0002-Prevent-reinstallation-of-an-already-in-use-group-ke.patch https://w1.fi/security/2017-1/rebased-v2.6-0003-Extend-protection-of-GTK-IGTK-reinstallation-of-WNM-.patch From 927f891007c402fefd1ff384645b3f07597c3ede Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Wed, 12 Jul 2017 16:03:24 +0200 Subject: [PATCH 2/8] 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 --- src/common/wpa_common.h | 11 +++++ src/rsn_supp/wpa.c | 116 ++++++++++++++++++++++++++++++------------------ src/rsn_supp/wpa_i.h | 4 ++ 3 files changed, 87 insertions(+), 44 deletions(-) diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index af1d0f0..d200285 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -217,6 +217,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) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 3c47879..95bd7be 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -714,6 +714,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, 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)", @@ -748,6 +757,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, } 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; } @@ -854,6 +866,48 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, } +#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) { @@ -864,30 +918,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, 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); - 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"); + if (wpa_supplicant_install_igtk(sm, igtk) < 0) return -1; - } } return 0; @@ -2307,7 +2345,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; @@ -2333,11 +2371,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) /* Prepare for the next transition */ wpa_ft_prepare_auth_request(sm, NULL); - clear_ptk = 0; + clear_keys = 0; } #endif /* CONFIG_IEEE80211R */ - 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. @@ -2347,6 +2385,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) 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 @@ -2877,6 +2919,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)); @@ -2949,29 +2995,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) os_memset(&gd, 0, sizeof(gd)); #ifdef CONFIG_IEEE80211W } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) { - struct wpa_igtk_kde igd; - u16 keyidx; - - 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)); + const struct wpa_igtk_kde *igtk; + + 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"); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index f653ba6..afc9e37 100644 --- 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 */ -- 2.7.4 From 8280294e74846ea342389a0cd17215050fa5afe8 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 1 Oct 2017 12:12:24 +0300 Subject: [PATCH 3/8] Extend protection of GTK/IGTK reinstallation of WNM-Sleep Mode cases This extends the protection to track last configured GTK/IGTK value separately from EAPOL-Key frames and WNM-Sleep Mode frames to cover a corner case where these two different mechanisms may get used when the GTK/IGTK has changed and tracking a single value is not sufficient to detect a possible key reconfiguration. Signed-off-by: Jouni Malinen --- src/rsn_supp/wpa.c | 53 +++++++++++++++++++++++++++++++++++++--------------- src/rsn_supp/wpa_i.h | 2 ++ 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 95bd7be..7a2c68d 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -709,14 +709,17 @@ struct wpa_gtk_data { static int wpa_supplicant_install_gtk(struct wpa_sm *sm, const struct wpa_gtk_data *gd, - const u8 *key_rsc) + const u8 *key_rsc, int wnm_sleep) { 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) { + if ((sm->gtk.gtk_len == (size_t) gd->gtk_len && + os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) || + (sm->gtk_wnm_sleep.gtk_len == (size_t) gd->gtk_len && + os_memcmp(sm->gtk_wnm_sleep.gtk, gd->gtk, + sm->gtk_wnm_sleep.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); @@ -757,8 +760,14 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, } 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); + if (wnm_sleep) { + sm->gtk_wnm_sleep.gtk_len = gd->gtk_len; + os_memcpy(sm->gtk_wnm_sleep.gtk, gd->gtk, + sm->gtk_wnm_sleep.gtk_len); + } else { + sm->gtk.gtk_len = gd->gtk_len; + os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len); + } return 0; } @@ -852,7 +861,7 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, gtk_len, gtk_len, &gd.key_rsc_len, &gd.alg) || - wpa_supplicant_install_gtk(sm, &gd, key_rsc))) { + wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Failed to install GTK"); os_memset(&gd, 0, sizeof(gd)); @@ -868,14 +877,18 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, #ifdef CONFIG_IEEE80211W static int wpa_supplicant_install_igtk(struct wpa_sm *sm, - const struct wpa_igtk_kde *igtk) + const struct wpa_igtk_kde *igtk, + int wnm_sleep) { 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) { + if ((sm->igtk.igtk_len == len && + os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) || + (sm->igtk_wnm_sleep.igtk_len == len && + os_memcmp(sm->igtk_wnm_sleep.igtk, igtk->igtk, + sm->igtk_wnm_sleep.igtk_len) == 0)) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)", keyidx); @@ -900,8 +913,14 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm, return -1; } - sm->igtk.igtk_len = len; - os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len); + if (wnm_sleep) { + sm->igtk_wnm_sleep.igtk_len = len; + os_memcpy(sm->igtk_wnm_sleep.igtk, igtk->igtk, + sm->igtk_wnm_sleep.igtk_len); + } else { + sm->igtk.igtk_len = len; + os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len); + } return 0; } @@ -924,7 +943,7 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, return -1; igtk = (const struct wpa_igtk_kde *) ie->igtk; - if (wpa_supplicant_install_igtk(sm, igtk) < 0) + if (wpa_supplicant_install_igtk(sm, igtk, 0) < 0) return -1; } @@ -1574,7 +1593,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc)) key_rsc = null_rsc; - if (wpa_supplicant_install_gtk(sm, &gd, key_rsc) || + if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) || wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0) goto failed; os_memset(&gd, 0, sizeof(gd)); @@ -2386,8 +2405,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) sm->tptk_set = 0; os_memset(&sm->tptk, 0, sizeof(sm->tptk)); os_memset(&sm->gtk, 0, sizeof(sm->gtk)); + os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep)); #ifdef CONFIG_IEEE80211W os_memset(&sm->igtk, 0, sizeof(sm->igtk)); + os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); #endif /* CONFIG_IEEE80211W */ } @@ -2920,8 +2941,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm) os_memset(&sm->ptk, 0, sizeof(sm->ptk)); os_memset(&sm->tptk, 0, sizeof(sm->tptk)); os_memset(&sm->gtk, 0, sizeof(sm->gtk)); + os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep)); #ifdef CONFIG_IEEE80211W os_memset(&sm->igtk, 0, sizeof(sm->igtk)); + os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); @@ -2986,7 +3009,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)", gd.gtk, gd.gtk_len); - if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) { + if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 1)) { os_memset(&gd, 0, sizeof(gd)); wpa_printf(MSG_DEBUG, "Failed to install the GTK in " "WNM mode"); @@ -2998,7 +3021,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) const struct wpa_igtk_kde *igtk; igtk = (const struct wpa_igtk_kde *) (buf + 2); - if (wpa_supplicant_install_igtk(sm, igtk) < 0) + if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0) return -1; #endif /* CONFIG_IEEE80211W */ } else { diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index afc9e37..9a54631 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -32,8 +32,10 @@ struct wpa_sm { int rx_replay_counter_set; u8 request_counter[WPA_REPLAY_COUNTER_LEN]; struct wpa_gtk gtk; + struct wpa_gtk gtk_wnm_sleep; #ifdef CONFIG_IEEE80211W struct wpa_igtk igtk; + struct wpa_igtk igtk_wnm_sleep; #endif /* CONFIG_IEEE80211W */ struct eapol_sm *eapol; /* EAPOL state machine from upper level code */ -- 2.7.4