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