00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00125
00126
00127
00128
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
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
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
00218 WPA_PUT_LE16(pos, 1);
00219 pos += 2;
00220
00221
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
00235 WPA_PUT_LE16(pos, 1);
00236 pos += 2;
00237
00238
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
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
00257 WPA_PUT_LE16(pos, capab);
00258 pos += 2;
00259
00260
00261 WPA_PUT_LE16(pos, 1);
00262 pos += 2;
00263
00264
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
00271 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
00272 pos += RSN_SELECTOR_LEN;
00273 }
00274 #endif
00275
00276 rsnie->len = (pos - (u8 *) rsnie) - 2;
00277
00278
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
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
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
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
00313 os_memcpy(pos, ric_ies, ric_ies_len);
00314 pos += ric_ies_len;
00315 }
00316
00317 if (kck) {
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
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
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;
00455
00456
00457
00458
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
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
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
00689
00690
00691
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
00703
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
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
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
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
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
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
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