summaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-connectivity/hostapd/hostapd/key-replay-cve-multiple.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-connectivity/hostapd/hostapd/key-replay-cve-multiple.patch')
-rw-r--r--meta-oe/recipes-connectivity/hostapd/hostapd/key-replay-cve-multiple.patch984
1 files changed, 0 insertions, 984 deletions
diff --git a/meta-oe/recipes-connectivity/hostapd/hostapd/key-replay-cve-multiple.patch b/meta-oe/recipes-connectivity/hostapd/hostapd/key-replay-cve-multiple.patch
deleted file mode 100644
index 694da8fb6..000000000
--- a/meta-oe/recipes-connectivity/hostapd/hostapd/key-replay-cve-multiple.patch
+++ /dev/null
@@ -1,984 +0,0 @@
1The WPA2 four-way handshake protocol is vulnerable to replay attacks which can
2result in unauthenticated clients gaining access to the network.
3
4Backport a number of patches from upstream to fix this.
5
6CVE: CVE-2017-13077
7CVE: CVE-2017-13078
8CVE: CVE-2017-13079
9CVE: CVE-2017-13080
10CVE: CVE-2017-13081
11CVE: CVE-2017-13082
12CVE: CVE-2017-13086
13CVE: CVE-2017-13087
14CVE: CVE-2017-13088
15
16Upstream-Status: Backport
17Signed-off-by: Ross Burton <ross.burton@intel.com>
18
19From cf4cab804c7afd5c45505528a8d16e46163243a2 Mon Sep 17 00:00:00 2001
20From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
21Date: Fri, 14 Jul 2017 15:15:35 +0200
22Subject: [PATCH 1/8] hostapd: Avoid key reinstallation in FT handshake
23
24Do not reinstall TK to the driver during Reassociation Response frame
25processing if the first attempt of setting the TK succeeded. This avoids
26issues related to clearing the TX/RX PN that could result in reusing
27same PN values for transmitted frames (e.g., due to CCM nonce reuse and
28also hitting replay protection on the receiver) and accepting replayed
29frames on RX side.
30
31This issue was introduced by the commit
320e84c25434e6a1f283c7b4e62e483729085b78d2 ('FT: Fix PTK configuration in
33authenticator') which allowed wpa_ft_install_ptk() to be called multiple
34times with the same PTK. While the second configuration attempt is
35needed with some drivers, it must be done only if the first attempt
36failed.
37
38Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
39---
40 src/ap/ieee802_11.c | 16 +++++++++++++---
41 src/ap/wpa_auth.c | 11 +++++++++++
42 src/ap/wpa_auth.h | 3 ++-
43 src/ap/wpa_auth_ft.c | 10 ++++++++++
44 src/ap/wpa_auth_i.h | 1 +
45 5 files changed, 37 insertions(+), 4 deletions(-)
46
47diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
48index 4e04169..333035f 100644
49--- a/src/ap/ieee802_11.c
50+++ b/src/ap/ieee802_11.c
51@@ -1841,6 +1841,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
52 {
53 struct ieee80211_ht_capabilities ht_cap;
54 struct ieee80211_vht_capabilities vht_cap;
55+ int set = 1;
56
57 /*
58 * Remove the STA entry to ensure the STA PS state gets cleared and
59@@ -1848,9 +1849,18 @@ static int add_associated_sta(struct hostapd_data *hapd,
60 * FT-over-the-DS, where a station re-associates back to the same AP but
61 * skips the authentication flow, or if working with a driver that
62 * does not support full AP client state.
63+ *
64+ * Skip this if the STA has already completed FT reassociation and the
65+ * TK has been configured since the TX/RX PN must not be reset to 0 for
66+ * the same key.
67 */
68- if (!sta->added_unassoc)
69+ if (!sta->added_unassoc &&
70+ (!(sta->flags & WLAN_STA_AUTHORIZED) ||
71+ !wpa_auth_sta_ft_tk_already_set(sta->wpa_sm))) {
72 hostapd_drv_sta_remove(hapd, sta->addr);
73+ wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
74+ set = 0;
75+ }
76
77 #ifdef CONFIG_IEEE80211N
78 if (sta->flags & WLAN_STA_HT)
79@@ -1873,11 +1883,11 @@ static int add_associated_sta(struct hostapd_data *hapd,
80 sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
81 sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
82 sta->vht_opmode, sta->p2p_ie ? 1 : 0,
83- sta->added_unassoc)) {
84+ set)) {
85 hostapd_logger(hapd, sta->addr,
86 HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
87 "Could not %s STA to kernel driver",
88- sta->added_unassoc ? "set" : "add");
89+ set ? "set" : "add");
90
91 if (sta->added_unassoc) {
92 hostapd_drv_sta_remove(hapd, sta->addr);
93diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
94index 3587086..707971d 100644
95--- a/src/ap/wpa_auth.c
96+++ b/src/ap/wpa_auth.c
97@@ -1745,6 +1745,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
98 #else /* CONFIG_IEEE80211R */
99 break;
100 #endif /* CONFIG_IEEE80211R */
101+ case WPA_DRV_STA_REMOVED:
102+ sm->tk_already_set = FALSE;
103+ return 0;
104 }
105
106 #ifdef CONFIG_IEEE80211R
107@@ -3250,6 +3253,14 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
108 }
109
110
111+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
112+{
113+ if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
114+ return 0;
115+ return sm->tk_already_set;
116+}
117+
118+
119 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
120 struct rsn_pmksa_cache_entry *entry)
121 {
122diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
123index 0de8d97..97461b0 100644
124--- a/src/ap/wpa_auth.h
125+++ b/src/ap/wpa_auth.h
126@@ -267,7 +267,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
127 u8 *data, size_t data_len);
128 enum wpa_event {
129 WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
130- WPA_REAUTH_EAPOL, WPA_ASSOC_FT
131+ WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED
132 };
133 void wpa_remove_ptk(struct wpa_state_machine *sm);
134 int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
135@@ -280,6 +280,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
136 int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
137 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
138 int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
139+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
140 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
141 struct rsn_pmksa_cache_entry *entry);
142 struct rsn_pmksa_cache_entry *
143diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
144index 42242a5..e63b99a 100644
145--- a/src/ap/wpa_auth_ft.c
146+++ b/src/ap/wpa_auth_ft.c
147@@ -780,6 +780,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
148 return;
149 }
150
151+ if (sm->tk_already_set) {
152+ /* Must avoid TK reconfiguration to prevent clearing of TX/RX
153+ * PN in the driver */
154+ wpa_printf(MSG_DEBUG,
155+ "FT: Do not re-install same PTK to the driver");
156+ return;
157+ }
158+
159 /* FIX: add STA entry to kernel/driver here? The set_key will fail
160 * most likely without this.. At the moment, STA entry is added only
161 * after association has been completed. This function will be called
162@@ -792,6 +800,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
163
164 /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
165 sm->pairwise_set = TRUE;
166+ sm->tk_already_set = TRUE;
167 }
168
169
170@@ -898,6 +907,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
171
172 sm->pairwise = pairwise;
173 sm->PTK_valid = TRUE;
174+ sm->tk_already_set = FALSE;
175 wpa_ft_install_ptk(sm);
176
177 buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
178diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
179index 72b7eb3..7fd8f05 100644
180--- a/src/ap/wpa_auth_i.h
181+++ b/src/ap/wpa_auth_i.h
182@@ -65,6 +65,7 @@ struct wpa_state_machine {
183 struct wpa_ptk PTK;
184 Boolean PTK_valid;
185 Boolean pairwise_set;
186+ Boolean tk_already_set;
187 int keycount;
188 Boolean Pair;
189 struct wpa_key_replay_counter {
190--
1912.7.4
192
193From 927f891007c402fefd1ff384645b3f07597c3ede Mon Sep 17 00:00:00 2001
194From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
195Date: Wed, 12 Jul 2017 16:03:24 +0200
196Subject: [PATCH 2/8] Prevent reinstallation of an already in-use group key
197
198Track the current GTK and IGTK that is in use and when receiving a
199(possibly retransmitted) Group Message 1 or WNM-Sleep Mode Response, do
200not install the given key if it is already in use. This prevents an
201attacker from trying to trick the client into resetting or lowering the
202sequence counter associated to the group key.
203
204Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
205---
206 src/common/wpa_common.h | 11 +++++
207 src/rsn_supp/wpa.c | 116 ++++++++++++++++++++++++++++++------------------
208 src/rsn_supp/wpa_i.h | 4 ++
209 3 files changed, 87 insertions(+), 44 deletions(-)
210
211diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
212index af1d0f0..d200285 100644
213--- a/src/common/wpa_common.h
214+++ b/src/common/wpa_common.h
215@@ -217,6 +217,17 @@ struct wpa_ptk {
216 size_t tk_len;
217 };
218
219+struct wpa_gtk {
220+ u8 gtk[WPA_GTK_MAX_LEN];
221+ size_t gtk_len;
222+};
223+
224+#ifdef CONFIG_IEEE80211W
225+struct wpa_igtk {
226+ u8 igtk[WPA_IGTK_MAX_LEN];
227+ size_t igtk_len;
228+};
229+#endif /* CONFIG_IEEE80211W */
230
231 /* WPA IE version 1
232 * 00-50-f2:1 (OUI:OUI type)
233diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
234index 3c47879..95bd7be 100644
235--- a/src/rsn_supp/wpa.c
236+++ b/src/rsn_supp/wpa.c
237@@ -714,6 +714,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
238 const u8 *_gtk = gd->gtk;
239 u8 gtk_buf[32];
240
241+ /* Detect possible key reinstallation */
242+ if (sm->gtk.gtk_len == (size_t) gd->gtk_len &&
243+ os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) {
244+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
245+ "WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
246+ gd->keyidx, gd->tx, gd->gtk_len);
247+ return 0;
248+ }
249+
250 wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
251 wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
252 "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
253@@ -748,6 +757,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
254 }
255 os_memset(gtk_buf, 0, sizeof(gtk_buf));
256
257+ sm->gtk.gtk_len = gd->gtk_len;
258+ os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
259+
260 return 0;
261 }
262
263@@ -854,6 +866,48 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
264 }
265
266
267+#ifdef CONFIG_IEEE80211W
268+static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
269+ const struct wpa_igtk_kde *igtk)
270+{
271+ size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
272+ u16 keyidx = WPA_GET_LE16(igtk->keyid);
273+
274+ /* Detect possible key reinstallation */
275+ if (sm->igtk.igtk_len == len &&
276+ os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) {
277+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
278+ "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
279+ keyidx);
280+ return 0;
281+ }
282+
283+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
284+ "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
285+ keyidx, MAC2STR(igtk->pn));
286+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
287+ if (keyidx > 4095) {
288+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
289+ "WPA: Invalid IGTK KeyID %d", keyidx);
290+ return -1;
291+ }
292+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
293+ broadcast_ether_addr,
294+ keyidx, 0, igtk->pn, sizeof(igtk->pn),
295+ igtk->igtk, len) < 0) {
296+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
297+ "WPA: Failed to configure IGTK to the driver");
298+ return -1;
299+ }
300+
301+ sm->igtk.igtk_len = len;
302+ os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
303+
304+ return 0;
305+}
306+#endif /* CONFIG_IEEE80211W */
307+
308+
309 static int ieee80211w_set_keys(struct wpa_sm *sm,
310 struct wpa_eapol_ie_parse *ie)
311 {
312@@ -864,30 +918,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
313 if (ie->igtk) {
314 size_t len;
315 const struct wpa_igtk_kde *igtk;
316- u16 keyidx;
317+
318 len = wpa_cipher_key_len(sm->mgmt_group_cipher);
319 if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
320 return -1;
321+
322 igtk = (const struct wpa_igtk_kde *) ie->igtk;
323- keyidx = WPA_GET_LE16(igtk->keyid);
324- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
325- "pn %02x%02x%02x%02x%02x%02x",
326- keyidx, MAC2STR(igtk->pn));
327- wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
328- igtk->igtk, len);
329- if (keyidx > 4095) {
330- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
331- "WPA: Invalid IGTK KeyID %d", keyidx);
332- return -1;
333- }
334- if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
335- broadcast_ether_addr,
336- keyidx, 0, igtk->pn, sizeof(igtk->pn),
337- igtk->igtk, len) < 0) {
338- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
339- "WPA: Failed to configure IGTK to the driver");
340+ if (wpa_supplicant_install_igtk(sm, igtk) < 0)
341 return -1;
342- }
343 }
344
345 return 0;
346@@ -2307,7 +2345,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
347 */
348 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
349 {
350- int clear_ptk = 1;
351+ int clear_keys = 1;
352
353 if (sm == NULL)
354 return;
355@@ -2333,11 +2371,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
356 /* Prepare for the next transition */
357 wpa_ft_prepare_auth_request(sm, NULL);
358
359- clear_ptk = 0;
360+ clear_keys = 0;
361 }
362 #endif /* CONFIG_IEEE80211R */
363
364- if (clear_ptk) {
365+ if (clear_keys) {
366 /*
367 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
368 * this is not part of a Fast BSS Transition.
369@@ -2347,6 +2385,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
370 os_memset(&sm->ptk, 0, sizeof(sm->ptk));
371 sm->tptk_set = 0;
372 os_memset(&sm->tptk, 0, sizeof(sm->tptk));
373+ os_memset(&sm->gtk, 0, sizeof(sm->gtk));
374+#ifdef CONFIG_IEEE80211W
375+ os_memset(&sm->igtk, 0, sizeof(sm->igtk));
376+#endif /* CONFIG_IEEE80211W */
377 }
378
379 #ifdef CONFIG_TDLS
380@@ -2877,6 +2919,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
381 os_memset(sm->pmk, 0, sizeof(sm->pmk));
382 os_memset(&sm->ptk, 0, sizeof(sm->ptk));
383 os_memset(&sm->tptk, 0, sizeof(sm->tptk));
384+ os_memset(&sm->gtk, 0, sizeof(sm->gtk));
385+#ifdef CONFIG_IEEE80211W
386+ os_memset(&sm->igtk, 0, sizeof(sm->igtk));
387+#endif /* CONFIG_IEEE80211W */
388 #ifdef CONFIG_IEEE80211R
389 os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
390 os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
391@@ -2949,29 +2995,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
392 os_memset(&gd, 0, sizeof(gd));
393 #ifdef CONFIG_IEEE80211W
394 } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
395- struct wpa_igtk_kde igd;
396- u16 keyidx;
397-
398- os_memset(&igd, 0, sizeof(igd));
399- keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
400- os_memcpy(igd.keyid, buf + 2, 2);
401- os_memcpy(igd.pn, buf + 4, 6);
402-
403- keyidx = WPA_GET_LE16(igd.keyid);
404- os_memcpy(igd.igtk, buf + 10, keylen);
405-
406- wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
407- igd.igtk, keylen);
408- if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
409- broadcast_ether_addr,
410- keyidx, 0, igd.pn, sizeof(igd.pn),
411- igd.igtk, keylen) < 0) {
412- wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
413- "WNM mode");
414- os_memset(&igd, 0, sizeof(igd));
415+ const struct wpa_igtk_kde *igtk;
416+
417+ igtk = (const struct wpa_igtk_kde *) (buf + 2);
418+ if (wpa_supplicant_install_igtk(sm, igtk) < 0)
419 return -1;
420- }
421- os_memset(&igd, 0, sizeof(igd));
422 #endif /* CONFIG_IEEE80211W */
423 } else {
424 wpa_printf(MSG_DEBUG, "Unknown element id");
425diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
426index f653ba6..afc9e37 100644
427--- a/src/rsn_supp/wpa_i.h
428+++ b/src/rsn_supp/wpa_i.h
429@@ -31,6 +31,10 @@ struct wpa_sm {
430 u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
431 int rx_replay_counter_set;
432 u8 request_counter[WPA_REPLAY_COUNTER_LEN];
433+ struct wpa_gtk gtk;
434+#ifdef CONFIG_IEEE80211W
435+ struct wpa_igtk igtk;
436+#endif /* CONFIG_IEEE80211W */
437
438 struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
439
440--
4412.7.4
442
443From 8280294e74846ea342389a0cd17215050fa5afe8 Mon Sep 17 00:00:00 2001
444From: Jouni Malinen <j@w1.fi>
445Date: Sun, 1 Oct 2017 12:12:24 +0300
446Subject: [PATCH 3/8] Extend protection of GTK/IGTK reinstallation of WNM-Sleep
447 Mode cases
448
449This extends the protection to track last configured GTK/IGTK value
450separately from EAPOL-Key frames and WNM-Sleep Mode frames to cover a
451corner case where these two different mechanisms may get used when the
452GTK/IGTK has changed and tracking a single value is not sufficient to
453detect a possible key reconfiguration.
454
455Signed-off-by: Jouni Malinen <j@w1.fi>
456---
457 src/rsn_supp/wpa.c | 53 +++++++++++++++++++++++++++++++++++++---------------
458 src/rsn_supp/wpa_i.h | 2 ++
459 2 files changed, 40 insertions(+), 15 deletions(-)
460
461diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
462index 95bd7be..7a2c68d 100644
463--- a/src/rsn_supp/wpa.c
464+++ b/src/rsn_supp/wpa.c
465@@ -709,14 +709,17 @@ struct wpa_gtk_data {
466
467 static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
468 const struct wpa_gtk_data *gd,
469- const u8 *key_rsc)
470+ const u8 *key_rsc, int wnm_sleep)
471 {
472 const u8 *_gtk = gd->gtk;
473 u8 gtk_buf[32];
474
475 /* Detect possible key reinstallation */
476- if (sm->gtk.gtk_len == (size_t) gd->gtk_len &&
477- os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) {
478+ if ((sm->gtk.gtk_len == (size_t) gd->gtk_len &&
479+ os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) ||
480+ (sm->gtk_wnm_sleep.gtk_len == (size_t) gd->gtk_len &&
481+ os_memcmp(sm->gtk_wnm_sleep.gtk, gd->gtk,
482+ sm->gtk_wnm_sleep.gtk_len) == 0)) {
483 wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
484 "WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
485 gd->keyidx, gd->tx, gd->gtk_len);
486@@ -757,8 +760,14 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
487 }
488 os_memset(gtk_buf, 0, sizeof(gtk_buf));
489
490- sm->gtk.gtk_len = gd->gtk_len;
491- os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
492+ if (wnm_sleep) {
493+ sm->gtk_wnm_sleep.gtk_len = gd->gtk_len;
494+ os_memcpy(sm->gtk_wnm_sleep.gtk, gd->gtk,
495+ sm->gtk_wnm_sleep.gtk_len);
496+ } else {
497+ sm->gtk.gtk_len = gd->gtk_len;
498+ os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
499+ }
500
501 return 0;
502 }
503@@ -852,7 +861,7 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
504 (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
505 gtk_len, gtk_len,
506 &gd.key_rsc_len, &gd.alg) ||
507- wpa_supplicant_install_gtk(sm, &gd, key_rsc))) {
508+ wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) {
509 wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
510 "RSN: Failed to install GTK");
511 os_memset(&gd, 0, sizeof(gd));
512@@ -868,14 +877,18 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
513
514 #ifdef CONFIG_IEEE80211W
515 static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
516- const struct wpa_igtk_kde *igtk)
517+ const struct wpa_igtk_kde *igtk,
518+ int wnm_sleep)
519 {
520 size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
521 u16 keyidx = WPA_GET_LE16(igtk->keyid);
522
523 /* Detect possible key reinstallation */
524- if (sm->igtk.igtk_len == len &&
525- os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) {
526+ if ((sm->igtk.igtk_len == len &&
527+ os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) ||
528+ (sm->igtk_wnm_sleep.igtk_len == len &&
529+ os_memcmp(sm->igtk_wnm_sleep.igtk, igtk->igtk,
530+ sm->igtk_wnm_sleep.igtk_len) == 0)) {
531 wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
532 "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
533 keyidx);
534@@ -900,8 +913,14 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
535 return -1;
536 }
537
538- sm->igtk.igtk_len = len;
539- os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
540+ if (wnm_sleep) {
541+ sm->igtk_wnm_sleep.igtk_len = len;
542+ os_memcpy(sm->igtk_wnm_sleep.igtk, igtk->igtk,
543+ sm->igtk_wnm_sleep.igtk_len);
544+ } else {
545+ sm->igtk.igtk_len = len;
546+ os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
547+ }
548
549 return 0;
550 }
551@@ -924,7 +943,7 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
552 return -1;
553
554 igtk = (const struct wpa_igtk_kde *) ie->igtk;
555- if (wpa_supplicant_install_igtk(sm, igtk) < 0)
556+ if (wpa_supplicant_install_igtk(sm, igtk, 0) < 0)
557 return -1;
558 }
559
560@@ -1574,7 +1593,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
561 if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
562 key_rsc = null_rsc;
563
564- if (wpa_supplicant_install_gtk(sm, &gd, key_rsc) ||
565+ if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) ||
566 wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
567 goto failed;
568 os_memset(&gd, 0, sizeof(gd));
569@@ -2386,8 +2405,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
570 sm->tptk_set = 0;
571 os_memset(&sm->tptk, 0, sizeof(sm->tptk));
572 os_memset(&sm->gtk, 0, sizeof(sm->gtk));
573+ os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
574 #ifdef CONFIG_IEEE80211W
575 os_memset(&sm->igtk, 0, sizeof(sm->igtk));
576+ os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
577 #endif /* CONFIG_IEEE80211W */
578 }
579
580@@ -2920,8 +2941,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
581 os_memset(&sm->ptk, 0, sizeof(sm->ptk));
582 os_memset(&sm->tptk, 0, sizeof(sm->tptk));
583 os_memset(&sm->gtk, 0, sizeof(sm->gtk));
584+ os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
585 #ifdef CONFIG_IEEE80211W
586 os_memset(&sm->igtk, 0, sizeof(sm->igtk));
587+ os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
588 #endif /* CONFIG_IEEE80211W */
589 #ifdef CONFIG_IEEE80211R
590 os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
591@@ -2986,7 +3009,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
592
593 wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
594 gd.gtk, gd.gtk_len);
595- if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
596+ if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 1)) {
597 os_memset(&gd, 0, sizeof(gd));
598 wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
599 "WNM mode");
600@@ -2998,7 +3021,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
601 const struct wpa_igtk_kde *igtk;
602
603 igtk = (const struct wpa_igtk_kde *) (buf + 2);
604- if (wpa_supplicant_install_igtk(sm, igtk) < 0)
605+ if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
606 return -1;
607 #endif /* CONFIG_IEEE80211W */
608 } else {
609diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
610index afc9e37..9a54631 100644
611--- a/src/rsn_supp/wpa_i.h
612+++ b/src/rsn_supp/wpa_i.h
613@@ -32,8 +32,10 @@ struct wpa_sm {
614 int rx_replay_counter_set;
615 u8 request_counter[WPA_REPLAY_COUNTER_LEN];
616 struct wpa_gtk gtk;
617+ struct wpa_gtk gtk_wnm_sleep;
618 #ifdef CONFIG_IEEE80211W
619 struct wpa_igtk igtk;
620+ struct wpa_igtk igtk_wnm_sleep;
621 #endif /* CONFIG_IEEE80211W */
622
623 struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
624--
6252.7.4
626
627From 8f82bc94e8697a9d47fa8774dfdaaede1084912c Mon Sep 17 00:00:00 2001
628From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
629Date: Fri, 29 Sep 2017 04:22:51 +0200
630Subject: [PATCH 4/8] Prevent installation of an all-zero TK
631
632Properly track whether a PTK has already been installed to the driver
633and the TK part cleared from memory. This prevents an attacker from
634trying to trick the client into installing an all-zero TK.
635
636This fixes the earlier fix in commit
637ad00d64e7d8827b3cebd665a0ceb08adabf15e1e ('Fix TK configuration to the
638driver in EAPOL-Key 3/4 retry case') which did not take into account
639possibility of an extra message 1/4 showing up between retries of
640message 3/4.
641
642Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
643---
644 src/common/wpa_common.h | 1 +
645 src/rsn_supp/wpa.c | 5 ++---
646 src/rsn_supp/wpa_i.h | 1 -
647 3 files changed, 3 insertions(+), 4 deletions(-)
648
649diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
650index d200285..1021ccb 100644
651--- a/src/common/wpa_common.h
652+++ b/src/common/wpa_common.h
653@@ -215,6 +215,7 @@ struct wpa_ptk {
654 size_t kck_len;
655 size_t kek_len;
656 size_t tk_len;
657+ int installed; /* 1 if key has already been installed to driver */
658 };
659
660 struct wpa_gtk {
661diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
662index 7a2c68d..0550a41 100644
663--- a/src/rsn_supp/wpa.c
664+++ b/src/rsn_supp/wpa.c
665@@ -510,7 +510,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
666 os_memset(buf, 0, sizeof(buf));
667 }
668 sm->tptk_set = 1;
669- sm->tk_to_set = 1;
670
671 kde = sm->assoc_wpa_ie;
672 kde_len = sm->assoc_wpa_ie_len;
673@@ -615,7 +614,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
674 enum wpa_alg alg;
675 const u8 *key_rsc;
676
677- if (!sm->tk_to_set) {
678+ if (sm->ptk.installed) {
679 wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
680 "WPA: Do not re-install same PTK to the driver");
681 return 0;
682@@ -659,7 +658,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
683
684 /* TK is not needed anymore in supplicant */
685 os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
686- sm->tk_to_set = 0;
687+ sm->ptk.installed = 1;
688
689 if (sm->wpa_ptk_rekey) {
690 eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
691diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
692index 9a54631..41f371f 100644
693--- a/src/rsn_supp/wpa_i.h
694+++ b/src/rsn_supp/wpa_i.h
695@@ -24,7 +24,6 @@ struct wpa_sm {
696 struct wpa_ptk ptk, tptk;
697 int ptk_set, tptk_set;
698 unsigned int msg_3_of_4_ok:1;
699- unsigned int tk_to_set:1;
700 u8 snonce[WPA_NONCE_LEN];
701 u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
702 int renew_snonce;
703--
7042.7.4
705
706From 12fac09b437a1dc8a0f253e265934a8aaf4d2f8b Mon Sep 17 00:00:00 2001
707From: Jouni Malinen <j@w1.fi>
708Date: Sun, 1 Oct 2017 12:32:57 +0300
709Subject: [PATCH 5/8] Fix PTK rekeying to generate a new ANonce
710
711The Authenticator state machine path for PTK rekeying ended up bypassing
712the AUTHENTICATION2 state where a new ANonce is generated when going
713directly to the PTKSTART state since there is no need to try to
714determine the PMK again in such a case. This is far from ideal since the
715new PTK would depend on a new nonce only from the supplicant.
716
717Fix this by generating a new ANonce when moving to the PTKSTART state
718for the purpose of starting new 4-way handshake to rekey PTK.
719
720Signed-off-by: Jouni Malinen <j@w1.fi>
721---
722 src/ap/wpa_auth.c | 24 +++++++++++++++++++++---
723 1 file changed, 21 insertions(+), 3 deletions(-)
724
725diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
726index 707971d..bf10cc1 100644
727--- a/src/ap/wpa_auth.c
728+++ b/src/ap/wpa_auth.c
729@@ -1901,6 +1901,21 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
730 }
731
732
733+static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
734+{
735+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
736+ wpa_printf(MSG_ERROR,
737+ "WPA: Failed to get random data for ANonce");
738+ sm->Disconnect = TRUE;
739+ return -1;
740+ }
741+ wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
742+ WPA_NONCE_LEN);
743+ sm->TimeoutCtr = 0;
744+ return 0;
745+}
746+
747+
748 SM_STATE(WPA_PTK, INITPMK)
749 {
750 u8 msk[2 * PMK_LEN];
751@@ -2458,9 +2473,12 @@ SM_STEP(WPA_PTK)
752 SM_ENTER(WPA_PTK, AUTHENTICATION);
753 else if (sm->ReAuthenticationRequest)
754 SM_ENTER(WPA_PTK, AUTHENTICATION2);
755- else if (sm->PTKRequest)
756- SM_ENTER(WPA_PTK, PTKSTART);
757- else switch (sm->wpa_ptk_state) {
758+ else if (sm->PTKRequest) {
759+ if (wpa_auth_sm_ptk_update(sm) < 0)
760+ SM_ENTER(WPA_PTK, DISCONNECTED);
761+ else
762+ SM_ENTER(WPA_PTK, PTKSTART);
763+ } else switch (sm->wpa_ptk_state) {
764 case WPA_PTK_INITIALIZE:
765 break;
766 case WPA_PTK_DISCONNECT:
767--
7682.7.4
769
770From 6c4bed4f47d1960ec04981a9d50e5076aea5223d Mon Sep 17 00:00:00 2001
771From: Jouni Malinen <j@w1.fi>
772Date: Fri, 22 Sep 2017 11:03:15 +0300
773Subject: [PATCH 6/8] TDLS: Reject TPK-TK reconfiguration
774
775Do not try to reconfigure the same TPK-TK to the driver after it has
776been successfully configured. This is an explicit check to avoid issues
777related to resetting the TX/RX packet number. There was already a check
778for this for TPK M2 (retries of that message are ignored completely), so
779that behavior does not get modified.
780
781For TPK M3, the TPK-TK could have been reconfigured, but that was
782followed by immediate teardown of the link due to an issue in updating
783the STA entry. Furthermore, for TDLS with any real security (i.e.,
784ignoring open/WEP), the TPK message exchange is protected on the AP path
785and simple replay attacks are not feasible.
786
787As an additional corner case, make sure the local nonce gets updated if
788the peer uses a very unlikely "random nonce" of all zeros.
789
790Signed-off-by: Jouni Malinen <j@w1.fi>
791---
792 src/rsn_supp/tdls.c | 38 ++++++++++++++++++++++++++++++++++++--
793 1 file changed, 36 insertions(+), 2 deletions(-)
794
795diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
796index e424168..9eb9738 100644
797--- a/src/rsn_supp/tdls.c
798+++ b/src/rsn_supp/tdls.c
799@@ -112,6 +112,7 @@ struct wpa_tdls_peer {
800 u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
801 } tpk;
802 int tpk_set;
803+ int tk_set; /* TPK-TK configured to the driver */
804 int tpk_success;
805 int tpk_in_progress;
806
807@@ -192,6 +193,20 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
808 u8 rsc[6];
809 enum wpa_alg alg;
810
811+ if (peer->tk_set) {
812+ /*
813+ * This same TPK-TK has already been configured to the driver
814+ * and this new configuration attempt (likely due to an
815+ * unexpected retransmitted frame) would result in clearing
816+ * the TX/RX sequence number which can break security, so must
817+ * not allow that to happen.
818+ */
819+ wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR
820+ " has already been configured to the driver - do not reconfigure",
821+ MAC2STR(peer->addr));
822+ return -1;
823+ }
824+
825 os_memset(rsc, 0, 6);
826
827 switch (peer->cipher) {
828@@ -209,12 +224,15 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
829 return -1;
830 }
831
832+ wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
833+ MAC2STR(peer->addr));
834 if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
835 rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
836 wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
837 "driver");
838 return -1;
839 }
840+ peer->tk_set = 1;
841 return 0;
842 }
843
844@@ -696,7 +714,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
845 peer->cipher = 0;
846 peer->qos_info = 0;
847 peer->wmm_capable = 0;
848- peer->tpk_set = peer->tpk_success = 0;
849+ peer->tk_set = peer->tpk_set = peer->tpk_success = 0;
850 peer->chan_switch_enabled = 0;
851 os_memset(&peer->tpk, 0, sizeof(peer->tpk));
852 os_memset(peer->inonce, 0, WPA_NONCE_LEN);
853@@ -1159,6 +1177,7 @@ skip_rsnie:
854 wpa_tdls_peer_free(sm, peer);
855 return -1;
856 }
857+ peer->tk_set = 0; /* A new nonce results in a new TK */
858 wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
859 peer->inonce, WPA_NONCE_LEN);
860 os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
861@@ -1751,6 +1770,19 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
862 }
863
864
865+static int tdls_nonce_set(const u8 *nonce)
866+{
867+ int i;
868+
869+ for (i = 0; i < WPA_NONCE_LEN; i++) {
870+ if (nonce[i])
871+ return 1;
872+ }
873+
874+ return 0;
875+}
876+
877+
878 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
879 const u8 *buf, size_t len)
880 {
881@@ -2004,7 +2036,8 @@ skip_rsn:
882 peer->rsnie_i_len = kde.rsn_ie_len;
883 peer->cipher = cipher;
884
885- if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
886+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0 ||
887+ !tdls_nonce_set(peer->inonce)) {
888 /*
889 * There is no point in updating the RNonce for every obtained
890 * TPK M1 frame (e.g., retransmission due to timeout) with the
891@@ -2020,6 +2053,7 @@ skip_rsn:
892 "TDLS: Failed to get random data for responder nonce");
893 goto error;
894 }
895+ peer->tk_set = 0; /* A new nonce results in a new TK */
896 }
897
898 #if 0
899--
9002.7.4
901
902Note: [PATCH 7/8] only applies to wpa_supplicant
903
904From b372ab0b7daea719749194dc554b26e6367603f2 Mon Sep 17 00:00:00 2001
905From: Jouni Malinen <j@w1.fi>
906Date: Fri, 22 Sep 2017 12:06:37 +0300
907Subject: [PATCH 8/8] FT: Do not allow multiple Reassociation Response frames
908
909The driver is expected to not report a second association event without
910the station having explicitly request a new association. As such, this
911case should not be reachable. However, since reconfiguring the same
912pairwise or group keys to the driver could result in nonce reuse issues,
913be extra careful here and do an additional state check to avoid this
914even if the local driver ends up somehow accepting an unexpected
915Reassociation Response frame.
916
917Signed-off-by: Jouni Malinen <j@w1.fi>
918---
919 src/rsn_supp/wpa.c | 3 +++
920 src/rsn_supp/wpa_ft.c | 8 ++++++++
921 src/rsn_supp/wpa_i.h | 1 +
922 3 files changed, 12 insertions(+)
923
924diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
925index 0550a41..2a53c6f 100644
926--- a/src/rsn_supp/wpa.c
927+++ b/src/rsn_supp/wpa.c
928@@ -2440,6 +2440,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
929 #ifdef CONFIG_TDLS
930 wpa_tdls_disassoc(sm);
931 #endif /* CONFIG_TDLS */
932+#ifdef CONFIG_IEEE80211R
933+ sm->ft_reassoc_completed = 0;
934+#endif /* CONFIG_IEEE80211R */
935
936 /* Keys are not needed in the WPA state machine anymore */
937 wpa_sm_drop_sa(sm);
938diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
939index 205793e..d45bb45 100644
940--- a/src/rsn_supp/wpa_ft.c
941+++ b/src/rsn_supp/wpa_ft.c
942@@ -153,6 +153,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
943 u16 capab;
944
945 sm->ft_completed = 0;
946+ sm->ft_reassoc_completed = 0;
947
948 buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
949 2 + sm->r0kh_id_len + ric_ies_len + 100;
950@@ -681,6 +682,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
951 return -1;
952 }
953
954+ if (sm->ft_reassoc_completed) {
955+ wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission");
956+ return 0;
957+ }
958+
959 if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
960 wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
961 return -1;
962@@ -781,6 +787,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
963 return -1;
964 }
965
966+ sm->ft_reassoc_completed = 1;
967+
968 if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
969 return -1;
970
971diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
972index 41f371f..56f88dc 100644
973--- a/src/rsn_supp/wpa_i.h
974+++ b/src/rsn_supp/wpa_i.h
975@@ -128,6 +128,7 @@ struct wpa_sm {
976 size_t r0kh_id_len;
977 u8 r1kh_id[FT_R1KH_ID_LEN];
978 int ft_completed;
979+ int ft_reassoc_completed;
980 int over_the_ds_in_progress;
981 u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
982 int set_ptk_after_assoc;
983--
9842.7.4