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