wpa_auth_ie.c revision 252726
1214501Srpaulo/* 2214501Srpaulo * hostapd - WPA/RSN IE and KDE definitions 3214501Srpaulo * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12214501Srpaulo#include "common/ieee802_11_defs.h" 13214501Srpaulo#include "eapol_auth/eapol_auth_sm.h" 14214501Srpaulo#include "ap_config.h" 15214501Srpaulo#include "ieee802_11.h" 16214501Srpaulo#include "wpa_auth.h" 17214501Srpaulo#include "pmksa_cache_auth.h" 18214501Srpaulo#include "wpa_auth_ie.h" 19214501Srpaulo#include "wpa_auth_i.h" 20214501Srpaulo 21214501Srpaulo 22252726Srpaulo#ifdef CONFIG_RSN_TESTING 23252726Srpauloint rsn_testing = 0; 24252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 25252726Srpaulo 26252726Srpaulo 27214501Srpaulostatic int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) 28214501Srpaulo{ 29214501Srpaulo struct wpa_ie_hdr *hdr; 30214501Srpaulo int num_suites; 31214501Srpaulo u8 *pos, *count; 32252726Srpaulo u32 suite; 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 40252726Srpaulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group); 41252726Srpaulo if (suite == 0) { 42214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", 43214501Srpaulo conf->wpa_group); 44214501Srpaulo return -1; 45214501Srpaulo } 46252726Srpaulo RSN_SELECTOR_PUT(pos, suite); 47214501Srpaulo pos += WPA_SELECTOR_LEN; 48214501Srpaulo 49214501Srpaulo count = pos; 50214501Srpaulo pos += 2; 51214501Srpaulo 52252726Srpaulo num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise); 53214501Srpaulo if (num_suites == 0) { 54214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", 55214501Srpaulo conf->wpa_pairwise); 56214501Srpaulo return -1; 57214501Srpaulo } 58252726Srpaulo pos += num_suites * WPA_SELECTOR_LEN; 59214501Srpaulo WPA_PUT_LE16(count, num_suites); 60214501Srpaulo 61214501Srpaulo num_suites = 0; 62214501Srpaulo count = pos; 63214501Srpaulo pos += 2; 64214501Srpaulo 65214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 66214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 67214501Srpaulo pos += WPA_SELECTOR_LEN; 68214501Srpaulo num_suites++; 69214501Srpaulo } 70214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { 71214501Srpaulo RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 72214501Srpaulo pos += WPA_SELECTOR_LEN; 73214501Srpaulo num_suites++; 74214501Srpaulo } 75214501Srpaulo 76214501Srpaulo if (num_suites == 0) { 77214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", 78214501Srpaulo conf->wpa_key_mgmt); 79214501Srpaulo return -1; 80214501Srpaulo } 81214501Srpaulo WPA_PUT_LE16(count, num_suites); 82214501Srpaulo 83214501Srpaulo /* WPA Capabilities; use defaults, so no need to include it */ 84214501Srpaulo 85214501Srpaulo hdr->len = (pos - buf) - 2; 86214501Srpaulo 87214501Srpaulo return pos - buf; 88214501Srpaulo} 89214501Srpaulo 90214501Srpaulo 91214501Srpauloint wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, 92214501Srpaulo const u8 *pmkid) 93214501Srpaulo{ 94214501Srpaulo struct rsn_ie_hdr *hdr; 95252726Srpaulo int num_suites, res; 96214501Srpaulo u8 *pos, *count; 97214501Srpaulo u16 capab; 98252726Srpaulo u32 suite; 99214501Srpaulo 100214501Srpaulo hdr = (struct rsn_ie_hdr *) buf; 101214501Srpaulo hdr->elem_id = WLAN_EID_RSN; 102214501Srpaulo WPA_PUT_LE16(hdr->version, RSN_VERSION); 103214501Srpaulo pos = (u8 *) (hdr + 1); 104214501Srpaulo 105252726Srpaulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group); 106252726Srpaulo if (suite == 0) { 107214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", 108214501Srpaulo conf->wpa_group); 109214501Srpaulo return -1; 110214501Srpaulo } 111252726Srpaulo RSN_SELECTOR_PUT(pos, suite); 112214501Srpaulo pos += RSN_SELECTOR_LEN; 113214501Srpaulo 114214501Srpaulo num_suites = 0; 115214501Srpaulo count = pos; 116214501Srpaulo pos += 2; 117214501Srpaulo 118252726Srpaulo#ifdef CONFIG_RSN_TESTING 119252726Srpaulo if (rsn_testing) { 120252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); 121214501Srpaulo pos += RSN_SELECTOR_LEN; 122214501Srpaulo num_suites++; 123214501Srpaulo } 124252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 125252726Srpaulo 126252726Srpaulo res = rsn_cipher_put_suites(pos, conf->rsn_pairwise); 127252726Srpaulo num_suites += res; 128252726Srpaulo pos += res * RSN_SELECTOR_LEN; 129252726Srpaulo 130252726Srpaulo#ifdef CONFIG_RSN_TESTING 131252726Srpaulo if (rsn_testing) { 132252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); 133214501Srpaulo pos += RSN_SELECTOR_LEN; 134214501Srpaulo num_suites++; 135214501Srpaulo } 136252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 137214501Srpaulo 138214501Srpaulo if (num_suites == 0) { 139214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", 140214501Srpaulo conf->rsn_pairwise); 141214501Srpaulo return -1; 142214501Srpaulo } 143214501Srpaulo WPA_PUT_LE16(count, num_suites); 144214501Srpaulo 145214501Srpaulo num_suites = 0; 146214501Srpaulo count = pos; 147214501Srpaulo pos += 2; 148214501Srpaulo 149252726Srpaulo#ifdef CONFIG_RSN_TESTING 150252726Srpaulo if (rsn_testing) { 151252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); 152252726Srpaulo pos += RSN_SELECTOR_LEN; 153252726Srpaulo num_suites++; 154252726Srpaulo } 155252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 156252726Srpaulo 157214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 158214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 159214501Srpaulo pos += RSN_SELECTOR_LEN; 160214501Srpaulo num_suites++; 161214501Srpaulo } 162214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { 163214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 164214501Srpaulo pos += RSN_SELECTOR_LEN; 165214501Srpaulo num_suites++; 166214501Srpaulo } 167214501Srpaulo#ifdef CONFIG_IEEE80211R 168214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 169214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 170214501Srpaulo pos += RSN_SELECTOR_LEN; 171214501Srpaulo num_suites++; 172214501Srpaulo } 173214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { 174214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 175214501Srpaulo pos += RSN_SELECTOR_LEN; 176214501Srpaulo num_suites++; 177214501Srpaulo } 178214501Srpaulo#endif /* CONFIG_IEEE80211R */ 179214501Srpaulo#ifdef CONFIG_IEEE80211W 180214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 181214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 182214501Srpaulo pos += RSN_SELECTOR_LEN; 183214501Srpaulo num_suites++; 184214501Srpaulo } 185214501Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 186214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 187214501Srpaulo pos += RSN_SELECTOR_LEN; 188214501Srpaulo num_suites++; 189214501Srpaulo } 190214501Srpaulo#endif /* CONFIG_IEEE80211W */ 191252726Srpaulo#ifdef CONFIG_SAE 192252726Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { 193252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); 194252726Srpaulo pos += RSN_SELECTOR_LEN; 195252726Srpaulo num_suites++; 196252726Srpaulo } 197252726Srpaulo if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { 198252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); 199252726Srpaulo pos += RSN_SELECTOR_LEN; 200252726Srpaulo num_suites++; 201252726Srpaulo } 202252726Srpaulo#endif /* CONFIG_SAE */ 203214501Srpaulo 204252726Srpaulo#ifdef CONFIG_RSN_TESTING 205252726Srpaulo if (rsn_testing) { 206252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); 207252726Srpaulo pos += RSN_SELECTOR_LEN; 208252726Srpaulo num_suites++; 209252726Srpaulo } 210252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 211252726Srpaulo 212214501Srpaulo if (num_suites == 0) { 213214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", 214214501Srpaulo conf->wpa_key_mgmt); 215214501Srpaulo return -1; 216214501Srpaulo } 217214501Srpaulo WPA_PUT_LE16(count, num_suites); 218214501Srpaulo 219214501Srpaulo /* RSN Capabilities */ 220214501Srpaulo capab = 0; 221214501Srpaulo if (conf->rsn_preauth) 222214501Srpaulo capab |= WPA_CAPABILITY_PREAUTH; 223214501Srpaulo if (conf->peerkey) 224214501Srpaulo capab |= WPA_CAPABILITY_PEERKEY_ENABLED; 225214501Srpaulo if (conf->wmm_enabled) { 226214501Srpaulo /* 4 PTKSA replay counters when using WMM */ 227214501Srpaulo capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); 228214501Srpaulo } 229214501Srpaulo#ifdef CONFIG_IEEE80211W 230214501Srpaulo if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 231214501Srpaulo capab |= WPA_CAPABILITY_MFPC; 232214501Srpaulo if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) 233214501Srpaulo capab |= WPA_CAPABILITY_MFPR; 234214501Srpaulo } 235214501Srpaulo#endif /* CONFIG_IEEE80211W */ 236252726Srpaulo#ifdef CONFIG_RSN_TESTING 237252726Srpaulo if (rsn_testing) 238252726Srpaulo capab |= BIT(8) | BIT(14) | BIT(15); 239252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 240214501Srpaulo WPA_PUT_LE16(pos, capab); 241214501Srpaulo pos += 2; 242214501Srpaulo 243214501Srpaulo if (pmkid) { 244214501Srpaulo if (pos + 2 + PMKID_LEN > buf + len) 245214501Srpaulo return -1; 246214501Srpaulo /* PMKID Count */ 247214501Srpaulo WPA_PUT_LE16(pos, 1); 248214501Srpaulo pos += 2; 249214501Srpaulo os_memcpy(pos, pmkid, PMKID_LEN); 250214501Srpaulo pos += PMKID_LEN; 251214501Srpaulo } 252214501Srpaulo 253214501Srpaulo#ifdef CONFIG_IEEE80211W 254214501Srpaulo if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 255214501Srpaulo if (pos + 2 + 4 > buf + len) 256214501Srpaulo return -1; 257214501Srpaulo if (pmkid == NULL) { 258214501Srpaulo /* PMKID Count */ 259214501Srpaulo WPA_PUT_LE16(pos, 0); 260214501Srpaulo pos += 2; 261214501Srpaulo } 262214501Srpaulo 263214501Srpaulo /* Management Group Cipher Suite */ 264214501Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 265214501Srpaulo pos += RSN_SELECTOR_LEN; 266214501Srpaulo } 267214501Srpaulo#endif /* CONFIG_IEEE80211W */ 268214501Srpaulo 269252726Srpaulo#ifdef CONFIG_RSN_TESTING 270252726Srpaulo if (rsn_testing) { 271252726Srpaulo /* 272252726Srpaulo * Fill in any defined fields and add extra data to the end of 273252726Srpaulo * the element. 274252726Srpaulo */ 275252726Srpaulo int pmkid_count_set = pmkid != NULL; 276252726Srpaulo if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) 277252726Srpaulo pmkid_count_set = 1; 278252726Srpaulo /* PMKID Count */ 279252726Srpaulo WPA_PUT_LE16(pos, 0); 280252726Srpaulo pos += 2; 281252726Srpaulo if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { 282252726Srpaulo /* Management Group Cipher Suite */ 283252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 284252726Srpaulo pos += RSN_SELECTOR_LEN; 285252726Srpaulo } 286252726Srpaulo 287252726Srpaulo os_memset(pos, 0x12, 17); 288252726Srpaulo pos += 17; 289252726Srpaulo } 290252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 291252726Srpaulo 292214501Srpaulo hdr->len = (pos - buf) - 2; 293214501Srpaulo 294214501Srpaulo return pos - buf; 295214501Srpaulo} 296214501Srpaulo 297214501Srpaulo 298214501Srpauloint wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) 299214501Srpaulo{ 300214501Srpaulo u8 *pos, buf[128]; 301214501Srpaulo int res; 302214501Srpaulo 303214501Srpaulo pos = buf; 304214501Srpaulo 305214501Srpaulo if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { 306214501Srpaulo res = wpa_write_rsn_ie(&wpa_auth->conf, 307214501Srpaulo pos, buf + sizeof(buf) - pos, NULL); 308214501Srpaulo if (res < 0) 309214501Srpaulo return res; 310214501Srpaulo pos += res; 311214501Srpaulo } 312214501Srpaulo#ifdef CONFIG_IEEE80211R 313252726Srpaulo if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) { 314214501Srpaulo res = wpa_write_mdie(&wpa_auth->conf, pos, 315214501Srpaulo buf + sizeof(buf) - pos); 316214501Srpaulo if (res < 0) 317214501Srpaulo return res; 318214501Srpaulo pos += res; 319214501Srpaulo } 320214501Srpaulo#endif /* CONFIG_IEEE80211R */ 321214501Srpaulo if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { 322214501Srpaulo res = wpa_write_wpa_ie(&wpa_auth->conf, 323214501Srpaulo pos, buf + sizeof(buf) - pos); 324214501Srpaulo if (res < 0) 325214501Srpaulo return res; 326214501Srpaulo pos += res; 327214501Srpaulo } 328214501Srpaulo 329214501Srpaulo os_free(wpa_auth->wpa_ie); 330214501Srpaulo wpa_auth->wpa_ie = os_malloc(pos - buf); 331214501Srpaulo if (wpa_auth->wpa_ie == NULL) 332214501Srpaulo return -1; 333214501Srpaulo os_memcpy(wpa_auth->wpa_ie, buf, pos - buf); 334214501Srpaulo wpa_auth->wpa_ie_len = pos - buf; 335214501Srpaulo 336214501Srpaulo return 0; 337214501Srpaulo} 338214501Srpaulo 339214501Srpaulo 340214501Srpaulou8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, 341214501Srpaulo const u8 *data2, size_t data2_len) 342214501Srpaulo{ 343214501Srpaulo *pos++ = WLAN_EID_VENDOR_SPECIFIC; 344214501Srpaulo *pos++ = RSN_SELECTOR_LEN + data_len + data2_len; 345214501Srpaulo RSN_SELECTOR_PUT(pos, kde); 346214501Srpaulo pos += RSN_SELECTOR_LEN; 347214501Srpaulo os_memcpy(pos, data, data_len); 348214501Srpaulo pos += data_len; 349214501Srpaulo if (data2) { 350214501Srpaulo os_memcpy(pos, data2, data2_len); 351214501Srpaulo pos += data2_len; 352214501Srpaulo } 353214501Srpaulo return pos; 354214501Srpaulo} 355214501Srpaulo 356214501Srpaulo 357214501Srpaulostruct wpa_auth_okc_iter_data { 358214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 359214501Srpaulo const u8 *aa; 360214501Srpaulo const u8 *spa; 361214501Srpaulo const u8 *pmkid; 362214501Srpaulo}; 363214501Srpaulo 364214501Srpaulo 365214501Srpaulostatic int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) 366214501Srpaulo{ 367214501Srpaulo struct wpa_auth_okc_iter_data *data = ctx; 368214501Srpaulo data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa, 369214501Srpaulo data->pmkid); 370214501Srpaulo if (data->pmksa) 371214501Srpaulo return 1; 372214501Srpaulo return 0; 373214501Srpaulo} 374214501Srpaulo 375214501Srpaulo 376214501Srpauloint wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, 377214501Srpaulo struct wpa_state_machine *sm, 378214501Srpaulo const u8 *wpa_ie, size_t wpa_ie_len, 379214501Srpaulo const u8 *mdie, size_t mdie_len) 380214501Srpaulo{ 381214501Srpaulo struct wpa_ie_data data; 382214501Srpaulo int ciphers, key_mgmt, res, version; 383214501Srpaulo u32 selector; 384214501Srpaulo size_t i; 385214501Srpaulo const u8 *pmkid = NULL; 386214501Srpaulo 387214501Srpaulo if (wpa_auth == NULL || sm == NULL) 388214501Srpaulo return WPA_NOT_ENABLED; 389214501Srpaulo 390214501Srpaulo if (wpa_ie == NULL || wpa_ie_len < 1) 391214501Srpaulo return WPA_INVALID_IE; 392214501Srpaulo 393214501Srpaulo if (wpa_ie[0] == WLAN_EID_RSN) 394214501Srpaulo version = WPA_PROTO_RSN; 395214501Srpaulo else 396214501Srpaulo version = WPA_PROTO_WPA; 397214501Srpaulo 398214501Srpaulo if (!(wpa_auth->conf.wpa & version)) { 399214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, 400214501Srpaulo version, MAC2STR(sm->addr)); 401214501Srpaulo return WPA_INVALID_PROTO; 402214501Srpaulo } 403214501Srpaulo 404214501Srpaulo if (version == WPA_PROTO_RSN) { 405214501Srpaulo res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); 406214501Srpaulo 407214501Srpaulo selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; 408214501Srpaulo if (0) { 409214501Srpaulo } 410214501Srpaulo#ifdef CONFIG_IEEE80211R 411214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 412214501Srpaulo selector = RSN_AUTH_KEY_MGMT_FT_802_1X; 413214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) 414214501Srpaulo selector = RSN_AUTH_KEY_MGMT_FT_PSK; 415214501Srpaulo#endif /* CONFIG_IEEE80211R */ 416214501Srpaulo#ifdef CONFIG_IEEE80211W 417214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 418214501Srpaulo selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; 419214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 420214501Srpaulo selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; 421214501Srpaulo#endif /* CONFIG_IEEE80211W */ 422252726Srpaulo#ifdef CONFIG_SAE 423252726Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_SAE) 424252726Srpaulo selector = RSN_AUTH_KEY_MGMT_SAE; 425252726Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) 426252726Srpaulo selector = RSN_AUTH_KEY_MGMT_FT_SAE; 427252726Srpaulo#endif /* CONFIG_SAE */ 428214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) 429214501Srpaulo selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; 430214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_PSK) 431214501Srpaulo selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; 432214501Srpaulo wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; 433214501Srpaulo 434252726Srpaulo selector = wpa_cipher_to_suite(WPA_PROTO_RSN, 435252726Srpaulo data.pairwise_cipher); 436252726Srpaulo if (!selector) 437214501Srpaulo selector = RSN_CIPHER_SUITE_CCMP; 438214501Srpaulo wpa_auth->dot11RSNAPairwiseCipherSelected = selector; 439214501Srpaulo 440252726Srpaulo selector = wpa_cipher_to_suite(WPA_PROTO_RSN, 441252726Srpaulo data.group_cipher); 442252726Srpaulo if (!selector) 443214501Srpaulo selector = RSN_CIPHER_SUITE_CCMP; 444214501Srpaulo wpa_auth->dot11RSNAGroupCipherSelected = selector; 445214501Srpaulo } else { 446214501Srpaulo res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); 447214501Srpaulo 448214501Srpaulo selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; 449214501Srpaulo if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) 450214501Srpaulo selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; 451214501Srpaulo else if (data.key_mgmt & WPA_KEY_MGMT_PSK) 452214501Srpaulo selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; 453214501Srpaulo wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; 454214501Srpaulo 455252726Srpaulo selector = wpa_cipher_to_suite(WPA_PROTO_WPA, 456252726Srpaulo data.pairwise_cipher); 457252726Srpaulo if (!selector) 458252726Srpaulo selector = RSN_CIPHER_SUITE_TKIP; 459214501Srpaulo wpa_auth->dot11RSNAPairwiseCipherSelected = selector; 460214501Srpaulo 461252726Srpaulo selector = wpa_cipher_to_suite(WPA_PROTO_WPA, 462252726Srpaulo data.group_cipher); 463252726Srpaulo if (!selector) 464214501Srpaulo selector = WPA_CIPHER_SUITE_TKIP; 465214501Srpaulo wpa_auth->dot11RSNAGroupCipherSelected = selector; 466214501Srpaulo } 467214501Srpaulo if (res) { 468214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " 469214501Srpaulo MACSTR " (res=%d)", MAC2STR(sm->addr), res); 470214501Srpaulo wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); 471214501Srpaulo return WPA_INVALID_IE; 472214501Srpaulo } 473214501Srpaulo 474214501Srpaulo if (data.group_cipher != wpa_auth->conf.wpa_group) { 475214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " 476214501Srpaulo MACSTR, data.group_cipher, MAC2STR(sm->addr)); 477214501Srpaulo return WPA_INVALID_GROUP; 478214501Srpaulo } 479214501Srpaulo 480214501Srpaulo key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; 481214501Srpaulo if (!key_mgmt) { 482214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " 483214501Srpaulo MACSTR, data.key_mgmt, MAC2STR(sm->addr)); 484214501Srpaulo return WPA_INVALID_AKMP; 485214501Srpaulo } 486214501Srpaulo if (0) { 487214501Srpaulo } 488214501Srpaulo#ifdef CONFIG_IEEE80211R 489214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 490214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; 491214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) 492214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; 493214501Srpaulo#endif /* CONFIG_IEEE80211R */ 494214501Srpaulo#ifdef CONFIG_IEEE80211W 495214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 496214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; 497214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 498214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; 499214501Srpaulo#endif /* CONFIG_IEEE80211W */ 500252726Srpaulo#ifdef CONFIG_SAE 501252726Srpaulo else if (key_mgmt & WPA_KEY_MGMT_SAE) 502252726Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE; 503252726Srpaulo else if (key_mgmt & WPA_KEY_MGMT_FT_SAE) 504252726Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE; 505252726Srpaulo#endif /* CONFIG_SAE */ 506214501Srpaulo else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) 507214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; 508214501Srpaulo else 509214501Srpaulo sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; 510214501Srpaulo 511214501Srpaulo if (version == WPA_PROTO_RSN) 512214501Srpaulo ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; 513214501Srpaulo else 514214501Srpaulo ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; 515214501Srpaulo if (!ciphers) { 516214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " 517214501Srpaulo "from " MACSTR, 518214501Srpaulo version == WPA_PROTO_RSN ? "RSN" : "WPA", 519214501Srpaulo data.pairwise_cipher, MAC2STR(sm->addr)); 520214501Srpaulo return WPA_INVALID_PAIRWISE; 521214501Srpaulo } 522214501Srpaulo 523214501Srpaulo#ifdef CONFIG_IEEE80211W 524214501Srpaulo if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { 525214501Srpaulo if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { 526214501Srpaulo wpa_printf(MSG_DEBUG, "Management frame protection " 527214501Srpaulo "required, but client did not enable it"); 528214501Srpaulo return WPA_MGMT_FRAME_PROTECTION_VIOLATION; 529214501Srpaulo } 530214501Srpaulo 531214501Srpaulo if (ciphers & WPA_CIPHER_TKIP) { 532214501Srpaulo wpa_printf(MSG_DEBUG, "Management frame protection " 533214501Srpaulo "cannot use TKIP"); 534214501Srpaulo return WPA_MGMT_FRAME_PROTECTION_VIOLATION; 535214501Srpaulo } 536214501Srpaulo 537214501Srpaulo if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { 538214501Srpaulo wpa_printf(MSG_DEBUG, "Unsupported management group " 539214501Srpaulo "cipher %d", data.mgmt_group_cipher); 540214501Srpaulo return WPA_INVALID_MGMT_GROUP_CIPHER; 541214501Srpaulo } 542214501Srpaulo } 543214501Srpaulo 544214501Srpaulo if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || 545214501Srpaulo !(data.capabilities & WPA_CAPABILITY_MFPC)) 546214501Srpaulo sm->mgmt_frame_prot = 0; 547214501Srpaulo else 548214501Srpaulo sm->mgmt_frame_prot = 1; 549214501Srpaulo#endif /* CONFIG_IEEE80211W */ 550214501Srpaulo 551214501Srpaulo#ifdef CONFIG_IEEE80211R 552214501Srpaulo if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { 553214501Srpaulo if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { 554214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " 555214501Srpaulo "MDIE not included"); 556214501Srpaulo return WPA_INVALID_MDIE; 557214501Srpaulo } 558214501Srpaulo if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, 559214501Srpaulo MOBILITY_DOMAIN_ID_LEN) != 0) { 560214501Srpaulo wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " 561214501Srpaulo "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); 562214501Srpaulo return WPA_INVALID_MDIE; 563214501Srpaulo } 564214501Srpaulo } 565214501Srpaulo#endif /* CONFIG_IEEE80211R */ 566214501Srpaulo 567214501Srpaulo if (ciphers & WPA_CIPHER_CCMP) 568214501Srpaulo sm->pairwise = WPA_CIPHER_CCMP; 569252726Srpaulo else if (ciphers & WPA_CIPHER_GCMP) 570252726Srpaulo sm->pairwise = WPA_CIPHER_GCMP; 571214501Srpaulo else 572214501Srpaulo sm->pairwise = WPA_CIPHER_TKIP; 573214501Srpaulo 574214501Srpaulo /* TODO: clear WPA/WPA2 state if STA changes from one to another */ 575214501Srpaulo if (wpa_ie[0] == WLAN_EID_RSN) 576214501Srpaulo sm->wpa = WPA_VERSION_WPA2; 577214501Srpaulo else 578214501Srpaulo sm->wpa = WPA_VERSION_WPA; 579214501Srpaulo 580214501Srpaulo sm->pmksa = NULL; 581214501Srpaulo for (i = 0; i < data.num_pmkid; i++) { 582214501Srpaulo wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", 583214501Srpaulo &data.pmkid[i * PMKID_LEN], PMKID_LEN); 584214501Srpaulo sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, 585214501Srpaulo &data.pmkid[i * PMKID_LEN]); 586214501Srpaulo if (sm->pmksa) { 587214501Srpaulo pmkid = sm->pmksa->pmkid; 588214501Srpaulo break; 589214501Srpaulo } 590214501Srpaulo } 591214501Srpaulo for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && 592214501Srpaulo i < data.num_pmkid; i++) { 593214501Srpaulo struct wpa_auth_okc_iter_data idata; 594214501Srpaulo idata.pmksa = NULL; 595214501Srpaulo idata.aa = wpa_auth->addr; 596214501Srpaulo idata.spa = sm->addr; 597214501Srpaulo idata.pmkid = &data.pmkid[i * PMKID_LEN]; 598214501Srpaulo wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); 599214501Srpaulo if (idata.pmksa) { 600214501Srpaulo wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, 601214501Srpaulo "OKC match for PMKID"); 602214501Srpaulo sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, 603214501Srpaulo idata.pmksa, 604214501Srpaulo wpa_auth->addr, 605214501Srpaulo idata.pmkid); 606214501Srpaulo pmkid = idata.pmkid; 607214501Srpaulo break; 608214501Srpaulo } 609214501Srpaulo } 610214501Srpaulo if (sm->pmksa) { 611214501Srpaulo wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, 612214501Srpaulo "PMKID found from PMKSA cache " 613214501Srpaulo "eap_type=%d vlan_id=%d", 614214501Srpaulo sm->pmksa->eap_type_authsrv, 615214501Srpaulo sm->pmksa->vlan_id); 616214501Srpaulo os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); 617214501Srpaulo } 618214501Srpaulo 619214501Srpaulo if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { 620214501Srpaulo os_free(sm->wpa_ie); 621214501Srpaulo sm->wpa_ie = os_malloc(wpa_ie_len); 622214501Srpaulo if (sm->wpa_ie == NULL) 623214501Srpaulo return WPA_ALLOC_FAIL; 624214501Srpaulo } 625214501Srpaulo os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); 626214501Srpaulo sm->wpa_ie_len = wpa_ie_len; 627214501Srpaulo 628214501Srpaulo return WPA_IE_OK; 629214501Srpaulo} 630214501Srpaulo 631214501Srpaulo 632214501Srpaulo/** 633214501Srpaulo * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 634214501Srpaulo * @pos: Pointer to the IE header 635214501Srpaulo * @end: Pointer to the end of the Key Data buffer 636214501Srpaulo * @ie: Pointer to parsed IE data 637214501Srpaulo * Returns: 0 on success, 1 if end mark is found, -1 on failure 638214501Srpaulo */ 639214501Srpaulostatic int wpa_parse_generic(const u8 *pos, const u8 *end, 640214501Srpaulo struct wpa_eapol_ie_parse *ie) 641214501Srpaulo{ 642214501Srpaulo if (pos[1] == 0) 643214501Srpaulo return 1; 644214501Srpaulo 645214501Srpaulo if (pos[1] >= 6 && 646214501Srpaulo RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 647214501Srpaulo pos[2 + WPA_SELECTOR_LEN] == 1 && 648214501Srpaulo pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 649214501Srpaulo ie->wpa_ie = pos; 650214501Srpaulo ie->wpa_ie_len = pos[1] + 2; 651214501Srpaulo return 0; 652214501Srpaulo } 653214501Srpaulo 654214501Srpaulo if (pos + 1 + RSN_SELECTOR_LEN < end && 655214501Srpaulo pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 656214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 657214501Srpaulo ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 658214501Srpaulo return 0; 659214501Srpaulo } 660214501Srpaulo 661214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 662214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 663214501Srpaulo ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 664214501Srpaulo ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 665214501Srpaulo return 0; 666214501Srpaulo } 667214501Srpaulo 668214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 669214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 670214501Srpaulo ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 671214501Srpaulo ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 672214501Srpaulo return 0; 673214501Srpaulo } 674214501Srpaulo 675214501Srpaulo#ifdef CONFIG_PEERKEY 676214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 677214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 678214501Srpaulo ie->smk = pos + 2 + RSN_SELECTOR_LEN; 679214501Srpaulo ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 680214501Srpaulo return 0; 681214501Srpaulo } 682214501Srpaulo 683214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 684214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 685214501Srpaulo ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 686214501Srpaulo ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 687214501Srpaulo return 0; 688214501Srpaulo } 689214501Srpaulo 690214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 691214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 692214501Srpaulo ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 693214501Srpaulo ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 694214501Srpaulo return 0; 695214501Srpaulo } 696214501Srpaulo 697214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 698214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 699214501Srpaulo ie->error = pos + 2 + RSN_SELECTOR_LEN; 700214501Srpaulo ie->error_len = pos[1] - RSN_SELECTOR_LEN; 701214501Srpaulo return 0; 702214501Srpaulo } 703214501Srpaulo#endif /* CONFIG_PEERKEY */ 704214501Srpaulo 705214501Srpaulo#ifdef CONFIG_IEEE80211W 706214501Srpaulo if (pos[1] > RSN_SELECTOR_LEN + 2 && 707214501Srpaulo RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 708214501Srpaulo ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 709214501Srpaulo ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 710214501Srpaulo return 0; 711214501Srpaulo } 712214501Srpaulo#endif /* CONFIG_IEEE80211W */ 713214501Srpaulo 714214501Srpaulo return 0; 715214501Srpaulo} 716214501Srpaulo 717214501Srpaulo 718214501Srpaulo/** 719214501Srpaulo * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs 720214501Srpaulo * @buf: Pointer to the Key Data buffer 721214501Srpaulo * @len: Key Data Length 722214501Srpaulo * @ie: Pointer to parsed IE data 723214501Srpaulo * Returns: 0 on success, -1 on failure 724214501Srpaulo */ 725214501Srpauloint wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) 726214501Srpaulo{ 727214501Srpaulo const u8 *pos, *end; 728214501Srpaulo int ret = 0; 729214501Srpaulo 730214501Srpaulo os_memset(ie, 0, sizeof(*ie)); 731214501Srpaulo for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 732214501Srpaulo if (pos[0] == 0xdd && 733214501Srpaulo ((pos == buf + len - 1) || pos[1] == 0)) { 734214501Srpaulo /* Ignore padding */ 735214501Srpaulo break; 736214501Srpaulo } 737214501Srpaulo if (pos + 2 + pos[1] > end) { 738214501Srpaulo wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 739214501Srpaulo "underflow (ie=%d len=%d pos=%d)", 740214501Srpaulo pos[0], pos[1], (int) (pos - buf)); 741214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 742214501Srpaulo buf, len); 743214501Srpaulo ret = -1; 744214501Srpaulo break; 745214501Srpaulo } 746214501Srpaulo if (*pos == WLAN_EID_RSN) { 747214501Srpaulo ie->rsn_ie = pos; 748214501Srpaulo ie->rsn_ie_len = pos[1] + 2; 749214501Srpaulo#ifdef CONFIG_IEEE80211R 750214501Srpaulo } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 751214501Srpaulo ie->mdie = pos; 752214501Srpaulo ie->mdie_len = pos[1] + 2; 753214501Srpaulo } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 754214501Srpaulo ie->ftie = pos; 755214501Srpaulo ie->ftie_len = pos[1] + 2; 756214501Srpaulo#endif /* CONFIG_IEEE80211R */ 757214501Srpaulo } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 758214501Srpaulo ret = wpa_parse_generic(pos, end, ie); 759214501Srpaulo if (ret < 0) 760214501Srpaulo break; 761214501Srpaulo if (ret > 0) { 762214501Srpaulo ret = 0; 763214501Srpaulo break; 764214501Srpaulo } 765214501Srpaulo } else { 766214501Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 767214501Srpaulo "Key Data IE", pos, 2 + pos[1]); 768214501Srpaulo } 769214501Srpaulo } 770214501Srpaulo 771214501Srpaulo return ret; 772214501Srpaulo} 773214501Srpaulo 774214501Srpaulo 775214501Srpauloint wpa_auth_uses_mfp(struct wpa_state_machine *sm) 776214501Srpaulo{ 777214501Srpaulo return sm ? sm->mgmt_frame_prot : 0; 778214501Srpaulo} 779