276 lines
9.3 KiB
Diff
276 lines
9.3 KiB
Diff
|
These three patches are follow-ups to the bug fixes for the 'KRACK' key
|
||
|
re-installation attacks on Wi-Fi's WPA2 security protocol. See upstream
|
||
|
security announcement for more information:
|
||
|
|
||
|
https://w1.fi/security/2017-1/wpa-packet-number-reuse-with-replayed-messages.txt
|
||
|
|
||
|
These three patches copied from upstream:
|
||
|
|
||
|
https://w1.fi/security/2017-1/rebased-v2.6-0006-TDLS-Reject-TPK-TK-reconfiguration.patch
|
||
|
https://w1.fi/security/2017-1/rebased-v2.6-0007-WNM-Ignore-WNM-Sleep-Mode-Response-without-pending-r.patch
|
||
|
https://w1.fi/security/2017-1/rebased-v2.6-0008-FT-Do-not-allow-multiple-Reassociation-Response-fram.patch
|
||
|
|
||
|
From 6c4bed4f47d1960ec04981a9d50e5076aea5223d Mon Sep 17 00:00:00 2001
|
||
|
From: Jouni Malinen <j@w1.fi>
|
||
|
Date: Fri, 22 Sep 2017 11:03:15 +0300
|
||
|
Subject: [PATCH 6/8] TDLS: Reject TPK-TK reconfiguration
|
||
|
|
||
|
Do not try to reconfigure the same TPK-TK to the driver after it has
|
||
|
been successfully configured. This is an explicit check to avoid issues
|
||
|
related to resetting the TX/RX packet number. There was already a check
|
||
|
for this for TPK M2 (retries of that message are ignored completely), so
|
||
|
that behavior does not get modified.
|
||
|
|
||
|
For TPK M3, the TPK-TK could have been reconfigured, but that was
|
||
|
followed by immediate teardown of the link due to an issue in updating
|
||
|
the STA entry. Furthermore, for TDLS with any real security (i.e.,
|
||
|
ignoring open/WEP), the TPK message exchange is protected on the AP path
|
||
|
and simple replay attacks are not feasible.
|
||
|
|
||
|
As an additional corner case, make sure the local nonce gets updated if
|
||
|
the peer uses a very unlikely "random nonce" of all zeros.
|
||
|
|
||
|
Signed-off-by: Jouni Malinen <j@w1.fi>
|
||
|
---
|
||
|
src/rsn_supp/tdls.c | 38 ++++++++++++++++++++++++++++++++++++--
|
||
|
1 file changed, 36 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
|
||
|
index e424168..9eb9738 100644
|
||
|
--- a/src/rsn_supp/tdls.c
|
||
|
+++ b/src/rsn_supp/tdls.c
|
||
|
@@ -112,6 +112,7 @@ struct wpa_tdls_peer {
|
||
|
u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
|
||
|
} tpk;
|
||
|
int tpk_set;
|
||
|
+ int tk_set; /* TPK-TK configured to the driver */
|
||
|
int tpk_success;
|
||
|
int tpk_in_progress;
|
||
|
|
||
|
@@ -192,6 +193,20 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
|
||
|
u8 rsc[6];
|
||
|
enum wpa_alg alg;
|
||
|
|
||
|
+ if (peer->tk_set) {
|
||
|
+ /*
|
||
|
+ * This same TPK-TK has already been configured to the driver
|
||
|
+ * and this new configuration attempt (likely due to an
|
||
|
+ * unexpected retransmitted frame) would result in clearing
|
||
|
+ * the TX/RX sequence number which can break security, so must
|
||
|
+ * not allow that to happen.
|
||
|
+ */
|
||
|
+ wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR
|
||
|
+ " has already been configured to the driver - do not reconfigure",
|
||
|
+ MAC2STR(peer->addr));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
os_memset(rsc, 0, 6);
|
||
|
|
||
|
switch (peer->cipher) {
|
||
|
@@ -209,12 +224,15 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
+ wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
|
||
|
+ MAC2STR(peer->addr));
|
||
|
if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
|
||
|
rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
|
||
|
wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
|
||
|
"driver");
|
||
|
return -1;
|
||
|
}
|
||
|
+ peer->tk_set = 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -696,7 +714,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
|
||
|
peer->cipher = 0;
|
||
|
peer->qos_info = 0;
|
||
|
peer->wmm_capable = 0;
|
||
|
- peer->tpk_set = peer->tpk_success = 0;
|
||
|
+ peer->tk_set = peer->tpk_set = peer->tpk_success = 0;
|
||
|
peer->chan_switch_enabled = 0;
|
||
|
os_memset(&peer->tpk, 0, sizeof(peer->tpk));
|
||
|
os_memset(peer->inonce, 0, WPA_NONCE_LEN);
|
||
|
@@ -1159,6 +1177,7 @@ skip_rsnie:
|
||
|
wpa_tdls_peer_free(sm, peer);
|
||
|
return -1;
|
||
|
}
|
||
|
+ peer->tk_set = 0; /* A new nonce results in a new TK */
|
||
|
wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
|
||
|
peer->inonce, WPA_NONCE_LEN);
|
||
|
os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
|
||
|
@@ -1751,6 +1770,19 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
|
||
|
}
|
||
|
|
||
|
|
||
|
+static int tdls_nonce_set(const u8 *nonce)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < WPA_NONCE_LEN; i++) {
|
||
|
+ if (nonce[i])
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||
|
const u8 *buf, size_t len)
|
||
|
{
|
||
|
@@ -2004,7 +2036,8 @@ skip_rsn:
|
||
|
peer->rsnie_i_len = kde.rsn_ie_len;
|
||
|
peer->cipher = cipher;
|
||
|
|
||
|
- if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
|
||
|
+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0 ||
|
||
|
+ !tdls_nonce_set(peer->inonce)) {
|
||
|
/*
|
||
|
* There is no point in updating the RNonce for every obtained
|
||
|
* TPK M1 frame (e.g., retransmission due to timeout) with the
|
||
|
@@ -2020,6 +2053,7 @@ skip_rsn:
|
||
|
"TDLS: Failed to get random data for responder nonce");
|
||
|
goto error;
|
||
|
}
|
||
|
+ peer->tk_set = 0; /* A new nonce results in a new TK */
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
--
|
||
|
2.7.4
|
||
|
|
||
|
From 53c5eb58e95004f86e65ee9fbfccbc291b139057 Mon Sep 17 00:00:00 2001
|
||
|
From: Jouni Malinen <j@w1.fi>
|
||
|
Date: Fri, 22 Sep 2017 11:25:02 +0300
|
||
|
Subject: [PATCH 7/8] WNM: Ignore WNM-Sleep Mode Response without pending
|
||
|
request
|
||
|
|
||
|
Commit 03ed0a52393710be6bdae657d1b36efa146520e5 ('WNM: Ignore WNM-Sleep
|
||
|
Mode Response if WNM-Sleep Mode has not been used') started ignoring the
|
||
|
response when no WNM-Sleep Mode Request had been used during the
|
||
|
association. This can be made tighter by clearing the used flag when
|
||
|
successfully processing a response. This adds an additional layer of
|
||
|
protection against unexpected retransmissions of the response frame.
|
||
|
|
||
|
Signed-off-by: Jouni Malinen <j@w1.fi>
|
||
|
---
|
||
|
wpa_supplicant/wnm_sta.c | 4 +++-
|
||
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
|
||
|
index 1b3409c..67a07ff 100644
|
||
|
--- a/wpa_supplicant/wnm_sta.c
|
||
|
+++ b/wpa_supplicant/wnm_sta.c
|
||
|
@@ -260,7 +260,7 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
|
||
|
|
||
|
if (!wpa_s->wnmsleep_used) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
- "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
|
||
|
+ "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
@@ -299,6 +299,8 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+ wpa_s->wnmsleep_used = 0;
|
||
|
+
|
||
|
if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
|
||
|
wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
|
||
|
wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
|
||
|
--
|
||
|
2.7.4
|
||
|
|
||
|
https://w1.fi/security/2017-1/wpa-packet-number-reuse-with-replayed-messages.txt
|
||
|
|
||
|
Patch copied from upstream:
|
||
|
|
||
|
https://w1.fi/security/2017-1/rebased-v2.6-0008-FT-Do-not-allow-multiple-Reassociation-Response-fram.patch
|
||
|
|
||
|
From b372ab0b7daea719749194dc554b26e6367603f2 Mon Sep 17 00:00:00 2001
|
||
|
From: Jouni Malinen <j@w1.fi>
|
||
|
Date: Fri, 22 Sep 2017 12:06:37 +0300
|
||
|
Subject: [PATCH 8/8] FT: Do not allow multiple Reassociation Response frames
|
||
|
|
||
|
The driver is expected to not report a second association event without
|
||
|
the station having explicitly request a new association. As such, this
|
||
|
case should not be reachable. However, since reconfiguring the same
|
||
|
pairwise or group keys to the driver could result in nonce reuse issues,
|
||
|
be extra careful here and do an additional state check to avoid this
|
||
|
even if the local driver ends up somehow accepting an unexpected
|
||
|
Reassociation Response frame.
|
||
|
|
||
|
Signed-off-by: Jouni Malinen <j@w1.fi>
|
||
|
---
|
||
|
src/rsn_supp/wpa.c | 3 +++
|
||
|
src/rsn_supp/wpa_ft.c | 8 ++++++++
|
||
|
src/rsn_supp/wpa_i.h | 1 +
|
||
|
3 files changed, 12 insertions(+)
|
||
|
|
||
|
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
|
||
|
index 0550a41..2a53c6f 100644
|
||
|
--- a/src/rsn_supp/wpa.c
|
||
|
+++ b/src/rsn_supp/wpa.c
|
||
|
@@ -2440,6 +2440,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
|
||
|
#ifdef CONFIG_TDLS
|
||
|
wpa_tdls_disassoc(sm);
|
||
|
#endif /* CONFIG_TDLS */
|
||
|
+#ifdef CONFIG_IEEE80211R
|
||
|
+ sm->ft_reassoc_completed = 0;
|
||
|
+#endif /* CONFIG_IEEE80211R */
|
||
|
|
||
|
/* Keys are not needed in the WPA state machine anymore */
|
||
|
wpa_sm_drop_sa(sm);
|
||
|
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
|
||
|
index 205793e..d45bb45 100644
|
||
|
--- a/src/rsn_supp/wpa_ft.c
|
||
|
+++ b/src/rsn_supp/wpa_ft.c
|
||
|
@@ -153,6 +153,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
|
||
|
u16 capab;
|
||
|
|
||
|
sm->ft_completed = 0;
|
||
|
+ sm->ft_reassoc_completed = 0;
|
||
|
|
||
|
buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
|
||
|
2 + sm->r0kh_id_len + ric_ies_len + 100;
|
||
|
@@ -681,6 +682,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
+ if (sm->ft_reassoc_completed) {
|
||
|
+ wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
|
||
|
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
|
||
|
return -1;
|
||
|
@@ -781,6 +787,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
+ sm->ft_reassoc_completed = 1;
|
||
|
+
|
||
|
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
|
||
|
return -1;
|
||
|
|
||
|
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
|
||
|
index 41f371f..56f88dc 100644
|
||
|
--- a/src/rsn_supp/wpa_i.h
|
||
|
+++ b/src/rsn_supp/wpa_i.h
|
||
|
@@ -128,6 +128,7 @@ struct wpa_sm {
|
||
|
size_t r0kh_id_len;
|
||
|
u8 r1kh_id[FT_R1KH_ID_LEN];
|
||
|
int ft_completed;
|
||
|
+ int ft_reassoc_completed;
|
||
|
int over_the_ds_in_progress;
|
||
|
u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
|
||
|
int set_ptk_after_assoc;
|
||
|
--
|
||
|
2.7.4
|
||
|
|