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