139beb93cSSam Leffler /* 239beb93cSSam Leffler * wpa_supplicant - WPA/RSN IE and KDE processing 339beb93cSSam Leffler * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "wpa.h" 1339beb93cSSam Leffler #include "pmksa_cache.h" 14e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 1539beb93cSSam Leffler #include "wpa_i.h" 1639beb93cSSam Leffler #include "wpa_ie.h" 1739beb93cSSam Leffler 1839beb93cSSam Leffler 1939beb93cSSam Leffler /** 2039beb93cSSam Leffler * wpa_parse_wpa_ie - Parse WPA/RSN IE 2139beb93cSSam Leffler * @wpa_ie: Pointer to WPA or RSN IE 2239beb93cSSam Leffler * @wpa_ie_len: Length of the WPA/RSN IE 2339beb93cSSam Leffler * @data: Pointer to data area for parsing results 2439beb93cSSam Leffler * Returns: 0 on success, -1 on failure 2539beb93cSSam Leffler * 2639beb93cSSam Leffler * Parse the contents of WPA or RSN IE and write the parsed data into data. 2739beb93cSSam Leffler */ 2839beb93cSSam Leffler int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, 2939beb93cSSam Leffler struct wpa_ie_data *data) 3039beb93cSSam Leffler { 3139beb93cSSam Leffler if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) 3239beb93cSSam Leffler return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); 3339beb93cSSam Leffler else 3439beb93cSSam Leffler return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); 3539beb93cSSam Leffler } 3639beb93cSSam Leffler 3739beb93cSSam Leffler 3839beb93cSSam Leffler static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, 3939beb93cSSam Leffler int pairwise_cipher, int group_cipher, 4039beb93cSSam Leffler int key_mgmt) 4139beb93cSSam Leffler { 4239beb93cSSam Leffler u8 *pos; 4339beb93cSSam Leffler struct wpa_ie_hdr *hdr; 44*f05cddf9SRui Paulo u32 suite; 4539beb93cSSam Leffler 4639beb93cSSam Leffler if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 4739beb93cSSam Leffler 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) 4839beb93cSSam Leffler return -1; 4939beb93cSSam Leffler 5039beb93cSSam Leffler hdr = (struct wpa_ie_hdr *) wpa_ie; 5139beb93cSSam Leffler hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; 5239beb93cSSam Leffler RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); 5339beb93cSSam Leffler WPA_PUT_LE16(hdr->version, WPA_VERSION); 5439beb93cSSam Leffler pos = (u8 *) (hdr + 1); 5539beb93cSSam Leffler 56*f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher); 57*f05cddf9SRui Paulo if (suite == 0) { 5839beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 5939beb93cSSam Leffler group_cipher); 6039beb93cSSam Leffler return -1; 6139beb93cSSam Leffler } 62*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 6339beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 6439beb93cSSam Leffler 6539beb93cSSam Leffler *pos++ = 1; 6639beb93cSSam Leffler *pos++ = 0; 67*f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher); 68*f05cddf9SRui Paulo if (suite == 0 || 69*f05cddf9SRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 70*f05cddf9SRui Paulo pairwise_cipher != WPA_CIPHER_NONE)) { 7139beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 7239beb93cSSam Leffler pairwise_cipher); 7339beb93cSSam Leffler return -1; 7439beb93cSSam Leffler } 75*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 7639beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 7739beb93cSSam Leffler 7839beb93cSSam Leffler *pos++ = 1; 7939beb93cSSam Leffler *pos++ = 0; 8039beb93cSSam Leffler if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 8139beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 8239beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 8339beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 8439beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { 8539beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); 86*f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 87*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM); 8839beb93cSSam Leffler } else { 8939beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 9039beb93cSSam Leffler key_mgmt); 9139beb93cSSam Leffler return -1; 9239beb93cSSam Leffler } 9339beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 9439beb93cSSam Leffler 9539beb93cSSam Leffler /* WPA Capabilities; use defaults, so no need to include it */ 9639beb93cSSam Leffler 9739beb93cSSam Leffler hdr->len = (pos - wpa_ie) - 2; 9839beb93cSSam Leffler 9939beb93cSSam Leffler WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 10039beb93cSSam Leffler 10139beb93cSSam Leffler return pos - wpa_ie; 10239beb93cSSam Leffler } 10339beb93cSSam Leffler 10439beb93cSSam Leffler 10539beb93cSSam Leffler static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, 10639beb93cSSam Leffler int pairwise_cipher, int group_cipher, 10739beb93cSSam Leffler int key_mgmt, int mgmt_group_cipher, 10839beb93cSSam Leffler struct wpa_sm *sm) 10939beb93cSSam Leffler { 11039beb93cSSam Leffler #ifndef CONFIG_NO_WPA2 11139beb93cSSam Leffler u8 *pos; 11239beb93cSSam Leffler struct rsn_ie_hdr *hdr; 11339beb93cSSam Leffler u16 capab; 114*f05cddf9SRui Paulo u32 suite; 11539beb93cSSam Leffler 11639beb93cSSam Leffler if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 11739beb93cSSam Leffler 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + 11839beb93cSSam Leffler (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { 11939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", 12039beb93cSSam Leffler (unsigned long) rsn_ie_len); 12139beb93cSSam Leffler return -1; 12239beb93cSSam Leffler } 12339beb93cSSam Leffler 12439beb93cSSam Leffler hdr = (struct rsn_ie_hdr *) rsn_ie; 12539beb93cSSam Leffler hdr->elem_id = WLAN_EID_RSN; 12639beb93cSSam Leffler WPA_PUT_LE16(hdr->version, RSN_VERSION); 12739beb93cSSam Leffler pos = (u8 *) (hdr + 1); 12839beb93cSSam Leffler 129*f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); 130*f05cddf9SRui Paulo if (suite == 0) { 13139beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 13239beb93cSSam Leffler group_cipher); 13339beb93cSSam Leffler return -1; 13439beb93cSSam Leffler } 135*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 13639beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 13739beb93cSSam Leffler 13839beb93cSSam Leffler *pos++ = 1; 13939beb93cSSam Leffler *pos++ = 0; 140*f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); 141*f05cddf9SRui Paulo if (suite == 0 || 142*f05cddf9SRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 143*f05cddf9SRui Paulo pairwise_cipher != WPA_CIPHER_NONE)) { 14439beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 14539beb93cSSam Leffler pairwise_cipher); 14639beb93cSSam Leffler return -1; 14739beb93cSSam Leffler } 148*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 14939beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 15039beb93cSSam Leffler 15139beb93cSSam Leffler *pos++ = 1; 15239beb93cSSam Leffler *pos++ = 0; 15339beb93cSSam Leffler if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 15439beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 15539beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 15639beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 157*f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 158*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM); 15939beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 16039beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { 16139beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 16239beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { 16339beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 16439beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 16539beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 16639beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { 16739beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 16839beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { 16939beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 17039beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 171*f05cddf9SRui Paulo #ifdef CONFIG_SAE 172*f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_SAE) { 173*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); 174*f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { 175*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); 176*f05cddf9SRui Paulo #endif /* CONFIG_SAE */ 17739beb93cSSam Leffler } else { 17839beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 17939beb93cSSam Leffler key_mgmt); 18039beb93cSSam Leffler return -1; 18139beb93cSSam Leffler } 18239beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 18339beb93cSSam Leffler 18439beb93cSSam Leffler /* RSN Capabilities */ 18539beb93cSSam Leffler capab = 0; 18639beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 187e28a4053SRui Paulo if (sm->mfp) 18839beb93cSSam Leffler capab |= WPA_CAPABILITY_MFPC; 189e28a4053SRui Paulo if (sm->mfp == 2) 190e28a4053SRui Paulo capab |= WPA_CAPABILITY_MFPR; 19139beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 19239beb93cSSam Leffler WPA_PUT_LE16(pos, capab); 19339beb93cSSam Leffler pos += 2; 19439beb93cSSam Leffler 19539beb93cSSam Leffler if (sm->cur_pmksa) { 19639beb93cSSam Leffler /* PMKID Count (2 octets, little endian) */ 19739beb93cSSam Leffler *pos++ = 1; 19839beb93cSSam Leffler *pos++ = 0; 19939beb93cSSam Leffler /* PMKID */ 20039beb93cSSam Leffler os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 20139beb93cSSam Leffler pos += PMKID_LEN; 20239beb93cSSam Leffler } 20339beb93cSSam Leffler 20439beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 20539beb93cSSam Leffler if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { 20639beb93cSSam Leffler if (!sm->cur_pmksa) { 20739beb93cSSam Leffler /* PMKID Count */ 20839beb93cSSam Leffler WPA_PUT_LE16(pos, 0); 20939beb93cSSam Leffler pos += 2; 21039beb93cSSam Leffler } 21139beb93cSSam Leffler 21239beb93cSSam Leffler /* Management Group Cipher Suite */ 21339beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 21439beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 21539beb93cSSam Leffler } 21639beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 21739beb93cSSam Leffler 21839beb93cSSam Leffler hdr->len = (pos - rsn_ie) - 2; 21939beb93cSSam Leffler 22039beb93cSSam Leffler WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 22139beb93cSSam Leffler 22239beb93cSSam Leffler return pos - rsn_ie; 22339beb93cSSam Leffler #else /* CONFIG_NO_WPA2 */ 22439beb93cSSam Leffler return -1; 22539beb93cSSam Leffler #endif /* CONFIG_NO_WPA2 */ 22639beb93cSSam Leffler } 22739beb93cSSam Leffler 22839beb93cSSam Leffler 22939beb93cSSam Leffler /** 23039beb93cSSam Leffler * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 23139beb93cSSam Leffler * @sm: Pointer to WPA state machine data from wpa_sm_init() 23239beb93cSSam Leffler * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 23339beb93cSSam Leffler * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 23439beb93cSSam Leffler * Returns: Length of the generated WPA/RSN IE or -1 on failure 23539beb93cSSam Leffler */ 23639beb93cSSam Leffler int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 23739beb93cSSam Leffler { 23839beb93cSSam Leffler if (sm->proto == WPA_PROTO_RSN) 23939beb93cSSam Leffler return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 24039beb93cSSam Leffler sm->pairwise_cipher, 24139beb93cSSam Leffler sm->group_cipher, 24239beb93cSSam Leffler sm->key_mgmt, sm->mgmt_group_cipher, 24339beb93cSSam Leffler sm); 24439beb93cSSam Leffler else 24539beb93cSSam Leffler return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 24639beb93cSSam Leffler sm->pairwise_cipher, 24739beb93cSSam Leffler sm->group_cipher, 24839beb93cSSam Leffler sm->key_mgmt); 24939beb93cSSam Leffler } 25039beb93cSSam Leffler 25139beb93cSSam Leffler 25239beb93cSSam Leffler /** 25339beb93cSSam Leffler * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 25439beb93cSSam Leffler * @pos: Pointer to the IE header 25539beb93cSSam Leffler * @end: Pointer to the end of the Key Data buffer 25639beb93cSSam Leffler * @ie: Pointer to parsed IE data 25739beb93cSSam Leffler * Returns: 0 on success, 1 if end mark is found, -1 on failure 25839beb93cSSam Leffler */ 25939beb93cSSam Leffler static int wpa_parse_generic(const u8 *pos, const u8 *end, 26039beb93cSSam Leffler struct wpa_eapol_ie_parse *ie) 26139beb93cSSam Leffler { 26239beb93cSSam Leffler if (pos[1] == 0) 26339beb93cSSam Leffler return 1; 26439beb93cSSam Leffler 26539beb93cSSam Leffler if (pos[1] >= 6 && 26639beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 26739beb93cSSam Leffler pos[2 + WPA_SELECTOR_LEN] == 1 && 26839beb93cSSam Leffler pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 26939beb93cSSam Leffler ie->wpa_ie = pos; 27039beb93cSSam Leffler ie->wpa_ie_len = pos[1] + 2; 271e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", 272e28a4053SRui Paulo ie->wpa_ie, ie->wpa_ie_len); 27339beb93cSSam Leffler return 0; 27439beb93cSSam Leffler } 27539beb93cSSam Leffler 27639beb93cSSam Leffler if (pos + 1 + RSN_SELECTOR_LEN < end && 27739beb93cSSam Leffler pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 27839beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 27939beb93cSSam Leffler ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 280e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", 281e28a4053SRui Paulo pos, pos[1] + 2); 28239beb93cSSam Leffler return 0; 28339beb93cSSam Leffler } 28439beb93cSSam Leffler 28539beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 28639beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 28739beb93cSSam Leffler ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 28839beb93cSSam Leffler ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 289e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", 290e28a4053SRui Paulo pos, pos[1] + 2); 29139beb93cSSam Leffler return 0; 29239beb93cSSam Leffler } 29339beb93cSSam Leffler 29439beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 29539beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 29639beb93cSSam Leffler ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 29739beb93cSSam Leffler ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 298e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", 299e28a4053SRui Paulo pos, pos[1] + 2); 30039beb93cSSam Leffler return 0; 30139beb93cSSam Leffler } 30239beb93cSSam Leffler 30339beb93cSSam Leffler #ifdef CONFIG_PEERKEY 30439beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 30539beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 30639beb93cSSam Leffler ie->smk = pos + 2 + RSN_SELECTOR_LEN; 30739beb93cSSam Leffler ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 308e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", 309e28a4053SRui Paulo pos, pos[1] + 2); 31039beb93cSSam Leffler return 0; 31139beb93cSSam Leffler } 31239beb93cSSam Leffler 31339beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 31439beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 31539beb93cSSam Leffler ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 31639beb93cSSam Leffler ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 317e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", 318e28a4053SRui Paulo pos, pos[1] + 2); 31939beb93cSSam Leffler return 0; 32039beb93cSSam Leffler } 32139beb93cSSam Leffler 32239beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 32339beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 32439beb93cSSam Leffler ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 32539beb93cSSam Leffler ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 326e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", 327e28a4053SRui Paulo pos, pos[1] + 2); 32839beb93cSSam Leffler return 0; 32939beb93cSSam Leffler } 33039beb93cSSam Leffler 33139beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 33239beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 33339beb93cSSam Leffler ie->error = pos + 2 + RSN_SELECTOR_LEN; 33439beb93cSSam Leffler ie->error_len = pos[1] - RSN_SELECTOR_LEN; 335e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", 336e28a4053SRui Paulo pos, pos[1] + 2); 33739beb93cSSam Leffler return 0; 33839beb93cSSam Leffler } 33939beb93cSSam Leffler #endif /* CONFIG_PEERKEY */ 34039beb93cSSam Leffler 34139beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 34239beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 34339beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 34439beb93cSSam Leffler ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 34539beb93cSSam Leffler ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 346e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", 347e28a4053SRui Paulo pos, pos[1] + 2); 34839beb93cSSam Leffler return 0; 34939beb93cSSam Leffler } 35039beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 35139beb93cSSam Leffler 35239beb93cSSam Leffler return 0; 35339beb93cSSam Leffler } 35439beb93cSSam Leffler 35539beb93cSSam Leffler 35639beb93cSSam Leffler /** 35739beb93cSSam Leffler * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs 35839beb93cSSam Leffler * @buf: Pointer to the Key Data buffer 35939beb93cSSam Leffler * @len: Key Data Length 36039beb93cSSam Leffler * @ie: Pointer to parsed IE data 36139beb93cSSam Leffler * Returns: 0 on success, -1 on failure 36239beb93cSSam Leffler */ 36339beb93cSSam Leffler int wpa_supplicant_parse_ies(const u8 *buf, size_t len, 36439beb93cSSam Leffler struct wpa_eapol_ie_parse *ie) 36539beb93cSSam Leffler { 36639beb93cSSam Leffler const u8 *pos, *end; 36739beb93cSSam Leffler int ret = 0; 36839beb93cSSam Leffler 36939beb93cSSam Leffler os_memset(ie, 0, sizeof(*ie)); 37039beb93cSSam Leffler for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 37139beb93cSSam Leffler if (pos[0] == 0xdd && 37239beb93cSSam Leffler ((pos == buf + len - 1) || pos[1] == 0)) { 37339beb93cSSam Leffler /* Ignore padding */ 37439beb93cSSam Leffler break; 37539beb93cSSam Leffler } 37639beb93cSSam Leffler if (pos + 2 + pos[1] > end) { 37739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 37839beb93cSSam Leffler "underflow (ie=%d len=%d pos=%d)", 37939beb93cSSam Leffler pos[0], pos[1], (int) (pos - buf)); 38039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 38139beb93cSSam Leffler buf, len); 38239beb93cSSam Leffler ret = -1; 38339beb93cSSam Leffler break; 38439beb93cSSam Leffler } 38539beb93cSSam Leffler if (*pos == WLAN_EID_RSN) { 38639beb93cSSam Leffler ie->rsn_ie = pos; 38739beb93cSSam Leffler ie->rsn_ie_len = pos[1] + 2; 388e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", 389e28a4053SRui Paulo ie->rsn_ie, ie->rsn_ie_len); 39039beb93cSSam Leffler } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 39139beb93cSSam Leffler ie->mdie = pos; 39239beb93cSSam Leffler ie->mdie_len = pos[1] + 2; 393e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", 394e28a4053SRui Paulo ie->mdie, ie->mdie_len); 395e28a4053SRui Paulo } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 396e28a4053SRui Paulo ie->ftie = pos; 397e28a4053SRui Paulo ie->ftie_len = pos[1] + 2; 398e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", 399e28a4053SRui Paulo ie->ftie, ie->ftie_len); 400e28a4053SRui Paulo } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { 401e28a4053SRui Paulo if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { 402e28a4053SRui Paulo ie->reassoc_deadline = pos; 403e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " 404e28a4053SRui Paulo "in EAPOL-Key", 405e28a4053SRui Paulo ie->reassoc_deadline, pos[1] + 2); 406e28a4053SRui Paulo } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { 407e28a4053SRui Paulo ie->key_lifetime = pos; 408e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " 409e28a4053SRui Paulo "in EAPOL-Key", 410e28a4053SRui Paulo ie->key_lifetime, pos[1] + 2); 411e28a4053SRui Paulo } else { 412e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " 413e28a4053SRui Paulo "EAPOL-Key Key Data IE", 414e28a4053SRui Paulo pos, 2 + pos[1]); 415e28a4053SRui Paulo } 416*f05cddf9SRui Paulo } else if (*pos == WLAN_EID_LINK_ID) { 417*f05cddf9SRui Paulo if (pos[1] >= 18) { 418*f05cddf9SRui Paulo ie->lnkid = pos; 419*f05cddf9SRui Paulo ie->lnkid_len = pos[1] + 2; 420*f05cddf9SRui Paulo } 421*f05cddf9SRui Paulo } else if (*pos == WLAN_EID_EXT_CAPAB) { 422*f05cddf9SRui Paulo ie->ext_capab = pos; 423*f05cddf9SRui Paulo ie->ext_capab_len = pos[1] + 2; 424*f05cddf9SRui Paulo } else if (*pos == WLAN_EID_SUPP_RATES) { 425*f05cddf9SRui Paulo ie->supp_rates = pos; 426*f05cddf9SRui Paulo ie->supp_rates_len = pos[1] + 2; 427*f05cddf9SRui Paulo } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { 428*f05cddf9SRui Paulo ie->ext_supp_rates = pos; 429*f05cddf9SRui Paulo ie->ext_supp_rates_len = pos[1] + 2; 43039beb93cSSam Leffler } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 43139beb93cSSam Leffler ret = wpa_parse_generic(pos, end, ie); 43239beb93cSSam Leffler if (ret < 0) 43339beb93cSSam Leffler break; 43439beb93cSSam Leffler if (ret > 0) { 43539beb93cSSam Leffler ret = 0; 43639beb93cSSam Leffler break; 43739beb93cSSam Leffler } 43839beb93cSSam Leffler } else { 43939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 44039beb93cSSam Leffler "Key Data IE", pos, 2 + pos[1]); 44139beb93cSSam Leffler } 44239beb93cSSam Leffler } 44339beb93cSSam Leffler 44439beb93cSSam Leffler return ret; 44539beb93cSSam Leffler } 446