2 * hostapd - IEEE 802.11r - Fast BSS Transition
3 * Copyright (c) 2004-2007, 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.
21 #include "ieee802_11.h"
23 #include "wpa_auth_i.h"
24 #include "wpa_auth_ie.h"
27 #ifdef CONFIG_IEEE80211R
29 static int wpa_ft_rrb_send(struct wpa_authenticator
*wpa_auth
, const u8
*dst
,
30 const u8
*data
, size_t data_len
)
32 if (wpa_auth
->cb
.send_ether
== NULL
)
34 return wpa_auth
->cb
.send_ether(wpa_auth
->cb
.ctx
, dst
, ETH_P_RRB
,
39 static int wpa_ft_action_send(struct wpa_authenticator
*wpa_auth
,
40 const u8
*dst
, const u8
*data
, size_t data_len
)
42 if (wpa_auth
->cb
.send_ft_action
== NULL
)
44 return wpa_auth
->cb
.send_ft_action(wpa_auth
->cb
.ctx
, dst
,
49 static struct wpa_state_machine
*
50 wpa_ft_add_sta(struct wpa_authenticator
*wpa_auth
, const u8
*sta_addr
)
52 if (wpa_auth
->cb
.add_sta
== NULL
)
54 return wpa_auth
->cb
.add_sta(wpa_auth
->cb
.ctx
, sta_addr
);
58 int wpa_write_mdie(struct wpa_auth_config
*conf
, u8
*buf
, size_t len
)
62 if (len
< 2 + sizeof(struct rsn_mdie
))
65 *pos
++ = WLAN_EID_MOBILITY_DOMAIN
;
66 *pos
++ = MOBILITY_DOMAIN_ID_LEN
+ 1;
67 os_memcpy(pos
, conf
->mobility_domain
, MOBILITY_DOMAIN_ID_LEN
);
68 pos
+= MOBILITY_DOMAIN_ID_LEN
;
69 capab
= RSN_FT_CAPAB_FT_OVER_DS
;
76 static int wpa_write_ftie(struct wpa_auth_config
*conf
, const u8
*r0kh_id
,
78 const u8
*anonce
, const u8
*snonce
,
79 u8
*buf
, size_t len
, const u8
*subelem
,
82 u8
*pos
= buf
, *ielen
;
85 if (len
< 2 + sizeof(*hdr
) + 2 + FT_R1KH_ID_LEN
+ 2 + r0kh_id_len
+
89 *pos
++ = WLAN_EID_FAST_BSS_TRANSITION
;
92 hdr
= (struct rsn_ftie
*) pos
;
93 os_memset(hdr
, 0, sizeof(*hdr
));
95 WPA_PUT_LE16(hdr
->mic_control
, 0);
97 os_memcpy(hdr
->anonce
, anonce
, WPA_NONCE_LEN
);
99 os_memcpy(hdr
->snonce
, snonce
, WPA_NONCE_LEN
);
101 /* Optional Parameters */
102 *pos
++ = FTIE_SUBELEM_R1KH_ID
;
103 *pos
++ = FT_R1KH_ID_LEN
;
104 os_memcpy(pos
, conf
->r1_key_holder
, FT_R1KH_ID_LEN
);
105 pos
+= FT_R1KH_ID_LEN
;
108 *pos
++ = FTIE_SUBELEM_R0KH_ID
;
109 *pos
++ = r0kh_id_len
;
110 os_memcpy(pos
, r0kh_id
, r0kh_id_len
);
115 os_memcpy(pos
, subelem
, subelem_len
);
119 *ielen
= pos
- buf
- 2;
125 struct wpa_ft_pmk_r0_sa
{
126 struct wpa_ft_pmk_r0_sa
*next
;
128 u8 pmk_r0_name
[WPA_PMK_NAME_LEN
];
130 /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
134 struct wpa_ft_pmk_r1_sa
{
135 struct wpa_ft_pmk_r1_sa
*next
;
137 u8 pmk_r1_name
[WPA_PMK_NAME_LEN
];
139 /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
142 struct wpa_ft_pmk_cache
{
143 struct wpa_ft_pmk_r0_sa
*pmk_r0
;
144 struct wpa_ft_pmk_r1_sa
*pmk_r1
;
147 struct wpa_ft_pmk_cache
* wpa_ft_pmk_cache_init(void)
149 struct wpa_ft_pmk_cache
*cache
;
151 cache
= os_zalloc(sizeof(*cache
));
157 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache
*cache
)
159 struct wpa_ft_pmk_r0_sa
*r0
, *r0prev
;
160 struct wpa_ft_pmk_r1_sa
*r1
, *r1prev
;
166 os_memset(r0prev
->pmk_r0
, 0, PMK_LEN
);
174 os_memset(r1prev
->pmk_r1
, 0, PMK_LEN
);
182 static int wpa_ft_store_pmk_r0(struct wpa_authenticator
*wpa_auth
,
183 const u8
*spa
, const u8
*pmk_r0
,
184 const u8
*pmk_r0_name
)
186 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
187 struct wpa_ft_pmk_r0_sa
*r0
;
189 /* TODO: add expiration and limit on number of entries in cache */
191 r0
= os_zalloc(sizeof(*r0
));
195 os_memcpy(r0
->pmk_r0
, pmk_r0
, PMK_LEN
);
196 os_memcpy(r0
->pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
);
197 os_memcpy(r0
->spa
, spa
, ETH_ALEN
);
199 r0
->next
= cache
->pmk_r0
;
206 static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator
*wpa_auth
,
207 const u8
*spa
, const u8
*pmk_r0_name
,
210 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
211 struct wpa_ft_pmk_r0_sa
*r0
;
215 if (os_memcmp(r0
->spa
, spa
, ETH_ALEN
) == 0 &&
216 os_memcmp(r0
->pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
)
218 os_memcpy(pmk_r0
, r0
->pmk_r0
, PMK_LEN
);
229 static int wpa_ft_store_pmk_r1(struct wpa_authenticator
*wpa_auth
,
230 const u8
*spa
, const u8
*pmk_r1
,
231 const u8
*pmk_r1_name
)
233 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
234 struct wpa_ft_pmk_r1_sa
*r1
;
236 /* TODO: add expiration and limit on number of entries in cache */
238 r1
= os_zalloc(sizeof(*r1
));
242 os_memcpy(r1
->pmk_r1
, pmk_r1
, PMK_LEN
);
243 os_memcpy(r1
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
);
244 os_memcpy(r1
->spa
, spa
, ETH_ALEN
);
246 r1
->next
= cache
->pmk_r1
;
253 static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator
*wpa_auth
,
254 const u8
*spa
, const u8
*pmk_r1_name
,
257 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
258 struct wpa_ft_pmk_r1_sa
*r1
;
262 if (os_memcmp(r1
->spa
, spa
, ETH_ALEN
) == 0 &&
263 os_memcmp(r1
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
)
265 os_memcpy(pmk_r1
, r1
->pmk_r1
, PMK_LEN
);
276 static int wpa_ft_pull_pmk_r1(struct wpa_authenticator
*wpa_auth
,
277 const u8
*s1kh_id
, const u8
*r0kh_id
,
278 size_t r0kh_id_len
, const u8
*pmk_r0_name
)
280 struct ft_remote_r0kh
*r0kh
;
281 struct ft_r0kh_r1kh_pull_frame frame
, f
;
283 r0kh
= wpa_auth
->conf
.r0kh_list
;
285 if (r0kh
->id_len
== r0kh_id_len
&&
286 os_memcmp(r0kh
->id
, r0kh_id
, r0kh_id_len
) == 0)
293 wpa_printf(MSG_DEBUG
, "FT: Send PMK-R1 pull request to remote R0KH "
294 "address " MACSTR
, MAC2STR(r0kh
->addr
));
296 os_memset(&frame
, 0, sizeof(frame
));
297 frame
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
298 frame
.packet_type
= FT_PACKET_R0KH_R1KH_PULL
;
299 frame
.data_length
= host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN
);
300 os_memcpy(frame
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
302 /* aes_wrap() does not support inplace encryption, so use a temporary
303 * buffer for the data. */
304 if (os_get_random(f
.nonce
, sizeof(f
.nonce
))) {
305 wpa_printf(MSG_DEBUG
, "FT: Failed to get random data for "
309 os_memcpy(f
.pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
);
310 os_memcpy(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
);
311 os_memcpy(f
.s1kh_id
, s1kh_id
, ETH_ALEN
);
313 if (aes_wrap(r0kh
->key
, (FT_R0KH_R1KH_PULL_DATA_LEN
+ 7) / 8,
314 f
.nonce
, frame
.nonce
) < 0)
317 wpa_ft_rrb_send(wpa_auth
, r0kh
->addr
, (u8
*) &frame
, sizeof(frame
));
323 int wpa_auth_derive_ptk_ft(struct wpa_state_machine
*sm
, const u8
*pmk
,
324 struct wpa_ptk
*ptk
, size_t ptk_len
)
326 u8 pmk_r0
[PMK_LEN
], pmk_r0_name
[WPA_PMK_NAME_LEN
];
327 u8 pmk_r1
[PMK_LEN
], pmk_r1_name
[WPA_PMK_NAME_LEN
];
328 u8 ptk_name
[WPA_PMK_NAME_LEN
];
329 const u8
*mdid
= sm
->wpa_auth
->conf
.mobility_domain
;
330 const u8
*r0kh
= sm
->wpa_auth
->conf
.r0_key_holder
;
331 size_t r0kh_len
= sm
->wpa_auth
->conf
.r0_key_holder_len
;
332 const u8
*r1kh
= sm
->wpa_auth
->conf
.r1_key_holder
;
333 const u8
*ssid
= sm
->wpa_auth
->conf
.ssid
;
334 size_t ssid_len
= sm
->wpa_auth
->conf
.ssid_len
;
337 if (sm
->xxkey_len
== 0) {
338 wpa_printf(MSG_DEBUG
, "FT: XXKey not available for key "
343 wpa_derive_pmk_r0(sm
->xxkey
, sm
->xxkey_len
, ssid
, ssid_len
, mdid
,
344 r0kh
, r0kh_len
, sm
->addr
, pmk_r0
, pmk_r0_name
);
345 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R0", pmk_r0
, PMK_LEN
);
346 wpa_hexdump(MSG_DEBUG
, "FT: PMKR0Name", pmk_r0_name
, WPA_PMK_NAME_LEN
);
347 wpa_ft_store_pmk_r0(sm
->wpa_auth
, sm
->addr
, pmk_r0
, pmk_r0_name
);
349 wpa_derive_pmk_r1(pmk_r0
, pmk_r0_name
, r1kh
, sm
->addr
,
350 pmk_r1
, pmk_r1_name
);
351 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", pmk_r1
, PMK_LEN
);
352 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", pmk_r1_name
, WPA_PMK_NAME_LEN
);
353 wpa_ft_store_pmk_r1(sm
->wpa_auth
, sm
->addr
, pmk_r1
, pmk_r1_name
);
355 wpa_pmk_r1_to_ptk(pmk_r1
, sm
->SNonce
, sm
->ANonce
, sm
->addr
,
356 sm
->wpa_auth
->addr
, pmk_r1_name
,
357 (u8
*) ptk
, ptk_len
, ptk_name
);
358 wpa_hexdump_key(MSG_DEBUG
, "FT: PTK", (u8
*) ptk
, ptk_len
);
359 wpa_hexdump(MSG_DEBUG
, "FT: PTKName", ptk_name
, WPA_PMK_NAME_LEN
);
365 static inline int wpa_auth_get_seqnum(struct wpa_authenticator
*wpa_auth
,
366 const u8
*addr
, int idx
, u8
*seq
)
368 if (wpa_auth
->cb
.get_seqnum
== NULL
)
370 return wpa_auth
->cb
.get_seqnum(wpa_auth
->cb
.ctx
, addr
, idx
, seq
);
374 #ifdef CONFIG_IEEE80211W
375 static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator
*wpa_auth
,
376 const u8
*addr
, int idx
, u8
*seq
)
378 if (wpa_auth
->cb
.get_seqnum_igtk
== NULL
)
380 return wpa_auth
->cb
.get_seqnum_igtk(wpa_auth
->cb
.ctx
, addr
, idx
, seq
);
382 #endif /* CONFIG_IEEE80211W */
385 static u8
* wpa_ft_gtk_subelem(struct wpa_state_machine
*sm
, size_t *len
)
388 struct wpa_group
*gsm
= sm
->group
;
389 size_t subelem_len
, pad_len
;
394 key_len
= gsm
->GTK_len
;
395 if (key_len
> sizeof(keybuf
))
399 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
402 pad_len
= key_len
% 8;
404 pad_len
= 8 - pad_len
;
405 if (key_len
+ pad_len
< 16)
408 os_memcpy(keybuf
, gsm
->GTK
[gsm
->GN
- 1], key_len
);
409 os_memset(keybuf
+ key_len
, 0, pad_len
);
410 keybuf
[key_len
] = 0xdd;
414 key
= gsm
->GTK
[gsm
->GN
- 1];
417 * Sub-elem ID[1] | Length[1] | Key Info[1] | Key Length[1] | RSC[8] |
420 subelem_len
= 12 + key_len
+ 8;
421 subelem
= os_zalloc(subelem_len
);
425 subelem
[0] = FTIE_SUBELEM_GTK
;
426 subelem
[1] = 10 + key_len
+ 8;
427 subelem
[2] = gsm
->GN
& 0x03; /* Key ID in B0-B1 of Key Info */
428 subelem
[3] = gsm
->GTK_len
;
429 wpa_auth_get_seqnum(sm
->wpa_auth
, NULL
, gsm
->GN
, subelem
+ 4);
430 if (aes_wrap(sm
->PTK
.kek
, key_len
/ 8, key
, subelem
+ 12)) {
440 #ifdef CONFIG_IEEE80211W
441 static u8
* wpa_ft_igtk_subelem(struct wpa_state_machine
*sm
, size_t *len
)
444 struct wpa_group
*gsm
= sm
->group
;
447 /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
449 subelem_len
= 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN
+ 8;
450 subelem
= os_zalloc(subelem_len
);
455 *pos
++ = FTIE_SUBELEM_IGTK
;
456 *pos
++ = subelem_len
- 2;
457 WPA_PUT_LE16(pos
, gsm
->GN_igtk
);
459 wpa_auth_get_seqnum_igtk(sm
->wpa_auth
, NULL
, gsm
->GN_igtk
, pos
);
461 *pos
++ = WPA_IGTK_LEN
;
462 if (aes_wrap(sm
->PTK
.kek
, WPA_IGTK_LEN
/ 8,
463 gsm
->IGTK
[gsm
->GN_igtk
- 4], pos
)) {
471 #endif /* CONFIG_IEEE80211W */
474 u8
* wpa_sm_write_assoc_resp_ies(struct wpa_state_machine
*sm
, u8
*pos
,
475 size_t max_len
, int auth_alg
)
477 u8
*end
, *mdie
, *ftie
, *rsnie
, *r0kh_id
, *subelem
= NULL
;
478 size_t mdie_len
, ftie_len
, rsnie_len
, r0kh_id_len
, subelem_len
= 0;
480 struct wpa_auth_config
*conf
;
481 struct rsn_ftie
*_ftie
;
486 conf
= &sm
->wpa_auth
->conf
;
488 if (sm
->wpa_key_mgmt
!= WPA_KEY_MGMT_FT_IEEE8021X
&&
489 sm
->wpa_key_mgmt
!= WPA_KEY_MGMT_FT_PSK
)
495 res
= wpa_write_rsn_ie(conf
, pos
, end
- pos
, sm
->pmk_r1_name
);
502 /* Mobility Domain Information */
503 res
= wpa_write_mdie(conf
, pos
, end
- pos
);
510 /* Fast BSS Transition Information */
511 if (auth_alg
== WLAN_AUTH_FT
) {
512 subelem
= wpa_ft_gtk_subelem(sm
, &subelem_len
);
513 r0kh_id
= sm
->r0kh_id
;
514 r0kh_id_len
= sm
->r0kh_id_len
;
515 #ifdef CONFIG_IEEE80211W
516 if (sm
->mgmt_frame_prot
) {
520 igtk
= wpa_ft_igtk_subelem(sm
, &igtk_len
);
525 nbuf
= os_realloc(subelem
, subelem_len
+ igtk_len
);
532 os_memcpy(subelem
+ subelem_len
, igtk
, igtk_len
);
533 subelem_len
+= igtk_len
;
536 #endif /* CONFIG_IEEE80211W */
538 r0kh_id
= conf
->r0_key_holder
;
539 r0kh_id_len
= conf
->r0_key_holder_len
;
541 res
= wpa_write_ftie(conf
, r0kh_id
, r0kh_id_len
, NULL
, NULL
, pos
,
542 end
- pos
, subelem
, subelem_len
);
550 _ftie
= (struct rsn_ftie
*) (ftie
+ 2);
551 _ftie
->mic_control
[1] = 3; /* Information element count */
552 if (wpa_ft_mic(sm
->PTK
.kck
, sm
->addr
, sm
->wpa_auth
->addr
, 6,
553 mdie
, mdie_len
, ftie
, ftie_len
,
554 rsnie
, rsnie_len
, NULL
, 0, _ftie
->mic
) < 0)
555 wpa_printf(MSG_DEBUG
, "FT: Failed to calculate MIC");
577 static int wpa_ft_parse_ftie(const u8
*ie
, size_t ie_len
,
578 struct wpa_ft_ies
*parse
)
583 parse
->ftie_len
= ie_len
;
585 pos
= ie
+ sizeof(struct rsn_ftie
);
588 while (pos
+ 2 <= end
&& pos
+ 2 + pos
[1] <= end
) {
590 case FTIE_SUBELEM_R1KH_ID
:
591 if (pos
[1] != FT_R1KH_ID_LEN
) {
592 wpa_printf(MSG_DEBUG
, "FT: Invalid R1KH-ID "
593 "length in FTIE: %d", pos
[1]);
596 parse
->r1kh_id
= pos
+ 2;
598 case FTIE_SUBELEM_GTK
:
599 parse
->gtk
= pos
+ 2;
600 parse
->gtk_len
= pos
[1];
602 case FTIE_SUBELEM_R0KH_ID
:
603 if (pos
[1] < 1 || pos
[1] > FT_R0KH_ID_MAX_LEN
) {
604 wpa_printf(MSG_DEBUG
, "FT: Invalid R0KH-ID "
605 "length in FTIE: %d", pos
[1]);
608 parse
->r0kh_id
= pos
+ 2;
609 parse
->r0kh_id_len
= pos
[1];
620 static int wpa_ft_parse_ies(const u8
*ies
, size_t ies_len
,
621 struct wpa_ft_ies
*parse
)
624 struct wpa_ie_data data
;
627 os_memset(parse
, 0, sizeof(*parse
));
633 while (pos
+ 2 <= end
&& pos
+ 2 + pos
[1] <= end
) {
636 parse
->rsn
= pos
+ 2;
637 parse
->rsn_len
= pos
[1];
638 ret
= wpa_parse_wpa_ie_rsn(parse
->rsn
- 2,
642 wpa_printf(MSG_DEBUG
, "FT: Failed to parse "
646 if (data
.num_pmkid
== 1 && data
.pmkid
)
647 parse
->rsn_pmkid
= data
.pmkid
;
649 case WLAN_EID_MOBILITY_DOMAIN
:
650 parse
->mdie
= pos
+ 2;
651 parse
->mdie_len
= pos
[1];
653 case WLAN_EID_FAST_BSS_TRANSITION
:
654 if (wpa_ft_parse_ftie(pos
+ 2, pos
[1], parse
) < 0)
666 static inline int wpa_auth_set_key(struct wpa_authenticator
*wpa_auth
,
668 const char *alg
, const u8
*addr
, int idx
,
669 u8
*key
, size_t key_len
)
671 if (wpa_auth
->cb
.set_key
== NULL
)
673 return wpa_auth
->cb
.set_key(wpa_auth
->cb
.ctx
, vlan_id
, alg
, addr
, idx
,
678 static void wpa_ft_install_ptk(struct wpa_state_machine
*sm
)
683 /* MLME-SETKEYS.request(PTK) */
684 if (sm
->pairwise
== WPA_CIPHER_TKIP
) {
687 } else if (sm
->pairwise
== WPA_CIPHER_CCMP
) {
693 /* FIX: add STA entry to kernel/driver here? The set_key will fail
694 * most likely without this.. At the moment, STA entry is added only
695 * after association has been completed. Alternatively, could
696 * re-configure PTK at that point(?).
698 if (wpa_auth_set_key(sm
->wpa_auth
, 0, alg
, sm
->addr
, 0,
702 /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
703 sm
->pairwise_set
= TRUE
;
707 static u16
wpa_ft_process_auth_req(struct wpa_state_machine
*sm
,
708 const u8
*ies
, size_t ies_len
,
709 u8
**resp_ies
, size_t *resp_ies_len
)
711 struct rsn_mdie
*mdie
;
712 struct rsn_ftie
*ftie
;
713 u8 pmk_r1
[PMK_LEN
], pmk_r1_name
[WPA_PMK_NAME_LEN
];
714 u8 ptk_name
[WPA_PMK_NAME_LEN
];
715 struct wpa_auth_config
*conf
;
716 struct wpa_ft_ies parse
;
717 size_t buflen
, ptk_len
;
724 sm
->pmk_r1_name_valid
= 0;
725 conf
= &sm
->wpa_auth
->conf
;
727 wpa_hexdump(MSG_DEBUG
, "FT: Received authentication frame IEs",
730 if (wpa_ft_parse_ies(ies
, ies_len
, &parse
) < 0) {
731 wpa_printf(MSG_DEBUG
, "FT: Failed to parse FT IEs");
732 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
735 mdie
= (struct rsn_mdie
*) parse
.mdie
;
736 if (mdie
== NULL
|| parse
.mdie_len
< sizeof(*mdie
) ||
737 os_memcmp(mdie
->mobility_domain
,
738 sm
->wpa_auth
->conf
.mobility_domain
,
739 MOBILITY_DOMAIN_ID_LEN
) != 0) {
740 wpa_printf(MSG_DEBUG
, "FT: Invalid MDIE");
741 return WLAN_STATUS_INVALID_MDIE
;
744 ftie
= (struct rsn_ftie
*) parse
.ftie
;
745 if (ftie
== NULL
|| parse
.ftie_len
< sizeof(*ftie
)) {
746 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE");
747 return WLAN_STATUS_INVALID_FTIE
;
750 os_memcpy(sm
->SNonce
, ftie
->snonce
, WPA_NONCE_LEN
);
752 if (parse
.r0kh_id
== NULL
) {
753 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE - no R0KH-ID");
754 return WLAN_STATUS_INVALID_FTIE
;
757 wpa_hexdump(MSG_DEBUG
, "FT: STA R0KH-ID",
758 parse
.r0kh_id
, parse
.r0kh_id_len
);
759 os_memcpy(sm
->r0kh_id
, parse
.r0kh_id
, parse
.r0kh_id_len
);
760 sm
->r0kh_id_len
= parse
.r0kh_id_len
;
762 if (parse
.rsn_pmkid
== NULL
) {
763 wpa_printf(MSG_DEBUG
, "FT: No PMKID in RSNIE");
764 return WLAN_STATUS_INVALID_PMKID
;
767 wpa_hexdump(MSG_DEBUG
, "FT: Requested PMKR0Name",
768 parse
.rsn_pmkid
, WPA_PMK_NAME_LEN
);
769 wpa_derive_pmk_r1_name(parse
.rsn_pmkid
,
770 sm
->wpa_auth
->conf
.r1_key_holder
, sm
->addr
,
772 wpa_hexdump(MSG_DEBUG
, "FT: Derived requested PMKR1Name",
773 pmk_r1_name
, WPA_PMK_NAME_LEN
);
775 if (wpa_ft_fetch_pmk_r1(sm
->wpa_auth
, sm
->addr
, pmk_r1_name
, pmk_r1
) <
777 if (wpa_ft_pull_pmk_r1(sm
->wpa_auth
, sm
->addr
, sm
->r0kh_id
,
778 sm
->r0kh_id_len
, parse
.rsn_pmkid
) < 0) {
779 wpa_printf(MSG_DEBUG
, "FT: Did not have matching "
780 "PMK-R1 and unknown R0KH-ID");
781 return WLAN_STATUS_INVALID_PMKID
;
785 * TODO: Should return "status pending" (and the caller should
786 * not send out response now). The real response will be sent
787 * once the response from R0KH is received.
789 return WLAN_STATUS_INVALID_PMKID
;
792 wpa_hexdump_key(MSG_DEBUG
, "FT: Selected PMK-R1", pmk_r1
, PMK_LEN
);
793 sm
->pmk_r1_name_valid
= 1;
794 os_memcpy(sm
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
);
796 if (os_get_random(sm
->ANonce
, WPA_NONCE_LEN
)) {
797 wpa_printf(MSG_DEBUG
, "FT: Failed to get random data for "
799 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
802 wpa_hexdump(MSG_DEBUG
, "FT: Received SNonce",
803 sm
->SNonce
, WPA_NONCE_LEN
);
804 wpa_hexdump(MSG_DEBUG
, "FT: Generated ANonce",
805 sm
->ANonce
, WPA_NONCE_LEN
);
807 ptk_len
= sm
->pairwise
== WPA_CIPHER_CCMP
? 48 : 64;
808 wpa_pmk_r1_to_ptk(pmk_r1
, sm
->SNonce
, sm
->ANonce
, sm
->addr
,
809 sm
->wpa_auth
->addr
, pmk_r1_name
,
810 (u8
*) &sm
->PTK
, ptk_len
, ptk_name
);
811 wpa_hexdump_key(MSG_DEBUG
, "FT: PTK",
812 (u8
*) &sm
->PTK
, ptk_len
);
813 wpa_hexdump(MSG_DEBUG
, "FT: PTKName", ptk_name
, WPA_PMK_NAME_LEN
);
815 wpa_ft_install_ptk(sm
);
817 buflen
= 2 + sizeof(struct rsn_mdie
) + 2 + sizeof(struct rsn_ftie
) +
818 2 + FT_R1KH_ID_LEN
+ 200;
819 *resp_ies
= os_zalloc(buflen
);
820 if (*resp_ies
== NULL
) {
821 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
825 end
= *resp_ies
+ buflen
;
827 ret
= wpa_write_rsn_ie(conf
, pos
, end
- pos
, parse
.rsn_pmkid
);
831 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
835 ret
= wpa_write_mdie(conf
, pos
, end
- pos
);
839 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
843 ret
= wpa_write_ftie(conf
, parse
.r0kh_id
, parse
.r0kh_id_len
,
844 sm
->ANonce
, sm
->SNonce
, pos
, end
- pos
, NULL
, 0);
848 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
852 *resp_ies_len
= pos
- *resp_ies
;
854 return WLAN_STATUS_SUCCESS
;
858 void wpa_ft_process_auth(struct wpa_state_machine
*sm
, const u8
*bssid
,
859 u16 auth_transaction
, const u8
*ies
, size_t ies_len
,
860 void (*cb
)(void *ctx
, const u8
*dst
, const u8
*bssid
,
861 u16 auth_transaction
, u16 status
,
862 const u8
*ies
, size_t ies_len
),
870 wpa_printf(MSG_DEBUG
, "FT: Received authentication frame, but "
871 "WPA SM not available");
875 wpa_printf(MSG_DEBUG
, "FT: Received authentication frame: STA=" MACSTR
876 " BSSID=" MACSTR
" transaction=%d",
877 MAC2STR(sm
->addr
), MAC2STR(bssid
), auth_transaction
);
878 status
= wpa_ft_process_auth_req(sm
, ies
, ies_len
, &resp_ies
,
881 wpa_printf(MSG_DEBUG
, "FT: FT authentication response: dst=" MACSTR
882 " auth_transaction=%d status=%d",
883 MAC2STR(sm
->addr
), auth_transaction
+ 1, status
);
884 wpa_hexdump(MSG_DEBUG
, "FT: Response IEs", resp_ies
, resp_ies_len
);
885 cb(ctx
, sm
->addr
, bssid
, auth_transaction
+ 1, status
,
886 resp_ies
, resp_ies_len
);
891 u16
wpa_ft_validate_reassoc(struct wpa_state_machine
*sm
, const u8
*ies
,
894 struct wpa_ft_ies parse
;
895 struct rsn_mdie
*mdie
;
896 struct rsn_ftie
*ftie
;
900 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
902 wpa_hexdump(MSG_DEBUG
, "FT: Reassoc Req IEs", ies
, ies_len
);
904 if (wpa_ft_parse_ies(ies
, ies_len
, &parse
) < 0) {
905 wpa_printf(MSG_DEBUG
, "FT: Failed to parse FT IEs");
906 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
909 if (parse
.rsn
== NULL
) {
910 wpa_printf(MSG_DEBUG
, "FT: No RSNIE in Reassoc Req");
911 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
914 if (parse
.rsn_pmkid
== NULL
) {
915 wpa_printf(MSG_DEBUG
, "FT: No PMKID in RSNIE");
916 return WLAN_STATUS_INVALID_PMKID
;
919 if (os_memcmp(parse
.rsn_pmkid
, sm
->pmk_r1_name
, WPA_PMK_NAME_LEN
) != 0)
921 wpa_printf(MSG_DEBUG
, "FT: PMKID in Reassoc Req did not match "
922 "with the PMKR1Name derived from auth request");
923 return WLAN_STATUS_INVALID_PMKID
;
926 mdie
= (struct rsn_mdie
*) parse
.mdie
;
927 if (mdie
== NULL
|| parse
.mdie_len
< sizeof(*mdie
) ||
928 os_memcmp(mdie
->mobility_domain
,
929 sm
->wpa_auth
->conf
.mobility_domain
,
930 MOBILITY_DOMAIN_ID_LEN
) != 0) {
931 wpa_printf(MSG_DEBUG
, "FT: Invalid MDIE");
932 return WLAN_STATUS_INVALID_MDIE
;
935 ftie
= (struct rsn_ftie
*) parse
.ftie
;
936 if (ftie
== NULL
|| parse
.ftie_len
< sizeof(*ftie
)) {
937 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE");
938 return WLAN_STATUS_INVALID_FTIE
;
942 * Assume that MDIE, FTIE, and RSN IE are protected and that there is
943 * no RIC, so total of 3 protected IEs.
945 if (ftie
->mic_control
[1] != 3) {
946 wpa_printf(MSG_DEBUG
, "FT: Unexpected IE count in FTIE (%d)",
947 ftie
->mic_control
[1]);
948 return WLAN_STATUS_INVALID_FTIE
;
951 if (wpa_ft_mic(sm
->PTK
.kck
, sm
->addr
, sm
->wpa_auth
->addr
, 5,
952 parse
.mdie
- 2, parse
.mdie_len
+ 2,
953 parse
.ftie
- 2, parse
.ftie_len
+ 2,
954 parse
.rsn
- 2, parse
.rsn_len
+ 2, NULL
, 0,
956 wpa_printf(MSG_DEBUG
, "FT: Failed to calculate MIC");
957 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
960 if (os_memcmp(mic
, ftie
->mic
, 16) != 0) {
961 wpa_printf(MSG_DEBUG
, "FT: Invalid MIC in FTIE");
962 wpa_hexdump(MSG_MSGDUMP
, "FT: Received MIC", ftie
->mic
, 16);
963 wpa_hexdump(MSG_MSGDUMP
, "FT: Calculated MIC", mic
, 16);
964 return WLAN_STATUS_INVALID_FTIE
;
967 return WLAN_STATUS_SUCCESS
;
971 int wpa_ft_action_rx(struct wpa_state_machine
*sm
, const u8
*data
, size_t len
)
973 const u8
*sta_addr
, *target_ap
;
977 struct ft_rrb_frame
*frame
;
983 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
984 * FT Request action frame body[variable]
988 wpa_printf(MSG_DEBUG
, "FT: Too short FT Action frame "
989 "(len=%lu)", (unsigned long) len
);
995 target_ap
= data
+ 8;
999 wpa_printf(MSG_DEBUG
, "FT: Received FT Action frame (STA=" MACSTR
1000 " Target AP=" MACSTR
" Action=%d)",
1001 MAC2STR(sta_addr
), MAC2STR(target_ap
), action
);
1003 if (os_memcmp(sta_addr
, sm
->addr
, ETH_ALEN
) != 0) {
1004 wpa_printf(MSG_DEBUG
, "FT: Mismatch in FT Action STA address: "
1005 "STA=" MACSTR
" STA-Address=" MACSTR
,
1006 MAC2STR(sm
->addr
), MAC2STR(sta_addr
));
1011 * Do some sanity checking on the target AP address (not own and not
1012 * broadcast. This could be extended to filter based on a list of known
1013 * APs in the MD (if such a list were configured).
1015 if ((target_ap
[0] & 0x01) ||
1016 os_memcmp(target_ap
, sm
->wpa_auth
->addr
, ETH_ALEN
) == 0) {
1017 wpa_printf(MSG_DEBUG
, "FT: Invalid Target AP in FT Action "
1022 wpa_hexdump(MSG_MSGDUMP
, "FT: Action frame body", ies
, ies_len
);
1024 /* RRB - Forward action frame to the target AP */
1025 frame
= os_malloc(sizeof(*frame
) + len
);
1026 frame
->frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1027 frame
->packet_type
= FT_PACKET_REQUEST
;
1028 frame
->action_length
= host_to_le16(len
);
1029 os_memcpy(frame
->ap_address
, sm
->wpa_auth
->addr
, ETH_ALEN
);
1030 os_memcpy(frame
+ 1, data
, len
);
1032 wpa_ft_rrb_send(sm
->wpa_auth
, target_ap
, (u8
*) frame
,
1033 sizeof(*frame
) + len
);
1040 static int wpa_ft_rrb_rx_request(struct wpa_authenticator
*wpa_auth
,
1041 const u8
*current_ap
, const u8
*sta_addr
,
1042 const u8
*body
, size_t len
)
1044 struct wpa_state_machine
*sm
;
1047 size_t resp_ies_len
, rlen
;
1048 struct ft_rrb_frame
*frame
;
1050 sm
= wpa_ft_add_sta(wpa_auth
, sta_addr
);
1052 wpa_printf(MSG_DEBUG
, "FT: Failed to add new STA based on "
1057 wpa_hexdump(MSG_MSGDUMP
, "FT: RRB Request Frame body", body
, len
);
1059 status
= wpa_ft_process_auth_req(sm
, body
, len
, &resp_ies
,
1062 wpa_printf(MSG_DEBUG
, "FT: RRB authentication response: STA=" MACSTR
1063 " CurrentAP=" MACSTR
" status=%d",
1064 MAC2STR(sm
->addr
), MAC2STR(current_ap
), status
);
1065 wpa_hexdump(MSG_DEBUG
, "FT: Response IEs", resp_ies
, resp_ies_len
);
1067 /* RRB - Forward action frame response to the Current AP */
1070 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1071 * Status_Code[2] FT Request action frame body[variable]
1073 rlen
= 2 + 2 * ETH_ALEN
+ 2 + resp_ies_len
;
1075 frame
= os_malloc(sizeof(*frame
) + rlen
);
1076 frame
->frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1077 frame
->packet_type
= FT_PACKET_RESPONSE
;
1078 frame
->action_length
= host_to_le16(rlen
);
1079 os_memcpy(frame
->ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1080 pos
= (u8
*) (frame
+ 1);
1081 *pos
++ = WLAN_ACTION_FT
;
1082 *pos
++ = 2; /* Action: Response */
1083 os_memcpy(pos
, sta_addr
, ETH_ALEN
);
1085 os_memcpy(pos
, wpa_auth
->addr
, ETH_ALEN
);
1087 WPA_PUT_LE16(pos
, status
);
1090 os_memcpy(pos
, resp_ies
, resp_ies_len
);
1094 wpa_ft_rrb_send(wpa_auth
, current_ap
, (u8
*) frame
,
1095 sizeof(*frame
) + rlen
);
1102 static int wpa_ft_rrb_rx_pull(struct wpa_authenticator
*wpa_auth
,
1104 const u8
*data
, size_t data_len
)
1106 struct ft_r0kh_r1kh_pull_frame
*frame
, f
;
1107 struct ft_remote_r1kh
*r1kh
;
1108 struct ft_r0kh_r1kh_resp_frame resp
, r
;
1111 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 pull");
1113 if (data_len
< sizeof(*frame
))
1116 r1kh
= wpa_auth
->conf
.r1kh_list
;
1118 if (os_memcmp(r1kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1123 wpa_printf(MSG_DEBUG
, "FT: No matching R1KH address found for "
1124 "PMK-R1 pull source address " MACSTR
,
1129 frame
= (struct ft_r0kh_r1kh_pull_frame
*) data
;
1130 /* aes_unwrap() does not support inplace decryption, so use a temporary
1131 * buffer for the data. */
1132 if (aes_unwrap(r1kh
->key
, (FT_R0KH_R1KH_PULL_DATA_LEN
+ 7) / 8,
1133 frame
->nonce
, f
.nonce
) < 0) {
1134 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 pull "
1135 "request from " MACSTR
, MAC2STR(src_addr
));
1139 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - nonce",
1140 f
.nonce
, sizeof(f
.nonce
));
1141 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - PMKR0Name",
1142 f
.pmk_r0_name
, WPA_PMK_NAME_LEN
);
1143 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
"S1KH-ID="
1144 MACSTR
, MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
));
1146 os_memset(&resp
, 0, sizeof(resp
));
1147 resp
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1148 resp
.packet_type
= FT_PACKET_R0KH_R1KH_RESP
;
1149 resp
.data_length
= host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN
);
1150 os_memcpy(resp
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1152 /* aes_wrap() does not support inplace encryption, so use a temporary
1153 * buffer for the data. */
1154 os_memcpy(r
.nonce
, f
.nonce
, sizeof(f
.nonce
));
1155 os_memcpy(r
.r1kh_id
, f
.r1kh_id
, FT_R1KH_ID_LEN
);
1156 os_memcpy(r
.s1kh_id
, f
.s1kh_id
, ETH_ALEN
);
1157 if (wpa_ft_fetch_pmk_r0(wpa_auth
, f
.s1kh_id
, f
.pmk_r0_name
, pmk_r0
) <
1159 wpa_printf(MSG_DEBUG
, "FT: No matching PMKR0Name found for "
1164 wpa_derive_pmk_r1(pmk_r0
, f
.pmk_r0_name
, f
.r1kh_id
, f
.s1kh_id
,
1165 r
.pmk_r1
, r
.pmk_r1_name
);
1166 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", r
.pmk_r1
, PMK_LEN
);
1167 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", r
.pmk_r1_name
,
1170 if (aes_wrap(r1kh
->key
, (FT_R0KH_R1KH_RESP_DATA_LEN
+ 7) / 8,
1171 r
.nonce
, resp
.nonce
) < 0) {
1172 os_memset(pmk_r0
, 0, PMK_LEN
);
1176 os_memset(pmk_r0
, 0, PMK_LEN
);
1178 wpa_ft_rrb_send(wpa_auth
, src_addr
, (u8
*) &resp
, sizeof(resp
));
1184 static int wpa_ft_rrb_rx_resp(struct wpa_authenticator
*wpa_auth
,
1186 const u8
*data
, size_t data_len
)
1188 struct ft_r0kh_r1kh_resp_frame
*frame
, f
;
1189 struct ft_remote_r0kh
*r0kh
;
1191 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 pull response");
1193 if (data_len
< sizeof(*frame
))
1196 r0kh
= wpa_auth
->conf
.r0kh_list
;
1198 if (os_memcmp(r0kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1203 wpa_printf(MSG_DEBUG
, "FT: No matching R0KH address found for "
1204 "PMK-R0 pull response source address " MACSTR
,
1209 frame
= (struct ft_r0kh_r1kh_resp_frame
*) data
;
1210 /* aes_unwrap() does not support inplace decryption, so use a temporary
1211 * buffer for the data. */
1212 if (aes_unwrap(r0kh
->key
, (FT_R0KH_R1KH_RESP_DATA_LEN
+ 7) / 8,
1213 frame
->nonce
, f
.nonce
) < 0) {
1214 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 pull "
1215 "response from " MACSTR
, MAC2STR(src_addr
));
1219 if (os_memcmp(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
)
1221 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull response did not use a "
1222 "matching R1KH-ID");
1226 /* TODO: verify that <nonce,s1kh_id> matches with a pending request
1227 * and call this requests callback function to finish request
1230 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - nonce",
1231 f
.nonce
, sizeof(f
.nonce
));
1232 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
"S1KH-ID="
1233 MACSTR
, MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
));
1234 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1 pull - PMK-R1",
1236 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - PMKR1Name",
1237 f
.pmk_r1_name
, WPA_PMK_NAME_LEN
);
1239 wpa_ft_store_pmk_r1(wpa_auth
, f
.s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
);
1240 os_memset(f
.pmk_r1
, 0, PMK_LEN
);
1246 static int wpa_ft_rrb_rx_push(struct wpa_authenticator
*wpa_auth
,
1248 const u8
*data
, size_t data_len
)
1250 struct ft_r0kh_r1kh_push_frame
*frame
, f
;
1251 struct ft_remote_r0kh
*r0kh
;
1255 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 push");
1257 if (data_len
< sizeof(*frame
))
1260 r0kh
= wpa_auth
->conf
.r0kh_list
;
1262 if (os_memcmp(r0kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1267 wpa_printf(MSG_DEBUG
, "FT: No matching R0KH address found for "
1268 "PMK-R0 push source address " MACSTR
,
1273 frame
= (struct ft_r0kh_r1kh_push_frame
*) data
;
1274 /* aes_unwrap() does not support inplace decryption, so use a temporary
1275 * buffer for the data. */
1276 if (aes_unwrap(r0kh
->key
, (FT_R0KH_R1KH_PUSH_DATA_LEN
+ 7) / 8,
1277 frame
->timestamp
, f
.timestamp
) < 0) {
1278 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 push from "
1279 MACSTR
, MAC2STR(src_addr
));
1284 tsend
= WPA_GET_LE32(f
.timestamp
);
1285 if ((now
.sec
> tsend
&& now
.sec
- tsend
> 60) ||
1286 (now
.sec
< tsend
&& tsend
- now
.sec
> 60)) {
1287 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push did not have a valid "
1288 "timestamp: sender time %d own time %d\n",
1289 (int) tsend
, (int) now
.sec
);
1293 if (os_memcmp(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
)
1295 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push did not use a matching "
1296 "R1KH-ID (received " MACSTR
" own " MACSTR
")",
1298 MAC2STR(wpa_auth
->conf
.r1_key_holder
));
1302 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push - R1KH-ID=" MACSTR
" S1KH-ID="
1303 MACSTR
, MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
));
1304 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1 push - PMK-R1",
1306 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 push - PMKR1Name",
1307 f
.pmk_r1_name
, WPA_PMK_NAME_LEN
);
1309 wpa_ft_store_pmk_r1(wpa_auth
, f
.s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
);
1310 os_memset(f
.pmk_r1
, 0, PMK_LEN
);
1316 int wpa_ft_rrb_rx(struct wpa_authenticator
*wpa_auth
, const u8
*src_addr
,
1317 const u8
*data
, size_t data_len
)
1319 struct ft_rrb_frame
*frame
;
1321 const u8
*pos
, *end
, *start
;
1323 const u8
*sta_addr
, *target_ap_addr
;
1325 wpa_printf(MSG_DEBUG
, "FT: RRB received frame from remote AP " MACSTR
,
1328 if (data_len
< sizeof(*frame
)) {
1329 wpa_printf(MSG_DEBUG
, "FT: Too short RRB frame (data_len=%lu)",
1330 (unsigned long) data_len
);
1335 frame
= (struct ft_rrb_frame
*) pos
;
1336 pos
+= sizeof(*frame
);
1338 alen
= le_to_host16(frame
->action_length
);
1339 wpa_printf(MSG_DEBUG
, "FT: RRB frame - frame_type=%d packet_type=%d "
1340 "action_length=%d ap_address=" MACSTR
,
1341 frame
->frame_type
, frame
->packet_type
, alen
,
1342 MAC2STR(frame
->ap_address
));
1344 if (frame
->frame_type
!= RSN_REMOTE_FRAME_TYPE_FT_RRB
) {
1345 /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
1346 wpa_printf(MSG_DEBUG
, "FT: RRB discarded frame with "
1347 "unrecognized type %d", frame
->frame_type
);
1351 if (alen
> data_len
- sizeof(*frame
)) {
1352 wpa_printf(MSG_DEBUG
, "FT: RRB frame too short for action "
1357 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_PULL
)
1358 return wpa_ft_rrb_rx_pull(wpa_auth
, src_addr
, data
, data_len
);
1359 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_RESP
)
1360 return wpa_ft_rrb_rx_resp(wpa_auth
, src_addr
, data
, data_len
);
1361 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_PUSH
)
1362 return wpa_ft_rrb_rx_push(wpa_auth
, src_addr
, data
, data_len
);
1364 wpa_hexdump(MSG_MSGDUMP
, "FT: RRB - FT Action frame", pos
, alen
);
1366 if (alen
< 1 + 1 + 2 * ETH_ALEN
) {
1367 wpa_printf(MSG_DEBUG
, "FT: Too short RRB frame (not enough "
1368 "room for Action Frame body); alen=%lu",
1369 (unsigned long) alen
);
1375 if (*pos
!= WLAN_ACTION_FT
) {
1376 wpa_printf(MSG_DEBUG
, "FT: Unexpected Action frame category "
1385 target_ap_addr
= pos
;
1387 wpa_printf(MSG_DEBUG
, "FT: RRB Action Frame: action=%d sta_addr="
1388 MACSTR
" target_ap_addr=" MACSTR
,
1389 action
, MAC2STR(sta_addr
), MAC2STR(target_ap_addr
));
1391 if (frame
->packet_type
== FT_PACKET_REQUEST
) {
1392 wpa_printf(MSG_DEBUG
, "FT: FT Packet Type - Request");
1395 wpa_printf(MSG_DEBUG
, "FT: Unexpected Action %d in "
1396 "RRB Request", action
);
1400 if (os_memcmp(target_ap_addr
, wpa_auth
->addr
, ETH_ALEN
) != 0) {
1401 wpa_printf(MSG_DEBUG
, "FT: Target AP address in the "
1402 "RRB Request does not match with own "
1407 if (wpa_ft_rrb_rx_request(wpa_auth
, frame
->ap_address
,
1408 sta_addr
, pos
, end
- pos
) < 0)
1410 } else if (frame
->packet_type
== FT_PACKET_RESPONSE
) {
1413 if (end
- pos
< 2) {
1414 wpa_printf(MSG_DEBUG
, "FT: Not enough room for status "
1415 "code in RRB Response");
1418 status_code
= WPA_GET_LE16(pos
);
1421 wpa_printf(MSG_DEBUG
, "FT: FT Packet Type - Response "
1422 "(status_code=%d)", status_code
);
1424 if (wpa_ft_action_send(wpa_auth
, sta_addr
, start
, alen
) < 0)
1427 wpa_printf(MSG_DEBUG
, "FT: RRB discarded frame with unknown "
1428 "packet_type %d", frame
->packet_type
);
1436 static void wpa_ft_generate_pmk_r1(struct wpa_authenticator
*wpa_auth
,
1437 struct wpa_ft_pmk_r0_sa
*pmk_r0
,
1438 struct ft_remote_r1kh
*r1kh
,
1441 struct ft_r0kh_r1kh_push_frame frame
, f
;
1444 os_memset(&frame
, 0, sizeof(frame
));
1445 frame
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1446 frame
.packet_type
= FT_PACKET_R0KH_R1KH_PUSH
;
1447 frame
.data_length
= host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN
);
1448 os_memcpy(frame
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1450 /* aes_wrap() does not support inplace encryption, so use a temporary
1451 * buffer for the data. */
1452 os_memcpy(f
.r1kh_id
, r1kh
->id
, FT_R1KH_ID_LEN
);
1453 os_memcpy(f
.s1kh_id
, s1kh_id
, ETH_ALEN
);
1454 os_memcpy(f
.pmk_r0_name
, pmk_r0
->pmk_r0_name
, WPA_PMK_NAME_LEN
);
1455 wpa_derive_pmk_r1(pmk_r0
->pmk_r0
, pmk_r0
->pmk_r0_name
, r1kh
->id
,
1456 s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
);
1457 wpa_printf(MSG_DEBUG
, "FT: R1KH-ID " MACSTR
, MAC2STR(r1kh
->id
));
1458 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", f
.pmk_r1
, PMK_LEN
);
1459 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", f
.pmk_r1_name
,
1462 WPA_PUT_LE32(f
.timestamp
, now
.sec
);
1463 if (aes_wrap(r1kh
->key
, (FT_R0KH_R1KH_PUSH_DATA_LEN
+ 7) / 8,
1464 f
.timestamp
, frame
.timestamp
) < 0)
1467 wpa_ft_rrb_send(wpa_auth
, r1kh
->addr
, (u8
*) &frame
, sizeof(frame
));
1471 void wpa_ft_push_pmk_r1(struct wpa_authenticator
*wpa_auth
, const u8
*addr
)
1473 struct wpa_ft_pmk_r0_sa
*r0
;
1474 struct ft_remote_r1kh
*r1kh
;
1476 if (!wpa_auth
->conf
.pmk_r1_push
)
1479 r0
= wpa_auth
->ft_pmk_cache
->pmk_r0
;
1481 if (os_memcmp(r0
->spa
, addr
, ETH_ALEN
) == 0)
1486 if (r0
== NULL
|| r0
->pmk_r1_pushed
)
1488 r0
->pmk_r1_pushed
= 1;
1490 wpa_printf(MSG_DEBUG
, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
1491 "for STA " MACSTR
, MAC2STR(addr
));
1493 r1kh
= wpa_auth
->conf
.r1kh_list
;
1495 wpa_ft_generate_pmk_r1(wpa_auth
, r0
, r1kh
, addr
);
1500 #endif /* CONFIG_IEEE80211R */