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
47 static int wpa_ft_parse_ies(const u8
*ies
, size_t ies_len
,
48 struct wpa_ft_ies
*parse
);
51 static int wpa_ft_rrb_send(struct wpa_authenticator
*wpa_auth
, const u8
*dst
,
52 const u8
*data
, size_t data_len
)
54 if (wpa_auth
->cb
.send_ether
== NULL
)
56 return wpa_auth
->cb
.send_ether(wpa_auth
->cb
.ctx
, dst
, ETH_P_RRB
,
61 static int wpa_ft_action_send(struct wpa_authenticator
*wpa_auth
,
62 const u8
*dst
, const u8
*data
, size_t data_len
)
64 if (wpa_auth
->cb
.send_ft_action
== NULL
)
66 return wpa_auth
->cb
.send_ft_action(wpa_auth
->cb
.ctx
, dst
,
71 static struct wpa_state_machine
*
72 wpa_ft_add_sta(struct wpa_authenticator
*wpa_auth
, const u8
*sta_addr
)
74 if (wpa_auth
->cb
.add_sta
== NULL
)
76 return wpa_auth
->cb
.add_sta(wpa_auth
->cb
.ctx
, sta_addr
);
80 int wpa_write_mdie(struct wpa_auth_config
*conf
, u8
*buf
, size_t len
)
84 if (len
< 2 + sizeof(struct rsn_mdie
))
87 *pos
++ = WLAN_EID_MOBILITY_DOMAIN
;
88 *pos
++ = MOBILITY_DOMAIN_ID_LEN
+ 1;
89 os_memcpy(pos
, conf
->mobility_domain
, MOBILITY_DOMAIN_ID_LEN
);
90 pos
+= MOBILITY_DOMAIN_ID_LEN
;
91 capab
= RSN_FT_CAPAB_FT_OVER_DS
;
98 static int wpa_write_ftie(struct wpa_auth_config
*conf
, const u8
*r0kh_id
,
100 const u8
*anonce
, const u8
*snonce
,
101 u8
*buf
, size_t len
, const u8
*subelem
,
104 u8
*pos
= buf
, *ielen
;
105 struct rsn_ftie
*hdr
;
107 if (len
< 2 + sizeof(*hdr
) + 2 + FT_R1KH_ID_LEN
+ 2 + r0kh_id_len
+
111 *pos
++ = WLAN_EID_FAST_BSS_TRANSITION
;
114 hdr
= (struct rsn_ftie
*) pos
;
115 os_memset(hdr
, 0, sizeof(*hdr
));
117 WPA_PUT_LE16(hdr
->mic_control
, 0);
119 os_memcpy(hdr
->anonce
, anonce
, WPA_NONCE_LEN
);
121 os_memcpy(hdr
->snonce
, snonce
, WPA_NONCE_LEN
);
123 /* Optional Parameters */
124 *pos
++ = FTIE_SUBELEM_R1KH_ID
;
125 *pos
++ = FT_R1KH_ID_LEN
;
126 os_memcpy(pos
, conf
->r1_key_holder
, FT_R1KH_ID_LEN
);
127 pos
+= FT_R1KH_ID_LEN
;
130 *pos
++ = FTIE_SUBELEM_R0KH_ID
;
131 *pos
++ = r0kh_id_len
;
132 os_memcpy(pos
, r0kh_id
, r0kh_id_len
);
137 os_memcpy(pos
, subelem
, subelem_len
);
141 *ielen
= pos
- buf
- 2;
147 struct wpa_ft_pmk_r0_sa
{
148 struct wpa_ft_pmk_r0_sa
*next
;
150 u8 pmk_r0_name
[WPA_PMK_NAME_LEN
];
152 /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
156 struct wpa_ft_pmk_r1_sa
{
157 struct wpa_ft_pmk_r1_sa
*next
;
159 u8 pmk_r1_name
[WPA_PMK_NAME_LEN
];
161 /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
164 struct wpa_ft_pmk_cache
{
165 struct wpa_ft_pmk_r0_sa
*pmk_r0
;
166 struct wpa_ft_pmk_r1_sa
*pmk_r1
;
169 struct wpa_ft_pmk_cache
* wpa_ft_pmk_cache_init(void)
171 struct wpa_ft_pmk_cache
*cache
;
173 cache
= os_zalloc(sizeof(*cache
));
179 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache
*cache
)
181 struct wpa_ft_pmk_r0_sa
*r0
, *r0prev
;
182 struct wpa_ft_pmk_r1_sa
*r1
, *r1prev
;
188 os_memset(r0prev
->pmk_r0
, 0, PMK_LEN
);
196 os_memset(r1prev
->pmk_r1
, 0, PMK_LEN
);
204 static int wpa_ft_store_pmk_r0(struct wpa_authenticator
*wpa_auth
,
205 const u8
*spa
, const u8
*pmk_r0
,
206 const u8
*pmk_r0_name
)
208 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
209 struct wpa_ft_pmk_r0_sa
*r0
;
211 /* TODO: add expiration and limit on number of entries in cache */
213 r0
= os_zalloc(sizeof(*r0
));
217 os_memcpy(r0
->pmk_r0
, pmk_r0
, PMK_LEN
);
218 os_memcpy(r0
->pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
);
219 os_memcpy(r0
->spa
, spa
, ETH_ALEN
);
221 r0
->next
= cache
->pmk_r0
;
228 static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator
*wpa_auth
,
229 const u8
*spa
, const u8
*pmk_r0_name
,
232 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
233 struct wpa_ft_pmk_r0_sa
*r0
;
237 if (os_memcmp(r0
->spa
, spa
, ETH_ALEN
) == 0 &&
238 os_memcmp(r0
->pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
)
240 os_memcpy(pmk_r0
, r0
->pmk_r0
, PMK_LEN
);
251 static int wpa_ft_store_pmk_r1(struct wpa_authenticator
*wpa_auth
,
252 const u8
*spa
, const u8
*pmk_r1
,
253 const u8
*pmk_r1_name
)
255 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
256 struct wpa_ft_pmk_r1_sa
*r1
;
258 /* TODO: add expiration and limit on number of entries in cache */
260 r1
= os_zalloc(sizeof(*r1
));
264 os_memcpy(r1
->pmk_r1
, pmk_r1
, PMK_LEN
);
265 os_memcpy(r1
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
);
266 os_memcpy(r1
->spa
, spa
, ETH_ALEN
);
268 r1
->next
= cache
->pmk_r1
;
275 static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator
*wpa_auth
,
276 const u8
*spa
, const u8
*pmk_r1_name
,
279 struct wpa_ft_pmk_cache
*cache
= wpa_auth
->ft_pmk_cache
;
280 struct wpa_ft_pmk_r1_sa
*r1
;
284 if (os_memcmp(r1
->spa
, spa
, ETH_ALEN
) == 0 &&
285 os_memcmp(r1
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
)
287 os_memcpy(pmk_r1
, r1
->pmk_r1
, PMK_LEN
);
298 static int wpa_ft_pull_pmk_r1(struct wpa_authenticator
*wpa_auth
,
299 const u8
*s1kh_id
, const u8
*r0kh_id
,
300 size_t r0kh_id_len
, const u8
*pmk_r0_name
)
302 struct ft_remote_r0kh
*r0kh
;
303 struct ft_r0kh_r1kh_pull_frame frame
, f
;
305 r0kh
= wpa_auth
->conf
.r0kh_list
;
307 if (r0kh
->id_len
== r0kh_id_len
&&
308 os_memcmp(r0kh
->id
, r0kh_id
, r0kh_id_len
) == 0)
315 wpa_printf(MSG_DEBUG
, "FT: Send PMK-R1 pull request to remote R0KH "
316 "address " MACSTR
, MAC2STR(r0kh
->addr
));
318 os_memset(&frame
, 0, sizeof(frame
));
319 frame
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
320 frame
.packet_type
= FT_PACKET_R0KH_R1KH_PULL
;
321 frame
.data_length
= host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN
);
322 os_memcpy(frame
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
324 /* aes_wrap() does not support inplace encryption, so use a temporary
325 * buffer for the data. */
326 if (os_get_random(f
.nonce
, sizeof(f
.nonce
))) {
327 wpa_printf(MSG_DEBUG
, "FT: Failed to get random data for "
331 os_memcpy(f
.pmk_r0_name
, pmk_r0_name
, WPA_PMK_NAME_LEN
);
332 os_memcpy(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
);
333 os_memcpy(f
.s1kh_id
, s1kh_id
, ETH_ALEN
);
335 if (aes_wrap(r0kh
->key
, (FT_R0KH_R1KH_PULL_DATA_LEN
+ 7) / 8,
336 f
.nonce
, frame
.nonce
) < 0)
339 wpa_ft_rrb_send(wpa_auth
, r0kh
->addr
, (u8
*) &frame
, sizeof(frame
));
345 int wpa_auth_derive_ptk_ft(struct wpa_state_machine
*sm
, const u8
*pmk
,
346 struct wpa_ptk
*ptk
, size_t ptk_len
)
348 u8 pmk_r0
[PMK_LEN
], pmk_r0_name
[WPA_PMK_NAME_LEN
];
349 u8 pmk_r1
[PMK_LEN
], pmk_r1_name
[WPA_PMK_NAME_LEN
];
350 u8 ptk_name
[WPA_PMK_NAME_LEN
];
351 const u8
*mdid
= sm
->wpa_auth
->conf
.mobility_domain
;
352 const u8
*r0kh
= sm
->wpa_auth
->conf
.r0_key_holder
;
353 size_t r0kh_len
= sm
->wpa_auth
->conf
.r0_key_holder_len
;
354 const u8
*r1kh
= sm
->wpa_auth
->conf
.r1_key_holder
;
355 const u8
*ssid
= sm
->wpa_auth
->conf
.ssid
;
356 size_t ssid_len
= sm
->wpa_auth
->conf
.ssid_len
;
359 if (sm
->xxkey_len
== 0) {
360 wpa_printf(MSG_DEBUG
, "FT: XXKey not available for key "
365 wpa_derive_pmk_r0(sm
->xxkey
, sm
->xxkey_len
, ssid
, ssid_len
, mdid
,
366 r0kh
, r0kh_len
, sm
->addr
, pmk_r0
, pmk_r0_name
);
367 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R0", pmk_r0
, PMK_LEN
);
368 wpa_hexdump(MSG_DEBUG
, "FT: PMKR0Name", pmk_r0_name
, WPA_PMK_NAME_LEN
);
369 wpa_ft_store_pmk_r0(sm
->wpa_auth
, sm
->addr
, pmk_r0
, pmk_r0_name
);
371 wpa_derive_pmk_r1(pmk_r0
, pmk_r0_name
, r1kh
, sm
->addr
,
372 pmk_r1
, pmk_r1_name
);
373 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", pmk_r1
, PMK_LEN
);
374 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", pmk_r1_name
, WPA_PMK_NAME_LEN
);
375 wpa_ft_store_pmk_r1(sm
->wpa_auth
, sm
->addr
, pmk_r1
, pmk_r1_name
);
377 wpa_pmk_r1_to_ptk(pmk_r1
, sm
->SNonce
, sm
->ANonce
, sm
->addr
,
378 sm
->wpa_auth
->addr
, pmk_r1_name
,
379 (u8
*) ptk
, ptk_len
, ptk_name
);
380 wpa_hexdump_key(MSG_DEBUG
, "FT: PTK", (u8
*) ptk
, ptk_len
);
381 wpa_hexdump(MSG_DEBUG
, "FT: PTKName", ptk_name
, WPA_PMK_NAME_LEN
);
387 static inline int wpa_auth_get_seqnum(struct wpa_authenticator
*wpa_auth
,
388 const u8
*addr
, int idx
, u8
*seq
)
390 if (wpa_auth
->cb
.get_seqnum
== NULL
)
392 return wpa_auth
->cb
.get_seqnum(wpa_auth
->cb
.ctx
, addr
, idx
, seq
);
396 #ifdef CONFIG_IEEE80211W
397 static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator
*wpa_auth
,
398 const u8
*addr
, int idx
, u8
*seq
)
400 if (wpa_auth
->cb
.get_seqnum_igtk
== NULL
)
402 return wpa_auth
->cb
.get_seqnum_igtk(wpa_auth
->cb
.ctx
, addr
, idx
, seq
);
404 #endif /* CONFIG_IEEE80211W */
407 static u8
* wpa_ft_gtk_subelem(struct wpa_state_machine
*sm
, size_t *len
)
410 struct wpa_group
*gsm
= sm
->group
;
411 size_t subelem_len
, pad_len
;
416 key_len
= gsm
->GTK_len
;
417 if (key_len
> sizeof(keybuf
))
421 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
424 pad_len
= key_len
% 8;
426 pad_len
= 8 - pad_len
;
427 if (key_len
+ pad_len
< 16)
430 os_memcpy(keybuf
, gsm
->GTK
[gsm
->GN
- 1], key_len
);
431 os_memset(keybuf
+ key_len
, 0, pad_len
);
432 keybuf
[key_len
] = 0xdd;
436 key
= gsm
->GTK
[gsm
->GN
- 1];
439 * Sub-elem ID[1] | Length[1] | Key Info[1] | Key Length[1] | RSC[8] |
442 subelem_len
= 12 + key_len
+ 8;
443 subelem
= os_zalloc(subelem_len
);
447 subelem
[0] = FTIE_SUBELEM_GTK
;
448 subelem
[1] = 10 + key_len
+ 8;
449 subelem
[2] = gsm
->GN
& 0x03; /* Key ID in B0-B1 of Key Info */
450 subelem
[3] = gsm
->GTK_len
;
451 wpa_auth_get_seqnum(sm
->wpa_auth
, NULL
, gsm
->GN
, subelem
+ 4);
452 if (aes_wrap(sm
->PTK
.kek
, key_len
/ 8, key
, subelem
+ 12)) {
462 #ifdef CONFIG_IEEE80211W
463 static u8
* wpa_ft_igtk_subelem(struct wpa_state_machine
*sm
, size_t *len
)
466 struct wpa_group
*gsm
= sm
->group
;
469 /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
471 subelem_len
= 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN
+ 8;
472 subelem
= os_zalloc(subelem_len
);
477 *pos
++ = FTIE_SUBELEM_IGTK
;
478 *pos
++ = subelem_len
- 2;
479 WPA_PUT_LE16(pos
, gsm
->GN_igtk
);
481 wpa_auth_get_seqnum_igtk(sm
->wpa_auth
, NULL
, gsm
->GN_igtk
, pos
);
483 *pos
++ = WPA_IGTK_LEN
;
484 if (aes_wrap(sm
->PTK
.kek
, WPA_IGTK_LEN
/ 8,
485 gsm
->IGTK
[gsm
->GN_igtk
- 4], pos
)) {
493 #endif /* CONFIG_IEEE80211W */
496 static u8
* wpa_ft_process_rdie(u8
*pos
, u8
*end
, u8 id
, u8 descr_count
,
497 const u8
*ies
, size_t ies_len
)
499 struct ieee802_11_elems parse
;
500 struct rsn_rdie
*rdie
;
502 wpa_printf(MSG_DEBUG
, "FT: Resource Request: id=%d descr_count=%d",
504 wpa_hexdump(MSG_MSGDUMP
, "FT: Resource descriptor IE(s)",
507 if (end
- pos
< (int) sizeof(*rdie
)) {
508 wpa_printf(MSG_ERROR
, "FT: Not enough room for response RDIE");
512 *pos
++ = WLAN_EID_RIC_DATA
;
513 *pos
++ = sizeof(*rdie
);
514 rdie
= (struct rsn_rdie
*) pos
;
516 rdie
->descr_count
= 0;
517 rdie
->status_code
= host_to_le16(WLAN_STATUS_SUCCESS
);
518 pos
+= sizeof(*rdie
);
520 if (ieee802_11_parse_elems((u8
*) ies
, ies_len
, &parse
, 1) ==
522 wpa_printf(MSG_DEBUG
, "FT: Failed to parse request IEs");
524 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
529 if (parse
.wmm_tspec
) {
530 struct wmm_tspec_element
*tspec
;
533 if (parse
.wmm_tspec_len
+ 2 < (int) sizeof(*tspec
)) {
534 wpa_printf(MSG_DEBUG
, "FT: Too short WMM TSPEC IE "
535 "(%d)", (int) parse
.wmm_tspec_len
);
537 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
540 if (end
- pos
< (int) sizeof(*tspec
)) {
541 wpa_printf(MSG_ERROR
, "FT: Not enough room for "
544 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
547 tspec
= (struct wmm_tspec_element
*) pos
;
548 os_memcpy(tspec
, parse
.wmm_tspec
- 2, sizeof(*tspec
));
549 res
= wmm_process_tspec(tspec
);
550 wpa_printf(MSG_DEBUG
, "FT: ADDTS processing result: %d", res
);
551 if (res
== WMM_ADDTS_STATUS_INVALID_PARAMETERS
)
553 host_to_le16(WLAN_STATUS_INVALID_PARAMETERS
);
554 else if (res
== WMM_ADDTS_STATUS_REFUSED
)
556 host_to_le16(WLAN_STATUS_REQUEST_DECLINED
);
558 /* TSPEC accepted; include updated TSPEC in response */
559 rdie
->descr_count
= 1;
560 pos
+= sizeof(*tspec
);
564 #endif /* NEED_AP_MLME */
566 wpa_printf(MSG_DEBUG
, "FT: No supported resource requested");
567 rdie
->status_code
= host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE
);
572 static u8
* wpa_ft_process_ric(u8
*pos
, u8
*end
, const u8
*ric
, size_t ric_len
)
574 const u8
*rpos
, *start
;
575 const struct rsn_rdie
*rdie
;
577 wpa_hexdump(MSG_MSGDUMP
, "FT: RIC Request", ric
, ric_len
);
580 while (rpos
+ sizeof(*rdie
) < ric
+ ric_len
) {
581 if (rpos
[0] != WLAN_EID_RIC_DATA
|| rpos
[1] < sizeof(*rdie
) ||
582 rpos
+ 2 + rpos
[1] > ric
+ ric_len
)
584 rdie
= (const struct rsn_rdie
*) (rpos
+ 2);
588 while (rpos
+ 2 <= ric
+ ric_len
&&
589 rpos
+ 2 + rpos
[1] <= ric
+ ric_len
) {
590 if (rpos
[0] == WLAN_EID_RIC_DATA
)
594 pos
= wpa_ft_process_rdie(pos
, end
, rdie
->id
,
596 start
, rpos
- start
);
603 u8
* wpa_sm_write_assoc_resp_ies(struct wpa_state_machine
*sm
, u8
*pos
,
604 size_t max_len
, int auth_alg
,
605 const u8
*req_ies
, size_t req_ies_len
)
607 u8
*end
, *mdie
, *ftie
, *rsnie
, *r0kh_id
, *subelem
= NULL
;
608 size_t mdie_len
, ftie_len
, rsnie_len
, r0kh_id_len
, subelem_len
= 0;
610 struct wpa_auth_config
*conf
;
611 struct rsn_ftie
*_ftie
;
612 struct wpa_ft_ies parse
;
618 conf
= &sm
->wpa_auth
->conf
;
620 if (sm
->wpa_key_mgmt
!= WPA_KEY_MGMT_FT_IEEE8021X
&&
621 sm
->wpa_key_mgmt
!= WPA_KEY_MGMT_FT_PSK
)
627 res
= wpa_write_rsn_ie(conf
, pos
, end
- pos
, sm
->pmk_r1_name
);
634 /* Mobility Domain Information */
635 res
= wpa_write_mdie(conf
, pos
, end
- pos
);
642 /* Fast BSS Transition Information */
643 if (auth_alg
== WLAN_AUTH_FT
) {
644 subelem
= wpa_ft_gtk_subelem(sm
, &subelem_len
);
645 r0kh_id
= sm
->r0kh_id
;
646 r0kh_id_len
= sm
->r0kh_id_len
;
647 #ifdef CONFIG_IEEE80211W
648 if (sm
->mgmt_frame_prot
) {
652 igtk
= wpa_ft_igtk_subelem(sm
, &igtk_len
);
657 nbuf
= os_realloc(subelem
, subelem_len
+ igtk_len
);
664 os_memcpy(subelem
+ subelem_len
, igtk
, igtk_len
);
665 subelem_len
+= igtk_len
;
668 #endif /* CONFIG_IEEE80211W */
670 r0kh_id
= conf
->r0_key_holder
;
671 r0kh_id_len
= conf
->r0_key_holder_len
;
673 res
= wpa_write_ftie(conf
, r0kh_id
, r0kh_id_len
, NULL
, NULL
, pos
,
674 end
- pos
, subelem
, subelem_len
);
682 _ftie
= (struct rsn_ftie
*) (ftie
+ 2);
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 _ftie
->mic_control
[1] += ieee802_11_ie_count(ric_start
,
691 if (ric_start
== pos
)
694 if (wpa_ft_mic(sm
->PTK
.kck
, sm
->addr
, sm
->wpa_auth
->addr
, 6,
695 mdie
, mdie_len
, ftie
, ftie_len
,
697 ric_start
, ric_start
? pos
- ric_start
: 0,
699 wpa_printf(MSG_DEBUG
, "FT: Failed to calculate MIC");
705 static int wpa_ft_parse_ftie(const u8
*ie
, size_t ie_len
,
706 struct wpa_ft_ies
*parse
)
711 parse
->ftie_len
= ie_len
;
713 pos
= ie
+ sizeof(struct rsn_ftie
);
716 while (pos
+ 2 <= end
&& pos
+ 2 + pos
[1] <= end
) {
718 case FTIE_SUBELEM_R1KH_ID
:
719 if (pos
[1] != FT_R1KH_ID_LEN
) {
720 wpa_printf(MSG_DEBUG
, "FT: Invalid R1KH-ID "
721 "length in FTIE: %d", pos
[1]);
724 parse
->r1kh_id
= pos
+ 2;
726 case FTIE_SUBELEM_GTK
:
727 parse
->gtk
= pos
+ 2;
728 parse
->gtk_len
= pos
[1];
730 case FTIE_SUBELEM_R0KH_ID
:
731 if (pos
[1] < 1 || pos
[1] > FT_R0KH_ID_MAX_LEN
) {
732 wpa_printf(MSG_DEBUG
, "FT: Invalid R0KH-ID "
733 "length in FTIE: %d", pos
[1]);
736 parse
->r0kh_id
= pos
+ 2;
737 parse
->r0kh_id_len
= pos
[1];
748 static int wpa_ft_parse_ies(const u8
*ies
, size_t ies_len
,
749 struct wpa_ft_ies
*parse
)
752 struct wpa_ie_data data
;
754 const struct rsn_ftie
*ftie
;
755 int prot_ie_count
= 0;
757 os_memset(parse
, 0, sizeof(*parse
));
763 while (pos
+ 2 <= end
&& pos
+ 2 + pos
[1] <= end
) {
766 parse
->rsn
= pos
+ 2;
767 parse
->rsn_len
= pos
[1];
768 ret
= wpa_parse_wpa_ie_rsn(parse
->rsn
- 2,
772 wpa_printf(MSG_DEBUG
, "FT: Failed to parse "
776 if (data
.num_pmkid
== 1 && data
.pmkid
)
777 parse
->rsn_pmkid
= data
.pmkid
;
779 case WLAN_EID_MOBILITY_DOMAIN
:
780 parse
->mdie
= pos
+ 2;
781 parse
->mdie_len
= pos
[1];
783 case WLAN_EID_FAST_BSS_TRANSITION
:
784 if (pos
[1] < sizeof(*ftie
))
786 ftie
= (const struct rsn_ftie
*) (pos
+ 2);
787 prot_ie_count
= ftie
->mic_control
[1];
788 if (wpa_ft_parse_ftie(pos
+ 2, pos
[1], parse
) < 0)
791 case WLAN_EID_RIC_DATA
:
792 if (parse
->ric
== NULL
)
799 if (prot_ie_count
== 0)
800 return 0; /* no MIC */
803 * Check that the protected IE count matches with IEs included in the
812 if (prot_ie_count
< 0) {
813 wpa_printf(MSG_DEBUG
, "FT: Some required IEs not included in "
814 "the protected IE count");
818 if (prot_ie_count
== 0 && parse
->ric
) {
819 wpa_printf(MSG_DEBUG
, "FT: RIC IE(s) in the frame, but not "
820 "included in protected IE count");
824 /* Determine the end of the RIC IE(s) */
826 while (pos
&& pos
+ 2 <= end
&& pos
+ 2 + pos
[1] <= end
&&
831 parse
->ric_len
= pos
- parse
->ric
;
833 wpa_printf(MSG_DEBUG
, "FT: %d protected IEs missing from "
834 "frame", (int) prot_ie_count
);
842 static inline int wpa_auth_set_key(struct wpa_authenticator
*wpa_auth
,
844 wpa_alg alg
, const u8
*addr
, int idx
,
845 u8
*key
, size_t key_len
)
847 if (wpa_auth
->cb
.set_key
== NULL
)
849 return wpa_auth
->cb
.set_key(wpa_auth
->cb
.ctx
, vlan_id
, alg
, addr
, idx
,
854 static void wpa_ft_install_ptk(struct wpa_state_machine
*sm
)
859 /* MLME-SETKEYS.request(PTK) */
860 if (sm
->pairwise
== WPA_CIPHER_TKIP
) {
863 } else if (sm
->pairwise
== WPA_CIPHER_CCMP
) {
869 /* FIX: add STA entry to kernel/driver here? The set_key will fail
870 * most likely without this.. At the moment, STA entry is added only
871 * after association has been completed. Alternatively, could
872 * re-configure PTK at that point(?).
874 if (wpa_auth_set_key(sm
->wpa_auth
, 0, alg
, sm
->addr
, 0,
878 /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
879 sm
->pairwise_set
= TRUE
;
883 static u16
wpa_ft_process_auth_req(struct wpa_state_machine
*sm
,
884 const u8
*ies
, size_t ies_len
,
885 u8
**resp_ies
, size_t *resp_ies_len
)
887 struct rsn_mdie
*mdie
;
888 struct rsn_ftie
*ftie
;
889 u8 pmk_r1
[PMK_LEN
], pmk_r1_name
[WPA_PMK_NAME_LEN
];
890 u8 ptk_name
[WPA_PMK_NAME_LEN
];
891 struct wpa_auth_config
*conf
;
892 struct wpa_ft_ies parse
;
893 size_t buflen
, ptk_len
;
900 sm
->pmk_r1_name_valid
= 0;
901 conf
= &sm
->wpa_auth
->conf
;
903 wpa_hexdump(MSG_DEBUG
, "FT: Received authentication frame IEs",
906 if (wpa_ft_parse_ies(ies
, ies_len
, &parse
) < 0) {
907 wpa_printf(MSG_DEBUG
, "FT: Failed to parse FT IEs");
908 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
911 mdie
= (struct rsn_mdie
*) parse
.mdie
;
912 if (mdie
== NULL
|| parse
.mdie_len
< sizeof(*mdie
) ||
913 os_memcmp(mdie
->mobility_domain
,
914 sm
->wpa_auth
->conf
.mobility_domain
,
915 MOBILITY_DOMAIN_ID_LEN
) != 0) {
916 wpa_printf(MSG_DEBUG
, "FT: Invalid MDIE");
917 return WLAN_STATUS_INVALID_MDIE
;
920 ftie
= (struct rsn_ftie
*) parse
.ftie
;
921 if (ftie
== NULL
|| parse
.ftie_len
< sizeof(*ftie
)) {
922 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE");
923 return WLAN_STATUS_INVALID_FTIE
;
926 os_memcpy(sm
->SNonce
, ftie
->snonce
, WPA_NONCE_LEN
);
928 if (parse
.r0kh_id
== NULL
) {
929 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE - no R0KH-ID");
930 return WLAN_STATUS_INVALID_FTIE
;
933 wpa_hexdump(MSG_DEBUG
, "FT: STA R0KH-ID",
934 parse
.r0kh_id
, parse
.r0kh_id_len
);
935 os_memcpy(sm
->r0kh_id
, parse
.r0kh_id
, parse
.r0kh_id_len
);
936 sm
->r0kh_id_len
= parse
.r0kh_id_len
;
938 if (parse
.rsn_pmkid
== NULL
) {
939 wpa_printf(MSG_DEBUG
, "FT: No PMKID in RSNIE");
940 return WLAN_STATUS_INVALID_PMKID
;
943 wpa_hexdump(MSG_DEBUG
, "FT: Requested PMKR0Name",
944 parse
.rsn_pmkid
, WPA_PMK_NAME_LEN
);
945 wpa_derive_pmk_r1_name(parse
.rsn_pmkid
,
946 sm
->wpa_auth
->conf
.r1_key_holder
, sm
->addr
,
948 wpa_hexdump(MSG_DEBUG
, "FT: Derived requested PMKR1Name",
949 pmk_r1_name
, WPA_PMK_NAME_LEN
);
951 if (wpa_ft_fetch_pmk_r1(sm
->wpa_auth
, sm
->addr
, pmk_r1_name
, pmk_r1
) <
953 if (wpa_ft_pull_pmk_r1(sm
->wpa_auth
, sm
->addr
, sm
->r0kh_id
,
954 sm
->r0kh_id_len
, parse
.rsn_pmkid
) < 0) {
955 wpa_printf(MSG_DEBUG
, "FT: Did not have matching "
956 "PMK-R1 and unknown R0KH-ID");
957 return WLAN_STATUS_INVALID_PMKID
;
961 * TODO: Should return "status pending" (and the caller should
962 * not send out response now). The real response will be sent
963 * once the response from R0KH is received.
965 return WLAN_STATUS_INVALID_PMKID
;
968 wpa_hexdump_key(MSG_DEBUG
, "FT: Selected PMK-R1", pmk_r1
, PMK_LEN
);
969 sm
->pmk_r1_name_valid
= 1;
970 os_memcpy(sm
->pmk_r1_name
, pmk_r1_name
, WPA_PMK_NAME_LEN
);
972 if (os_get_random(sm
->ANonce
, WPA_NONCE_LEN
)) {
973 wpa_printf(MSG_DEBUG
, "FT: Failed to get random data for "
975 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
978 wpa_hexdump(MSG_DEBUG
, "FT: Received SNonce",
979 sm
->SNonce
, WPA_NONCE_LEN
);
980 wpa_hexdump(MSG_DEBUG
, "FT: Generated ANonce",
981 sm
->ANonce
, WPA_NONCE_LEN
);
983 ptk_len
= sm
->pairwise
== WPA_CIPHER_CCMP
? 48 : 64;
984 wpa_pmk_r1_to_ptk(pmk_r1
, sm
->SNonce
, sm
->ANonce
, sm
->addr
,
985 sm
->wpa_auth
->addr
, pmk_r1_name
,
986 (u8
*) &sm
->PTK
, ptk_len
, ptk_name
);
987 wpa_hexdump_key(MSG_DEBUG
, "FT: PTK",
988 (u8
*) &sm
->PTK
, ptk_len
);
989 wpa_hexdump(MSG_DEBUG
, "FT: PTKName", ptk_name
, WPA_PMK_NAME_LEN
);
991 wpa_ft_install_ptk(sm
);
993 buflen
= 2 + sizeof(struct rsn_mdie
) + 2 + sizeof(struct rsn_ftie
) +
994 2 + FT_R1KH_ID_LEN
+ 200;
995 *resp_ies
= os_zalloc(buflen
);
996 if (*resp_ies
== NULL
) {
997 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1001 end
= *resp_ies
+ buflen
;
1003 ret
= wpa_write_rsn_ie(conf
, pos
, end
- pos
, parse
.rsn_pmkid
);
1007 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1011 ret
= wpa_write_mdie(conf
, pos
, end
- pos
);
1015 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1019 ret
= wpa_write_ftie(conf
, parse
.r0kh_id
, parse
.r0kh_id_len
,
1020 sm
->ANonce
, sm
->SNonce
, pos
, end
- pos
, NULL
, 0);
1024 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1028 *resp_ies_len
= pos
- *resp_ies
;
1030 return WLAN_STATUS_SUCCESS
;
1034 void wpa_ft_process_auth(struct wpa_state_machine
*sm
, const u8
*bssid
,
1035 u16 auth_transaction
, const u8
*ies
, size_t ies_len
,
1036 void (*cb
)(void *ctx
, const u8
*dst
, const u8
*bssid
,
1037 u16 auth_transaction
, u16 status
,
1038 const u8
*ies
, size_t ies_len
),
1043 size_t resp_ies_len
;
1046 wpa_printf(MSG_DEBUG
, "FT: Received authentication frame, but "
1047 "WPA SM not available");
1051 wpa_printf(MSG_DEBUG
, "FT: Received authentication frame: STA=" MACSTR
1052 " BSSID=" MACSTR
" transaction=%d",
1053 MAC2STR(sm
->addr
), MAC2STR(bssid
), auth_transaction
);
1054 status
= wpa_ft_process_auth_req(sm
, ies
, ies_len
, &resp_ies
,
1057 wpa_printf(MSG_DEBUG
, "FT: FT authentication response: dst=" MACSTR
1058 " auth_transaction=%d status=%d",
1059 MAC2STR(sm
->addr
), auth_transaction
+ 1, status
);
1060 wpa_hexdump(MSG_DEBUG
, "FT: Response IEs", resp_ies
, resp_ies_len
);
1061 cb(ctx
, sm
->addr
, bssid
, auth_transaction
+ 1, status
,
1062 resp_ies
, resp_ies_len
);
1067 u16
wpa_ft_validate_reassoc(struct wpa_state_machine
*sm
, const u8
*ies
,
1070 struct wpa_ft_ies parse
;
1071 struct rsn_mdie
*mdie
;
1072 struct rsn_ftie
*ftie
;
1076 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1078 wpa_hexdump(MSG_DEBUG
, "FT: Reassoc Req IEs", ies
, ies_len
);
1080 if (wpa_ft_parse_ies(ies
, ies_len
, &parse
) < 0) {
1081 wpa_printf(MSG_DEBUG
, "FT: Failed to parse FT IEs");
1082 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1085 if (parse
.rsn
== NULL
) {
1086 wpa_printf(MSG_DEBUG
, "FT: No RSNIE in Reassoc Req");
1087 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1090 if (parse
.rsn_pmkid
== NULL
) {
1091 wpa_printf(MSG_DEBUG
, "FT: No PMKID in RSNIE");
1092 return WLAN_STATUS_INVALID_PMKID
;
1095 if (os_memcmp(parse
.rsn_pmkid
, sm
->pmk_r1_name
, WPA_PMK_NAME_LEN
) != 0)
1097 wpa_printf(MSG_DEBUG
, "FT: PMKID in Reassoc Req did not match "
1098 "with the PMKR1Name derived from auth request");
1099 return WLAN_STATUS_INVALID_PMKID
;
1102 mdie
= (struct rsn_mdie
*) parse
.mdie
;
1103 if (mdie
== NULL
|| parse
.mdie_len
< sizeof(*mdie
) ||
1104 os_memcmp(mdie
->mobility_domain
,
1105 sm
->wpa_auth
->conf
.mobility_domain
,
1106 MOBILITY_DOMAIN_ID_LEN
) != 0) {
1107 wpa_printf(MSG_DEBUG
, "FT: Invalid MDIE");
1108 return WLAN_STATUS_INVALID_MDIE
;
1111 ftie
= (struct rsn_ftie
*) parse
.ftie
;
1112 if (ftie
== NULL
|| parse
.ftie_len
< sizeof(*ftie
)) {
1113 wpa_printf(MSG_DEBUG
, "FT: Invalid FTIE");
1114 return WLAN_STATUS_INVALID_FTIE
;
1117 if (wpa_ft_mic(sm
->PTK
.kck
, sm
->addr
, sm
->wpa_auth
->addr
, 5,
1118 parse
.mdie
- 2, parse
.mdie_len
+ 2,
1119 parse
.ftie
- 2, parse
.ftie_len
+ 2,
1120 parse
.rsn
- 2, parse
.rsn_len
+ 2,
1121 parse
.ric
, parse
.ric_len
,
1123 wpa_printf(MSG_DEBUG
, "FT: Failed to calculate MIC");
1124 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1127 if (os_memcmp(mic
, ftie
->mic
, 16) != 0) {
1128 wpa_printf(MSG_DEBUG
, "FT: Invalid MIC in FTIE");
1129 wpa_hexdump(MSG_MSGDUMP
, "FT: Received MIC", ftie
->mic
, 16);
1130 wpa_hexdump(MSG_MSGDUMP
, "FT: Calculated MIC", mic
, 16);
1131 return WLAN_STATUS_INVALID_FTIE
;
1134 return WLAN_STATUS_SUCCESS
;
1138 int wpa_ft_action_rx(struct wpa_state_machine
*sm
, const u8
*data
, size_t len
)
1140 const u8
*sta_addr
, *target_ap
;
1144 struct ft_rrb_frame
*frame
;
1150 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1151 * FT Request action frame body[variable]
1155 wpa_printf(MSG_DEBUG
, "FT: Too short FT Action frame "
1156 "(len=%lu)", (unsigned long) len
);
1161 sta_addr
= data
+ 2;
1162 target_ap
= data
+ 8;
1166 wpa_printf(MSG_DEBUG
, "FT: Received FT Action frame (STA=" MACSTR
1167 " Target AP=" MACSTR
" Action=%d)",
1168 MAC2STR(sta_addr
), MAC2STR(target_ap
), action
);
1170 if (os_memcmp(sta_addr
, sm
->addr
, ETH_ALEN
) != 0) {
1171 wpa_printf(MSG_DEBUG
, "FT: Mismatch in FT Action STA address: "
1172 "STA=" MACSTR
" STA-Address=" MACSTR
,
1173 MAC2STR(sm
->addr
), MAC2STR(sta_addr
));
1178 * Do some sanity checking on the target AP address (not own and not
1179 * broadcast. This could be extended to filter based on a list of known
1180 * APs in the MD (if such a list were configured).
1182 if ((target_ap
[0] & 0x01) ||
1183 os_memcmp(target_ap
, sm
->wpa_auth
->addr
, ETH_ALEN
) == 0) {
1184 wpa_printf(MSG_DEBUG
, "FT: Invalid Target AP in FT Action "
1189 wpa_hexdump(MSG_MSGDUMP
, "FT: Action frame body", ies
, ies_len
);
1191 /* RRB - Forward action frame to the target AP */
1192 frame
= os_malloc(sizeof(*frame
) + len
);
1193 frame
->frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1194 frame
->packet_type
= FT_PACKET_REQUEST
;
1195 frame
->action_length
= host_to_le16(len
);
1196 os_memcpy(frame
->ap_address
, sm
->wpa_auth
->addr
, ETH_ALEN
);
1197 os_memcpy(frame
+ 1, data
, len
);
1199 wpa_ft_rrb_send(sm
->wpa_auth
, target_ap
, (u8
*) frame
,
1200 sizeof(*frame
) + len
);
1207 static int wpa_ft_rrb_rx_request(struct wpa_authenticator
*wpa_auth
,
1208 const u8
*current_ap
, const u8
*sta_addr
,
1209 const u8
*body
, size_t len
)
1211 struct wpa_state_machine
*sm
;
1214 size_t resp_ies_len
, rlen
;
1215 struct ft_rrb_frame
*frame
;
1217 sm
= wpa_ft_add_sta(wpa_auth
, sta_addr
);
1219 wpa_printf(MSG_DEBUG
, "FT: Failed to add new STA based on "
1224 wpa_hexdump(MSG_MSGDUMP
, "FT: RRB Request Frame body", body
, len
);
1226 status
= wpa_ft_process_auth_req(sm
, body
, len
, &resp_ies
,
1229 wpa_printf(MSG_DEBUG
, "FT: RRB authentication response: STA=" MACSTR
1230 " CurrentAP=" MACSTR
" status=%d",
1231 MAC2STR(sm
->addr
), MAC2STR(current_ap
), status
);
1232 wpa_hexdump(MSG_DEBUG
, "FT: Response IEs", resp_ies
, resp_ies_len
);
1234 /* RRB - Forward action frame response to the Current AP */
1237 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
1238 * Status_Code[2] FT Request action frame body[variable]
1240 rlen
= 2 + 2 * ETH_ALEN
+ 2 + resp_ies_len
;
1242 frame
= os_malloc(sizeof(*frame
) + rlen
);
1243 frame
->frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1244 frame
->packet_type
= FT_PACKET_RESPONSE
;
1245 frame
->action_length
= host_to_le16(rlen
);
1246 os_memcpy(frame
->ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1247 pos
= (u8
*) (frame
+ 1);
1248 *pos
++ = WLAN_ACTION_FT
;
1249 *pos
++ = 2; /* Action: Response */
1250 os_memcpy(pos
, sta_addr
, ETH_ALEN
);
1252 os_memcpy(pos
, wpa_auth
->addr
, ETH_ALEN
);
1254 WPA_PUT_LE16(pos
, status
);
1257 os_memcpy(pos
, resp_ies
, resp_ies_len
);
1261 wpa_ft_rrb_send(wpa_auth
, current_ap
, (u8
*) frame
,
1262 sizeof(*frame
) + rlen
);
1269 static int wpa_ft_rrb_rx_pull(struct wpa_authenticator
*wpa_auth
,
1271 const u8
*data
, size_t data_len
)
1273 struct ft_r0kh_r1kh_pull_frame
*frame
, f
;
1274 struct ft_remote_r1kh
*r1kh
;
1275 struct ft_r0kh_r1kh_resp_frame resp
, r
;
1278 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 pull");
1280 if (data_len
< sizeof(*frame
))
1283 r1kh
= wpa_auth
->conf
.r1kh_list
;
1285 if (os_memcmp(r1kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1290 wpa_printf(MSG_DEBUG
, "FT: No matching R1KH address found for "
1291 "PMK-R1 pull source address " MACSTR
,
1296 frame
= (struct ft_r0kh_r1kh_pull_frame
*) data
;
1297 /* aes_unwrap() does not support inplace decryption, so use a temporary
1298 * buffer for the data. */
1299 if (aes_unwrap(r1kh
->key
, (FT_R0KH_R1KH_PULL_DATA_LEN
+ 7) / 8,
1300 frame
->nonce
, f
.nonce
) < 0) {
1301 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 pull "
1302 "request from " MACSTR
, MAC2STR(src_addr
));
1306 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - nonce",
1307 f
.nonce
, sizeof(f
.nonce
));
1308 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - PMKR0Name",
1309 f
.pmk_r0_name
, WPA_PMK_NAME_LEN
);
1310 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
"S1KH-ID="
1311 MACSTR
, MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
));
1313 os_memset(&resp
, 0, sizeof(resp
));
1314 resp
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1315 resp
.packet_type
= FT_PACKET_R0KH_R1KH_RESP
;
1316 resp
.data_length
= host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN
);
1317 os_memcpy(resp
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1319 /* aes_wrap() does not support inplace encryption, so use a temporary
1320 * buffer for the data. */
1321 os_memcpy(r
.nonce
, f
.nonce
, sizeof(f
.nonce
));
1322 os_memcpy(r
.r1kh_id
, f
.r1kh_id
, FT_R1KH_ID_LEN
);
1323 os_memcpy(r
.s1kh_id
, f
.s1kh_id
, ETH_ALEN
);
1324 if (wpa_ft_fetch_pmk_r0(wpa_auth
, f
.s1kh_id
, f
.pmk_r0_name
, pmk_r0
) <
1326 wpa_printf(MSG_DEBUG
, "FT: No matching PMKR0Name found for "
1331 wpa_derive_pmk_r1(pmk_r0
, f
.pmk_r0_name
, f
.r1kh_id
, f
.s1kh_id
,
1332 r
.pmk_r1
, r
.pmk_r1_name
);
1333 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", r
.pmk_r1
, PMK_LEN
);
1334 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", r
.pmk_r1_name
,
1337 if (aes_wrap(r1kh
->key
, (FT_R0KH_R1KH_RESP_DATA_LEN
+ 7) / 8,
1338 r
.nonce
, resp
.nonce
) < 0) {
1339 os_memset(pmk_r0
, 0, PMK_LEN
);
1343 os_memset(pmk_r0
, 0, PMK_LEN
);
1345 wpa_ft_rrb_send(wpa_auth
, src_addr
, (u8
*) &resp
, sizeof(resp
));
1351 static int wpa_ft_rrb_rx_resp(struct wpa_authenticator
*wpa_auth
,
1353 const u8
*data
, size_t data_len
)
1355 struct ft_r0kh_r1kh_resp_frame
*frame
, f
;
1356 struct ft_remote_r0kh
*r0kh
;
1358 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 pull response");
1360 if (data_len
< sizeof(*frame
))
1363 r0kh
= wpa_auth
->conf
.r0kh_list
;
1365 if (os_memcmp(r0kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1370 wpa_printf(MSG_DEBUG
, "FT: No matching R0KH address found for "
1371 "PMK-R0 pull response source address " MACSTR
,
1376 frame
= (struct ft_r0kh_r1kh_resp_frame
*) data
;
1377 /* aes_unwrap() does not support inplace decryption, so use a temporary
1378 * buffer for the data. */
1379 if (aes_unwrap(r0kh
->key
, (FT_R0KH_R1KH_RESP_DATA_LEN
+ 7) / 8,
1380 frame
->nonce
, f
.nonce
) < 0) {
1381 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 pull "
1382 "response from " MACSTR
, MAC2STR(src_addr
));
1386 if (os_memcmp(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
)
1388 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull response did not use a "
1389 "matching R1KH-ID");
1393 /* TODO: verify that <nonce,s1kh_id> matches with a pending request
1394 * and call this requests callback function to finish request
1397 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - nonce",
1398 f
.nonce
, sizeof(f
.nonce
));
1399 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
"S1KH-ID="
1400 MACSTR
, MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
));
1401 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1 pull - PMK-R1",
1403 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 pull - PMKR1Name",
1404 f
.pmk_r1_name
, WPA_PMK_NAME_LEN
);
1406 wpa_ft_store_pmk_r1(wpa_auth
, f
.s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
);
1407 os_memset(f
.pmk_r1
, 0, PMK_LEN
);
1413 static int wpa_ft_rrb_rx_push(struct wpa_authenticator
*wpa_auth
,
1415 const u8
*data
, size_t data_len
)
1417 struct ft_r0kh_r1kh_push_frame
*frame
, f
;
1418 struct ft_remote_r0kh
*r0kh
;
1422 wpa_printf(MSG_DEBUG
, "FT: Received PMK-R1 push");
1424 if (data_len
< sizeof(*frame
))
1427 r0kh
= wpa_auth
->conf
.r0kh_list
;
1429 if (os_memcmp(r0kh
->addr
, src_addr
, ETH_ALEN
) == 0)
1434 wpa_printf(MSG_DEBUG
, "FT: No matching R0KH address found for "
1435 "PMK-R0 push source address " MACSTR
,
1440 frame
= (struct ft_r0kh_r1kh_push_frame
*) data
;
1441 /* aes_unwrap() does not support inplace decryption, so use a temporary
1442 * buffer for the data. */
1443 if (aes_unwrap(r0kh
->key
, (FT_R0KH_R1KH_PUSH_DATA_LEN
+ 7) / 8,
1444 frame
->timestamp
, f
.timestamp
) < 0) {
1445 wpa_printf(MSG_DEBUG
, "FT: Failed to decrypt PMK-R1 push from "
1446 MACSTR
, MAC2STR(src_addr
));
1451 tsend
= WPA_GET_LE32(f
.timestamp
);
1452 if ((now
.sec
> tsend
&& now
.sec
- tsend
> 60) ||
1453 (now
.sec
< tsend
&& tsend
- now
.sec
> 60)) {
1454 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push did not have a valid "
1455 "timestamp: sender time %d own time %d\n",
1456 (int) tsend
, (int) now
.sec
);
1460 if (os_memcmp(f
.r1kh_id
, wpa_auth
->conf
.r1_key_holder
, FT_R1KH_ID_LEN
)
1462 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push did not use a matching "
1463 "R1KH-ID (received " MACSTR
" own " MACSTR
")",
1465 MAC2STR(wpa_auth
->conf
.r1_key_holder
));
1469 wpa_printf(MSG_DEBUG
, "FT: PMK-R1 push - R1KH-ID=" MACSTR
" S1KH-ID="
1470 MACSTR
, MAC2STR(f
.r1kh_id
), MAC2STR(f
.s1kh_id
));
1471 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1 push - PMK-R1",
1473 wpa_hexdump(MSG_DEBUG
, "FT: PMK-R1 push - PMKR1Name",
1474 f
.pmk_r1_name
, WPA_PMK_NAME_LEN
);
1476 wpa_ft_store_pmk_r1(wpa_auth
, f
.s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
);
1477 os_memset(f
.pmk_r1
, 0, PMK_LEN
);
1483 int wpa_ft_rrb_rx(struct wpa_authenticator
*wpa_auth
, const u8
*src_addr
,
1484 const u8
*data
, size_t data_len
)
1486 struct ft_rrb_frame
*frame
;
1488 const u8
*pos
, *end
, *start
;
1490 const u8
*sta_addr
, *target_ap_addr
;
1492 wpa_printf(MSG_DEBUG
, "FT: RRB received frame from remote AP " MACSTR
,
1495 if (data_len
< sizeof(*frame
)) {
1496 wpa_printf(MSG_DEBUG
, "FT: Too short RRB frame (data_len=%lu)",
1497 (unsigned long) data_len
);
1502 frame
= (struct ft_rrb_frame
*) pos
;
1503 pos
+= sizeof(*frame
);
1505 alen
= le_to_host16(frame
->action_length
);
1506 wpa_printf(MSG_DEBUG
, "FT: RRB frame - frame_type=%d packet_type=%d "
1507 "action_length=%d ap_address=" MACSTR
,
1508 frame
->frame_type
, frame
->packet_type
, alen
,
1509 MAC2STR(frame
->ap_address
));
1511 if (frame
->frame_type
!= RSN_REMOTE_FRAME_TYPE_FT_RRB
) {
1512 /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
1513 wpa_printf(MSG_DEBUG
, "FT: RRB discarded frame with "
1514 "unrecognized type %d", frame
->frame_type
);
1518 if (alen
> data_len
- sizeof(*frame
)) {
1519 wpa_printf(MSG_DEBUG
, "FT: RRB frame too short for action "
1524 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_PULL
)
1525 return wpa_ft_rrb_rx_pull(wpa_auth
, src_addr
, data
, data_len
);
1526 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_RESP
)
1527 return wpa_ft_rrb_rx_resp(wpa_auth
, src_addr
, data
, data_len
);
1528 if (frame
->packet_type
== FT_PACKET_R0KH_R1KH_PUSH
)
1529 return wpa_ft_rrb_rx_push(wpa_auth
, src_addr
, data
, data_len
);
1531 wpa_hexdump(MSG_MSGDUMP
, "FT: RRB - FT Action frame", pos
, alen
);
1533 if (alen
< 1 + 1 + 2 * ETH_ALEN
) {
1534 wpa_printf(MSG_DEBUG
, "FT: Too short RRB frame (not enough "
1535 "room for Action Frame body); alen=%lu",
1536 (unsigned long) alen
);
1542 if (*pos
!= WLAN_ACTION_FT
) {
1543 wpa_printf(MSG_DEBUG
, "FT: Unexpected Action frame category "
1552 target_ap_addr
= pos
;
1554 wpa_printf(MSG_DEBUG
, "FT: RRB Action Frame: action=%d sta_addr="
1555 MACSTR
" target_ap_addr=" MACSTR
,
1556 action
, MAC2STR(sta_addr
), MAC2STR(target_ap_addr
));
1558 if (frame
->packet_type
== FT_PACKET_REQUEST
) {
1559 wpa_printf(MSG_DEBUG
, "FT: FT Packet Type - Request");
1562 wpa_printf(MSG_DEBUG
, "FT: Unexpected Action %d in "
1563 "RRB Request", action
);
1567 if (os_memcmp(target_ap_addr
, wpa_auth
->addr
, ETH_ALEN
) != 0) {
1568 wpa_printf(MSG_DEBUG
, "FT: Target AP address in the "
1569 "RRB Request does not match with own "
1574 if (wpa_ft_rrb_rx_request(wpa_auth
, frame
->ap_address
,
1575 sta_addr
, pos
, end
- pos
) < 0)
1577 } else if (frame
->packet_type
== FT_PACKET_RESPONSE
) {
1580 if (end
- pos
< 2) {
1581 wpa_printf(MSG_DEBUG
, "FT: Not enough room for status "
1582 "code in RRB Response");
1585 status_code
= WPA_GET_LE16(pos
);
1588 wpa_printf(MSG_DEBUG
, "FT: FT Packet Type - Response "
1589 "(status_code=%d)", status_code
);
1591 if (wpa_ft_action_send(wpa_auth
, sta_addr
, start
, alen
) < 0)
1594 wpa_printf(MSG_DEBUG
, "FT: RRB discarded frame with unknown "
1595 "packet_type %d", frame
->packet_type
);
1603 static void wpa_ft_generate_pmk_r1(struct wpa_authenticator
*wpa_auth
,
1604 struct wpa_ft_pmk_r0_sa
*pmk_r0
,
1605 struct ft_remote_r1kh
*r1kh
,
1608 struct ft_r0kh_r1kh_push_frame frame
, f
;
1611 os_memset(&frame
, 0, sizeof(frame
));
1612 frame
.frame_type
= RSN_REMOTE_FRAME_TYPE_FT_RRB
;
1613 frame
.packet_type
= FT_PACKET_R0KH_R1KH_PUSH
;
1614 frame
.data_length
= host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN
);
1615 os_memcpy(frame
.ap_address
, wpa_auth
->addr
, ETH_ALEN
);
1617 /* aes_wrap() does not support inplace encryption, so use a temporary
1618 * buffer for the data. */
1619 os_memcpy(f
.r1kh_id
, r1kh
->id
, FT_R1KH_ID_LEN
);
1620 os_memcpy(f
.s1kh_id
, s1kh_id
, ETH_ALEN
);
1621 os_memcpy(f
.pmk_r0_name
, pmk_r0
->pmk_r0_name
, WPA_PMK_NAME_LEN
);
1622 wpa_derive_pmk_r1(pmk_r0
->pmk_r0
, pmk_r0
->pmk_r0_name
, r1kh
->id
,
1623 s1kh_id
, f
.pmk_r1
, f
.pmk_r1_name
);
1624 wpa_printf(MSG_DEBUG
, "FT: R1KH-ID " MACSTR
, MAC2STR(r1kh
->id
));
1625 wpa_hexdump_key(MSG_DEBUG
, "FT: PMK-R1", f
.pmk_r1
, PMK_LEN
);
1626 wpa_hexdump(MSG_DEBUG
, "FT: PMKR1Name", f
.pmk_r1_name
,
1629 WPA_PUT_LE32(f
.timestamp
, now
.sec
);
1630 if (aes_wrap(r1kh
->key
, (FT_R0KH_R1KH_PUSH_DATA_LEN
+ 7) / 8,
1631 f
.timestamp
, frame
.timestamp
) < 0)
1634 wpa_ft_rrb_send(wpa_auth
, r1kh
->addr
, (u8
*) &frame
, sizeof(frame
));
1638 void wpa_ft_push_pmk_r1(struct wpa_authenticator
*wpa_auth
, const u8
*addr
)
1640 struct wpa_ft_pmk_r0_sa
*r0
;
1641 struct ft_remote_r1kh
*r1kh
;
1643 if (!wpa_auth
->conf
.pmk_r1_push
)
1646 r0
= wpa_auth
->ft_pmk_cache
->pmk_r0
;
1648 if (os_memcmp(r0
->spa
, addr
, ETH_ALEN
) == 0)
1653 if (r0
== NULL
|| r0
->pmk_r1_pushed
)
1655 r0
->pmk_r1_pushed
= 1;
1657 wpa_printf(MSG_DEBUG
, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
1658 "for STA " MACSTR
, MAC2STR(addr
));
1660 r1kh
= wpa_auth
->conf
.r1kh_list
;
1662 wpa_ft_generate_pmk_r1(wpa_auth
, r0
, r1kh
, addr
);
1667 #endif /* CONFIG_IEEE80211R */