Line data Source code
1 : /*
2 : * hostapd - IEEE 802.11r - Fast BSS Transition
3 : * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "utils/includes.h"
10 :
11 : #include "utils/common.h"
12 : #include "utils/eloop.h"
13 : #include "common/ieee802_11_defs.h"
14 : #include "common/ieee802_11_common.h"
15 : #include "crypto/aes_wrap.h"
16 : #include "crypto/random.h"
17 : #include "ap_config.h"
18 : #include "ieee802_11.h"
19 : #include "wmm.h"
20 : #include "wpa_auth.h"
21 : #include "wpa_auth_i.h"
22 :
23 :
24 : #ifdef CONFIG_IEEE80211R
25 :
26 : static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
27 : const u8 *current_ap, const u8 *sta_addr,
28 : u16 status, const u8 *resp_ies,
29 : size_t resp_ies_len);
30 :
31 :
32 245 : static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
33 : const u8 *data, size_t data_len)
34 : {
35 245 : if (wpa_auth->cb.send_ether == NULL)
36 0 : return -1;
37 245 : wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
38 245 : return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
39 : data, data_len);
40 : }
41 :
42 :
43 109 : static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
44 : const u8 *dst, const u8 *data, size_t data_len)
45 : {
46 109 : if (wpa_auth->cb.send_ft_action == NULL)
47 0 : return -1;
48 109 : return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
49 : data, data_len);
50 : }
51 :
52 :
53 : static struct wpa_state_machine *
54 113 : wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
55 : {
56 113 : if (wpa_auth->cb.add_sta == NULL)
57 0 : return NULL;
58 113 : return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
59 : }
60 :
61 :
62 0 : static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
63 : const u8 *sta_addr,
64 : u8 *tspec_ie, size_t tspec_ielen)
65 : {
66 0 : if (wpa_auth->cb.add_tspec == NULL) {
67 0 : wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
68 0 : return -1;
69 : }
70 0 : return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
71 : tspec_ielen);
72 : }
73 :
74 :
75 498 : int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
76 : {
77 498 : u8 *pos = buf;
78 : u8 capab;
79 498 : if (len < 2 + sizeof(struct rsn_mdie))
80 0 : return -1;
81 :
82 498 : *pos++ = WLAN_EID_MOBILITY_DOMAIN;
83 498 : *pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
84 498 : os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
85 498 : pos += MOBILITY_DOMAIN_ID_LEN;
86 498 : capab = 0;
87 498 : if (conf->ft_over_ds)
88 498 : capab |= RSN_FT_CAPAB_FT_OVER_DS;
89 498 : *pos++ = capab;
90 :
91 498 : return pos - buf;
92 : }
93 :
94 :
95 480 : int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
96 : size_t r0kh_id_len,
97 : const u8 *anonce, const u8 *snonce,
98 : u8 *buf, size_t len, const u8 *subelem,
99 : size_t subelem_len)
100 : {
101 480 : u8 *pos = buf, *ielen;
102 : struct rsn_ftie *hdr;
103 :
104 480 : if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
105 : subelem_len)
106 0 : return -1;
107 :
108 480 : *pos++ = WLAN_EID_FAST_BSS_TRANSITION;
109 480 : ielen = pos++;
110 :
111 480 : hdr = (struct rsn_ftie *) pos;
112 480 : os_memset(hdr, 0, sizeof(*hdr));
113 480 : pos += sizeof(*hdr);
114 480 : WPA_PUT_LE16(hdr->mic_control, 0);
115 480 : if (anonce)
116 442 : os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
117 480 : if (snonce)
118 442 : os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
119 :
120 : /* Optional Parameters */
121 480 : *pos++ = FTIE_SUBELEM_R1KH_ID;
122 480 : *pos++ = FT_R1KH_ID_LEN;
123 480 : os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
124 480 : pos += FT_R1KH_ID_LEN;
125 :
126 480 : if (r0kh_id) {
127 480 : *pos++ = FTIE_SUBELEM_R0KH_ID;
128 480 : *pos++ = r0kh_id_len;
129 480 : os_memcpy(pos, r0kh_id, r0kh_id_len);
130 480 : pos += r0kh_id_len;
131 : }
132 :
133 480 : if (subelem) {
134 221 : os_memcpy(pos, subelem, subelem_len);
135 221 : pos += subelem_len;
136 : }
137 :
138 480 : *ielen = pos - buf - 2;
139 :
140 480 : return pos - buf;
141 : }
142 :
143 :
144 : struct wpa_ft_pmk_r0_sa {
145 : struct wpa_ft_pmk_r0_sa *next;
146 : u8 pmk_r0[PMK_LEN];
147 : u8 pmk_r0_name[WPA_PMK_NAME_LEN];
148 : u8 spa[ETH_ALEN];
149 : int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
150 : /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
151 : int pmk_r1_pushed;
152 : };
153 :
154 : struct wpa_ft_pmk_r1_sa {
155 : struct wpa_ft_pmk_r1_sa *next;
156 : u8 pmk_r1[PMK_LEN];
157 : u8 pmk_r1_name[WPA_PMK_NAME_LEN];
158 : u8 spa[ETH_ALEN];
159 : int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
160 : /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
161 : };
162 :
163 : struct wpa_ft_pmk_cache {
164 : struct wpa_ft_pmk_r0_sa *pmk_r0;
165 : struct wpa_ft_pmk_r1_sa *pmk_r1;
166 : };
167 :
168 437 : struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
169 : {
170 : struct wpa_ft_pmk_cache *cache;
171 :
172 437 : cache = os_zalloc(sizeof(*cache));
173 :
174 437 : return cache;
175 : }
176 :
177 :
178 437 : void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
179 : {
180 : struct wpa_ft_pmk_r0_sa *r0, *r0prev;
181 : struct wpa_ft_pmk_r1_sa *r1, *r1prev;
182 :
183 437 : r0 = cache->pmk_r0;
184 893 : while (r0) {
185 19 : r0prev = r0;
186 19 : r0 = r0->next;
187 19 : os_memset(r0prev->pmk_r0, 0, PMK_LEN);
188 19 : os_free(r0prev);
189 : }
190 :
191 437 : r1 = cache->pmk_r1;
192 906 : while (r1) {
193 32 : r1prev = r1;
194 32 : r1 = r1->next;
195 32 : os_memset(r1prev->pmk_r1, 0, PMK_LEN);
196 32 : os_free(r1prev);
197 : }
198 :
199 437 : os_free(cache);
200 437 : }
201 :
202 :
203 19 : static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
204 : const u8 *spa, const u8 *pmk_r0,
205 : const u8 *pmk_r0_name, int pairwise)
206 : {
207 19 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
208 : struct wpa_ft_pmk_r0_sa *r0;
209 :
210 : /* TODO: add expiration and limit on number of entries in cache */
211 :
212 19 : r0 = os_zalloc(sizeof(*r0));
213 19 : if (r0 == NULL)
214 0 : return -1;
215 :
216 19 : os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
217 19 : os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
218 19 : os_memcpy(r0->spa, spa, ETH_ALEN);
219 19 : r0->pairwise = pairwise;
220 :
221 19 : r0->next = cache->pmk_r0;
222 19 : cache->pmk_r0 = r0;
223 :
224 19 : return 0;
225 : }
226 :
227 :
228 3 : static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
229 : const u8 *spa, const u8 *pmk_r0_name,
230 : u8 *pmk_r0, int *pairwise)
231 : {
232 3 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
233 : struct wpa_ft_pmk_r0_sa *r0;
234 :
235 3 : r0 = cache->pmk_r0;
236 6 : while (r0) {
237 6 : if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
238 3 : os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
239 : WPA_PMK_NAME_LEN) == 0) {
240 3 : os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
241 3 : if (pairwise)
242 3 : *pairwise = r0->pairwise;
243 3 : return 0;
244 : }
245 :
246 0 : r0 = r0->next;
247 : }
248 :
249 0 : return -1;
250 : }
251 :
252 :
253 32 : static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
254 : const u8 *spa, const u8 *pmk_r1,
255 : const u8 *pmk_r1_name, int pairwise)
256 : {
257 32 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
258 : struct wpa_ft_pmk_r1_sa *r1;
259 :
260 : /* TODO: add expiration and limit on number of entries in cache */
261 :
262 32 : r1 = os_zalloc(sizeof(*r1));
263 32 : if (r1 == NULL)
264 0 : return -1;
265 :
266 32 : os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
267 32 : os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
268 32 : os_memcpy(r1->spa, spa, ETH_ALEN);
269 32 : r1->pairwise = pairwise;
270 :
271 32 : r1->next = cache->pmk_r1;
272 32 : cache->pmk_r1 = r1;
273 :
274 32 : return 0;
275 : }
276 :
277 :
278 229 : static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
279 : const u8 *spa, const u8 *pmk_r1_name,
280 : u8 *pmk_r1, int *pairwise)
281 : {
282 229 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
283 : struct wpa_ft_pmk_r1_sa *r1;
284 :
285 229 : r1 = cache->pmk_r1;
286 458 : while (r1) {
287 442 : if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
288 221 : os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
289 : WPA_PMK_NAME_LEN) == 0) {
290 221 : os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
291 221 : if (pairwise)
292 221 : *pairwise = r1->pairwise;
293 221 : return 0;
294 : }
295 :
296 0 : r1 = r1->next;
297 : }
298 :
299 8 : return -1;
300 : }
301 :
302 :
303 8 : static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
304 : const u8 *ies, size_t ies_len,
305 : const u8 *pmk_r0_name)
306 : {
307 : struct ft_remote_r0kh *r0kh;
308 : struct ft_r0kh_r1kh_pull_frame frame, f;
309 :
310 8 : r0kh = sm->wpa_auth->conf.r0kh_list;
311 25 : while (r0kh) {
312 32 : if (r0kh->id_len == sm->r0kh_id_len &&
313 16 : os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) ==
314 : 0)
315 7 : break;
316 9 : r0kh = r0kh->next;
317 : }
318 8 : if (r0kh == NULL) {
319 2 : wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
320 1 : sm->r0kh_id, sm->r0kh_id_len);
321 1 : return -1;
322 : }
323 :
324 42 : wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
325 42 : "address " MACSTR, MAC2STR(r0kh->addr));
326 :
327 7 : os_memset(&frame, 0, sizeof(frame));
328 7 : frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
329 7 : frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
330 7 : frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
331 7 : os_memcpy(frame.ap_address, sm->wpa_auth->addr, ETH_ALEN);
332 :
333 : /* aes_wrap() does not support inplace encryption, so use a temporary
334 : * buffer for the data. */
335 7 : if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) {
336 0 : wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
337 : "nonce");
338 0 : return -1;
339 : }
340 7 : os_memcpy(sm->ft_pending_pull_nonce, f.nonce,
341 : FT_R0KH_R1KH_PULL_NONCE_LEN);
342 7 : os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
343 7 : os_memcpy(f.r1kh_id, sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
344 7 : os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
345 7 : os_memset(f.pad, 0, sizeof(f.pad));
346 :
347 7 : if (aes_wrap(r0kh->key, sizeof(r0kh->key),
348 : (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
349 : f.nonce, frame.nonce) < 0)
350 0 : return -1;
351 :
352 7 : wpabuf_free(sm->ft_pending_req_ies);
353 7 : sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len);
354 7 : if (sm->ft_pending_req_ies == NULL)
355 0 : return -1;
356 :
357 7 : wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
358 :
359 7 : return 0;
360 : }
361 :
362 :
363 19 : int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
364 : struct wpa_ptk *ptk, size_t ptk_len)
365 : {
366 : u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
367 : u8 pmk_r1[PMK_LEN];
368 : u8 ptk_name[WPA_PMK_NAME_LEN];
369 19 : const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
370 19 : const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
371 19 : size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
372 19 : const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
373 19 : const u8 *ssid = sm->wpa_auth->conf.ssid;
374 19 : size_t ssid_len = sm->wpa_auth->conf.ssid_len;
375 :
376 :
377 19 : if (sm->xxkey_len == 0) {
378 0 : wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
379 : "derivation");
380 0 : return -1;
381 : }
382 :
383 19 : wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
384 19 : r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
385 19 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
386 19 : wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
387 19 : wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
388 : sm->pairwise);
389 :
390 19 : wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
391 19 : pmk_r1, sm->pmk_r1_name);
392 19 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
393 19 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
394 : WPA_PMK_NAME_LEN);
395 19 : wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
396 : sm->pairwise);
397 :
398 19 : wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
399 19 : sm->wpa_auth->addr, sm->pmk_r1_name,
400 : (u8 *) ptk, ptk_len, ptk_name);
401 19 : wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
402 19 : wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
403 :
404 19 : return 0;
405 : }
406 :
407 :
408 225 : static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
409 : const u8 *addr, int idx, u8 *seq)
410 : {
411 225 : if (wpa_auth->cb.get_seqnum == NULL)
412 0 : return -1;
413 225 : return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
414 : }
415 :
416 :
417 221 : static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
418 : {
419 : u8 *subelem;
420 221 : struct wpa_group *gsm = sm->group;
421 : size_t subelem_len, pad_len;
422 : const u8 *key;
423 : size_t key_len;
424 : u8 keybuf[32];
425 :
426 221 : key_len = gsm->GTK_len;
427 221 : if (key_len > sizeof(keybuf))
428 0 : return NULL;
429 :
430 : /*
431 : * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
432 : * than 16 bytes.
433 : */
434 221 : pad_len = key_len % 8;
435 221 : if (pad_len)
436 0 : pad_len = 8 - pad_len;
437 221 : if (key_len + pad_len < 16)
438 0 : pad_len += 8;
439 221 : if (pad_len && key_len < sizeof(keybuf)) {
440 0 : os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
441 0 : os_memset(keybuf + key_len, 0, pad_len);
442 0 : keybuf[key_len] = 0xdd;
443 0 : key_len += pad_len;
444 0 : key = keybuf;
445 : } else
446 221 : key = gsm->GTK[gsm->GN - 1];
447 :
448 : /*
449 : * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
450 : * Key[5..32].
451 : */
452 221 : subelem_len = 13 + key_len + 8;
453 221 : subelem = os_zalloc(subelem_len);
454 221 : if (subelem == NULL)
455 0 : return NULL;
456 :
457 221 : subelem[0] = FTIE_SUBELEM_GTK;
458 221 : subelem[1] = 11 + key_len + 8;
459 : /* Key ID in B0-B1 of Key Info */
460 221 : WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
461 221 : subelem[4] = gsm->GTK_len;
462 221 : wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
463 221 : if (aes_wrap(sm->PTK.kek, 16, key_len / 8, key, subelem + 13)) {
464 0 : os_free(subelem);
465 0 : return NULL;
466 : }
467 :
468 221 : *len = subelem_len;
469 221 : return subelem;
470 : }
471 :
472 :
473 : #ifdef CONFIG_IEEE80211W
474 4 : static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
475 : {
476 : u8 *subelem, *pos;
477 4 : struct wpa_group *gsm = sm->group;
478 : size_t subelem_len;
479 :
480 : /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
481 : * Key[16+8] */
482 4 : subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
483 4 : subelem = os_zalloc(subelem_len);
484 4 : if (subelem == NULL)
485 0 : return NULL;
486 :
487 4 : pos = subelem;
488 4 : *pos++ = FTIE_SUBELEM_IGTK;
489 4 : *pos++ = subelem_len - 2;
490 4 : WPA_PUT_LE16(pos, gsm->GN_igtk);
491 4 : pos += 2;
492 4 : wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
493 4 : pos += 6;
494 4 : *pos++ = WPA_IGTK_LEN;
495 4 : if (aes_wrap(sm->PTK.kek, 16, WPA_IGTK_LEN / 8,
496 4 : gsm->IGTK[gsm->GN_igtk - 4], pos)) {
497 0 : os_free(subelem);
498 0 : return NULL;
499 : }
500 :
501 4 : *len = subelem_len;
502 4 : return subelem;
503 : }
504 : #endif /* CONFIG_IEEE80211W */
505 :
506 :
507 0 : static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
508 : u8 *pos, u8 *end, u8 id, u8 descr_count,
509 : const u8 *ies, size_t ies_len)
510 : {
511 : struct ieee802_11_elems parse;
512 : struct rsn_rdie *rdie;
513 :
514 0 : wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
515 : id, descr_count);
516 0 : wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
517 : ies, ies_len);
518 :
519 0 : if (end - pos < (int) sizeof(*rdie)) {
520 0 : wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
521 0 : return pos;
522 : }
523 :
524 0 : *pos++ = WLAN_EID_RIC_DATA;
525 0 : *pos++ = sizeof(*rdie);
526 0 : rdie = (struct rsn_rdie *) pos;
527 0 : rdie->id = id;
528 0 : rdie->descr_count = 0;
529 0 : rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
530 0 : pos += sizeof(*rdie);
531 :
532 0 : if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
533 : ParseFailed) {
534 0 : wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
535 0 : rdie->status_code =
536 : host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
537 0 : return pos;
538 : }
539 :
540 : #ifdef NEED_AP_MLME
541 0 : if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
542 : struct wmm_tspec_element *tspec;
543 : int res;
544 :
545 0 : if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
546 0 : wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
547 0 : "(%d)", (int) parse.wmm_tspec_len);
548 0 : rdie->status_code =
549 : host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
550 0 : return pos;
551 : }
552 0 : if (end - pos < (int) sizeof(*tspec)) {
553 0 : wpa_printf(MSG_ERROR, "FT: Not enough room for "
554 : "response TSPEC");
555 0 : rdie->status_code =
556 : host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
557 0 : return pos;
558 : }
559 0 : tspec = (struct wmm_tspec_element *) pos;
560 0 : os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
561 0 : res = wmm_process_tspec(tspec);
562 0 : wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
563 0 : if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
564 0 : rdie->status_code =
565 : host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
566 0 : else if (res == WMM_ADDTS_STATUS_REFUSED)
567 0 : rdie->status_code =
568 : host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
569 : else {
570 : /* TSPEC accepted; include updated TSPEC in response */
571 0 : rdie->descr_count = 1;
572 0 : pos += sizeof(*tspec);
573 : }
574 0 : return pos;
575 : }
576 : #endif /* NEED_AP_MLME */
577 :
578 0 : if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
579 : struct wmm_tspec_element *tspec;
580 : int res;
581 :
582 0 : tspec = (struct wmm_tspec_element *) pos;
583 0 : os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
584 0 : res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
585 : sizeof(*tspec));
586 0 : if (res >= 0) {
587 0 : if (res)
588 0 : rdie->status_code = host_to_le16(res);
589 : else {
590 : /* TSPEC accepted; include updated TSPEC in
591 : * response */
592 0 : rdie->descr_count = 1;
593 0 : pos += sizeof(*tspec);
594 : }
595 0 : return pos;
596 : }
597 : }
598 :
599 0 : wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
600 0 : rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
601 0 : return pos;
602 : }
603 :
604 :
605 0 : static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
606 : const u8 *ric, size_t ric_len)
607 : {
608 : const u8 *rpos, *start;
609 : const struct rsn_rdie *rdie;
610 :
611 0 : wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
612 :
613 0 : rpos = ric;
614 0 : while (rpos + sizeof(*rdie) < ric + ric_len) {
615 0 : if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
616 0 : rpos + 2 + rpos[1] > ric + ric_len)
617 : break;
618 0 : rdie = (const struct rsn_rdie *) (rpos + 2);
619 0 : rpos += 2 + rpos[1];
620 0 : start = rpos;
621 :
622 0 : while (rpos + 2 <= ric + ric_len &&
623 0 : rpos + 2 + rpos[1] <= ric + ric_len) {
624 0 : if (rpos[0] == WLAN_EID_RIC_DATA)
625 0 : break;
626 0 : rpos += 2 + rpos[1];
627 : }
628 0 : pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
629 0 : rdie->descr_count,
630 0 : start, rpos - start);
631 : }
632 :
633 0 : return pos;
634 : }
635 :
636 :
637 1299 : u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
638 : size_t max_len, int auth_alg,
639 : const u8 *req_ies, size_t req_ies_len)
640 : {
641 1299 : u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
642 1299 : size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
643 : int res;
644 : struct wpa_auth_config *conf;
645 : struct rsn_ftie *_ftie;
646 : struct wpa_ft_ies parse;
647 : u8 *ric_start;
648 : u8 *anonce, *snonce;
649 :
650 1299 : if (sm == NULL)
651 277 : return pos;
652 :
653 1022 : conf = &sm->wpa_auth->conf;
654 :
655 1022 : if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
656 782 : return pos;
657 :
658 240 : end = pos + max_len;
659 :
660 240 : if (auth_alg == WLAN_AUTH_FT) {
661 : /*
662 : * RSN (only present if this is a Reassociation Response and
663 : * part of a fast BSS transition)
664 : */
665 221 : res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
666 221 : if (res < 0)
667 0 : return pos;
668 221 : rsnie = pos;
669 221 : rsnie_len = res;
670 221 : pos += res;
671 : }
672 :
673 : /* Mobility Domain Information */
674 240 : res = wpa_write_mdie(conf, pos, end - pos);
675 240 : if (res < 0)
676 0 : return pos;
677 240 : mdie = pos;
678 240 : mdie_len = res;
679 240 : pos += res;
680 :
681 : /* Fast BSS Transition Information */
682 240 : if (auth_alg == WLAN_AUTH_FT) {
683 221 : subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
684 221 : r0kh_id = sm->r0kh_id;
685 221 : r0kh_id_len = sm->r0kh_id_len;
686 221 : anonce = sm->ANonce;
687 221 : snonce = sm->SNonce;
688 : #ifdef CONFIG_IEEE80211W
689 221 : if (sm->mgmt_frame_prot) {
690 : u8 *igtk;
691 : size_t igtk_len;
692 : u8 *nbuf;
693 4 : igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
694 4 : if (igtk == NULL) {
695 0 : os_free(subelem);
696 0 : return pos;
697 : }
698 4 : nbuf = os_realloc(subelem, subelem_len + igtk_len);
699 4 : if (nbuf == NULL) {
700 0 : os_free(subelem);
701 0 : os_free(igtk);
702 0 : return pos;
703 : }
704 4 : subelem = nbuf;
705 4 : os_memcpy(subelem + subelem_len, igtk, igtk_len);
706 4 : subelem_len += igtk_len;
707 4 : os_free(igtk);
708 : }
709 : #endif /* CONFIG_IEEE80211W */
710 : } else {
711 19 : r0kh_id = conf->r0_key_holder;
712 19 : r0kh_id_len = conf->r0_key_holder_len;
713 19 : anonce = NULL;
714 19 : snonce = NULL;
715 : }
716 480 : res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
717 240 : end - pos, subelem, subelem_len);
718 240 : os_free(subelem);
719 240 : if (res < 0)
720 0 : return pos;
721 240 : ftie = pos;
722 240 : ftie_len = res;
723 240 : pos += res;
724 :
725 240 : os_free(sm->assoc_resp_ftie);
726 240 : sm->assoc_resp_ftie = os_malloc(ftie_len);
727 240 : if (sm->assoc_resp_ftie)
728 240 : os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
729 :
730 240 : _ftie = (struct rsn_ftie *) (ftie + 2);
731 240 : if (auth_alg == WLAN_AUTH_FT)
732 221 : _ftie->mic_control[1] = 3; /* Information element count */
733 :
734 240 : ric_start = pos;
735 240 : if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
736 0 : pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
737 : parse.ric_len);
738 0 : if (auth_alg == WLAN_AUTH_FT)
739 0 : _ftie->mic_control[1] +=
740 0 : ieee802_11_ie_count(ric_start,
741 0 : pos - ric_start);
742 : }
743 240 : if (ric_start == pos)
744 240 : ric_start = NULL;
745 :
746 461 : if (auth_alg == WLAN_AUTH_FT &&
747 221 : wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
748 : mdie, mdie_len, ftie, ftie_len,
749 : rsnie, rsnie_len,
750 0 : ric_start, ric_start ? pos - ric_start : 0,
751 221 : _ftie->mic) < 0)
752 0 : wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
753 :
754 240 : return pos;
755 : }
756 :
757 :
758 442 : static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
759 : int vlan_id,
760 : enum wpa_alg alg, const u8 *addr, int idx,
761 : u8 *key, size_t key_len)
762 : {
763 442 : if (wpa_auth->cb.set_key == NULL)
764 0 : return -1;
765 442 : return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
766 : key, key_len);
767 : }
768 :
769 :
770 442 : void wpa_ft_install_ptk(struct wpa_state_machine *sm)
771 : {
772 : enum wpa_alg alg;
773 : int klen;
774 :
775 : /* MLME-SETKEYS.request(PTK) */
776 442 : alg = wpa_cipher_to_alg(sm->pairwise);
777 442 : klen = wpa_cipher_key_len(sm->pairwise);
778 442 : if (!wpa_cipher_valid_pairwise(sm->pairwise)) {
779 0 : wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
780 : "PTK configuration", sm->pairwise);
781 0 : return;
782 : }
783 :
784 : /* FIX: add STA entry to kernel/driver here? The set_key will fail
785 : * most likely without this.. At the moment, STA entry is added only
786 : * after association has been completed. This function will be called
787 : * again after association to get the PTK configured, but that could be
788 : * optimized by adding the STA entry earlier.
789 : */
790 884 : if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
791 442 : sm->PTK.tk1, klen))
792 13 : return;
793 :
794 : /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
795 429 : sm->pairwise_set = TRUE;
796 : }
797 :
798 :
799 229 : static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
800 : const u8 *ies, size_t ies_len,
801 : u8 **resp_ies, size_t *resp_ies_len)
802 : {
803 : struct rsn_mdie *mdie;
804 : struct rsn_ftie *ftie;
805 : u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
806 : u8 ptk_name[WPA_PMK_NAME_LEN];
807 : struct wpa_auth_config *conf;
808 : struct wpa_ft_ies parse;
809 : size_t buflen, ptk_len;
810 : int ret;
811 : u8 *pos, *end;
812 : int pairwise;
813 :
814 229 : *resp_ies = NULL;
815 229 : *resp_ies_len = 0;
816 :
817 229 : sm->pmk_r1_name_valid = 0;
818 229 : conf = &sm->wpa_auth->conf;
819 :
820 229 : wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
821 : ies, ies_len);
822 :
823 229 : if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
824 0 : wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
825 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
826 : }
827 :
828 229 : mdie = (struct rsn_mdie *) parse.mdie;
829 458 : if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
830 229 : os_memcmp(mdie->mobility_domain,
831 : sm->wpa_auth->conf.mobility_domain,
832 : MOBILITY_DOMAIN_ID_LEN) != 0) {
833 0 : wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
834 0 : return WLAN_STATUS_INVALID_MDIE;
835 : }
836 :
837 229 : ftie = (struct rsn_ftie *) parse.ftie;
838 229 : if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
839 0 : wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
840 0 : return WLAN_STATUS_INVALID_FTIE;
841 : }
842 :
843 229 : os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
844 :
845 229 : if (parse.r0kh_id == NULL) {
846 0 : wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
847 0 : return WLAN_STATUS_INVALID_FTIE;
848 : }
849 :
850 458 : wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
851 229 : parse.r0kh_id, parse.r0kh_id_len);
852 229 : os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
853 229 : sm->r0kh_id_len = parse.r0kh_id_len;
854 :
855 229 : if (parse.rsn_pmkid == NULL) {
856 0 : wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
857 0 : return WLAN_STATUS_INVALID_PMKID;
858 : }
859 :
860 229 : wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
861 229 : parse.rsn_pmkid, WPA_PMK_NAME_LEN);
862 229 : wpa_derive_pmk_r1_name(parse.rsn_pmkid,
863 229 : sm->wpa_auth->conf.r1_key_holder, sm->addr,
864 : pmk_r1_name);
865 229 : wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
866 : pmk_r1_name, WPA_PMK_NAME_LEN);
867 :
868 229 : if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
869 : &pairwise) < 0) {
870 8 : if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
871 1 : wpa_printf(MSG_DEBUG, "FT: Did not have matching "
872 : "PMK-R1 and unknown R0KH-ID");
873 1 : return WLAN_STATUS_INVALID_PMKID;
874 : }
875 :
876 7 : return -1; /* Status pending */
877 : }
878 :
879 221 : wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
880 221 : sm->pmk_r1_name_valid = 1;
881 221 : os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
882 :
883 221 : if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
884 0 : wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
885 : "ANonce");
886 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
887 : }
888 :
889 221 : wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
890 221 : sm->SNonce, WPA_NONCE_LEN);
891 221 : wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
892 221 : sm->ANonce, WPA_NONCE_LEN);
893 :
894 221 : ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
895 221 : wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
896 221 : sm->wpa_auth->addr, pmk_r1_name,
897 221 : (u8 *) &sm->PTK, ptk_len, ptk_name);
898 221 : wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
899 221 : (u8 *) &sm->PTK, ptk_len);
900 221 : wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
901 :
902 221 : sm->pairwise = pairwise;
903 221 : sm->PTK_valid = TRUE;
904 221 : wpa_ft_install_ptk(sm);
905 :
906 221 : buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
907 : 2 + FT_R1KH_ID_LEN + 200;
908 221 : *resp_ies = os_zalloc(buflen);
909 221 : if (*resp_ies == NULL) {
910 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
911 : }
912 :
913 221 : pos = *resp_ies;
914 221 : end = *resp_ies + buflen;
915 :
916 221 : ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
917 221 : if (ret < 0) {
918 0 : os_free(*resp_ies);
919 0 : *resp_ies = NULL;
920 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
921 : }
922 221 : pos += ret;
923 :
924 221 : ret = wpa_write_mdie(conf, pos, end - pos);
925 221 : if (ret < 0) {
926 0 : os_free(*resp_ies);
927 0 : *resp_ies = NULL;
928 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
929 : }
930 221 : pos += ret;
931 :
932 442 : ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
933 442 : sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
934 221 : if (ret < 0) {
935 0 : os_free(*resp_ies);
936 0 : *resp_ies = NULL;
937 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
938 : }
939 221 : pos += ret;
940 :
941 221 : *resp_ies_len = pos - *resp_ies;
942 :
943 221 : return WLAN_STATUS_SUCCESS;
944 : }
945 :
946 :
947 113 : void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
948 : u16 auth_transaction, const u8 *ies, size_t ies_len,
949 : void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
950 : u16 auth_transaction, u16 status,
951 : const u8 *ies, size_t ies_len),
952 : void *ctx)
953 : {
954 : u16 status;
955 : u8 *resp_ies;
956 : size_t resp_ies_len;
957 : int res;
958 :
959 113 : if (sm == NULL) {
960 0 : wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
961 : "WPA SM not available");
962 0 : return;
963 : }
964 :
965 1469 : wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
966 : " BSSID=" MACSTR " transaction=%d",
967 1356 : MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
968 113 : sm->ft_pending_cb = cb;
969 113 : sm->ft_pending_cb_ctx = ctx;
970 113 : sm->ft_pending_auth_transaction = auth_transaction;
971 113 : res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
972 : &resp_ies_len);
973 113 : if (res < 0) {
974 2 : wpa_printf(MSG_DEBUG, "FT: Callback postponed until response is available");
975 2 : return;
976 : }
977 111 : status = res;
978 :
979 777 : wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
980 : " auth_transaction=%d status=%d",
981 666 : MAC2STR(sm->addr), auth_transaction + 1, status);
982 111 : wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
983 111 : cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
984 : resp_ies, resp_ies_len);
985 111 : os_free(resp_ies);
986 : }
987 :
988 :
989 221 : u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
990 : size_t ies_len)
991 : {
992 : struct wpa_ft_ies parse;
993 : struct rsn_mdie *mdie;
994 : struct rsn_ftie *ftie;
995 : u8 mic[16];
996 : unsigned int count;
997 :
998 221 : if (sm == NULL)
999 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
1000 :
1001 221 : wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
1002 :
1003 221 : if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
1004 0 : wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
1005 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
1006 : }
1007 :
1008 221 : if (parse.rsn == NULL) {
1009 0 : wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
1010 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
1011 : }
1012 :
1013 221 : if (parse.rsn_pmkid == NULL) {
1014 0 : wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
1015 0 : return WLAN_STATUS_INVALID_PMKID;
1016 : }
1017 :
1018 221 : if (os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)
1019 : != 0) {
1020 0 : wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
1021 : "with the PMKR1Name derived from auth request");
1022 0 : return WLAN_STATUS_INVALID_PMKID;
1023 : }
1024 :
1025 221 : mdie = (struct rsn_mdie *) parse.mdie;
1026 442 : if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
1027 221 : os_memcmp(mdie->mobility_domain,
1028 : sm->wpa_auth->conf.mobility_domain,
1029 : MOBILITY_DOMAIN_ID_LEN) != 0) {
1030 0 : wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
1031 0 : return WLAN_STATUS_INVALID_MDIE;
1032 : }
1033 :
1034 221 : ftie = (struct rsn_ftie *) parse.ftie;
1035 221 : if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
1036 0 : wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
1037 0 : return WLAN_STATUS_INVALID_FTIE;
1038 : }
1039 :
1040 221 : if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
1041 0 : wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
1042 0 : wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
1043 0 : ftie->snonce, WPA_NONCE_LEN);
1044 0 : wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
1045 0 : sm->SNonce, WPA_NONCE_LEN);
1046 0 : return -1;
1047 : }
1048 :
1049 221 : if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
1050 0 : wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
1051 0 : wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
1052 0 : ftie->anonce, WPA_NONCE_LEN);
1053 0 : wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
1054 0 : sm->ANonce, WPA_NONCE_LEN);
1055 0 : return -1;
1056 : }
1057 :
1058 :
1059 221 : if (parse.r0kh_id == NULL) {
1060 0 : wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
1061 0 : return -1;
1062 : }
1063 :
1064 442 : if (parse.r0kh_id_len != sm->r0kh_id_len ||
1065 221 : os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
1066 : {
1067 0 : wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
1068 : "the current R0KH-ID");
1069 0 : wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
1070 0 : parse.r0kh_id, parse.r0kh_id_len);
1071 0 : wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
1072 0 : sm->r0kh_id, sm->r0kh_id_len);
1073 0 : return -1;
1074 : }
1075 :
1076 221 : if (parse.r1kh_id == NULL) {
1077 0 : wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
1078 0 : return -1;
1079 : }
1080 :
1081 221 : if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
1082 : FT_R1KH_ID_LEN) != 0) {
1083 0 : wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
1084 : "ReassocReq");
1085 0 : wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
1086 0 : parse.r1kh_id, FT_R1KH_ID_LEN);
1087 0 : wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
1088 0 : sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
1089 0 : return -1;
1090 : }
1091 :
1092 442 : if (parse.rsn_pmkid == NULL ||
1093 221 : os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
1094 : {
1095 0 : wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
1096 0 : "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
1097 0 : return -1;
1098 : }
1099 :
1100 221 : count = 3;
1101 221 : if (parse.ric)
1102 0 : count += ieee802_11_ie_count(parse.ric, parse.ric_len);
1103 221 : if (ftie->mic_control[1] != count) {
1104 0 : wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
1105 : "Control: received %u expected %u",
1106 0 : ftie->mic_control[1], count);
1107 0 : return -1;
1108 : }
1109 :
1110 1547 : if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
1111 442 : parse.mdie - 2, parse.mdie_len + 2,
1112 442 : parse.ftie - 2, parse.ftie_len + 2,
1113 442 : parse.rsn - 2, parse.rsn_len + 2,
1114 : parse.ric, parse.ric_len,
1115 : mic) < 0) {
1116 0 : wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
1117 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
1118 : }
1119 :
1120 221 : if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
1121 0 : wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
1122 0 : wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
1123 0 : MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
1124 0 : wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
1125 0 : wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
1126 0 : wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
1127 0 : parse.mdie - 2, parse.mdie_len + 2);
1128 0 : wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
1129 0 : parse.ftie - 2, parse.ftie_len + 2);
1130 0 : wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
1131 0 : parse.rsn - 2, parse.rsn_len + 2);
1132 0 : return WLAN_STATUS_INVALID_FTIE;
1133 : }
1134 :
1135 221 : return WLAN_STATUS_SUCCESS;
1136 : }
1137 :
1138 :
1139 113 : int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
1140 : {
1141 : const u8 *sta_addr, *target_ap;
1142 : const u8 *ies;
1143 : size_t ies_len;
1144 : u8 action;
1145 : struct ft_rrb_frame *frame;
1146 :
1147 113 : if (sm == NULL)
1148 0 : return -1;
1149 :
1150 : /*
1151 : * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1152 : * FT Request action frame body[variable]
1153 : */
1154 :
1155 113 : if (len < 14) {
1156 0 : wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
1157 : "(len=%lu)", (unsigned long) len);
1158 0 : return -1;
1159 : }
1160 :
1161 113 : action = data[1];
1162 113 : sta_addr = data + 2;
1163 113 : target_ap = data + 8;
1164 113 : ies = data + 14;
1165 113 : ies_len = len - 14;
1166 :
1167 1469 : wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
1168 : " Target AP=" MACSTR " Action=%d)",
1169 1356 : MAC2STR(sta_addr), MAC2STR(target_ap), action);
1170 :
1171 113 : if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
1172 0 : wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
1173 : "STA=" MACSTR " STA-Address=" MACSTR,
1174 0 : MAC2STR(sm->addr), MAC2STR(sta_addr));
1175 0 : return -1;
1176 : }
1177 :
1178 : /*
1179 : * Do some sanity checking on the target AP address (not own and not
1180 : * broadcast. This could be extended to filter based on a list of known
1181 : * APs in the MD (if such a list were configured).
1182 : */
1183 226 : if ((target_ap[0] & 0x01) ||
1184 113 : os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
1185 0 : wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
1186 : "frame");
1187 0 : return -1;
1188 : }
1189 :
1190 113 : wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
1191 :
1192 : /* RRB - Forward action frame to the target AP */
1193 113 : frame = os_malloc(sizeof(*frame) + len);
1194 113 : if (frame == NULL)
1195 0 : return -1;
1196 113 : frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1197 113 : frame->packet_type = FT_PACKET_REQUEST;
1198 113 : frame->action_length = host_to_le16(len);
1199 113 : os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
1200 113 : os_memcpy(frame + 1, data, len);
1201 :
1202 113 : wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
1203 : sizeof(*frame) + len);
1204 113 : os_free(frame);
1205 :
1206 113 : return 0;
1207 : }
1208 :
1209 :
1210 1 : static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid,
1211 : u16 auth_transaction, u16 resp,
1212 : const u8 *ies, size_t ies_len)
1213 : {
1214 1 : struct wpa_state_machine *sm = ctx;
1215 6 : wpa_printf(MSG_DEBUG, "FT: Over-the-DS RX request cb for " MACSTR,
1216 6 : MAC2STR(sm->addr));
1217 1 : wpa_ft_send_rrb_auth_resp(sm, sm->ft_pending_current_ap, sm->addr,
1218 : WLAN_STATUS_SUCCESS, ies, ies_len);
1219 1 : }
1220 :
1221 :
1222 113 : static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
1223 : const u8 *current_ap, const u8 *sta_addr,
1224 : const u8 *body, size_t len)
1225 : {
1226 : struct wpa_state_machine *sm;
1227 : u16 status;
1228 : u8 *resp_ies;
1229 : size_t resp_ies_len;
1230 : int res;
1231 :
1232 113 : sm = wpa_ft_add_sta(wpa_auth, sta_addr);
1233 113 : if (sm == NULL) {
1234 0 : wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
1235 : "RRB Request");
1236 0 : return -1;
1237 : }
1238 :
1239 113 : wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
1240 :
1241 113 : sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb;
1242 113 : sm->ft_pending_cb_ctx = sm;
1243 113 : os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN);
1244 113 : res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
1245 : &resp_ies_len);
1246 113 : if (res < 0) {
1247 5 : wpa_printf(MSG_DEBUG, "FT: No immediate response available - wait for pull response");
1248 5 : return 0;
1249 : }
1250 108 : status = res;
1251 :
1252 108 : res = wpa_ft_send_rrb_auth_resp(sm, current_ap, sta_addr, status,
1253 : resp_ies, resp_ies_len);
1254 108 : os_free(resp_ies);
1255 108 : return res;
1256 : }
1257 :
1258 :
1259 109 : static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
1260 : const u8 *current_ap, const u8 *sta_addr,
1261 : u16 status, const u8 *resp_ies,
1262 : size_t resp_ies_len)
1263 : {
1264 109 : struct wpa_authenticator *wpa_auth = sm->wpa_auth;
1265 : size_t rlen;
1266 : struct ft_rrb_frame *frame;
1267 : u8 *pos;
1268 :
1269 1417 : wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
1270 : " CurrentAP=" MACSTR " status=%d",
1271 1308 : MAC2STR(sm->addr), MAC2STR(current_ap), status);
1272 109 : wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
1273 :
1274 : /* RRB - Forward action frame response to the Current AP */
1275 :
1276 : /*
1277 : * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1278 : * Status_Code[2] FT Request action frame body[variable]
1279 : */
1280 109 : rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
1281 :
1282 109 : frame = os_malloc(sizeof(*frame) + rlen);
1283 109 : if (frame == NULL)
1284 0 : return -1;
1285 109 : frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1286 109 : frame->packet_type = FT_PACKET_RESPONSE;
1287 109 : frame->action_length = host_to_le16(rlen);
1288 109 : os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
1289 109 : pos = (u8 *) (frame + 1);
1290 109 : *pos++ = WLAN_ACTION_FT;
1291 109 : *pos++ = 2; /* Action: Response */
1292 109 : os_memcpy(pos, sta_addr, ETH_ALEN);
1293 109 : pos += ETH_ALEN;
1294 109 : os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
1295 109 : pos += ETH_ALEN;
1296 109 : WPA_PUT_LE16(pos, status);
1297 109 : pos += 2;
1298 109 : if (resp_ies)
1299 108 : os_memcpy(pos, resp_ies, resp_ies_len);
1300 :
1301 109 : wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
1302 : sizeof(*frame) + rlen);
1303 109 : os_free(frame);
1304 :
1305 109 : return 0;
1306 : }
1307 :
1308 :
1309 6 : static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
1310 : const u8 *src_addr,
1311 : const u8 *data, size_t data_len)
1312 : {
1313 : struct ft_r0kh_r1kh_pull_frame *frame, f;
1314 : struct ft_remote_r1kh *r1kh;
1315 : struct ft_r0kh_r1kh_resp_frame resp, r;
1316 : u8 pmk_r0[PMK_LEN];
1317 : int pairwise;
1318 :
1319 6 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
1320 :
1321 6 : if (data_len < sizeof(*frame))
1322 0 : return -1;
1323 :
1324 6 : r1kh = wpa_auth->conf.r1kh_list;
1325 13 : while (r1kh) {
1326 6 : if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
1327 5 : break;
1328 1 : r1kh = r1kh->next;
1329 : }
1330 6 : if (r1kh == NULL) {
1331 6 : wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
1332 : "PMK-R1 pull source address " MACSTR,
1333 6 : MAC2STR(src_addr));
1334 1 : return -1;
1335 : }
1336 :
1337 5 : frame = (struct ft_r0kh_r1kh_pull_frame *) data;
1338 : /* aes_unwrap() does not support inplace decryption, so use a temporary
1339 : * buffer for the data. */
1340 5 : if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
1341 : (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
1342 5 : frame->nonce, f.nonce) < 0) {
1343 12 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
1344 12 : "request from " MACSTR, MAC2STR(src_addr));
1345 2 : return -1;
1346 : }
1347 :
1348 3 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
1349 : f.nonce, sizeof(f.nonce));
1350 3 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
1351 : f.pmk_r0_name, WPA_PMK_NAME_LEN);
1352 36 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
1353 36 : MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
1354 :
1355 3 : os_memset(&resp, 0, sizeof(resp));
1356 3 : resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1357 3 : resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
1358 3 : resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
1359 3 : os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
1360 :
1361 : /* aes_wrap() does not support inplace encryption, so use a temporary
1362 : * buffer for the data. */
1363 3 : os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
1364 3 : os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
1365 3 : os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
1366 3 : if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
1367 : &pairwise) < 0) {
1368 0 : wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
1369 : "PMK-R1 pull");
1370 0 : return -1;
1371 : }
1372 :
1373 3 : wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
1374 : r.pmk_r1, r.pmk_r1_name);
1375 3 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
1376 3 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
1377 : WPA_PMK_NAME_LEN);
1378 3 : r.pairwise = host_to_le16(pairwise);
1379 3 : os_memset(r.pad, 0, sizeof(r.pad));
1380 :
1381 3 : if (aes_wrap(r1kh->key, sizeof(r1kh->key),
1382 : (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
1383 : r.nonce, resp.nonce) < 0) {
1384 0 : os_memset(pmk_r0, 0, PMK_LEN);
1385 0 : return -1;
1386 : }
1387 :
1388 3 : os_memset(pmk_r0, 0, PMK_LEN);
1389 :
1390 3 : wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
1391 :
1392 3 : return 0;
1393 : }
1394 :
1395 :
1396 3 : static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
1397 : {
1398 3 : struct wpa_state_machine *sm = eloop_ctx;
1399 : int res;
1400 : u8 *resp_ies;
1401 : size_t resp_ies_len;
1402 : u16 status;
1403 :
1404 3 : res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies),
1405 3 : wpabuf_len(sm->ft_pending_req_ies),
1406 : &resp_ies, &resp_ies_len);
1407 3 : wpabuf_free(sm->ft_pending_req_ies);
1408 3 : sm->ft_pending_req_ies = NULL;
1409 3 : if (res < 0)
1410 0 : res = WLAN_STATUS_UNSPECIFIED_FAILURE;
1411 3 : status = res;
1412 21 : wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR
1413 18 : " - status %u", MAC2STR(sm->addr), status);
1414 :
1415 6 : sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr,
1416 3 : sm->ft_pending_auth_transaction + 1, status,
1417 : resp_ies, resp_ies_len);
1418 3 : os_free(resp_ies);
1419 3 : }
1420 :
1421 :
1422 3 : static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
1423 : {
1424 3 : struct ft_r0kh_r1kh_resp_frame *frame = ctx;
1425 :
1426 3 : if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
1427 0 : return 0;
1428 3 : if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
1429 : FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
1430 0 : return 0;
1431 3 : if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
1432 0 : return 0;
1433 :
1434 18 : wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
1435 18 : MACSTR " - process from timeout", MAC2STR(sm->addr));
1436 3 : eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL);
1437 3 : return 1;
1438 : }
1439 :
1440 :
1441 3 : static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
1442 : const u8 *src_addr,
1443 : const u8 *data, size_t data_len)
1444 : {
1445 : struct ft_r0kh_r1kh_resp_frame *frame, f;
1446 : struct ft_remote_r0kh *r0kh;
1447 : int pairwise, res;
1448 :
1449 3 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
1450 :
1451 3 : if (data_len < sizeof(*frame))
1452 0 : return -1;
1453 :
1454 3 : r0kh = wpa_auth->conf.r0kh_list;
1455 9 : while (r0kh) {
1456 6 : if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
1457 3 : break;
1458 3 : r0kh = r0kh->next;
1459 : }
1460 3 : if (r0kh == NULL) {
1461 0 : wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
1462 : "PMK-R0 pull response source address " MACSTR,
1463 0 : MAC2STR(src_addr));
1464 0 : return -1;
1465 : }
1466 :
1467 3 : frame = (struct ft_r0kh_r1kh_resp_frame *) data;
1468 : /* aes_unwrap() does not support inplace decryption, so use a temporary
1469 : * buffer for the data. */
1470 3 : if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
1471 : (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
1472 3 : frame->nonce, f.nonce) < 0) {
1473 0 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
1474 0 : "response from " MACSTR, MAC2STR(src_addr));
1475 0 : return -1;
1476 : }
1477 :
1478 3 : if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
1479 : FT_R1KH_ID_LEN) != 0) {
1480 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
1481 : "matching R1KH-ID");
1482 0 : return -1;
1483 : }
1484 :
1485 3 : pairwise = le_to_host16(f.pairwise);
1486 3 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
1487 : f.nonce, sizeof(f.nonce));
1488 36 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
1489 : MACSTR " pairwise=0x%x",
1490 36 : MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
1491 3 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
1492 : f.pmk_r1, PMK_LEN);
1493 3 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
1494 : f.pmk_r1_name, WPA_PMK_NAME_LEN);
1495 :
1496 3 : res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
1497 : pairwise);
1498 3 : wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
1499 3 : wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
1500 3 : os_memset(f.pmk_r1, 0, PMK_LEN);
1501 :
1502 3 : return res ? 0 : -1;
1503 : }
1504 :
1505 :
1506 12 : static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
1507 : const u8 *src_addr,
1508 : const u8 *data, size_t data_len)
1509 : {
1510 : struct ft_r0kh_r1kh_push_frame *frame, f;
1511 : struct ft_remote_r0kh *r0kh;
1512 : struct os_time now;
1513 : os_time_t tsend;
1514 : int pairwise;
1515 :
1516 12 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
1517 :
1518 12 : if (data_len < sizeof(*frame))
1519 0 : return -1;
1520 :
1521 12 : r0kh = wpa_auth->conf.r0kh_list;
1522 37 : while (r0kh) {
1523 24 : if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
1524 11 : break;
1525 13 : r0kh = r0kh->next;
1526 : }
1527 12 : if (r0kh == NULL) {
1528 6 : wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
1529 : "PMK-R0 push source address " MACSTR,
1530 6 : MAC2STR(src_addr));
1531 1 : return -1;
1532 : }
1533 :
1534 11 : frame = (struct ft_r0kh_r1kh_push_frame *) data;
1535 : /* aes_unwrap() does not support inplace decryption, so use a temporary
1536 : * buffer for the data. */
1537 11 : if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
1538 : (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
1539 11 : frame->timestamp, f.timestamp) < 0) {
1540 6 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
1541 6 : MACSTR, MAC2STR(src_addr));
1542 1 : return -1;
1543 : }
1544 :
1545 10 : os_get_time(&now);
1546 10 : tsend = WPA_GET_LE32(f.timestamp);
1547 20 : if ((now.sec > tsend && now.sec - tsend > 60) ||
1548 10 : (now.sec < tsend && tsend - now.sec > 60)) {
1549 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
1550 : "timestamp: sender time %d own time %d\n",
1551 0 : (int) tsend, (int) now.sec);
1552 0 : return -1;
1553 : }
1554 :
1555 10 : if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
1556 : FT_R1KH_ID_LEN) != 0) {
1557 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
1558 : "R1KH-ID (received " MACSTR " own " MACSTR ")",
1559 0 : MAC2STR(f.r1kh_id),
1560 0 : MAC2STR(wpa_auth->conf.r1_key_holder));
1561 0 : return -1;
1562 : }
1563 :
1564 10 : pairwise = le_to_host16(f.pairwise);
1565 120 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
1566 : MACSTR " pairwise=0x%x",
1567 120 : MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
1568 10 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
1569 : f.pmk_r1, PMK_LEN);
1570 10 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
1571 : f.pmk_r1_name, WPA_PMK_NAME_LEN);
1572 :
1573 10 : wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
1574 : pairwise);
1575 10 : os_memset(f.pmk_r1, 0, PMK_LEN);
1576 :
1577 10 : return 0;
1578 : }
1579 :
1580 :
1581 244 : int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
1582 : const u8 *data, size_t data_len)
1583 : {
1584 : struct ft_rrb_frame *frame;
1585 : u16 alen;
1586 : const u8 *pos, *end, *start;
1587 : u8 action;
1588 : const u8 *sta_addr, *target_ap_addr;
1589 :
1590 1464 : wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
1591 1464 : MAC2STR(src_addr));
1592 :
1593 244 : if (data_len < sizeof(*frame)) {
1594 0 : wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
1595 : (unsigned long) data_len);
1596 0 : return -1;
1597 : }
1598 :
1599 244 : pos = data;
1600 244 : frame = (struct ft_rrb_frame *) pos;
1601 244 : pos += sizeof(*frame);
1602 :
1603 244 : alen = le_to_host16(frame->action_length);
1604 1952 : wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
1605 : "action_length=%d ap_address=" MACSTR,
1606 488 : frame->frame_type, frame->packet_type, alen,
1607 1464 : MAC2STR(frame->ap_address));
1608 :
1609 244 : if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
1610 : /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
1611 1 : wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
1612 1 : "unrecognized type %d", frame->frame_type);
1613 1 : return -1;
1614 : }
1615 :
1616 243 : if (alen > data_len - sizeof(*frame)) {
1617 0 : wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
1618 : "frame");
1619 0 : return -1;
1620 : }
1621 :
1622 243 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
1623 6 : return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
1624 237 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
1625 3 : return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
1626 234 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
1627 12 : return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
1628 :
1629 222 : wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
1630 :
1631 222 : if (alen < 1 + 1 + 2 * ETH_ALEN) {
1632 0 : wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
1633 : "room for Action Frame body); alen=%lu",
1634 : (unsigned long) alen);
1635 0 : return -1;
1636 : }
1637 222 : start = pos;
1638 222 : end = pos + alen;
1639 :
1640 222 : if (*pos != WLAN_ACTION_FT) {
1641 0 : wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
1642 0 : "%d", *pos);
1643 0 : return -1;
1644 : }
1645 :
1646 222 : pos++;
1647 222 : action = *pos++;
1648 222 : sta_addr = pos;
1649 222 : pos += ETH_ALEN;
1650 222 : target_ap_addr = pos;
1651 222 : pos += ETH_ALEN;
1652 2664 : wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
1653 : MACSTR " target_ap_addr=" MACSTR,
1654 2664 : action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
1655 :
1656 222 : if (frame->packet_type == FT_PACKET_REQUEST) {
1657 113 : wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
1658 :
1659 113 : if (action != 1) {
1660 0 : wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
1661 : "RRB Request", action);
1662 0 : return -1;
1663 : }
1664 :
1665 113 : if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
1666 0 : wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
1667 : "RRB Request does not match with own "
1668 : "address");
1669 0 : return -1;
1670 : }
1671 :
1672 113 : if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
1673 113 : sta_addr, pos, end - pos) < 0)
1674 0 : return -1;
1675 109 : } else if (frame->packet_type == FT_PACKET_RESPONSE) {
1676 : u16 status_code;
1677 :
1678 109 : if (end - pos < 2) {
1679 0 : wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
1680 : "code in RRB Response");
1681 0 : return -1;
1682 : }
1683 109 : status_code = WPA_GET_LE16(pos);
1684 109 : pos += 2;
1685 :
1686 109 : wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
1687 : "(status_code=%d)", status_code);
1688 :
1689 109 : if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
1690 0 : return -1;
1691 : } else {
1692 0 : wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
1693 0 : "packet_type %d", frame->packet_type);
1694 0 : return -1;
1695 : }
1696 :
1697 222 : if (end > pos) {
1698 221 : wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
1699 221 : pos, end - pos);
1700 : }
1701 :
1702 222 : return 0;
1703 : }
1704 :
1705 :
1706 13 : static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
1707 : struct wpa_ft_pmk_r0_sa *pmk_r0,
1708 : struct ft_remote_r1kh *r1kh,
1709 : const u8 *s1kh_id, int pairwise)
1710 : {
1711 : struct ft_r0kh_r1kh_push_frame frame, f;
1712 : struct os_time now;
1713 :
1714 13 : os_memset(&frame, 0, sizeof(frame));
1715 13 : frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1716 13 : frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
1717 13 : frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
1718 13 : os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
1719 :
1720 : /* aes_wrap() does not support inplace encryption, so use a temporary
1721 : * buffer for the data. */
1722 13 : os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
1723 13 : os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
1724 13 : os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
1725 13 : wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
1726 : s1kh_id, f.pmk_r1, f.pmk_r1_name);
1727 13 : wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
1728 13 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
1729 13 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
1730 : WPA_PMK_NAME_LEN);
1731 13 : os_get_time(&now);
1732 13 : WPA_PUT_LE32(f.timestamp, now.sec);
1733 13 : f.pairwise = host_to_le16(pairwise);
1734 13 : os_memset(f.pad, 0, sizeof(f.pad));
1735 13 : if (aes_wrap(r1kh->key, sizeof(r1kh->key),
1736 : (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
1737 : f.timestamp, frame.timestamp) < 0)
1738 13 : return;
1739 :
1740 13 : wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
1741 : }
1742 :
1743 :
1744 565 : void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
1745 : {
1746 : struct wpa_ft_pmk_r0_sa *r0;
1747 : struct ft_remote_r1kh *r1kh;
1748 :
1749 565 : if (!wpa_auth->conf.pmk_r1_push)
1750 552 : return;
1751 :
1752 13 : r0 = wpa_auth->ft_pmk_cache->pmk_r0;
1753 26 : while (r0) {
1754 13 : if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
1755 13 : break;
1756 0 : r0 = r0->next;
1757 : }
1758 :
1759 13 : if (r0 == NULL || r0->pmk_r1_pushed)
1760 0 : return;
1761 13 : r0->pmk_r1_pushed = 1;
1762 :
1763 78 : wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
1764 78 : "for STA " MACSTR, MAC2STR(addr));
1765 :
1766 13 : r1kh = wpa_auth->conf.r1kh_list;
1767 39 : while (r1kh) {
1768 13 : wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
1769 13 : r1kh = r1kh->next;
1770 : }
1771 : }
1772 :
1773 : #endif /* CONFIG_IEEE80211R */
|