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 * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler #include "common.h" 1839beb93cSSam Leffler #include "wpa.h" 1939beb93cSSam Leffler #include "pmksa_cache.h" 20*e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 2139beb93cSSam Leffler #include "wpa_i.h" 2239beb93cSSam Leffler #include "wpa_ie.h" 2339beb93cSSam Leffler 2439beb93cSSam Leffler 2539beb93cSSam Leffler static int wpa_selector_to_bitfield(const u8 *s) 2639beb93cSSam Leffler { 2739beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) 2839beb93cSSam Leffler return WPA_CIPHER_NONE; 2939beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) 3039beb93cSSam Leffler return WPA_CIPHER_WEP40; 3139beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) 3239beb93cSSam Leffler return WPA_CIPHER_TKIP; 3339beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) 3439beb93cSSam Leffler return WPA_CIPHER_CCMP; 3539beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) 3639beb93cSSam Leffler return WPA_CIPHER_WEP104; 3739beb93cSSam Leffler return 0; 3839beb93cSSam Leffler } 3939beb93cSSam Leffler 4039beb93cSSam Leffler 4139beb93cSSam Leffler static int wpa_key_mgmt_to_bitfield(const u8 *s) 4239beb93cSSam Leffler { 4339beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) 4439beb93cSSam Leffler return WPA_KEY_MGMT_IEEE8021X; 4539beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) 4639beb93cSSam Leffler return WPA_KEY_MGMT_PSK; 4739beb93cSSam Leffler if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) 4839beb93cSSam Leffler return WPA_KEY_MGMT_WPA_NONE; 4939beb93cSSam Leffler return 0; 5039beb93cSSam Leffler } 5139beb93cSSam Leffler 5239beb93cSSam Leffler 5339beb93cSSam Leffler static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, 5439beb93cSSam Leffler struct wpa_ie_data *data) 5539beb93cSSam Leffler { 5639beb93cSSam Leffler const struct wpa_ie_hdr *hdr; 5739beb93cSSam Leffler const u8 *pos; 5839beb93cSSam Leffler int left; 5939beb93cSSam Leffler int i, count; 6039beb93cSSam Leffler 6139beb93cSSam Leffler os_memset(data, 0, sizeof(*data)); 6239beb93cSSam Leffler data->proto = WPA_PROTO_WPA; 6339beb93cSSam Leffler data->pairwise_cipher = WPA_CIPHER_TKIP; 6439beb93cSSam Leffler data->group_cipher = WPA_CIPHER_TKIP; 6539beb93cSSam Leffler data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 6639beb93cSSam Leffler data->capabilities = 0; 6739beb93cSSam Leffler data->pmkid = NULL; 6839beb93cSSam Leffler data->num_pmkid = 0; 6939beb93cSSam Leffler data->mgmt_group_cipher = 0; 7039beb93cSSam Leffler 7139beb93cSSam Leffler if (wpa_ie_len == 0) { 7239beb93cSSam Leffler /* No WPA IE - fail silently */ 7339beb93cSSam Leffler return -1; 7439beb93cSSam Leffler } 7539beb93cSSam Leffler 7639beb93cSSam Leffler if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { 7739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 7839beb93cSSam Leffler __func__, (unsigned long) wpa_ie_len); 7939beb93cSSam Leffler return -1; 8039beb93cSSam Leffler } 8139beb93cSSam Leffler 8239beb93cSSam Leffler hdr = (const struct wpa_ie_hdr *) wpa_ie; 8339beb93cSSam Leffler 8439beb93cSSam Leffler if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || 8539beb93cSSam Leffler hdr->len != wpa_ie_len - 2 || 8639beb93cSSam Leffler RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || 8739beb93cSSam Leffler WPA_GET_LE16(hdr->version) != WPA_VERSION) { 8839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 8939beb93cSSam Leffler __func__); 9039beb93cSSam Leffler return -1; 9139beb93cSSam Leffler } 9239beb93cSSam Leffler 9339beb93cSSam Leffler pos = (const u8 *) (hdr + 1); 9439beb93cSSam Leffler left = wpa_ie_len - sizeof(*hdr); 9539beb93cSSam Leffler 9639beb93cSSam Leffler if (left >= WPA_SELECTOR_LEN) { 9739beb93cSSam Leffler data->group_cipher = wpa_selector_to_bitfield(pos); 9839beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 9939beb93cSSam Leffler left -= WPA_SELECTOR_LEN; 10039beb93cSSam Leffler } else if (left > 0) { 10139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 10239beb93cSSam Leffler __func__, left); 10339beb93cSSam Leffler return -1; 10439beb93cSSam Leffler } 10539beb93cSSam Leffler 10639beb93cSSam Leffler if (left >= 2) { 10739beb93cSSam Leffler data->pairwise_cipher = 0; 10839beb93cSSam Leffler count = WPA_GET_LE16(pos); 10939beb93cSSam Leffler pos += 2; 11039beb93cSSam Leffler left -= 2; 11139beb93cSSam Leffler if (count == 0 || left < count * WPA_SELECTOR_LEN) { 11239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 11339beb93cSSam Leffler "count %u left %u", __func__, count, left); 11439beb93cSSam Leffler return -1; 11539beb93cSSam Leffler } 11639beb93cSSam Leffler for (i = 0; i < count; i++) { 11739beb93cSSam Leffler data->pairwise_cipher |= wpa_selector_to_bitfield(pos); 11839beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 11939beb93cSSam Leffler left -= WPA_SELECTOR_LEN; 12039beb93cSSam Leffler } 12139beb93cSSam Leffler } else if (left == 1) { 12239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 12339beb93cSSam Leffler __func__); 12439beb93cSSam Leffler return -1; 12539beb93cSSam Leffler } 12639beb93cSSam Leffler 12739beb93cSSam Leffler if (left >= 2) { 12839beb93cSSam Leffler data->key_mgmt = 0; 12939beb93cSSam Leffler count = WPA_GET_LE16(pos); 13039beb93cSSam Leffler pos += 2; 13139beb93cSSam Leffler left -= 2; 13239beb93cSSam Leffler if (count == 0 || left < count * WPA_SELECTOR_LEN) { 13339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 13439beb93cSSam Leffler "count %u left %u", __func__, count, left); 13539beb93cSSam Leffler return -1; 13639beb93cSSam Leffler } 13739beb93cSSam Leffler for (i = 0; i < count; i++) { 13839beb93cSSam Leffler data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); 13939beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 14039beb93cSSam Leffler left -= WPA_SELECTOR_LEN; 14139beb93cSSam Leffler } 14239beb93cSSam Leffler } else if (left == 1) { 14339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 14439beb93cSSam Leffler __func__); 14539beb93cSSam Leffler return -1; 14639beb93cSSam Leffler } 14739beb93cSSam Leffler 14839beb93cSSam Leffler if (left >= 2) { 14939beb93cSSam Leffler data->capabilities = WPA_GET_LE16(pos); 15039beb93cSSam Leffler pos += 2; 15139beb93cSSam Leffler left -= 2; 15239beb93cSSam Leffler } 15339beb93cSSam Leffler 15439beb93cSSam Leffler if (left > 0) { 15539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", 15639beb93cSSam Leffler __func__, left); 15739beb93cSSam Leffler } 15839beb93cSSam Leffler 15939beb93cSSam Leffler return 0; 16039beb93cSSam Leffler } 16139beb93cSSam Leffler 16239beb93cSSam Leffler 16339beb93cSSam Leffler /** 16439beb93cSSam Leffler * wpa_parse_wpa_ie - Parse WPA/RSN IE 16539beb93cSSam Leffler * @wpa_ie: Pointer to WPA or RSN IE 16639beb93cSSam Leffler * @wpa_ie_len: Length of the WPA/RSN IE 16739beb93cSSam Leffler * @data: Pointer to data area for parsing results 16839beb93cSSam Leffler * Returns: 0 on success, -1 on failure 16939beb93cSSam Leffler * 17039beb93cSSam Leffler * Parse the contents of WPA or RSN IE and write the parsed data into data. 17139beb93cSSam Leffler */ 17239beb93cSSam Leffler int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, 17339beb93cSSam Leffler struct wpa_ie_data *data) 17439beb93cSSam Leffler { 17539beb93cSSam Leffler if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) 17639beb93cSSam Leffler return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); 17739beb93cSSam Leffler else 17839beb93cSSam Leffler return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); 17939beb93cSSam Leffler } 18039beb93cSSam Leffler 18139beb93cSSam Leffler 18239beb93cSSam Leffler static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, 18339beb93cSSam Leffler int pairwise_cipher, int group_cipher, 18439beb93cSSam Leffler int key_mgmt) 18539beb93cSSam Leffler { 18639beb93cSSam Leffler u8 *pos; 18739beb93cSSam Leffler struct wpa_ie_hdr *hdr; 18839beb93cSSam Leffler 18939beb93cSSam Leffler if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 19039beb93cSSam Leffler 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) 19139beb93cSSam Leffler return -1; 19239beb93cSSam Leffler 19339beb93cSSam Leffler hdr = (struct wpa_ie_hdr *) wpa_ie; 19439beb93cSSam Leffler hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; 19539beb93cSSam Leffler RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); 19639beb93cSSam Leffler WPA_PUT_LE16(hdr->version, WPA_VERSION); 19739beb93cSSam Leffler pos = (u8 *) (hdr + 1); 19839beb93cSSam Leffler 19939beb93cSSam Leffler if (group_cipher == WPA_CIPHER_CCMP) { 20039beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 20139beb93cSSam Leffler } else if (group_cipher == WPA_CIPHER_TKIP) { 20239beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 20339beb93cSSam Leffler } else if (group_cipher == WPA_CIPHER_WEP104) { 20439beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); 20539beb93cSSam Leffler } else if (group_cipher == WPA_CIPHER_WEP40) { 20639beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); 20739beb93cSSam Leffler } else { 20839beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 20939beb93cSSam Leffler group_cipher); 21039beb93cSSam Leffler return -1; 21139beb93cSSam Leffler } 21239beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 21339beb93cSSam Leffler 21439beb93cSSam Leffler *pos++ = 1; 21539beb93cSSam Leffler *pos++ = 0; 21639beb93cSSam Leffler if (pairwise_cipher == WPA_CIPHER_CCMP) { 21739beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 21839beb93cSSam Leffler } else if (pairwise_cipher == WPA_CIPHER_TKIP) { 21939beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 22039beb93cSSam Leffler } else if (pairwise_cipher == WPA_CIPHER_NONE) { 22139beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); 22239beb93cSSam Leffler } else { 22339beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 22439beb93cSSam Leffler pairwise_cipher); 22539beb93cSSam Leffler return -1; 22639beb93cSSam Leffler } 22739beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 22839beb93cSSam Leffler 22939beb93cSSam Leffler *pos++ = 1; 23039beb93cSSam Leffler *pos++ = 0; 23139beb93cSSam Leffler if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 23239beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 23339beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 23439beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 23539beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { 23639beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); 23739beb93cSSam Leffler } else { 23839beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 23939beb93cSSam Leffler key_mgmt); 24039beb93cSSam Leffler return -1; 24139beb93cSSam Leffler } 24239beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 24339beb93cSSam Leffler 24439beb93cSSam Leffler /* WPA Capabilities; use defaults, so no need to include it */ 24539beb93cSSam Leffler 24639beb93cSSam Leffler hdr->len = (pos - wpa_ie) - 2; 24739beb93cSSam Leffler 24839beb93cSSam Leffler WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 24939beb93cSSam Leffler 25039beb93cSSam Leffler return pos - wpa_ie; 25139beb93cSSam Leffler } 25239beb93cSSam Leffler 25339beb93cSSam Leffler 25439beb93cSSam Leffler static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, 25539beb93cSSam Leffler int pairwise_cipher, int group_cipher, 25639beb93cSSam Leffler int key_mgmt, int mgmt_group_cipher, 25739beb93cSSam Leffler struct wpa_sm *sm) 25839beb93cSSam Leffler { 25939beb93cSSam Leffler #ifndef CONFIG_NO_WPA2 26039beb93cSSam Leffler u8 *pos; 26139beb93cSSam Leffler struct rsn_ie_hdr *hdr; 26239beb93cSSam Leffler u16 capab; 26339beb93cSSam Leffler 26439beb93cSSam Leffler if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 26539beb93cSSam Leffler 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + 26639beb93cSSam Leffler (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { 26739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", 26839beb93cSSam Leffler (unsigned long) rsn_ie_len); 26939beb93cSSam Leffler return -1; 27039beb93cSSam Leffler } 27139beb93cSSam Leffler 27239beb93cSSam Leffler hdr = (struct rsn_ie_hdr *) rsn_ie; 27339beb93cSSam Leffler hdr->elem_id = WLAN_EID_RSN; 27439beb93cSSam Leffler WPA_PUT_LE16(hdr->version, RSN_VERSION); 27539beb93cSSam Leffler pos = (u8 *) (hdr + 1); 27639beb93cSSam Leffler 27739beb93cSSam Leffler if (group_cipher == WPA_CIPHER_CCMP) { 27839beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 27939beb93cSSam Leffler } else if (group_cipher == WPA_CIPHER_TKIP) { 28039beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 28139beb93cSSam Leffler } else if (group_cipher == WPA_CIPHER_WEP104) { 28239beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); 28339beb93cSSam Leffler } else if (group_cipher == WPA_CIPHER_WEP40) { 28439beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); 28539beb93cSSam Leffler } else { 28639beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 28739beb93cSSam Leffler group_cipher); 28839beb93cSSam Leffler return -1; 28939beb93cSSam Leffler } 29039beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 29139beb93cSSam Leffler 29239beb93cSSam Leffler *pos++ = 1; 29339beb93cSSam Leffler *pos++ = 0; 29439beb93cSSam Leffler if (pairwise_cipher == WPA_CIPHER_CCMP) { 29539beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 29639beb93cSSam Leffler } else if (pairwise_cipher == WPA_CIPHER_TKIP) { 29739beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 29839beb93cSSam Leffler } else if (pairwise_cipher == WPA_CIPHER_NONE) { 29939beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); 30039beb93cSSam Leffler } else { 30139beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 30239beb93cSSam Leffler pairwise_cipher); 30339beb93cSSam Leffler return -1; 30439beb93cSSam Leffler } 30539beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 30639beb93cSSam Leffler 30739beb93cSSam Leffler *pos++ = 1; 30839beb93cSSam Leffler *pos++ = 0; 30939beb93cSSam Leffler if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 31039beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 31139beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 31239beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 31339beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 31439beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { 31539beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 31639beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { 31739beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 31839beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 31939beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 32039beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { 32139beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 32239beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { 32339beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 32439beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 32539beb93cSSam Leffler } else { 32639beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 32739beb93cSSam Leffler key_mgmt); 32839beb93cSSam Leffler return -1; 32939beb93cSSam Leffler } 33039beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 33139beb93cSSam Leffler 33239beb93cSSam Leffler /* RSN Capabilities */ 33339beb93cSSam Leffler capab = 0; 33439beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 335*e28a4053SRui Paulo if (sm->mfp) 33639beb93cSSam Leffler capab |= WPA_CAPABILITY_MFPC; 337*e28a4053SRui Paulo if (sm->mfp == 2) 338*e28a4053SRui Paulo capab |= WPA_CAPABILITY_MFPR; 33939beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 34039beb93cSSam Leffler WPA_PUT_LE16(pos, capab); 34139beb93cSSam Leffler pos += 2; 34239beb93cSSam Leffler 34339beb93cSSam Leffler if (sm->cur_pmksa) { 34439beb93cSSam Leffler /* PMKID Count (2 octets, little endian) */ 34539beb93cSSam Leffler *pos++ = 1; 34639beb93cSSam Leffler *pos++ = 0; 34739beb93cSSam Leffler /* PMKID */ 34839beb93cSSam Leffler os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 34939beb93cSSam Leffler pos += PMKID_LEN; 35039beb93cSSam Leffler } 35139beb93cSSam Leffler 35239beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 35339beb93cSSam Leffler if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { 35439beb93cSSam Leffler if (!sm->cur_pmksa) { 35539beb93cSSam Leffler /* PMKID Count */ 35639beb93cSSam Leffler WPA_PUT_LE16(pos, 0); 35739beb93cSSam Leffler pos += 2; 35839beb93cSSam Leffler } 35939beb93cSSam Leffler 36039beb93cSSam Leffler /* Management Group Cipher Suite */ 36139beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 36239beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 36339beb93cSSam Leffler } 36439beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 36539beb93cSSam Leffler 36639beb93cSSam Leffler hdr->len = (pos - rsn_ie) - 2; 36739beb93cSSam Leffler 36839beb93cSSam Leffler WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 36939beb93cSSam Leffler 37039beb93cSSam Leffler return pos - rsn_ie; 37139beb93cSSam Leffler #else /* CONFIG_NO_WPA2 */ 37239beb93cSSam Leffler return -1; 37339beb93cSSam Leffler #endif /* CONFIG_NO_WPA2 */ 37439beb93cSSam Leffler } 37539beb93cSSam Leffler 37639beb93cSSam Leffler 37739beb93cSSam Leffler /** 37839beb93cSSam Leffler * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 37939beb93cSSam Leffler * @sm: Pointer to WPA state machine data from wpa_sm_init() 38039beb93cSSam Leffler * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 38139beb93cSSam Leffler * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 38239beb93cSSam Leffler * Returns: Length of the generated WPA/RSN IE or -1 on failure 38339beb93cSSam Leffler */ 38439beb93cSSam Leffler int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 38539beb93cSSam Leffler { 38639beb93cSSam Leffler if (sm->proto == WPA_PROTO_RSN) 38739beb93cSSam Leffler return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 38839beb93cSSam Leffler sm->pairwise_cipher, 38939beb93cSSam Leffler sm->group_cipher, 39039beb93cSSam Leffler sm->key_mgmt, sm->mgmt_group_cipher, 39139beb93cSSam Leffler sm); 39239beb93cSSam Leffler else 39339beb93cSSam Leffler return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 39439beb93cSSam Leffler sm->pairwise_cipher, 39539beb93cSSam Leffler sm->group_cipher, 39639beb93cSSam Leffler sm->key_mgmt); 39739beb93cSSam Leffler } 39839beb93cSSam Leffler 39939beb93cSSam Leffler 40039beb93cSSam Leffler /** 40139beb93cSSam Leffler * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 40239beb93cSSam Leffler * @pos: Pointer to the IE header 40339beb93cSSam Leffler * @end: Pointer to the end of the Key Data buffer 40439beb93cSSam Leffler * @ie: Pointer to parsed IE data 40539beb93cSSam Leffler * Returns: 0 on success, 1 if end mark is found, -1 on failure 40639beb93cSSam Leffler */ 40739beb93cSSam Leffler static int wpa_parse_generic(const u8 *pos, const u8 *end, 40839beb93cSSam Leffler struct wpa_eapol_ie_parse *ie) 40939beb93cSSam Leffler { 41039beb93cSSam Leffler if (pos[1] == 0) 41139beb93cSSam Leffler return 1; 41239beb93cSSam Leffler 41339beb93cSSam Leffler if (pos[1] >= 6 && 41439beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 41539beb93cSSam Leffler pos[2 + WPA_SELECTOR_LEN] == 1 && 41639beb93cSSam Leffler pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 41739beb93cSSam Leffler ie->wpa_ie = pos; 41839beb93cSSam Leffler ie->wpa_ie_len = pos[1] + 2; 419*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", 420*e28a4053SRui Paulo ie->wpa_ie, ie->wpa_ie_len); 42139beb93cSSam Leffler return 0; 42239beb93cSSam Leffler } 42339beb93cSSam Leffler 42439beb93cSSam Leffler if (pos + 1 + RSN_SELECTOR_LEN < end && 42539beb93cSSam Leffler pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 42639beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 42739beb93cSSam Leffler ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 428*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", 429*e28a4053SRui 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_GROUPKEY) { 43539beb93cSSam Leffler ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 43639beb93cSSam Leffler ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 437*e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", 438*e28a4053SRui Paulo pos, pos[1] + 2); 43939beb93cSSam Leffler return 0; 44039beb93cSSam Leffler } 44139beb93cSSam Leffler 44239beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 44339beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 44439beb93cSSam Leffler ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 44539beb93cSSam Leffler ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 446*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", 447*e28a4053SRui Paulo pos, pos[1] + 2); 44839beb93cSSam Leffler return 0; 44939beb93cSSam Leffler } 45039beb93cSSam Leffler 45139beb93cSSam Leffler #ifdef CONFIG_PEERKEY 45239beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 45339beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 45439beb93cSSam Leffler ie->smk = pos + 2 + RSN_SELECTOR_LEN; 45539beb93cSSam Leffler ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 456*e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", 457*e28a4053SRui Paulo pos, pos[1] + 2); 45839beb93cSSam Leffler return 0; 45939beb93cSSam Leffler } 46039beb93cSSam Leffler 46139beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 46239beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 46339beb93cSSam Leffler ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 46439beb93cSSam Leffler ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 465*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", 466*e28a4053SRui Paulo pos, pos[1] + 2); 46739beb93cSSam Leffler return 0; 46839beb93cSSam Leffler } 46939beb93cSSam Leffler 47039beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 47139beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 47239beb93cSSam Leffler ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 47339beb93cSSam Leffler ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 474*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", 475*e28a4053SRui Paulo pos, pos[1] + 2); 47639beb93cSSam Leffler return 0; 47739beb93cSSam Leffler } 47839beb93cSSam Leffler 47939beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 48039beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 48139beb93cSSam Leffler ie->error = pos + 2 + RSN_SELECTOR_LEN; 48239beb93cSSam Leffler ie->error_len = pos[1] - RSN_SELECTOR_LEN; 483*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", 484*e28a4053SRui Paulo pos, pos[1] + 2); 48539beb93cSSam Leffler return 0; 48639beb93cSSam Leffler } 48739beb93cSSam Leffler #endif /* CONFIG_PEERKEY */ 48839beb93cSSam Leffler 48939beb93cSSam Leffler #ifdef CONFIG_IEEE80211W 49039beb93cSSam Leffler if (pos[1] > RSN_SELECTOR_LEN + 2 && 49139beb93cSSam Leffler RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 49239beb93cSSam Leffler ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 49339beb93cSSam Leffler ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 494*e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", 495*e28a4053SRui Paulo pos, pos[1] + 2); 49639beb93cSSam Leffler return 0; 49739beb93cSSam Leffler } 49839beb93cSSam Leffler #endif /* CONFIG_IEEE80211W */ 49939beb93cSSam Leffler 50039beb93cSSam Leffler return 0; 50139beb93cSSam Leffler } 50239beb93cSSam Leffler 50339beb93cSSam Leffler 50439beb93cSSam Leffler /** 50539beb93cSSam Leffler * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs 50639beb93cSSam Leffler * @buf: Pointer to the Key Data buffer 50739beb93cSSam Leffler * @len: Key Data Length 50839beb93cSSam Leffler * @ie: Pointer to parsed IE data 50939beb93cSSam Leffler * Returns: 0 on success, -1 on failure 51039beb93cSSam Leffler */ 51139beb93cSSam Leffler int wpa_supplicant_parse_ies(const u8 *buf, size_t len, 51239beb93cSSam Leffler struct wpa_eapol_ie_parse *ie) 51339beb93cSSam Leffler { 51439beb93cSSam Leffler const u8 *pos, *end; 51539beb93cSSam Leffler int ret = 0; 51639beb93cSSam Leffler 51739beb93cSSam Leffler os_memset(ie, 0, sizeof(*ie)); 51839beb93cSSam Leffler for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 51939beb93cSSam Leffler if (pos[0] == 0xdd && 52039beb93cSSam Leffler ((pos == buf + len - 1) || pos[1] == 0)) { 52139beb93cSSam Leffler /* Ignore padding */ 52239beb93cSSam Leffler break; 52339beb93cSSam Leffler } 52439beb93cSSam Leffler if (pos + 2 + pos[1] > end) { 52539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 52639beb93cSSam Leffler "underflow (ie=%d len=%d pos=%d)", 52739beb93cSSam Leffler pos[0], pos[1], (int) (pos - buf)); 52839beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 52939beb93cSSam Leffler buf, len); 53039beb93cSSam Leffler ret = -1; 53139beb93cSSam Leffler break; 53239beb93cSSam Leffler } 53339beb93cSSam Leffler if (*pos == WLAN_EID_RSN) { 53439beb93cSSam Leffler ie->rsn_ie = pos; 53539beb93cSSam Leffler ie->rsn_ie_len = pos[1] + 2; 536*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", 537*e28a4053SRui Paulo ie->rsn_ie, ie->rsn_ie_len); 53839beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 53939beb93cSSam Leffler } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 54039beb93cSSam Leffler ie->mdie = pos; 54139beb93cSSam Leffler ie->mdie_len = pos[1] + 2; 542*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", 543*e28a4053SRui Paulo ie->mdie, ie->mdie_len); 544*e28a4053SRui Paulo } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 545*e28a4053SRui Paulo ie->ftie = pos; 546*e28a4053SRui Paulo ie->ftie_len = pos[1] + 2; 547*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", 548*e28a4053SRui Paulo ie->ftie, ie->ftie_len); 549*e28a4053SRui Paulo } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { 550*e28a4053SRui Paulo if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { 551*e28a4053SRui Paulo ie->reassoc_deadline = pos; 552*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " 553*e28a4053SRui Paulo "in EAPOL-Key", 554*e28a4053SRui Paulo ie->reassoc_deadline, pos[1] + 2); 555*e28a4053SRui Paulo } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { 556*e28a4053SRui Paulo ie->key_lifetime = pos; 557*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " 558*e28a4053SRui Paulo "in EAPOL-Key", 559*e28a4053SRui Paulo ie->key_lifetime, pos[1] + 2); 560*e28a4053SRui Paulo } else { 561*e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " 562*e28a4053SRui Paulo "EAPOL-Key Key Data IE", 563*e28a4053SRui Paulo pos, 2 + pos[1]); 564*e28a4053SRui Paulo } 56539beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 56639beb93cSSam Leffler } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 56739beb93cSSam Leffler ret = wpa_parse_generic(pos, end, ie); 56839beb93cSSam Leffler if (ret < 0) 56939beb93cSSam Leffler break; 57039beb93cSSam Leffler if (ret > 0) { 57139beb93cSSam Leffler ret = 0; 57239beb93cSSam Leffler break; 57339beb93cSSam Leffler } 57439beb93cSSam Leffler } else { 57539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 57639beb93cSSam Leffler "Key Data IE", pos, 2 + pos[1]); 57739beb93cSSam Leffler } 57839beb93cSSam Leffler } 57939beb93cSSam Leffler 58039beb93cSSam Leffler return ret; 58139beb93cSSam Leffler } 582