wpa_auth_ie.c revision 214501
1214501Srpaulo/* 2214501Srpaulo * hostapd - WPA/RSN IE and KDE definitions 3214501Srpaulo * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo */ 14214501Srpaulo 15214501Srpaulo#include "utils/includes.h" 16214501Srpaulo 17214501Srpaulo#include "utils/common.h" 18214501Srpaulo#include "common/ieee802_11_defs.h" 19214501Srpaulo#include "eapol_auth/eapol_auth_sm.h" 20214501Srpaulo#include "ap_config.h" 21214501Srpaulo#include "ieee802_11.h" 22214501Srpaulo#include "wpa_auth.h" 23214501Srpaulo#include "pmksa_cache_auth.h" 24214501Srpaulo#include "wpa_auth_ie.h" 25214501Srpaulo#include "wpa_auth_i.h" 26214501Srpaulo 27214501Srpaulo 28214501Srpaulostatic int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) 29214501Srpaulo{ 30214501Srpaulo struct wpa_ie_hdr *hdr; 31214501Srpaulo int num_suites; 32214501Srpaulo u8 *pos, *count; 33214501Srpaulo 34214501Srpaulo hdr = (struct wpa_ie_hdr *) buf; 35214501Srpaulo hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; 36214501Srpaulo RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); 37214501Srpaulo WPA_PUT_LE16(hdr->version, WPA_VERSION); 38214501Srpaulo pos = (u8 *) (hdr + 1); 39214501Srpaulo 40214501Srpaulo if (conf->wpa_group == WPA_CIPHER_CCMP) { 41214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 42214501Srpaulo } else if (conf->wpa_group == WPA_CIPHER_TKIP) { 43214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 44214501Srpaulo } else if (conf->wpa_group == WPA_CIPHER_WEP104) { 45214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); 46214501Srpaulo } else if (conf->wpa_group == WPA_CIPHER_WEP40) { 47214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); 48214501Srpaulo } else { 49214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", 50214501Srpaulo conf->wpa_group); 51214501Srpaulo return -1; 52214501Srpaulo } 53214501Srpaulo pos += WPA_SELECTOR_LEN; 54214501Srpaulo 55214501Srpaulo num_suites = 0; 56214501Srpaulo count = pos; 57214501Srpaulo pos += 2; 58214501Srpaulo 59214501Srpaulo if (conf->wpa_pairwise & WPA_CIPHER_CCMP) { 60214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 61214501Srpaulo pos += WPA_SELECTOR_LEN; 62214501Srpaulo num_suites++; 63214501Srpaulo } 64214501Srpaulo if (conf->wpa_pairwise & WPA_CIPHER_TKIP) { 65214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 66214501Srpaulo pos += WPA_SELECTOR_LEN; 67214501Srpaulo num_suites++; 68214501Srpaulo } 69214501Srpaulo if (conf->wpa_pairwise & WPA_CIPHER_NONE) { 70214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); 71214501Srpaulo pos += WPA_SELECTOR_LEN; 72214501Srpaulo num_suites++; 73214501Srpaulo } 74214501Srpaulo 75214501Srpaulo if (num_suites == 0) { 76214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", 77214501Srpaulo conf->wpa_pairwise); 78214501Srpaulo return -1; 79214501Srpaulo } 80214501Srpaulo WPA_PUT_LE16(count, num_suites); 81214501Srpaulo 82214501Srpaulo num_suites = 0; 83214501Srpaulo count = pos; 84214501Srpaulo pos += 2; 85214501Srpaulo 86214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 87214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 88214501Srpaulo pos += WPA_SELECTOR_LEN; 89214501Srpaulo num_suites++; 90214501Srpaulo } 91214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { 92214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 93214501Srpaulo pos += WPA_SELECTOR_LEN; 94214501Srpaulo num_suites++; 95214501Srpaulo } 96214501Srpaulo 97214501Srpaulo if (num_suites == 0) { 98214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", 99214501Srpaulo conf->wpa_key_mgmt); 100214501Srpaulo return -1; 101214501Srpaulo } 102214501Srpaulo WPA_PUT_LE16(count, num_suites); 103214501Srpaulo 104214501Srpaulo /* WPA Capabilities; use defaults, so no need to include it */ 105214501Srpaulo 106214501Srpaulo hdr->len = (pos - buf) - 2; 107214501Srpaulo 108214501Srpaulo return pos - buf; 109214501Srpaulo} 110214501Srpaulo 111214501Srpaulo 112214501Srpauloint wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, 113214501Srpaulo const u8 *pmkid) 114214501Srpaulo{ 115214501Srpaulo struct rsn_ie_hdr *hdr; 116214501Srpaulo int num_suites; 117214501Srpaulo u8 *pos, *count; 118214501Srpaulo u16 capab; 119214501Srpaulo 120214501Srpaulo hdr = (struct rsn_ie_hdr *) buf; 121214501Srpaulo hdr->elem_id = WLAN_EID_RSN; 122214501Srpaulo WPA_PUT_LE16(hdr->version, RSN_VERSION); 123214501Srpaulo pos = (u8 *) (hdr + 1); 124214501Srpaulo 125214501Srpaulo if (conf->wpa_group == WPA_CIPHER_CCMP) { 126214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 127214501Srpaulo } else if (conf->wpa_group == WPA_CIPHER_TKIP) { 128214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 129214501Srpaulo } else if (conf->wpa_group == WPA_CIPHER_WEP104) { 130214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); 131214501Srpaulo } else if (conf->wpa_group == WPA_CIPHER_WEP40) { 132214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); 133214501Srpaulo } else { 134214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", 135214501Srpaulo conf->wpa_group); 136214501Srpaulo return -1; 137214501Srpaulo } 138214501Srpaulo pos += RSN_SELECTOR_LEN; 139214501Srpaulo 140214501Srpaulo num_suites = 0; 141214501Srpaulo count = pos; 142214501Srpaulo pos += 2; 143214501Srpaulo 144214501Srpaulo if (conf->rsn_pairwise & WPA_CIPHER_CCMP) { 145214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 146214501Srpaulo pos += RSN_SELECTOR_LEN; 147214501Srpaulo num_suites++; 148214501Srpaulo } 149214501Srpaulo if (conf->rsn_pairwise & WPA_CIPHER_TKIP) { 150214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 151214501Srpaulo pos += RSN_SELECTOR_LEN; 152214501Srpaulo num_suites++; 153214501Srpaulo } 154214501Srpaulo if (conf->rsn_pairwise & WPA_CIPHER_NONE) { 155214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); 156214501Srpaulo pos += RSN_SELECTOR_LEN; 157214501Srpaulo num_suites++; 158214501Srpaulo } 159214501Srpaulo 160214501Srpaulo if (num_suites == 0) { 161214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", 162214501Srpaulo conf->rsn_pairwise); 163214501Srpaulo return -1; 164214501Srpaulo } 165214501Srpaulo WPA_PUT_LE16(count, num_suites); 166214501Srpaulo 167214501Srpaulo num_suites = 0; 168214501Srpaulo count = pos; 169214501Srpaulo pos += 2; 170214501Srpaulo 171214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 172214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 173214501Srpaulo pos += RSN_SELECTOR_LEN; 174214501Srpaulo num_suites++; 175214501Srpaulo } 176214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { 177214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 178214501Srpaulo pos += RSN_SELECTOR_LEN; 179214501Srpaulo num_suites++; 180214501Srpaulo } 181214501Srpaulo#ifdef CONFIG_IEEE80211R 182214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 183214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 184214501Srpaulo pos += RSN_SELECTOR_LEN; 185214501Srpaulo num_suites++; 186214501Srpaulo } 187214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { 188214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 189214501Srpaulo pos += RSN_SELECTOR_LEN; 190214501Srpaulo num_suites++; 191214501Srpaulo } 192214501Srpaulo#endif /* CONFIG_IEEE80211R */ 193214501Srpaulo#ifdef CONFIG_IEEE80211W 194214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 195214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 196214501Srpaulo pos += RSN_SELECTOR_LEN; 197214501Srpaulo num_suites++; 198214501Srpaulo } 199214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 200214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 201214501Srpaulo pos += RSN_SELECTOR_LEN; 202214501Srpaulo num_suites++; 203214501Srpaulo } 204214501Srpaulo#endif /* CONFIG_IEEE80211W */ 205214501Srpaulo 206214501Srpaulo if (num_suites == 0) { 207214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", 208214501Srpaulo conf->wpa_key_mgmt); 209214501Srpaulo return -1; 210214501Srpaulo } 211214501Srpaulo WPA_PUT_LE16(count, num_suites); 212214501Srpaulo 213214501Srpaulo /* RSN Capabilities */ 214214501Srpaulo capab = 0; 215214501Srpaulo if (conf->rsn_preauth) 216214501Srpaulo capab |= WPA_CAPABILITY_PREAUTH; 217214501Srpaulo if (conf->peerkey) 218214501Srpaulo capab |= WPA_CAPABILITY_PEERKEY_ENABLED; 219214501Srpaulo if (conf->wmm_enabled) { 220214501Srpaulo /* 4 PTKSA replay counters when using WMM */ 221214501Srpaulo capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); 222214501Srpaulo } 223214501Srpaulo#ifdef CONFIG_IEEE80211W 224214501Srpaulo if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 225214501Srpaulo capab |= WPA_CAPABILITY_MFPC; 226214501Srpaulo if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) 227214501Srpaulo capab |= WPA_CAPABILITY_MFPR; 228214501Srpaulo } 229214501Srpaulo#endif /* CONFIG_IEEE80211W */ 230214501Srpaulo WPA_PUT_LE16(pos, capab); 231214501Srpaulo pos += 2; 232214501Srpaulo 233214501Srpaulo if (pmkid) { 234214501Srpaulo if (pos + 2 + PMKID_LEN > buf + len) 235214501Srpaulo return -1; 236214501Srpaulo /* PMKID Count */ 237214501Srpaulo WPA_PUT_LE16(pos, 1); 238214501Srpaulo pos += 2; 239214501Srpaulo os_memcpy(pos, pmkid, PMKID_LEN); 240214501Srpaulo pos += PMKID_LEN; 241214501Srpaulo } 242214501Srpaulo 243214501Srpaulo#ifdef CONFIG_IEEE80211W 244214501Srpaulo if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 245214501Srpaulo if (pos + 2 + 4 > buf + len) 246214501Srpaulo return -1; 247214501Srpaulo if (pmkid == NULL) { 248214501Srpaulo /* PMKID Count */ 249214501Srpaulo WPA_PUT_LE16(pos, 0); 250214501Srpaulo pos += 2; 251214501Srpaulo } 252214501Srpaulo 253214501Srpaulo /* Management Group Cipher Suite */ 254214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 255214501Srpaulo pos += RSN_SELECTOR_LEN; 256214501Srpaulo } 257214501Srpaulo#endif /* CONFIG_IEEE80211W */ 258214501Srpaulo 259214501Srpaulo hdr->len = (pos - buf) - 2; 260214501Srpaulo 261214501Srpaulo return pos - buf; 262214501Srpaulo} 263214501Srpaulo 264214501Srpaulo 265214501Srpauloint wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) 266214501Srpaulo{ 267214501Srpaulo u8 *pos, buf[128]; 268214501Srpaulo int res; 269214501Srpaulo 270214501Srpaulo pos = buf; 271214501Srpaulo 272214501Srpaulo if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { 273214501Srpaulo res = wpa_write_rsn_ie(&wpa_auth->conf, 274214501Srpaulo pos, buf + sizeof(buf) - pos, NULL); 275214501Srpaulo if (res < 0) 276214501Srpaulo return res; 277214501Srpaulo pos += res; 278214501Srpaulo } 279214501Srpaulo#ifdef CONFIG_IEEE80211R 280214501Srpaulo if (wpa_auth->conf.wpa_key_mgmt & 281214501Srpaulo (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) { 282214501Srpaulo res = wpa_write_mdie(&wpa_auth->conf, pos, 283214501Srpaulo buf + sizeof(buf) - pos); 284214501Srpaulo if (res < 0) 285214501Srpaulo return res; 286214501Srpaulo pos += res; 287214501Srpaulo } 288214501Srpaulo#endif /* CONFIG_IEEE80211R */ 289214501Srpaulo if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { 290214501Srpaulo res = wpa_write_wpa_ie(&wpa_auth->conf, 291214501Srpaulo pos, buf + sizeof(buf) - pos); 292214501Srpaulo if (res < 0) 293214501Srpaulo return res; 294214501Srpaulo pos += res; 295214501Srpaulo } 296214501Srpaulo 297214501Srpaulo os_free(wpa_auth->wpa_ie); 298214501Srpaulo wpa_auth->wpa_ie = os_malloc(pos - buf); 299214501Srpaulo if (wpa_auth->wpa_ie == NULL) 300214501Srpaulo return -1; 301214501Srpaulo os_memcpy(wpa_auth->wpa_ie, buf, pos - buf); 302214501Srpaulo wpa_auth->wpa_ie_len = pos - buf; 303214501Srpaulo 304214501Srpaulo return 0; 305214501Srpaulo} 306214501Srpaulo 307214501Srpaulo 308214501Srpaulou8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, 309214501Srpaulo const u8 *data2, size_t data2_len) 310214501Srpaulo{ 311214501Srpaulo *pos++ = WLAN_EID_VENDOR_SPECIFIC; 312214501Srpaulo *pos++ = RSN_SELECTOR_LEN + data_len + data2_len; 313214501Srpaulo RSN_SELECTOR_PUT(pos, kde); 314214501Srpaulo pos += RSN_SELECTOR_LEN; 315214501Srpaulo os_memcpy(pos, data, data_len); 316214501Srpaulo pos += data_len; 317214501Srpaulo if (data2) { 318214501Srpaulo os_memcpy(pos, data2, data2_len); 319214501Srpaulo pos += data2_len; 320214501Srpaulo } 321214501Srpaulo return pos; 322214501Srpaulo} 323214501Srpaulo 324214501Srpaulo 325214501Srpaulostatic int wpa_selector_to_bitfield(const u8 *s) 326214501Srpaulo{ 327214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) 328214501Srpaulo return WPA_CIPHER_NONE; 329214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) 330214501Srpaulo return WPA_CIPHER_WEP40; 331214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) 332214501Srpaulo return WPA_CIPHER_TKIP; 333214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) 334214501Srpaulo return WPA_CIPHER_CCMP; 335214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) 336214501Srpaulo return WPA_CIPHER_WEP104; 337214501Srpaulo return 0; 338214501Srpaulo} 339214501Srpaulo 340214501Srpaulo 341214501Srpaulostatic int wpa_key_mgmt_to_bitfield(const u8 *s) 342214501Srpaulo{ 343214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) 344214501Srpaulo return WPA_KEY_MGMT_IEEE8021X; 345214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) 346214501Srpaulo return WPA_KEY_MGMT_PSK; 347214501Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) 348214501Srpaulo return WPA_KEY_MGMT_WPA_NONE; 349214501Srpaulo return 0; 350214501Srpaulo} 351214501Srpaulo 352214501Srpaulo 353214501Srpaulostatic int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, 354214501Srpaulo struct wpa_ie_data *data) 355214501Srpaulo{ 356214501Srpaulo const struct wpa_ie_hdr *hdr; 357214501Srpaulo const u8 *pos; 358214501Srpaulo int left; 359214501Srpaulo int i, count; 360214501Srpaulo 361214501Srpaulo os_memset(data, 0, sizeof(*data)); 362214501Srpaulo data->pairwise_cipher = WPA_CIPHER_TKIP; 363214501Srpaulo data->group_cipher = WPA_CIPHER_TKIP; 364214501Srpaulo data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 365214501Srpaulo data->mgmt_group_cipher = 0; 366214501Srpaulo 367214501Srpaulo if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) 368214501Srpaulo return -1; 369214501Srpaulo 370214501Srpaulo hdr = (const struct wpa_ie_hdr *) wpa_ie; 371214501Srpaulo 372214501Srpaulo if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || 373214501Srpaulo hdr->len != wpa_ie_len - 2 || 374214501Srpaulo RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || 375214501Srpaulo WPA_GET_LE16(hdr->version) != WPA_VERSION) { 376214501Srpaulo return -2; 377214501Srpaulo } 378214501Srpaulo 379214501Srpaulo pos = (const u8 *) (hdr + 1); 380214501Srpaulo left = wpa_ie_len - sizeof(*hdr); 381214501Srpaulo 382214501Srpaulo if (left >= WPA_SELECTOR_LEN) { 383214501Srpaulo data->group_cipher = wpa_selector_to_bitfield(pos); 384214501Srpaulo pos += WPA_SELECTOR_LEN; 385214501Srpaulo left -= WPA_SELECTOR_LEN; 386214501Srpaulo } else if (left > 0) 387214501Srpaulo return -3; 388214501Srpaulo 389214501Srpaulo if (left >= 2) { 390214501Srpaulo data->pairwise_cipher = 0; 391214501Srpaulo count = WPA_GET_LE16(pos); 392214501Srpaulo pos += 2; 393214501Srpaulo left -= 2; 394214501Srpaulo if (count == 0 || left < count * WPA_SELECTOR_LEN) 395214501Srpaulo return -4; 396214501Srpaulo for (i = 0; i < count; i++) { 397214501Srpaulo data->pairwise_cipher |= wpa_selector_to_bitfield(pos); 398214501Srpaulo pos += WPA_SELECTOR_LEN; 399214501Srpaulo left -= WPA_SELECTOR_LEN; 400214501Srpaulo } 401214501Srpaulo } else if (left == 1) 402214501Srpaulo return -5; 403214501Srpaulo 404214501Srpaulo if (left >= 2) { 405214501Srpaulo data->key_mgmt = 0; 406214501Srpaulo count = WPA_GET_LE16(pos); 407214501Srpaulo pos += 2; 408214501Srpaulo left -= 2; 409214501Srpaulo if (count == 0 || left < count * WPA_SELECTOR_LEN) 410214501Srpaulo return -6; 411214501Srpaulo for (i = 0; i < count; i++) { 412214501Srpaulo data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); 413214501Srpaulo pos += WPA_SELECTOR_LEN; 414214501Srpaulo left -= WPA_SELECTOR_LEN; 415214501Srpaulo } 416214501Srpaulo } else if (left == 1) 417214501Srpaulo return -7; 418214501Srpaulo 419214501Srpaulo if (left >= 2) { 420214501Srpaulo data->capabilities = WPA_GET_LE16(pos); 421214501Srpaulo pos += 2; 422214501Srpaulo left -= 2; 423214501Srpaulo } 424214501Srpaulo 425214501Srpaulo if (left > 0) { 426214501Srpaulo return -8; 427214501Srpaulo } 428214501Srpaulo 429214501Srpaulo return 0; 430214501Srpaulo} 431214501Srpaulo 432214501Srpaulo 433214501Srpaulostruct wpa_auth_okc_iter_data { 434214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 435214501Srpaulo const u8 *aa; 436214501Srpaulo const u8 *spa; 437214501Srpaulo const u8 *pmkid; 438214501Srpaulo}; 439214501Srpaulo 440214501Srpaulo 441214501Srpaulostatic int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) 442214501Srpaulo{ 443214501Srpaulo struct wpa_auth_okc_iter_data *data = ctx; 444214501Srpaulo data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa, 445214501Srpaulo data->pmkid); 446214501Srpaulo if (data->pmksa) 447214501Srpaulo return 1; 448214501Srpaulo return 0; 449214501Srpaulo} 450214501Srpaulo 451214501Srpaulo 452214501Srpauloint wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, 453214501Srpaulo struct wpa_state_machine *sm, 454214501Srpaulo const u8 *wpa_ie, size_t wpa_ie_len, 455214501Srpaulo const u8 *mdie, size_t mdie_len) 456214501Srpaulo{ 457214501Srpaulo struct wpa_ie_data data; 458214501Srpaulo int ciphers, key_mgmt, res, version; 459214501Srpaulo u32 selector; 460214501Srpaulo size_t i; 461214501Srpaulo const u8 *pmkid = NULL; 462214501Srpaulo 463214501Srpaulo if (wpa_auth == NULL || sm == NULL) 464214501Srpaulo return WPA_NOT_ENABLED; 465214501Srpaulo 466214501Srpaulo if (wpa_ie == NULL || wpa_ie_len < 1) 467214501Srpaulo return WPA_INVALID_IE; 468214501Srpaulo 469214501Srpaulo if (wpa_ie[0] == WLAN_EID_RSN) 470214501Srpaulo version = WPA_PROTO_RSN; 471214501Srpaulo else 472214501Srpaulo version = WPA_PROTO_WPA; 473214501Srpaulo 474214501Srpaulo if (!(wpa_auth->conf.wpa & version)) { 475214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, 476214501Srpaulo version, MAC2STR(sm->addr)); 477214501Srpaulo return WPA_INVALID_PROTO; 478214501Srpaulo } 479214501Srpaulo 480214501Srpaulo if (version == WPA_PROTO_RSN) { 481214501Srpaulo res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); 482214501Srpaulo 483214501Srpaulo selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; 484214501Srpaulo if (0) { 485214501Srpaulo } 486214501Srpaulo#ifdef CONFIG_IEEE80211R 487214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 488214501Srpaulo selector = RSN_AUTH_KEY_MGMT_FT_802_1X; 489214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) 490214501Srpaulo selector = RSN_AUTH_KEY_MGMT_FT_PSK; 491214501Srpaulo#endif /* CONFIG_IEEE80211R */ 492214501Srpaulo#ifdef CONFIG_IEEE80211W 493214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 494214501Srpaulo selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; 495214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 496214501Srpaulo selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; 497214501Srpaulo#endif /* CONFIG_IEEE80211W */ 498214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) 499214501Srpaulo selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; 500214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_PSK) 501214501Srpaulo selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; 502214501Srpaulo wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; 503214501Srpaulo 504214501Srpaulo selector = RSN_CIPHER_SUITE_CCMP; 505214501Srpaulo if (data.pairwise_cipher & WPA_CIPHER_CCMP) 506214501Srpaulo selector = RSN_CIPHER_SUITE_CCMP; 507214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_TKIP) 508214501Srpaulo selector = RSN_CIPHER_SUITE_TKIP; 509214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_WEP104) 510214501Srpaulo selector = RSN_CIPHER_SUITE_WEP104; 511214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_WEP40) 512214501Srpaulo selector = RSN_CIPHER_SUITE_WEP40; 513214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_NONE) 514214501Srpaulo selector = RSN_CIPHER_SUITE_NONE; 515214501Srpaulo wpa_auth->dot11RSNAPairwiseCipherSelected = selector; 516214501Srpaulo 517214501Srpaulo selector = RSN_CIPHER_SUITE_CCMP; 518214501Srpaulo if (data.group_cipher & WPA_CIPHER_CCMP) 519214501Srpaulo selector = RSN_CIPHER_SUITE_CCMP; 520214501Srpaulo else if (data.group_cipher & WPA_CIPHER_TKIP) 521214501Srpaulo selector = RSN_CIPHER_SUITE_TKIP; 522214501Srpaulo else if (data.group_cipher & WPA_CIPHER_WEP104) 523214501Srpaulo selector = RSN_CIPHER_SUITE_WEP104; 524214501Srpaulo else if (data.group_cipher & WPA_CIPHER_WEP40) 525214501Srpaulo selector = RSN_CIPHER_SUITE_WEP40; 526214501Srpaulo else if (data.group_cipher & WPA_CIPHER_NONE) 527214501Srpaulo selector = RSN_CIPHER_SUITE_NONE; 528214501Srpaulo wpa_auth->dot11RSNAGroupCipherSelected = selector; 529214501Srpaulo } else { 530214501Srpaulo res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); 531214501Srpaulo 532214501Srpaulo selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; 533214501Srpaulo if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) 534214501Srpaulo selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; 535214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_PSK) 536214501Srpaulo selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; 537214501Srpaulo wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; 538214501Srpaulo 539214501Srpaulo selector = WPA_CIPHER_SUITE_TKIP; 540214501Srpaulo if (data.pairwise_cipher & WPA_CIPHER_CCMP) 541214501Srpaulo selector = WPA_CIPHER_SUITE_CCMP; 542214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_TKIP) 543214501Srpaulo selector = WPA_CIPHER_SUITE_TKIP; 544214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_WEP104) 545214501Srpaulo selector = WPA_CIPHER_SUITE_WEP104; 546214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_WEP40) 547214501Srpaulo selector = WPA_CIPHER_SUITE_WEP40; 548214501Srpaulo else if (data.pairwise_cipher & WPA_CIPHER_NONE) 549214501Srpaulo selector = WPA_CIPHER_SUITE_NONE; 550214501Srpaulo wpa_auth->dot11RSNAPairwiseCipherSelected = selector; 551214501Srpaulo 552214501Srpaulo selector = WPA_CIPHER_SUITE_TKIP; 553214501Srpaulo if (data.group_cipher & WPA_CIPHER_CCMP) 554214501Srpaulo selector = WPA_CIPHER_SUITE_CCMP; 555214501Srpaulo else if (data.group_cipher & WPA_CIPHER_TKIP) 556214501Srpaulo selector = WPA_CIPHER_SUITE_TKIP; 557214501Srpaulo else if (data.group_cipher & WPA_CIPHER_WEP104) 558214501Srpaulo selector = WPA_CIPHER_SUITE_WEP104; 559214501Srpaulo else if (data.group_cipher & WPA_CIPHER_WEP40) 560214501Srpaulo selector = WPA_CIPHER_SUITE_WEP40; 561214501Srpaulo else if (data.group_cipher & WPA_CIPHER_NONE) 562214501Srpaulo selector = WPA_CIPHER_SUITE_NONE; 563214501Srpaulo wpa_auth->dot11RSNAGroupCipherSelected = selector; 564214501Srpaulo } 565214501Srpaulo if (res) { 566214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " 567214501Srpaulo MACSTR " (res=%d)", MAC2STR(sm->addr), res); 568214501Srpaulo wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); 569214501Srpaulo return WPA_INVALID_IE; 570214501Srpaulo } 571214501Srpaulo 572214501Srpaulo if (data.group_cipher != wpa_auth->conf.wpa_group) { 573214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " 574214501Srpaulo MACSTR, data.group_cipher, MAC2STR(sm->addr)); 575214501Srpaulo return WPA_INVALID_GROUP; 576214501Srpaulo } 577214501Srpaulo 578214501Srpaulo key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; 579214501Srpaulo if (!key_mgmt) { 580214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " 581214501Srpaulo MACSTR, data.key_mgmt, MAC2STR(sm->addr)); 582214501Srpaulo return WPA_INVALID_AKMP; 583214501Srpaulo } 584214501Srpaulo if (0) { 585214501Srpaulo } 586214501Srpaulo#ifdef CONFIG_IEEE80211R 587214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 588214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; 589214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) 590214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; 591214501Srpaulo#endif /* CONFIG_IEEE80211R */ 592214501Srpaulo#ifdef CONFIG_IEEE80211W 593214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 594214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; 595214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 596214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; 597214501Srpaulo#endif /* CONFIG_IEEE80211W */ 598214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) 599214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; 600214501Srpaulo else 601214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; 602214501Srpaulo 603214501Srpaulo if (version == WPA_PROTO_RSN) 604214501Srpaulo ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; 605214501Srpaulo else 606214501Srpaulo ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; 607214501Srpaulo if (!ciphers) { 608214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " 609214501Srpaulo "from " MACSTR, 610214501Srpaulo version == WPA_PROTO_RSN ? "RSN" : "WPA", 611214501Srpaulo data.pairwise_cipher, MAC2STR(sm->addr)); 612214501Srpaulo return WPA_INVALID_PAIRWISE; 613214501Srpaulo } 614214501Srpaulo 615214501Srpaulo#ifdef CONFIG_IEEE80211W 616214501Srpaulo if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { 617214501Srpaulo if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { 618214501Srpaulo wpa_printf(MSG_DEBUG, "Management frame protection " 619214501Srpaulo "required, but client did not enable it"); 620214501Srpaulo return WPA_MGMT_FRAME_PROTECTION_VIOLATION; 621214501Srpaulo } 622214501Srpaulo 623214501Srpaulo if (ciphers & WPA_CIPHER_TKIP) { 624214501Srpaulo wpa_printf(MSG_DEBUG, "Management frame protection " 625214501Srpaulo "cannot use TKIP"); 626214501Srpaulo return WPA_MGMT_FRAME_PROTECTION_VIOLATION; 627214501Srpaulo } 628214501Srpaulo 629214501Srpaulo if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { 630214501Srpaulo wpa_printf(MSG_DEBUG, "Unsupported management group " 631214501Srpaulo "cipher %d", data.mgmt_group_cipher); 632214501Srpaulo return WPA_INVALID_MGMT_GROUP_CIPHER; 633214501Srpaulo } 634214501Srpaulo } 635214501Srpaulo 636214501Srpaulo if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || 637214501Srpaulo !(data.capabilities & WPA_CAPABILITY_MFPC)) 638214501Srpaulo sm->mgmt_frame_prot = 0; 639214501Srpaulo else 640214501Srpaulo sm->mgmt_frame_prot = 1; 641214501Srpaulo#endif /* CONFIG_IEEE80211W */ 642214501Srpaulo 643214501Srpaulo#ifdef CONFIG_IEEE80211R 644214501Srpaulo if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { 645214501Srpaulo if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { 646214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " 647214501Srpaulo "MDIE not included"); 648214501Srpaulo return WPA_INVALID_MDIE; 649214501Srpaulo } 650214501Srpaulo if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, 651214501Srpaulo MOBILITY_DOMAIN_ID_LEN) != 0) { 652214501Srpaulo wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " 653214501Srpaulo "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); 654214501Srpaulo return WPA_INVALID_MDIE; 655214501Srpaulo } 656214501Srpaulo } 657214501Srpaulo#endif /* CONFIG_IEEE80211R */ 658214501Srpaulo 659214501Srpaulo if (ciphers & WPA_CIPHER_CCMP) 660214501Srpaulo sm->pairwise = WPA_CIPHER_CCMP; 661214501Srpaulo else 662214501Srpaulo sm->pairwise = WPA_CIPHER_TKIP; 663214501Srpaulo 664214501Srpaulo /* TODO: clear WPA/WPA2 state if STA changes from one to another */ 665214501Srpaulo if (wpa_ie[0] == WLAN_EID_RSN) 666214501Srpaulo sm->wpa = WPA_VERSION_WPA2; 667214501Srpaulo else 668214501Srpaulo sm->wpa = WPA_VERSION_WPA; 669214501Srpaulo 670214501Srpaulo sm->pmksa = NULL; 671214501Srpaulo for (i = 0; i < data.num_pmkid; i++) { 672214501Srpaulo wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", 673214501Srpaulo &data.pmkid[i * PMKID_LEN], PMKID_LEN); 674214501Srpaulo sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, 675214501Srpaulo &data.pmkid[i * PMKID_LEN]); 676214501Srpaulo if (sm->pmksa) { 677214501Srpaulo pmkid = sm->pmksa->pmkid; 678214501Srpaulo break; 679214501Srpaulo } 680214501Srpaulo } 681214501Srpaulo for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && 682214501Srpaulo i < data.num_pmkid; i++) { 683214501Srpaulo struct wpa_auth_okc_iter_data idata; 684214501Srpaulo idata.pmksa = NULL; 685214501Srpaulo idata.aa = wpa_auth->addr; 686214501Srpaulo idata.spa = sm->addr; 687214501Srpaulo idata.pmkid = &data.pmkid[i * PMKID_LEN]; 688214501Srpaulo wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); 689214501Srpaulo if (idata.pmksa) { 690214501Srpaulo wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, 691214501Srpaulo "OKC match for PMKID"); 692214501Srpaulo sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, 693214501Srpaulo idata.pmksa, 694214501Srpaulo wpa_auth->addr, 695214501Srpaulo idata.pmkid); 696214501Srpaulo pmkid = idata.pmkid; 697214501Srpaulo break; 698214501Srpaulo } 699214501Srpaulo } 700214501Srpaulo if (sm->pmksa) { 701214501Srpaulo wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, 702214501Srpaulo "PMKID found from PMKSA cache " 703214501Srpaulo "eap_type=%d vlan_id=%d", 704214501Srpaulo sm->pmksa->eap_type_authsrv, 705214501Srpaulo sm->pmksa->vlan_id); 706214501Srpaulo os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); 707214501Srpaulo } 708214501Srpaulo 709214501Srpaulo if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { 710214501Srpaulo os_free(sm->wpa_ie); 711214501Srpaulo sm->wpa_ie = os_malloc(wpa_ie_len); 712214501Srpaulo if (sm->wpa_ie == NULL) 713214501Srpaulo return WPA_ALLOC_FAIL; 714214501Srpaulo } 715214501Srpaulo os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); 716214501Srpaulo sm->wpa_ie_len = wpa_ie_len; 717214501Srpaulo 718214501Srpaulo return WPA_IE_OK; 719214501Srpaulo} 720214501Srpaulo 721214501Srpaulo 722214501Srpaulo/** 723214501Srpaulo * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 724214501Srpaulo * @pos: Pointer to the IE header 725214501Srpaulo * @end: Pointer to the end of the Key Data buffer 726214501Srpaulo * @ie: Pointer to parsed IE data 727214501Srpaulo * Returns: 0 on success, 1 if end mark is found, -1 on failure 728214501Srpaulo */ 729214501Srpaulostatic int wpa_parse_generic(const u8 *pos, const u8 *end, 730214501Srpaulo struct wpa_eapol_ie_parse *ie) 731214501Srpaulo{ 732214501Srpaulo if (pos[1] == 0) 733214501Srpaulo return 1; 734214501Srpaulo 735214501Srpaulo if (pos[1] >= 6 && 736214501Srpaulo RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 737214501Srpaulo pos[2 + WPA_SELECTOR_LEN] == 1 && 738214501Srpaulo pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 739214501Srpaulo ie->wpa_ie = pos; 740214501Srpaulo ie->wpa_ie_len = pos[1] + 2; 741214501Srpaulo return 0; 742214501Srpaulo } 743214501Srpaulo 744214501Srpaulo if (pos + 1 + RSN_SELECTOR_LEN < end && 745214501Srpaulo pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 746214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 747214501Srpaulo ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 748214501Srpaulo return 0; 749214501Srpaulo } 750214501Srpaulo 751214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 752214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 753214501Srpaulo ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 754214501Srpaulo ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 755214501Srpaulo return 0; 756214501Srpaulo } 757214501Srpaulo 758214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 759214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 760214501Srpaulo ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 761214501Srpaulo ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 762214501Srpaulo return 0; 763214501Srpaulo } 764214501Srpaulo 765214501Srpaulo#ifdef CONFIG_PEERKEY 766214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 767214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 768214501Srpaulo ie->smk = pos + 2 + RSN_SELECTOR_LEN; 769214501Srpaulo ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 770214501Srpaulo return 0; 771214501Srpaulo } 772214501Srpaulo 773214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 774214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 775214501Srpaulo ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 776214501Srpaulo ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 777214501Srpaulo return 0; 778214501Srpaulo } 779214501Srpaulo 780214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 781214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 782214501Srpaulo ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 783214501Srpaulo ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 784214501Srpaulo return 0; 785214501Srpaulo } 786214501Srpaulo 787214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 788214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 789214501Srpaulo ie->error = pos + 2 + RSN_SELECTOR_LEN; 790214501Srpaulo ie->error_len = pos[1] - RSN_SELECTOR_LEN; 791214501Srpaulo return 0; 792214501Srpaulo } 793214501Srpaulo#endif /* CONFIG_PEERKEY */ 794214501Srpaulo 795214501Srpaulo#ifdef CONFIG_IEEE80211W 796214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 797214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 798214501Srpaulo ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 799214501Srpaulo ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 800214501Srpaulo return 0; 801214501Srpaulo } 802214501Srpaulo#endif /* CONFIG_IEEE80211W */ 803214501Srpaulo 804214501Srpaulo return 0; 805214501Srpaulo} 806214501Srpaulo 807214501Srpaulo 808214501Srpaulo/** 809214501Srpaulo * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs 810214501Srpaulo * @buf: Pointer to the Key Data buffer 811214501Srpaulo * @len: Key Data Length 812214501Srpaulo * @ie: Pointer to parsed IE data 813214501Srpaulo * Returns: 0 on success, -1 on failure 814214501Srpaulo */ 815214501Srpauloint wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) 816214501Srpaulo{ 817214501Srpaulo const u8 *pos, *end; 818214501Srpaulo int ret = 0; 819214501Srpaulo 820214501Srpaulo os_memset(ie, 0, sizeof(*ie)); 821214501Srpaulo for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 822214501Srpaulo if (pos[0] == 0xdd && 823214501Srpaulo ((pos == buf + len - 1) || pos[1] == 0)) { 824214501Srpaulo /* Ignore padding */ 825214501Srpaulo break; 826214501Srpaulo } 827214501Srpaulo if (pos + 2 + pos[1] > end) { 828214501Srpaulo wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 829214501Srpaulo "underflow (ie=%d len=%d pos=%d)", 830214501Srpaulo pos[0], pos[1], (int) (pos - buf)); 831214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 832214501Srpaulo buf, len); 833214501Srpaulo ret = -1; 834214501Srpaulo break; 835214501Srpaulo } 836214501Srpaulo if (*pos == WLAN_EID_RSN) { 837214501Srpaulo ie->rsn_ie = pos; 838214501Srpaulo ie->rsn_ie_len = pos[1] + 2; 839214501Srpaulo#ifdef CONFIG_IEEE80211R 840214501Srpaulo } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 841214501Srpaulo ie->mdie = pos; 842214501Srpaulo ie->mdie_len = pos[1] + 2; 843214501Srpaulo } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 844214501Srpaulo ie->ftie = pos; 845214501Srpaulo ie->ftie_len = pos[1] + 2; 846214501Srpaulo#endif /* CONFIG_IEEE80211R */ 847214501Srpaulo } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 848214501Srpaulo ret = wpa_parse_generic(pos, end, ie); 849214501Srpaulo if (ret < 0) 850214501Srpaulo break; 851214501Srpaulo if (ret > 0) { 852214501Srpaulo ret = 0; 853214501Srpaulo break; 854214501Srpaulo } 855214501Srpaulo } else { 856214501Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 857214501Srpaulo "Key Data IE", pos, 2 + pos[1]); 858214501Srpaulo } 859214501Srpaulo } 860214501Srpaulo 861214501Srpaulo return ret; 862214501Srpaulo} 863214501Srpaulo 864214501Srpaulo 865214501Srpauloint wpa_auth_uses_mfp(struct wpa_state_machine *sm) 866214501Srpaulo{ 867214501Srpaulo return sm ? sm->mgmt_frame_prot : 0; 868214501Srpaulo} 869