2 * hostapd - IEEE 802.11r - Fast BSS Transition
3 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
15 #include "utils/includes.h"
17 #include "utils/common.h"
18 #include "common/ieee802_11_defs.h"
19 #include "common/ieee802_11_common.h"
20 #include "crypto/aes_wrap.h"
21 #include "crypto/random.h"
22 #include "ap_config.h"
23 #include "ieee802_11.h"
26 #include "wpa_auth_i.h"
29 #ifdef CONFIG_IEEE80211R
31 static int wpa_ft_rrb_send(struct wpa_authenticator
*wpa_auth
, const u8
*dst
,
32 const u8
*data
, size_t data_len
)
34 if (wpa_auth
->cb
.send_ether
== NULL
)
36 wpa_printf(MSG_DEBUG
, "FT: RRB send to " MACSTR
, MAC2STR(dst
));
37 return wpa_auth
->cb
.send_ether(wpa_auth
->cb
.ctx
, dst
, ETH_P_RRB
,
42 static int wpa_ft_action_send(struct wpa_authenticator
*wpa_auth
,
43 const u8
*dst
, const u8
*data
, size_t data_len
)
45 if (wpa_auth
->cb
.send_ft_action
== NULL
)
47 return wpa_auth
->cb
.send_ft_action(wpa_auth
->cb
.ctx
, dst
,
52 static struct wpa_state_machine
*
53 wpa_ft_add_sta(struct wpa_authenticator
*wpa_auth
, const u8
*sta_addr
)
55 if (wpa_auth
->cb
.add_sta
== NULL
)
57 return wpa_auth
->cb
.add_sta(wpa_auth
->cb
.ctx
, sta_addr
);
61 int wpa_write_mdie(struct wpa_auth_config
*conf
, u8
*buf
, size_t len
)
65 if (len
< 2 + sizeof(struct rsn_mdie
))
68 *pos
++ = WLAN_EID_MOBILITY_DOMAIN
;
69 *pos
++ = MOBILITY_DOMAIN_ID_LEN
+ 1;
70 os_memcpy(pos
, conf
->mobility_domain
, MOBILITY_DOMAIN_ID_LEN
);
71 pos
+= MOBILITY_DOMAIN_ID_LEN
;
74 capab
|= RSN_FT_CAPAB_FT_OVER_DS
;
81 int wpa_write_ftie(struct wpa_auth_config
*conf
, const u8
*r0kh_id
,
83 const u8
*anonce
, const u8
*snonce
,
84 u8
*buf
, size_t len
, const u8
*subelem
,
87 u8
*pos
= buf
, *ielen
;
90 if (len
< 2 + sizeof(*hdr
) + 2 + FT_R1KH_ID_LEN
+ 2 + r0kh_id_len
+
94 *pos
++ = WLAN_EID_FAST_BSS_TRANSITION
;
97 hdr
= (struct rsn_ftie
*) pos
;
98 os_memset(hdr
, 0, sizeof(*hdr
));
100 WPA_PUT_LE16(hdr
->mic_control
, 0);
102 os_memcpy(hdr
->anonce
, anonce
, WPA_NONCE_LEN
);
104 os_memcpy(hdr
->snonce
, snonce
, WPA_NONCE_LEN
);
106 /* Optional Parameters */
107 *pos
++ = FTIE_SUBELEM_R1KH_ID
;
108 *pos
++ = FT_R1KH_ID_LEN
;
109 os_memcpy(pos
, conf
->r1_key_holder
, FT_R1KH_ID_LEN
);
110 pos
+= FT_R1KH_ID_LEN
;
113 *pos
++ = FTIE_SUBELEM_R0KH_ID
;
114 *pos
++ = r0kh_id_len
;
115 os_memcpy(pos
, r0kh_id
, r0kh_id_len
);
120 os_memcpy(pos
, subelem
, subelem_len
);
124 *ielen
= pos
- buf
- 2;
130 struct wpa_ft_pmk_r0_sa
{
131 struct wpa_ft_pmk_r0_sa
*next
;
133 u8 pmk_r0_name
[WPA_PMK_NAME_LEN
];
135 int pairwise
; /* Pairwise cipher suite, WPA_CIPHER_* */
136 /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
140 struct wpa_ft_pmk_r1_sa
{
141 struct wpa_ft_pmk_r1_sa
*next
;
143 u8 pmk_r1_name
[WPA_PMK_NAME_LEN
];
145 int pairwise
; /* Pairwise cipher suite, WPA_CIPHER_* */
146 /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
149 struct wpa_ft_pmk_cache
{
150 struct wpa_ft_pmk_r0_sa
*pmk_r0
;
151 struct wpa_ft_pmk_r1_sa
*pmk_r1
;
154 struct wpa_ft_pmk_cache
* wpa_ft_pmk_cache_init(void)
156 struct wpa_ft_pmk_cache
*cache
;
158 cache
= os_zalloc(sizeof(*cache
));
164 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache
*cache
)
166 struct wpa_ft_pmk_r0_sa
*r0
, *r0prev
;
167 struct wpa_ft_pmk_r1_sa
*r1
, *r1prev
;
173 os_memset(r0prev
->pmk_r0
, 0, PMK_LEN
);
181 os_memset(r1prev
->pmk_r1
, 0, PMK_LEN
);
189 static int wpa_ft_store_pmk_r0(struct wpa_authenticator
*wpa_auth
,
190 const u8
*spa
, const u8
*pmk_r0
,
191 const u8
*pmk_r0_name
, int pairwise
)
193 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
194 struct wpa_ft_pmk_r0_sa
*r0
;
196 /* TODO: add expiration and limit on number of entries in cache */
198 r0
= os_zalloc(sizeof(*r0
));
202 os_memcpy(r0
->pmk_r0
, pmk_r0
, PMK_LEN
);
203 os_memcpy(r0
->pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
);
204 os_memcpy(r0
->spa
, spa
, ETH_ALEN
);
205 r0
->pairwise
= pairwise
;
207 r0
->next
= cache
->pmk_r0
;
214 static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator
*wpa_auth
,
215 const u8
*spa
, const u8
*pmk_r0_name
,
216 u8
*pmk_r0
, int *pairwise
)
218 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
219 struct wpa_ft_pmk_r0_sa
*r0
;
223 if (os_memcmp(r0
->spa
, spa
, ETH_ALEN
) == 0 &&
224 os_memcmp(r0
->pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
)
226 os_memcpy(pmk_r0
, r0
->pmk_r0
, PMK_LEN
);
228 *pairwise
= r0
->pairwise
;
239 static int wpa_ft_store_pmk_r1(struct wpa_authenticator
*wpa_auth
,
240 const u8
*spa
, const u8
*pmk_r1
,
241 const u8
*pmk_r1_name
, int pairwise
)
243 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
244 struct wpa_ft_pmk_r1_sa
*r1
;
246 /* TODO: add expiration and limit on number of entries in cache */
248 r1
= os_zalloc(sizeof(*r1
));
252 os_memcpy(r1
->pmk_r1
, pmk_r1
, PMK_LEN
);
253 os_memcpy(r1
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
);
254 os_memcpy(r1
->spa
, spa
, ETH_ALEN
);
255 r1
->pairwise
= pairwise
;
257 r1
->next
= cache
->pmk_r1
;
264 static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator
*wpa_auth
,
265 const u8
*spa
, const u8
*pmk_r1_name
,
266 u8
*pmk_r1
, int *pairwise
)
268 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
269 struct wpa_ft_pmk_r1_sa
*r1
;
273 if (os_memcmp(r1
->spa
, spa
, ETH_ALEN
) == 0 &&
274 os_memcmp(r1
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
)
276 os_memcpy(pmk_r1
, r1
->pmk_r1
, PMK_LEN
);
278 *pairwise
= r1
->pairwise
;
289 static int wpa_ft_pull_pmk_r1(struct wpa_authenticator
*wpa_auth
,
290 const u8
*s1kh_id
, const u8
*r0kh_id
,
291 size_t r0kh_id_len
, const u8
*pmk_r0_name
)
293 struct ft_remote_r0kh
*r0kh
;
294 struct ft_r0kh_r1kh_pull_frame frame
, f
;
296 r0kh
= wpa_auth
->conf
.r0kh_list
;
298 if (r0kh
->id_len
== r0kh_id_len
&&
299 os_memcmp(r0kh
->id
, r0kh_id
, r0kh_id_len
) == 0)
306 wpa_printf(MSG_DEBUG
, "FT: Send PMK-R1 pull request to remote R0KH "
307 "address " MACSTR
, MAC2STR(r0kh
->addr
));
309 os_memset(&frame
, 0, sizeof(frame
));
310 frame
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
311 frame
.packet_type
= FT_PACKET_R0KH_R1KH_PULL
;
312 frame
.data_length
= host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN
);
313 os_memcpy(frame
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
315 /* aes_wrap() does not support inplace encryption, so use a temporary
316 * buffer for the data. */
317 if (random_get_bytes(f
.nonce
, sizeof(f
.nonce
))) {
318 wpa_printf(MSG_DEBUG
, "FT: Failed to get random data for "
322 os_memcpy(f
.pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
);
323 os_memcpy(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
);
324 os_memcpy(f
.s1kh_id
, s1kh_id
, ETH_ALEN
);
326 if (aes_wrap(r0kh
->key
, (FT_R0KH_R1KH_PULL_DATA_LEN
+ 7) / 8,
327 f
.nonce
, frame
.nonce
) < 0)
330 wpa_ft_rrb_send(wpa_auth
, r0kh
->addr
, (u8
*) &frame
, sizeof(frame
));
336 int wpa_auth_derive_ptk_ft(struct wpa_state_machine
*sm
, const u8
*pmk
,
337 struct wpa_ptk
*ptk
, size_t ptk_len
)
339 u8 pmk_r0
[PMK_LEN
], pmk_r0_name
[WPA_PMK_NAME_LEN
];
341 u8 ptk_name
[WPA_PMK_NAME_LEN
];
342 const u8
*mdid
= sm
->wpa_auth
->conf
.mobility_domain
;
343 const u8
*r0kh
= sm
->wpa_auth
->conf
.r0_key_holder
;
344 size_t r0kh_len
= sm
->wpa_auth
->conf
.r0_key_holder_len
;
345 const u8
*r1kh
= sm
->wpa_auth
->conf
.r1_key_holder
;
346 const u8
*ssid
= sm
->wpa_auth
->conf
.ssid
;
347 size_t ssid_len
= sm
->wpa_auth
->conf
.ssid_len
;
350 if (sm
->xxkey_len
== 0) {
351 wpa_printf(MSG_DEBUG
, "FT: XXKey not available for key "
356 wpa_derive_pmk_r0(sm
->xxkey
, sm
->xxkey_len
, ssid
, ssid_len
, mdid
,
357 r0kh
, r0kh_len
, sm
->addr
, pmk_r0
, pmk_r0_name
);
358 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R0", pmk_r0
, PMK_LEN
);
359 wpa_hexdump(MSG_DEBUG
, "FT: PMKR0Name", pmk_r0_name
, WPA_PMK_NAME_LEN
);
360 wpa_ft_store_pmk_r0(sm
->wpa_auth
, sm
->addr
, pmk_r0
, pmk_r0_name
,
363 wpa_derive_pmk_r1(pmk_r0
, pmk_r0_name
, r1kh
, sm
->addr
,
364 pmk_r1
, sm
->pmk_r1_name
);
365 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", pmk_r1
, PMK_LEN
);
366 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", sm
->pmk_r1_name
,
368 wpa_ft_store_pmk_r1(sm
->wpa_auth
, sm
->addr
, pmk_r1
, sm
->pmk_r1_name
,
371 wpa_pmk_r1_to_ptk(pmk_r1
, sm
->SNonce
, sm
->ANonce
, sm
->addr
,
372 sm
->wpa_auth
->addr
, sm
->pmk_r1_name
,
373 (u8
*) ptk
, ptk_len
, ptk_name
);
374 wpa_hexdump_key(MSG_DEBUG
, "FT: PTK", (u8
*) ptk
, ptk_len
);
375 wpa_hexdump(MSG_DEBUG
, "FT: PTKName", ptk_name
, WPA_PMK_NAME_LEN
);
381 static inline int wpa_auth_get_seqnum(struct wpa_authenticator
*wpa_auth
,
382 const u8
*addr
, int idx
, u8
*seq
)
384 if (wpa_auth
->cb
.get_seqnum
== NULL
)
386 return wpa_auth
->cb
.get_seqnum(wpa_auth
->cb
.ctx
, addr
, idx
, seq
);
390 static u8
* wpa_ft_gtk_subelem(struct wpa_state_machine
*sm
, size_t *len
)
393 struct wpa_group
*gsm
= sm
->group
;
394 size_t subelem_len
, pad_len
;
399 key_len
= gsm
->GTK_len
;
400 if (key_len
> sizeof(keybuf
))
404 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
407 pad_len
= key_len
% 8;
409 pad_len
= 8 - pad_len
;
410 if (key_len
+ pad_len
< 16)
413 os_memcpy(keybuf
, gsm
->GTK
[gsm
->GN
- 1], key_len
);
414 os_memset(keybuf
+ key_len
, 0, pad_len
);
415 keybuf
[key_len
] = 0xdd;
419 key
= gsm
->GTK
[gsm
->GN
- 1];
422 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
425 subelem_len
= 13 + key_len
+ 8;
426 subelem
= os_zalloc(subelem_len
);
430 subelem
[0] = FTIE_SUBELEM_GTK
;
431 subelem
[1] = 11 + key_len
+ 8;
432 /* Key ID in B0-B1 of Key Info */
433 WPA_PUT_LE16(&subelem
[2], gsm
->GN
& 0x03);
434 subelem
[4] = gsm
->GTK_len
;
435 wpa_auth_get_seqnum(sm
->wpa_auth
, NULL
, gsm
->GN
, subelem
+ 5);
436 if (aes_wrap(sm
->PTK
.kek
, key_len
/ 8, key
, subelem
+ 13)) {
446 #ifdef CONFIG_IEEE80211W
447 static u8
* wpa_ft_igtk_subelem(struct wpa_state_machine
*sm
, size_t *len
)
450 struct wpa_group
*gsm
= sm
->group
;
453 /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
455 subelem_len
= 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN
+ 8;
456 subelem
= os_zalloc(subelem_len
);
461 *pos
++ = FTIE_SUBELEM_IGTK
;
462 *pos
++ = subelem_len
- 2;
463 WPA_PUT_LE16(pos
, gsm
->GN_igtk
);
465 wpa_auth_get_seqnum(sm
->wpa_auth
, NULL
, gsm
->GN_igtk
, pos
);
467 *pos
++ = WPA_IGTK_LEN
;
468 if (aes_wrap(sm
->PTK
.kek
, WPA_IGTK_LEN
/ 8,
469 gsm
->IGTK
[gsm
->GN_igtk
- 4], pos
)) {
477 #endif /* CONFIG_IEEE80211W */
480 static u8
* wpa_ft_process_rdie(u8
*pos
, u8
*end
, u8 id
, u8 descr_count
,
481 const u8
*ies
, size_t ies_len
)
483 struct ieee802_11_elems parse
;
484 struct rsn_rdie
*rdie
;
486 wpa_printf(MSG_DEBUG
, "FT: Resource Request: id=%d descr_count=%d",
488 wpa_hexdump(MSG_MSGDUMP
, "FT: Resource descriptor IE(s)",
491 if (end
- pos
< (int) sizeof(*rdie
)) {
492 wpa_printf(MSG_ERROR
, "FT: Not enough room for response RDIE");
496 *pos
++ = WLAN_EID_RIC_DATA
;
497 *pos
++ = sizeof(*rdie
);
498 rdie
= (struct rsn_rdie
*) pos
;
500 rdie
->descr_count
= 0;
501 rdie
->status_code
= host_to_le16(WLAN_STATUS_SUCCESS
);
502 pos
+= sizeof(*rdie
);
504 if (ieee802_11_parse_elems((u8
*) ies
, ies_len
, &parse
, 1) ==
506 wpa_printf(MSG_DEBUG
, "FT: Failed to parse request IEs");
508 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
513 if (parse
.wmm_tspec
) {
514 struct wmm_tspec_element
*tspec
;
517 if (parse
.wmm_tspec_len
+ 2 < (int) sizeof(*tspec
)) {
518 wpa_printf(MSG_DEBUG
, "FT: Too short WMM TSPEC IE "
519 "(%d)", (int) parse
.wmm_tspec_len
);
521 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
524 if (end
- pos
< (int) sizeof(*tspec
)) {
525 wpa_printf(MSG_ERROR
, "FT: Not enough room for "
528 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
531 tspec
= (struct wmm_tspec_element
*) pos
;
532 os_memcpy(tspec
, parse
.wmm_tspec
- 2, sizeof(*tspec
));
533 res
= wmm_process_tspec(tspec
);
534 wpa_printf(MSG_DEBUG
, "FT: ADDTS processing result: %d", res
);
535 if (res
== WMM_ADDTS_STATUS_INVALID_PARAMETERS
)
537 host_to_le16(WLAN_STATUS_INVALID_PARAMETERS
);
538 else if (res
== WMM_ADDTS_STATUS_REFUSED
)
540 host_to_le16(WLAN_STATUS_REQUEST_DECLINED
);
542 /* TSPEC accepted; include updated TSPEC in response */
543 rdie
->descr_count
= 1;
544 pos
+= sizeof(*tspec
);
548 #endif /* NEED_AP_MLME */
550 wpa_printf(MSG_DEBUG
, "FT: No supported resource requested");
551 rdie
->status_code
= host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
556 static u8
* wpa_ft_process_ric(u8
*pos
, u8
*end
, const u8
*ric
, size_t ric_len
)
558 const u8
*rpos
, *start
;
559 const struct rsn_rdie
*rdie
;
561 wpa_hexdump(MSG_MSGDUMP
, "FT: RIC Request", ric
, ric_len
);
564 while (rpos
+ sizeof(*rdie
) < ric
+ ric_len
) {
565 if (rpos
[0] != WLAN_EID_RIC_DATA
|| rpos
[1] < sizeof(*rdie
) ||
566 rpos
+ 2 + rpos
[1] > ric
+ ric_len
)
568 rdie
= (const struct rsn_rdie
*) (rpos
+ 2);
572 while (rpos
+ 2 <= ric
+ ric_len
&&
573 rpos
+ 2 + rpos
[1] <= ric
+ ric_len
) {
574 if (rpos
[0] == WLAN_EID_RIC_DATA
)
578 pos
= wpa_ft_process_rdie(pos
, end
, rdie
->id
,
580 start
, rpos
- start
);
587 u8
* wpa_sm_write_assoc_resp_ies(struct wpa_state_machine
*sm
, u8
*pos
,
588 size_t max_len
, int auth_alg
,
589 const u8
*req_ies
, size_t req_ies_len
)
591 u8
*end
, *mdie
, *ftie
, *rsnie
= NULL
, *r0kh_id
, *subelem
= NULL
;
592 size_t mdie_len
, ftie_len
, rsnie_len
= 0, r0kh_id_len
, subelem_len
= 0;
594 struct wpa_auth_config
*conf
;
595 struct rsn_ftie
*_ftie
;
596 struct wpa_ft_ies parse
;
603 conf
= &sm
->wpa_auth
->conf
;
605 if (sm
->wpa_key_mgmt
!= WPA_KEY_MGMT_FT_IEEE8021X
&&
606 sm
->wpa_key_mgmt
!= WPA_KEY_MGMT_FT_PSK
)
611 if (auth_alg
== WLAN_AUTH_FT
) {
613 * RSN (only present if this is a Reassociation Response and
614 * part of a fast BSS transition)
616 res
= wpa_write_rsn_ie(conf
, pos
, end
- pos
, sm
->pmk_r1_name
);
624 /* Mobility Domain Information */
625 res
= wpa_write_mdie(conf
, pos
, end
- pos
);
632 /* Fast BSS Transition Information */
633 if (auth_alg
== WLAN_AUTH_FT
) {
634 subelem
= wpa_ft_gtk_subelem(sm
, &subelem_len
);
635 r0kh_id
= sm
->r0kh_id
;
636 r0kh_id_len
= sm
->r0kh_id_len
;
639 #ifdef CONFIG_IEEE80211W
640 if (sm
->mgmt_frame_prot
) {
644 igtk
= wpa_ft_igtk_subelem(sm
, &igtk_len
);
649 nbuf
= os_realloc(subelem
, subelem_len
+ igtk_len
);
656 os_memcpy(subelem
+ subelem_len
, igtk
, igtk_len
);
657 subelem_len
+= igtk_len
;
660 #endif /* CONFIG_IEEE80211W */
662 r0kh_id
= conf
->r0_key_holder
;
663 r0kh_id_len
= conf
->r0_key_holder_len
;
667 res
= wpa_write_ftie(conf
, r0kh_id
, r0kh_id_len
, anonce
, snonce
, pos
,
668 end
- pos
, subelem
, subelem_len
);
676 os_free(sm
->assoc_resp_ftie
);
677 sm
->assoc_resp_ftie
= os_malloc(ftie_len
);
678 if (sm
->assoc_resp_ftie
)
679 os_memcpy(sm
->assoc_resp_ftie
, ftie
, ftie_len
);
681 _ftie
= (struct rsn_ftie
*) (ftie
+ 2);
682 if (auth_alg
== WLAN_AUTH_FT
)
683 _ftie
->mic_control
[1] = 3; /* Information element count */
686 if (wpa_ft_parse_ies(req_ies
, req_ies_len
, &parse
) == 0 && parse
.ric
) {
687 pos
= wpa_ft_process_ric(pos
, end
, parse
.ric
, parse
.ric_len
);
688 if (auth_alg
== WLAN_AUTH_FT
)
689 _ftie
->mic_control
[1] +=
690 ieee802_11_ie_count(ric_start
,
693 if (ric_start
== pos
)
696 if (auth_alg
== WLAN_AUTH_FT
&&
697 wpa_ft_mic(sm
->PTK
.kck
, sm
->addr
, sm
->wpa_auth
->addr
, 6,
698 mdie
, mdie_len
, ftie
, ftie_len
,
700 ric_start
, ric_start
? pos
- ric_start
: 0,
702 wpa_printf(MSG_DEBUG
, "FT: Failed to calculate MIC");
708 static inline int wpa_auth_set_key(struct wpa_authenticator
*wpa_auth
,
710 enum wpa_alg alg
, const u8
*addr
, int idx
,
711 u8
*key
, size_t key_len
)
713 if (wpa_auth
->cb
.set_key
== NULL
)
715 return wpa_auth
->cb
.set_key(wpa_auth
->cb
.ctx
, vlan_id
, alg
, addr
, idx
,
720 void wpa_ft_install_ptk(struct wpa_state_machine
*sm
)
725 /* MLME-SETKEYS.request(PTK) */
726 if (sm
->pairwise
== WPA_CIPHER_TKIP
) {
729 } else if (sm
->pairwise
== WPA_CIPHER_CCMP
) {
733 wpa_printf(MSG_DEBUG
, "FT: Unknown pairwise alg 0x%x - skip "
734 "PTK configuration", sm
->pairwise
);
738 /* FIX: add STA entry to kernel/driver here? The set_key will fail
739 * most likely without this.. At the moment, STA entry is added only
740 * after association has been completed. This function will be called
741 * again after association to get the PTK configured, but that could be
742 * optimized by adding the STA entry earlier.
744 if (wpa_auth_set_key(sm
->wpa_auth
, 0, alg
, sm
->addr
, 0,
748 /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
749 sm
->pairwise_set
= TRUE
;
753 static u16
wpa_ft_process_auth_req(struct wpa_state_machine
*sm
,
754 const u8
*ies
, size_t ies_len
,
755 u8
**resp_ies
, size_t *resp_ies_len
)
757 struct rsn_mdie
*mdie
;
758 struct rsn_ftie
*ftie
;
759 u8 pmk_r1
[PMK_LEN
], pmk_r1_name
[WPA_PMK_NAME_LEN
];
760 u8 ptk_name
[WPA_PMK_NAME_LEN
];
761 struct wpa_auth_config
*conf
;
762 struct wpa_ft_ies parse
;
763 size_t buflen
, ptk_len
;
771 sm
->pmk_r1_name_valid
= 0;
772 conf
= &sm
->wpa_auth
->conf
;
774 wpa_hexdump(MSG_DEBUG
, "FT: Received authentication frame IEs",
777 if (wpa_ft_parse_ies(ies
, ies_len
, &parse
) < 0) {
778 wpa_printf(MSG_DEBUG
, "FT: Failed to parse FT IEs");
779 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
782 mdie
= (struct rsn_mdie
*) parse
.mdie
;
783 if (mdie
== NULL
|| parse
.mdie_len
< sizeof(*mdie
) ||
784 os_memcmp(mdie
->mobility_domain
,
785 sm
->wpa_auth
->conf
.mobility_domain
,
786 MOBILITY_DOMAIN_ID_LEN
) != 0) {
787 wpa_printf(MSG_DEBUG
, "FT: Invalid MDIE");
788 return WLAN_STATUS_INVALID_MDIE
;
791 ftie
= (struct rsn_ftie
*) parse
.ftie
;
792 if (ftie
== NULL
|| parse
.ftie_len
< sizeof(*ftie
)) {
793 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE");
794 return WLAN_STATUS_INVALID_FTIE
;
797 os_memcpy(sm
->SNonce
, ftie
->snonce
, WPA_NONCE_LEN
);
799 if (parse
.r0kh_id
== NULL
) {
800 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE - no R0KH-ID");
801 return WLAN_STATUS_INVALID_FTIE
;
804 wpa_hexdump(MSG_DEBUG
, "FT: STA R0KH-ID",
805 parse
.r0kh_id
, parse
.r0kh_id_len
);
806 os_memcpy(sm
->r0kh_id
, parse
.r0kh_id
, parse
.r0kh_id_len
);
807 sm
->r0kh_id_len
= parse
.r0kh_id_len
;
809 if (parse
.rsn_pmkid
== NULL
) {
810 wpa_printf(MSG_DEBUG
, "FT: No PMKID in RSNIE");
811 return WLAN_STATUS_INVALID_PMKID
;
814 wpa_hexdump(MSG_DEBUG
, "FT: Requested PMKR0Name",
815 parse
.rsn_pmkid
, WPA_PMK_NAME_LEN
);
816 wpa_derive_pmk_r1_name(parse
.rsn_pmkid
,
817 sm
->wpa_auth
->conf
.r1_key_holder
, sm
->addr
,
819 wpa_hexdump(MSG_DEBUG
, "FT: Derived requested PMKR1Name",
820 pmk_r1_name
, WPA_PMK_NAME_LEN
);
822 if (wpa_ft_fetch_pmk_r1(sm
->wpa_auth
, sm
->addr
, pmk_r1_name
, pmk_r1
,
824 if (wpa_ft_pull_pmk_r1(sm
->wpa_auth
, sm
->addr
, sm
->r0kh_id
,
825 sm
->r0kh_id_len
, parse
.rsn_pmkid
) < 0) {
826 wpa_printf(MSG_DEBUG
, "FT: Did not have matching "
827 "PMK-R1 and unknown R0KH-ID");
828 return WLAN_STATUS_INVALID_PMKID
;
832 * TODO: Should return "status pending" (and the caller should
833 * not send out response now). The real response will be sent
834 * once the response from R0KH is received.
836 return WLAN_STATUS_INVALID_PMKID
;
839 wpa_hexdump_key(MSG_DEBUG
, "FT: Selected PMK-R1", pmk_r1
, PMK_LEN
);
840 sm
->pmk_r1_name_valid
= 1;
841 os_memcpy(sm
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
);
843 if (random_get_bytes(sm
->ANonce
, WPA_NONCE_LEN
)) {
844 wpa_printf(MSG_DEBUG
, "FT: Failed to get random data for "
846 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
849 wpa_hexdump(MSG_DEBUG
, "FT: Received SNonce",
850 sm
->SNonce
, WPA_NONCE_LEN
);
851 wpa_hexdump(MSG_DEBUG
, "FT: Generated ANonce",
852 sm
->ANonce
, WPA_NONCE_LEN
);
854 ptk_len
= pairwise
!= WPA_CIPHER_CCMP
? 64 : 48;
855 wpa_pmk_r1_to_ptk(pmk_r1
, sm
->SNonce
, sm
->ANonce
, sm
->addr
,
856 sm
->wpa_auth
->addr
, pmk_r1_name
,
857 (u8
*) &sm
->PTK
, ptk_len
, ptk_name
);
858 wpa_hexdump_key(MSG_DEBUG
, "FT: PTK",
859 (u8
*) &sm
->PTK
, ptk_len
);
860 wpa_hexdump(MSG_DEBUG
, "FT: PTKName", ptk_name
, WPA_PMK_NAME_LEN
);
862 sm
->pairwise
= pairwise
;
863 wpa_ft_install_ptk(sm
);
865 buflen
= 2 + sizeof(struct rsn_mdie
) + 2 + sizeof(struct rsn_ftie
) +
866 2 + FT_R1KH_ID_LEN
+ 200;
867 *resp_ies
= os_zalloc(buflen
);
868 if (*resp_ies
== NULL
) {
869 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
873 end
= *resp_ies
+ buflen
;
875 ret
= wpa_write_rsn_ie(conf
, pos
, end
- pos
, parse
.rsn_pmkid
);
879 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
883 ret
= wpa_write_mdie(conf
, pos
, end
- pos
);
887 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
891 ret
= wpa_write_ftie(conf
, parse
.r0kh_id
, parse
.r0kh_id_len
,
892 sm
->ANonce
, sm
->SNonce
, pos
, end
- pos
, NULL
, 0);
896 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
900 *resp_ies_len
= pos
- *resp_ies
;
902 return WLAN_STATUS_SUCCESS
;
906 void wpa_ft_process_auth(struct wpa_state_machine
*sm
, const u8
*bssid
,
907 u16 auth_transaction
, const u8
*ies
, size_t ies_len
,
908 void (*cb
)(void *ctx
, const u8
*dst
, const u8
*bssid
,
909 u16 auth_transaction
, u16 status
,
910 const u8
*ies
, size_t ies_len
),
918 wpa_printf(MSG_DEBUG
, "FT: Received authentication frame, but "
919 "WPA SM not available");
923 wpa_printf(MSG_DEBUG
, "FT: Received authentication frame: STA=" MACSTR
924 " BSSID=" MACSTR
" transaction=%d",
925 MAC2STR(sm
->addr
), MAC2STR(bssid
), auth_transaction
);
926 status
= wpa_ft_process_auth_req(sm
, ies
, ies_len
, &resp_ies
,
929 wpa_printf(MSG_DEBUG
, "FT: FT authentication response: dst=" MACSTR
930 " auth_transaction=%d status=%d",
931 MAC2STR(sm
->addr
), auth_transaction
+ 1, status
);
932 wpa_hexdump(MSG_DEBUG
, "FT: Response IEs", resp_ies
, resp_ies_len
);
933 cb(ctx
, sm
->addr
, bssid
, auth_transaction
+ 1, status
,
934 resp_ies
, resp_ies_len
);
939 u16
wpa_ft_validate_reassoc(struct wpa_state_machine
*sm
, const u8
*ies
,
942 struct wpa_ft_ies parse
;
943 struct rsn_mdie
*mdie
;
944 struct rsn_ftie
*ftie
;
949 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
951 wpa_hexdump(MSG_DEBUG
, "FT: Reassoc Req IEs", ies
, ies_len
);
953 if (wpa_ft_parse_ies(ies
, ies_len
, &parse
) < 0) {
954 wpa_printf(MSG_DEBUG
, "FT: Failed to parse FT IEs");
955 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
958 if (parse
.rsn
== NULL
) {
959 wpa_printf(MSG_DEBUG
, "FT: No RSNIE in Reassoc Req");
960 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
963 if (parse
.rsn_pmkid
== NULL
) {
964 wpa_printf(MSG_DEBUG
, "FT: No PMKID in RSNIE");
965 return WLAN_STATUS_INVALID_PMKID
;
968 if (os_memcmp(parse
.rsn_pmkid
, sm
->pmk_r1_name
, WPA_PMK_NAME_LEN
) != 0)
970 wpa_printf(MSG_DEBUG
, "FT: PMKID in Reassoc Req did not match "
971 "with the PMKR1Name derived from auth request");
972 return WLAN_STATUS_INVALID_PMKID
;
975 mdie
= (struct rsn_mdie
*) parse
.mdie
;
976 if (mdie
== NULL
|| parse
.mdie_len
< sizeof(*mdie
) ||
977 os_memcmp(mdie
->mobility_domain
,
978 sm
->wpa_auth
->conf
.mobility_domain
,
979 MOBILITY_DOMAIN_ID_LEN
) != 0) {
980 wpa_printf(MSG_DEBUG
, "FT: Invalid MDIE");
981 return WLAN_STATUS_INVALID_MDIE
;
984 ftie
= (struct rsn_ftie
*) parse
.ftie
;
985 if (ftie
== NULL
|| parse
.ftie_len
< sizeof(*ftie
)) {
986 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE");
987 return WLAN_STATUS_INVALID_FTIE
;
990 if (os_memcmp(ftie
->snonce
, sm
->SNonce
, WPA_NONCE_LEN
) != 0) {
991 wpa_printf(MSG_DEBUG
, "FT: SNonce mismatch in FTIE");
992 wpa_hexdump(MSG_DEBUG
, "FT: Received SNonce",
993 ftie
->snonce
, WPA_NONCE_LEN
);
994 wpa_hexdump(MSG_DEBUG
, "FT: Expected SNonce",
995 sm
->SNonce
, WPA_NONCE_LEN
);
999 if (os_memcmp(ftie
->anonce
, sm
->ANonce
, WPA_NONCE_LEN
) != 0) {
1000 wpa_printf(MSG_DEBUG
, "FT: ANonce mismatch in FTIE");
1001 wpa_hexdump(MSG_DEBUG
, "FT: Received ANonce",
1002 ftie
->anonce
, WPA_NONCE_LEN
);
1003 wpa_hexdump(MSG_DEBUG
, "FT: Expected ANonce",
1004 sm
->ANonce
, WPA_NONCE_LEN
);
1009 if (parse
.r0kh_id
== NULL
) {
1010 wpa_printf(MSG_DEBUG
, "FT: No R0KH-ID subelem in FTIE");
1014 if (parse
.r0kh_id_len
!= sm
->r0kh_id_len
||
1015 os_memcmp(parse
.r0kh_id
, sm
->r0kh_id
, parse
.r0kh_id_len
) != 0) {
1016 wpa_printf(MSG_DEBUG
, "FT: R0KH-ID in FTIE did not match with "
1017 "the current R0KH-ID");
1018 wpa_hexdump(MSG_DEBUG
, "FT: R0KH-ID in FTIE",
1019 parse
.r0kh_id
, parse
.r0kh_id_len
);
1020 wpa_hexdump(MSG_DEBUG
, "FT: The current R0KH-ID",
1021 sm
->r0kh_id
, sm
->r0kh_id_len
);
1025 if (parse
.r1kh_id
== NULL
) {
1026 wpa_printf(MSG_DEBUG
, "FT: No R1KH-ID subelem in FTIE");
1030 if (os_memcmp(parse
.r1kh_id
, sm
->wpa_auth
->conf
.r1_key_holder
,
1031 FT_R1KH_ID_LEN
) != 0) {
1032 wpa_printf(MSG_DEBUG
, "FT: Unknown R1KH-ID used in "
1034 wpa_hexdump(MSG_DEBUG
, "FT: R1KH-ID in FTIE",
1035 parse
.r1kh_id
, FT_R1KH_ID_LEN
);
1036 wpa_hexdump(MSG_DEBUG
, "FT: Expected R1KH-ID",
1037 sm
->wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
);
1041 if (parse
.rsn_pmkid
== NULL
||
1042 os_memcmp(parse
.rsn_pmkid
, sm
->pmk_r1_name
, WPA_PMK_NAME_LEN
)) {
1043 wpa_printf(MSG_DEBUG
, "FT: No matching PMKR1Name (PMKID) in "
1044 "RSNIE (pmkid=%d)", !!parse
.rsn_pmkid
);
1050 count
+= ieee802_11_ie_count(parse
.ric
, parse
.ric_len
);
1051 if (ftie
->mic_control
[1] != count
) {
1052 wpa_printf(MSG_DEBUG
, "FT: Unexpected IE count in MIC "
1053 "Control: received %u expected %u",
1054 ftie
->mic_control
[1], count
);
1058 if (wpa_ft_mic(sm
->PTK
.kck
, sm
->addr
, sm
->wpa_auth
->addr
, 5,
1059 parse
.mdie
- 2, parse
.mdie_len
+ 2,
1060 parse
.ftie
- 2, parse
.ftie_len
+ 2,
1061 parse
.rsn
- 2, parse
.rsn_len
+ 2,
1062 parse
.ric
, parse
.ric_len
,
1064 wpa_printf(MSG_DEBUG
, "FT: Failed to calculate MIC");
1065 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1068 if (os_memcmp(mic
, ftie
->mic
, 16) != 0) {
1069 wpa_printf(MSG_DEBUG
, "FT: Invalid MIC in FTIE");
1070 wpa_hexdump(MSG_MSGDUMP
, "FT: Received MIC", ftie
->mic
, 16);
1071 wpa_hexdump(MSG_MSGDUMP
, "FT: Calculated MIC", mic
, 16);
1072 return WLAN_STATUS_INVALID_FTIE
;
1075 return WLAN_STATUS_SUCCESS
;
1079 int wpa_ft_action_rx(struct wpa_state_machine
*sm
, const u8
*data
, size_t len
)
1081 const u8
*sta_addr
, *target_ap
;
1085 struct ft_rrb_frame
*frame
;
1091 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1092 * FT Request action frame body[variable]
1096 wpa_printf(MSG_DEBUG
, "FT: Too short FT Action frame "
1097 "(len=%lu)", (unsigned long) len
);
1102 sta_addr
= data
+ 2;
1103 target_ap
= data
+ 8;
1107 wpa_printf(MSG_DEBUG
, "FT: Received FT Action frame (STA=" MACSTR
1108 " Target AP=" MACSTR
" Action=%d)",
1109 MAC2STR(sta_addr
), MAC2STR(target_ap
), action
);
1111 if (os_memcmp(sta_addr
, sm
->addr
, ETH_ALEN
) != 0) {
1112 wpa_printf(MSG_DEBUG
, "FT: Mismatch in FT Action STA address: "
1113 "STA=" MACSTR
" STA-Address=" MACSTR
,
1114 MAC2STR(sm
->addr
), MAC2STR(sta_addr
));
1119 * Do some sanity checking on the target AP address (not own and not
1120 * broadcast. This could be extended to filter based on a list of known
1121 * APs in the MD (if such a list were configured).
1123 if ((target_ap
[0] & 0x01) ||
1124 os_memcmp(target_ap
, sm
->wpa_auth
->addr
, ETH_ALEN
) == 0) {
1125 wpa_printf(MSG_DEBUG
, "FT: Invalid Target AP in FT Action "
1130 wpa_hexdump(MSG_MSGDUMP
, "FT: Action frame body", ies
, ies_len
);
1132 /* RRB - Forward action frame to the target AP */
1133 frame
= os_malloc(sizeof(*frame
) + len
);
1134 frame
->frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1135 frame
->packet_type
= FT_PACKET_REQUEST
;
1136 frame
->action_length
= host_to_le16(len
);
1137 os_memcpy(frame
->ap_address
, sm
->wpa_auth
->addr
, ETH_ALEN
);
1138 os_memcpy(frame
+ 1, data
, len
);
1140 wpa_ft_rrb_send(sm
->wpa_auth
, target_ap
, (u8
*) frame
,
1141 sizeof(*frame
) + len
);
1148 static int wpa_ft_rrb_rx_request(struct wpa_authenticator
*wpa_auth
,
1149 const u8
*current_ap
, const u8
*sta_addr
,
1150 const u8
*body
, size_t len
)
1152 struct wpa_state_machine
*sm
;
1155 size_t resp_ies_len
, rlen
;
1156 struct ft_rrb_frame
*frame
;
1158 sm
= wpa_ft_add_sta(wpa_auth
, sta_addr
);
1160 wpa_printf(MSG_DEBUG
, "FT: Failed to add new STA based on "
1165 wpa_hexdump(MSG_MSGDUMP
, "FT: RRB Request Frame body", body
, len
);
1167 status
= wpa_ft_process_auth_req(sm
, body
, len
, &resp_ies
,
1170 wpa_printf(MSG_DEBUG
, "FT: RRB authentication response: STA=" MACSTR
1171 " CurrentAP=" MACSTR
" status=%d",
1172 MAC2STR(sm
->addr
), MAC2STR(current_ap
), status
);
1173 wpa_hexdump(MSG_DEBUG
, "FT: Response IEs", resp_ies
, resp_ies_len
);
1175 /* RRB - Forward action frame response to the Current AP */
1178 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1179 * Status_Code[2] FT Request action frame body[variable]
1181 rlen
= 2 + 2 * ETH_ALEN
+ 2 + resp_ies_len
;
1183 frame
= os_malloc(sizeof(*frame
) + rlen
);
1184 frame
->frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1185 frame
->packet_type
= FT_PACKET_RESPONSE
;
1186 frame
->action_length
= host_to_le16(rlen
);
1187 os_memcpy(frame
->ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1188 pos
= (u8
*) (frame
+ 1);
1189 *pos
++ = WLAN_ACTION_FT
;
1190 *pos
++ = 2; /* Action: Response */
1191 os_memcpy(pos
, sta_addr
, ETH_ALEN
);
1193 os_memcpy(pos
, wpa_auth
->addr
, ETH_ALEN
);
1195 WPA_PUT_LE16(pos
, status
);
1198 os_memcpy(pos
, resp_ies
, resp_ies_len
);
1202 wpa_ft_rrb_send(wpa_auth
, current_ap
, (u8
*) frame
,
1203 sizeof(*frame
) + rlen
);
1210 static int wpa_ft_rrb_rx_pull(struct wpa_authenticator
*wpa_auth
,
1212 const u8
*data
, size_t data_len
)
1214 struct ft_r0kh_r1kh_pull_frame
*frame
, f
;
1215 struct ft_remote_r1kh
*r1kh
;
1216 struct ft_r0kh_r1kh_resp_frame resp
, r
;
1220 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 pull");
1222 if (data_len
< sizeof(*frame
))
1225 r1kh
= wpa_auth
->conf
.r1kh_list
;
1227 if (os_memcmp(r1kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1232 wpa_printf(MSG_DEBUG
, "FT: No matching R1KH address found for "
1233 "PMK-R1 pull source address " MACSTR
,
1238 frame
= (struct ft_r0kh_r1kh_pull_frame
*) data
;
1239 /* aes_unwrap() does not support inplace decryption, so use a temporary
1240 * buffer for the data. */
1241 if (aes_unwrap(r1kh
->key
, (FT_R0KH_R1KH_PULL_DATA_LEN
+ 7) / 8,
1242 frame
->nonce
, f
.nonce
) < 0) {
1243 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 pull "
1244 "request from " MACSTR
, MAC2STR(src_addr
));
1248 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - nonce",
1249 f
.nonce
, sizeof(f
.nonce
));
1250 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - PMKR0Name",
1251 f
.pmk_r0_name
, WPA_PMK_NAME_LEN
);
1252 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
"S1KH-ID="
1253 MACSTR
, MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
));
1255 os_memset(&resp
, 0, sizeof(resp
));
1256 resp
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1257 resp
.packet_type
= FT_PACKET_R0KH_R1KH_RESP
;
1258 resp
.data_length
= host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN
);
1259 os_memcpy(resp
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1261 /* aes_wrap() does not support inplace encryption, so use a temporary
1262 * buffer for the data. */
1263 os_memcpy(r
.nonce
, f
.nonce
, sizeof(f
.nonce
));
1264 os_memcpy(r
.r1kh_id
, f
.r1kh_id
, FT_R1KH_ID_LEN
);
1265 os_memcpy(r
.s1kh_id
, f
.s1kh_id
, ETH_ALEN
);
1266 if (wpa_ft_fetch_pmk_r0(wpa_auth
, f
.s1kh_id
, f
.pmk_r0_name
, pmk_r0
,
1268 wpa_printf(MSG_DEBUG
, "FT: No matching PMKR0Name found for "
1273 wpa_derive_pmk_r1(pmk_r0
, f
.pmk_r0_name
, f
.r1kh_id
, f
.s1kh_id
,
1274 r
.pmk_r1
, r
.pmk_r1_name
);
1275 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", r
.pmk_r1
, PMK_LEN
);
1276 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", r
.pmk_r1_name
,
1278 r
.pairwise
= host_to_le16(pairwise
);
1280 if (aes_wrap(r1kh
->key
, (FT_R0KH_R1KH_RESP_DATA_LEN
+ 7) / 8,
1281 r
.nonce
, resp
.nonce
) < 0) {
1282 os_memset(pmk_r0
, 0, PMK_LEN
);
1286 os_memset(pmk_r0
, 0, PMK_LEN
);
1288 wpa_ft_rrb_send(wpa_auth
, src_addr
, (u8
*) &resp
, sizeof(resp
));
1294 static int wpa_ft_rrb_rx_resp(struct wpa_authenticator
*wpa_auth
,
1296 const u8
*data
, size_t data_len
)
1298 struct ft_r0kh_r1kh_resp_frame
*frame
, f
;
1299 struct ft_remote_r0kh
*r0kh
;
1302 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 pull response");
1304 if (data_len
< sizeof(*frame
))
1307 r0kh
= wpa_auth
->conf
.r0kh_list
;
1309 if (os_memcmp(r0kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1314 wpa_printf(MSG_DEBUG
, "FT: No matching R0KH address found for "
1315 "PMK-R0 pull response source address " MACSTR
,
1320 frame
= (struct ft_r0kh_r1kh_resp_frame
*) data
;
1321 /* aes_unwrap() does not support inplace decryption, so use a temporary
1322 * buffer for the data. */
1323 if (aes_unwrap(r0kh
->key
, (FT_R0KH_R1KH_RESP_DATA_LEN
+ 7) / 8,
1324 frame
->nonce
, f
.nonce
) < 0) {
1325 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 pull "
1326 "response from " MACSTR
, MAC2STR(src_addr
));
1330 if (os_memcmp(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
)
1332 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull response did not use a "
1333 "matching R1KH-ID");
1337 /* TODO: verify that <nonce,s1kh_id> matches with a pending request
1338 * and call this requests callback function to finish request
1341 pairwise
= le_to_host16(f
.pairwise
);
1342 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - nonce",
1343 f
.nonce
, sizeof(f
.nonce
));
1344 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
"S1KH-ID="
1345 MACSTR
" pairwise=0x%x",
1346 MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
), pairwise
);
1347 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1 pull - PMK-R1",
1349 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - PMKR1Name",
1350 f
.pmk_r1_name
, WPA_PMK_NAME_LEN
);
1352 wpa_ft_store_pmk_r1(wpa_auth
, f
.s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
,
1354 os_memset(f
.pmk_r1
, 0, PMK_LEN
);
1360 static int wpa_ft_rrb_rx_push(struct wpa_authenticator
*wpa_auth
,
1362 const u8
*data
, size_t data_len
)
1364 struct ft_r0kh_r1kh_push_frame
*frame
, f
;
1365 struct ft_remote_r0kh
*r0kh
;
1370 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 push");
1372 if (data_len
< sizeof(*frame
))
1375 r0kh
= wpa_auth
->conf
.r0kh_list
;
1377 if (os_memcmp(r0kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1382 wpa_printf(MSG_DEBUG
, "FT: No matching R0KH address found for "
1383 "PMK-R0 push source address " MACSTR
,
1388 frame
= (struct ft_r0kh_r1kh_push_frame
*) data
;
1389 /* aes_unwrap() does not support inplace decryption, so use a temporary
1390 * buffer for the data. */
1391 if (aes_unwrap(r0kh
->key
, (FT_R0KH_R1KH_PUSH_DATA_LEN
+ 7) / 8,
1392 frame
->timestamp
, f
.timestamp
) < 0) {
1393 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 push from "
1394 MACSTR
, MAC2STR(src_addr
));
1399 tsend
= WPA_GET_LE32(f
.timestamp
);
1400 if ((now
.sec
> tsend
&& now
.sec
- tsend
> 60) ||
1401 (now
.sec
< tsend
&& tsend
- now
.sec
> 60)) {
1402 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push did not have a valid "
1403 "timestamp: sender time %d own time %d\n",
1404 (int) tsend
, (int) now
.sec
);
1408 if (os_memcmp(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
)
1410 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push did not use a matching "
1411 "R1KH-ID (received " MACSTR
" own " MACSTR
")",
1413 MAC2STR(wpa_auth
->conf
.r1_key_holder
));
1417 pairwise
= le_to_host16(f
.pairwise
);
1418 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push - R1KH-ID=" MACSTR
" S1KH-ID="
1419 MACSTR
" pairwise=0x%x",
1420 MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
), pairwise
);
1421 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1 push - PMK-R1",
1423 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 push - PMKR1Name",
1424 f
.pmk_r1_name
, WPA_PMK_NAME_LEN
);
1426 wpa_ft_store_pmk_r1(wpa_auth
, f
.s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
,
1428 os_memset(f
.pmk_r1
, 0, PMK_LEN
);
1434 int wpa_ft_rrb_rx(struct wpa_authenticator
*wpa_auth
, const u8
*src_addr
,
1435 const u8
*data
, size_t data_len
)
1437 struct ft_rrb_frame
*frame
;
1439 const u8
*pos
, *end
, *start
;
1441 const u8
*sta_addr
, *target_ap_addr
;
1443 wpa_printf(MSG_DEBUG
, "FT: RRB received frame from remote AP " MACSTR
,
1446 if (data_len
< sizeof(*frame
)) {
1447 wpa_printf(MSG_DEBUG
, "FT: Too short RRB frame (data_len=%lu)",
1448 (unsigned long) data_len
);
1453 frame
= (struct ft_rrb_frame
*) pos
;
1454 pos
+= sizeof(*frame
);
1456 alen
= le_to_host16(frame
->action_length
);
1457 wpa_printf(MSG_DEBUG
, "FT: RRB frame - frame_type=%d packet_type=%d "
1458 "action_length=%d ap_address=" MACSTR
,
1459 frame
->frame_type
, frame
->packet_type
, alen
,
1460 MAC2STR(frame
->ap_address
));
1462 if (frame
->frame_type
!= RSN_REMOTE_FRAME_TYPE_FT_RRB
) {
1463 /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
1464 wpa_printf(MSG_DEBUG
, "FT: RRB discarded frame with "
1465 "unrecognized type %d", frame
->frame_type
);
1469 if (alen
> data_len
- sizeof(*frame
)) {
1470 wpa_printf(MSG_DEBUG
, "FT: RRB frame too short for action "
1475 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_PULL
)
1476 return wpa_ft_rrb_rx_pull(wpa_auth
, src_addr
, data
, data_len
);
1477 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_RESP
)
1478 return wpa_ft_rrb_rx_resp(wpa_auth
, src_addr
, data
, data_len
);
1479 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_PUSH
)
1480 return wpa_ft_rrb_rx_push(wpa_auth
, src_addr
, data
, data_len
);
1482 wpa_hexdump(MSG_MSGDUMP
, "FT: RRB - FT Action frame", pos
, alen
);
1484 if (alen
< 1 + 1 + 2 * ETH_ALEN
) {
1485 wpa_printf(MSG_DEBUG
, "FT: Too short RRB frame (not enough "
1486 "room for Action Frame body); alen=%lu",
1487 (unsigned long) alen
);
1493 if (*pos
!= WLAN_ACTION_FT
) {
1494 wpa_printf(MSG_DEBUG
, "FT: Unexpected Action frame category "
1503 target_ap_addr
= pos
;
1505 wpa_printf(MSG_DEBUG
, "FT: RRB Action Frame: action=%d sta_addr="
1506 MACSTR
" target_ap_addr=" MACSTR
,
1507 action
, MAC2STR(sta_addr
), MAC2STR(target_ap_addr
));
1509 if (frame
->packet_type
== FT_PACKET_REQUEST
) {
1510 wpa_printf(MSG_DEBUG
, "FT: FT Packet Type - Request");
1513 wpa_printf(MSG_DEBUG
, "FT: Unexpected Action %d in "
1514 "RRB Request", action
);
1518 if (os_memcmp(target_ap_addr
, wpa_auth
->addr
, ETH_ALEN
) != 0) {
1519 wpa_printf(MSG_DEBUG
, "FT: Target AP address in the "
1520 "RRB Request does not match with own "
1525 if (wpa_ft_rrb_rx_request(wpa_auth
, frame
->ap_address
,
1526 sta_addr
, pos
, end
- pos
) < 0)
1528 } else if (frame
->packet_type
== FT_PACKET_RESPONSE
) {
1531 if (end
- pos
< 2) {
1532 wpa_printf(MSG_DEBUG
, "FT: Not enough room for status "
1533 "code in RRB Response");
1536 status_code
= WPA_GET_LE16(pos
);
1539 wpa_printf(MSG_DEBUG
, "FT: FT Packet Type - Response "
1540 "(status_code=%d)", status_code
);
1542 if (wpa_ft_action_send(wpa_auth
, sta_addr
, start
, alen
) < 0)
1545 wpa_printf(MSG_DEBUG
, "FT: RRB discarded frame with unknown "
1546 "packet_type %d", frame
->packet_type
);
1554 static void wpa_ft_generate_pmk_r1(struct wpa_authenticator
*wpa_auth
,
1555 struct wpa_ft_pmk_r0_sa
*pmk_r0
,
1556 struct ft_remote_r1kh
*r1kh
,
1557 const u8
*s1kh_id
, int pairwise
)
1559 struct ft_r0kh_r1kh_push_frame frame
, f
;
1562 os_memset(&frame
, 0, sizeof(frame
));
1563 frame
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1564 frame
.packet_type
= FT_PACKET_R0KH_R1KH_PUSH
;
1565 frame
.data_length
= host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN
);
1566 os_memcpy(frame
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1568 /* aes_wrap() does not support inplace encryption, so use a temporary
1569 * buffer for the data. */
1570 os_memcpy(f
.r1kh_id
, r1kh
->id
, FT_R1KH_ID_LEN
);
1571 os_memcpy(f
.s1kh_id
, s1kh_id
, ETH_ALEN
);
1572 os_memcpy(f
.pmk_r0_name
, pmk_r0
->pmk_r0_name
, WPA_PMK_NAME_LEN
);
1573 wpa_derive_pmk_r1(pmk_r0
->pmk_r0
, pmk_r0
->pmk_r0_name
, r1kh
->id
,
1574 s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
);
1575 wpa_printf(MSG_DEBUG
, "FT: R1KH-ID " MACSTR
, MAC2STR(r1kh
->id
));
1576 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", f
.pmk_r1
, PMK_LEN
);
1577 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", f
.pmk_r1_name
,
1580 WPA_PUT_LE32(f
.timestamp
, now
.sec
);
1581 f
.pairwise
= host_to_le16(pairwise
);
1582 if (aes_wrap(r1kh
->key
, (FT_R0KH_R1KH_PUSH_DATA_LEN
+ 7) / 8,
1583 f
.timestamp
, frame
.timestamp
) < 0)
1586 wpa_ft_rrb_send(wpa_auth
, r1kh
->addr
, (u8
*) &frame
, sizeof(frame
));
1590 void wpa_ft_push_pmk_r1(struct wpa_authenticator
*wpa_auth
, const u8
*addr
)
1592 struct wpa_ft_pmk_r0_sa
*r0
;
1593 struct ft_remote_r1kh
*r1kh
;
1595 if (!wpa_auth
->conf
.pmk_r1_push
)
1598 r0
= wpa_auth
->ft_pmk_cache
->pmk_r0
;
1600 if (os_memcmp(r0
->spa
, addr
, ETH_ALEN
) == 0)
1605 if (r0
== NULL
|| r0
->pmk_r1_pushed
)
1607 r0
->pmk_r1_pushed
= 1;
1609 wpa_printf(MSG_DEBUG
, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
1610 "for STA " MACSTR
, MAC2STR(addr
));
1612 r1kh
= wpa_auth
->conf
.r1kh_list
;
1614 wpa_ft_generate_pmk_r1(wpa_auth
, r0
, r1kh
, addr
, r0
->pairwise
);
1619 #endif /* CONFIG_IEEE80211R */