139beb93cSSam Leffler /* 239beb93cSSam Leffler * WPA/RSN - Shared functions for supplicant and authenticator 3*5b9c547cSRui Paulo * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 12e28a4053SRui Paulo #include "crypto/md5.h" 13e28a4053SRui Paulo #include "crypto/sha1.h" 14e28a4053SRui Paulo #include "crypto/sha256.h" 15*5b9c547cSRui Paulo #include "crypto/sha384.h" 16e28a4053SRui Paulo #include "crypto/aes_wrap.h" 17e28a4053SRui Paulo #include "crypto/crypto.h" 1839beb93cSSam Leffler #include "ieee802_11_defs.h" 1939beb93cSSam Leffler #include "defs.h" 2039beb93cSSam Leffler #include "wpa_common.h" 2139beb93cSSam Leffler 2239beb93cSSam Leffler 23*5b9c547cSRui Paulo static unsigned int wpa_kck_len(int akmp) 24*5b9c547cSRui Paulo { 25*5b9c547cSRui Paulo if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) 26*5b9c547cSRui Paulo return 24; 27*5b9c547cSRui Paulo return 16; 28*5b9c547cSRui Paulo } 29*5b9c547cSRui Paulo 30*5b9c547cSRui Paulo 31*5b9c547cSRui Paulo static unsigned int wpa_kek_len(int akmp) 32*5b9c547cSRui Paulo { 33*5b9c547cSRui Paulo if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) 34*5b9c547cSRui Paulo return 32; 35*5b9c547cSRui Paulo return 16; 36*5b9c547cSRui Paulo } 37*5b9c547cSRui Paulo 38*5b9c547cSRui Paulo 39*5b9c547cSRui Paulo unsigned int wpa_mic_len(int akmp) 40*5b9c547cSRui Paulo { 41*5b9c547cSRui Paulo if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) 42*5b9c547cSRui Paulo return 24; 43*5b9c547cSRui Paulo return 16; 44*5b9c547cSRui Paulo } 45*5b9c547cSRui Paulo 46*5b9c547cSRui Paulo 4739beb93cSSam Leffler /** 4839beb93cSSam Leffler * wpa_eapol_key_mic - Calculate EAPOL-Key MIC 4939beb93cSSam Leffler * @key: EAPOL-Key Key Confirmation Key (KCK) 50*5b9c547cSRui Paulo * @key_len: KCK length in octets 51*5b9c547cSRui Paulo * @akmp: WPA_KEY_MGMT_* used in key derivation 5239beb93cSSam Leffler * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) 5339beb93cSSam Leffler * @buf: Pointer to the beginning of the EAPOL header (version field) 5439beb93cSSam Leffler * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) 5539beb93cSSam Leffler * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written 5639beb93cSSam Leffler * Returns: 0 on success, -1 on failure 5739beb93cSSam Leffler * 5839beb93cSSam Leffler * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has 5939beb93cSSam Leffler * to be cleared (all zeroes) when calling this function. 6039beb93cSSam Leffler * 6139beb93cSSam Leffler * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the 6239beb93cSSam Leffler * description of the Key MIC calculation. It includes packet data from the 6339beb93cSSam Leffler * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change 6439beb93cSSam Leffler * happened during final editing of the standard and the correct behavior is 6539beb93cSSam Leffler * defined in the last draft (IEEE 802.11i/D10). 6639beb93cSSam Leffler */ 67*5b9c547cSRui Paulo int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, 68*5b9c547cSRui Paulo const u8 *buf, size_t len, u8 *mic) 6939beb93cSSam Leffler { 70*5b9c547cSRui Paulo u8 hash[SHA384_MAC_LEN]; 7139beb93cSSam Leffler 7239beb93cSSam Leffler switch (ver) { 73f05cddf9SRui Paulo #ifndef CONFIG_FIPS 7439beb93cSSam Leffler case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: 75*5b9c547cSRui Paulo return hmac_md5(key, key_len, buf, len, mic); 76f05cddf9SRui Paulo #endif /* CONFIG_FIPS */ 7739beb93cSSam Leffler case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: 78*5b9c547cSRui Paulo if (hmac_sha1(key, key_len, buf, len, hash)) 79e28a4053SRui Paulo return -1; 8039beb93cSSam Leffler os_memcpy(mic, hash, MD5_MAC_LEN); 8139beb93cSSam Leffler break; 823157ba21SRui Paulo #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) 8339beb93cSSam Leffler case WPA_KEY_INFO_TYPE_AES_128_CMAC: 8439beb93cSSam Leffler return omac1_aes_128(key, buf, len, mic); 853157ba21SRui Paulo #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ 86*5b9c547cSRui Paulo case WPA_KEY_INFO_TYPE_AKM_DEFINED: 87*5b9c547cSRui Paulo switch (akmp) { 88*5b9c547cSRui Paulo #ifdef CONFIG_HS20 89*5b9c547cSRui Paulo case WPA_KEY_MGMT_OSEN: 90*5b9c547cSRui Paulo return omac1_aes_128(key, buf, len, mic); 91*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 92*5b9c547cSRui Paulo #ifdef CONFIG_SUITEB 93*5b9c547cSRui Paulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B: 94*5b9c547cSRui Paulo if (hmac_sha256(key, key_len, buf, len, hash)) 95*5b9c547cSRui Paulo return -1; 96*5b9c547cSRui Paulo os_memcpy(mic, hash, MD5_MAC_LEN); 97*5b9c547cSRui Paulo break; 98*5b9c547cSRui Paulo #endif /* CONFIG_SUITEB */ 99*5b9c547cSRui Paulo #ifdef CONFIG_SUITEB192 100*5b9c547cSRui Paulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: 101*5b9c547cSRui Paulo if (hmac_sha384(key, key_len, buf, len, hash)) 102*5b9c547cSRui Paulo return -1; 103*5b9c547cSRui Paulo os_memcpy(mic, hash, 24); 104*5b9c547cSRui Paulo break; 105*5b9c547cSRui Paulo #endif /* CONFIG_SUITEB192 */ 106*5b9c547cSRui Paulo default: 107*5b9c547cSRui Paulo return -1; 108*5b9c547cSRui Paulo } 109*5b9c547cSRui Paulo break; 11039beb93cSSam Leffler default: 11139beb93cSSam Leffler return -1; 11239beb93cSSam Leffler } 11339beb93cSSam Leffler 11439beb93cSSam Leffler return 0; 11539beb93cSSam Leffler } 11639beb93cSSam Leffler 11739beb93cSSam Leffler 11839beb93cSSam Leffler /** 11939beb93cSSam Leffler * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces 12039beb93cSSam Leffler * @pmk: Pairwise master key 12139beb93cSSam Leffler * @pmk_len: Length of PMK 12239beb93cSSam Leffler * @label: Label to use in derivation 12339beb93cSSam Leffler * @addr1: AA or SA 12439beb93cSSam Leffler * @addr2: SA or AA 12539beb93cSSam Leffler * @nonce1: ANonce or SNonce 12639beb93cSSam Leffler * @nonce2: SNonce or ANonce 12739beb93cSSam Leffler * @ptk: Buffer for pairwise transient key 128*5b9c547cSRui Paulo * @akmp: Negotiated AKM 129*5b9c547cSRui Paulo * @cipher: Negotiated pairwise cipher 130*5b9c547cSRui Paulo * Returns: 0 on success, -1 on failure 13139beb93cSSam Leffler * 13239beb93cSSam Leffler * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy 13339beb93cSSam Leffler * PTK = PRF-X(PMK, "Pairwise key expansion", 13439beb93cSSam Leffler * Min(AA, SA) || Max(AA, SA) || 13539beb93cSSam Leffler * Min(ANonce, SNonce) || Max(ANonce, SNonce)) 13639beb93cSSam Leffler * 13739beb93cSSam Leffler * STK = PRF-X(SMK, "Peer key expansion", 13839beb93cSSam Leffler * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || 13939beb93cSSam Leffler * Min(INonce, PNonce) || Max(INonce, PNonce)) 14039beb93cSSam Leffler */ 141*5b9c547cSRui Paulo int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, 14239beb93cSSam Leffler const u8 *addr1, const u8 *addr2, 14339beb93cSSam Leffler const u8 *nonce1, const u8 *nonce2, 144*5b9c547cSRui Paulo struct wpa_ptk *ptk, int akmp, int cipher) 14539beb93cSSam Leffler { 14639beb93cSSam Leffler u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; 147*5b9c547cSRui Paulo u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; 148*5b9c547cSRui Paulo size_t ptk_len; 14939beb93cSSam Leffler 15039beb93cSSam Leffler if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { 15139beb93cSSam Leffler os_memcpy(data, addr1, ETH_ALEN); 15239beb93cSSam Leffler os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); 15339beb93cSSam Leffler } else { 15439beb93cSSam Leffler os_memcpy(data, addr2, ETH_ALEN); 15539beb93cSSam Leffler os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); 15639beb93cSSam Leffler } 15739beb93cSSam Leffler 15839beb93cSSam Leffler if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { 15939beb93cSSam Leffler os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); 16039beb93cSSam Leffler os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, 16139beb93cSSam Leffler WPA_NONCE_LEN); 16239beb93cSSam Leffler } else { 16339beb93cSSam Leffler os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); 16439beb93cSSam Leffler os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, 16539beb93cSSam Leffler WPA_NONCE_LEN); 16639beb93cSSam Leffler } 16739beb93cSSam Leffler 168*5b9c547cSRui Paulo ptk->kck_len = wpa_kck_len(akmp); 169*5b9c547cSRui Paulo ptk->kek_len = wpa_kek_len(akmp); 170*5b9c547cSRui Paulo ptk->tk_len = wpa_cipher_key_len(cipher); 171*5b9c547cSRui Paulo ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len; 172*5b9c547cSRui Paulo 17339beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 174*5b9c547cSRui Paulo if (wpa_key_mgmt_sha256(akmp)) 17539beb93cSSam Leffler sha256_prf(pmk, pmk_len, label, data, sizeof(data), 176*5b9c547cSRui Paulo tmp, ptk_len); 17739beb93cSSam Leffler else 17839beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 179*5b9c547cSRui Paulo sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len); 18039beb93cSSam Leffler 18139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, 18239beb93cSSam Leffler MAC2STR(addr1), MAC2STR(addr2)); 183f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); 184f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); 18539beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); 186*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len); 187*5b9c547cSRui Paulo 188*5b9c547cSRui Paulo os_memcpy(ptk->kck, tmp, ptk->kck_len); 189*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len); 190*5b9c547cSRui Paulo 191*5b9c547cSRui Paulo os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); 192*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len); 193*5b9c547cSRui Paulo 194*5b9c547cSRui Paulo os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); 195*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len); 196*5b9c547cSRui Paulo 197*5b9c547cSRui Paulo os_memset(tmp, 0, sizeof(tmp)); 198*5b9c547cSRui Paulo return 0; 19939beb93cSSam Leffler } 20039beb93cSSam Leffler 20139beb93cSSam Leffler 20239beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 203*5b9c547cSRui Paulo int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, 204*5b9c547cSRui Paulo const u8 *ap_addr, u8 transaction_seqnum, 205*5b9c547cSRui Paulo const u8 *mdie, size_t mdie_len, 20639beb93cSSam Leffler const u8 *ftie, size_t ftie_len, 20739beb93cSSam Leffler const u8 *rsnie, size_t rsnie_len, 20839beb93cSSam Leffler const u8 *ric, size_t ric_len, u8 *mic) 20939beb93cSSam Leffler { 21039beb93cSSam Leffler u8 *buf, *pos; 21139beb93cSSam Leffler size_t buf_len; 21239beb93cSSam Leffler 213*5b9c547cSRui Paulo if (kck_len != 16) { 214*5b9c547cSRui Paulo wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u", 215*5b9c547cSRui Paulo (unsigned int) kck_len); 216*5b9c547cSRui Paulo return -1; 217*5b9c547cSRui Paulo } 218*5b9c547cSRui Paulo 21939beb93cSSam Leffler buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; 22039beb93cSSam Leffler buf = os_malloc(buf_len); 22139beb93cSSam Leffler if (buf == NULL) 22239beb93cSSam Leffler return -1; 22339beb93cSSam Leffler 22439beb93cSSam Leffler pos = buf; 22539beb93cSSam Leffler os_memcpy(pos, sta_addr, ETH_ALEN); 22639beb93cSSam Leffler pos += ETH_ALEN; 22739beb93cSSam Leffler os_memcpy(pos, ap_addr, ETH_ALEN); 22839beb93cSSam Leffler pos += ETH_ALEN; 22939beb93cSSam Leffler *pos++ = transaction_seqnum; 23039beb93cSSam Leffler if (rsnie) { 23139beb93cSSam Leffler os_memcpy(pos, rsnie, rsnie_len); 23239beb93cSSam Leffler pos += rsnie_len; 23339beb93cSSam Leffler } 23439beb93cSSam Leffler if (mdie) { 23539beb93cSSam Leffler os_memcpy(pos, mdie, mdie_len); 23639beb93cSSam Leffler pos += mdie_len; 23739beb93cSSam Leffler } 23839beb93cSSam Leffler if (ftie) { 23939beb93cSSam Leffler struct rsn_ftie *_ftie; 24039beb93cSSam Leffler os_memcpy(pos, ftie, ftie_len); 24139beb93cSSam Leffler if (ftie_len < 2 + sizeof(*_ftie)) { 24239beb93cSSam Leffler os_free(buf); 24339beb93cSSam Leffler return -1; 24439beb93cSSam Leffler } 24539beb93cSSam Leffler _ftie = (struct rsn_ftie *) (pos + 2); 24639beb93cSSam Leffler os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); 24739beb93cSSam Leffler pos += ftie_len; 24839beb93cSSam Leffler } 24939beb93cSSam Leffler if (ric) { 25039beb93cSSam Leffler os_memcpy(pos, ric, ric_len); 25139beb93cSSam Leffler pos += ric_len; 25239beb93cSSam Leffler } 25339beb93cSSam Leffler 25439beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); 25539beb93cSSam Leffler if (omac1_aes_128(kck, buf, pos - buf, mic)) { 25639beb93cSSam Leffler os_free(buf); 25739beb93cSSam Leffler return -1; 25839beb93cSSam Leffler } 25939beb93cSSam Leffler 26039beb93cSSam Leffler os_free(buf); 26139beb93cSSam Leffler 26239beb93cSSam Leffler return 0; 26339beb93cSSam Leffler } 264f05cddf9SRui Paulo 265f05cddf9SRui Paulo 266f05cddf9SRui Paulo static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, 267f05cddf9SRui Paulo struct wpa_ft_ies *parse) 268f05cddf9SRui Paulo { 269f05cddf9SRui Paulo const u8 *end, *pos; 270f05cddf9SRui Paulo 271f05cddf9SRui Paulo parse->ftie = ie; 272f05cddf9SRui Paulo parse->ftie_len = ie_len; 273f05cddf9SRui Paulo 274f05cddf9SRui Paulo pos = ie + sizeof(struct rsn_ftie); 275f05cddf9SRui Paulo end = ie + ie_len; 276f05cddf9SRui Paulo 277f05cddf9SRui Paulo while (pos + 2 <= end && pos + 2 + pos[1] <= end) { 278f05cddf9SRui Paulo switch (pos[0]) { 279f05cddf9SRui Paulo case FTIE_SUBELEM_R1KH_ID: 280f05cddf9SRui Paulo if (pos[1] != FT_R1KH_ID_LEN) { 281f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " 282f05cddf9SRui Paulo "length in FTIE: %d", pos[1]); 283f05cddf9SRui Paulo return -1; 284f05cddf9SRui Paulo } 285f05cddf9SRui Paulo parse->r1kh_id = pos + 2; 286f05cddf9SRui Paulo break; 287f05cddf9SRui Paulo case FTIE_SUBELEM_GTK: 288f05cddf9SRui Paulo parse->gtk = pos + 2; 289f05cddf9SRui Paulo parse->gtk_len = pos[1]; 290f05cddf9SRui Paulo break; 291f05cddf9SRui Paulo case FTIE_SUBELEM_R0KH_ID: 292f05cddf9SRui Paulo if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { 293f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " 294f05cddf9SRui Paulo "length in FTIE: %d", pos[1]); 295f05cddf9SRui Paulo return -1; 296f05cddf9SRui Paulo } 297f05cddf9SRui Paulo parse->r0kh_id = pos + 2; 298f05cddf9SRui Paulo parse->r0kh_id_len = pos[1]; 299f05cddf9SRui Paulo break; 300f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W 301f05cddf9SRui Paulo case FTIE_SUBELEM_IGTK: 302f05cddf9SRui Paulo parse->igtk = pos + 2; 303f05cddf9SRui Paulo parse->igtk_len = pos[1]; 304f05cddf9SRui Paulo break; 305f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */ 306f05cddf9SRui Paulo } 307f05cddf9SRui Paulo 308f05cddf9SRui Paulo pos += 2 + pos[1]; 309f05cddf9SRui Paulo } 310f05cddf9SRui Paulo 311f05cddf9SRui Paulo return 0; 312f05cddf9SRui Paulo } 313f05cddf9SRui Paulo 314f05cddf9SRui Paulo 315f05cddf9SRui Paulo int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, 316f05cddf9SRui Paulo struct wpa_ft_ies *parse) 317f05cddf9SRui Paulo { 318f05cddf9SRui Paulo const u8 *end, *pos; 319f05cddf9SRui Paulo struct wpa_ie_data data; 320f05cddf9SRui Paulo int ret; 321f05cddf9SRui Paulo const struct rsn_ftie *ftie; 322f05cddf9SRui Paulo int prot_ie_count = 0; 323f05cddf9SRui Paulo 324f05cddf9SRui Paulo os_memset(parse, 0, sizeof(*parse)); 325f05cddf9SRui Paulo if (ies == NULL) 326f05cddf9SRui Paulo return 0; 327f05cddf9SRui Paulo 328f05cddf9SRui Paulo pos = ies; 329f05cddf9SRui Paulo end = ies + ies_len; 330f05cddf9SRui Paulo while (pos + 2 <= end && pos + 2 + pos[1] <= end) { 331f05cddf9SRui Paulo switch (pos[0]) { 332f05cddf9SRui Paulo case WLAN_EID_RSN: 333f05cddf9SRui Paulo parse->rsn = pos + 2; 334f05cddf9SRui Paulo parse->rsn_len = pos[1]; 335f05cddf9SRui Paulo ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, 336f05cddf9SRui Paulo parse->rsn_len + 2, 337f05cddf9SRui Paulo &data); 338f05cddf9SRui Paulo if (ret < 0) { 339f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "FT: Failed to parse " 340f05cddf9SRui Paulo "RSN IE: %d", ret); 341f05cddf9SRui Paulo return -1; 342f05cddf9SRui Paulo } 343f05cddf9SRui Paulo if (data.num_pmkid == 1 && data.pmkid) 344f05cddf9SRui Paulo parse->rsn_pmkid = data.pmkid; 345f05cddf9SRui Paulo break; 346f05cddf9SRui Paulo case WLAN_EID_MOBILITY_DOMAIN: 347f05cddf9SRui Paulo parse->mdie = pos + 2; 348f05cddf9SRui Paulo parse->mdie_len = pos[1]; 349f05cddf9SRui Paulo break; 350f05cddf9SRui Paulo case WLAN_EID_FAST_BSS_TRANSITION: 351f05cddf9SRui Paulo if (pos[1] < sizeof(*ftie)) 352f05cddf9SRui Paulo return -1; 353f05cddf9SRui Paulo ftie = (const struct rsn_ftie *) (pos + 2); 354f05cddf9SRui Paulo prot_ie_count = ftie->mic_control[1]; 355f05cddf9SRui Paulo if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) 356f05cddf9SRui Paulo return -1; 357f05cddf9SRui Paulo break; 358f05cddf9SRui Paulo case WLAN_EID_TIMEOUT_INTERVAL: 359f05cddf9SRui Paulo parse->tie = pos + 2; 360f05cddf9SRui Paulo parse->tie_len = pos[1]; 361f05cddf9SRui Paulo break; 362f05cddf9SRui Paulo case WLAN_EID_RIC_DATA: 363f05cddf9SRui Paulo if (parse->ric == NULL) 364f05cddf9SRui Paulo parse->ric = pos; 365f05cddf9SRui Paulo break; 366f05cddf9SRui Paulo } 367f05cddf9SRui Paulo 368f05cddf9SRui Paulo pos += 2 + pos[1]; 369f05cddf9SRui Paulo } 370f05cddf9SRui Paulo 371f05cddf9SRui Paulo if (prot_ie_count == 0) 372f05cddf9SRui Paulo return 0; /* no MIC */ 373f05cddf9SRui Paulo 374f05cddf9SRui Paulo /* 375f05cddf9SRui Paulo * Check that the protected IE count matches with IEs included in the 376f05cddf9SRui Paulo * frame. 377f05cddf9SRui Paulo */ 378f05cddf9SRui Paulo if (parse->rsn) 379f05cddf9SRui Paulo prot_ie_count--; 380f05cddf9SRui Paulo if (parse->mdie) 381f05cddf9SRui Paulo prot_ie_count--; 382f05cddf9SRui Paulo if (parse->ftie) 383f05cddf9SRui Paulo prot_ie_count--; 384f05cddf9SRui Paulo if (prot_ie_count < 0) { 385f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " 386f05cddf9SRui Paulo "the protected IE count"); 387f05cddf9SRui Paulo return -1; 388f05cddf9SRui Paulo } 389f05cddf9SRui Paulo 390f05cddf9SRui Paulo if (prot_ie_count == 0 && parse->ric) { 391f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " 392f05cddf9SRui Paulo "included in protected IE count"); 393f05cddf9SRui Paulo return -1; 394f05cddf9SRui Paulo } 395f05cddf9SRui Paulo 396f05cddf9SRui Paulo /* Determine the end of the RIC IE(s) */ 397f05cddf9SRui Paulo pos = parse->ric; 398f05cddf9SRui Paulo while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && 399f05cddf9SRui Paulo prot_ie_count) { 400f05cddf9SRui Paulo prot_ie_count--; 401f05cddf9SRui Paulo pos += 2 + pos[1]; 402f05cddf9SRui Paulo } 403f05cddf9SRui Paulo parse->ric_len = pos - parse->ric; 404f05cddf9SRui Paulo if (prot_ie_count) { 405f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " 406f05cddf9SRui Paulo "frame", (int) prot_ie_count); 407f05cddf9SRui Paulo return -1; 408f05cddf9SRui Paulo } 409f05cddf9SRui Paulo 410f05cddf9SRui Paulo return 0; 411f05cddf9SRui Paulo } 41239beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 41339beb93cSSam Leffler 41439beb93cSSam Leffler 41539beb93cSSam Leffler static int rsn_selector_to_bitfield(const u8 *s) 41639beb93cSSam Leffler { 41739beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) 41839beb93cSSam Leffler return WPA_CIPHER_NONE; 41939beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) 42039beb93cSSam Leffler return WPA_CIPHER_WEP40; 42139beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) 42239beb93cSSam Leffler return WPA_CIPHER_TKIP; 42339beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) 42439beb93cSSam Leffler return WPA_CIPHER_CCMP; 42539beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) 42639beb93cSSam Leffler return WPA_CIPHER_WEP104; 42739beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 42839beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) 42939beb93cSSam Leffler return WPA_CIPHER_AES_128_CMAC; 43039beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 431f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) 432f05cddf9SRui Paulo return WPA_CIPHER_GCMP; 433*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256) 434*5b9c547cSRui Paulo return WPA_CIPHER_CCMP_256; 435*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256) 436*5b9c547cSRui Paulo return WPA_CIPHER_GCMP_256; 437*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128) 438*5b9c547cSRui Paulo return WPA_CIPHER_BIP_GMAC_128; 439*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256) 440*5b9c547cSRui Paulo return WPA_CIPHER_BIP_GMAC_256; 441*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) 442*5b9c547cSRui Paulo return WPA_CIPHER_BIP_CMAC_256; 443*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED) 444*5b9c547cSRui Paulo return WPA_CIPHER_GTK_NOT_USED; 44539beb93cSSam Leffler return 0; 44639beb93cSSam Leffler } 44739beb93cSSam Leffler 44839beb93cSSam Leffler 44939beb93cSSam Leffler static int rsn_key_mgmt_to_bitfield(const u8 *s) 45039beb93cSSam Leffler { 45139beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) 45239beb93cSSam Leffler return WPA_KEY_MGMT_IEEE8021X; 45339beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) 45439beb93cSSam Leffler return WPA_KEY_MGMT_PSK; 45539beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 45639beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) 45739beb93cSSam Leffler return WPA_KEY_MGMT_FT_IEEE8021X; 45839beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) 45939beb93cSSam Leffler return WPA_KEY_MGMT_FT_PSK; 46039beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 46139beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 46239beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) 46339beb93cSSam Leffler return WPA_KEY_MGMT_IEEE8021X_SHA256; 46439beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) 46539beb93cSSam Leffler return WPA_KEY_MGMT_PSK_SHA256; 46639beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 467f05cddf9SRui Paulo #ifdef CONFIG_SAE 468f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE) 469f05cddf9SRui Paulo return WPA_KEY_MGMT_SAE; 470f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE) 471f05cddf9SRui Paulo return WPA_KEY_MGMT_FT_SAE; 472f05cddf9SRui Paulo #endif /* CONFIG_SAE */ 473*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B) 474*5b9c547cSRui Paulo return WPA_KEY_MGMT_IEEE8021X_SUITE_B; 475*5b9c547cSRui Paulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192) 476*5b9c547cSRui Paulo return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; 47739beb93cSSam Leffler return 0; 47839beb93cSSam Leffler } 479*5b9c547cSRui Paulo 480*5b9c547cSRui Paulo 481*5b9c547cSRui Paulo static int wpa_cipher_valid_group(int cipher) 482*5b9c547cSRui Paulo { 483*5b9c547cSRui Paulo return wpa_cipher_valid_pairwise(cipher) || 484*5b9c547cSRui Paulo cipher == WPA_CIPHER_WEP104 || 485*5b9c547cSRui Paulo cipher == WPA_CIPHER_WEP40 || 486*5b9c547cSRui Paulo cipher == WPA_CIPHER_GTK_NOT_USED; 487*5b9c547cSRui Paulo } 488*5b9c547cSRui Paulo 489*5b9c547cSRui Paulo 490*5b9c547cSRui Paulo #ifdef CONFIG_IEEE80211W 491*5b9c547cSRui Paulo int wpa_cipher_valid_mgmt_group(int cipher) 492*5b9c547cSRui Paulo { 493*5b9c547cSRui Paulo return cipher == WPA_CIPHER_AES_128_CMAC || 494*5b9c547cSRui Paulo cipher == WPA_CIPHER_BIP_GMAC_128 || 495*5b9c547cSRui Paulo cipher == WPA_CIPHER_BIP_GMAC_256 || 496*5b9c547cSRui Paulo cipher == WPA_CIPHER_BIP_CMAC_256; 497*5b9c547cSRui Paulo } 498*5b9c547cSRui Paulo #endif /* CONFIG_IEEE80211W */ 49939beb93cSSam Leffler 50039beb93cSSam Leffler 50139beb93cSSam Leffler /** 50239beb93cSSam Leffler * wpa_parse_wpa_ie_rsn - Parse RSN IE 50339beb93cSSam Leffler * @rsn_ie: Buffer containing RSN IE 50439beb93cSSam Leffler * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) 50539beb93cSSam Leffler * @data: Pointer to structure that will be filled in with parsed data 50639beb93cSSam Leffler * Returns: 0 on success, <0 on failure 50739beb93cSSam Leffler */ 50839beb93cSSam Leffler int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, 50939beb93cSSam Leffler struct wpa_ie_data *data) 51039beb93cSSam Leffler { 51139beb93cSSam Leffler const struct rsn_ie_hdr *hdr; 51239beb93cSSam Leffler const u8 *pos; 51339beb93cSSam Leffler int left; 51439beb93cSSam Leffler int i, count; 51539beb93cSSam Leffler 51639beb93cSSam Leffler os_memset(data, 0, sizeof(*data)); 51739beb93cSSam Leffler data->proto = WPA_PROTO_RSN; 51839beb93cSSam Leffler data->pairwise_cipher = WPA_CIPHER_CCMP; 51939beb93cSSam Leffler data->group_cipher = WPA_CIPHER_CCMP; 52039beb93cSSam Leffler data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 52139beb93cSSam Leffler data->capabilities = 0; 52239beb93cSSam Leffler data->pmkid = NULL; 52339beb93cSSam Leffler data->num_pmkid = 0; 52439beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 52539beb93cSSam Leffler data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; 52639beb93cSSam Leffler #else /* CONFIG_IEEE80211W */ 52739beb93cSSam Leffler data->mgmt_group_cipher = 0; 52839beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 52939beb93cSSam Leffler 53039beb93cSSam Leffler if (rsn_ie_len == 0) { 53139beb93cSSam Leffler /* No RSN IE - fail silently */ 53239beb93cSSam Leffler return -1; 53339beb93cSSam Leffler } 53439beb93cSSam Leffler 53539beb93cSSam Leffler if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { 53639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 53739beb93cSSam Leffler __func__, (unsigned long) rsn_ie_len); 53839beb93cSSam Leffler return -1; 53939beb93cSSam Leffler } 54039beb93cSSam Leffler 54139beb93cSSam Leffler hdr = (const struct rsn_ie_hdr *) rsn_ie; 54239beb93cSSam Leffler 54339beb93cSSam Leffler if (hdr->elem_id != WLAN_EID_RSN || 54439beb93cSSam Leffler hdr->len != rsn_ie_len - 2 || 54539beb93cSSam Leffler WPA_GET_LE16(hdr->version) != RSN_VERSION) { 54639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 54739beb93cSSam Leffler __func__); 54839beb93cSSam Leffler return -2; 54939beb93cSSam Leffler } 55039beb93cSSam Leffler 55139beb93cSSam Leffler pos = (const u8 *) (hdr + 1); 55239beb93cSSam Leffler left = rsn_ie_len - sizeof(*hdr); 55339beb93cSSam Leffler 55439beb93cSSam Leffler if (left >= RSN_SELECTOR_LEN) { 55539beb93cSSam Leffler data->group_cipher = rsn_selector_to_bitfield(pos); 556*5b9c547cSRui Paulo if (!wpa_cipher_valid_group(data->group_cipher)) { 557*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x", 558*5b9c547cSRui Paulo __func__, data->group_cipher); 55939beb93cSSam Leffler return -1; 56039beb93cSSam Leffler } 56139beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 56239beb93cSSam Leffler left -= RSN_SELECTOR_LEN; 56339beb93cSSam Leffler } else if (left > 0) { 56439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 56539beb93cSSam Leffler __func__, left); 56639beb93cSSam Leffler return -3; 56739beb93cSSam Leffler } 56839beb93cSSam Leffler 56939beb93cSSam Leffler if (left >= 2) { 57039beb93cSSam Leffler data->pairwise_cipher = 0; 57139beb93cSSam Leffler count = WPA_GET_LE16(pos); 57239beb93cSSam Leffler pos += 2; 57339beb93cSSam Leffler left -= 2; 574*5b9c547cSRui Paulo if (count == 0 || count > left / RSN_SELECTOR_LEN) { 57539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 57639beb93cSSam Leffler "count %u left %u", __func__, count, left); 57739beb93cSSam Leffler return -4; 57839beb93cSSam Leffler } 57939beb93cSSam Leffler for (i = 0; i < count; i++) { 58039beb93cSSam Leffler data->pairwise_cipher |= rsn_selector_to_bitfield(pos); 58139beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 58239beb93cSSam Leffler left -= RSN_SELECTOR_LEN; 58339beb93cSSam Leffler } 58439beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 58539beb93cSSam Leffler if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { 58639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " 58739beb93cSSam Leffler "pairwise cipher", __func__); 58839beb93cSSam Leffler return -1; 58939beb93cSSam Leffler } 59039beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 59139beb93cSSam Leffler } else if (left == 1) { 59239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 59339beb93cSSam Leffler __func__); 59439beb93cSSam Leffler return -5; 59539beb93cSSam Leffler } 59639beb93cSSam Leffler 59739beb93cSSam Leffler if (left >= 2) { 59839beb93cSSam Leffler data->key_mgmt = 0; 59939beb93cSSam Leffler count = WPA_GET_LE16(pos); 60039beb93cSSam Leffler pos += 2; 60139beb93cSSam Leffler left -= 2; 602*5b9c547cSRui Paulo if (count == 0 || count > left / RSN_SELECTOR_LEN) { 60339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 60439beb93cSSam Leffler "count %u left %u", __func__, count, left); 60539beb93cSSam Leffler return -6; 60639beb93cSSam Leffler } 60739beb93cSSam Leffler for (i = 0; i < count; i++) { 60839beb93cSSam Leffler data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); 60939beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 61039beb93cSSam Leffler left -= RSN_SELECTOR_LEN; 61139beb93cSSam Leffler } 61239beb93cSSam Leffler } else if (left == 1) { 61339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 61439beb93cSSam Leffler __func__); 61539beb93cSSam Leffler return -7; 61639beb93cSSam Leffler } 61739beb93cSSam Leffler 61839beb93cSSam Leffler if (left >= 2) { 61939beb93cSSam Leffler data->capabilities = WPA_GET_LE16(pos); 62039beb93cSSam Leffler pos += 2; 62139beb93cSSam Leffler left -= 2; 62239beb93cSSam Leffler } 62339beb93cSSam Leffler 62439beb93cSSam Leffler if (left >= 2) { 625*5b9c547cSRui Paulo u16 num_pmkid = WPA_GET_LE16(pos); 62639beb93cSSam Leffler pos += 2; 62739beb93cSSam Leffler left -= 2; 628*5b9c547cSRui Paulo if (num_pmkid > (unsigned int) left / PMKID_LEN) { 62939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: PMKID underflow " 630*5b9c547cSRui Paulo "(num_pmkid=%u left=%d)", 631*5b9c547cSRui Paulo __func__, num_pmkid, left); 63239beb93cSSam Leffler data->num_pmkid = 0; 63339beb93cSSam Leffler return -9; 63439beb93cSSam Leffler } else { 635*5b9c547cSRui Paulo data->num_pmkid = num_pmkid; 63639beb93cSSam Leffler data->pmkid = pos; 63739beb93cSSam Leffler pos += data->num_pmkid * PMKID_LEN; 63839beb93cSSam Leffler left -= data->num_pmkid * PMKID_LEN; 63939beb93cSSam Leffler } 64039beb93cSSam Leffler } 64139beb93cSSam Leffler 64239beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 64339beb93cSSam Leffler if (left >= 4) { 64439beb93cSSam Leffler data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); 645*5b9c547cSRui Paulo if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) { 64639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: Unsupported management " 64739beb93cSSam Leffler "group cipher 0x%x", __func__, 64839beb93cSSam Leffler data->mgmt_group_cipher); 64939beb93cSSam Leffler return -10; 65039beb93cSSam Leffler } 65139beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 65239beb93cSSam Leffler left -= RSN_SELECTOR_LEN; 65339beb93cSSam Leffler } 65439beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 65539beb93cSSam Leffler 65639beb93cSSam Leffler if (left > 0) { 657*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, 658*5b9c547cSRui Paulo "wpa_parse_wpa_ie_rsn: ignore trailing bytes", 659*5b9c547cSRui Paulo pos, left); 66039beb93cSSam Leffler } 66139beb93cSSam Leffler 66239beb93cSSam Leffler return 0; 66339beb93cSSam Leffler } 66439beb93cSSam Leffler 66539beb93cSSam Leffler 666f05cddf9SRui Paulo static int wpa_selector_to_bitfield(const u8 *s) 667f05cddf9SRui Paulo { 668f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) 669f05cddf9SRui Paulo return WPA_CIPHER_NONE; 670f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) 671f05cddf9SRui Paulo return WPA_CIPHER_WEP40; 672f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) 673f05cddf9SRui Paulo return WPA_CIPHER_TKIP; 674f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) 675f05cddf9SRui Paulo return WPA_CIPHER_CCMP; 676f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) 677f05cddf9SRui Paulo return WPA_CIPHER_WEP104; 678f05cddf9SRui Paulo return 0; 679f05cddf9SRui Paulo } 680f05cddf9SRui Paulo 681f05cddf9SRui Paulo 682f05cddf9SRui Paulo static int wpa_key_mgmt_to_bitfield(const u8 *s) 683f05cddf9SRui Paulo { 684f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) 685f05cddf9SRui Paulo return WPA_KEY_MGMT_IEEE8021X; 686f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) 687f05cddf9SRui Paulo return WPA_KEY_MGMT_PSK; 688f05cddf9SRui Paulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) 689f05cddf9SRui Paulo return WPA_KEY_MGMT_WPA_NONE; 690f05cddf9SRui Paulo return 0; 691f05cddf9SRui Paulo } 692f05cddf9SRui Paulo 693f05cddf9SRui Paulo 694f05cddf9SRui Paulo int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, 695f05cddf9SRui Paulo struct wpa_ie_data *data) 696f05cddf9SRui Paulo { 697f05cddf9SRui Paulo const struct wpa_ie_hdr *hdr; 698f05cddf9SRui Paulo const u8 *pos; 699f05cddf9SRui Paulo int left; 700f05cddf9SRui Paulo int i, count; 701f05cddf9SRui Paulo 702f05cddf9SRui Paulo os_memset(data, 0, sizeof(*data)); 703f05cddf9SRui Paulo data->proto = WPA_PROTO_WPA; 704f05cddf9SRui Paulo data->pairwise_cipher = WPA_CIPHER_TKIP; 705f05cddf9SRui Paulo data->group_cipher = WPA_CIPHER_TKIP; 706f05cddf9SRui Paulo data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 707f05cddf9SRui Paulo data->capabilities = 0; 708f05cddf9SRui Paulo data->pmkid = NULL; 709f05cddf9SRui Paulo data->num_pmkid = 0; 710f05cddf9SRui Paulo data->mgmt_group_cipher = 0; 711f05cddf9SRui Paulo 712f05cddf9SRui Paulo if (wpa_ie_len == 0) { 713f05cddf9SRui Paulo /* No WPA IE - fail silently */ 714f05cddf9SRui Paulo return -1; 715f05cddf9SRui Paulo } 716f05cddf9SRui Paulo 717f05cddf9SRui Paulo if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { 718f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 719f05cddf9SRui Paulo __func__, (unsigned long) wpa_ie_len); 720f05cddf9SRui Paulo return -1; 721f05cddf9SRui Paulo } 722f05cddf9SRui Paulo 723f05cddf9SRui Paulo hdr = (const struct wpa_ie_hdr *) wpa_ie; 724f05cddf9SRui Paulo 725f05cddf9SRui Paulo if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || 726f05cddf9SRui Paulo hdr->len != wpa_ie_len - 2 || 727f05cddf9SRui Paulo RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || 728f05cddf9SRui Paulo WPA_GET_LE16(hdr->version) != WPA_VERSION) { 729f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 730f05cddf9SRui Paulo __func__); 731f05cddf9SRui Paulo return -2; 732f05cddf9SRui Paulo } 733f05cddf9SRui Paulo 734f05cddf9SRui Paulo pos = (const u8 *) (hdr + 1); 735f05cddf9SRui Paulo left = wpa_ie_len - sizeof(*hdr); 736f05cddf9SRui Paulo 737f05cddf9SRui Paulo if (left >= WPA_SELECTOR_LEN) { 738f05cddf9SRui Paulo data->group_cipher = wpa_selector_to_bitfield(pos); 739f05cddf9SRui Paulo pos += WPA_SELECTOR_LEN; 740f05cddf9SRui Paulo left -= WPA_SELECTOR_LEN; 741f05cddf9SRui Paulo } else if (left > 0) { 742f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 743f05cddf9SRui Paulo __func__, left); 744f05cddf9SRui Paulo return -3; 745f05cddf9SRui Paulo } 746f05cddf9SRui Paulo 747f05cddf9SRui Paulo if (left >= 2) { 748f05cddf9SRui Paulo data->pairwise_cipher = 0; 749f05cddf9SRui Paulo count = WPA_GET_LE16(pos); 750f05cddf9SRui Paulo pos += 2; 751f05cddf9SRui Paulo left -= 2; 752*5b9c547cSRui Paulo if (count == 0 || count > left / WPA_SELECTOR_LEN) { 753f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 754f05cddf9SRui Paulo "count %u left %u", __func__, count, left); 755f05cddf9SRui Paulo return -4; 756f05cddf9SRui Paulo } 757f05cddf9SRui Paulo for (i = 0; i < count; i++) { 758f05cddf9SRui Paulo data->pairwise_cipher |= wpa_selector_to_bitfield(pos); 759f05cddf9SRui Paulo pos += WPA_SELECTOR_LEN; 760f05cddf9SRui Paulo left -= WPA_SELECTOR_LEN; 761f05cddf9SRui Paulo } 762f05cddf9SRui Paulo } else if (left == 1) { 763f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 764f05cddf9SRui Paulo __func__); 765f05cddf9SRui Paulo return -5; 766f05cddf9SRui Paulo } 767f05cddf9SRui Paulo 768f05cddf9SRui Paulo if (left >= 2) { 769f05cddf9SRui Paulo data->key_mgmt = 0; 770f05cddf9SRui Paulo count = WPA_GET_LE16(pos); 771f05cddf9SRui Paulo pos += 2; 772f05cddf9SRui Paulo left -= 2; 773*5b9c547cSRui Paulo if (count == 0 || count > left / WPA_SELECTOR_LEN) { 774f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 775f05cddf9SRui Paulo "count %u left %u", __func__, count, left); 776f05cddf9SRui Paulo return -6; 777f05cddf9SRui Paulo } 778f05cddf9SRui Paulo for (i = 0; i < count; i++) { 779f05cddf9SRui Paulo data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); 780f05cddf9SRui Paulo pos += WPA_SELECTOR_LEN; 781f05cddf9SRui Paulo left -= WPA_SELECTOR_LEN; 782f05cddf9SRui Paulo } 783f05cddf9SRui Paulo } else if (left == 1) { 784f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 785f05cddf9SRui Paulo __func__); 786f05cddf9SRui Paulo return -7; 787f05cddf9SRui Paulo } 788f05cddf9SRui Paulo 789f05cddf9SRui Paulo if (left >= 2) { 790f05cddf9SRui Paulo data->capabilities = WPA_GET_LE16(pos); 791f05cddf9SRui Paulo pos += 2; 792f05cddf9SRui Paulo left -= 2; 793f05cddf9SRui Paulo } 794f05cddf9SRui Paulo 795f05cddf9SRui Paulo if (left > 0) { 796*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, 797*5b9c547cSRui Paulo "wpa_parse_wpa_ie_wpa: ignore trailing bytes", 798*5b9c547cSRui Paulo pos, left); 799f05cddf9SRui Paulo } 800f05cddf9SRui Paulo 801f05cddf9SRui Paulo return 0; 802f05cddf9SRui Paulo } 803f05cddf9SRui Paulo 804f05cddf9SRui Paulo 80539beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 80639beb93cSSam Leffler 80739beb93cSSam Leffler /** 80839beb93cSSam Leffler * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name 80939beb93cSSam Leffler * 81039beb93cSSam Leffler * IEEE Std 802.11r-2008 - 8.5.1.5.3 81139beb93cSSam Leffler */ 81239beb93cSSam Leffler void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, 81339beb93cSSam Leffler const u8 *ssid, size_t ssid_len, 81439beb93cSSam Leffler const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, 81539beb93cSSam Leffler const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) 81639beb93cSSam Leffler { 81739beb93cSSam Leffler u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + 81839beb93cSSam Leffler FT_R0KH_ID_MAX_LEN + ETH_ALEN]; 81939beb93cSSam Leffler u8 *pos, r0_key_data[48], hash[32]; 82039beb93cSSam Leffler const u8 *addr[2]; 82139beb93cSSam Leffler size_t len[2]; 82239beb93cSSam Leffler 82339beb93cSSam Leffler /* 82439beb93cSSam Leffler * R0-Key-Data = KDF-384(XXKey, "FT-R0", 82539beb93cSSam Leffler * SSIDlength || SSID || MDID || R0KHlength || 82639beb93cSSam Leffler * R0KH-ID || S0KH-ID) 82739beb93cSSam Leffler * XXKey is either the second 256 bits of MSK or PSK. 82839beb93cSSam Leffler * PMK-R0 = L(R0-Key-Data, 0, 256) 82939beb93cSSam Leffler * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) 83039beb93cSSam Leffler */ 83139beb93cSSam Leffler if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) 83239beb93cSSam Leffler return; 83339beb93cSSam Leffler pos = buf; 83439beb93cSSam Leffler *pos++ = ssid_len; 83539beb93cSSam Leffler os_memcpy(pos, ssid, ssid_len); 83639beb93cSSam Leffler pos += ssid_len; 83739beb93cSSam Leffler os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); 83839beb93cSSam Leffler pos += MOBILITY_DOMAIN_ID_LEN; 83939beb93cSSam Leffler *pos++ = r0kh_id_len; 84039beb93cSSam Leffler os_memcpy(pos, r0kh_id, r0kh_id_len); 84139beb93cSSam Leffler pos += r0kh_id_len; 84239beb93cSSam Leffler os_memcpy(pos, s0kh_id, ETH_ALEN); 84339beb93cSSam Leffler pos += ETH_ALEN; 84439beb93cSSam Leffler 84539beb93cSSam Leffler sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, 84639beb93cSSam Leffler r0_key_data, sizeof(r0_key_data)); 84739beb93cSSam Leffler os_memcpy(pmk_r0, r0_key_data, PMK_LEN); 84839beb93cSSam Leffler 84939beb93cSSam Leffler /* 85039beb93cSSam Leffler * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) 85139beb93cSSam Leffler */ 85239beb93cSSam Leffler addr[0] = (const u8 *) "FT-R0N"; 85339beb93cSSam Leffler len[0] = 6; 85439beb93cSSam Leffler addr[1] = r0_key_data + PMK_LEN; 85539beb93cSSam Leffler len[1] = 16; 85639beb93cSSam Leffler 85739beb93cSSam Leffler sha256_vector(2, addr, len, hash); 85839beb93cSSam Leffler os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); 85939beb93cSSam Leffler } 86039beb93cSSam Leffler 86139beb93cSSam Leffler 86239beb93cSSam Leffler /** 86339beb93cSSam Leffler * wpa_derive_pmk_r1_name - Derive PMKR1Name 86439beb93cSSam Leffler * 86539beb93cSSam Leffler * IEEE Std 802.11r-2008 - 8.5.1.5.4 86639beb93cSSam Leffler */ 86739beb93cSSam Leffler void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, 86839beb93cSSam Leffler const u8 *s1kh_id, u8 *pmk_r1_name) 86939beb93cSSam Leffler { 87039beb93cSSam Leffler u8 hash[32]; 87139beb93cSSam Leffler const u8 *addr[4]; 87239beb93cSSam Leffler size_t len[4]; 87339beb93cSSam Leffler 87439beb93cSSam Leffler /* 87539beb93cSSam Leffler * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || 87639beb93cSSam Leffler * R1KH-ID || S1KH-ID)) 87739beb93cSSam Leffler */ 87839beb93cSSam Leffler addr[0] = (const u8 *) "FT-R1N"; 87939beb93cSSam Leffler len[0] = 6; 88039beb93cSSam Leffler addr[1] = pmk_r0_name; 88139beb93cSSam Leffler len[1] = WPA_PMK_NAME_LEN; 88239beb93cSSam Leffler addr[2] = r1kh_id; 88339beb93cSSam Leffler len[2] = FT_R1KH_ID_LEN; 88439beb93cSSam Leffler addr[3] = s1kh_id; 88539beb93cSSam Leffler len[3] = ETH_ALEN; 88639beb93cSSam Leffler 88739beb93cSSam Leffler sha256_vector(4, addr, len, hash); 88839beb93cSSam Leffler os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); 88939beb93cSSam Leffler } 89039beb93cSSam Leffler 89139beb93cSSam Leffler 89239beb93cSSam Leffler /** 89339beb93cSSam Leffler * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 89439beb93cSSam Leffler * 89539beb93cSSam Leffler * IEEE Std 802.11r-2008 - 8.5.1.5.4 89639beb93cSSam Leffler */ 89739beb93cSSam Leffler void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, 89839beb93cSSam Leffler const u8 *r1kh_id, const u8 *s1kh_id, 89939beb93cSSam Leffler u8 *pmk_r1, u8 *pmk_r1_name) 90039beb93cSSam Leffler { 90139beb93cSSam Leffler u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; 90239beb93cSSam Leffler u8 *pos; 90339beb93cSSam Leffler 90439beb93cSSam Leffler /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ 90539beb93cSSam Leffler pos = buf; 90639beb93cSSam Leffler os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); 90739beb93cSSam Leffler pos += FT_R1KH_ID_LEN; 90839beb93cSSam Leffler os_memcpy(pos, s1kh_id, ETH_ALEN); 90939beb93cSSam Leffler pos += ETH_ALEN; 91039beb93cSSam Leffler 91139beb93cSSam Leffler sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); 91239beb93cSSam Leffler 91339beb93cSSam Leffler wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); 91439beb93cSSam Leffler } 91539beb93cSSam Leffler 91639beb93cSSam Leffler 91739beb93cSSam Leffler /** 91839beb93cSSam Leffler * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 91939beb93cSSam Leffler * 92039beb93cSSam Leffler * IEEE Std 802.11r-2008 - 8.5.1.5.5 92139beb93cSSam Leffler */ 922*5b9c547cSRui Paulo int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, 92339beb93cSSam Leffler const u8 *sta_addr, const u8 *bssid, 92439beb93cSSam Leffler const u8 *pmk_r1_name, 925*5b9c547cSRui Paulo struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher) 92639beb93cSSam Leffler { 92739beb93cSSam Leffler u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; 92839beb93cSSam Leffler u8 *pos, hash[32]; 92939beb93cSSam Leffler const u8 *addr[6]; 93039beb93cSSam Leffler size_t len[6]; 931*5b9c547cSRui Paulo u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; 932*5b9c547cSRui Paulo size_t ptk_len; 93339beb93cSSam Leffler 93439beb93cSSam Leffler /* 93539beb93cSSam Leffler * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || 93639beb93cSSam Leffler * BSSID || STA-ADDR) 93739beb93cSSam Leffler */ 93839beb93cSSam Leffler pos = buf; 93939beb93cSSam Leffler os_memcpy(pos, snonce, WPA_NONCE_LEN); 94039beb93cSSam Leffler pos += WPA_NONCE_LEN; 94139beb93cSSam Leffler os_memcpy(pos, anonce, WPA_NONCE_LEN); 94239beb93cSSam Leffler pos += WPA_NONCE_LEN; 94339beb93cSSam Leffler os_memcpy(pos, bssid, ETH_ALEN); 94439beb93cSSam Leffler pos += ETH_ALEN; 94539beb93cSSam Leffler os_memcpy(pos, sta_addr, ETH_ALEN); 94639beb93cSSam Leffler pos += ETH_ALEN; 94739beb93cSSam Leffler 948*5b9c547cSRui Paulo ptk->kck_len = wpa_kck_len(akmp); 949*5b9c547cSRui Paulo ptk->kek_len = wpa_kek_len(akmp); 950*5b9c547cSRui Paulo ptk->tk_len = wpa_cipher_key_len(cipher); 951*5b9c547cSRui Paulo ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len; 952*5b9c547cSRui Paulo 953*5b9c547cSRui Paulo sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len); 95439beb93cSSam Leffler 95539beb93cSSam Leffler /* 95639beb93cSSam Leffler * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || 95739beb93cSSam Leffler * ANonce || BSSID || STA-ADDR)) 95839beb93cSSam Leffler */ 95939beb93cSSam Leffler addr[0] = pmk_r1_name; 96039beb93cSSam Leffler len[0] = WPA_PMK_NAME_LEN; 96139beb93cSSam Leffler addr[1] = (const u8 *) "FT-PTKN"; 96239beb93cSSam Leffler len[1] = 7; 96339beb93cSSam Leffler addr[2] = snonce; 96439beb93cSSam Leffler len[2] = WPA_NONCE_LEN; 96539beb93cSSam Leffler addr[3] = anonce; 96639beb93cSSam Leffler len[3] = WPA_NONCE_LEN; 96739beb93cSSam Leffler addr[4] = bssid; 96839beb93cSSam Leffler len[4] = ETH_ALEN; 96939beb93cSSam Leffler addr[5] = sta_addr; 97039beb93cSSam Leffler len[5] = ETH_ALEN; 97139beb93cSSam Leffler 97239beb93cSSam Leffler sha256_vector(6, addr, len, hash); 97339beb93cSSam Leffler os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); 974*5b9c547cSRui Paulo 975*5b9c547cSRui Paulo os_memcpy(ptk->kck, tmp, ptk->kck_len); 976*5b9c547cSRui Paulo os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); 977*5b9c547cSRui Paulo os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); 978*5b9c547cSRui Paulo 979*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len); 980*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len); 981*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len); 982*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); 983*5b9c547cSRui Paulo 984*5b9c547cSRui Paulo os_memset(tmp, 0, sizeof(tmp)); 985*5b9c547cSRui Paulo 986*5b9c547cSRui Paulo return 0; 98739beb93cSSam Leffler } 98839beb93cSSam Leffler 98939beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 990e28a4053SRui Paulo 991e28a4053SRui Paulo 992e28a4053SRui Paulo /** 993e28a4053SRui Paulo * rsn_pmkid - Calculate PMK identifier 994e28a4053SRui Paulo * @pmk: Pairwise master key 995e28a4053SRui Paulo * @pmk_len: Length of pmk in bytes 996e28a4053SRui Paulo * @aa: Authenticator address 997e28a4053SRui Paulo * @spa: Supplicant address 998e28a4053SRui Paulo * @pmkid: Buffer for PMKID 999e28a4053SRui Paulo * @use_sha256: Whether to use SHA256-based KDF 1000e28a4053SRui Paulo * 1001e28a4053SRui Paulo * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy 1002e28a4053SRui Paulo * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) 1003e28a4053SRui Paulo */ 1004e28a4053SRui Paulo void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, 1005e28a4053SRui Paulo u8 *pmkid, int use_sha256) 1006e28a4053SRui Paulo { 1007e28a4053SRui Paulo char *title = "PMK Name"; 1008e28a4053SRui Paulo const u8 *addr[3]; 1009e28a4053SRui Paulo const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 1010e28a4053SRui Paulo unsigned char hash[SHA256_MAC_LEN]; 1011e28a4053SRui Paulo 1012e28a4053SRui Paulo addr[0] = (u8 *) title; 1013e28a4053SRui Paulo addr[1] = aa; 1014e28a4053SRui Paulo addr[2] = spa; 1015e28a4053SRui Paulo 1016e28a4053SRui Paulo #ifdef CONFIG_IEEE80211W 1017e28a4053SRui Paulo if (use_sha256) 1018e28a4053SRui Paulo hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); 1019e28a4053SRui Paulo else 1020e28a4053SRui Paulo #endif /* CONFIG_IEEE80211W */ 1021e28a4053SRui Paulo hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); 1022e28a4053SRui Paulo os_memcpy(pmkid, hash, PMKID_LEN); 1023e28a4053SRui Paulo } 1024e28a4053SRui Paulo 1025e28a4053SRui Paulo 1026*5b9c547cSRui Paulo #ifdef CONFIG_SUITEB 1027*5b9c547cSRui Paulo /** 1028*5b9c547cSRui Paulo * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM 1029*5b9c547cSRui Paulo * @kck: Key confirmation key 1030*5b9c547cSRui Paulo * @kck_len: Length of kck in bytes 1031*5b9c547cSRui Paulo * @aa: Authenticator address 1032*5b9c547cSRui Paulo * @spa: Supplicant address 1033*5b9c547cSRui Paulo * @pmkid: Buffer for PMKID 1034*5b9c547cSRui Paulo * Returns: 0 on success, -1 on failure 1035*5b9c547cSRui Paulo * 1036*5b9c547cSRui Paulo * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy 1037*5b9c547cSRui Paulo * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA)) 1038*5b9c547cSRui Paulo */ 1039*5b9c547cSRui Paulo int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa, 1040*5b9c547cSRui Paulo const u8 *spa, u8 *pmkid) 1041*5b9c547cSRui Paulo { 1042*5b9c547cSRui Paulo char *title = "PMK Name"; 1043*5b9c547cSRui Paulo const u8 *addr[3]; 1044*5b9c547cSRui Paulo const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 1045*5b9c547cSRui Paulo unsigned char hash[SHA256_MAC_LEN]; 1046*5b9c547cSRui Paulo 1047*5b9c547cSRui Paulo addr[0] = (u8 *) title; 1048*5b9c547cSRui Paulo addr[1] = aa; 1049*5b9c547cSRui Paulo addr[2] = spa; 1050*5b9c547cSRui Paulo 1051*5b9c547cSRui Paulo if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0) 1052*5b9c547cSRui Paulo return -1; 1053*5b9c547cSRui Paulo os_memcpy(pmkid, hash, PMKID_LEN); 1054*5b9c547cSRui Paulo return 0; 1055*5b9c547cSRui Paulo } 1056*5b9c547cSRui Paulo #endif /* CONFIG_SUITEB */ 1057*5b9c547cSRui Paulo 1058*5b9c547cSRui Paulo 1059*5b9c547cSRui Paulo #ifdef CONFIG_SUITEB192 1060*5b9c547cSRui Paulo /** 1061*5b9c547cSRui Paulo * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM 1062*5b9c547cSRui Paulo * @kck: Key confirmation key 1063*5b9c547cSRui Paulo * @kck_len: Length of kck in bytes 1064*5b9c547cSRui Paulo * @aa: Authenticator address 1065*5b9c547cSRui Paulo * @spa: Supplicant address 1066*5b9c547cSRui Paulo * @pmkid: Buffer for PMKID 1067*5b9c547cSRui Paulo * Returns: 0 on success, -1 on failure 1068*5b9c547cSRui Paulo * 1069*5b9c547cSRui Paulo * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy 1070*5b9c547cSRui Paulo * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA)) 1071*5b9c547cSRui Paulo */ 1072*5b9c547cSRui Paulo int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa, 1073*5b9c547cSRui Paulo const u8 *spa, u8 *pmkid) 1074*5b9c547cSRui Paulo { 1075*5b9c547cSRui Paulo char *title = "PMK Name"; 1076*5b9c547cSRui Paulo const u8 *addr[3]; 1077*5b9c547cSRui Paulo const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 1078*5b9c547cSRui Paulo unsigned char hash[SHA384_MAC_LEN]; 1079*5b9c547cSRui Paulo 1080*5b9c547cSRui Paulo addr[0] = (u8 *) title; 1081*5b9c547cSRui Paulo addr[1] = aa; 1082*5b9c547cSRui Paulo addr[2] = spa; 1083*5b9c547cSRui Paulo 1084*5b9c547cSRui Paulo if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0) 1085*5b9c547cSRui Paulo return -1; 1086*5b9c547cSRui Paulo os_memcpy(pmkid, hash, PMKID_LEN); 1087*5b9c547cSRui Paulo return 0; 1088*5b9c547cSRui Paulo } 1089*5b9c547cSRui Paulo #endif /* CONFIG_SUITEB192 */ 1090*5b9c547cSRui Paulo 1091*5b9c547cSRui Paulo 1092e28a4053SRui Paulo /** 1093e28a4053SRui Paulo * wpa_cipher_txt - Convert cipher suite to a text string 1094e28a4053SRui Paulo * @cipher: Cipher suite (WPA_CIPHER_* enum) 1095e28a4053SRui Paulo * Returns: Pointer to a text string of the cipher suite name 1096e28a4053SRui Paulo */ 1097e28a4053SRui Paulo const char * wpa_cipher_txt(int cipher) 1098e28a4053SRui Paulo { 1099e28a4053SRui Paulo switch (cipher) { 1100e28a4053SRui Paulo case WPA_CIPHER_NONE: 1101e28a4053SRui Paulo return "NONE"; 1102e28a4053SRui Paulo case WPA_CIPHER_WEP40: 1103e28a4053SRui Paulo return "WEP-40"; 1104e28a4053SRui Paulo case WPA_CIPHER_WEP104: 1105e28a4053SRui Paulo return "WEP-104"; 1106e28a4053SRui Paulo case WPA_CIPHER_TKIP: 1107e28a4053SRui Paulo return "TKIP"; 1108e28a4053SRui Paulo case WPA_CIPHER_CCMP: 1109e28a4053SRui Paulo return "CCMP"; 1110e28a4053SRui Paulo case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: 1111e28a4053SRui Paulo return "CCMP+TKIP"; 1112f05cddf9SRui Paulo case WPA_CIPHER_GCMP: 1113f05cddf9SRui Paulo return "GCMP"; 1114*5b9c547cSRui Paulo case WPA_CIPHER_GCMP_256: 1115*5b9c547cSRui Paulo return "GCMP-256"; 1116*5b9c547cSRui Paulo case WPA_CIPHER_CCMP_256: 1117*5b9c547cSRui Paulo return "CCMP-256"; 1118*5b9c547cSRui Paulo case WPA_CIPHER_GTK_NOT_USED: 1119*5b9c547cSRui Paulo return "GTK_NOT_USED"; 1120e28a4053SRui Paulo default: 1121e28a4053SRui Paulo return "UNKNOWN"; 1122e28a4053SRui Paulo } 1123e28a4053SRui Paulo } 1124e28a4053SRui Paulo 1125e28a4053SRui Paulo 1126e28a4053SRui Paulo /** 1127e28a4053SRui Paulo * wpa_key_mgmt_txt - Convert key management suite to a text string 1128e28a4053SRui Paulo * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) 1129e28a4053SRui Paulo * @proto: WPA/WPA2 version (WPA_PROTO_*) 1130e28a4053SRui Paulo * Returns: Pointer to a text string of the key management suite name 1131e28a4053SRui Paulo */ 1132e28a4053SRui Paulo const char * wpa_key_mgmt_txt(int key_mgmt, int proto) 1133e28a4053SRui Paulo { 1134e28a4053SRui Paulo switch (key_mgmt) { 1135e28a4053SRui Paulo case WPA_KEY_MGMT_IEEE8021X: 1136e28a4053SRui Paulo if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 1137e28a4053SRui Paulo return "WPA2+WPA/IEEE 802.1X/EAP"; 1138e28a4053SRui Paulo return proto == WPA_PROTO_RSN ? 1139e28a4053SRui Paulo "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; 1140e28a4053SRui Paulo case WPA_KEY_MGMT_PSK: 1141e28a4053SRui Paulo if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 1142e28a4053SRui Paulo return "WPA2-PSK+WPA-PSK"; 1143e28a4053SRui Paulo return proto == WPA_PROTO_RSN ? 1144e28a4053SRui Paulo "WPA2-PSK" : "WPA-PSK"; 1145e28a4053SRui Paulo case WPA_KEY_MGMT_NONE: 1146e28a4053SRui Paulo return "NONE"; 1147e28a4053SRui Paulo case WPA_KEY_MGMT_IEEE8021X_NO_WPA: 1148e28a4053SRui Paulo return "IEEE 802.1X (no WPA)"; 1149e28a4053SRui Paulo #ifdef CONFIG_IEEE80211R 1150e28a4053SRui Paulo case WPA_KEY_MGMT_FT_IEEE8021X: 1151e28a4053SRui Paulo return "FT-EAP"; 1152e28a4053SRui Paulo case WPA_KEY_MGMT_FT_PSK: 1153e28a4053SRui Paulo return "FT-PSK"; 1154e28a4053SRui Paulo #endif /* CONFIG_IEEE80211R */ 1155e28a4053SRui Paulo #ifdef CONFIG_IEEE80211W 1156e28a4053SRui Paulo case WPA_KEY_MGMT_IEEE8021X_SHA256: 1157e28a4053SRui Paulo return "WPA2-EAP-SHA256"; 1158e28a4053SRui Paulo case WPA_KEY_MGMT_PSK_SHA256: 1159e28a4053SRui Paulo return "WPA2-PSK-SHA256"; 1160e28a4053SRui Paulo #endif /* CONFIG_IEEE80211W */ 1161*5b9c547cSRui Paulo case WPA_KEY_MGMT_WPS: 1162*5b9c547cSRui Paulo return "WPS"; 1163*5b9c547cSRui Paulo case WPA_KEY_MGMT_SAE: 1164*5b9c547cSRui Paulo return "SAE"; 1165*5b9c547cSRui Paulo case WPA_KEY_MGMT_FT_SAE: 1166*5b9c547cSRui Paulo return "FT-SAE"; 1167*5b9c547cSRui Paulo case WPA_KEY_MGMT_OSEN: 1168*5b9c547cSRui Paulo return "OSEN"; 1169*5b9c547cSRui Paulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B: 1170*5b9c547cSRui Paulo return "WPA2-EAP-SUITE-B"; 1171*5b9c547cSRui Paulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: 1172*5b9c547cSRui Paulo return "WPA2-EAP-SUITE-B-192"; 1173e28a4053SRui Paulo default: 1174e28a4053SRui Paulo return "UNKNOWN"; 1175e28a4053SRui Paulo } 1176e28a4053SRui Paulo } 1177e28a4053SRui Paulo 1178e28a4053SRui Paulo 1179*5b9c547cSRui Paulo u32 wpa_akm_to_suite(int akm) 1180*5b9c547cSRui Paulo { 1181*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_FT_IEEE8021X) 1182*5b9c547cSRui Paulo return WLAN_AKM_SUITE_FT_8021X; 1183*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_FT_PSK) 1184*5b9c547cSRui Paulo return WLAN_AKM_SUITE_FT_PSK; 1185*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_IEEE8021X) 1186*5b9c547cSRui Paulo return WLAN_AKM_SUITE_8021X; 1187*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256) 1188*5b9c547cSRui Paulo return WLAN_AKM_SUITE_8021X_SHA256; 1189*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_IEEE8021X) 1190*5b9c547cSRui Paulo return WLAN_AKM_SUITE_8021X; 1191*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_PSK_SHA256) 1192*5b9c547cSRui Paulo return WLAN_AKM_SUITE_PSK_SHA256; 1193*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_PSK) 1194*5b9c547cSRui Paulo return WLAN_AKM_SUITE_PSK; 1195*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_CCKM) 1196*5b9c547cSRui Paulo return WLAN_AKM_SUITE_CCKM; 1197*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_OSEN) 1198*5b9c547cSRui Paulo return WLAN_AKM_SUITE_OSEN; 1199*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B) 1200*5b9c547cSRui Paulo return WLAN_AKM_SUITE_8021X_SUITE_B; 1201*5b9c547cSRui Paulo if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) 1202*5b9c547cSRui Paulo return WLAN_AKM_SUITE_8021X_SUITE_B_192; 1203*5b9c547cSRui Paulo return 0; 1204*5b9c547cSRui Paulo } 1205*5b9c547cSRui Paulo 1206*5b9c547cSRui Paulo 1207e28a4053SRui Paulo int wpa_compare_rsn_ie(int ft_initial_assoc, 1208e28a4053SRui Paulo const u8 *ie1, size_t ie1len, 1209e28a4053SRui Paulo const u8 *ie2, size_t ie2len) 1210e28a4053SRui Paulo { 1211e28a4053SRui Paulo if (ie1 == NULL || ie2 == NULL) 1212e28a4053SRui Paulo return -1; 1213e28a4053SRui Paulo 1214e28a4053SRui Paulo if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) 1215e28a4053SRui Paulo return 0; /* identical IEs */ 1216e28a4053SRui Paulo 1217e28a4053SRui Paulo #ifdef CONFIG_IEEE80211R 1218e28a4053SRui Paulo if (ft_initial_assoc) { 1219e28a4053SRui Paulo struct wpa_ie_data ie1d, ie2d; 1220e28a4053SRui Paulo /* 1221e28a4053SRui Paulo * The PMKID-List in RSN IE is different between Beacon/Probe 1222e28a4053SRui Paulo * Response/(Re)Association Request frames and EAPOL-Key 1223e28a4053SRui Paulo * messages in FT initial mobility domain association. Allow 1224e28a4053SRui Paulo * for this, but verify that other parts of the RSN IEs are 1225e28a4053SRui Paulo * identical. 1226e28a4053SRui Paulo */ 1227e28a4053SRui Paulo if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || 1228e28a4053SRui Paulo wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) 1229e28a4053SRui Paulo return -1; 1230e28a4053SRui Paulo if (ie1d.proto == ie2d.proto && 1231e28a4053SRui Paulo ie1d.pairwise_cipher == ie2d.pairwise_cipher && 1232e28a4053SRui Paulo ie1d.group_cipher == ie2d.group_cipher && 1233e28a4053SRui Paulo ie1d.key_mgmt == ie2d.key_mgmt && 1234e28a4053SRui Paulo ie1d.capabilities == ie2d.capabilities && 1235e28a4053SRui Paulo ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) 1236e28a4053SRui Paulo return 0; 1237e28a4053SRui Paulo } 1238e28a4053SRui Paulo #endif /* CONFIG_IEEE80211R */ 1239e28a4053SRui Paulo 1240e28a4053SRui Paulo return -1; 1241e28a4053SRui Paulo } 1242e28a4053SRui Paulo 1243e28a4053SRui Paulo 1244e28a4053SRui Paulo #ifdef CONFIG_IEEE80211R 1245e28a4053SRui Paulo int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) 1246e28a4053SRui Paulo { 1247e28a4053SRui Paulo u8 *start, *end, *rpos, *rend; 1248e28a4053SRui Paulo int added = 0; 1249e28a4053SRui Paulo 1250e28a4053SRui Paulo start = ies; 1251e28a4053SRui Paulo end = ies + ies_len; 1252e28a4053SRui Paulo 1253e28a4053SRui Paulo while (start < end) { 1254e28a4053SRui Paulo if (*start == WLAN_EID_RSN) 1255e28a4053SRui Paulo break; 1256e28a4053SRui Paulo start += 2 + start[1]; 1257e28a4053SRui Paulo } 1258e28a4053SRui Paulo if (start >= end) { 1259e28a4053SRui Paulo wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " 1260e28a4053SRui Paulo "IEs data"); 1261e28a4053SRui Paulo return -1; 1262e28a4053SRui Paulo } 1263e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", 1264e28a4053SRui Paulo start, 2 + start[1]); 1265e28a4053SRui Paulo 1266e28a4053SRui Paulo /* Find start of PMKID-Count */ 1267e28a4053SRui Paulo rpos = start + 2; 1268e28a4053SRui Paulo rend = rpos + start[1]; 1269e28a4053SRui Paulo 1270e28a4053SRui Paulo /* Skip Version and Group Data Cipher Suite */ 1271e28a4053SRui Paulo rpos += 2 + 4; 1272e28a4053SRui Paulo /* Skip Pairwise Cipher Suite Count and List */ 1273e28a4053SRui Paulo rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 1274e28a4053SRui Paulo /* Skip AKM Suite Count and List */ 1275e28a4053SRui Paulo rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 1276e28a4053SRui Paulo 1277e28a4053SRui Paulo if (rpos == rend) { 1278e28a4053SRui Paulo /* Add RSN Capabilities */ 1279e28a4053SRui Paulo os_memmove(rpos + 2, rpos, end - rpos); 1280e28a4053SRui Paulo *rpos++ = 0; 1281e28a4053SRui Paulo *rpos++ = 0; 1282e28a4053SRui Paulo } else { 1283e28a4053SRui Paulo /* Skip RSN Capabilities */ 1284e28a4053SRui Paulo rpos += 2; 1285e28a4053SRui Paulo if (rpos > rend) { 1286e28a4053SRui Paulo wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " 1287e28a4053SRui Paulo "IEs data"); 1288e28a4053SRui Paulo return -1; 1289e28a4053SRui Paulo } 1290e28a4053SRui Paulo } 1291e28a4053SRui Paulo 1292e28a4053SRui Paulo if (rpos == rend) { 1293e28a4053SRui Paulo /* No PMKID-Count field included; add it */ 1294e28a4053SRui Paulo os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); 1295e28a4053SRui Paulo WPA_PUT_LE16(rpos, 1); 1296e28a4053SRui Paulo rpos += 2; 1297e28a4053SRui Paulo os_memcpy(rpos, pmkid, PMKID_LEN); 1298e28a4053SRui Paulo added += 2 + PMKID_LEN; 1299e28a4053SRui Paulo start[1] += 2 + PMKID_LEN; 1300e28a4053SRui Paulo } else { 1301e28a4053SRui Paulo /* PMKID-Count was included; use it */ 1302e28a4053SRui Paulo if (WPA_GET_LE16(rpos) != 0) { 1303e28a4053SRui Paulo wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " 1304e28a4053SRui Paulo "in RSN IE in EAPOL-Key data"); 1305e28a4053SRui Paulo return -1; 1306e28a4053SRui Paulo } 1307e28a4053SRui Paulo WPA_PUT_LE16(rpos, 1); 1308e28a4053SRui Paulo rpos += 2; 1309e28a4053SRui Paulo os_memmove(rpos + PMKID_LEN, rpos, end - rpos); 1310e28a4053SRui Paulo os_memcpy(rpos, pmkid, PMKID_LEN); 1311e28a4053SRui Paulo added += PMKID_LEN; 1312e28a4053SRui Paulo start[1] += PMKID_LEN; 1313e28a4053SRui Paulo } 1314e28a4053SRui Paulo 1315e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " 1316e28a4053SRui Paulo "(PMKID inserted)", start, 2 + start[1]); 1317e28a4053SRui Paulo 1318e28a4053SRui Paulo return added; 1319e28a4053SRui Paulo } 1320e28a4053SRui Paulo #endif /* CONFIG_IEEE80211R */ 1321f05cddf9SRui Paulo 1322f05cddf9SRui Paulo 1323f05cddf9SRui Paulo int wpa_cipher_key_len(int cipher) 1324f05cddf9SRui Paulo { 1325f05cddf9SRui Paulo switch (cipher) { 1326*5b9c547cSRui Paulo case WPA_CIPHER_CCMP_256: 1327*5b9c547cSRui Paulo case WPA_CIPHER_GCMP_256: 1328*5b9c547cSRui Paulo case WPA_CIPHER_BIP_GMAC_256: 1329*5b9c547cSRui Paulo case WPA_CIPHER_BIP_CMAC_256: 1330*5b9c547cSRui Paulo return 32; 1331f05cddf9SRui Paulo case WPA_CIPHER_CCMP: 1332f05cddf9SRui Paulo case WPA_CIPHER_GCMP: 1333*5b9c547cSRui Paulo case WPA_CIPHER_AES_128_CMAC: 1334*5b9c547cSRui Paulo case WPA_CIPHER_BIP_GMAC_128: 1335f05cddf9SRui Paulo return 16; 1336f05cddf9SRui Paulo case WPA_CIPHER_TKIP: 1337f05cddf9SRui Paulo return 32; 1338f05cddf9SRui Paulo case WPA_CIPHER_WEP104: 1339f05cddf9SRui Paulo return 13; 1340f05cddf9SRui Paulo case WPA_CIPHER_WEP40: 1341f05cddf9SRui Paulo return 5; 1342f05cddf9SRui Paulo } 1343f05cddf9SRui Paulo 1344f05cddf9SRui Paulo return 0; 1345f05cddf9SRui Paulo } 1346f05cddf9SRui Paulo 1347f05cddf9SRui Paulo 1348f05cddf9SRui Paulo int wpa_cipher_rsc_len(int cipher) 1349f05cddf9SRui Paulo { 1350f05cddf9SRui Paulo switch (cipher) { 1351*5b9c547cSRui Paulo case WPA_CIPHER_CCMP_256: 1352*5b9c547cSRui Paulo case WPA_CIPHER_GCMP_256: 1353f05cddf9SRui Paulo case WPA_CIPHER_CCMP: 1354f05cddf9SRui Paulo case WPA_CIPHER_GCMP: 1355f05cddf9SRui Paulo case WPA_CIPHER_TKIP: 1356f05cddf9SRui Paulo return 6; 1357f05cddf9SRui Paulo case WPA_CIPHER_WEP104: 1358f05cddf9SRui Paulo case WPA_CIPHER_WEP40: 1359f05cddf9SRui Paulo return 0; 1360f05cddf9SRui Paulo } 1361f05cddf9SRui Paulo 1362f05cddf9SRui Paulo return 0; 1363f05cddf9SRui Paulo } 1364f05cddf9SRui Paulo 1365f05cddf9SRui Paulo 1366f05cddf9SRui Paulo int wpa_cipher_to_alg(int cipher) 1367f05cddf9SRui Paulo { 1368f05cddf9SRui Paulo switch (cipher) { 1369*5b9c547cSRui Paulo case WPA_CIPHER_CCMP_256: 1370*5b9c547cSRui Paulo return WPA_ALG_CCMP_256; 1371*5b9c547cSRui Paulo case WPA_CIPHER_GCMP_256: 1372*5b9c547cSRui Paulo return WPA_ALG_GCMP_256; 1373f05cddf9SRui Paulo case WPA_CIPHER_CCMP: 1374f05cddf9SRui Paulo return WPA_ALG_CCMP; 1375f05cddf9SRui Paulo case WPA_CIPHER_GCMP: 1376f05cddf9SRui Paulo return WPA_ALG_GCMP; 1377f05cddf9SRui Paulo case WPA_CIPHER_TKIP: 1378f05cddf9SRui Paulo return WPA_ALG_TKIP; 1379f05cddf9SRui Paulo case WPA_CIPHER_WEP104: 1380f05cddf9SRui Paulo case WPA_CIPHER_WEP40: 1381f05cddf9SRui Paulo return WPA_ALG_WEP; 1382*5b9c547cSRui Paulo case WPA_CIPHER_AES_128_CMAC: 1383*5b9c547cSRui Paulo return WPA_ALG_IGTK; 1384*5b9c547cSRui Paulo case WPA_CIPHER_BIP_GMAC_128: 1385*5b9c547cSRui Paulo return WPA_ALG_BIP_GMAC_128; 1386*5b9c547cSRui Paulo case WPA_CIPHER_BIP_GMAC_256: 1387*5b9c547cSRui Paulo return WPA_ALG_BIP_GMAC_256; 1388*5b9c547cSRui Paulo case WPA_CIPHER_BIP_CMAC_256: 1389*5b9c547cSRui Paulo return WPA_ALG_BIP_CMAC_256; 1390f05cddf9SRui Paulo } 1391f05cddf9SRui Paulo return WPA_ALG_NONE; 1392f05cddf9SRui Paulo } 1393f05cddf9SRui Paulo 1394f05cddf9SRui Paulo 1395f05cddf9SRui Paulo int wpa_cipher_valid_pairwise(int cipher) 1396f05cddf9SRui Paulo { 1397*5b9c547cSRui Paulo return cipher == WPA_CIPHER_CCMP_256 || 1398*5b9c547cSRui Paulo cipher == WPA_CIPHER_GCMP_256 || 1399*5b9c547cSRui Paulo cipher == WPA_CIPHER_CCMP || 1400f05cddf9SRui Paulo cipher == WPA_CIPHER_GCMP || 1401f05cddf9SRui Paulo cipher == WPA_CIPHER_TKIP; 1402f05cddf9SRui Paulo } 1403f05cddf9SRui Paulo 1404f05cddf9SRui Paulo 1405f05cddf9SRui Paulo u32 wpa_cipher_to_suite(int proto, int cipher) 1406f05cddf9SRui Paulo { 1407*5b9c547cSRui Paulo if (cipher & WPA_CIPHER_CCMP_256) 1408*5b9c547cSRui Paulo return RSN_CIPHER_SUITE_CCMP_256; 1409*5b9c547cSRui Paulo if (cipher & WPA_CIPHER_GCMP_256) 1410*5b9c547cSRui Paulo return RSN_CIPHER_SUITE_GCMP_256; 1411f05cddf9SRui Paulo if (cipher & WPA_CIPHER_CCMP) 1412f05cddf9SRui Paulo return (proto == WPA_PROTO_RSN ? 1413f05cddf9SRui Paulo RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); 1414f05cddf9SRui Paulo if (cipher & WPA_CIPHER_GCMP) 1415f05cddf9SRui Paulo return RSN_CIPHER_SUITE_GCMP; 1416f05cddf9SRui Paulo if (cipher & WPA_CIPHER_TKIP) 1417f05cddf9SRui Paulo return (proto == WPA_PROTO_RSN ? 1418f05cddf9SRui Paulo RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); 1419f05cddf9SRui Paulo if (cipher & WPA_CIPHER_WEP104) 1420f05cddf9SRui Paulo return (proto == WPA_PROTO_RSN ? 1421f05cddf9SRui Paulo RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); 1422f05cddf9SRui Paulo if (cipher & WPA_CIPHER_WEP40) 1423f05cddf9SRui Paulo return (proto == WPA_PROTO_RSN ? 1424f05cddf9SRui Paulo RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); 1425f05cddf9SRui Paulo if (cipher & WPA_CIPHER_NONE) 1426f05cddf9SRui Paulo return (proto == WPA_PROTO_RSN ? 1427f05cddf9SRui Paulo RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); 1428*5b9c547cSRui Paulo if (cipher & WPA_CIPHER_GTK_NOT_USED) 1429*5b9c547cSRui Paulo return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; 1430*5b9c547cSRui Paulo if (cipher & WPA_CIPHER_AES_128_CMAC) 1431*5b9c547cSRui Paulo return RSN_CIPHER_SUITE_AES_128_CMAC; 1432*5b9c547cSRui Paulo if (cipher & WPA_CIPHER_BIP_GMAC_128) 1433*5b9c547cSRui Paulo return RSN_CIPHER_SUITE_BIP_GMAC_128; 1434*5b9c547cSRui Paulo if (cipher & WPA_CIPHER_BIP_GMAC_256) 1435*5b9c547cSRui Paulo return RSN_CIPHER_SUITE_BIP_GMAC_256; 1436*5b9c547cSRui Paulo if (cipher & WPA_CIPHER_BIP_CMAC_256) 1437*5b9c547cSRui Paulo return RSN_CIPHER_SUITE_BIP_CMAC_256; 1438f05cddf9SRui Paulo return 0; 1439f05cddf9SRui Paulo } 1440f05cddf9SRui Paulo 1441f05cddf9SRui Paulo 1442*5b9c547cSRui Paulo int rsn_cipher_put_suites(u8 *start, int ciphers) 1443f05cddf9SRui Paulo { 1444*5b9c547cSRui Paulo u8 *pos = start; 1445f05cddf9SRui Paulo 1446*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_CCMP_256) { 1447*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256); 1448*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 1449*5b9c547cSRui Paulo } 1450*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GCMP_256) { 1451*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256); 1452*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 1453*5b9c547cSRui Paulo } 1454f05cddf9SRui Paulo if (ciphers & WPA_CIPHER_CCMP) { 1455f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 1456f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1457f05cddf9SRui Paulo } 1458f05cddf9SRui Paulo if (ciphers & WPA_CIPHER_GCMP) { 1459f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); 1460f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1461f05cddf9SRui Paulo } 1462f05cddf9SRui Paulo if (ciphers & WPA_CIPHER_TKIP) { 1463f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 1464f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1465f05cddf9SRui Paulo } 1466f05cddf9SRui Paulo if (ciphers & WPA_CIPHER_NONE) { 1467f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); 1468f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1469f05cddf9SRui Paulo } 1470f05cddf9SRui Paulo 1471*5b9c547cSRui Paulo return (pos - start) / RSN_SELECTOR_LEN; 1472f05cddf9SRui Paulo } 1473f05cddf9SRui Paulo 1474f05cddf9SRui Paulo 1475*5b9c547cSRui Paulo int wpa_cipher_put_suites(u8 *start, int ciphers) 1476f05cddf9SRui Paulo { 1477*5b9c547cSRui Paulo u8 *pos = start; 1478f05cddf9SRui Paulo 1479f05cddf9SRui Paulo if (ciphers & WPA_CIPHER_CCMP) { 1480f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 1481f05cddf9SRui Paulo pos += WPA_SELECTOR_LEN; 1482f05cddf9SRui Paulo } 1483f05cddf9SRui Paulo if (ciphers & WPA_CIPHER_TKIP) { 1484f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 1485f05cddf9SRui Paulo pos += WPA_SELECTOR_LEN; 1486f05cddf9SRui Paulo } 1487f05cddf9SRui Paulo if (ciphers & WPA_CIPHER_NONE) { 1488f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); 1489f05cddf9SRui Paulo pos += WPA_SELECTOR_LEN; 1490f05cddf9SRui Paulo } 1491f05cddf9SRui Paulo 1492*5b9c547cSRui Paulo return (pos - start) / RSN_SELECTOR_LEN; 1493*5b9c547cSRui Paulo } 1494*5b9c547cSRui Paulo 1495*5b9c547cSRui Paulo 1496*5b9c547cSRui Paulo int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) 1497*5b9c547cSRui Paulo { 1498*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_CCMP_256) 1499*5b9c547cSRui Paulo return WPA_CIPHER_CCMP_256; 1500*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GCMP_256) 1501*5b9c547cSRui Paulo return WPA_CIPHER_GCMP_256; 1502*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_CCMP) 1503*5b9c547cSRui Paulo return WPA_CIPHER_CCMP; 1504*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GCMP) 1505*5b9c547cSRui Paulo return WPA_CIPHER_GCMP; 1506*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_TKIP) 1507*5b9c547cSRui Paulo return WPA_CIPHER_TKIP; 1508*5b9c547cSRui Paulo if (none_allowed && (ciphers & WPA_CIPHER_NONE)) 1509*5b9c547cSRui Paulo return WPA_CIPHER_NONE; 1510*5b9c547cSRui Paulo return -1; 1511*5b9c547cSRui Paulo } 1512*5b9c547cSRui Paulo 1513*5b9c547cSRui Paulo 1514*5b9c547cSRui Paulo int wpa_pick_group_cipher(int ciphers) 1515*5b9c547cSRui Paulo { 1516*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_CCMP_256) 1517*5b9c547cSRui Paulo return WPA_CIPHER_CCMP_256; 1518*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GCMP_256) 1519*5b9c547cSRui Paulo return WPA_CIPHER_GCMP_256; 1520*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_CCMP) 1521*5b9c547cSRui Paulo return WPA_CIPHER_CCMP; 1522*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GCMP) 1523*5b9c547cSRui Paulo return WPA_CIPHER_GCMP; 1524*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GTK_NOT_USED) 1525*5b9c547cSRui Paulo return WPA_CIPHER_GTK_NOT_USED; 1526*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_TKIP) 1527*5b9c547cSRui Paulo return WPA_CIPHER_TKIP; 1528*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_WEP104) 1529*5b9c547cSRui Paulo return WPA_CIPHER_WEP104; 1530*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_WEP40) 1531*5b9c547cSRui Paulo return WPA_CIPHER_WEP40; 1532*5b9c547cSRui Paulo return -1; 1533*5b9c547cSRui Paulo } 1534*5b9c547cSRui Paulo 1535*5b9c547cSRui Paulo 1536*5b9c547cSRui Paulo int wpa_parse_cipher(const char *value) 1537*5b9c547cSRui Paulo { 1538*5b9c547cSRui Paulo int val = 0, last; 1539*5b9c547cSRui Paulo char *start, *end, *buf; 1540*5b9c547cSRui Paulo 1541*5b9c547cSRui Paulo buf = os_strdup(value); 1542*5b9c547cSRui Paulo if (buf == NULL) 1543*5b9c547cSRui Paulo return -1; 1544*5b9c547cSRui Paulo start = buf; 1545*5b9c547cSRui Paulo 1546*5b9c547cSRui Paulo while (*start != '\0') { 1547*5b9c547cSRui Paulo while (*start == ' ' || *start == '\t') 1548*5b9c547cSRui Paulo start++; 1549*5b9c547cSRui Paulo if (*start == '\0') 1550*5b9c547cSRui Paulo break; 1551*5b9c547cSRui Paulo end = start; 1552*5b9c547cSRui Paulo while (*end != ' ' && *end != '\t' && *end != '\0') 1553*5b9c547cSRui Paulo end++; 1554*5b9c547cSRui Paulo last = *end == '\0'; 1555*5b9c547cSRui Paulo *end = '\0'; 1556*5b9c547cSRui Paulo if (os_strcmp(start, "CCMP-256") == 0) 1557*5b9c547cSRui Paulo val |= WPA_CIPHER_CCMP_256; 1558*5b9c547cSRui Paulo else if (os_strcmp(start, "GCMP-256") == 0) 1559*5b9c547cSRui Paulo val |= WPA_CIPHER_GCMP_256; 1560*5b9c547cSRui Paulo else if (os_strcmp(start, "CCMP") == 0) 1561*5b9c547cSRui Paulo val |= WPA_CIPHER_CCMP; 1562*5b9c547cSRui Paulo else if (os_strcmp(start, "GCMP") == 0) 1563*5b9c547cSRui Paulo val |= WPA_CIPHER_GCMP; 1564*5b9c547cSRui Paulo else if (os_strcmp(start, "TKIP") == 0) 1565*5b9c547cSRui Paulo val |= WPA_CIPHER_TKIP; 1566*5b9c547cSRui Paulo else if (os_strcmp(start, "WEP104") == 0) 1567*5b9c547cSRui Paulo val |= WPA_CIPHER_WEP104; 1568*5b9c547cSRui Paulo else if (os_strcmp(start, "WEP40") == 0) 1569*5b9c547cSRui Paulo val |= WPA_CIPHER_WEP40; 1570*5b9c547cSRui Paulo else if (os_strcmp(start, "NONE") == 0) 1571*5b9c547cSRui Paulo val |= WPA_CIPHER_NONE; 1572*5b9c547cSRui Paulo else if (os_strcmp(start, "GTK_NOT_USED") == 0) 1573*5b9c547cSRui Paulo val |= WPA_CIPHER_GTK_NOT_USED; 1574*5b9c547cSRui Paulo else { 1575*5b9c547cSRui Paulo os_free(buf); 1576*5b9c547cSRui Paulo return -1; 1577*5b9c547cSRui Paulo } 1578*5b9c547cSRui Paulo 1579*5b9c547cSRui Paulo if (last) 1580*5b9c547cSRui Paulo break; 1581*5b9c547cSRui Paulo start = end + 1; 1582*5b9c547cSRui Paulo } 1583*5b9c547cSRui Paulo os_free(buf); 1584*5b9c547cSRui Paulo 1585*5b9c547cSRui Paulo return val; 1586*5b9c547cSRui Paulo } 1587*5b9c547cSRui Paulo 1588*5b9c547cSRui Paulo 1589*5b9c547cSRui Paulo int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) 1590*5b9c547cSRui Paulo { 1591*5b9c547cSRui Paulo char *pos = start; 1592*5b9c547cSRui Paulo int ret; 1593*5b9c547cSRui Paulo 1594*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_CCMP_256) { 1595*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sCCMP-256", 1596*5b9c547cSRui Paulo pos == start ? "" : delim); 1597*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1598*5b9c547cSRui Paulo return -1; 1599*5b9c547cSRui Paulo pos += ret; 1600*5b9c547cSRui Paulo } 1601*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GCMP_256) { 1602*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sGCMP-256", 1603*5b9c547cSRui Paulo pos == start ? "" : delim); 1604*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1605*5b9c547cSRui Paulo return -1; 1606*5b9c547cSRui Paulo pos += ret; 1607*5b9c547cSRui Paulo } 1608*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_CCMP) { 1609*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sCCMP", 1610*5b9c547cSRui Paulo pos == start ? "" : delim); 1611*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1612*5b9c547cSRui Paulo return -1; 1613*5b9c547cSRui Paulo pos += ret; 1614*5b9c547cSRui Paulo } 1615*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_GCMP) { 1616*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sGCMP", 1617*5b9c547cSRui Paulo pos == start ? "" : delim); 1618*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1619*5b9c547cSRui Paulo return -1; 1620*5b9c547cSRui Paulo pos += ret; 1621*5b9c547cSRui Paulo } 1622*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_TKIP) { 1623*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sTKIP", 1624*5b9c547cSRui Paulo pos == start ? "" : delim); 1625*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1626*5b9c547cSRui Paulo return -1; 1627*5b9c547cSRui Paulo pos += ret; 1628*5b9c547cSRui Paulo } 1629*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_WEP104) { 1630*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sWEP104", 1631*5b9c547cSRui Paulo pos == start ? "" : delim); 1632*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1633*5b9c547cSRui Paulo return -1; 1634*5b9c547cSRui Paulo pos += ret; 1635*5b9c547cSRui Paulo } 1636*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_WEP40) { 1637*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sWEP40", 1638*5b9c547cSRui Paulo pos == start ? "" : delim); 1639*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1640*5b9c547cSRui Paulo return -1; 1641*5b9c547cSRui Paulo pos += ret; 1642*5b9c547cSRui Paulo } 1643*5b9c547cSRui Paulo if (ciphers & WPA_CIPHER_NONE) { 1644*5b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "%sNONE", 1645*5b9c547cSRui Paulo pos == start ? "" : delim); 1646*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) 1647*5b9c547cSRui Paulo return -1; 1648*5b9c547cSRui Paulo pos += ret; 1649*5b9c547cSRui Paulo } 1650*5b9c547cSRui Paulo 1651*5b9c547cSRui Paulo return pos - start; 1652*5b9c547cSRui Paulo } 1653*5b9c547cSRui Paulo 1654*5b9c547cSRui Paulo 1655*5b9c547cSRui Paulo int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise) 1656*5b9c547cSRui Paulo { 1657*5b9c547cSRui Paulo int pairwise = 0; 1658*5b9c547cSRui Paulo 1659*5b9c547cSRui Paulo /* Select group cipher based on the enabled pairwise cipher suites */ 1660*5b9c547cSRui Paulo if (wpa & 1) 1661*5b9c547cSRui Paulo pairwise |= wpa_pairwise; 1662*5b9c547cSRui Paulo if (wpa & 2) 1663*5b9c547cSRui Paulo pairwise |= rsn_pairwise; 1664*5b9c547cSRui Paulo 1665*5b9c547cSRui Paulo if (pairwise & WPA_CIPHER_TKIP) 1666*5b9c547cSRui Paulo return WPA_CIPHER_TKIP; 1667*5b9c547cSRui Paulo if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP) 1668*5b9c547cSRui Paulo return WPA_CIPHER_GCMP; 1669*5b9c547cSRui Paulo if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP | 1670*5b9c547cSRui Paulo WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256) 1671*5b9c547cSRui Paulo return WPA_CIPHER_GCMP_256; 1672*5b9c547cSRui Paulo if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP | 1673*5b9c547cSRui Paulo WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256) 1674*5b9c547cSRui Paulo return WPA_CIPHER_CCMP_256; 1675*5b9c547cSRui Paulo return WPA_CIPHER_CCMP; 1676f05cddf9SRui Paulo } 1677