$search
00001 /* 00002 * WPA Supplicant - IEEE 802.11r - Fast BSS Transition 00003 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "crypto/aes_wrap.h" 00019 #include "common/ieee802_11_defs.h" 00020 #include "common/ieee802_11_common.h" 00021 #include "wpa.h" 00022 #include "wpa_i.h" 00023 #include "wpa_ie.h" 00024 00025 #ifdef CONFIG_IEEE80211R 00026 00027 struct wpa_ft_ies { 00028 const u8 *mdie; 00029 size_t mdie_len; 00030 const u8 *ftie; 00031 size_t ftie_len; 00032 const u8 *r1kh_id; 00033 const u8 *gtk; 00034 size_t gtk_len; 00035 const u8 *r0kh_id; 00036 size_t r0kh_id_len; 00037 const u8 *rsn; 00038 size_t rsn_len; 00039 const u8 *rsn_pmkid; 00040 const u8 *tie; 00041 size_t tie_len; 00042 const u8 *igtk; 00043 size_t igtk_len; 00044 const u8 *ric; 00045 size_t ric_len; 00046 }; 00047 00048 static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, 00049 struct wpa_ft_ies *parse); 00050 00051 00052 int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, 00053 const struct wpa_eapol_key *key, 00054 struct wpa_ptk *ptk, size_t ptk_len) 00055 { 00056 u8 ptk_name[WPA_PMK_NAME_LEN]; 00057 const u8 *anonce = key->key_nonce; 00058 00059 if (sm->xxkey_len == 0) { 00060 wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " 00061 "derivation"); 00062 return -1; 00063 } 00064 00065 wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid, 00066 sm->ssid_len, sm->mobility_domain, 00067 sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, 00068 sm->pmk_r0, sm->pmk_r0_name); 00069 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN); 00070 wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", 00071 sm->pmk_r0_name, WPA_PMK_NAME_LEN); 00072 wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, 00073 sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); 00074 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); 00075 wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, 00076 WPA_PMK_NAME_LEN); 00077 wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, 00078 sm->bssid, sm->pmk_r1_name, 00079 (u8 *) ptk, ptk_len, ptk_name); 00080 wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); 00081 wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); 00082 00083 return 0; 00084 } 00085 00086 00094 int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) 00095 { 00096 struct wpa_ft_ies ft; 00097 00098 if (sm == NULL) 00099 return 0; 00100 00101 if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0) 00102 return -1; 00103 00104 if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) 00105 return -1; 00106 00107 if (ft.mdie) { 00108 wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", 00109 ft.mdie, MOBILITY_DOMAIN_ID_LEN); 00110 os_memcpy(sm->mobility_domain, ft.mdie, 00111 MOBILITY_DOMAIN_ID_LEN); 00112 sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; 00113 wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", 00114 sm->mdie_ft_capab); 00115 } else 00116 os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); 00117 00118 if (ft.r0kh_id) { 00119 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", 00120 ft.r0kh_id, ft.r0kh_id_len); 00121 os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len); 00122 sm->r0kh_id_len = ft.r0kh_id_len; 00123 } else { 00124 /* FIX: When should R0KH-ID be cleared? We need to keep the 00125 * old R0KH-ID in order to be able to use this during FT. */ 00126 /* 00127 * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN); 00128 * sm->r0kh_id_len = 0; 00129 */ 00130 } 00131 00132 if (ft.r1kh_id) { 00133 wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", 00134 ft.r1kh_id, FT_R1KH_ID_LEN); 00135 os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN); 00136 } else 00137 os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); 00138 00139 os_free(sm->assoc_resp_ies); 00140 sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2); 00141 if (sm->assoc_resp_ies) { 00142 u8 *pos = sm->assoc_resp_ies; 00143 if (ft.mdie) { 00144 os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); 00145 pos += ft.mdie_len + 2; 00146 } 00147 if (ft.ftie) { 00148 os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2); 00149 pos += ft.ftie_len + 2; 00150 } 00151 sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies; 00152 wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from " 00153 "(Re)Association Response", 00154 sm->assoc_resp_ies, sm->assoc_resp_ies_len); 00155 } 00156 00157 return 0; 00158 } 00159 00160 00176 static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, 00177 const u8 *anonce, const u8 *pmk_name, 00178 const u8 *kck, const u8 *target_ap, 00179 const u8 *ric_ies, size_t ric_ies_len, 00180 const u8 *ap_mdie) 00181 { 00182 size_t buf_len; 00183 u8 *buf, *pos, *ftie_len, *ftie_pos; 00184 struct rsn_mdie *mdie; 00185 struct rsn_ftie *ftie; 00186 struct rsn_ie_hdr *rsnie; 00187 u16 capab; 00188 00189 sm->ft_completed = 0; 00190 00191 buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + 00192 2 + sm->r0kh_id_len + ric_ies_len + 100; 00193 buf = os_zalloc(buf_len); 00194 if (buf == NULL) 00195 return NULL; 00196 pos = buf; 00197 00198 /* RSNIE[PMKR0Name/PMKR1Name] */ 00199 rsnie = (struct rsn_ie_hdr *) pos; 00200 rsnie->elem_id = WLAN_EID_RSN; 00201 WPA_PUT_LE16(rsnie->version, RSN_VERSION); 00202 pos = (u8 *) (rsnie + 1); 00203 00204 /* Group Suite Selector */ 00205 if (sm->group_cipher == WPA_CIPHER_CCMP) 00206 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 00207 else if (sm->group_cipher == WPA_CIPHER_TKIP) 00208 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 00209 else { 00210 wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)", 00211 sm->group_cipher); 00212 os_free(buf); 00213 return NULL; 00214 } 00215 pos += RSN_SELECTOR_LEN; 00216 00217 /* Pairwise Suite Count */ 00218 WPA_PUT_LE16(pos, 1); 00219 pos += 2; 00220 00221 /* Pairwise Suite List */ 00222 if (sm->pairwise_cipher == WPA_CIPHER_CCMP) 00223 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 00224 else if (sm->pairwise_cipher == WPA_CIPHER_TKIP) 00225 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 00226 else { 00227 wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)", 00228 sm->pairwise_cipher); 00229 os_free(buf); 00230 return NULL; 00231 } 00232 pos += RSN_SELECTOR_LEN; 00233 00234 /* Authenticated Key Management Suite Count */ 00235 WPA_PUT_LE16(pos, 1); 00236 pos += 2; 00237 00238 /* Authenticated Key Management Suite List */ 00239 if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) 00240 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 00241 else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) 00242 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 00243 else { 00244 wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", 00245 sm->key_mgmt); 00246 os_free(buf); 00247 return NULL; 00248 } 00249 pos += RSN_SELECTOR_LEN; 00250 00251 /* RSN Capabilities */ 00252 capab = 0; 00253 #ifdef CONFIG_IEEE80211W 00254 if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) 00255 capab |= WPA_CAPABILITY_MFPC; 00256 #endif /* CONFIG_IEEE80211W */ 00257 WPA_PUT_LE16(pos, capab); 00258 pos += 2; 00259 00260 /* PMKID Count */ 00261 WPA_PUT_LE16(pos, 1); 00262 pos += 2; 00263 00264 /* PMKID List [PMKR0Name/PMKR1Name] */ 00265 os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN); 00266 pos += WPA_PMK_NAME_LEN; 00267 00268 #ifdef CONFIG_IEEE80211W 00269 if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { 00270 /* Management Group Cipher Suite */ 00271 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 00272 pos += RSN_SELECTOR_LEN; 00273 } 00274 #endif /* CONFIG_IEEE80211W */ 00275 00276 rsnie->len = (pos - (u8 *) rsnie) - 2; 00277 00278 /* MDIE */ 00279 *pos++ = WLAN_EID_MOBILITY_DOMAIN; 00280 *pos++ = sizeof(*mdie); 00281 mdie = (struct rsn_mdie *) pos; 00282 pos += sizeof(*mdie); 00283 os_memcpy(mdie->mobility_domain, sm->mobility_domain, 00284 MOBILITY_DOMAIN_ID_LEN); 00285 mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] : 00286 sm->mdie_ft_capab; 00287 00288 /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */ 00289 ftie_pos = pos; 00290 *pos++ = WLAN_EID_FAST_BSS_TRANSITION; 00291 ftie_len = pos++; 00292 ftie = (struct rsn_ftie *) pos; 00293 pos += sizeof(*ftie); 00294 os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); 00295 if (anonce) 00296 os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); 00297 if (kck) { 00298 /* R1KH-ID sub-element in third FT message */ 00299 *pos++ = FTIE_SUBELEM_R1KH_ID; 00300 *pos++ = FT_R1KH_ID_LEN; 00301 os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN); 00302 pos += FT_R1KH_ID_LEN; 00303 } 00304 /* R0KH-ID sub-element */ 00305 *pos++ = FTIE_SUBELEM_R0KH_ID; 00306 *pos++ = sm->r0kh_id_len; 00307 os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len); 00308 pos += sm->r0kh_id_len; 00309 *ftie_len = pos - ftie_len - 1; 00310 00311 if (ric_ies) { 00312 /* RIC Request */ 00313 os_memcpy(pos, ric_ies, ric_ies_len); 00314 pos += ric_ies_len; 00315 } 00316 00317 if (kck) { 00318 /* 00319 * IEEE Std 802.11r-2008, 11A.8.4 00320 * MIC shall be calculated over: 00321 * non-AP STA MAC address 00322 * Target AP MAC address 00323 * Transaction seq number (5 for ReassocReq, 3 otherwise) 00324 * RSN IE 00325 * MDIE 00326 * FTIE (with MIC field set to 0) 00327 * RIC-Request (if present) 00328 */ 00329 /* Information element count */ 00330 ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies, 00331 ric_ies_len); 00332 if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5, 00333 ((u8 *) mdie) - 2, 2 + sizeof(*mdie), 00334 ftie_pos, 2 + *ftie_len, 00335 (u8 *) rsnie, 2 + rsnie->len, ric_ies, 00336 ric_ies_len, ftie->mic) < 0) { 00337 wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); 00338 os_free(buf); 00339 return NULL; 00340 } 00341 } 00342 00343 *len = pos - buf; 00344 00345 return buf; 00346 } 00347 00348 00349 static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, 00350 struct wpa_ft_ies *parse) 00351 { 00352 const u8 *end, *pos; 00353 00354 parse->ftie = ie; 00355 parse->ftie_len = ie_len; 00356 00357 pos = ie + sizeof(struct rsn_ftie); 00358 end = ie + ie_len; 00359 00360 while (pos + 2 <= end && pos + 2 + pos[1] <= end) { 00361 switch (pos[0]) { 00362 case FTIE_SUBELEM_R1KH_ID: 00363 if (pos[1] != FT_R1KH_ID_LEN) { 00364 wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " 00365 "length in FTIE: %d", pos[1]); 00366 return -1; 00367 } 00368 parse->r1kh_id = pos + 2; 00369 break; 00370 case FTIE_SUBELEM_GTK: 00371 parse->gtk = pos + 2; 00372 parse->gtk_len = pos[1]; 00373 break; 00374 case FTIE_SUBELEM_R0KH_ID: 00375 if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { 00376 wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " 00377 "length in FTIE: %d", pos[1]); 00378 return -1; 00379 } 00380 parse->r0kh_id = pos + 2; 00381 parse->r0kh_id_len = pos[1]; 00382 break; 00383 #ifdef CONFIG_IEEE80211W 00384 case FTIE_SUBELEM_IGTK: 00385 parse->igtk = pos + 2; 00386 parse->igtk_len = pos[1]; 00387 break; 00388 #endif /* CONFIG_IEEE80211W */ 00389 } 00390 00391 pos += 2 + pos[1]; 00392 } 00393 00394 return 0; 00395 } 00396 00397 00398 static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, 00399 struct wpa_ft_ies *parse) 00400 { 00401 const u8 *end, *pos; 00402 struct wpa_ie_data data; 00403 int ret; 00404 const struct rsn_ftie *ftie; 00405 int prot_ie_count = 0; 00406 00407 os_memset(parse, 0, sizeof(*parse)); 00408 if (ies == NULL) 00409 return 0; 00410 00411 pos = ies; 00412 end = ies + ies_len; 00413 while (pos + 2 <= end && pos + 2 + pos[1] <= end) { 00414 switch (pos[0]) { 00415 case WLAN_EID_RSN: 00416 parse->rsn = pos + 2; 00417 parse->rsn_len = pos[1]; 00418 ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, 00419 parse->rsn_len + 2, 00420 &data); 00421 if (ret < 0) { 00422 wpa_printf(MSG_DEBUG, "FT: Failed to parse " 00423 "RSN IE: %d", ret); 00424 return -1; 00425 } 00426 if (data.num_pmkid == 1 && data.pmkid) 00427 parse->rsn_pmkid = data.pmkid; 00428 break; 00429 case WLAN_EID_MOBILITY_DOMAIN: 00430 parse->mdie = pos + 2; 00431 parse->mdie_len = pos[1]; 00432 break; 00433 case WLAN_EID_FAST_BSS_TRANSITION: 00434 if (pos[1] < sizeof(*ftie)) 00435 return -1; 00436 ftie = (const struct rsn_ftie *) (pos + 2); 00437 prot_ie_count = ftie->mic_control[1]; 00438 if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) 00439 return -1; 00440 break; 00441 case WLAN_EID_TIMEOUT_INTERVAL: 00442 parse->tie = pos + 2; 00443 parse->tie_len = pos[1]; 00444 break; 00445 case WLAN_EID_RIC_DATA: 00446 if (parse->ric == NULL) 00447 parse->ric = pos; 00448 } 00449 00450 pos += 2 + pos[1]; 00451 } 00452 00453 if (prot_ie_count == 0) 00454 return 0; /* no MIC */ 00455 00456 /* 00457 * Check that the protected IE count matches with IEs included in the 00458 * frame. 00459 */ 00460 if (parse->rsn) 00461 prot_ie_count--; 00462 if (parse->mdie) 00463 prot_ie_count--; 00464 if (parse->ftie) 00465 prot_ie_count--; 00466 if (parse->tie) 00467 prot_ie_count--; 00468 if (prot_ie_count < 0) { 00469 wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " 00470 "the protected IE count"); 00471 return -1; 00472 } 00473 00474 if (prot_ie_count == 0 && parse->ric) { 00475 wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " 00476 "included in protected IE count"); 00477 return -1; 00478 } 00479 00480 /* Determine the end of the RIC IE(s) */ 00481 pos = parse->ric; 00482 while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && 00483 prot_ie_count) { 00484 prot_ie_count--; 00485 pos += 2 + pos[1]; 00486 } 00487 parse->ric_len = pos - parse->ric; 00488 if (prot_ie_count) { 00489 wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " 00490 "frame", (int) prot_ie_count); 00491 return -1; 00492 } 00493 00494 return 0; 00495 } 00496 00497 00498 static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) 00499 { 00500 int keylen; 00501 enum wpa_alg alg; 00502 u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 }; 00503 00504 wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver."); 00505 00506 switch (sm->pairwise_cipher) { 00507 case WPA_CIPHER_CCMP: 00508 alg = WPA_ALG_CCMP; 00509 keylen = 16; 00510 break; 00511 case WPA_CIPHER_TKIP: 00512 alg = WPA_ALG_TKIP; 00513 keylen = 32; 00514 break; 00515 default: 00516 wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d", 00517 sm->pairwise_cipher); 00518 return -1; 00519 } 00520 00521 if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, 00522 sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) { 00523 wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); 00524 return -1; 00525 } 00526 00527 return 0; 00528 } 00529 00530 00537 int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) 00538 { 00539 u8 *ft_ies; 00540 size_t ft_ies_len; 00541 00542 /* Generate a new SNonce */ 00543 if (os_get_random(sm->snonce, WPA_NONCE_LEN)) { 00544 wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); 00545 return -1; 00546 } 00547 00548 ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, 00549 NULL, sm->bssid, NULL, 0, mdie); 00550 if (ft_ies) { 00551 wpa_sm_update_ft_ies(sm, sm->mobility_domain, 00552 ft_ies, ft_ies_len); 00553 os_free(ft_ies); 00554 } 00555 00556 return 0; 00557 } 00558 00559 00560 int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, 00561 int ft_action, const u8 *target_ap, 00562 const u8 *ric_ies, size_t ric_ies_len) 00563 { 00564 u8 *ft_ies; 00565 size_t ft_ies_len, ptk_len; 00566 struct wpa_ft_ies parse; 00567 struct rsn_mdie *mdie; 00568 struct rsn_ftie *ftie; 00569 u8 ptk_name[WPA_PMK_NAME_LEN]; 00570 int ret; 00571 const u8 *bssid; 00572 00573 wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); 00574 wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); 00575 00576 if (ft_action) { 00577 if (!sm->over_the_ds_in_progress) { 00578 wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " 00579 "- drop FT Action Response"); 00580 return -1; 00581 } 00582 00583 if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) { 00584 wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " 00585 "with this Target AP - drop FT Action " 00586 "Response"); 00587 return -1; 00588 } 00589 } 00590 00591 if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && 00592 sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { 00593 wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " 00594 "enabled for this connection"); 00595 return -1; 00596 } 00597 00598 if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { 00599 wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); 00600 return -1; 00601 } 00602 00603 mdie = (struct rsn_mdie *) parse.mdie; 00604 if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || 00605 os_memcmp(mdie->mobility_domain, sm->mobility_domain, 00606 MOBILITY_DOMAIN_ID_LEN) != 0) { 00607 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); 00608 return -1; 00609 } 00610 00611 ftie = (struct rsn_ftie *) parse.ftie; 00612 if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { 00613 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); 00614 return -1; 00615 } 00616 00617 if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { 00618 wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); 00619 wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", 00620 ftie->snonce, WPA_NONCE_LEN); 00621 wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", 00622 sm->snonce, WPA_NONCE_LEN); 00623 return -1; 00624 } 00625 00626 if (parse.r0kh_id == NULL) { 00627 wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); 00628 return -1; 00629 } 00630 00631 if (parse.r0kh_id_len != sm->r0kh_id_len || 00632 os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { 00633 wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " 00634 "the current R0KH-ID"); 00635 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", 00636 parse.r0kh_id, parse.r0kh_id_len); 00637 wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", 00638 sm->r0kh_id, sm->r0kh_id_len); 00639 return -1; 00640 } 00641 00642 if (parse.r1kh_id == NULL) { 00643 wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); 00644 return -1; 00645 } 00646 00647 if (parse.rsn_pmkid == NULL || 00648 os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) { 00649 wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in " 00650 "RSNIE"); 00651 return -1; 00652 } 00653 00654 os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN); 00655 wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); 00656 wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); 00657 wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN); 00658 os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN); 00659 wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, 00660 sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); 00661 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); 00662 wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", 00663 sm->pmk_r1_name, WPA_PMK_NAME_LEN); 00664 00665 bssid = target_ap; 00666 ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64; 00667 wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr, 00668 bssid, sm->pmk_r1_name, 00669 (u8 *) &sm->ptk, ptk_len, ptk_name); 00670 wpa_hexdump_key(MSG_DEBUG, "FT: PTK", 00671 (u8 *) &sm->ptk, ptk_len); 00672 wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); 00673 00674 ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, 00675 sm->pmk_r1_name, sm->ptk.kck, bssid, 00676 ric_ies, ric_ies_len, 00677 parse.mdie ? parse.mdie - 2 : NULL); 00678 if (ft_ies) { 00679 wpa_sm_update_ft_ies(sm, sm->mobility_domain, 00680 ft_ies, ft_ies_len); 00681 os_free(ft_ies); 00682 } 00683 00684 wpa_sm_mark_authenticated(sm, bssid); 00685 ret = wpa_ft_install_ptk(sm, bssid); 00686 if (ret) { 00687 /* 00688 * Some drivers do not support key configuration when we are 00689 * not associated with the target AP. Work around this by 00690 * trying again after the following reassociation gets 00691 * completed. 00692 */ 00693 wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to " 00694 "association - try again after reassociation"); 00695 sm->set_ptk_after_assoc = 1; 00696 } else 00697 sm->set_ptk_after_assoc = 0; 00698 00699 sm->ft_completed = 1; 00700 if (ft_action) { 00701 /* 00702 * The caller is expected trigger re-association with the 00703 * Target AP. 00704 */ 00705 os_memcpy(sm->bssid, target_ap, ETH_ALEN); 00706 } 00707 00708 return 0; 00709 } 00710 00711 00712 int wpa_ft_is_completed(struct wpa_sm *sm) 00713 { 00714 if (sm == NULL) 00715 return 0; 00716 00717 if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && 00718 sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) 00719 return 0; 00720 00721 return sm->ft_completed; 00722 } 00723 00724 00725 static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, 00726 size_t gtk_elem_len) 00727 { 00728 u8 gtk[32]; 00729 int keyidx; 00730 enum wpa_alg alg; 00731 size_t gtk_len, keylen, rsc_len; 00732 00733 if (gtk_elem == NULL) { 00734 wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE"); 00735 return 0; 00736 } 00737 00738 wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp", 00739 gtk_elem, gtk_elem_len); 00740 00741 if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 || 00742 gtk_elem_len - 19 > sizeof(gtk)) { 00743 wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem " 00744 "length %lu", (unsigned long) gtk_elem_len); 00745 return -1; 00746 } 00747 gtk_len = gtk_elem_len - 19; 00748 if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) { 00749 wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " 00750 "decrypt GTK"); 00751 return -1; 00752 } 00753 00754 switch (sm->group_cipher) { 00755 case WPA_CIPHER_CCMP: 00756 keylen = 16; 00757 rsc_len = 6; 00758 alg = WPA_ALG_CCMP; 00759 break; 00760 case WPA_CIPHER_TKIP: 00761 keylen = 32; 00762 rsc_len = 6; 00763 alg = WPA_ALG_TKIP; 00764 break; 00765 case WPA_CIPHER_WEP104: 00766 keylen = 13; 00767 rsc_len = 0; 00768 alg = WPA_ALG_WEP; 00769 break; 00770 case WPA_CIPHER_WEP40: 00771 keylen = 5; 00772 rsc_len = 0; 00773 alg = WPA_ALG_WEP; 00774 break; 00775 default: 00776 wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d", 00777 sm->group_cipher); 00778 return -1; 00779 } 00780 00781 if (gtk_len < keylen) { 00782 wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE"); 00783 return -1; 00784 } 00785 00786 /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */ 00787 00788 keyidx = WPA_GET_LE16(gtk_elem) & 0x03; 00789 00790 if (gtk_elem[2] != keylen) { 00791 wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d " 00792 "negotiated %lu", 00793 gtk_elem[2], (unsigned long) keylen); 00794 return -1; 00795 } 00796 00797 wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen); 00798 if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff", 00799 keyidx, 0, gtk_elem + 3, rsc_len, gtk, keylen) < 00800 0) { 00801 wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " 00802 "driver."); 00803 return -1; 00804 } 00805 00806 return 0; 00807 } 00808 00809 00810 #ifdef CONFIG_IEEE80211W 00811 static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, 00812 size_t igtk_elem_len) 00813 { 00814 u8 igtk[WPA_IGTK_LEN]; 00815 u16 keyidx; 00816 00817 if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) 00818 return 0; 00819 00820 if (igtk_elem == NULL) { 00821 wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE"); 00822 return 0; 00823 } 00824 00825 wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp", 00826 igtk_elem, igtk_elem_len); 00827 00828 if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) { 00829 wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem " 00830 "length %lu", (unsigned long) igtk_elem_len); 00831 return -1; 00832 } 00833 if (igtk_elem[8] != WPA_IGTK_LEN) { 00834 wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length " 00835 "%d", igtk_elem[8]); 00836 return -1; 00837 } 00838 00839 if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) { 00840 wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " 00841 "decrypt IGTK"); 00842 return -1; 00843 } 00844 00845 /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */ 00846 00847 keyidx = WPA_GET_LE16(igtk_elem); 00848 00849 wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk, 00850 WPA_IGTK_LEN); 00851 if (wpa_sm_set_key(sm, WPA_ALG_IGTK, (u8 *) "\xff\xff\xff\xff\xff\xff", 00852 keyidx, 0, igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 00853 0) { 00854 wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the " 00855 "driver."); 00856 return -1; 00857 } 00858 00859 return 0; 00860 } 00861 #endif /* CONFIG_IEEE80211W */ 00862 00863 00864 int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, 00865 size_t ies_len, const u8 *src_addr) 00866 { 00867 struct wpa_ft_ies parse; 00868 struct rsn_mdie *mdie; 00869 struct rsn_ftie *ftie; 00870 unsigned int count; 00871 u8 mic[16]; 00872 00873 wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); 00874 00875 if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && 00876 sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { 00877 wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " 00878 "enabled for this connection"); 00879 return -1; 00880 } 00881 00882 if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { 00883 wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); 00884 return -1; 00885 } 00886 00887 mdie = (struct rsn_mdie *) parse.mdie; 00888 if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || 00889 os_memcmp(mdie->mobility_domain, sm->mobility_domain, 00890 MOBILITY_DOMAIN_ID_LEN) != 0) { 00891 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); 00892 return -1; 00893 } 00894 00895 ftie = (struct rsn_ftie *) parse.ftie; 00896 if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { 00897 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); 00898 return -1; 00899 } 00900 00901 if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { 00902 wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); 00903 wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", 00904 ftie->snonce, WPA_NONCE_LEN); 00905 wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", 00906 sm->snonce, WPA_NONCE_LEN); 00907 return -1; 00908 } 00909 00910 if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) { 00911 wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); 00912 wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", 00913 ftie->anonce, WPA_NONCE_LEN); 00914 wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", 00915 sm->anonce, WPA_NONCE_LEN); 00916 return -1; 00917 } 00918 00919 if (parse.r0kh_id == NULL) { 00920 wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); 00921 return -1; 00922 } 00923 00924 if (parse.r0kh_id_len != sm->r0kh_id_len || 00925 os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { 00926 wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " 00927 "the current R0KH-ID"); 00928 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", 00929 parse.r0kh_id, parse.r0kh_id_len); 00930 wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", 00931 sm->r0kh_id, sm->r0kh_id_len); 00932 return -1; 00933 } 00934 00935 if (parse.r1kh_id == NULL) { 00936 wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); 00937 return -1; 00938 } 00939 00940 if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { 00941 wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " 00942 "ReassocResp"); 00943 return -1; 00944 } 00945 00946 if (parse.rsn_pmkid == NULL || 00947 os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { 00948 wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " 00949 "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); 00950 return -1; 00951 } 00952 00953 count = 3; 00954 if (parse.tie) 00955 count++; 00956 if (ftie->mic_control[1] != count) { 00957 wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " 00958 "Control: received %u expected %u", 00959 ftie->mic_control[1], count); 00960 return -1; 00961 } 00962 00963 if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6, 00964 parse.mdie - 2, parse.mdie_len + 2, 00965 parse.ftie - 2, parse.ftie_len + 2, 00966 parse.rsn - 2, parse.rsn_len + 2, 00967 parse.ric, parse.ric_len, 00968 mic) < 0) { 00969 wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); 00970 return -1; 00971 } 00972 00973 if (os_memcmp(mic, ftie->mic, 16) != 0) { 00974 wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); 00975 wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); 00976 wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); 00977 return -1; 00978 } 00979 00980 if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) 00981 return -1; 00982 00983 #ifdef CONFIG_IEEE80211W 00984 if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0) 00985 return -1; 00986 #endif /* CONFIG_IEEE80211W */ 00987 00988 if (sm->set_ptk_after_assoc) { 00989 wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we " 00990 "are associated"); 00991 if (wpa_ft_install_ptk(sm, src_addr) < 0) 00992 return -1; 00993 sm->set_ptk_after_assoc = 0; 00994 } 00995 00996 if (parse.ric) { 00997 wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response", 00998 parse.ric, parse.ric_len); 00999 /* TODO: parse response and inform driver about results */ 01000 } 01001 01002 return 0; 01003 } 01004 01005 01013 int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, 01014 const u8 *mdie) 01015 { 01016 u8 *ft_ies; 01017 size_t ft_ies_len; 01018 01019 wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR, 01020 MAC2STR(target_ap)); 01021 01022 /* Generate a new SNonce */ 01023 if (os_get_random(sm->snonce, WPA_NONCE_LEN)) { 01024 wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); 01025 return -1; 01026 } 01027 01028 ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, 01029 NULL, target_ap, NULL, 0, mdie); 01030 if (ft_ies) { 01031 sm->over_the_ds_in_progress = 1; 01032 os_memcpy(sm->target_ap, target_ap, ETH_ALEN); 01033 wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len); 01034 os_free(ft_ies); 01035 } 01036 01037 return 0; 01038 } 01039 01040 #endif /* CONFIG_IEEE80211R */