Merge ~morphis/snappy-hwe-snaps/+git/wifi-ap:hostapd-2.6-krack-fixes into ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-ap:hostapd/2.6
- Git
- lp:~morphis/snappy-hwe-snaps/+git/wifi-ap
- hostapd-2.6-krack-fixes
- Merge into hostapd/2.6
Status: | Merged |
---|---|
Approved by: | Alfonso Sanchez-Beato |
Approved revision: | 71a9967679a174551b38312a41b7bf448a1cdbc2 |
Merged at revision: | 0125bab503042e0f984c9dc961837fa0bc58bb3a |
Proposed branch: | ~morphis/snappy-hwe-snaps/+git/wifi-ap:hostapd-2.6-krack-fixes |
Merge into: | ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-ap:hostapd/2.6 |
Diff against target: |
659 lines (+225/-61) 10 files modified
src/ap/ieee802_11.c (+13/-3) src/ap/wpa_auth.c (+32/-3) src/ap/wpa_auth.h (+2/-1) src/ap/wpa_auth_ft.c (+10/-0) src/ap/wpa_auth_i.h (+1/-0) src/common/wpa_common.h (+12/-0) src/rsn_supp/tdls.c (+36/-2) src/rsn_supp/wpa.c (+104/-51) src/rsn_supp/wpa_ft.c (+8/-0) src/rsn_supp/wpa_i.h (+7/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
System Enablement Bot | continuous-integration | Approve | |
Roberto Mier Escandon (community) | Approve | ||
Oliver Grawert | Approve | ||
Alfonso Sanchez-Beato | Approve | ||
Review via email: mp+332311@code.launchpad.net |
Commit message
Description of the change
Apply CVE fixes for Krack attack
See https:/
All patches are taken from upstream except rebased-
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
Roberto Mier Escandon (rmescandon) wrote : | # |
lgtm, but I would like more people to take a look, just in case
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:71a9967679a
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c |
2 | index 4e04169..333035f 100644 |
3 | --- a/src/ap/ieee802_11.c |
4 | +++ b/src/ap/ieee802_11.c |
5 | @@ -1841,6 +1841,7 @@ static int add_associated_sta(struct hostapd_data *hapd, |
6 | { |
7 | struct ieee80211_ht_capabilities ht_cap; |
8 | struct ieee80211_vht_capabilities vht_cap; |
9 | + int set = 1; |
10 | |
11 | /* |
12 | * Remove the STA entry to ensure the STA PS state gets cleared and |
13 | @@ -1848,9 +1849,18 @@ static int add_associated_sta(struct hostapd_data *hapd, |
14 | * FT-over-the-DS, where a station re-associates back to the same AP but |
15 | * skips the authentication flow, or if working with a driver that |
16 | * does not support full AP client state. |
17 | + * |
18 | + * Skip this if the STA has already completed FT reassociation and the |
19 | + * TK has been configured since the TX/RX PN must not be reset to 0 for |
20 | + * the same key. |
21 | */ |
22 | - if (!sta->added_unassoc) |
23 | + if (!sta->added_unassoc && |
24 | + (!(sta->flags & WLAN_STA_AUTHORIZED) || |
25 | + !wpa_auth_sta_ft_tk_already_set(sta->wpa_sm))) { |
26 | hostapd_drv_sta_remove(hapd, sta->addr); |
27 | + wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED); |
28 | + set = 0; |
29 | + } |
30 | |
31 | #ifdef CONFIG_IEEE80211N |
32 | if (sta->flags & WLAN_STA_HT) |
33 | @@ -1873,11 +1883,11 @@ static int add_associated_sta(struct hostapd_data *hapd, |
34 | sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, |
35 | sta->flags | WLAN_STA_ASSOC, sta->qosinfo, |
36 | sta->vht_opmode, sta->p2p_ie ? 1 : 0, |
37 | - sta->added_unassoc)) { |
38 | + set)) { |
39 | hostapd_logger(hapd, sta->addr, |
40 | HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, |
41 | "Could not %s STA to kernel driver", |
42 | - sta->added_unassoc ? "set" : "add"); |
43 | + set ? "set" : "add"); |
44 | |
45 | if (sta->added_unassoc) { |
46 | hostapd_drv_sta_remove(hapd, sta->addr); |
47 | diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c |
48 | index 3587086..bf10cc1 100644 |
49 | --- a/src/ap/wpa_auth.c |
50 | +++ b/src/ap/wpa_auth.c |
51 | @@ -1745,6 +1745,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) |
52 | #else /* CONFIG_IEEE80211R */ |
53 | break; |
54 | #endif /* CONFIG_IEEE80211R */ |
55 | + case WPA_DRV_STA_REMOVED: |
56 | + sm->tk_already_set = FALSE; |
57 | + return 0; |
58 | } |
59 | |
60 | #ifdef CONFIG_IEEE80211R |
61 | @@ -1898,6 +1901,21 @@ SM_STATE(WPA_PTK, AUTHENTICATION2) |
62 | } |
63 | |
64 | |
65 | +static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm) |
66 | +{ |
67 | + if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { |
68 | + wpa_printf(MSG_ERROR, |
69 | + "WPA: Failed to get random data for ANonce"); |
70 | + sm->Disconnect = TRUE; |
71 | + return -1; |
72 | + } |
73 | + wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce, |
74 | + WPA_NONCE_LEN); |
75 | + sm->TimeoutCtr = 0; |
76 | + return 0; |
77 | +} |
78 | + |
79 | + |
80 | SM_STATE(WPA_PTK, INITPMK) |
81 | { |
82 | u8 msk[2 * PMK_LEN]; |
83 | @@ -2455,9 +2473,12 @@ SM_STEP(WPA_PTK) |
84 | SM_ENTER(WPA_PTK, AUTHENTICATION); |
85 | else if (sm->ReAuthenticationRequest) |
86 | SM_ENTER(WPA_PTK, AUTHENTICATION2); |
87 | - else if (sm->PTKRequest) |
88 | - SM_ENTER(WPA_PTK, PTKSTART); |
89 | - else switch (sm->wpa_ptk_state) { |
90 | + else if (sm->PTKRequest) { |
91 | + if (wpa_auth_sm_ptk_update(sm) < 0) |
92 | + SM_ENTER(WPA_PTK, DISCONNECTED); |
93 | + else |
94 | + SM_ENTER(WPA_PTK, PTKSTART); |
95 | + } else switch (sm->wpa_ptk_state) { |
96 | case WPA_PTK_INITIALIZE: |
97 | break; |
98 | case WPA_PTK_DISCONNECT: |
99 | @@ -3250,6 +3271,14 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm) |
100 | } |
101 | |
102 | |
103 | +int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm) |
104 | +{ |
105 | + if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt)) |
106 | + return 0; |
107 | + return sm->tk_already_set; |
108 | +} |
109 | + |
110 | + |
111 | int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, |
112 | struct rsn_pmksa_cache_entry *entry) |
113 | { |
114 | diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h |
115 | index 0de8d97..97461b0 100644 |
116 | --- a/src/ap/wpa_auth.h |
117 | +++ b/src/ap/wpa_auth.h |
118 | @@ -267,7 +267,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, |
119 | u8 *data, size_t data_len); |
120 | enum wpa_event { |
121 | WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, |
122 | - WPA_REAUTH_EAPOL, WPA_ASSOC_FT |
123 | + WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED |
124 | }; |
125 | void wpa_remove_ptk(struct wpa_state_machine *sm); |
126 | int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event); |
127 | @@ -280,6 +280,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm); |
128 | int wpa_auth_get_pairwise(struct wpa_state_machine *sm); |
129 | int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); |
130 | int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); |
131 | +int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm); |
132 | int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, |
133 | struct rsn_pmksa_cache_entry *entry); |
134 | struct rsn_pmksa_cache_entry * |
135 | diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c |
136 | index 42242a5..e63b99a 100644 |
137 | --- a/src/ap/wpa_auth_ft.c |
138 | +++ b/src/ap/wpa_auth_ft.c |
139 | @@ -780,6 +780,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) |
140 | return; |
141 | } |
142 | |
143 | + if (sm->tk_already_set) { |
144 | + /* Must avoid TK reconfiguration to prevent clearing of TX/RX |
145 | + * PN in the driver */ |
146 | + wpa_printf(MSG_DEBUG, |
147 | + "FT: Do not re-install same PTK to the driver"); |
148 | + return; |
149 | + } |
150 | + |
151 | /* FIX: add STA entry to kernel/driver here? The set_key will fail |
152 | * most likely without this.. At the moment, STA entry is added only |
153 | * after association has been completed. This function will be called |
154 | @@ -792,6 +800,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) |
155 | |
156 | /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ |
157 | sm->pairwise_set = TRUE; |
158 | + sm->tk_already_set = TRUE; |
159 | } |
160 | |
161 | |
162 | @@ -898,6 +907,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, |
163 | |
164 | sm->pairwise = pairwise; |
165 | sm->PTK_valid = TRUE; |
166 | + sm->tk_already_set = FALSE; |
167 | wpa_ft_install_ptk(sm); |
168 | |
169 | buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + |
170 | diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h |
171 | index 72b7eb3..7fd8f05 100644 |
172 | --- a/src/ap/wpa_auth_i.h |
173 | +++ b/src/ap/wpa_auth_i.h |
174 | @@ -65,6 +65,7 @@ struct wpa_state_machine { |
175 | struct wpa_ptk PTK; |
176 | Boolean PTK_valid; |
177 | Boolean pairwise_set; |
178 | + Boolean tk_already_set; |
179 | int keycount; |
180 | Boolean Pair; |
181 | struct wpa_key_replay_counter { |
182 | diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h |
183 | index af1d0f0..1021ccb 100644 |
184 | --- a/src/common/wpa_common.h |
185 | +++ b/src/common/wpa_common.h |
186 | @@ -215,8 +215,20 @@ struct wpa_ptk { |
187 | size_t kck_len; |
188 | size_t kek_len; |
189 | size_t tk_len; |
190 | + int installed; /* 1 if key has already been installed to driver */ |
191 | }; |
192 | |
193 | +struct wpa_gtk { |
194 | + u8 gtk[WPA_GTK_MAX_LEN]; |
195 | + size_t gtk_len; |
196 | +}; |
197 | + |
198 | +#ifdef CONFIG_IEEE80211W |
199 | +struct wpa_igtk { |
200 | + u8 igtk[WPA_IGTK_MAX_LEN]; |
201 | + size_t igtk_len; |
202 | +}; |
203 | +#endif /* CONFIG_IEEE80211W */ |
204 | |
205 | /* WPA IE version 1 |
206 | * 00-50-f2:1 (OUI:OUI type) |
207 | diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c |
208 | index e424168..9eb9738 100644 |
209 | --- a/src/rsn_supp/tdls.c |
210 | +++ b/src/rsn_supp/tdls.c |
211 | @@ -112,6 +112,7 @@ struct wpa_tdls_peer { |
212 | u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */ |
213 | } tpk; |
214 | int tpk_set; |
215 | + int tk_set; /* TPK-TK configured to the driver */ |
216 | int tpk_success; |
217 | int tpk_in_progress; |
218 | |
219 | @@ -192,6 +193,20 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) |
220 | u8 rsc[6]; |
221 | enum wpa_alg alg; |
222 | |
223 | + if (peer->tk_set) { |
224 | + /* |
225 | + * This same TPK-TK has already been configured to the driver |
226 | + * and this new configuration attempt (likely due to an |
227 | + * unexpected retransmitted frame) would result in clearing |
228 | + * the TX/RX sequence number which can break security, so must |
229 | + * not allow that to happen. |
230 | + */ |
231 | + wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR |
232 | + " has already been configured to the driver - do not reconfigure", |
233 | + MAC2STR(peer->addr)); |
234 | + return -1; |
235 | + } |
236 | + |
237 | os_memset(rsc, 0, 6); |
238 | |
239 | switch (peer->cipher) { |
240 | @@ -209,12 +224,15 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) |
241 | return -1; |
242 | } |
243 | |
244 | + wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR, |
245 | + MAC2STR(peer->addr)); |
246 | if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, |
247 | rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { |
248 | wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " |
249 | "driver"); |
250 | return -1; |
251 | } |
252 | + peer->tk_set = 1; |
253 | return 0; |
254 | } |
255 | |
256 | @@ -696,7 +714,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer) |
257 | peer->cipher = 0; |
258 | peer->qos_info = 0; |
259 | peer->wmm_capable = 0; |
260 | - peer->tpk_set = peer->tpk_success = 0; |
261 | + peer->tk_set = peer->tpk_set = peer->tpk_success = 0; |
262 | peer->chan_switch_enabled = 0; |
263 | os_memset(&peer->tpk, 0, sizeof(peer->tpk)); |
264 | os_memset(peer->inonce, 0, WPA_NONCE_LEN); |
265 | @@ -1159,6 +1177,7 @@ skip_rsnie: |
266 | wpa_tdls_peer_free(sm, peer); |
267 | return -1; |
268 | } |
269 | + peer->tk_set = 0; /* A new nonce results in a new TK */ |
270 | wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", |
271 | peer->inonce, WPA_NONCE_LEN); |
272 | os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); |
273 | @@ -1751,6 +1770,19 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer, |
274 | } |
275 | |
276 | |
277 | +static int tdls_nonce_set(const u8 *nonce) |
278 | +{ |
279 | + int i; |
280 | + |
281 | + for (i = 0; i < WPA_NONCE_LEN; i++) { |
282 | + if (nonce[i]) |
283 | + return 1; |
284 | + } |
285 | + |
286 | + return 0; |
287 | +} |
288 | + |
289 | + |
290 | static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, |
291 | const u8 *buf, size_t len) |
292 | { |
293 | @@ -2004,7 +2036,8 @@ skip_rsn: |
294 | peer->rsnie_i_len = kde.rsn_ie_len; |
295 | peer->cipher = cipher; |
296 | |
297 | - if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) { |
298 | + if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0 || |
299 | + !tdls_nonce_set(peer->inonce)) { |
300 | /* |
301 | * There is no point in updating the RNonce for every obtained |
302 | * TPK M1 frame (e.g., retransmission due to timeout) with the |
303 | @@ -2020,6 +2053,7 @@ skip_rsn: |
304 | "TDLS: Failed to get random data for responder nonce"); |
305 | goto error; |
306 | } |
307 | + peer->tk_set = 0; /* A new nonce results in a new TK */ |
308 | } |
309 | |
310 | #if 0 |
311 | diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c |
312 | index 3c47879..2a53c6f 100644 |
313 | --- a/src/rsn_supp/wpa.c |
314 | +++ b/src/rsn_supp/wpa.c |
315 | @@ -510,7 +510,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, |
316 | os_memset(buf, 0, sizeof(buf)); |
317 | } |
318 | sm->tptk_set = 1; |
319 | - sm->tk_to_set = 1; |
320 | |
321 | kde = sm->assoc_wpa_ie; |
322 | kde_len = sm->assoc_wpa_ie_len; |
323 | @@ -615,7 +614,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, |
324 | enum wpa_alg alg; |
325 | const u8 *key_rsc; |
326 | |
327 | - if (!sm->tk_to_set) { |
328 | + if (sm->ptk.installed) { |
329 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, |
330 | "WPA: Do not re-install same PTK to the driver"); |
331 | return 0; |
332 | @@ -659,7 +658,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, |
333 | |
334 | /* TK is not needed anymore in supplicant */ |
335 | os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN); |
336 | - sm->tk_to_set = 0; |
337 | + sm->ptk.installed = 1; |
338 | |
339 | if (sm->wpa_ptk_rekey) { |
340 | eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); |
341 | @@ -709,11 +708,23 @@ struct wpa_gtk_data { |
342 | |
343 | static int wpa_supplicant_install_gtk(struct wpa_sm *sm, |
344 | const struct wpa_gtk_data *gd, |
345 | - const u8 *key_rsc) |
346 | + const u8 *key_rsc, int wnm_sleep) |
347 | { |
348 | const u8 *_gtk = gd->gtk; |
349 | u8 gtk_buf[32]; |
350 | |
351 | + /* Detect possible key reinstallation */ |
352 | + if ((sm->gtk.gtk_len == (size_t) gd->gtk_len && |
353 | + os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) || |
354 | + (sm->gtk_wnm_sleep.gtk_len == (size_t) gd->gtk_len && |
355 | + os_memcmp(sm->gtk_wnm_sleep.gtk, gd->gtk, |
356 | + sm->gtk_wnm_sleep.gtk_len) == 0)) { |
357 | + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, |
358 | + "WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)", |
359 | + gd->keyidx, gd->tx, gd->gtk_len); |
360 | + return 0; |
361 | + } |
362 | + |
363 | wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); |
364 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, |
365 | "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)", |
366 | @@ -748,6 +759,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, |
367 | } |
368 | os_memset(gtk_buf, 0, sizeof(gtk_buf)); |
369 | |
370 | + if (wnm_sleep) { |
371 | + sm->gtk_wnm_sleep.gtk_len = gd->gtk_len; |
372 | + os_memcpy(sm->gtk_wnm_sleep.gtk, gd->gtk, |
373 | + sm->gtk_wnm_sleep.gtk_len); |
374 | + } else { |
375 | + sm->gtk.gtk_len = gd->gtk_len; |
376 | + os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len); |
377 | + } |
378 | + |
379 | return 0; |
380 | } |
381 | |
382 | @@ -840,7 +860,7 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, |
383 | (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, |
384 | gtk_len, gtk_len, |
385 | &gd.key_rsc_len, &gd.alg) || |
386 | - wpa_supplicant_install_gtk(sm, &gd, key_rsc))) { |
387 | + wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) { |
388 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, |
389 | "RSN: Failed to install GTK"); |
390 | os_memset(&gd, 0, sizeof(gd)); |
391 | @@ -854,6 +874,58 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, |
392 | } |
393 | |
394 | |
395 | +#ifdef CONFIG_IEEE80211W |
396 | +static int wpa_supplicant_install_igtk(struct wpa_sm *sm, |
397 | + const struct wpa_igtk_kde *igtk, |
398 | + int wnm_sleep) |
399 | +{ |
400 | + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher); |
401 | + u16 keyidx = WPA_GET_LE16(igtk->keyid); |
402 | + |
403 | + /* Detect possible key reinstallation */ |
404 | + if ((sm->igtk.igtk_len == len && |
405 | + os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) || |
406 | + (sm->igtk_wnm_sleep.igtk_len == len && |
407 | + os_memcmp(sm->igtk_wnm_sleep.igtk, igtk->igtk, |
408 | + sm->igtk_wnm_sleep.igtk_len) == 0)) { |
409 | + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, |
410 | + "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)", |
411 | + keyidx); |
412 | + return 0; |
413 | + } |
414 | + |
415 | + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, |
416 | + "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x", |
417 | + keyidx, MAC2STR(igtk->pn)); |
418 | + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len); |
419 | + if (keyidx > 4095) { |
420 | + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, |
421 | + "WPA: Invalid IGTK KeyID %d", keyidx); |
422 | + return -1; |
423 | + } |
424 | + if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), |
425 | + broadcast_ether_addr, |
426 | + keyidx, 0, igtk->pn, sizeof(igtk->pn), |
427 | + igtk->igtk, len) < 0) { |
428 | + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, |
429 | + "WPA: Failed to configure IGTK to the driver"); |
430 | + return -1; |
431 | + } |
432 | + |
433 | + if (wnm_sleep) { |
434 | + sm->igtk_wnm_sleep.igtk_len = len; |
435 | + os_memcpy(sm->igtk_wnm_sleep.igtk, igtk->igtk, |
436 | + sm->igtk_wnm_sleep.igtk_len); |
437 | + } else { |
438 | + sm->igtk.igtk_len = len; |
439 | + os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len); |
440 | + } |
441 | + |
442 | + return 0; |
443 | +} |
444 | +#endif /* CONFIG_IEEE80211W */ |
445 | + |
446 | + |
447 | static int ieee80211w_set_keys(struct wpa_sm *sm, |
448 | struct wpa_eapol_ie_parse *ie) |
449 | { |
450 | @@ -864,30 +936,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, |
451 | if (ie->igtk) { |
452 | size_t len; |
453 | const struct wpa_igtk_kde *igtk; |
454 | - u16 keyidx; |
455 | + |
456 | len = wpa_cipher_key_len(sm->mgmt_group_cipher); |
457 | if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len) |
458 | return -1; |
459 | + |
460 | igtk = (const struct wpa_igtk_kde *) ie->igtk; |
461 | - keyidx = WPA_GET_LE16(igtk->keyid); |
462 | - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d " |
463 | - "pn %02x%02x%02x%02x%02x%02x", |
464 | - keyidx, MAC2STR(igtk->pn)); |
465 | - wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", |
466 | - igtk->igtk, len); |
467 | - if (keyidx > 4095) { |
468 | - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, |
469 | - "WPA: Invalid IGTK KeyID %d", keyidx); |
470 | - return -1; |
471 | - } |
472 | - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), |
473 | - broadcast_ether_addr, |
474 | - keyidx, 0, igtk->pn, sizeof(igtk->pn), |
475 | - igtk->igtk, len) < 0) { |
476 | - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, |
477 | - "WPA: Failed to configure IGTK to the driver"); |
478 | + if (wpa_supplicant_install_igtk(sm, igtk, 0) < 0) |
479 | return -1; |
480 | - } |
481 | } |
482 | |
483 | return 0; |
484 | @@ -1536,7 +1592,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, |
485 | if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc)) |
486 | key_rsc = null_rsc; |
487 | |
488 | - if (wpa_supplicant_install_gtk(sm, &gd, key_rsc) || |
489 | + if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) || |
490 | wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0) |
491 | goto failed; |
492 | os_memset(&gd, 0, sizeof(gd)); |
493 | @@ -2307,7 +2363,7 @@ void wpa_sm_deinit(struct wpa_sm *sm) |
494 | */ |
495 | void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) |
496 | { |
497 | - int clear_ptk = 1; |
498 | + int clear_keys = 1; |
499 | |
500 | if (sm == NULL) |
501 | return; |
502 | @@ -2333,11 +2389,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) |
503 | /* Prepare for the next transition */ |
504 | wpa_ft_prepare_auth_request(sm, NULL); |
505 | |
506 | - clear_ptk = 0; |
507 | + clear_keys = 0; |
508 | } |
509 | #endif /* CONFIG_IEEE80211R */ |
510 | |
511 | - if (clear_ptk) { |
512 | + if (clear_keys) { |
513 | /* |
514 | * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if |
515 | * this is not part of a Fast BSS Transition. |
516 | @@ -2347,6 +2403,12 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) |
517 | os_memset(&sm->ptk, 0, sizeof(sm->ptk)); |
518 | sm->tptk_set = 0; |
519 | os_memset(&sm->tptk, 0, sizeof(sm->tptk)); |
520 | + os_memset(&sm->gtk, 0, sizeof(sm->gtk)); |
521 | + os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep)); |
522 | +#ifdef CONFIG_IEEE80211W |
523 | + os_memset(&sm->igtk, 0, sizeof(sm->igtk)); |
524 | + os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); |
525 | +#endif /* CONFIG_IEEE80211W */ |
526 | } |
527 | |
528 | #ifdef CONFIG_TDLS |
529 | @@ -2378,6 +2440,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm) |
530 | #ifdef CONFIG_TDLS |
531 | wpa_tdls_disassoc(sm); |
532 | #endif /* CONFIG_TDLS */ |
533 | +#ifdef CONFIG_IEEE80211R |
534 | + sm->ft_reassoc_completed = 0; |
535 | +#endif /* CONFIG_IEEE80211R */ |
536 | |
537 | /* Keys are not needed in the WPA state machine anymore */ |
538 | wpa_sm_drop_sa(sm); |
539 | @@ -2877,6 +2942,12 @@ void wpa_sm_drop_sa(struct wpa_sm *sm) |
540 | os_memset(sm->pmk, 0, sizeof(sm->pmk)); |
541 | os_memset(&sm->ptk, 0, sizeof(sm->ptk)); |
542 | os_memset(&sm->tptk, 0, sizeof(sm->tptk)); |
543 | + os_memset(&sm->gtk, 0, sizeof(sm->gtk)); |
544 | + os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep)); |
545 | +#ifdef CONFIG_IEEE80211W |
546 | + os_memset(&sm->igtk, 0, sizeof(sm->igtk)); |
547 | + os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); |
548 | +#endif /* CONFIG_IEEE80211W */ |
549 | #ifdef CONFIG_IEEE80211R |
550 | os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); |
551 | os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0)); |
552 | @@ -2940,7 +3011,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) |
553 | |
554 | wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)", |
555 | gd.gtk, gd.gtk_len); |
556 | - if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) { |
557 | + if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 1)) { |
558 | os_memset(&gd, 0, sizeof(gd)); |
559 | wpa_printf(MSG_DEBUG, "Failed to install the GTK in " |
560 | "WNM mode"); |
561 | @@ -2949,29 +3020,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) |
562 | os_memset(&gd, 0, sizeof(gd)); |
563 | #ifdef CONFIG_IEEE80211W |
564 | } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) { |
565 | - struct wpa_igtk_kde igd; |
566 | - u16 keyidx; |
567 | - |
568 | - os_memset(&igd, 0, sizeof(igd)); |
569 | - keylen = wpa_cipher_key_len(sm->mgmt_group_cipher); |
570 | - os_memcpy(igd.keyid, buf + 2, 2); |
571 | - os_memcpy(igd.pn, buf + 4, 6); |
572 | - |
573 | - keyidx = WPA_GET_LE16(igd.keyid); |
574 | - os_memcpy(igd.igtk, buf + 10, keylen); |
575 | - |
576 | - wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", |
577 | - igd.igtk, keylen); |
578 | - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), |
579 | - broadcast_ether_addr, |
580 | - keyidx, 0, igd.pn, sizeof(igd.pn), |
581 | - igd.igtk, keylen) < 0) { |
582 | - wpa_printf(MSG_DEBUG, "Failed to install the IGTK in " |
583 | - "WNM mode"); |
584 | - os_memset(&igd, 0, sizeof(igd)); |
585 | + const struct wpa_igtk_kde *igtk; |
586 | + |
587 | + igtk = (const struct wpa_igtk_kde *) (buf + 2); |
588 | + if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0) |
589 | return -1; |
590 | - } |
591 | - os_memset(&igd, 0, sizeof(igd)); |
592 | #endif /* CONFIG_IEEE80211W */ |
593 | } else { |
594 | wpa_printf(MSG_DEBUG, "Unknown element id"); |
595 | diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c |
596 | index 205793e..d45bb45 100644 |
597 | --- a/src/rsn_supp/wpa_ft.c |
598 | +++ b/src/rsn_supp/wpa_ft.c |
599 | @@ -153,6 +153,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, |
600 | u16 capab; |
601 | |
602 | sm->ft_completed = 0; |
603 | + sm->ft_reassoc_completed = 0; |
604 | |
605 | buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + |
606 | 2 + sm->r0kh_id_len + ric_ies_len + 100; |
607 | @@ -681,6 +682,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, |
608 | return -1; |
609 | } |
610 | |
611 | + if (sm->ft_reassoc_completed) { |
612 | + wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission"); |
613 | + return 0; |
614 | + } |
615 | + |
616 | if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { |
617 | wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); |
618 | return -1; |
619 | @@ -781,6 +787,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, |
620 | return -1; |
621 | } |
622 | |
623 | + sm->ft_reassoc_completed = 1; |
624 | + |
625 | if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) |
626 | return -1; |
627 | |
628 | diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h |
629 | index f653ba6..56f88dc 100644 |
630 | --- a/src/rsn_supp/wpa_i.h |
631 | +++ b/src/rsn_supp/wpa_i.h |
632 | @@ -24,13 +24,18 @@ struct wpa_sm { |
633 | struct wpa_ptk ptk, tptk; |
634 | int ptk_set, tptk_set; |
635 | unsigned int msg_3_of_4_ok:1; |
636 | - unsigned int tk_to_set:1; |
637 | u8 snonce[WPA_NONCE_LEN]; |
638 | u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */ |
639 | int renew_snonce; |
640 | u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; |
641 | int rx_replay_counter_set; |
642 | u8 request_counter[WPA_REPLAY_COUNTER_LEN]; |
643 | + struct wpa_gtk gtk; |
644 | + struct wpa_gtk gtk_wnm_sleep; |
645 | +#ifdef CONFIG_IEEE80211W |
646 | + struct wpa_igtk igtk; |
647 | + struct wpa_igtk igtk_wnm_sleep; |
648 | +#endif /* CONFIG_IEEE80211W */ |
649 | |
650 | struct eapol_sm *eapol; /* EAPOL state machine from upper level code */ |
651 | |
652 | @@ -123,6 +128,7 @@ struct wpa_sm { |
653 | size_t r0kh_id_len; |
654 | u8 r1kh_id[FT_R1KH_ID_LEN]; |
655 | int ft_completed; |
656 | + int ft_reassoc_completed; |
657 | int over_the_ds_in_progress; |
658 | u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */ |
659 | int set_ptk_after_assoc; |
LGTM