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 40 : static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
33 : const u8 *data, size_t data_len)
34 : {
35 40 : if (wpa_auth->cb.send_ether == NULL)
36 0 : return -1;
37 40 : wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
38 40 : return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
39 : data, data_len);
40 : }
41 :
42 :
43 9 : static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
44 : const u8 *dst, const u8 *data, size_t data_len)
45 : {
46 9 : if (wpa_auth->cb.send_ft_action == NULL)
47 0 : return -1;
48 9 : 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 13 : wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
55 : {
56 13 : if (wpa_auth->cb.add_sta == NULL)
57 0 : return NULL;
58 13 : 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 87 : int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
76 : {
77 87 : u8 *pos = buf;
78 : u8 capab;
79 87 : if (len < 2 + sizeof(struct rsn_mdie))
80 0 : return -1;
81 :
82 87 : *pos++ = WLAN_EID_MOBILITY_DOMAIN;
83 87 : *pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
84 87 : os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
85 87 : pos += MOBILITY_DOMAIN_ID_LEN;
86 87 : capab = 0;
87 87 : if (conf->ft_over_ds)
88 87 : capab |= RSN_FT_CAPAB_FT_OVER_DS;
89 87 : *pos++ = capab;
90 :
91 87 : return pos - buf;
92 : }
93 :
94 :
95 72 : 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 72 : u8 *pos = buf, *ielen;
102 : struct rsn_ftie *hdr;
103 :
104 72 : if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
105 : subelem_len)
106 0 : return -1;
107 :
108 72 : *pos++ = WLAN_EID_FAST_BSS_TRANSITION;
109 72 : ielen = pos++;
110 :
111 72 : hdr = (struct rsn_ftie *) pos;
112 72 : os_memset(hdr, 0, sizeof(*hdr));
113 72 : pos += sizeof(*hdr);
114 72 : WPA_PUT_LE16(hdr->mic_control, 0);
115 72 : if (anonce)
116 40 : os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
117 72 : if (snonce)
118 40 : os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
119 :
120 : /* Optional Parameters */
121 72 : *pos++ = FTIE_SUBELEM_R1KH_ID;
122 72 : *pos++ = FT_R1KH_ID_LEN;
123 72 : os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
124 72 : pos += FT_R1KH_ID_LEN;
125 :
126 72 : if (r0kh_id) {
127 72 : *pos++ = FTIE_SUBELEM_R0KH_ID;
128 72 : *pos++ = r0kh_id_len;
129 72 : os_memcpy(pos, r0kh_id, r0kh_id_len);
130 72 : pos += r0kh_id_len;
131 : }
132 :
133 72 : if (subelem) {
134 20 : os_memcpy(pos, subelem, subelem_len);
135 20 : pos += subelem_len;
136 : }
137 :
138 72 : *ielen = pos - buf - 2;
139 :
140 72 : 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 508 : struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
169 : {
170 : struct wpa_ft_pmk_cache *cache;
171 :
172 508 : cache = os_zalloc(sizeof(*cache));
173 :
174 508 : return cache;
175 : }
176 :
177 :
178 508 : 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 508 : r0 = cache->pmk_r0;
184 1032 : while (r0) {
185 16 : r0prev = r0;
186 16 : r0 = r0->next;
187 16 : os_memset(r0prev->pmk_r0, 0, PMK_LEN);
188 16 : os_free(r0prev);
189 : }
190 :
191 508 : r1 = cache->pmk_r1;
192 1042 : while (r1) {
193 26 : r1prev = r1;
194 26 : r1 = r1->next;
195 26 : os_memset(r1prev->pmk_r1, 0, PMK_LEN);
196 26 : os_free(r1prev);
197 : }
198 :
199 508 : os_free(cache);
200 508 : }
201 :
202 :
203 16 : 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 16 : 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 16 : r0 = os_zalloc(sizeof(*r0));
213 16 : if (r0 == NULL)
214 0 : return -1;
215 :
216 16 : os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
217 16 : os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
218 16 : os_memcpy(r0->spa, spa, ETH_ALEN);
219 16 : r0->pairwise = pairwise;
220 :
221 16 : r0->next = cache->pmk_r0;
222 16 : cache->pmk_r0 = r0;
223 :
224 16 : return 0;
225 : }
226 :
227 :
228 2 : 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 2 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
233 : struct wpa_ft_pmk_r0_sa *r0;
234 :
235 2 : r0 = cache->pmk_r0;
236 4 : while (r0) {
237 4 : if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
238 2 : os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
239 : == 0) {
240 2 : os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
241 2 : if (pairwise)
242 2 : *pairwise = r0->pairwise;
243 2 : return 0;
244 : }
245 :
246 0 : r0 = r0->next;
247 : }
248 :
249 0 : return -1;
250 : }
251 :
252 :
253 26 : 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 26 : 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 26 : r1 = os_zalloc(sizeof(*r1));
263 26 : if (r1 == NULL)
264 0 : return -1;
265 :
266 26 : os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
267 26 : os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
268 26 : os_memcpy(r1->spa, spa, ETH_ALEN);
269 26 : r1->pairwise = pairwise;
270 :
271 26 : r1->next = cache->pmk_r1;
272 26 : cache->pmk_r1 = r1;
273 :
274 26 : return 0;
275 : }
276 :
277 :
278 27 : 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 27 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
283 : struct wpa_ft_pmk_r1_sa *r1;
284 :
285 27 : r1 = cache->pmk_r1;
286 54 : while (r1) {
287 40 : if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
288 20 : os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
289 : == 0) {
290 20 : os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
291 20 : if (pairwise)
292 20 : *pairwise = r1->pairwise;
293 20 : return 0;
294 : }
295 :
296 0 : r1 = r1->next;
297 : }
298 :
299 7 : return -1;
300 : }
301 :
302 :
303 7 : 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 7 : r0kh = sm->wpa_auth->conf.r0kh_list;
311 22 : while (r0kh) {
312 28 : if (r0kh->id_len == sm->r0kh_id_len &&
313 14 : os_memcmp(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) == 0)
314 6 : break;
315 8 : r0kh = r0kh->next;
316 : }
317 7 : 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 36 : wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
324 36 : "address " MACSTR, MAC2STR(r0kh->addr));
325 :
326 6 : os_memset(&frame, 0, sizeof(frame));
327 6 : frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
328 6 : frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
329 6 : frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
330 6 : 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 6 : 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 6 : os_memcpy(sm->ft_pending_pull_nonce, f.nonce,
340 : FT_R0KH_R1KH_PULL_NONCE_LEN);
341 6 : os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
342 6 : os_memcpy(f.r1kh_id, sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
343 6 : os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
344 6 : os_memset(f.pad, 0, sizeof(f.pad));
345 :
346 6 : 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 6 : wpabuf_free(sm->ft_pending_req_ies);
351 6 : sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len);
352 6 : if (sm->ft_pending_req_ies == NULL)
353 0 : return -1;
354 :
355 6 : wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
356 :
357 6 : return 0;
358 : }
359 :
360 :
361 16 : 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 16 : const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
368 16 : const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
369 16 : size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
370 16 : const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
371 16 : const u8 *ssid = sm->wpa_auth->conf.ssid;
372 16 : size_t ssid_len = sm->wpa_auth->conf.ssid_len;
373 :
374 :
375 16 : 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 16 : wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
382 16 : r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
383 16 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
384 16 : wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
385 16 : wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
386 : sm->pairwise);
387 :
388 16 : wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
389 16 : pmk_r1, sm->pmk_r1_name);
390 16 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
391 16 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
392 : WPA_PMK_NAME_LEN);
393 16 : wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
394 : sm->pairwise);
395 :
396 16 : wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
397 16 : sm->wpa_auth->addr, sm->pmk_r1_name,
398 : (u8 *) ptk, ptk_len, ptk_name);
399 16 : wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
400 16 : wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
401 :
402 16 : return 0;
403 : }
404 :
405 :
406 24 : static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
407 : const u8 *addr, int idx, u8 *seq)
408 : {
409 24 : if (wpa_auth->cb.get_seqnum == NULL)
410 0 : return -1;
411 24 : return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
412 : }
413 :
414 :
415 20 : static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
416 : {
417 : u8 *subelem;
418 20 : 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 20 : key_len = gsm->GTK_len;
425 20 : 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 20 : pad_len = key_len % 8;
433 20 : if (pad_len)
434 0 : pad_len = 8 - pad_len;
435 20 : if (key_len + pad_len < 16)
436 0 : pad_len += 8;
437 20 : 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 20 : 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 20 : subelem_len = 13 + key_len + 8;
451 20 : subelem = os_zalloc(subelem_len);
452 20 : if (subelem == NULL)
453 0 : return NULL;
454 :
455 20 : subelem[0] = FTIE_SUBELEM_GTK;
456 20 : subelem[1] = 11 + key_len + 8;
457 : /* Key ID in B0-B1 of Key Info */
458 20 : WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
459 20 : subelem[4] = gsm->GTK_len;
460 20 : wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
461 20 : if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
462 0 : os_free(subelem);
463 0 : return NULL;
464 : }
465 :
466 20 : *len = subelem_len;
467 20 : 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 1020 : 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 1020 : u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
640 1020 : 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 1020 : if (sm == NULL)
649 375 : return pos;
650 :
651 645 : conf = &sm->wpa_auth->conf;
652 :
653 645 : if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
654 609 : return pos;
655 :
656 36 : end = pos + max_len;
657 :
658 36 : 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 20 : res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
664 20 : if (res < 0)
665 0 : return pos;
666 20 : rsnie = pos;
667 20 : rsnie_len = res;
668 20 : pos += res;
669 : }
670 :
671 : /* Mobility Domain Information */
672 36 : res = wpa_write_mdie(conf, pos, end - pos);
673 36 : if (res < 0)
674 0 : return pos;
675 36 : mdie = pos;
676 36 : mdie_len = res;
677 36 : pos += res;
678 :
679 : /* Fast BSS Transition Information */
680 36 : if (auth_alg == WLAN_AUTH_FT) {
681 20 : subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
682 20 : r0kh_id = sm->r0kh_id;
683 20 : r0kh_id_len = sm->r0kh_id_len;
684 20 : anonce = sm->ANonce;
685 20 : snonce = sm->SNonce;
686 : #ifdef CONFIG_IEEE80211W
687 20 : 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 16 : r0kh_id = conf->r0_key_holder;
710 16 : r0kh_id_len = conf->r0_key_holder_len;
711 16 : anonce = NULL;
712 16 : snonce = NULL;
713 : }
714 72 : res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
715 36 : end - pos, subelem, subelem_len);
716 36 : os_free(subelem);
717 36 : if (res < 0)
718 0 : return pos;
719 36 : ftie = pos;
720 36 : ftie_len = res;
721 36 : pos += res;
722 :
723 36 : os_free(sm->assoc_resp_ftie);
724 36 : sm->assoc_resp_ftie = os_malloc(ftie_len);
725 36 : if (sm->assoc_resp_ftie)
726 36 : os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
727 :
728 36 : _ftie = (struct rsn_ftie *) (ftie + 2);
729 36 : if (auth_alg == WLAN_AUTH_FT)
730 20 : _ftie->mic_control[1] = 3; /* Information element count */
731 :
732 36 : ric_start = pos;
733 36 : 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 36 : if (ric_start == pos)
742 36 : ric_start = NULL;
743 :
744 56 : if (auth_alg == WLAN_AUTH_FT &&
745 20 : 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 20 : _ftie->mic) < 0)
750 0 : wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
751 :
752 36 : return pos;
753 : }
754 :
755 :
756 40 : 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 40 : if (wpa_auth->cb.set_key == NULL)
762 0 : return -1;
763 40 : return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
764 : key, key_len);
765 : }
766 :
767 :
768 40 : 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 40 : alg = wpa_cipher_to_alg(sm->pairwise);
775 40 : klen = wpa_cipher_key_len(sm->pairwise);
776 40 : 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 80 : if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
789 40 : sm->PTK.tk1, klen))
790 10 : return;
791 :
792 : /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
793 30 : sm->pairwise_set = TRUE;
794 : }
795 :
796 :
797 27 : 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 27 : *resp_ies = NULL;
813 27 : *resp_ies_len = 0;
814 :
815 27 : sm->pmk_r1_name_valid = 0;
816 27 : conf = &sm->wpa_auth->conf;
817 :
818 27 : wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
819 : ies, ies_len);
820 :
821 27 : 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 27 : mdie = (struct rsn_mdie *) parse.mdie;
827 54 : if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
828 27 : 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 27 : ftie = (struct rsn_ftie *) parse.ftie;
836 27 : 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 27 : os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
842 :
843 27 : 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 54 : wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
849 27 : parse.r0kh_id, parse.r0kh_id_len);
850 27 : os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
851 27 : sm->r0kh_id_len = parse.r0kh_id_len;
852 :
853 27 : 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 27 : wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
859 27 : parse.rsn_pmkid, WPA_PMK_NAME_LEN);
860 27 : wpa_derive_pmk_r1_name(parse.rsn_pmkid,
861 27 : sm->wpa_auth->conf.r1_key_holder, sm->addr,
862 : pmk_r1_name);
863 27 : wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
864 : pmk_r1_name, WPA_PMK_NAME_LEN);
865 :
866 27 : if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
867 : &pairwise) < 0) {
868 7 : 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 6 : return -1; /* Status pending */
875 : }
876 :
877 20 : wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
878 20 : sm->pmk_r1_name_valid = 1;
879 20 : os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
880 :
881 20 : 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 20 : wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
888 20 : sm->SNonce, WPA_NONCE_LEN);
889 20 : wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
890 20 : sm->ANonce, WPA_NONCE_LEN);
891 :
892 20 : ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
893 20 : wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
894 20 : sm->wpa_auth->addr, pmk_r1_name,
895 20 : (u8 *) &sm->PTK, ptk_len, ptk_name);
896 20 : wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
897 20 : (u8 *) &sm->PTK, ptk_len);
898 20 : wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
899 :
900 20 : sm->pairwise = pairwise;
901 20 : wpa_ft_install_ptk(sm);
902 :
903 20 : buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
904 : 2 + FT_R1KH_ID_LEN + 200;
905 20 : *resp_ies = os_zalloc(buflen);
906 20 : if (*resp_ies == NULL) {
907 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
908 : }
909 :
910 20 : pos = *resp_ies;
911 20 : end = *resp_ies + buflen;
912 :
913 20 : ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
914 20 : if (ret < 0) {
915 0 : os_free(*resp_ies);
916 0 : *resp_ies = NULL;
917 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
918 : }
919 20 : pos += ret;
920 :
921 20 : ret = wpa_write_mdie(conf, pos, end - pos);
922 20 : if (ret < 0) {
923 0 : os_free(*resp_ies);
924 0 : *resp_ies = NULL;
925 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
926 : }
927 20 : pos += ret;
928 :
929 40 : ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
930 40 : sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
931 20 : if (ret < 0) {
932 0 : os_free(*resp_ies);
933 0 : *resp_ies = NULL;
934 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
935 : }
936 20 : pos += ret;
937 :
938 20 : *resp_ies_len = pos - *resp_ies;
939 :
940 20 : return WLAN_STATUS_SUCCESS;
941 : }
942 :
943 :
944 12 : void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
945 : u16 auth_transaction, const u8 *ies, size_t ies_len,
946 : void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
947 : u16 auth_transaction, u16 status,
948 : const u8 *ies, size_t ies_len),
949 : void *ctx)
950 : {
951 : u16 status;
952 : u8 *resp_ies;
953 : size_t resp_ies_len;
954 : int res;
955 :
956 12 : if (sm == NULL) {
957 0 : wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
958 : "WPA SM not available");
959 0 : return;
960 : }
961 :
962 156 : wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
963 : " BSSID=" MACSTR " transaction=%d",
964 144 : MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
965 12 : sm->ft_pending_cb = cb;
966 12 : sm->ft_pending_cb_ctx = ctx;
967 12 : sm->ft_pending_auth_transaction = auth_transaction;
968 12 : res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
969 : &resp_ies_len);
970 12 : if (res < 0) {
971 1 : wpa_printf(MSG_DEBUG, "FT: Callback postponed until response is available");
972 1 : return;
973 : }
974 11 : status = res;
975 :
976 77 : wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
977 : " auth_transaction=%d status=%d",
978 66 : MAC2STR(sm->addr), auth_transaction + 1, status);
979 11 : wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
980 11 : cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
981 : resp_ies, resp_ies_len);
982 11 : os_free(resp_ies);
983 : }
984 :
985 :
986 20 : u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
987 : size_t ies_len)
988 : {
989 : struct wpa_ft_ies parse;
990 : struct rsn_mdie *mdie;
991 : struct rsn_ftie *ftie;
992 : u8 mic[16];
993 : unsigned int count;
994 :
995 20 : if (sm == NULL)
996 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
997 :
998 20 : wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
999 :
1000 20 : if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
1001 0 : wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
1002 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
1003 : }
1004 :
1005 20 : if (parse.rsn == NULL) {
1006 0 : wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
1007 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
1008 : }
1009 :
1010 20 : if (parse.rsn_pmkid == NULL) {
1011 0 : wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
1012 0 : return WLAN_STATUS_INVALID_PMKID;
1013 : }
1014 :
1015 20 : if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
1016 : {
1017 0 : wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
1018 : "with the PMKR1Name derived from auth request");
1019 0 : return WLAN_STATUS_INVALID_PMKID;
1020 : }
1021 :
1022 20 : mdie = (struct rsn_mdie *) parse.mdie;
1023 40 : if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
1024 20 : os_memcmp(mdie->mobility_domain,
1025 : sm->wpa_auth->conf.mobility_domain,
1026 : MOBILITY_DOMAIN_ID_LEN) != 0) {
1027 0 : wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
1028 0 : return WLAN_STATUS_INVALID_MDIE;
1029 : }
1030 :
1031 20 : ftie = (struct rsn_ftie *) parse.ftie;
1032 20 : if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
1033 0 : wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
1034 0 : return WLAN_STATUS_INVALID_FTIE;
1035 : }
1036 :
1037 20 : if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
1038 0 : wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
1039 0 : wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
1040 0 : ftie->snonce, WPA_NONCE_LEN);
1041 0 : wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
1042 0 : sm->SNonce, WPA_NONCE_LEN);
1043 0 : return -1;
1044 : }
1045 :
1046 20 : if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
1047 0 : wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
1048 0 : wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
1049 0 : ftie->anonce, WPA_NONCE_LEN);
1050 0 : wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
1051 0 : sm->ANonce, WPA_NONCE_LEN);
1052 0 : return -1;
1053 : }
1054 :
1055 :
1056 20 : if (parse.r0kh_id == NULL) {
1057 0 : wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
1058 0 : return -1;
1059 : }
1060 :
1061 40 : if (parse.r0kh_id_len != sm->r0kh_id_len ||
1062 20 : os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
1063 0 : wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
1064 : "the current R0KH-ID");
1065 0 : wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
1066 0 : parse.r0kh_id, parse.r0kh_id_len);
1067 0 : wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
1068 0 : sm->r0kh_id, sm->r0kh_id_len);
1069 0 : return -1;
1070 : }
1071 :
1072 20 : if (parse.r1kh_id == NULL) {
1073 0 : wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
1074 0 : return -1;
1075 : }
1076 :
1077 20 : if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
1078 : FT_R1KH_ID_LEN) != 0) {
1079 0 : wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
1080 : "ReassocReq");
1081 0 : wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
1082 0 : parse.r1kh_id, FT_R1KH_ID_LEN);
1083 0 : wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
1084 0 : sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
1085 0 : return -1;
1086 : }
1087 :
1088 40 : if (parse.rsn_pmkid == NULL ||
1089 20 : os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
1090 0 : wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
1091 0 : "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
1092 0 : return -1;
1093 : }
1094 :
1095 20 : count = 3;
1096 20 : if (parse.ric)
1097 0 : count += ieee802_11_ie_count(parse.ric, parse.ric_len);
1098 20 : if (ftie->mic_control[1] != count) {
1099 0 : wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
1100 : "Control: received %u expected %u",
1101 0 : ftie->mic_control[1], count);
1102 0 : return -1;
1103 : }
1104 :
1105 140 : if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
1106 40 : parse.mdie - 2, parse.mdie_len + 2,
1107 40 : parse.ftie - 2, parse.ftie_len + 2,
1108 40 : parse.rsn - 2, parse.rsn_len + 2,
1109 : parse.ric, parse.ric_len,
1110 : mic) < 0) {
1111 0 : wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
1112 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
1113 : }
1114 :
1115 20 : if (os_memcmp(mic, ftie->mic, 16) != 0) {
1116 0 : wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
1117 0 : wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
1118 0 : MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
1119 0 : wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
1120 0 : wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
1121 0 : wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
1122 0 : parse.mdie - 2, parse.mdie_len + 2);
1123 0 : wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
1124 0 : parse.ftie - 2, parse.ftie_len + 2);
1125 0 : wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
1126 0 : parse.rsn - 2, parse.rsn_len + 2);
1127 0 : return WLAN_STATUS_INVALID_FTIE;
1128 : }
1129 :
1130 20 : return WLAN_STATUS_SUCCESS;
1131 : }
1132 :
1133 :
1134 13 : int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
1135 : {
1136 : const u8 *sta_addr, *target_ap;
1137 : const u8 *ies;
1138 : size_t ies_len;
1139 : u8 action;
1140 : struct ft_rrb_frame *frame;
1141 :
1142 13 : if (sm == NULL)
1143 0 : return -1;
1144 :
1145 : /*
1146 : * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1147 : * FT Request action frame body[variable]
1148 : */
1149 :
1150 13 : if (len < 14) {
1151 0 : wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
1152 : "(len=%lu)", (unsigned long) len);
1153 0 : return -1;
1154 : }
1155 :
1156 13 : action = data[1];
1157 13 : sta_addr = data + 2;
1158 13 : target_ap = data + 8;
1159 13 : ies = data + 14;
1160 13 : ies_len = len - 14;
1161 :
1162 169 : wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
1163 : " Target AP=" MACSTR " Action=%d)",
1164 156 : MAC2STR(sta_addr), MAC2STR(target_ap), action);
1165 :
1166 13 : if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
1167 0 : wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
1168 : "STA=" MACSTR " STA-Address=" MACSTR,
1169 0 : MAC2STR(sm->addr), MAC2STR(sta_addr));
1170 0 : return -1;
1171 : }
1172 :
1173 : /*
1174 : * Do some sanity checking on the target AP address (not own and not
1175 : * broadcast. This could be extended to filter based on a list of known
1176 : * APs in the MD (if such a list were configured).
1177 : */
1178 26 : if ((target_ap[0] & 0x01) ||
1179 13 : os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
1180 0 : wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
1181 : "frame");
1182 0 : return -1;
1183 : }
1184 :
1185 13 : wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
1186 :
1187 : /* RRB - Forward action frame to the target AP */
1188 13 : frame = os_malloc(sizeof(*frame) + len);
1189 13 : if (frame == NULL)
1190 0 : return -1;
1191 13 : frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1192 13 : frame->packet_type = FT_PACKET_REQUEST;
1193 13 : frame->action_length = host_to_le16(len);
1194 13 : os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
1195 13 : os_memcpy(frame + 1, data, len);
1196 :
1197 13 : wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
1198 : sizeof(*frame) + len);
1199 13 : os_free(frame);
1200 :
1201 13 : return 0;
1202 : }
1203 :
1204 :
1205 1 : static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid,
1206 : u16 auth_transaction, u16 resp,
1207 : const u8 *ies, size_t ies_len)
1208 : {
1209 1 : struct wpa_state_machine *sm = ctx;
1210 6 : wpa_printf(MSG_DEBUG, "FT: Over-the-DS RX request cb for " MACSTR,
1211 6 : MAC2STR(sm->addr));
1212 1 : wpa_ft_send_rrb_auth_resp(sm, sm->ft_pending_current_ap, sm->addr,
1213 : WLAN_STATUS_SUCCESS, ies, ies_len);
1214 1 : }
1215 :
1216 :
1217 13 : static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
1218 : const u8 *current_ap, const u8 *sta_addr,
1219 : const u8 *body, size_t len)
1220 : {
1221 : struct wpa_state_machine *sm;
1222 : u16 status;
1223 : u8 *resp_ies;
1224 : size_t resp_ies_len;
1225 : int res;
1226 :
1227 13 : sm = wpa_ft_add_sta(wpa_auth, sta_addr);
1228 13 : if (sm == NULL) {
1229 0 : wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
1230 : "RRB Request");
1231 0 : return -1;
1232 : }
1233 :
1234 13 : wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
1235 :
1236 13 : sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb;
1237 13 : sm->ft_pending_cb_ctx = sm;
1238 13 : os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN);
1239 13 : res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
1240 : &resp_ies_len);
1241 13 : if (res < 0) {
1242 5 : wpa_printf(MSG_DEBUG, "FT: No immediate response available - wait for pull response");
1243 5 : return 0;
1244 : }
1245 8 : status = res;
1246 :
1247 8 : res = wpa_ft_send_rrb_auth_resp(sm, current_ap, sta_addr, status,
1248 : resp_ies, resp_ies_len);
1249 8 : os_free(resp_ies);
1250 8 : return res;
1251 : }
1252 :
1253 :
1254 9 : static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
1255 : const u8 *current_ap, const u8 *sta_addr,
1256 : u16 status, const u8 *resp_ies,
1257 : size_t resp_ies_len)
1258 : {
1259 9 : struct wpa_authenticator *wpa_auth = sm->wpa_auth;
1260 : size_t rlen;
1261 : struct ft_rrb_frame *frame;
1262 : u8 *pos;
1263 :
1264 117 : wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
1265 : " CurrentAP=" MACSTR " status=%d",
1266 108 : MAC2STR(sm->addr), MAC2STR(current_ap), status);
1267 9 : wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
1268 :
1269 : /* RRB - Forward action frame response to the Current AP */
1270 :
1271 : /*
1272 : * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1273 : * Status_Code[2] FT Request action frame body[variable]
1274 : */
1275 9 : rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
1276 :
1277 9 : frame = os_malloc(sizeof(*frame) + rlen);
1278 9 : if (frame == NULL)
1279 0 : return -1;
1280 9 : frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1281 9 : frame->packet_type = FT_PACKET_RESPONSE;
1282 9 : frame->action_length = host_to_le16(rlen);
1283 9 : os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
1284 9 : pos = (u8 *) (frame + 1);
1285 9 : *pos++ = WLAN_ACTION_FT;
1286 9 : *pos++ = 2; /* Action: Response */
1287 9 : os_memcpy(pos, sta_addr, ETH_ALEN);
1288 9 : pos += ETH_ALEN;
1289 9 : os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
1290 9 : pos += ETH_ALEN;
1291 9 : WPA_PUT_LE16(pos, status);
1292 9 : pos += 2;
1293 9 : if (resp_ies)
1294 8 : os_memcpy(pos, resp_ies, resp_ies_len);
1295 :
1296 9 : wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
1297 : sizeof(*frame) + rlen);
1298 9 : os_free(frame);
1299 :
1300 9 : return 0;
1301 : }
1302 :
1303 :
1304 5 : static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
1305 : const u8 *src_addr,
1306 : const u8 *data, size_t data_len)
1307 : {
1308 : struct ft_r0kh_r1kh_pull_frame *frame, f;
1309 : struct ft_remote_r1kh *r1kh;
1310 : struct ft_r0kh_r1kh_resp_frame resp, r;
1311 : u8 pmk_r0[PMK_LEN];
1312 : int pairwise;
1313 :
1314 5 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
1315 :
1316 5 : if (data_len < sizeof(*frame))
1317 0 : return -1;
1318 :
1319 5 : r1kh = wpa_auth->conf.r1kh_list;
1320 11 : while (r1kh) {
1321 5 : if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
1322 4 : break;
1323 1 : r1kh = r1kh->next;
1324 : }
1325 5 : if (r1kh == NULL) {
1326 6 : wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
1327 : "PMK-R1 pull source address " MACSTR,
1328 6 : MAC2STR(src_addr));
1329 1 : return -1;
1330 : }
1331 :
1332 4 : frame = (struct ft_r0kh_r1kh_pull_frame *) data;
1333 : /* aes_unwrap() does not support inplace decryption, so use a temporary
1334 : * buffer for the data. */
1335 4 : if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
1336 4 : frame->nonce, f.nonce) < 0) {
1337 12 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
1338 12 : "request from " MACSTR, MAC2STR(src_addr));
1339 2 : return -1;
1340 : }
1341 :
1342 2 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
1343 : f.nonce, sizeof(f.nonce));
1344 2 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
1345 : f.pmk_r0_name, WPA_PMK_NAME_LEN);
1346 24 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
1347 24 : MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
1348 :
1349 2 : os_memset(&resp, 0, sizeof(resp));
1350 2 : resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1351 2 : resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
1352 2 : resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
1353 2 : os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
1354 :
1355 : /* aes_wrap() does not support inplace encryption, so use a temporary
1356 : * buffer for the data. */
1357 2 : os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
1358 2 : os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
1359 2 : os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
1360 2 : if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
1361 : &pairwise) < 0) {
1362 0 : wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
1363 : "PMK-R1 pull");
1364 0 : return -1;
1365 : }
1366 :
1367 2 : wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
1368 : r.pmk_r1, r.pmk_r1_name);
1369 2 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
1370 2 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
1371 : WPA_PMK_NAME_LEN);
1372 2 : r.pairwise = host_to_le16(pairwise);
1373 2 : os_memset(r.pad, 0, sizeof(r.pad));
1374 :
1375 2 : if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
1376 : r.nonce, resp.nonce) < 0) {
1377 0 : os_memset(pmk_r0, 0, PMK_LEN);
1378 0 : return -1;
1379 : }
1380 :
1381 2 : os_memset(pmk_r0, 0, PMK_LEN);
1382 :
1383 2 : wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
1384 :
1385 2 : return 0;
1386 : }
1387 :
1388 :
1389 2 : static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
1390 : {
1391 2 : struct wpa_state_machine *sm = eloop_ctx;
1392 : int res;
1393 : u8 *resp_ies;
1394 : size_t resp_ies_len;
1395 : u16 status;
1396 :
1397 2 : res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies),
1398 2 : wpabuf_len(sm->ft_pending_req_ies),
1399 : &resp_ies, &resp_ies_len);
1400 2 : wpabuf_free(sm->ft_pending_req_ies);
1401 2 : sm->ft_pending_req_ies = NULL;
1402 2 : if (res < 0)
1403 0 : res = WLAN_STATUS_UNSPECIFIED_FAILURE;
1404 2 : status = res;
1405 14 : wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR
1406 12 : " - status %u", MAC2STR(sm->addr), status);
1407 :
1408 4 : sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr,
1409 2 : sm->ft_pending_auth_transaction + 1, status,
1410 : resp_ies, resp_ies_len);
1411 2 : os_free(resp_ies);
1412 2 : }
1413 :
1414 :
1415 2 : static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
1416 : {
1417 2 : struct ft_r0kh_r1kh_resp_frame *frame = ctx;
1418 :
1419 2 : if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
1420 0 : return 0;
1421 2 : if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
1422 : FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
1423 0 : return 0;
1424 2 : if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
1425 0 : return 0;
1426 :
1427 12 : wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
1428 12 : MACSTR " - process from timeout", MAC2STR(sm->addr));
1429 2 : eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL);
1430 2 : return 1;
1431 : }
1432 :
1433 :
1434 2 : static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
1435 : const u8 *src_addr,
1436 : const u8 *data, size_t data_len)
1437 : {
1438 : struct ft_r0kh_r1kh_resp_frame *frame, f;
1439 : struct ft_remote_r0kh *r0kh;
1440 : int pairwise, res;
1441 :
1442 2 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
1443 :
1444 2 : if (data_len < sizeof(*frame))
1445 0 : return -1;
1446 :
1447 2 : r0kh = wpa_auth->conf.r0kh_list;
1448 6 : while (r0kh) {
1449 4 : if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
1450 2 : break;
1451 2 : r0kh = r0kh->next;
1452 : }
1453 2 : if (r0kh == NULL) {
1454 0 : wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
1455 : "PMK-R0 pull response source address " MACSTR,
1456 0 : MAC2STR(src_addr));
1457 0 : return -1;
1458 : }
1459 :
1460 2 : frame = (struct ft_r0kh_r1kh_resp_frame *) data;
1461 : /* aes_unwrap() does not support inplace decryption, so use a temporary
1462 : * buffer for the data. */
1463 2 : if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
1464 2 : frame->nonce, f.nonce) < 0) {
1465 0 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
1466 0 : "response from " MACSTR, MAC2STR(src_addr));
1467 0 : return -1;
1468 : }
1469 :
1470 2 : if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
1471 : != 0) {
1472 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
1473 : "matching R1KH-ID");
1474 0 : return -1;
1475 : }
1476 :
1477 2 : pairwise = le_to_host16(f.pairwise);
1478 2 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
1479 : f.nonce, sizeof(f.nonce));
1480 24 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
1481 : MACSTR " pairwise=0x%x",
1482 24 : MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
1483 2 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
1484 : f.pmk_r1, PMK_LEN);
1485 2 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
1486 : f.pmk_r1_name, WPA_PMK_NAME_LEN);
1487 :
1488 2 : res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
1489 : pairwise);
1490 2 : wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
1491 2 : wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
1492 2 : os_memset(f.pmk_r1, 0, PMK_LEN);
1493 :
1494 2 : return res ? 0 : -1;
1495 : }
1496 :
1497 :
1498 10 : static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
1499 : const u8 *src_addr,
1500 : const u8 *data, size_t data_len)
1501 : {
1502 : struct ft_r0kh_r1kh_push_frame *frame, f;
1503 : struct ft_remote_r0kh *r0kh;
1504 : struct os_time now;
1505 : os_time_t tsend;
1506 : int pairwise;
1507 :
1508 10 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
1509 :
1510 10 : if (data_len < sizeof(*frame))
1511 0 : return -1;
1512 :
1513 10 : r0kh = wpa_auth->conf.r0kh_list;
1514 31 : while (r0kh) {
1515 20 : if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
1516 9 : break;
1517 11 : r0kh = r0kh->next;
1518 : }
1519 10 : if (r0kh == NULL) {
1520 6 : wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
1521 : "PMK-R0 push source address " MACSTR,
1522 6 : MAC2STR(src_addr));
1523 1 : return -1;
1524 : }
1525 :
1526 9 : frame = (struct ft_r0kh_r1kh_push_frame *) data;
1527 : /* aes_unwrap() does not support inplace decryption, so use a temporary
1528 : * buffer for the data. */
1529 9 : if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
1530 9 : frame->timestamp, f.timestamp) < 0) {
1531 6 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
1532 6 : MACSTR, MAC2STR(src_addr));
1533 1 : return -1;
1534 : }
1535 :
1536 8 : os_get_time(&now);
1537 8 : tsend = WPA_GET_LE32(f.timestamp);
1538 16 : if ((now.sec > tsend && now.sec - tsend > 60) ||
1539 8 : (now.sec < tsend && tsend - now.sec > 60)) {
1540 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
1541 : "timestamp: sender time %d own time %d\n",
1542 0 : (int) tsend, (int) now.sec);
1543 0 : return -1;
1544 : }
1545 :
1546 8 : if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
1547 : != 0) {
1548 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
1549 : "R1KH-ID (received " MACSTR " own " MACSTR ")",
1550 0 : MAC2STR(f.r1kh_id),
1551 0 : MAC2STR(wpa_auth->conf.r1_key_holder));
1552 0 : return -1;
1553 : }
1554 :
1555 8 : pairwise = le_to_host16(f.pairwise);
1556 96 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
1557 : MACSTR " pairwise=0x%x",
1558 96 : MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
1559 8 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
1560 : f.pmk_r1, PMK_LEN);
1561 8 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
1562 : f.pmk_r1_name, WPA_PMK_NAME_LEN);
1563 :
1564 8 : wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
1565 : pairwise);
1566 8 : os_memset(f.pmk_r1, 0, PMK_LEN);
1567 :
1568 8 : return 0;
1569 : }
1570 :
1571 :
1572 49 : int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
1573 : const u8 *data, size_t data_len)
1574 : {
1575 : struct ft_rrb_frame *frame;
1576 : u16 alen;
1577 : const u8 *pos, *end, *start;
1578 : u8 action;
1579 : const u8 *sta_addr, *target_ap_addr;
1580 :
1581 294 : wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
1582 294 : MAC2STR(src_addr));
1583 :
1584 49 : if (data_len < sizeof(*frame)) {
1585 0 : wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
1586 : (unsigned long) data_len);
1587 0 : return -1;
1588 : }
1589 :
1590 49 : pos = data;
1591 49 : frame = (struct ft_rrb_frame *) pos;
1592 49 : pos += sizeof(*frame);
1593 :
1594 49 : alen = le_to_host16(frame->action_length);
1595 392 : wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
1596 : "action_length=%d ap_address=" MACSTR,
1597 98 : frame->frame_type, frame->packet_type, alen,
1598 294 : MAC2STR(frame->ap_address));
1599 :
1600 49 : if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
1601 : /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
1602 10 : wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
1603 10 : "unrecognized type %d", frame->frame_type);
1604 10 : return -1;
1605 : }
1606 :
1607 39 : if (alen > data_len - sizeof(*frame)) {
1608 0 : wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
1609 : "frame");
1610 0 : return -1;
1611 : }
1612 :
1613 39 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
1614 5 : return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
1615 34 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
1616 2 : return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
1617 32 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
1618 10 : return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
1619 :
1620 22 : wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
1621 :
1622 22 : if (alen < 1 + 1 + 2 * ETH_ALEN) {
1623 0 : wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
1624 : "room for Action Frame body); alen=%lu",
1625 : (unsigned long) alen);
1626 0 : return -1;
1627 : }
1628 22 : start = pos;
1629 22 : end = pos + alen;
1630 :
1631 22 : if (*pos != WLAN_ACTION_FT) {
1632 0 : wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
1633 0 : "%d", *pos);
1634 0 : return -1;
1635 : }
1636 :
1637 22 : pos++;
1638 22 : action = *pos++;
1639 22 : sta_addr = pos;
1640 22 : pos += ETH_ALEN;
1641 22 : target_ap_addr = pos;
1642 22 : pos += ETH_ALEN;
1643 264 : wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
1644 : MACSTR " target_ap_addr=" MACSTR,
1645 264 : action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
1646 :
1647 22 : if (frame->packet_type == FT_PACKET_REQUEST) {
1648 13 : wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
1649 :
1650 13 : if (action != 1) {
1651 0 : wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
1652 : "RRB Request", action);
1653 0 : return -1;
1654 : }
1655 :
1656 13 : if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
1657 0 : wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
1658 : "RRB Request does not match with own "
1659 : "address");
1660 0 : return -1;
1661 : }
1662 :
1663 13 : if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
1664 13 : sta_addr, pos, end - pos) < 0)
1665 0 : return -1;
1666 9 : } else if (frame->packet_type == FT_PACKET_RESPONSE) {
1667 : u16 status_code;
1668 :
1669 9 : if (end - pos < 2) {
1670 0 : wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
1671 : "code in RRB Response");
1672 0 : return -1;
1673 : }
1674 9 : status_code = WPA_GET_LE16(pos);
1675 9 : pos += 2;
1676 :
1677 9 : wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
1678 : "(status_code=%d)", status_code);
1679 :
1680 9 : if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
1681 0 : return -1;
1682 : } else {
1683 0 : wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
1684 0 : "packet_type %d", frame->packet_type);
1685 0 : return -1;
1686 : }
1687 :
1688 22 : return 0;
1689 : }
1690 :
1691 :
1692 10 : static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
1693 : struct wpa_ft_pmk_r0_sa *pmk_r0,
1694 : struct ft_remote_r1kh *r1kh,
1695 : const u8 *s1kh_id, int pairwise)
1696 : {
1697 : struct ft_r0kh_r1kh_push_frame frame, f;
1698 : struct os_time now;
1699 :
1700 10 : os_memset(&frame, 0, sizeof(frame));
1701 10 : frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1702 10 : frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
1703 10 : frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
1704 10 : os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
1705 :
1706 : /* aes_wrap() does not support inplace encryption, so use a temporary
1707 : * buffer for the data. */
1708 10 : os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
1709 10 : os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
1710 10 : os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
1711 10 : wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
1712 : s1kh_id, f.pmk_r1, f.pmk_r1_name);
1713 10 : wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
1714 10 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
1715 10 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
1716 : WPA_PMK_NAME_LEN);
1717 10 : os_get_time(&now);
1718 10 : WPA_PUT_LE32(f.timestamp, now.sec);
1719 10 : f.pairwise = host_to_le16(pairwise);
1720 10 : os_memset(f.pad, 0, sizeof(f.pad));
1721 10 : if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
1722 : f.timestamp, frame.timestamp) < 0)
1723 10 : return;
1724 :
1725 10 : wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
1726 : }
1727 :
1728 :
1729 627 : void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
1730 : {
1731 : struct wpa_ft_pmk_r0_sa *r0;
1732 : struct ft_remote_r1kh *r1kh;
1733 :
1734 627 : if (!wpa_auth->conf.pmk_r1_push)
1735 617 : return;
1736 :
1737 10 : r0 = wpa_auth->ft_pmk_cache->pmk_r0;
1738 20 : while (r0) {
1739 10 : if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
1740 10 : break;
1741 0 : r0 = r0->next;
1742 : }
1743 :
1744 10 : if (r0 == NULL || r0->pmk_r1_pushed)
1745 0 : return;
1746 10 : r0->pmk_r1_pushed = 1;
1747 :
1748 60 : wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
1749 60 : "for STA " MACSTR, MAC2STR(addr));
1750 :
1751 10 : r1kh = wpa_auth->conf.r1kh_list;
1752 30 : while (r1kh) {
1753 10 : wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
1754 10 : r1kh = r1kh->next;
1755 : }
1756 : }
1757 :
1758 : #endif /* CONFIG_IEEE80211R */
|