139beb93cSSam Leffler /* 239beb93cSSam Leffler * wpa_supplicant - WPA/RSN IE and KDE processing 3*5b9c547cSRui Paulo * Copyright (c) 2003-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" 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; 44f05cddf9SRui 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 56f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher); 57f05cddf9SRui Paulo if (suite == 0) { 5839beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 5939beb93cSSam Leffler group_cipher); 6039beb93cSSam Leffler return -1; 6139beb93cSSam Leffler } 62f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 6339beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 6439beb93cSSam Leffler 6539beb93cSSam Leffler *pos++ = 1; 6639beb93cSSam Leffler *pos++ = 0; 67f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher); 68f05cddf9SRui Paulo if (suite == 0 || 69f05cddf9SRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 70f05cddf9SRui 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 } 75f05cddf9SRui 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); 86f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 87f05cddf9SRui 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 u8 *pos; 11139beb93cSSam Leffler struct rsn_ie_hdr *hdr; 11239beb93cSSam Leffler u16 capab; 113f05cddf9SRui Paulo u32 suite; 11439beb93cSSam Leffler 11539beb93cSSam Leffler if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 11639beb93cSSam Leffler 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + 11739beb93cSSam Leffler (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { 11839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", 11939beb93cSSam Leffler (unsigned long) rsn_ie_len); 12039beb93cSSam Leffler return -1; 12139beb93cSSam Leffler } 12239beb93cSSam Leffler 12339beb93cSSam Leffler hdr = (struct rsn_ie_hdr *) rsn_ie; 12439beb93cSSam Leffler hdr->elem_id = WLAN_EID_RSN; 12539beb93cSSam Leffler WPA_PUT_LE16(hdr->version, RSN_VERSION); 12639beb93cSSam Leffler pos = (u8 *) (hdr + 1); 12739beb93cSSam Leffler 128f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); 129f05cddf9SRui Paulo if (suite == 0) { 13039beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 13139beb93cSSam Leffler group_cipher); 13239beb93cSSam Leffler return -1; 13339beb93cSSam Leffler } 134f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 13539beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 13639beb93cSSam Leffler 13739beb93cSSam Leffler *pos++ = 1; 13839beb93cSSam Leffler *pos++ = 0; 139f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); 140f05cddf9SRui Paulo if (suite == 0 || 141f05cddf9SRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 142f05cddf9SRui Paulo pairwise_cipher != WPA_CIPHER_NONE)) { 14339beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 14439beb93cSSam Leffler pairwise_cipher); 14539beb93cSSam Leffler return -1; 14639beb93cSSam Leffler } 147f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 14839beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 14939beb93cSSam Leffler 15039beb93cSSam Leffler *pos++ = 1; 15139beb93cSSam Leffler *pos++ = 0; 15239beb93cSSam Leffler if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 15339beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 15439beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 15539beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 156f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 157f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM); 15839beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 15939beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { 16039beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 16139beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { 16239beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 16339beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 16439beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 16539beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { 16639beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 16739beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { 16839beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 16939beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 170f05cddf9SRui Paulo #ifdef CONFIG_SAE 171f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_SAE) { 172f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); 173f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { 174f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); 175f05cddf9SRui Paulo #endif /* CONFIG_SAE */ 176*5b9c547cSRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { 177*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192); 178*5b9c547cSRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 179*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B); 18039beb93cSSam Leffler } else { 18139beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 18239beb93cSSam Leffler key_mgmt); 18339beb93cSSam Leffler return -1; 18439beb93cSSam Leffler } 18539beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 18639beb93cSSam Leffler 18739beb93cSSam Leffler /* RSN Capabilities */ 18839beb93cSSam Leffler capab = 0; 18939beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 190e28a4053SRui Paulo if (sm->mfp) 19139beb93cSSam Leffler capab |= WPA_CAPABILITY_MFPC; 192e28a4053SRui Paulo if (sm->mfp == 2) 193e28a4053SRui Paulo capab |= WPA_CAPABILITY_MFPR; 19439beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 19539beb93cSSam Leffler WPA_PUT_LE16(pos, capab); 19639beb93cSSam Leffler pos += 2; 19739beb93cSSam Leffler 19839beb93cSSam Leffler if (sm->cur_pmksa) { 19939beb93cSSam Leffler /* PMKID Count (2 octets, little endian) */ 20039beb93cSSam Leffler *pos++ = 1; 20139beb93cSSam Leffler *pos++ = 0; 20239beb93cSSam Leffler /* PMKID */ 20339beb93cSSam Leffler os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 20439beb93cSSam Leffler pos += PMKID_LEN; 20539beb93cSSam Leffler } 20639beb93cSSam Leffler 20739beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 208*5b9c547cSRui Paulo if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) { 20939beb93cSSam Leffler if (!sm->cur_pmksa) { 21039beb93cSSam Leffler /* PMKID Count */ 21139beb93cSSam Leffler WPA_PUT_LE16(pos, 0); 21239beb93cSSam Leffler pos += 2; 21339beb93cSSam Leffler } 21439beb93cSSam Leffler 21539beb93cSSam Leffler /* Management Group Cipher Suite */ 216*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, 217*5b9c547cSRui Paulo mgmt_group_cipher)); 21839beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 21939beb93cSSam Leffler } 22039beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 22139beb93cSSam Leffler 22239beb93cSSam Leffler hdr->len = (pos - rsn_ie) - 2; 22339beb93cSSam Leffler 22439beb93cSSam Leffler WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 22539beb93cSSam Leffler 22639beb93cSSam Leffler return pos - rsn_ie; 22739beb93cSSam Leffler } 22839beb93cSSam Leffler 22939beb93cSSam Leffler 230*5b9c547cSRui Paulo #ifdef CONFIG_HS20 231*5b9c547cSRui Paulo static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len, 232*5b9c547cSRui Paulo int pairwise_cipher, int group_cipher, 233*5b9c547cSRui Paulo int key_mgmt) 234*5b9c547cSRui Paulo { 235*5b9c547cSRui Paulo u8 *pos, *len; 236*5b9c547cSRui Paulo u32 suite; 237*5b9c547cSRui Paulo 238*5b9c547cSRui Paulo if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN + 239*5b9c547cSRui Paulo 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN) 240*5b9c547cSRui Paulo return -1; 241*5b9c547cSRui Paulo 242*5b9c547cSRui Paulo pos = wpa_ie; 243*5b9c547cSRui Paulo *pos++ = WLAN_EID_VENDOR_SPECIFIC; 244*5b9c547cSRui Paulo len = pos++; /* to be filled */ 245*5b9c547cSRui Paulo WPA_PUT_BE24(pos, OUI_WFA); 246*5b9c547cSRui Paulo pos += 3; 247*5b9c547cSRui Paulo *pos++ = HS20_OSEN_OUI_TYPE; 248*5b9c547cSRui Paulo 249*5b9c547cSRui Paulo /* Group Data Cipher Suite */ 250*5b9c547cSRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); 251*5b9c547cSRui Paulo if (suite == 0) { 252*5b9c547cSRui Paulo wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 253*5b9c547cSRui Paulo group_cipher); 254*5b9c547cSRui Paulo return -1; 255*5b9c547cSRui Paulo } 256*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, suite); 257*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 258*5b9c547cSRui Paulo 259*5b9c547cSRui Paulo /* Pairwise Cipher Suite Count and List */ 260*5b9c547cSRui Paulo WPA_PUT_LE16(pos, 1); 261*5b9c547cSRui Paulo pos += 2; 262*5b9c547cSRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); 263*5b9c547cSRui Paulo if (suite == 0 || 264*5b9c547cSRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 265*5b9c547cSRui Paulo pairwise_cipher != WPA_CIPHER_NONE)) { 266*5b9c547cSRui Paulo wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 267*5b9c547cSRui Paulo pairwise_cipher); 268*5b9c547cSRui Paulo return -1; 269*5b9c547cSRui Paulo } 270*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, suite); 271*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 272*5b9c547cSRui Paulo 273*5b9c547cSRui Paulo /* AKM Suite Count and List */ 274*5b9c547cSRui Paulo WPA_PUT_LE16(pos, 1); 275*5b9c547cSRui Paulo pos += 2; 276*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); 277*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 278*5b9c547cSRui Paulo 279*5b9c547cSRui Paulo *len = pos - len - 1; 280*5b9c547cSRui Paulo 281*5b9c547cSRui Paulo WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 282*5b9c547cSRui Paulo 283*5b9c547cSRui Paulo return pos - wpa_ie; 284*5b9c547cSRui Paulo } 285*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 286*5b9c547cSRui Paulo 287*5b9c547cSRui Paulo 28839beb93cSSam Leffler /** 28939beb93cSSam Leffler * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 29039beb93cSSam Leffler * @sm: Pointer to WPA state machine data from wpa_sm_init() 29139beb93cSSam Leffler * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 29239beb93cSSam Leffler * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 29339beb93cSSam Leffler * Returns: Length of the generated WPA/RSN IE or -1 on failure 29439beb93cSSam Leffler */ 29539beb93cSSam Leffler int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 29639beb93cSSam Leffler { 29739beb93cSSam Leffler if (sm->proto == WPA_PROTO_RSN) 29839beb93cSSam Leffler return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 29939beb93cSSam Leffler sm->pairwise_cipher, 30039beb93cSSam Leffler sm->group_cipher, 30139beb93cSSam Leffler sm->key_mgmt, sm->mgmt_group_cipher, 30239beb93cSSam Leffler sm); 303*5b9c547cSRui Paulo #ifdef CONFIG_HS20 304*5b9c547cSRui Paulo else if (sm->proto == WPA_PROTO_OSEN) 305*5b9c547cSRui Paulo return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len, 306*5b9c547cSRui Paulo sm->pairwise_cipher, 307*5b9c547cSRui Paulo sm->group_cipher, 308*5b9c547cSRui Paulo sm->key_mgmt); 309*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 31039beb93cSSam Leffler else 31139beb93cSSam Leffler return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 31239beb93cSSam Leffler sm->pairwise_cipher, 31339beb93cSSam Leffler sm->group_cipher, 31439beb93cSSam Leffler sm->key_mgmt); 31539beb93cSSam Leffler } 31639beb93cSSam Leffler 31739beb93cSSam Leffler 31839beb93cSSam Leffler /** 319*5b9c547cSRui Paulo * wpa_parse_vendor_specific - Parse Vendor Specific IEs 320*5b9c547cSRui Paulo * @pos: Pointer to the IE header 321*5b9c547cSRui Paulo * @end: Pointer to the end of the Key Data buffer 322*5b9c547cSRui Paulo * @ie: Pointer to parsed IE data 323*5b9c547cSRui Paulo * Returns: 0 on success, 1 if end mark is found, -1 on failure 324*5b9c547cSRui Paulo */ 325*5b9c547cSRui Paulo static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end, 326*5b9c547cSRui Paulo struct wpa_eapol_ie_parse *ie) 327*5b9c547cSRui Paulo { 328*5b9c547cSRui Paulo unsigned int oui; 329*5b9c547cSRui Paulo 330*5b9c547cSRui Paulo if (pos[1] < 4) { 331*5b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)", 332*5b9c547cSRui Paulo pos[1]); 333*5b9c547cSRui Paulo return 1; 334*5b9c547cSRui Paulo } 335*5b9c547cSRui Paulo 336*5b9c547cSRui Paulo oui = WPA_GET_BE24(&pos[2]); 337*5b9c547cSRui Paulo if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) { 338*5b9c547cSRui Paulo if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) { 339*5b9c547cSRui Paulo ie->wmm = &pos[2]; 340*5b9c547cSRui Paulo ie->wmm_len = pos[1]; 341*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: WMM IE", 342*5b9c547cSRui Paulo ie->wmm, ie->wmm_len); 343*5b9c547cSRui Paulo } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) { 344*5b9c547cSRui Paulo ie->wmm = &pos[2]; 345*5b9c547cSRui Paulo ie->wmm_len = pos[1]; 346*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element", 347*5b9c547cSRui Paulo ie->wmm, ie->wmm_len); 348*5b9c547cSRui Paulo } 349*5b9c547cSRui Paulo } 350*5b9c547cSRui Paulo return 0; 351*5b9c547cSRui Paulo } 352*5b9c547cSRui Paulo 353*5b9c547cSRui Paulo 354*5b9c547cSRui Paulo /** 35539beb93cSSam Leffler * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 35639beb93cSSam Leffler * @pos: Pointer to the IE header 35739beb93cSSam Leffler * @end: Pointer to the end of the Key Data buffer 35839beb93cSSam Leffler * @ie: Pointer to parsed IE data 35939beb93cSSam Leffler * Returns: 0 on success, 1 if end mark is found, -1 on failure 36039beb93cSSam Leffler */ 36139beb93cSSam Leffler static int wpa_parse_generic(const u8 *pos, const u8 *end, 36239beb93cSSam Leffler struct wpa_eapol_ie_parse *ie) 36339beb93cSSam Leffler { 36439beb93cSSam Leffler if (pos[1] == 0) 36539beb93cSSam Leffler return 1; 36639beb93cSSam Leffler 36739beb93cSSam Leffler if (pos[1] >= 6 && 36839beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 36939beb93cSSam Leffler pos[2 + WPA_SELECTOR_LEN] == 1 && 37039beb93cSSam Leffler pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 37139beb93cSSam Leffler ie->wpa_ie = pos; 37239beb93cSSam Leffler ie->wpa_ie_len = pos[1] + 2; 373e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", 374e28a4053SRui Paulo ie->wpa_ie, ie->wpa_ie_len); 37539beb93cSSam Leffler return 0; 37639beb93cSSam Leffler } 37739beb93cSSam Leffler 37839beb93cSSam Leffler if (pos + 1 + RSN_SELECTOR_LEN < end && 37939beb93cSSam Leffler pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 38039beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 38139beb93cSSam Leffler ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 382e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", 383e28a4053SRui Paulo pos, pos[1] + 2); 38439beb93cSSam Leffler return 0; 38539beb93cSSam Leffler } 38639beb93cSSam Leffler 38739beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 38839beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 38939beb93cSSam Leffler ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 39039beb93cSSam Leffler ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 391e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", 392e28a4053SRui Paulo pos, pos[1] + 2); 39339beb93cSSam Leffler return 0; 39439beb93cSSam Leffler } 39539beb93cSSam Leffler 39639beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 39739beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 39839beb93cSSam Leffler ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 39939beb93cSSam Leffler ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 400e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", 401e28a4053SRui Paulo pos, pos[1] + 2); 40239beb93cSSam Leffler return 0; 40339beb93cSSam Leffler } 40439beb93cSSam Leffler 40539beb93cSSam Leffler #ifdef CONFIG_PEERKEY 40639beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 40739beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 40839beb93cSSam Leffler ie->smk = pos + 2 + RSN_SELECTOR_LEN; 40939beb93cSSam Leffler ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 410e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", 411e28a4053SRui Paulo pos, pos[1] + 2); 41239beb93cSSam Leffler return 0; 41339beb93cSSam Leffler } 41439beb93cSSam Leffler 41539beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 41639beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 41739beb93cSSam Leffler ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 41839beb93cSSam Leffler ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 419e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", 420e28a4053SRui Paulo pos, pos[1] + 2); 42139beb93cSSam Leffler return 0; 42239beb93cSSam Leffler } 42339beb93cSSam Leffler 42439beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 42539beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 42639beb93cSSam Leffler ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 42739beb93cSSam Leffler ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 428e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", 429e28a4053SRui Paulo pos, pos[1] + 2); 43039beb93cSSam Leffler return 0; 43139beb93cSSam Leffler } 43239beb93cSSam Leffler 43339beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 43439beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 43539beb93cSSam Leffler ie->error = pos + 2 + RSN_SELECTOR_LEN; 43639beb93cSSam Leffler ie->error_len = pos[1] - RSN_SELECTOR_LEN; 437e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", 438e28a4053SRui Paulo pos, pos[1] + 2); 43939beb93cSSam Leffler return 0; 44039beb93cSSam Leffler } 44139beb93cSSam Leffler #endif /* CONFIG_PEERKEY */ 44239beb93cSSam Leffler 44339beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 44439beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 44539beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 44639beb93cSSam Leffler ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 44739beb93cSSam Leffler ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 448e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", 449e28a4053SRui Paulo pos, pos[1] + 2); 45039beb93cSSam Leffler return 0; 45139beb93cSSam Leffler } 45239beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 45339beb93cSSam Leffler 454*5b9c547cSRui Paulo #ifdef CONFIG_P2P 455*5b9c547cSRui Paulo if (pos[1] >= RSN_SELECTOR_LEN + 1 && 456*5b9c547cSRui Paulo RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { 457*5b9c547cSRui Paulo ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; 458*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", 459*5b9c547cSRui Paulo ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN); 460*5b9c547cSRui Paulo return 0; 461*5b9c547cSRui Paulo } 462*5b9c547cSRui Paulo 463*5b9c547cSRui Paulo if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 && 464*5b9c547cSRui Paulo RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) { 465*5b9c547cSRui Paulo ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN; 466*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, 467*5b9c547cSRui Paulo "WPA: IP Address Allocation in EAPOL-Key", 468*5b9c547cSRui Paulo ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN); 469*5b9c547cSRui Paulo return 0; 470*5b9c547cSRui Paulo } 471*5b9c547cSRui Paulo #endif /* CONFIG_P2P */ 472*5b9c547cSRui Paulo 47339beb93cSSam Leffler return 0; 47439beb93cSSam Leffler } 47539beb93cSSam Leffler 47639beb93cSSam Leffler 47739beb93cSSam Leffler /** 47839beb93cSSam Leffler * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs 47939beb93cSSam Leffler * @buf: Pointer to the Key Data buffer 48039beb93cSSam Leffler * @len: Key Data Length 48139beb93cSSam Leffler * @ie: Pointer to parsed IE data 48239beb93cSSam Leffler * Returns: 0 on success, -1 on failure 48339beb93cSSam Leffler */ 48439beb93cSSam Leffler int wpa_supplicant_parse_ies(const u8 *buf, size_t len, 48539beb93cSSam Leffler struct wpa_eapol_ie_parse *ie) 48639beb93cSSam Leffler { 48739beb93cSSam Leffler const u8 *pos, *end; 48839beb93cSSam Leffler int ret = 0; 48939beb93cSSam Leffler 49039beb93cSSam Leffler os_memset(ie, 0, sizeof(*ie)); 49139beb93cSSam Leffler for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 49239beb93cSSam Leffler if (pos[0] == 0xdd && 49339beb93cSSam Leffler ((pos == buf + len - 1) || pos[1] == 0)) { 49439beb93cSSam Leffler /* Ignore padding */ 49539beb93cSSam Leffler break; 49639beb93cSSam Leffler } 49739beb93cSSam Leffler if (pos + 2 + pos[1] > end) { 49839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 49939beb93cSSam Leffler "underflow (ie=%d len=%d pos=%d)", 50039beb93cSSam Leffler pos[0], pos[1], (int) (pos - buf)); 50139beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 50239beb93cSSam Leffler buf, len); 50339beb93cSSam Leffler ret = -1; 50439beb93cSSam Leffler break; 50539beb93cSSam Leffler } 50639beb93cSSam Leffler if (*pos == WLAN_EID_RSN) { 50739beb93cSSam Leffler ie->rsn_ie = pos; 50839beb93cSSam Leffler ie->rsn_ie_len = pos[1] + 2; 509e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", 510e28a4053SRui Paulo ie->rsn_ie, ie->rsn_ie_len); 51139beb93cSSam Leffler } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 51239beb93cSSam Leffler ie->mdie = pos; 51339beb93cSSam Leffler ie->mdie_len = pos[1] + 2; 514e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", 515e28a4053SRui Paulo ie->mdie, ie->mdie_len); 516e28a4053SRui Paulo } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 517e28a4053SRui Paulo ie->ftie = pos; 518e28a4053SRui Paulo ie->ftie_len = pos[1] + 2; 519e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", 520e28a4053SRui Paulo ie->ftie, ie->ftie_len); 521e28a4053SRui Paulo } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { 522e28a4053SRui Paulo if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { 523e28a4053SRui Paulo ie->reassoc_deadline = pos; 524e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " 525e28a4053SRui Paulo "in EAPOL-Key", 526e28a4053SRui Paulo ie->reassoc_deadline, pos[1] + 2); 527e28a4053SRui Paulo } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { 528e28a4053SRui Paulo ie->key_lifetime = pos; 529e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " 530e28a4053SRui Paulo "in EAPOL-Key", 531e28a4053SRui Paulo ie->key_lifetime, pos[1] + 2); 532e28a4053SRui Paulo } else { 533e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " 534e28a4053SRui Paulo "EAPOL-Key Key Data IE", 535e28a4053SRui Paulo pos, 2 + pos[1]); 536e28a4053SRui Paulo } 537f05cddf9SRui Paulo } else if (*pos == WLAN_EID_LINK_ID) { 538f05cddf9SRui Paulo if (pos[1] >= 18) { 539f05cddf9SRui Paulo ie->lnkid = pos; 540f05cddf9SRui Paulo ie->lnkid_len = pos[1] + 2; 541f05cddf9SRui Paulo } 542f05cddf9SRui Paulo } else if (*pos == WLAN_EID_EXT_CAPAB) { 543f05cddf9SRui Paulo ie->ext_capab = pos; 544f05cddf9SRui Paulo ie->ext_capab_len = pos[1] + 2; 545f05cddf9SRui Paulo } else if (*pos == WLAN_EID_SUPP_RATES) { 546f05cddf9SRui Paulo ie->supp_rates = pos; 547f05cddf9SRui Paulo ie->supp_rates_len = pos[1] + 2; 548f05cddf9SRui Paulo } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { 549f05cddf9SRui Paulo ie->ext_supp_rates = pos; 550f05cddf9SRui Paulo ie->ext_supp_rates_len = pos[1] + 2; 551*5b9c547cSRui Paulo } else if (*pos == WLAN_EID_HT_CAP) { 552*5b9c547cSRui Paulo ie->ht_capabilities = pos + 2; 553*5b9c547cSRui Paulo ie->ht_capabilities_len = pos[1]; 554*5b9c547cSRui Paulo } else if (*pos == WLAN_EID_VHT_AID) { 555*5b9c547cSRui Paulo if (pos[1] >= 2) 556*5b9c547cSRui Paulo ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff; 557*5b9c547cSRui Paulo } else if (*pos == WLAN_EID_VHT_CAP) { 558*5b9c547cSRui Paulo ie->vht_capabilities = pos + 2; 559*5b9c547cSRui Paulo ie->vht_capabilities_len = pos[1]; 560*5b9c547cSRui Paulo } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) { 561*5b9c547cSRui Paulo ie->qosinfo = pos[2]; 562*5b9c547cSRui Paulo } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) { 563*5b9c547cSRui Paulo ie->supp_channels = pos + 2; 564*5b9c547cSRui Paulo ie->supp_channels_len = pos[1]; 565*5b9c547cSRui Paulo } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) { 566*5b9c547cSRui Paulo /* 567*5b9c547cSRui Paulo * The value of the Length field of the Supported 568*5b9c547cSRui Paulo * Operating Classes element is between 2 and 253. 569*5b9c547cSRui Paulo * Silently skip invalid elements to avoid interop 570*5b9c547cSRui Paulo * issues when trying to use the value. 571*5b9c547cSRui Paulo */ 572*5b9c547cSRui Paulo if (pos[1] >= 2 && pos[1] <= 253) { 573*5b9c547cSRui Paulo ie->supp_oper_classes = pos + 2; 574*5b9c547cSRui Paulo ie->supp_oper_classes_len = pos[1]; 575*5b9c547cSRui Paulo } 57639beb93cSSam Leffler } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 57739beb93cSSam Leffler ret = wpa_parse_generic(pos, end, ie); 57839beb93cSSam Leffler if (ret < 0) 57939beb93cSSam Leffler break; 58039beb93cSSam Leffler if (ret > 0) { 58139beb93cSSam Leffler ret = 0; 58239beb93cSSam Leffler break; 58339beb93cSSam Leffler } 584*5b9c547cSRui Paulo 585*5b9c547cSRui Paulo ret = wpa_parse_vendor_specific(pos, end, ie); 586*5b9c547cSRui Paulo if (ret < 0) 587*5b9c547cSRui Paulo break; 588*5b9c547cSRui Paulo if (ret > 0) { 589*5b9c547cSRui Paulo ret = 0; 590*5b9c547cSRui Paulo break; 591*5b9c547cSRui Paulo } 59239beb93cSSam Leffler } else { 59339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 59439beb93cSSam Leffler "Key Data IE", pos, 2 + pos[1]); 59539beb93cSSam Leffler } 59639beb93cSSam Leffler } 59739beb93cSSam Leffler 59839beb93cSSam Leffler return ret; 59939beb93cSSam Leffler } 600