$search
00001 /* 00002 * WPA/RSN - Shared functions for supplicant and authenticator 00003 * Copyright (c) 2002-2008, 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/md5.h" 00019 #include "crypto/sha1.h" 00020 #include "crypto/sha256.h" 00021 #include "crypto/aes_wrap.h" 00022 #include "crypto/crypto.h" 00023 #include "ieee802_11_defs.h" 00024 #include "defs.h" 00025 #include "wpa_common.h" 00026 00027 00046 int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, 00047 u8 *mic) 00048 { 00049 u8 hash[SHA1_MAC_LEN]; 00050 00051 switch (ver) { 00052 case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: 00053 return hmac_md5(key, 16, buf, len, mic); 00054 case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: 00055 if (hmac_sha1(key, 16, buf, len, hash)) 00056 return -1; 00057 os_memcpy(mic, hash, MD5_MAC_LEN); 00058 break; 00059 #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) 00060 case WPA_KEY_INFO_TYPE_AES_128_CMAC: 00061 return omac1_aes_128(key, buf, len, mic); 00062 #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ 00063 default: 00064 return -1; 00065 } 00066 00067 return 0; 00068 } 00069 00070 00093 void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, 00094 const u8 *addr1, const u8 *addr2, 00095 const u8 *nonce1, const u8 *nonce2, 00096 u8 *ptk, size_t ptk_len, int use_sha256) 00097 { 00098 u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; 00099 00100 if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { 00101 os_memcpy(data, addr1, ETH_ALEN); 00102 os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); 00103 } else { 00104 os_memcpy(data, addr2, ETH_ALEN); 00105 os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); 00106 } 00107 00108 if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { 00109 os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); 00110 os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, 00111 WPA_NONCE_LEN); 00112 } else { 00113 os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); 00114 os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, 00115 WPA_NONCE_LEN); 00116 } 00117 00118 #ifdef CONFIG_IEEE80211W 00119 if (use_sha256) 00120 sha256_prf(pmk, pmk_len, label, data, sizeof(data), 00121 ptk, ptk_len); 00122 else 00123 #endif /* CONFIG_IEEE80211W */ 00124 sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, 00125 ptk_len); 00126 00127 wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, 00128 MAC2STR(addr1), MAC2STR(addr2)); 00129 wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); 00130 wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); 00131 } 00132 00133 00134 #ifdef CONFIG_IEEE80211R 00135 int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, 00136 u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, 00137 const u8 *ftie, size_t ftie_len, 00138 const u8 *rsnie, size_t rsnie_len, 00139 const u8 *ric, size_t ric_len, u8 *mic) 00140 { 00141 u8 *buf, *pos; 00142 size_t buf_len; 00143 00144 buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; 00145 buf = os_malloc(buf_len); 00146 if (buf == NULL) 00147 return -1; 00148 00149 pos = buf; 00150 os_memcpy(pos, sta_addr, ETH_ALEN); 00151 pos += ETH_ALEN; 00152 os_memcpy(pos, ap_addr, ETH_ALEN); 00153 pos += ETH_ALEN; 00154 *pos++ = transaction_seqnum; 00155 if (rsnie) { 00156 os_memcpy(pos, rsnie, rsnie_len); 00157 pos += rsnie_len; 00158 } 00159 if (mdie) { 00160 os_memcpy(pos, mdie, mdie_len); 00161 pos += mdie_len; 00162 } 00163 if (ftie) { 00164 struct rsn_ftie *_ftie; 00165 os_memcpy(pos, ftie, ftie_len); 00166 if (ftie_len < 2 + sizeof(*_ftie)) { 00167 os_free(buf); 00168 return -1; 00169 } 00170 _ftie = (struct rsn_ftie *) (pos + 2); 00171 os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); 00172 pos += ftie_len; 00173 } 00174 if (ric) { 00175 os_memcpy(pos, ric, ric_len); 00176 pos += ric_len; 00177 } 00178 00179 wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); 00180 if (omac1_aes_128(kck, buf, pos - buf, mic)) { 00181 os_free(buf); 00182 return -1; 00183 } 00184 00185 os_free(buf); 00186 00187 return 0; 00188 } 00189 #endif /* CONFIG_IEEE80211R */ 00190 00191 00192 #ifndef CONFIG_NO_WPA2 00193 static int rsn_selector_to_bitfield(const u8 *s) 00194 { 00195 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) 00196 return WPA_CIPHER_NONE; 00197 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) 00198 return WPA_CIPHER_WEP40; 00199 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) 00200 return WPA_CIPHER_TKIP; 00201 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) 00202 return WPA_CIPHER_CCMP; 00203 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) 00204 return WPA_CIPHER_WEP104; 00205 #ifdef CONFIG_IEEE80211W 00206 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) 00207 return WPA_CIPHER_AES_128_CMAC; 00208 #endif /* CONFIG_IEEE80211W */ 00209 return 0; 00210 } 00211 00212 00213 static int rsn_key_mgmt_to_bitfield(const u8 *s) 00214 { 00215 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) 00216 return WPA_KEY_MGMT_IEEE8021X; 00217 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) 00218 return WPA_KEY_MGMT_PSK; 00219 #ifdef CONFIG_IEEE80211R 00220 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) 00221 return WPA_KEY_MGMT_FT_IEEE8021X; 00222 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) 00223 return WPA_KEY_MGMT_FT_PSK; 00224 #endif /* CONFIG_IEEE80211R */ 00225 #ifdef CONFIG_IEEE80211W 00226 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) 00227 return WPA_KEY_MGMT_IEEE8021X_SHA256; 00228 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) 00229 return WPA_KEY_MGMT_PSK_SHA256; 00230 #endif /* CONFIG_IEEE80211W */ 00231 return 0; 00232 } 00233 #endif /* CONFIG_NO_WPA2 */ 00234 00235 00243 int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, 00244 struct wpa_ie_data *data) 00245 { 00246 #ifndef CONFIG_NO_WPA2 00247 const struct rsn_ie_hdr *hdr; 00248 const u8 *pos; 00249 int left; 00250 int i, count; 00251 00252 os_memset(data, 0, sizeof(*data)); 00253 data->proto = WPA_PROTO_RSN; 00254 data->pairwise_cipher = WPA_CIPHER_CCMP; 00255 data->group_cipher = WPA_CIPHER_CCMP; 00256 data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 00257 data->capabilities = 0; 00258 data->pmkid = NULL; 00259 data->num_pmkid = 0; 00260 #ifdef CONFIG_IEEE80211W 00261 data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; 00262 #else /* CONFIG_IEEE80211W */ 00263 data->mgmt_group_cipher = 0; 00264 #endif /* CONFIG_IEEE80211W */ 00265 00266 if (rsn_ie_len == 0) { 00267 /* No RSN IE - fail silently */ 00268 return -1; 00269 } 00270 00271 if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { 00272 wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 00273 __func__, (unsigned long) rsn_ie_len); 00274 return -1; 00275 } 00276 00277 hdr = (const struct rsn_ie_hdr *) rsn_ie; 00278 00279 if (hdr->elem_id != WLAN_EID_RSN || 00280 hdr->len != rsn_ie_len - 2 || 00281 WPA_GET_LE16(hdr->version) != RSN_VERSION) { 00282 wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 00283 __func__); 00284 return -2; 00285 } 00286 00287 pos = (const u8 *) (hdr + 1); 00288 left = rsn_ie_len - sizeof(*hdr); 00289 00290 if (left >= RSN_SELECTOR_LEN) { 00291 data->group_cipher = rsn_selector_to_bitfield(pos); 00292 #ifdef CONFIG_IEEE80211W 00293 if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { 00294 wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " 00295 "cipher", __func__); 00296 return -1; 00297 } 00298 #endif /* CONFIG_IEEE80211W */ 00299 pos += RSN_SELECTOR_LEN; 00300 left -= RSN_SELECTOR_LEN; 00301 } else if (left > 0) { 00302 wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 00303 __func__, left); 00304 return -3; 00305 } 00306 00307 if (left >= 2) { 00308 data->pairwise_cipher = 0; 00309 count = WPA_GET_LE16(pos); 00310 pos += 2; 00311 left -= 2; 00312 if (count == 0 || left < count * RSN_SELECTOR_LEN) { 00313 wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 00314 "count %u left %u", __func__, count, left); 00315 return -4; 00316 } 00317 for (i = 0; i < count; i++) { 00318 data->pairwise_cipher |= rsn_selector_to_bitfield(pos); 00319 pos += RSN_SELECTOR_LEN; 00320 left -= RSN_SELECTOR_LEN; 00321 } 00322 #ifdef CONFIG_IEEE80211W 00323 if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { 00324 wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " 00325 "pairwise cipher", __func__); 00326 return -1; 00327 } 00328 #endif /* CONFIG_IEEE80211W */ 00329 } else if (left == 1) { 00330 wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 00331 __func__); 00332 return -5; 00333 } 00334 00335 if (left >= 2) { 00336 data->key_mgmt = 0; 00337 count = WPA_GET_LE16(pos); 00338 pos += 2; 00339 left -= 2; 00340 if (count == 0 || left < count * RSN_SELECTOR_LEN) { 00341 wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 00342 "count %u left %u", __func__, count, left); 00343 return -6; 00344 } 00345 for (i = 0; i < count; i++) { 00346 data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); 00347 pos += RSN_SELECTOR_LEN; 00348 left -= RSN_SELECTOR_LEN; 00349 } 00350 } else if (left == 1) { 00351 wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 00352 __func__); 00353 return -7; 00354 } 00355 00356 if (left >= 2) { 00357 data->capabilities = WPA_GET_LE16(pos); 00358 pos += 2; 00359 left -= 2; 00360 } 00361 00362 if (left >= 2) { 00363 data->num_pmkid = WPA_GET_LE16(pos); 00364 pos += 2; 00365 left -= 2; 00366 if (left < (int) data->num_pmkid * PMKID_LEN) { 00367 wpa_printf(MSG_DEBUG, "%s: PMKID underflow " 00368 "(num_pmkid=%lu left=%d)", 00369 __func__, (unsigned long) data->num_pmkid, 00370 left); 00371 data->num_pmkid = 0; 00372 return -9; 00373 } else { 00374 data->pmkid = pos; 00375 pos += data->num_pmkid * PMKID_LEN; 00376 left -= data->num_pmkid * PMKID_LEN; 00377 } 00378 } 00379 00380 #ifdef CONFIG_IEEE80211W 00381 if (left >= 4) { 00382 data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); 00383 if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { 00384 wpa_printf(MSG_DEBUG, "%s: Unsupported management " 00385 "group cipher 0x%x", __func__, 00386 data->mgmt_group_cipher); 00387 return -10; 00388 } 00389 pos += RSN_SELECTOR_LEN; 00390 left -= RSN_SELECTOR_LEN; 00391 } 00392 #endif /* CONFIG_IEEE80211W */ 00393 00394 if (left > 0) { 00395 wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", 00396 __func__, left); 00397 } 00398 00399 return 0; 00400 #else /* CONFIG_NO_WPA2 */ 00401 return -1; 00402 #endif /* CONFIG_NO_WPA2 */ 00403 } 00404 00405 00406 #ifdef CONFIG_IEEE80211R 00407 00413 void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, 00414 const u8 *ssid, size_t ssid_len, 00415 const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, 00416 const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) 00417 { 00418 u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + 00419 FT_R0KH_ID_MAX_LEN + ETH_ALEN]; 00420 u8 *pos, r0_key_data[48], hash[32]; 00421 const u8 *addr[2]; 00422 size_t len[2]; 00423 00424 /* 00425 * R0-Key-Data = KDF-384(XXKey, "FT-R0", 00426 * SSIDlength || SSID || MDID || R0KHlength || 00427 * R0KH-ID || S0KH-ID) 00428 * XXKey is either the second 256 bits of MSK or PSK. 00429 * PMK-R0 = L(R0-Key-Data, 0, 256) 00430 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) 00431 */ 00432 if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) 00433 return; 00434 pos = buf; 00435 *pos++ = ssid_len; 00436 os_memcpy(pos, ssid, ssid_len); 00437 pos += ssid_len; 00438 os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); 00439 pos += MOBILITY_DOMAIN_ID_LEN; 00440 *pos++ = r0kh_id_len; 00441 os_memcpy(pos, r0kh_id, r0kh_id_len); 00442 pos += r0kh_id_len; 00443 os_memcpy(pos, s0kh_id, ETH_ALEN); 00444 pos += ETH_ALEN; 00445 00446 sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, 00447 r0_key_data, sizeof(r0_key_data)); 00448 os_memcpy(pmk_r0, r0_key_data, PMK_LEN); 00449 00450 /* 00451 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) 00452 */ 00453 addr[0] = (const u8 *) "FT-R0N"; 00454 len[0] = 6; 00455 addr[1] = r0_key_data + PMK_LEN; 00456 len[1] = 16; 00457 00458 sha256_vector(2, addr, len, hash); 00459 os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); 00460 } 00461 00462 00468 void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, 00469 const u8 *s1kh_id, u8 *pmk_r1_name) 00470 { 00471 u8 hash[32]; 00472 const u8 *addr[4]; 00473 size_t len[4]; 00474 00475 /* 00476 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || 00477 * R1KH-ID || S1KH-ID)) 00478 */ 00479 addr[0] = (const u8 *) "FT-R1N"; 00480 len[0] = 6; 00481 addr[1] = pmk_r0_name; 00482 len[1] = WPA_PMK_NAME_LEN; 00483 addr[2] = r1kh_id; 00484 len[2] = FT_R1KH_ID_LEN; 00485 addr[3] = s1kh_id; 00486 len[3] = ETH_ALEN; 00487 00488 sha256_vector(4, addr, len, hash); 00489 os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); 00490 } 00491 00492 00498 void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, 00499 const u8 *r1kh_id, const u8 *s1kh_id, 00500 u8 *pmk_r1, u8 *pmk_r1_name) 00501 { 00502 u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; 00503 u8 *pos; 00504 00505 /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ 00506 pos = buf; 00507 os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); 00508 pos += FT_R1KH_ID_LEN; 00509 os_memcpy(pos, s1kh_id, ETH_ALEN); 00510 pos += ETH_ALEN; 00511 00512 sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); 00513 00514 wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); 00515 } 00516 00517 00523 void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, 00524 const u8 *sta_addr, const u8 *bssid, 00525 const u8 *pmk_r1_name, 00526 u8 *ptk, size_t ptk_len, u8 *ptk_name) 00527 { 00528 u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; 00529 u8 *pos, hash[32]; 00530 const u8 *addr[6]; 00531 size_t len[6]; 00532 00533 /* 00534 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || 00535 * BSSID || STA-ADDR) 00536 */ 00537 pos = buf; 00538 os_memcpy(pos, snonce, WPA_NONCE_LEN); 00539 pos += WPA_NONCE_LEN; 00540 os_memcpy(pos, anonce, WPA_NONCE_LEN); 00541 pos += WPA_NONCE_LEN; 00542 os_memcpy(pos, bssid, ETH_ALEN); 00543 pos += ETH_ALEN; 00544 os_memcpy(pos, sta_addr, ETH_ALEN); 00545 pos += ETH_ALEN; 00546 00547 sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); 00548 00549 /* 00550 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || 00551 * ANonce || BSSID || STA-ADDR)) 00552 */ 00553 addr[0] = pmk_r1_name; 00554 len[0] = WPA_PMK_NAME_LEN; 00555 addr[1] = (const u8 *) "FT-PTKN"; 00556 len[1] = 7; 00557 addr[2] = snonce; 00558 len[2] = WPA_NONCE_LEN; 00559 addr[3] = anonce; 00560 len[3] = WPA_NONCE_LEN; 00561 addr[4] = bssid; 00562 len[4] = ETH_ALEN; 00563 addr[5] = sta_addr; 00564 len[5] = ETH_ALEN; 00565 00566 sha256_vector(6, addr, len, hash); 00567 os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); 00568 } 00569 00570 #endif /* CONFIG_IEEE80211R */ 00571 00572 00585 void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, 00586 u8 *pmkid, int use_sha256) 00587 { 00588 char *title = "PMK Name"; 00589 const u8 *addr[3]; 00590 const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 00591 unsigned char hash[SHA256_MAC_LEN]; 00592 00593 addr[0] = (u8 *) title; 00594 addr[1] = aa; 00595 addr[2] = spa; 00596 00597 #ifdef CONFIG_IEEE80211W 00598 if (use_sha256) 00599 hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); 00600 else 00601 #endif /* CONFIG_IEEE80211W */ 00602 hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); 00603 os_memcpy(pmkid, hash, PMKID_LEN); 00604 } 00605 00606 00612 const char * wpa_cipher_txt(int cipher) 00613 { 00614 switch (cipher) { 00615 case WPA_CIPHER_NONE: 00616 return "NONE"; 00617 case WPA_CIPHER_WEP40: 00618 return "WEP-40"; 00619 case WPA_CIPHER_WEP104: 00620 return "WEP-104"; 00621 case WPA_CIPHER_TKIP: 00622 return "TKIP"; 00623 case WPA_CIPHER_CCMP: 00624 return "CCMP"; 00625 case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: 00626 return "CCMP+TKIP"; 00627 default: 00628 return "UNKNOWN"; 00629 } 00630 } 00631 00632 00639 const char * wpa_key_mgmt_txt(int key_mgmt, int proto) 00640 { 00641 switch (key_mgmt) { 00642 case WPA_KEY_MGMT_IEEE8021X: 00643 if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 00644 return "WPA2+WPA/IEEE 802.1X/EAP"; 00645 return proto == WPA_PROTO_RSN ? 00646 "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; 00647 case WPA_KEY_MGMT_PSK: 00648 if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 00649 return "WPA2-PSK+WPA-PSK"; 00650 return proto == WPA_PROTO_RSN ? 00651 "WPA2-PSK" : "WPA-PSK"; 00652 case WPA_KEY_MGMT_NONE: 00653 return "NONE"; 00654 case WPA_KEY_MGMT_IEEE8021X_NO_WPA: 00655 return "IEEE 802.1X (no WPA)"; 00656 #ifdef CONFIG_IEEE80211R 00657 case WPA_KEY_MGMT_FT_IEEE8021X: 00658 return "FT-EAP"; 00659 case WPA_KEY_MGMT_FT_PSK: 00660 return "FT-PSK"; 00661 #endif /* CONFIG_IEEE80211R */ 00662 #ifdef CONFIG_IEEE80211W 00663 case WPA_KEY_MGMT_IEEE8021X_SHA256: 00664 return "WPA2-EAP-SHA256"; 00665 case WPA_KEY_MGMT_PSK_SHA256: 00666 return "WPA2-PSK-SHA256"; 00667 #endif /* CONFIG_IEEE80211W */ 00668 default: 00669 return "UNKNOWN"; 00670 } 00671 } 00672 00673 00674 int wpa_compare_rsn_ie(int ft_initial_assoc, 00675 const u8 *ie1, size_t ie1len, 00676 const u8 *ie2, size_t ie2len) 00677 { 00678 if (ie1 == NULL || ie2 == NULL) 00679 return -1; 00680 00681 if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) 00682 return 0; /* identical IEs */ 00683 00684 #ifdef CONFIG_IEEE80211R 00685 if (ft_initial_assoc) { 00686 struct wpa_ie_data ie1d, ie2d; 00687 /* 00688 * The PMKID-List in RSN IE is different between Beacon/Probe 00689 * Response/(Re)Association Request frames and EAPOL-Key 00690 * messages in FT initial mobility domain association. Allow 00691 * for this, but verify that other parts of the RSN IEs are 00692 * identical. 00693 */ 00694 if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || 00695 wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) 00696 return -1; 00697 if (ie1d.proto == ie2d.proto && 00698 ie1d.pairwise_cipher == ie2d.pairwise_cipher && 00699 ie1d.group_cipher == ie2d.group_cipher && 00700 ie1d.key_mgmt == ie2d.key_mgmt && 00701 ie1d.capabilities == ie2d.capabilities && 00702 ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) 00703 return 0; 00704 } 00705 #endif /* CONFIG_IEEE80211R */ 00706 00707 return -1; 00708 } 00709 00710 00711 #ifdef CONFIG_IEEE80211R 00712 int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) 00713 { 00714 u8 *start, *end, *rpos, *rend; 00715 int added = 0; 00716 00717 start = ies; 00718 end = ies + ies_len; 00719 00720 while (start < end) { 00721 if (*start == WLAN_EID_RSN) 00722 break; 00723 start += 2 + start[1]; 00724 } 00725 if (start >= end) { 00726 wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " 00727 "IEs data"); 00728 return -1; 00729 } 00730 wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", 00731 start, 2 + start[1]); 00732 00733 /* Find start of PMKID-Count */ 00734 rpos = start + 2; 00735 rend = rpos + start[1]; 00736 00737 /* Skip Version and Group Data Cipher Suite */ 00738 rpos += 2 + 4; 00739 /* Skip Pairwise Cipher Suite Count and List */ 00740 rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 00741 /* Skip AKM Suite Count and List */ 00742 rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 00743 00744 if (rpos == rend) { 00745 /* Add RSN Capabilities */ 00746 os_memmove(rpos + 2, rpos, end - rpos); 00747 *rpos++ = 0; 00748 *rpos++ = 0; 00749 } else { 00750 /* Skip RSN Capabilities */ 00751 rpos += 2; 00752 if (rpos > rend) { 00753 wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " 00754 "IEs data"); 00755 return -1; 00756 } 00757 } 00758 00759 if (rpos == rend) { 00760 /* No PMKID-Count field included; add it */ 00761 os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); 00762 WPA_PUT_LE16(rpos, 1); 00763 rpos += 2; 00764 os_memcpy(rpos, pmkid, PMKID_LEN); 00765 added += 2 + PMKID_LEN; 00766 start[1] += 2 + PMKID_LEN; 00767 } else { 00768 /* PMKID-Count was included; use it */ 00769 if (WPA_GET_LE16(rpos) != 0) { 00770 wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " 00771 "in RSN IE in EAPOL-Key data"); 00772 return -1; 00773 } 00774 WPA_PUT_LE16(rpos, 1); 00775 rpos += 2; 00776 os_memmove(rpos + PMKID_LEN, rpos, end - rpos); 00777 os_memcpy(rpos, pmkid, PMKID_LEN); 00778 added += PMKID_LEN; 00779 start[1] += PMKID_LEN; 00780 } 00781 00782 wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " 00783 "(PMKID inserted)", start, 2 + start[1]); 00784 00785 return added; 00786 } 00787 #endif /* CONFIG_IEEE80211R */