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 0 : static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
33 : const u8 *data, size_t data_len)
34 : {
35 0 : if (wpa_auth->cb.send_ether == NULL)
36 0 : return -1;
37 0 : wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
38 0 : return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
39 : data, data_len);
40 : }
41 :
42 :
43 0 : static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
44 : const u8 *dst, const u8 *data, size_t data_len)
45 : {
46 0 : if (wpa_auth->cb.send_ft_action == NULL)
47 0 : return -1;
48 0 : 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 0 : wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
55 : {
56 0 : if (wpa_auth->cb.add_sta == NULL)
57 0 : return NULL;
58 0 : 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 0 : int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
76 : {
77 0 : u8 *pos = buf;
78 : u8 capab;
79 0 : if (len < 2 + sizeof(struct rsn_mdie))
80 0 : return -1;
81 :
82 0 : *pos++ = WLAN_EID_MOBILITY_DOMAIN;
83 0 : *pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
84 0 : os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
85 0 : pos += MOBILITY_DOMAIN_ID_LEN;
86 0 : capab = 0;
87 0 : if (conf->ft_over_ds)
88 0 : capab |= RSN_FT_CAPAB_FT_OVER_DS;
89 0 : *pos++ = capab;
90 :
91 0 : return pos - buf;
92 : }
93 :
94 :
95 0 : 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 0 : u8 *pos = buf, *ielen;
102 : struct rsn_ftie *hdr;
103 :
104 0 : if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
105 : subelem_len)
106 0 : return -1;
107 :
108 0 : *pos++ = WLAN_EID_FAST_BSS_TRANSITION;
109 0 : ielen = pos++;
110 :
111 0 : hdr = (struct rsn_ftie *) pos;
112 0 : os_memset(hdr, 0, sizeof(*hdr));
113 0 : pos += sizeof(*hdr);
114 0 : WPA_PUT_LE16(hdr->mic_control, 0);
115 0 : if (anonce)
116 0 : os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
117 0 : if (snonce)
118 0 : os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
119 :
120 : /* Optional Parameters */
121 0 : *pos++ = FTIE_SUBELEM_R1KH_ID;
122 0 : *pos++ = FT_R1KH_ID_LEN;
123 0 : os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
124 0 : pos += FT_R1KH_ID_LEN;
125 :
126 0 : if (r0kh_id) {
127 0 : *pos++ = FTIE_SUBELEM_R0KH_ID;
128 0 : *pos++ = r0kh_id_len;
129 0 : os_memcpy(pos, r0kh_id, r0kh_id_len);
130 0 : pos += r0kh_id_len;
131 : }
132 :
133 0 : if (subelem) {
134 0 : os_memcpy(pos, subelem, subelem_len);
135 0 : pos += subelem_len;
136 : }
137 :
138 0 : *ielen = pos - buf - 2;
139 :
140 0 : 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 139 : struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
169 : {
170 : struct wpa_ft_pmk_cache *cache;
171 :
172 139 : cache = os_zalloc(sizeof(*cache));
173 :
174 139 : return cache;
175 : }
176 :
177 :
178 139 : 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 139 : r0 = cache->pmk_r0;
184 278 : while (r0) {
185 0 : r0prev = r0;
186 0 : r0 = r0->next;
187 0 : os_memset(r0prev->pmk_r0, 0, PMK_LEN);
188 0 : os_free(r0prev);
189 : }
190 :
191 139 : r1 = cache->pmk_r1;
192 278 : while (r1) {
193 0 : r1prev = r1;
194 0 : r1 = r1->next;
195 0 : os_memset(r1prev->pmk_r1, 0, PMK_LEN);
196 0 : os_free(r1prev);
197 : }
198 :
199 139 : os_free(cache);
200 139 : }
201 :
202 :
203 0 : 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 0 : 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 0 : r0 = os_zalloc(sizeof(*r0));
213 0 : if (r0 == NULL)
214 0 : return -1;
215 :
216 0 : os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
217 0 : os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
218 0 : os_memcpy(r0->spa, spa, ETH_ALEN);
219 0 : r0->pairwise = pairwise;
220 :
221 0 : r0->next = cache->pmk_r0;
222 0 : cache->pmk_r0 = r0;
223 :
224 0 : return 0;
225 : }
226 :
227 :
228 0 : 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 0 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
233 : struct wpa_ft_pmk_r0_sa *r0;
234 :
235 0 : r0 = cache->pmk_r0;
236 0 : while (r0) {
237 0 : if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
238 0 : os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
239 : == 0) {
240 0 : os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
241 0 : if (pairwise)
242 0 : *pairwise = r0->pairwise;
243 0 : return 0;
244 : }
245 :
246 0 : r0 = r0->next;
247 : }
248 :
249 0 : return -1;
250 : }
251 :
252 :
253 0 : 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 0 : 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 0 : r1 = os_zalloc(sizeof(*r1));
263 0 : if (r1 == NULL)
264 0 : return -1;
265 :
266 0 : os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
267 0 : os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
268 0 : os_memcpy(r1->spa, spa, ETH_ALEN);
269 0 : r1->pairwise = pairwise;
270 :
271 0 : r1->next = cache->pmk_r1;
272 0 : cache->pmk_r1 = r1;
273 :
274 0 : return 0;
275 : }
276 :
277 :
278 0 : 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 0 : struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
283 : struct wpa_ft_pmk_r1_sa *r1;
284 :
285 0 : r1 = cache->pmk_r1;
286 0 : while (r1) {
287 0 : if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
288 0 : os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
289 : == 0) {
290 0 : os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
291 0 : if (pairwise)
292 0 : *pairwise = r1->pairwise;
293 0 : return 0;
294 : }
295 :
296 0 : r1 = r1->next;
297 : }
298 :
299 0 : return -1;
300 : }
301 :
302 :
303 0 : 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 0 : r0kh = sm->wpa_auth->conf.r0kh_list;
311 0 : while (r0kh) {
312 0 : if (r0kh->id_len == sm->r0kh_id_len &&
313 0 : os_memcmp(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) == 0)
314 0 : break;
315 0 : r0kh = r0kh->next;
316 : }
317 0 : if (r0kh == NULL) {
318 0 : wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
319 0 : sm->r0kh_id, sm->r0kh_id_len);
320 0 : return -1;
321 : }
322 :
323 0 : wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
324 0 : "address " MACSTR, MAC2STR(r0kh->addr));
325 :
326 0 : os_memset(&frame, 0, sizeof(frame));
327 0 : frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
328 0 : frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
329 0 : frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
330 0 : 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 0 : 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 0 : os_memcpy(sm->ft_pending_pull_nonce, f.nonce,
340 : FT_R0KH_R1KH_PULL_NONCE_LEN);
341 0 : os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
342 0 : os_memcpy(f.r1kh_id, sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
343 0 : os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
344 0 : os_memset(f.pad, 0, sizeof(f.pad));
345 :
346 0 : 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 0 : wpabuf_free(sm->ft_pending_req_ies);
351 0 : sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len);
352 0 : if (sm->ft_pending_req_ies == NULL)
353 0 : return -1;
354 :
355 0 : wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
356 :
357 0 : return 0;
358 : }
359 :
360 :
361 0 : 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 0 : const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
368 0 : const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
369 0 : size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
370 0 : const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
371 0 : const u8 *ssid = sm->wpa_auth->conf.ssid;
372 0 : size_t ssid_len = sm->wpa_auth->conf.ssid_len;
373 :
374 :
375 0 : 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 0 : wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
382 0 : r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
383 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
384 0 : wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
385 0 : wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
386 : sm->pairwise);
387 :
388 0 : wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
389 0 : pmk_r1, sm->pmk_r1_name);
390 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
391 0 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
392 : WPA_PMK_NAME_LEN);
393 0 : wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
394 : sm->pairwise);
395 :
396 0 : wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
397 0 : sm->wpa_auth->addr, sm->pmk_r1_name,
398 : (u8 *) ptk, ptk_len, ptk_name);
399 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
400 0 : wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
401 :
402 0 : return 0;
403 : }
404 :
405 :
406 0 : static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
407 : const u8 *addr, int idx, u8 *seq)
408 : {
409 0 : if (wpa_auth->cb.get_seqnum == NULL)
410 0 : return -1;
411 0 : return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
412 : }
413 :
414 :
415 0 : static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
416 : {
417 : u8 *subelem;
418 0 : 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 0 : key_len = gsm->GTK_len;
425 0 : 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 0 : pad_len = key_len % 8;
433 0 : if (pad_len)
434 0 : pad_len = 8 - pad_len;
435 0 : if (key_len + pad_len < 16)
436 0 : pad_len += 8;
437 0 : 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 0 : 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 0 : subelem_len = 13 + key_len + 8;
451 0 : subelem = os_zalloc(subelem_len);
452 0 : if (subelem == NULL)
453 0 : return NULL;
454 :
455 0 : subelem[0] = FTIE_SUBELEM_GTK;
456 0 : subelem[1] = 11 + key_len + 8;
457 : /* Key ID in B0-B1 of Key Info */
458 0 : WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
459 0 : subelem[4] = gsm->GTK_len;
460 0 : wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
461 0 : if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
462 0 : os_free(subelem);
463 0 : return NULL;
464 : }
465 :
466 0 : *len = subelem_len;
467 0 : return subelem;
468 : }
469 :
470 :
471 : #ifdef CONFIG_IEEE80211W
472 0 : static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
473 : {
474 : u8 *subelem, *pos;
475 0 : 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 0 : subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
481 0 : subelem = os_zalloc(subelem_len);
482 0 : if (subelem == NULL)
483 0 : return NULL;
484 :
485 0 : pos = subelem;
486 0 : *pos++ = FTIE_SUBELEM_IGTK;
487 0 : *pos++ = subelem_len - 2;
488 0 : WPA_PUT_LE16(pos, gsm->GN_igtk);
489 0 : pos += 2;
490 0 : wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
491 0 : pos += 6;
492 0 : *pos++ = WPA_IGTK_LEN;
493 0 : if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
494 0 : gsm->IGTK[gsm->GN_igtk - 4], pos)) {
495 0 : os_free(subelem);
496 0 : return NULL;
497 : }
498 :
499 0 : *len = subelem_len;
500 0 : 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 277 : 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 277 : u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
640 277 : 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 277 : if (sm == NULL)
649 132 : return pos;
650 :
651 145 : conf = &sm->wpa_auth->conf;
652 :
653 145 : if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
654 145 : return pos;
655 :
656 0 : end = pos + max_len;
657 :
658 0 : 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 0 : res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
664 0 : if (res < 0)
665 0 : return pos;
666 0 : rsnie = pos;
667 0 : rsnie_len = res;
668 0 : pos += res;
669 : }
670 :
671 : /* Mobility Domain Information */
672 0 : res = wpa_write_mdie(conf, pos, end - pos);
673 0 : if (res < 0)
674 0 : return pos;
675 0 : mdie = pos;
676 0 : mdie_len = res;
677 0 : pos += res;
678 :
679 : /* Fast BSS Transition Information */
680 0 : if (auth_alg == WLAN_AUTH_FT) {
681 0 : subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
682 0 : r0kh_id = sm->r0kh_id;
683 0 : r0kh_id_len = sm->r0kh_id_len;
684 0 : anonce = sm->ANonce;
685 0 : snonce = sm->SNonce;
686 : #ifdef CONFIG_IEEE80211W
687 0 : if (sm->mgmt_frame_prot) {
688 : u8 *igtk;
689 : size_t igtk_len;
690 : u8 *nbuf;
691 0 : igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
692 0 : if (igtk == NULL) {
693 0 : os_free(subelem);
694 0 : return pos;
695 : }
696 0 : nbuf = os_realloc(subelem, subelem_len + igtk_len);
697 0 : if (nbuf == NULL) {
698 0 : os_free(subelem);
699 0 : os_free(igtk);
700 0 : return pos;
701 : }
702 0 : subelem = nbuf;
703 0 : os_memcpy(subelem + subelem_len, igtk, igtk_len);
704 0 : subelem_len += igtk_len;
705 0 : os_free(igtk);
706 : }
707 : #endif /* CONFIG_IEEE80211W */
708 : } else {
709 0 : r0kh_id = conf->r0_key_holder;
710 0 : r0kh_id_len = conf->r0_key_holder_len;
711 0 : anonce = NULL;
712 0 : snonce = NULL;
713 : }
714 0 : res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
715 0 : end - pos, subelem, subelem_len);
716 0 : os_free(subelem);
717 0 : if (res < 0)
718 0 : return pos;
719 0 : ftie = pos;
720 0 : ftie_len = res;
721 0 : pos += res;
722 :
723 0 : os_free(sm->assoc_resp_ftie);
724 0 : sm->assoc_resp_ftie = os_malloc(ftie_len);
725 0 : if (sm->assoc_resp_ftie)
726 0 : os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
727 :
728 0 : _ftie = (struct rsn_ftie *) (ftie + 2);
729 0 : if (auth_alg == WLAN_AUTH_FT)
730 0 : _ftie->mic_control[1] = 3; /* Information element count */
731 :
732 0 : ric_start = pos;
733 0 : 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 0 : if (ric_start == pos)
742 0 : ric_start = NULL;
743 :
744 0 : if (auth_alg == WLAN_AUTH_FT &&
745 0 : 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 0 : _ftie->mic) < 0)
750 0 : wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
751 :
752 0 : return pos;
753 : }
754 :
755 :
756 0 : 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 0 : if (wpa_auth->cb.set_key == NULL)
762 0 : return -1;
763 0 : return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
764 : key, key_len);
765 : }
766 :
767 :
768 0 : 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 0 : alg = wpa_cipher_to_alg(sm->pairwise);
775 0 : klen = wpa_cipher_key_len(sm->pairwise);
776 0 : 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 0 : if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
789 0 : sm->PTK.tk1, klen))
790 0 : return;
791 :
792 : /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
793 0 : sm->pairwise_set = TRUE;
794 : }
795 :
796 :
797 0 : 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 0 : *resp_ies = NULL;
813 0 : *resp_ies_len = 0;
814 :
815 0 : sm->pmk_r1_name_valid = 0;
816 0 : conf = &sm->wpa_auth->conf;
817 :
818 0 : wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
819 : ies, ies_len);
820 :
821 0 : 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 0 : mdie = (struct rsn_mdie *) parse.mdie;
827 0 : if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
828 0 : 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 0 : ftie = (struct rsn_ftie *) parse.ftie;
836 0 : 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 0 : os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
842 :
843 0 : 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 0 : wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
849 0 : parse.r0kh_id, parse.r0kh_id_len);
850 0 : os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
851 0 : sm->r0kh_id_len = parse.r0kh_id_len;
852 :
853 0 : 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 0 : wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
859 0 : parse.rsn_pmkid, WPA_PMK_NAME_LEN);
860 0 : wpa_derive_pmk_r1_name(parse.rsn_pmkid,
861 0 : sm->wpa_auth->conf.r1_key_holder, sm->addr,
862 : pmk_r1_name);
863 0 : wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
864 : pmk_r1_name, WPA_PMK_NAME_LEN);
865 :
866 0 : if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
867 : &pairwise) < 0) {
868 0 : if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
869 0 : wpa_printf(MSG_DEBUG, "FT: Did not have matching "
870 : "PMK-R1 and unknown R0KH-ID");
871 0 : return WLAN_STATUS_INVALID_PMKID;
872 : }
873 :
874 0 : return -1; /* Status pending */
875 : }
876 :
877 0 : wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
878 0 : sm->pmk_r1_name_valid = 1;
879 0 : os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
880 :
881 0 : 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 0 : wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
888 0 : sm->SNonce, WPA_NONCE_LEN);
889 0 : wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
890 0 : sm->ANonce, WPA_NONCE_LEN);
891 :
892 0 : ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
893 0 : wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
894 0 : sm->wpa_auth->addr, pmk_r1_name,
895 0 : (u8 *) &sm->PTK, ptk_len, ptk_name);
896 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
897 0 : (u8 *) &sm->PTK, ptk_len);
898 0 : wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
899 :
900 0 : sm->pairwise = pairwise;
901 0 : sm->PTK_valid = TRUE;
902 0 : wpa_ft_install_ptk(sm);
903 :
904 0 : buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
905 : 2 + FT_R1KH_ID_LEN + 200;
906 0 : *resp_ies = os_zalloc(buflen);
907 0 : if (*resp_ies == NULL) {
908 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
909 : }
910 :
911 0 : pos = *resp_ies;
912 0 : end = *resp_ies + buflen;
913 :
914 0 : ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
915 0 : if (ret < 0) {
916 0 : os_free(*resp_ies);
917 0 : *resp_ies = NULL;
918 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
919 : }
920 0 : pos += ret;
921 :
922 0 : ret = wpa_write_mdie(conf, pos, end - pos);
923 0 : if (ret < 0) {
924 0 : os_free(*resp_ies);
925 0 : *resp_ies = NULL;
926 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
927 : }
928 0 : pos += ret;
929 :
930 0 : ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
931 0 : sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
932 0 : if (ret < 0) {
933 0 : os_free(*resp_ies);
934 0 : *resp_ies = NULL;
935 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
936 : }
937 0 : pos += ret;
938 :
939 0 : *resp_ies_len = pos - *resp_ies;
940 :
941 0 : return WLAN_STATUS_SUCCESS;
942 : }
943 :
944 :
945 0 : 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 0 : 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 0 : wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
964 : " BSSID=" MACSTR " transaction=%d",
965 0 : MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
966 0 : sm->ft_pending_cb = cb;
967 0 : sm->ft_pending_cb_ctx = ctx;
968 0 : sm->ft_pending_auth_transaction = auth_transaction;
969 0 : res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
970 : &resp_ies_len);
971 0 : if (res < 0) {
972 0 : wpa_printf(MSG_DEBUG, "FT: Callback postponed until response is available");
973 0 : return;
974 : }
975 0 : status = res;
976 :
977 0 : wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
978 : " auth_transaction=%d status=%d",
979 0 : MAC2STR(sm->addr), auth_transaction + 1, status);
980 0 : wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
981 0 : cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
982 : resp_ies, resp_ies_len);
983 0 : os_free(resp_ies);
984 : }
985 :
986 :
987 0 : 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 0 : if (sm == NULL)
997 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
998 :
999 0 : wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
1000 :
1001 0 : 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 0 : 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 0 : 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 0 : 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 0 : mdie = (struct rsn_mdie *) parse.mdie;
1024 0 : if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
1025 0 : 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 0 : ftie = (struct rsn_ftie *) parse.ftie;
1033 0 : 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 0 : 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 0 : 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 0 : 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 0 : if (parse.r0kh_id_len != sm->r0kh_id_len ||
1063 0 : 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 0 : 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 0 : 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 0 : if (parse.rsn_pmkid == NULL ||
1090 0 : 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 0 : count = 3;
1097 0 : if (parse.ric)
1098 0 : count += ieee802_11_ie_count(parse.ric, parse.ric_len);
1099 0 : 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 0 : if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
1107 0 : parse.mdie - 2, parse.mdie_len + 2,
1108 0 : parse.ftie - 2, parse.ftie_len + 2,
1109 0 : 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 0 : 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 0 : return WLAN_STATUS_SUCCESS;
1132 : }
1133 :
1134 :
1135 0 : 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 0 : 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 0 : 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 0 : action = data[1];
1158 0 : sta_addr = data + 2;
1159 0 : target_ap = data + 8;
1160 0 : ies = data + 14;
1161 0 : ies_len = len - 14;
1162 :
1163 0 : wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
1164 : " Target AP=" MACSTR " Action=%d)",
1165 0 : MAC2STR(sta_addr), MAC2STR(target_ap), action);
1166 :
1167 0 : 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 0 : if ((target_ap[0] & 0x01) ||
1180 0 : 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 0 : wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
1187 :
1188 : /* RRB - Forward action frame to the target AP */
1189 0 : frame = os_malloc(sizeof(*frame) + len);
1190 0 : if (frame == NULL)
1191 0 : return -1;
1192 0 : frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1193 0 : frame->packet_type = FT_PACKET_REQUEST;
1194 0 : frame->action_length = host_to_le16(len);
1195 0 : os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
1196 0 : os_memcpy(frame + 1, data, len);
1197 :
1198 0 : wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
1199 : sizeof(*frame) + len);
1200 0 : os_free(frame);
1201 :
1202 0 : return 0;
1203 : }
1204 :
1205 :
1206 0 : 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 0 : struct wpa_state_machine *sm = ctx;
1211 0 : wpa_printf(MSG_DEBUG, "FT: Over-the-DS RX request cb for " MACSTR,
1212 0 : MAC2STR(sm->addr));
1213 0 : wpa_ft_send_rrb_auth_resp(sm, sm->ft_pending_current_ap, sm->addr,
1214 : WLAN_STATUS_SUCCESS, ies, ies_len);
1215 0 : }
1216 :
1217 :
1218 0 : 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 0 : sm = wpa_ft_add_sta(wpa_auth, sta_addr);
1229 0 : 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 0 : wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
1236 :
1237 0 : sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb;
1238 0 : sm->ft_pending_cb_ctx = sm;
1239 0 : os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN);
1240 0 : res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
1241 : &resp_ies_len);
1242 0 : if (res < 0) {
1243 0 : wpa_printf(MSG_DEBUG, "FT: No immediate response available - wait for pull response");
1244 0 : return 0;
1245 : }
1246 0 : status = res;
1247 :
1248 0 : res = wpa_ft_send_rrb_auth_resp(sm, current_ap, sta_addr, status,
1249 : resp_ies, resp_ies_len);
1250 0 : os_free(resp_ies);
1251 0 : return res;
1252 : }
1253 :
1254 :
1255 0 : 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 0 : struct wpa_authenticator *wpa_auth = sm->wpa_auth;
1261 : size_t rlen;
1262 : struct ft_rrb_frame *frame;
1263 : u8 *pos;
1264 :
1265 0 : wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
1266 : " CurrentAP=" MACSTR " status=%d",
1267 0 : MAC2STR(sm->addr), MAC2STR(current_ap), status);
1268 0 : 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 0 : rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
1277 :
1278 0 : frame = os_malloc(sizeof(*frame) + rlen);
1279 0 : if (frame == NULL)
1280 0 : return -1;
1281 0 : frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1282 0 : frame->packet_type = FT_PACKET_RESPONSE;
1283 0 : frame->action_length = host_to_le16(rlen);
1284 0 : os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
1285 0 : pos = (u8 *) (frame + 1);
1286 0 : *pos++ = WLAN_ACTION_FT;
1287 0 : *pos++ = 2; /* Action: Response */
1288 0 : os_memcpy(pos, sta_addr, ETH_ALEN);
1289 0 : pos += ETH_ALEN;
1290 0 : os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
1291 0 : pos += ETH_ALEN;
1292 0 : WPA_PUT_LE16(pos, status);
1293 0 : pos += 2;
1294 0 : if (resp_ies)
1295 0 : os_memcpy(pos, resp_ies, resp_ies_len);
1296 :
1297 0 : wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
1298 : sizeof(*frame) + rlen);
1299 0 : os_free(frame);
1300 :
1301 0 : return 0;
1302 : }
1303 :
1304 :
1305 0 : 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 0 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
1316 :
1317 0 : if (data_len < sizeof(*frame))
1318 0 : return -1;
1319 :
1320 0 : r1kh = wpa_auth->conf.r1kh_list;
1321 0 : while (r1kh) {
1322 0 : if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
1323 0 : break;
1324 0 : r1kh = r1kh->next;
1325 : }
1326 0 : if (r1kh == NULL) {
1327 0 : wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
1328 : "PMK-R1 pull source address " MACSTR,
1329 0 : MAC2STR(src_addr));
1330 0 : return -1;
1331 : }
1332 :
1333 0 : 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 0 : if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
1337 0 : frame->nonce, f.nonce) < 0) {
1338 0 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
1339 0 : "request from " MACSTR, MAC2STR(src_addr));
1340 0 : return -1;
1341 : }
1342 :
1343 0 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
1344 : f.nonce, sizeof(f.nonce));
1345 0 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
1346 : f.pmk_r0_name, WPA_PMK_NAME_LEN);
1347 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
1348 0 : MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
1349 :
1350 0 : os_memset(&resp, 0, sizeof(resp));
1351 0 : resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1352 0 : resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
1353 0 : resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
1354 0 : 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 0 : os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
1359 0 : os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
1360 0 : os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
1361 0 : 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 0 : 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 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
1371 0 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
1372 : WPA_PMK_NAME_LEN);
1373 0 : r.pairwise = host_to_le16(pairwise);
1374 0 : os_memset(r.pad, 0, sizeof(r.pad));
1375 :
1376 0 : 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 0 : os_memset(pmk_r0, 0, PMK_LEN);
1383 :
1384 0 : wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
1385 :
1386 0 : return 0;
1387 : }
1388 :
1389 :
1390 0 : static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
1391 : {
1392 0 : 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 0 : res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies),
1399 0 : wpabuf_len(sm->ft_pending_req_ies),
1400 : &resp_ies, &resp_ies_len);
1401 0 : wpabuf_free(sm->ft_pending_req_ies);
1402 0 : sm->ft_pending_req_ies = NULL;
1403 0 : if (res < 0)
1404 0 : res = WLAN_STATUS_UNSPECIFIED_FAILURE;
1405 0 : status = res;
1406 0 : wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR
1407 0 : " - status %u", MAC2STR(sm->addr), status);
1408 :
1409 0 : sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr,
1410 0 : sm->ft_pending_auth_transaction + 1, status,
1411 : resp_ies, resp_ies_len);
1412 0 : os_free(resp_ies);
1413 0 : }
1414 :
1415 :
1416 0 : static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
1417 : {
1418 0 : struct ft_r0kh_r1kh_resp_frame *frame = ctx;
1419 :
1420 0 : if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
1421 0 : return 0;
1422 0 : if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
1423 : FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
1424 0 : return 0;
1425 0 : if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
1426 0 : return 0;
1427 :
1428 0 : wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
1429 0 : MACSTR " - process from timeout", MAC2STR(sm->addr));
1430 0 : eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL);
1431 0 : return 1;
1432 : }
1433 :
1434 :
1435 0 : 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 0 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
1444 :
1445 0 : if (data_len < sizeof(*frame))
1446 0 : return -1;
1447 :
1448 0 : r0kh = wpa_auth->conf.r0kh_list;
1449 0 : while (r0kh) {
1450 0 : if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
1451 0 : break;
1452 0 : r0kh = r0kh->next;
1453 : }
1454 0 : 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 0 : 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 0 : if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
1465 0 : 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 0 : 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 0 : pairwise = le_to_host16(f.pairwise);
1479 0 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
1480 : f.nonce, sizeof(f.nonce));
1481 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
1482 : MACSTR " pairwise=0x%x",
1483 0 : MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
1484 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
1485 : f.pmk_r1, PMK_LEN);
1486 0 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
1487 : f.pmk_r1_name, WPA_PMK_NAME_LEN);
1488 :
1489 0 : res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
1490 : pairwise);
1491 0 : wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
1492 0 : wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
1493 0 : os_memset(f.pmk_r1, 0, PMK_LEN);
1494 :
1495 0 : return res ? 0 : -1;
1496 : }
1497 :
1498 :
1499 0 : 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 0 : wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
1510 :
1511 0 : if (data_len < sizeof(*frame))
1512 0 : return -1;
1513 :
1514 0 : r0kh = wpa_auth->conf.r0kh_list;
1515 0 : while (r0kh) {
1516 0 : if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
1517 0 : break;
1518 0 : r0kh = r0kh->next;
1519 : }
1520 0 : if (r0kh == NULL) {
1521 0 : wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
1522 : "PMK-R0 push source address " MACSTR,
1523 0 : MAC2STR(src_addr));
1524 0 : return -1;
1525 : }
1526 :
1527 0 : 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 0 : if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
1531 0 : frame->timestamp, f.timestamp) < 0) {
1532 0 : wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
1533 0 : MACSTR, MAC2STR(src_addr));
1534 0 : return -1;
1535 : }
1536 :
1537 0 : os_get_time(&now);
1538 0 : tsend = WPA_GET_LE32(f.timestamp);
1539 0 : if ((now.sec > tsend && now.sec - tsend > 60) ||
1540 0 : (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 0 : 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 0 : pairwise = le_to_host16(f.pairwise);
1557 0 : wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
1558 : MACSTR " pairwise=0x%x",
1559 0 : MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
1560 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
1561 : f.pmk_r1, PMK_LEN);
1562 0 : wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
1563 : f.pmk_r1_name, WPA_PMK_NAME_LEN);
1564 :
1565 0 : wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
1566 : pairwise);
1567 0 : os_memset(f.pmk_r1, 0, PMK_LEN);
1568 :
1569 0 : return 0;
1570 : }
1571 :
1572 :
1573 1 : 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 6 : wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
1583 6 : MAC2STR(src_addr));
1584 :
1585 1 : 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 1 : pos = data;
1592 1 : frame = (struct ft_rrb_frame *) pos;
1593 1 : pos += sizeof(*frame);
1594 :
1595 1 : alen = le_to_host16(frame->action_length);
1596 8 : wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
1597 : "action_length=%d ap_address=" MACSTR,
1598 2 : frame->frame_type, frame->packet_type, alen,
1599 6 : MAC2STR(frame->ap_address));
1600 :
1601 1 : if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
1602 : /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
1603 1 : wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
1604 1 : "unrecognized type %d", frame->frame_type);
1605 1 : return -1;
1606 : }
1607 :
1608 0 : 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 0 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
1615 0 : return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
1616 0 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
1617 0 : return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
1618 0 : if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
1619 0 : return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
1620 :
1621 0 : wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
1622 :
1623 0 : 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 0 : start = pos;
1630 0 : end = pos + alen;
1631 :
1632 0 : 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 0 : pos++;
1639 0 : action = *pos++;
1640 0 : sta_addr = pos;
1641 0 : pos += ETH_ALEN;
1642 0 : target_ap_addr = pos;
1643 0 : pos += ETH_ALEN;
1644 0 : wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
1645 : MACSTR " target_ap_addr=" MACSTR,
1646 0 : action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
1647 :
1648 0 : if (frame->packet_type == FT_PACKET_REQUEST) {
1649 0 : wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
1650 :
1651 0 : 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 0 : 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 0 : if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
1665 0 : sta_addr, pos, end - pos) < 0)
1666 0 : return -1;
1667 0 : } else if (frame->packet_type == FT_PACKET_RESPONSE) {
1668 : u16 status_code;
1669 :
1670 0 : 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 0 : status_code = WPA_GET_LE16(pos);
1676 0 : pos += 2;
1677 :
1678 0 : wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
1679 : "(status_code=%d)", status_code);
1680 :
1681 0 : 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 0 : return 0;
1690 : }
1691 :
1692 :
1693 0 : 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 0 : os_memset(&frame, 0, sizeof(frame));
1702 0 : frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
1703 0 : frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
1704 0 : frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
1705 0 : 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 0 : os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
1710 0 : os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
1711 0 : os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
1712 0 : 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 0 : wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
1715 0 : wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
1716 0 : wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
1717 : WPA_PMK_NAME_LEN);
1718 0 : os_get_time(&now);
1719 0 : WPA_PUT_LE32(f.timestamp, now.sec);
1720 0 : f.pairwise = host_to_le16(pairwise);
1721 0 : os_memset(f.pad, 0, sizeof(f.pad));
1722 0 : if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
1723 : f.timestamp, frame.timestamp) < 0)
1724 0 : return;
1725 :
1726 0 : wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
1727 : }
1728 :
1729 :
1730 149 : 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 149 : if (!wpa_auth->conf.pmk_r1_push)
1736 149 : return;
1737 :
1738 0 : r0 = wpa_auth->ft_pmk_cache->pmk_r0;
1739 0 : while (r0) {
1740 0 : if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
1741 0 : break;
1742 0 : r0 = r0->next;
1743 : }
1744 :
1745 0 : if (r0 == NULL || r0->pmk_r1_pushed)
1746 0 : return;
1747 0 : r0->pmk_r1_pushed = 1;
1748 :
1749 0 : wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
1750 0 : "for STA " MACSTR, MAC2STR(addr));
1751 :
1752 0 : r1kh = wpa_auth->conf.r1kh_list;
1753 0 : while (r1kh) {
1754 0 : wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
1755 0 : r1kh = r1kh->next;
1756 : }
1757 : }
1758 :
1759 : #endif /* CONFIG_IEEE80211R */
|