wpa_ft.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
1/* 2 * WPA Supplicant - IEEE 802.11r - Fast BSS Transition 3 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 4 * 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. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include "includes.h" 16 17#include "common.h" 18#include "crypto/aes_wrap.h" 19#include "crypto/random.h" 20#include "common/ieee802_11_defs.h" 21#include "common/ieee802_11_common.h" 22#include "wpa.h" 23#include "wpa_i.h" 24 25#ifdef CONFIG_IEEE80211R 26 27int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, 28 const struct wpa_eapol_key *key, 29 struct wpa_ptk *ptk, size_t ptk_len) 30{ 31 u8 ptk_name[WPA_PMK_NAME_LEN]; 32 const u8 *anonce = key->key_nonce; 33 34 if (sm->xxkey_len == 0) { 35 wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " 36 "derivation"); 37 return -1; 38 } 39 40 wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid, 41 sm->ssid_len, sm->mobility_domain, 42 sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, 43 sm->pmk_r0, sm->pmk_r0_name); 44 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN); 45 wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", 46 sm->pmk_r0_name, WPA_PMK_NAME_LEN); 47 wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, 48 sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); 49 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); 50 wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, 51 WPA_PMK_NAME_LEN); 52 wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, 53 sm->bssid, sm->pmk_r1_name, 54 (u8 *) ptk, ptk_len, ptk_name); 55 wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); 56 wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); 57 58 return 0; 59} 60 61 62/** 63 * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters 64 * @sm: Pointer to WPA state machine data from wpa_sm_init() 65 * @ies: Association Response IEs or %NULL to clear FT parameters 66 * @ies_len: Length of ies buffer in octets 67 * Returns: 0 on success, -1 on failure 68 */ 69int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) 70{ 71 struct wpa_ft_ies ft; 72 73 if (sm == NULL) 74 return 0; 75 76 if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0) 77 return -1; 78 79 if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) 80 return -1; 81 82 if (ft.mdie) { 83 wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", 84 ft.mdie, MOBILITY_DOMAIN_ID_LEN); 85 os_memcpy(sm->mobility_domain, ft.mdie, 86 MOBILITY_DOMAIN_ID_LEN); 87 sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; 88 wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", 89 sm->mdie_ft_capab); 90 } else 91 os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); 92 93 if (ft.r0kh_id) { 94 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", 95 ft.r0kh_id, ft.r0kh_id_len); 96 os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len); 97 sm->r0kh_id_len = ft.r0kh_id_len; 98 } else { 99 /* FIX: When should R0KH-ID be cleared? We need to keep the 100 * old R0KH-ID in order to be able to use this during FT. */ 101 /* 102 * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN); 103 * sm->r0kh_id_len = 0; 104 */ 105 } 106 107 if (ft.r1kh_id) { 108 wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", 109 ft.r1kh_id, FT_R1KH_ID_LEN); 110 os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN); 111 } else 112 os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); 113 114 os_free(sm->assoc_resp_ies); 115 sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2); 116 if (sm->assoc_resp_ies) { 117 u8 *pos = sm->assoc_resp_ies; 118 if (ft.mdie) { 119 os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); 120 pos += ft.mdie_len + 2; 121 } 122 if (ft.ftie) { 123 os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2); 124 pos += ft.ftie_len + 2; 125 } 126 sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies; 127 wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from " 128 "(Re)Association Response", 129 sm->assoc_resp_ies, sm->assoc_resp_ies_len); 130 } 131 132 return 0; 133} 134 135 136/** 137 * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request 138 * @sm: Pointer to WPA state machine data from wpa_sm_init() 139 * @len: Buffer for returning the length of the IEs 140 * @anonce: ANonce or %NULL if not yet available 141 * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List 142 * @kck: 128-bit KCK for MIC or %NULL if no MIC is used 143 * @target_ap: Target AP address 144 * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL 145 * @ric_ies_len: Length of ric_ies buffer in octets 146 * @ap_mdie: Mobility Domain IE from the target AP 147 * Returns: Pointer to buffer with IEs or %NULL on failure 148 * 149 * Caller is responsible for freeing the returned buffer with os_free(); 150 */ 151static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, 152 const u8 *anonce, const u8 *pmk_name, 153 const u8 *kck, const u8 *target_ap, 154 const u8 *ric_ies, size_t ric_ies_len, 155 const u8 *ap_mdie) 156{ 157 size_t buf_len; 158 u8 *buf, *pos, *ftie_len, *ftie_pos; 159 struct rsn_mdie *mdie; 160 struct rsn_ftie *ftie; 161 struct rsn_ie_hdr *rsnie; 162 u16 capab; 163 164 sm->ft_completed = 0; 165 166 buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + 167 2 + sm->r0kh_id_len + ric_ies_len + 100; 168 buf = os_zalloc(buf_len); 169 if (buf == NULL) 170 return NULL; 171 pos = buf; 172 173 /* RSNIE[PMKR0Name/PMKR1Name] */ 174 rsnie = (struct rsn_ie_hdr *) pos; 175 rsnie->elem_id = WLAN_EID_RSN; 176 WPA_PUT_LE16(rsnie->version, RSN_VERSION); 177 pos = (u8 *) (rsnie + 1); 178 179 /* Group Suite Selector */ 180 if (sm->group_cipher == WPA_CIPHER_CCMP) 181 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 182 else if (sm->group_cipher == WPA_CIPHER_TKIP) 183 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 184 else { 185 wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)", 186 sm->group_cipher); 187 os_free(buf); 188 return NULL; 189 } 190 pos += RSN_SELECTOR_LEN; 191 192 /* Pairwise Suite Count */ 193 WPA_PUT_LE16(pos, 1); 194 pos += 2; 195 196 /* Pairwise Suite List */ 197 if (sm->pairwise_cipher == WPA_CIPHER_CCMP) 198 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 199 else if (sm->pairwise_cipher == WPA_CIPHER_TKIP) 200 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 201 else { 202 wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)", 203 sm->pairwise_cipher); 204 os_free(buf); 205 return NULL; 206 } 207 pos += RSN_SELECTOR_LEN; 208 209 /* Authenticated Key Management Suite Count */ 210 WPA_PUT_LE16(pos, 1); 211 pos += 2; 212 213 /* Authenticated Key Management Suite List */ 214 if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) 215 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 216 else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) 217 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 218 else { 219 wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", 220 sm->key_mgmt); 221 os_free(buf); 222 return NULL; 223 } 224 pos += RSN_SELECTOR_LEN; 225 226 /* RSN Capabilities */ 227 capab = 0; 228#ifdef CONFIG_IEEE80211W 229 if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) 230 capab |= WPA_CAPABILITY_MFPC; 231#endif /* CONFIG_IEEE80211W */ 232 WPA_PUT_LE16(pos, capab); 233 pos += 2; 234 235 /* PMKID Count */ 236 WPA_PUT_LE16(pos, 1); 237 pos += 2; 238 239 /* PMKID List [PMKR0Name/PMKR1Name] */ 240 os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN); 241 pos += WPA_PMK_NAME_LEN; 242 243#ifdef CONFIG_IEEE80211W 244 if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { 245 /* Management Group Cipher Suite */ 246 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 247 pos += RSN_SELECTOR_LEN; 248 } 249#endif /* CONFIG_IEEE80211W */ 250 251 rsnie->len = (pos - (u8 *) rsnie) - 2; 252 253 /* MDIE */ 254 *pos++ = WLAN_EID_MOBILITY_DOMAIN; 255 *pos++ = sizeof(*mdie); 256 mdie = (struct rsn_mdie *) pos; 257 pos += sizeof(*mdie); 258 os_memcpy(mdie->mobility_domain, sm->mobility_domain, 259 MOBILITY_DOMAIN_ID_LEN); 260 mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] : 261 sm->mdie_ft_capab; 262 263 /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */ 264 ftie_pos = pos; 265 *pos++ = WLAN_EID_FAST_BSS_TRANSITION; 266 ftie_len = pos++; 267 ftie = (struct rsn_ftie *) pos; 268 pos += sizeof(*ftie); 269 os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); 270 if (anonce) 271 os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); 272 if (kck) { 273 /* R1KH-ID sub-element in third FT message */ 274 *pos++ = FTIE_SUBELEM_R1KH_ID; 275 *pos++ = FT_R1KH_ID_LEN; 276 os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN); 277 pos += FT_R1KH_ID_LEN; 278 } 279 /* R0KH-ID sub-element */ 280 *pos++ = FTIE_SUBELEM_R0KH_ID; 281 *pos++ = sm->r0kh_id_len; 282 os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len); 283 pos += sm->r0kh_id_len; 284 *ftie_len = pos - ftie_len - 1; 285 286 if (ric_ies) { 287 /* RIC Request */ 288 os_memcpy(pos, ric_ies, ric_ies_len); 289 pos += ric_ies_len; 290 } 291 292 if (kck) { 293 /* 294 * IEEE Std 802.11r-2008, 11A.8.4 295 * MIC shall be calculated over: 296 * non-AP STA MAC address 297 * Target AP MAC address 298 * Transaction seq number (5 for ReassocReq, 3 otherwise) 299 * RSN IE 300 * MDIE 301 * FTIE (with MIC field set to 0) 302 * RIC-Request (if present) 303 */ 304 /* Information element count */ 305 ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies, 306 ric_ies_len); 307 if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5, 308 ((u8 *) mdie) - 2, 2 + sizeof(*mdie), 309 ftie_pos, 2 + *ftie_len, 310 (u8 *) rsnie, 2 + rsnie->len, ric_ies, 311 ric_ies_len, ftie->mic) < 0) { 312 wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); 313 os_free(buf); 314 return NULL; 315 } 316 } 317 318 *len = pos - buf; 319 320 return buf; 321} 322 323 324static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) 325{ 326 int keylen; 327 enum wpa_alg alg; 328 u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 }; 329 330 wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver."); 331 332 switch (sm->pairwise_cipher) { 333 case WPA_CIPHER_CCMP: 334 alg = WPA_ALG_CCMP; 335 keylen = 16; 336 break; 337 case WPA_CIPHER_TKIP: 338 alg = WPA_ALG_TKIP; 339 keylen = 32; 340 break; 341 default: 342 wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d", 343 sm->pairwise_cipher); 344 return -1; 345 } 346 347 if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, 348 sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) { 349 wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); 350 return -1; 351 } 352 353 return 0; 354} 355 356 357/** 358 * wpa_ft_prepare_auth_request - Generate over-the-air auth request 359 * @sm: Pointer to WPA state machine data from wpa_sm_init() 360 * @mdie: Target AP MDIE 361 * Returns: 0 on success, -1 on failure 362 */ 363int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) 364{ 365 u8 *ft_ies; 366 size_t ft_ies_len; 367 368 /* Generate a new SNonce */ 369 if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { 370 wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); 371 return -1; 372 } 373 374 ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, 375 NULL, sm->bssid, NULL, 0, mdie); 376 if (ft_ies) { 377 wpa_sm_update_ft_ies(sm, sm->mobility_domain, 378 ft_ies, ft_ies_len); 379 os_free(ft_ies); 380 } 381 382 return 0; 383} 384 385 386int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, 387 int ft_action, const u8 *target_ap, 388 const u8 *ric_ies, size_t ric_ies_len) 389{ 390 u8 *ft_ies; 391 size_t ft_ies_len, ptk_len; 392 struct wpa_ft_ies parse; 393 struct rsn_mdie *mdie; 394 struct rsn_ftie *ftie; 395 u8 ptk_name[WPA_PMK_NAME_LEN]; 396 int ret; 397 const u8 *bssid; 398 399 wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); 400 wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); 401 402 if (ft_action) { 403 if (!sm->over_the_ds_in_progress) { 404 wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " 405 "- drop FT Action Response"); 406 return -1; 407 } 408 409 if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) { 410 wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " 411 "with this Target AP - drop FT Action " 412 "Response"); 413 return -1; 414 } 415 } 416 417 if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && 418 sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { 419 wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " 420 "enabled for this connection"); 421 return -1; 422 } 423 424 if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { 425 wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); 426 return -1; 427 } 428 429 mdie = (struct rsn_mdie *) parse.mdie; 430 if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || 431 os_memcmp(mdie->mobility_domain, sm->mobility_domain, 432 MOBILITY_DOMAIN_ID_LEN) != 0) { 433 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); 434 return -1; 435 } 436 437 ftie = (struct rsn_ftie *) parse.ftie; 438 if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { 439 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); 440 return -1; 441 } 442 443 if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { 444 wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); 445 wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", 446 ftie->snonce, WPA_NONCE_LEN); 447 wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", 448 sm->snonce, WPA_NONCE_LEN); 449 return -1; 450 } 451 452 if (parse.r0kh_id == NULL) { 453 wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); 454 return -1; 455 } 456 457 if (parse.r0kh_id_len != sm->r0kh_id_len || 458 os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { 459 wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " 460 "the current R0KH-ID"); 461 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", 462 parse.r0kh_id, parse.r0kh_id_len); 463 wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", 464 sm->r0kh_id, sm->r0kh_id_len); 465 return -1; 466 } 467 468 if (parse.r1kh_id == NULL) { 469 wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); 470 return -1; 471 } 472 473 if (parse.rsn_pmkid == NULL || 474 os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) { 475 wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in " 476 "RSNIE"); 477 return -1; 478 } 479 480 os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN); 481 wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); 482 wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); 483 wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN); 484 os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN); 485 wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, 486 sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); 487 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); 488 wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", 489 sm->pmk_r1_name, WPA_PMK_NAME_LEN); 490 491 bssid = target_ap; 492 ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64; 493 wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr, 494 bssid, sm->pmk_r1_name, 495 (u8 *) &sm->ptk, ptk_len, ptk_name); 496 wpa_hexdump_key(MSG_DEBUG, "FT: PTK", 497 (u8 *) &sm->ptk, ptk_len); 498 wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); 499 500 ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, 501 sm->pmk_r1_name, sm->ptk.kck, bssid, 502 ric_ies, ric_ies_len, 503 parse.mdie ? parse.mdie - 2 : NULL); 504 if (ft_ies) { 505 wpa_sm_update_ft_ies(sm, sm->mobility_domain, 506 ft_ies, ft_ies_len); 507 os_free(ft_ies); 508 } 509 510 wpa_sm_mark_authenticated(sm, bssid); 511 ret = wpa_ft_install_ptk(sm, bssid); 512 if (ret) { 513 /* 514 * Some drivers do not support key configuration when we are 515 * not associated with the target AP. Work around this by 516 * trying again after the following reassociation gets 517 * completed. 518 */ 519 wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to " 520 "association - try again after reassociation"); 521 sm->set_ptk_after_assoc = 1; 522 } else 523 sm->set_ptk_after_assoc = 0; 524 525 sm->ft_completed = 1; 526 if (ft_action) { 527 /* 528 * The caller is expected trigger re-association with the 529 * Target AP. 530 */ 531 os_memcpy(sm->bssid, target_ap, ETH_ALEN); 532 } 533 534 return 0; 535} 536 537 538int wpa_ft_is_completed(struct wpa_sm *sm) 539{ 540 if (sm == NULL) 541 return 0; 542 543 if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && 544 sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) 545 return 0; 546 547 return sm->ft_completed; 548} 549 550 551static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, 552 size_t gtk_elem_len) 553{ 554 u8 gtk[32]; 555 int keyidx; 556 enum wpa_alg alg; 557 size_t gtk_len, keylen, rsc_len; 558 559 if (gtk_elem == NULL) { 560 wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE"); 561 return 0; 562 } 563 564 wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp", 565 gtk_elem, gtk_elem_len); 566 567 if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 || 568 gtk_elem_len - 19 > sizeof(gtk)) { 569 wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem " 570 "length %lu", (unsigned long) gtk_elem_len); 571 return -1; 572 } 573 gtk_len = gtk_elem_len - 19; 574 if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) { 575 wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " 576 "decrypt GTK"); 577 return -1; 578 } 579 580 switch (sm->group_cipher) { 581 case WPA_CIPHER_CCMP: 582 keylen = 16; 583 rsc_len = 6; 584 alg = WPA_ALG_CCMP; 585 break; 586 case WPA_CIPHER_TKIP: 587 keylen = 32; 588 rsc_len = 6; 589 alg = WPA_ALG_TKIP; 590 break; 591 case WPA_CIPHER_WEP104: 592 keylen = 13; 593 rsc_len = 0; 594 alg = WPA_ALG_WEP; 595 break; 596 case WPA_CIPHER_WEP40: 597 keylen = 5; 598 rsc_len = 0; 599 alg = WPA_ALG_WEP; 600 break; 601 default: 602 wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d", 603 sm->group_cipher); 604 return -1; 605 } 606 607 if (gtk_len < keylen) { 608 wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE"); 609 return -1; 610 } 611 612 /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */ 613 614 keyidx = WPA_GET_LE16(gtk_elem) & 0x03; 615 616 if (gtk_elem[2] != keylen) { 617 wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d " 618 "negotiated %lu", 619 gtk_elem[2], (unsigned long) keylen); 620 return -1; 621 } 622 623 wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen); 624 if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0, 625 gtk_elem + 3, rsc_len, gtk, keylen) < 0) { 626 wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " 627 "driver."); 628 return -1; 629 } 630 631 return 0; 632} 633 634 635#ifdef CONFIG_IEEE80211W 636static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, 637 size_t igtk_elem_len) 638{ 639 u8 igtk[WPA_IGTK_LEN]; 640 u16 keyidx; 641 642 if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) 643 return 0; 644 645 if (igtk_elem == NULL) { 646 wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE"); 647 return 0; 648 } 649 650 wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp", 651 igtk_elem, igtk_elem_len); 652 653 if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) { 654 wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem " 655 "length %lu", (unsigned long) igtk_elem_len); 656 return -1; 657 } 658 if (igtk_elem[8] != WPA_IGTK_LEN) { 659 wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length " 660 "%d", igtk_elem[8]); 661 return -1; 662 } 663 664 if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) { 665 wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " 666 "decrypt IGTK"); 667 return -1; 668 } 669 670 /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */ 671 672 keyidx = WPA_GET_LE16(igtk_elem); 673 674 wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk, 675 WPA_IGTK_LEN); 676 if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0, 677 igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) { 678 wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the " 679 "driver."); 680 return -1; 681 } 682 683 return 0; 684} 685#endif /* CONFIG_IEEE80211W */ 686 687 688int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, 689 size_t ies_len, const u8 *src_addr) 690{ 691 struct wpa_ft_ies parse; 692 struct rsn_mdie *mdie; 693 struct rsn_ftie *ftie; 694 unsigned int count; 695 u8 mic[16]; 696 697 wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); 698 699 if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && 700 sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { 701 wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " 702 "enabled for this connection"); 703 return -1; 704 } 705 706 if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { 707 wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); 708 return -1; 709 } 710 711 mdie = (struct rsn_mdie *) parse.mdie; 712 if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || 713 os_memcmp(mdie->mobility_domain, sm->mobility_domain, 714 MOBILITY_DOMAIN_ID_LEN) != 0) { 715 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); 716 return -1; 717 } 718 719 ftie = (struct rsn_ftie *) parse.ftie; 720 if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { 721 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); 722 return -1; 723 } 724 725 if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { 726 wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); 727 wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", 728 ftie->snonce, WPA_NONCE_LEN); 729 wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", 730 sm->snonce, WPA_NONCE_LEN); 731 return -1; 732 } 733 734 if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) { 735 wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); 736 wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", 737 ftie->anonce, WPA_NONCE_LEN); 738 wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", 739 sm->anonce, WPA_NONCE_LEN); 740 return -1; 741 } 742 743 if (parse.r0kh_id == NULL) { 744 wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); 745 return -1; 746 } 747 748 if (parse.r0kh_id_len != sm->r0kh_id_len || 749 os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { 750 wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " 751 "the current R0KH-ID"); 752 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", 753 parse.r0kh_id, parse.r0kh_id_len); 754 wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", 755 sm->r0kh_id, sm->r0kh_id_len); 756 return -1; 757 } 758 759 if (parse.r1kh_id == NULL) { 760 wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); 761 return -1; 762 } 763 764 if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { 765 wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " 766 "ReassocResp"); 767 return -1; 768 } 769 770 if (parse.rsn_pmkid == NULL || 771 os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { 772 wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " 773 "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); 774 return -1; 775 } 776 777 count = 3; 778 if (parse.ric) 779 count += ieee802_11_ie_count(parse.ric, parse.ric_len); 780 if (ftie->mic_control[1] != count) { 781 wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " 782 "Control: received %u expected %u", 783 ftie->mic_control[1], count); 784 return -1; 785 } 786 787 if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6, 788 parse.mdie - 2, parse.mdie_len + 2, 789 parse.ftie - 2, parse.ftie_len + 2, 790 parse.rsn - 2, parse.rsn_len + 2, 791 parse.ric, parse.ric_len, 792 mic) < 0) { 793 wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); 794 return -1; 795 } 796 797 if (os_memcmp(mic, ftie->mic, 16) != 0) { 798 wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); 799 wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); 800 wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); 801 return -1; 802 } 803 804 if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) 805 return -1; 806 807#ifdef CONFIG_IEEE80211W 808 if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0) 809 return -1; 810#endif /* CONFIG_IEEE80211W */ 811 812 if (sm->set_ptk_after_assoc) { 813 wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we " 814 "are associated"); 815 if (wpa_ft_install_ptk(sm, src_addr) < 0) 816 return -1; 817 sm->set_ptk_after_assoc = 0; 818 } 819 820 if (parse.ric) { 821 wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response", 822 parse.ric, parse.ric_len); 823 /* TODO: parse response and inform driver about results */ 824 } 825 826 return 0; 827} 828 829 830/** 831 * wpa_ft_start_over_ds - Generate over-the-DS auth request 832 * @sm: Pointer to WPA state machine data from wpa_sm_init() 833 * @target_ap: Target AP Address 834 * @mdie: Mobility Domain IE from the target AP 835 * Returns: 0 on success, -1 on failure 836 */ 837int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, 838 const u8 *mdie) 839{ 840 u8 *ft_ies; 841 size_t ft_ies_len; 842 843 wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR, 844 MAC2STR(target_ap)); 845 846 /* Generate a new SNonce */ 847 if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { 848 wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); 849 return -1; 850 } 851 852 ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, 853 NULL, target_ap, NULL, 0, mdie); 854 if (ft_ies) { 855 sm->over_the_ds_in_progress = 1; 856 os_memcpy(sm->target_ap, target_ap, ETH_ALEN); 857 wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len); 858 os_free(ft_ies); 859 } 860 861 return 0; 862} 863 864#endif /* CONFIG_IEEE80211R */ 865