wpa_common.c revision 252726
1189251Ssam/* 2189251Ssam * WPA/RSN - Shared functions for supplicant and authenticator 3189251Ssam * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/md5.h" 13214734Srpaulo#include "crypto/sha1.h" 14214734Srpaulo#include "crypto/sha256.h" 15214734Srpaulo#include "crypto/aes_wrap.h" 16214734Srpaulo#include "crypto/crypto.h" 17189251Ssam#include "ieee802_11_defs.h" 18189251Ssam#include "defs.h" 19189251Ssam#include "wpa_common.h" 20189251Ssam 21189251Ssam 22189251Ssam/** 23189251Ssam * wpa_eapol_key_mic - Calculate EAPOL-Key MIC 24189251Ssam * @key: EAPOL-Key Key Confirmation Key (KCK) 25189251Ssam * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) 26189251Ssam * @buf: Pointer to the beginning of the EAPOL header (version field) 27189251Ssam * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) 28189251Ssam * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written 29189251Ssam * Returns: 0 on success, -1 on failure 30189251Ssam * 31189251Ssam * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has 32189251Ssam * to be cleared (all zeroes) when calling this function. 33189251Ssam * 34189251Ssam * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the 35189251Ssam * description of the Key MIC calculation. It includes packet data from the 36189251Ssam * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change 37189251Ssam * happened during final editing of the standard and the correct behavior is 38189251Ssam * defined in the last draft (IEEE 802.11i/D10). 39189251Ssam */ 40189251Ssamint wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, 41189251Ssam u8 *mic) 42189251Ssam{ 43189251Ssam u8 hash[SHA1_MAC_LEN]; 44189251Ssam 45189251Ssam switch (ver) { 46252726Srpaulo#ifndef CONFIG_FIPS 47189251Ssam case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: 48214734Srpaulo return hmac_md5(key, 16, buf, len, mic); 49252726Srpaulo#endif /* CONFIG_FIPS */ 50189251Ssam case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: 51214734Srpaulo if (hmac_sha1(key, 16, buf, len, hash)) 52214734Srpaulo return -1; 53189251Ssam os_memcpy(mic, hash, MD5_MAC_LEN); 54189251Ssam break; 55209158Srpaulo#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) 56189251Ssam case WPA_KEY_INFO_TYPE_AES_128_CMAC: 57189251Ssam return omac1_aes_128(key, buf, len, mic); 58209158Srpaulo#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ 59189251Ssam default: 60189251Ssam return -1; 61189251Ssam } 62189251Ssam 63189251Ssam return 0; 64189251Ssam} 65189251Ssam 66189251Ssam 67189251Ssam/** 68189251Ssam * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces 69189251Ssam * @pmk: Pairwise master key 70189251Ssam * @pmk_len: Length of PMK 71189251Ssam * @label: Label to use in derivation 72189251Ssam * @addr1: AA or SA 73189251Ssam * @addr2: SA or AA 74189251Ssam * @nonce1: ANonce or SNonce 75189251Ssam * @nonce2: SNonce or ANonce 76189251Ssam * @ptk: Buffer for pairwise transient key 77189251Ssam * @ptk_len: Length of PTK 78189251Ssam * @use_sha256: Whether to use SHA256-based KDF 79189251Ssam * 80189251Ssam * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy 81189251Ssam * PTK = PRF-X(PMK, "Pairwise key expansion", 82189251Ssam * Min(AA, SA) || Max(AA, SA) || 83189251Ssam * Min(ANonce, SNonce) || Max(ANonce, SNonce)) 84189251Ssam * 85189251Ssam * STK = PRF-X(SMK, "Peer key expansion", 86189251Ssam * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || 87189251Ssam * Min(INonce, PNonce) || Max(INonce, PNonce)) 88189251Ssam */ 89189251Ssamvoid wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, 90189251Ssam const u8 *addr1, const u8 *addr2, 91189251Ssam const u8 *nonce1, const u8 *nonce2, 92189251Ssam u8 *ptk, size_t ptk_len, int use_sha256) 93189251Ssam{ 94189251Ssam u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; 95189251Ssam 96189251Ssam if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { 97189251Ssam os_memcpy(data, addr1, ETH_ALEN); 98189251Ssam os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); 99189251Ssam } else { 100189251Ssam os_memcpy(data, addr2, ETH_ALEN); 101189251Ssam os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); 102189251Ssam } 103189251Ssam 104189251Ssam if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { 105189251Ssam os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); 106189251Ssam os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, 107189251Ssam WPA_NONCE_LEN); 108189251Ssam } else { 109189251Ssam os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); 110189251Ssam os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, 111189251Ssam WPA_NONCE_LEN); 112189251Ssam } 113189251Ssam 114189251Ssam#ifdef CONFIG_IEEE80211W 115189251Ssam if (use_sha256) 116189251Ssam sha256_prf(pmk, pmk_len, label, data, sizeof(data), 117189251Ssam ptk, ptk_len); 118189251Ssam else 119189251Ssam#endif /* CONFIG_IEEE80211W */ 120189251Ssam sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, 121189251Ssam ptk_len); 122189251Ssam 123189251Ssam wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, 124189251Ssam MAC2STR(addr1), MAC2STR(addr2)); 125252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); 126252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); 127189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); 128189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); 129189251Ssam} 130189251Ssam 131189251Ssam 132189251Ssam#ifdef CONFIG_IEEE80211R 133189251Ssamint wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, 134189251Ssam u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, 135189251Ssam const u8 *ftie, size_t ftie_len, 136189251Ssam const u8 *rsnie, size_t rsnie_len, 137189251Ssam const u8 *ric, size_t ric_len, u8 *mic) 138189251Ssam{ 139189251Ssam u8 *buf, *pos; 140189251Ssam size_t buf_len; 141189251Ssam 142189251Ssam buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; 143189251Ssam buf = os_malloc(buf_len); 144189251Ssam if (buf == NULL) 145189251Ssam return -1; 146189251Ssam 147189251Ssam pos = buf; 148189251Ssam os_memcpy(pos, sta_addr, ETH_ALEN); 149189251Ssam pos += ETH_ALEN; 150189251Ssam os_memcpy(pos, ap_addr, ETH_ALEN); 151189251Ssam pos += ETH_ALEN; 152189251Ssam *pos++ = transaction_seqnum; 153189251Ssam if (rsnie) { 154189251Ssam os_memcpy(pos, rsnie, rsnie_len); 155189251Ssam pos += rsnie_len; 156189251Ssam } 157189251Ssam if (mdie) { 158189251Ssam os_memcpy(pos, mdie, mdie_len); 159189251Ssam pos += mdie_len; 160189251Ssam } 161189251Ssam if (ftie) { 162189251Ssam struct rsn_ftie *_ftie; 163189251Ssam os_memcpy(pos, ftie, ftie_len); 164189251Ssam if (ftie_len < 2 + sizeof(*_ftie)) { 165189251Ssam os_free(buf); 166189251Ssam return -1; 167189251Ssam } 168189251Ssam _ftie = (struct rsn_ftie *) (pos + 2); 169189251Ssam os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); 170189251Ssam pos += ftie_len; 171189251Ssam } 172189251Ssam if (ric) { 173189251Ssam os_memcpy(pos, ric, ric_len); 174189251Ssam pos += ric_len; 175189251Ssam } 176189251Ssam 177189251Ssam wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); 178189251Ssam if (omac1_aes_128(kck, buf, pos - buf, mic)) { 179189251Ssam os_free(buf); 180189251Ssam return -1; 181189251Ssam } 182189251Ssam 183189251Ssam os_free(buf); 184189251Ssam 185189251Ssam return 0; 186189251Ssam} 187252726Srpaulo 188252726Srpaulo 189252726Srpaulostatic int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, 190252726Srpaulo struct wpa_ft_ies *parse) 191252726Srpaulo{ 192252726Srpaulo const u8 *end, *pos; 193252726Srpaulo 194252726Srpaulo parse->ftie = ie; 195252726Srpaulo parse->ftie_len = ie_len; 196252726Srpaulo 197252726Srpaulo pos = ie + sizeof(struct rsn_ftie); 198252726Srpaulo end = ie + ie_len; 199252726Srpaulo 200252726Srpaulo while (pos + 2 <= end && pos + 2 + pos[1] <= end) { 201252726Srpaulo switch (pos[0]) { 202252726Srpaulo case FTIE_SUBELEM_R1KH_ID: 203252726Srpaulo if (pos[1] != FT_R1KH_ID_LEN) { 204252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " 205252726Srpaulo "length in FTIE: %d", pos[1]); 206252726Srpaulo return -1; 207252726Srpaulo } 208252726Srpaulo parse->r1kh_id = pos + 2; 209252726Srpaulo break; 210252726Srpaulo case FTIE_SUBELEM_GTK: 211252726Srpaulo parse->gtk = pos + 2; 212252726Srpaulo parse->gtk_len = pos[1]; 213252726Srpaulo break; 214252726Srpaulo case FTIE_SUBELEM_R0KH_ID: 215252726Srpaulo if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { 216252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " 217252726Srpaulo "length in FTIE: %d", pos[1]); 218252726Srpaulo return -1; 219252726Srpaulo } 220252726Srpaulo parse->r0kh_id = pos + 2; 221252726Srpaulo parse->r0kh_id_len = pos[1]; 222252726Srpaulo break; 223252726Srpaulo#ifdef CONFIG_IEEE80211W 224252726Srpaulo case FTIE_SUBELEM_IGTK: 225252726Srpaulo parse->igtk = pos + 2; 226252726Srpaulo parse->igtk_len = pos[1]; 227252726Srpaulo break; 228252726Srpaulo#endif /* CONFIG_IEEE80211W */ 229252726Srpaulo } 230252726Srpaulo 231252726Srpaulo pos += 2 + pos[1]; 232252726Srpaulo } 233252726Srpaulo 234252726Srpaulo return 0; 235252726Srpaulo} 236252726Srpaulo 237252726Srpaulo 238252726Srpauloint wpa_ft_parse_ies(const u8 *ies, size_t ies_len, 239252726Srpaulo struct wpa_ft_ies *parse) 240252726Srpaulo{ 241252726Srpaulo const u8 *end, *pos; 242252726Srpaulo struct wpa_ie_data data; 243252726Srpaulo int ret; 244252726Srpaulo const struct rsn_ftie *ftie; 245252726Srpaulo int prot_ie_count = 0; 246252726Srpaulo 247252726Srpaulo os_memset(parse, 0, sizeof(*parse)); 248252726Srpaulo if (ies == NULL) 249252726Srpaulo return 0; 250252726Srpaulo 251252726Srpaulo pos = ies; 252252726Srpaulo end = ies + ies_len; 253252726Srpaulo while (pos + 2 <= end && pos + 2 + pos[1] <= end) { 254252726Srpaulo switch (pos[0]) { 255252726Srpaulo case WLAN_EID_RSN: 256252726Srpaulo parse->rsn = pos + 2; 257252726Srpaulo parse->rsn_len = pos[1]; 258252726Srpaulo ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, 259252726Srpaulo parse->rsn_len + 2, 260252726Srpaulo &data); 261252726Srpaulo if (ret < 0) { 262252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Failed to parse " 263252726Srpaulo "RSN IE: %d", ret); 264252726Srpaulo return -1; 265252726Srpaulo } 266252726Srpaulo if (data.num_pmkid == 1 && data.pmkid) 267252726Srpaulo parse->rsn_pmkid = data.pmkid; 268252726Srpaulo break; 269252726Srpaulo case WLAN_EID_MOBILITY_DOMAIN: 270252726Srpaulo parse->mdie = pos + 2; 271252726Srpaulo parse->mdie_len = pos[1]; 272252726Srpaulo break; 273252726Srpaulo case WLAN_EID_FAST_BSS_TRANSITION: 274252726Srpaulo if (pos[1] < sizeof(*ftie)) 275252726Srpaulo return -1; 276252726Srpaulo ftie = (const struct rsn_ftie *) (pos + 2); 277252726Srpaulo prot_ie_count = ftie->mic_control[1]; 278252726Srpaulo if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) 279252726Srpaulo return -1; 280252726Srpaulo break; 281252726Srpaulo case WLAN_EID_TIMEOUT_INTERVAL: 282252726Srpaulo parse->tie = pos + 2; 283252726Srpaulo parse->tie_len = pos[1]; 284252726Srpaulo break; 285252726Srpaulo case WLAN_EID_RIC_DATA: 286252726Srpaulo if (parse->ric == NULL) 287252726Srpaulo parse->ric = pos; 288252726Srpaulo break; 289252726Srpaulo } 290252726Srpaulo 291252726Srpaulo pos += 2 + pos[1]; 292252726Srpaulo } 293252726Srpaulo 294252726Srpaulo if (prot_ie_count == 0) 295252726Srpaulo return 0; /* no MIC */ 296252726Srpaulo 297252726Srpaulo /* 298252726Srpaulo * Check that the protected IE count matches with IEs included in the 299252726Srpaulo * frame. 300252726Srpaulo */ 301252726Srpaulo if (parse->rsn) 302252726Srpaulo prot_ie_count--; 303252726Srpaulo if (parse->mdie) 304252726Srpaulo prot_ie_count--; 305252726Srpaulo if (parse->ftie) 306252726Srpaulo prot_ie_count--; 307252726Srpaulo if (prot_ie_count < 0) { 308252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " 309252726Srpaulo "the protected IE count"); 310252726Srpaulo return -1; 311252726Srpaulo } 312252726Srpaulo 313252726Srpaulo if (prot_ie_count == 0 && parse->ric) { 314252726Srpaulo wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " 315252726Srpaulo "included in protected IE count"); 316252726Srpaulo return -1; 317252726Srpaulo } 318252726Srpaulo 319252726Srpaulo /* Determine the end of the RIC IE(s) */ 320252726Srpaulo pos = parse->ric; 321252726Srpaulo while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && 322252726Srpaulo prot_ie_count) { 323252726Srpaulo prot_ie_count--; 324252726Srpaulo pos += 2 + pos[1]; 325252726Srpaulo } 326252726Srpaulo parse->ric_len = pos - parse->ric; 327252726Srpaulo if (prot_ie_count) { 328252726Srpaulo wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " 329252726Srpaulo "frame", (int) prot_ie_count); 330252726Srpaulo return -1; 331252726Srpaulo } 332252726Srpaulo 333252726Srpaulo return 0; 334252726Srpaulo} 335189251Ssam#endif /* CONFIG_IEEE80211R */ 336189251Ssam 337189251Ssam 338189251Ssam#ifndef CONFIG_NO_WPA2 339189251Ssamstatic int rsn_selector_to_bitfield(const u8 *s) 340189251Ssam{ 341189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) 342189251Ssam return WPA_CIPHER_NONE; 343189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) 344189251Ssam return WPA_CIPHER_WEP40; 345189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) 346189251Ssam return WPA_CIPHER_TKIP; 347189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) 348189251Ssam return WPA_CIPHER_CCMP; 349189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) 350189251Ssam return WPA_CIPHER_WEP104; 351189251Ssam#ifdef CONFIG_IEEE80211W 352189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) 353189251Ssam return WPA_CIPHER_AES_128_CMAC; 354189251Ssam#endif /* CONFIG_IEEE80211W */ 355252726Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) 356252726Srpaulo return WPA_CIPHER_GCMP; 357189251Ssam return 0; 358189251Ssam} 359189251Ssam 360189251Ssam 361189251Ssamstatic int rsn_key_mgmt_to_bitfield(const u8 *s) 362189251Ssam{ 363189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) 364189251Ssam return WPA_KEY_MGMT_IEEE8021X; 365189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) 366189251Ssam return WPA_KEY_MGMT_PSK; 367189251Ssam#ifdef CONFIG_IEEE80211R 368189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) 369189251Ssam return WPA_KEY_MGMT_FT_IEEE8021X; 370189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) 371189251Ssam return WPA_KEY_MGMT_FT_PSK; 372189251Ssam#endif /* CONFIG_IEEE80211R */ 373189251Ssam#ifdef CONFIG_IEEE80211W 374189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) 375189251Ssam return WPA_KEY_MGMT_IEEE8021X_SHA256; 376189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) 377189251Ssam return WPA_KEY_MGMT_PSK_SHA256; 378189251Ssam#endif /* CONFIG_IEEE80211W */ 379252726Srpaulo#ifdef CONFIG_SAE 380252726Srpaulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE) 381252726Srpaulo return WPA_KEY_MGMT_SAE; 382252726Srpaulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE) 383252726Srpaulo return WPA_KEY_MGMT_FT_SAE; 384252726Srpaulo#endif /* CONFIG_SAE */ 385189251Ssam return 0; 386189251Ssam} 387189251Ssam#endif /* CONFIG_NO_WPA2 */ 388189251Ssam 389189251Ssam 390189251Ssam/** 391189251Ssam * wpa_parse_wpa_ie_rsn - Parse RSN IE 392189251Ssam * @rsn_ie: Buffer containing RSN IE 393189251Ssam * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) 394189251Ssam * @data: Pointer to structure that will be filled in with parsed data 395189251Ssam * Returns: 0 on success, <0 on failure 396189251Ssam */ 397189251Ssamint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, 398189251Ssam struct wpa_ie_data *data) 399189251Ssam{ 400189251Ssam#ifndef CONFIG_NO_WPA2 401189251Ssam const struct rsn_ie_hdr *hdr; 402189251Ssam const u8 *pos; 403189251Ssam int left; 404189251Ssam int i, count; 405189251Ssam 406189251Ssam os_memset(data, 0, sizeof(*data)); 407189251Ssam data->proto = WPA_PROTO_RSN; 408189251Ssam data->pairwise_cipher = WPA_CIPHER_CCMP; 409189251Ssam data->group_cipher = WPA_CIPHER_CCMP; 410189251Ssam data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 411189251Ssam data->capabilities = 0; 412189251Ssam data->pmkid = NULL; 413189251Ssam data->num_pmkid = 0; 414189251Ssam#ifdef CONFIG_IEEE80211W 415189251Ssam data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; 416189251Ssam#else /* CONFIG_IEEE80211W */ 417189251Ssam data->mgmt_group_cipher = 0; 418189251Ssam#endif /* CONFIG_IEEE80211W */ 419189251Ssam 420189251Ssam if (rsn_ie_len == 0) { 421189251Ssam /* No RSN IE - fail silently */ 422189251Ssam return -1; 423189251Ssam } 424189251Ssam 425189251Ssam if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { 426189251Ssam wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 427189251Ssam __func__, (unsigned long) rsn_ie_len); 428189251Ssam return -1; 429189251Ssam } 430189251Ssam 431189251Ssam hdr = (const struct rsn_ie_hdr *) rsn_ie; 432189251Ssam 433189251Ssam if (hdr->elem_id != WLAN_EID_RSN || 434189251Ssam hdr->len != rsn_ie_len - 2 || 435189251Ssam WPA_GET_LE16(hdr->version) != RSN_VERSION) { 436189251Ssam wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 437189251Ssam __func__); 438189251Ssam return -2; 439189251Ssam } 440189251Ssam 441189251Ssam pos = (const u8 *) (hdr + 1); 442189251Ssam left = rsn_ie_len - sizeof(*hdr); 443189251Ssam 444189251Ssam if (left >= RSN_SELECTOR_LEN) { 445189251Ssam data->group_cipher = rsn_selector_to_bitfield(pos); 446189251Ssam#ifdef CONFIG_IEEE80211W 447189251Ssam if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { 448189251Ssam wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " 449189251Ssam "cipher", __func__); 450189251Ssam return -1; 451189251Ssam } 452189251Ssam#endif /* CONFIG_IEEE80211W */ 453189251Ssam pos += RSN_SELECTOR_LEN; 454189251Ssam left -= RSN_SELECTOR_LEN; 455189251Ssam } else if (left > 0) { 456189251Ssam wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 457189251Ssam __func__, left); 458189251Ssam return -3; 459189251Ssam } 460189251Ssam 461189251Ssam if (left >= 2) { 462189251Ssam data->pairwise_cipher = 0; 463189251Ssam count = WPA_GET_LE16(pos); 464189251Ssam pos += 2; 465189251Ssam left -= 2; 466189251Ssam if (count == 0 || left < count * RSN_SELECTOR_LEN) { 467189251Ssam wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 468189251Ssam "count %u left %u", __func__, count, left); 469189251Ssam return -4; 470189251Ssam } 471189251Ssam for (i = 0; i < count; i++) { 472189251Ssam data->pairwise_cipher |= rsn_selector_to_bitfield(pos); 473189251Ssam pos += RSN_SELECTOR_LEN; 474189251Ssam left -= RSN_SELECTOR_LEN; 475189251Ssam } 476189251Ssam#ifdef CONFIG_IEEE80211W 477189251Ssam if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { 478189251Ssam wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " 479189251Ssam "pairwise cipher", __func__); 480189251Ssam return -1; 481189251Ssam } 482189251Ssam#endif /* CONFIG_IEEE80211W */ 483189251Ssam } else if (left == 1) { 484189251Ssam wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 485189251Ssam __func__); 486189251Ssam return -5; 487189251Ssam } 488189251Ssam 489189251Ssam if (left >= 2) { 490189251Ssam data->key_mgmt = 0; 491189251Ssam count = WPA_GET_LE16(pos); 492189251Ssam pos += 2; 493189251Ssam left -= 2; 494189251Ssam if (count == 0 || left < count * RSN_SELECTOR_LEN) { 495189251Ssam wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 496189251Ssam "count %u left %u", __func__, count, left); 497189251Ssam return -6; 498189251Ssam } 499189251Ssam for (i = 0; i < count; i++) { 500189251Ssam data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); 501189251Ssam pos += RSN_SELECTOR_LEN; 502189251Ssam left -= RSN_SELECTOR_LEN; 503189251Ssam } 504189251Ssam } else if (left == 1) { 505189251Ssam wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 506189251Ssam __func__); 507189251Ssam return -7; 508189251Ssam } 509189251Ssam 510189251Ssam if (left >= 2) { 511189251Ssam data->capabilities = WPA_GET_LE16(pos); 512189251Ssam pos += 2; 513189251Ssam left -= 2; 514189251Ssam } 515189251Ssam 516189251Ssam if (left >= 2) { 517189251Ssam data->num_pmkid = WPA_GET_LE16(pos); 518189251Ssam pos += 2; 519189251Ssam left -= 2; 520189251Ssam if (left < (int) data->num_pmkid * PMKID_LEN) { 521189251Ssam wpa_printf(MSG_DEBUG, "%s: PMKID underflow " 522189251Ssam "(num_pmkid=%lu left=%d)", 523189251Ssam __func__, (unsigned long) data->num_pmkid, 524189251Ssam left); 525189251Ssam data->num_pmkid = 0; 526189251Ssam return -9; 527189251Ssam } else { 528189251Ssam data->pmkid = pos; 529189251Ssam pos += data->num_pmkid * PMKID_LEN; 530189251Ssam left -= data->num_pmkid * PMKID_LEN; 531189251Ssam } 532189251Ssam } 533189251Ssam 534189251Ssam#ifdef CONFIG_IEEE80211W 535189251Ssam if (left >= 4) { 536189251Ssam data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); 537189251Ssam if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { 538189251Ssam wpa_printf(MSG_DEBUG, "%s: Unsupported management " 539189251Ssam "group cipher 0x%x", __func__, 540189251Ssam data->mgmt_group_cipher); 541189251Ssam return -10; 542189251Ssam } 543189251Ssam pos += RSN_SELECTOR_LEN; 544189251Ssam left -= RSN_SELECTOR_LEN; 545189251Ssam } 546189251Ssam#endif /* CONFIG_IEEE80211W */ 547189251Ssam 548189251Ssam if (left > 0) { 549189251Ssam wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", 550189251Ssam __func__, left); 551189251Ssam } 552189251Ssam 553189251Ssam return 0; 554189251Ssam#else /* CONFIG_NO_WPA2 */ 555189251Ssam return -1; 556189251Ssam#endif /* CONFIG_NO_WPA2 */ 557189251Ssam} 558189251Ssam 559189251Ssam 560252726Srpaulostatic int wpa_selector_to_bitfield(const u8 *s) 561252726Srpaulo{ 562252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) 563252726Srpaulo return WPA_CIPHER_NONE; 564252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) 565252726Srpaulo return WPA_CIPHER_WEP40; 566252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) 567252726Srpaulo return WPA_CIPHER_TKIP; 568252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) 569252726Srpaulo return WPA_CIPHER_CCMP; 570252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) 571252726Srpaulo return WPA_CIPHER_WEP104; 572252726Srpaulo return 0; 573252726Srpaulo} 574252726Srpaulo 575252726Srpaulo 576252726Srpaulostatic int wpa_key_mgmt_to_bitfield(const u8 *s) 577252726Srpaulo{ 578252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) 579252726Srpaulo return WPA_KEY_MGMT_IEEE8021X; 580252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) 581252726Srpaulo return WPA_KEY_MGMT_PSK; 582252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) 583252726Srpaulo return WPA_KEY_MGMT_WPA_NONE; 584252726Srpaulo return 0; 585252726Srpaulo} 586252726Srpaulo 587252726Srpaulo 588252726Srpauloint wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, 589252726Srpaulo struct wpa_ie_data *data) 590252726Srpaulo{ 591252726Srpaulo const struct wpa_ie_hdr *hdr; 592252726Srpaulo const u8 *pos; 593252726Srpaulo int left; 594252726Srpaulo int i, count; 595252726Srpaulo 596252726Srpaulo os_memset(data, 0, sizeof(*data)); 597252726Srpaulo data->proto = WPA_PROTO_WPA; 598252726Srpaulo data->pairwise_cipher = WPA_CIPHER_TKIP; 599252726Srpaulo data->group_cipher = WPA_CIPHER_TKIP; 600252726Srpaulo data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 601252726Srpaulo data->capabilities = 0; 602252726Srpaulo data->pmkid = NULL; 603252726Srpaulo data->num_pmkid = 0; 604252726Srpaulo data->mgmt_group_cipher = 0; 605252726Srpaulo 606252726Srpaulo if (wpa_ie_len == 0) { 607252726Srpaulo /* No WPA IE - fail silently */ 608252726Srpaulo return -1; 609252726Srpaulo } 610252726Srpaulo 611252726Srpaulo if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { 612252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 613252726Srpaulo __func__, (unsigned long) wpa_ie_len); 614252726Srpaulo return -1; 615252726Srpaulo } 616252726Srpaulo 617252726Srpaulo hdr = (const struct wpa_ie_hdr *) wpa_ie; 618252726Srpaulo 619252726Srpaulo if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || 620252726Srpaulo hdr->len != wpa_ie_len - 2 || 621252726Srpaulo RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || 622252726Srpaulo WPA_GET_LE16(hdr->version) != WPA_VERSION) { 623252726Srpaulo wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 624252726Srpaulo __func__); 625252726Srpaulo return -2; 626252726Srpaulo } 627252726Srpaulo 628252726Srpaulo pos = (const u8 *) (hdr + 1); 629252726Srpaulo left = wpa_ie_len - sizeof(*hdr); 630252726Srpaulo 631252726Srpaulo if (left >= WPA_SELECTOR_LEN) { 632252726Srpaulo data->group_cipher = wpa_selector_to_bitfield(pos); 633252726Srpaulo pos += WPA_SELECTOR_LEN; 634252726Srpaulo left -= WPA_SELECTOR_LEN; 635252726Srpaulo } else if (left > 0) { 636252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 637252726Srpaulo __func__, left); 638252726Srpaulo return -3; 639252726Srpaulo } 640252726Srpaulo 641252726Srpaulo if (left >= 2) { 642252726Srpaulo data->pairwise_cipher = 0; 643252726Srpaulo count = WPA_GET_LE16(pos); 644252726Srpaulo pos += 2; 645252726Srpaulo left -= 2; 646252726Srpaulo if (count == 0 || left < count * WPA_SELECTOR_LEN) { 647252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 648252726Srpaulo "count %u left %u", __func__, count, left); 649252726Srpaulo return -4; 650252726Srpaulo } 651252726Srpaulo for (i = 0; i < count; i++) { 652252726Srpaulo data->pairwise_cipher |= wpa_selector_to_bitfield(pos); 653252726Srpaulo pos += WPA_SELECTOR_LEN; 654252726Srpaulo left -= WPA_SELECTOR_LEN; 655252726Srpaulo } 656252726Srpaulo } else if (left == 1) { 657252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 658252726Srpaulo __func__); 659252726Srpaulo return -5; 660252726Srpaulo } 661252726Srpaulo 662252726Srpaulo if (left >= 2) { 663252726Srpaulo data->key_mgmt = 0; 664252726Srpaulo count = WPA_GET_LE16(pos); 665252726Srpaulo pos += 2; 666252726Srpaulo left -= 2; 667252726Srpaulo if (count == 0 || left < count * WPA_SELECTOR_LEN) { 668252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 669252726Srpaulo "count %u left %u", __func__, count, left); 670252726Srpaulo return -6; 671252726Srpaulo } 672252726Srpaulo for (i = 0; i < count; i++) { 673252726Srpaulo data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); 674252726Srpaulo pos += WPA_SELECTOR_LEN; 675252726Srpaulo left -= WPA_SELECTOR_LEN; 676252726Srpaulo } 677252726Srpaulo } else if (left == 1) { 678252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 679252726Srpaulo __func__); 680252726Srpaulo return -7; 681252726Srpaulo } 682252726Srpaulo 683252726Srpaulo if (left >= 2) { 684252726Srpaulo data->capabilities = WPA_GET_LE16(pos); 685252726Srpaulo pos += 2; 686252726Srpaulo left -= 2; 687252726Srpaulo } 688252726Srpaulo 689252726Srpaulo if (left > 0) { 690252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", 691252726Srpaulo __func__, left); 692252726Srpaulo } 693252726Srpaulo 694252726Srpaulo return 0; 695252726Srpaulo} 696252726Srpaulo 697252726Srpaulo 698189251Ssam#ifdef CONFIG_IEEE80211R 699189251Ssam 700189251Ssam/** 701189251Ssam * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name 702189251Ssam * 703189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.3 704189251Ssam */ 705189251Ssamvoid wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, 706189251Ssam const u8 *ssid, size_t ssid_len, 707189251Ssam const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, 708189251Ssam const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) 709189251Ssam{ 710189251Ssam u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + 711189251Ssam FT_R0KH_ID_MAX_LEN + ETH_ALEN]; 712189251Ssam u8 *pos, r0_key_data[48], hash[32]; 713189251Ssam const u8 *addr[2]; 714189251Ssam size_t len[2]; 715189251Ssam 716189251Ssam /* 717189251Ssam * R0-Key-Data = KDF-384(XXKey, "FT-R0", 718189251Ssam * SSIDlength || SSID || MDID || R0KHlength || 719189251Ssam * R0KH-ID || S0KH-ID) 720189251Ssam * XXKey is either the second 256 bits of MSK or PSK. 721189251Ssam * PMK-R0 = L(R0-Key-Data, 0, 256) 722189251Ssam * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) 723189251Ssam */ 724189251Ssam if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) 725189251Ssam return; 726189251Ssam pos = buf; 727189251Ssam *pos++ = ssid_len; 728189251Ssam os_memcpy(pos, ssid, ssid_len); 729189251Ssam pos += ssid_len; 730189251Ssam os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); 731189251Ssam pos += MOBILITY_DOMAIN_ID_LEN; 732189251Ssam *pos++ = r0kh_id_len; 733189251Ssam os_memcpy(pos, r0kh_id, r0kh_id_len); 734189251Ssam pos += r0kh_id_len; 735189251Ssam os_memcpy(pos, s0kh_id, ETH_ALEN); 736189251Ssam pos += ETH_ALEN; 737189251Ssam 738189251Ssam sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, 739189251Ssam r0_key_data, sizeof(r0_key_data)); 740189251Ssam os_memcpy(pmk_r0, r0_key_data, PMK_LEN); 741189251Ssam 742189251Ssam /* 743189251Ssam * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) 744189251Ssam */ 745189251Ssam addr[0] = (const u8 *) "FT-R0N"; 746189251Ssam len[0] = 6; 747189251Ssam addr[1] = r0_key_data + PMK_LEN; 748189251Ssam len[1] = 16; 749189251Ssam 750189251Ssam sha256_vector(2, addr, len, hash); 751189251Ssam os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); 752189251Ssam} 753189251Ssam 754189251Ssam 755189251Ssam/** 756189251Ssam * wpa_derive_pmk_r1_name - Derive PMKR1Name 757189251Ssam * 758189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4 759189251Ssam */ 760189251Ssamvoid wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, 761189251Ssam const u8 *s1kh_id, u8 *pmk_r1_name) 762189251Ssam{ 763189251Ssam u8 hash[32]; 764189251Ssam const u8 *addr[4]; 765189251Ssam size_t len[4]; 766189251Ssam 767189251Ssam /* 768189251Ssam * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || 769189251Ssam * R1KH-ID || S1KH-ID)) 770189251Ssam */ 771189251Ssam addr[0] = (const u8 *) "FT-R1N"; 772189251Ssam len[0] = 6; 773189251Ssam addr[1] = pmk_r0_name; 774189251Ssam len[1] = WPA_PMK_NAME_LEN; 775189251Ssam addr[2] = r1kh_id; 776189251Ssam len[2] = FT_R1KH_ID_LEN; 777189251Ssam addr[3] = s1kh_id; 778189251Ssam len[3] = ETH_ALEN; 779189251Ssam 780189251Ssam sha256_vector(4, addr, len, hash); 781189251Ssam os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); 782189251Ssam} 783189251Ssam 784189251Ssam 785189251Ssam/** 786189251Ssam * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 787189251Ssam * 788189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4 789189251Ssam */ 790189251Ssamvoid wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, 791189251Ssam const u8 *r1kh_id, const u8 *s1kh_id, 792189251Ssam u8 *pmk_r1, u8 *pmk_r1_name) 793189251Ssam{ 794189251Ssam u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; 795189251Ssam u8 *pos; 796189251Ssam 797189251Ssam /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ 798189251Ssam pos = buf; 799189251Ssam os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); 800189251Ssam pos += FT_R1KH_ID_LEN; 801189251Ssam os_memcpy(pos, s1kh_id, ETH_ALEN); 802189251Ssam pos += ETH_ALEN; 803189251Ssam 804189251Ssam sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); 805189251Ssam 806189251Ssam wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); 807189251Ssam} 808189251Ssam 809189251Ssam 810189251Ssam/** 811189251Ssam * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 812189251Ssam * 813189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.5 814189251Ssam */ 815189251Ssamvoid wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, 816189251Ssam const u8 *sta_addr, const u8 *bssid, 817189251Ssam const u8 *pmk_r1_name, 818189251Ssam u8 *ptk, size_t ptk_len, u8 *ptk_name) 819189251Ssam{ 820189251Ssam u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; 821189251Ssam u8 *pos, hash[32]; 822189251Ssam const u8 *addr[6]; 823189251Ssam size_t len[6]; 824189251Ssam 825189251Ssam /* 826189251Ssam * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || 827189251Ssam * BSSID || STA-ADDR) 828189251Ssam */ 829189251Ssam pos = buf; 830189251Ssam os_memcpy(pos, snonce, WPA_NONCE_LEN); 831189251Ssam pos += WPA_NONCE_LEN; 832189251Ssam os_memcpy(pos, anonce, WPA_NONCE_LEN); 833189251Ssam pos += WPA_NONCE_LEN; 834189251Ssam os_memcpy(pos, bssid, ETH_ALEN); 835189251Ssam pos += ETH_ALEN; 836189251Ssam os_memcpy(pos, sta_addr, ETH_ALEN); 837189251Ssam pos += ETH_ALEN; 838189251Ssam 839189251Ssam sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); 840189251Ssam 841189251Ssam /* 842189251Ssam * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || 843189251Ssam * ANonce || BSSID || STA-ADDR)) 844189251Ssam */ 845189251Ssam addr[0] = pmk_r1_name; 846189251Ssam len[0] = WPA_PMK_NAME_LEN; 847189251Ssam addr[1] = (const u8 *) "FT-PTKN"; 848189251Ssam len[1] = 7; 849189251Ssam addr[2] = snonce; 850189251Ssam len[2] = WPA_NONCE_LEN; 851189251Ssam addr[3] = anonce; 852189251Ssam len[3] = WPA_NONCE_LEN; 853189251Ssam addr[4] = bssid; 854189251Ssam len[4] = ETH_ALEN; 855189251Ssam addr[5] = sta_addr; 856189251Ssam len[5] = ETH_ALEN; 857189251Ssam 858189251Ssam sha256_vector(6, addr, len, hash); 859189251Ssam os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); 860189251Ssam} 861189251Ssam 862189251Ssam#endif /* CONFIG_IEEE80211R */ 863214734Srpaulo 864214734Srpaulo 865214734Srpaulo/** 866214734Srpaulo * rsn_pmkid - Calculate PMK identifier 867214734Srpaulo * @pmk: Pairwise master key 868214734Srpaulo * @pmk_len: Length of pmk in bytes 869214734Srpaulo * @aa: Authenticator address 870214734Srpaulo * @spa: Supplicant address 871214734Srpaulo * @pmkid: Buffer for PMKID 872214734Srpaulo * @use_sha256: Whether to use SHA256-based KDF 873214734Srpaulo * 874214734Srpaulo * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy 875214734Srpaulo * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) 876214734Srpaulo */ 877214734Srpaulovoid rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, 878214734Srpaulo u8 *pmkid, int use_sha256) 879214734Srpaulo{ 880214734Srpaulo char *title = "PMK Name"; 881214734Srpaulo const u8 *addr[3]; 882214734Srpaulo const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 883214734Srpaulo unsigned char hash[SHA256_MAC_LEN]; 884214734Srpaulo 885214734Srpaulo addr[0] = (u8 *) title; 886214734Srpaulo addr[1] = aa; 887214734Srpaulo addr[2] = spa; 888214734Srpaulo 889214734Srpaulo#ifdef CONFIG_IEEE80211W 890214734Srpaulo if (use_sha256) 891214734Srpaulo hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); 892214734Srpaulo else 893214734Srpaulo#endif /* CONFIG_IEEE80211W */ 894214734Srpaulo hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); 895214734Srpaulo os_memcpy(pmkid, hash, PMKID_LEN); 896214734Srpaulo} 897214734Srpaulo 898214734Srpaulo 899214734Srpaulo/** 900214734Srpaulo * wpa_cipher_txt - Convert cipher suite to a text string 901214734Srpaulo * @cipher: Cipher suite (WPA_CIPHER_* enum) 902214734Srpaulo * Returns: Pointer to a text string of the cipher suite name 903214734Srpaulo */ 904214734Srpauloconst char * wpa_cipher_txt(int cipher) 905214734Srpaulo{ 906214734Srpaulo switch (cipher) { 907214734Srpaulo case WPA_CIPHER_NONE: 908214734Srpaulo return "NONE"; 909214734Srpaulo case WPA_CIPHER_WEP40: 910214734Srpaulo return "WEP-40"; 911214734Srpaulo case WPA_CIPHER_WEP104: 912214734Srpaulo return "WEP-104"; 913214734Srpaulo case WPA_CIPHER_TKIP: 914214734Srpaulo return "TKIP"; 915214734Srpaulo case WPA_CIPHER_CCMP: 916214734Srpaulo return "CCMP"; 917214734Srpaulo case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: 918214734Srpaulo return "CCMP+TKIP"; 919252726Srpaulo case WPA_CIPHER_GCMP: 920252726Srpaulo return "GCMP"; 921214734Srpaulo default: 922214734Srpaulo return "UNKNOWN"; 923214734Srpaulo } 924214734Srpaulo} 925214734Srpaulo 926214734Srpaulo 927214734Srpaulo/** 928214734Srpaulo * wpa_key_mgmt_txt - Convert key management suite to a text string 929214734Srpaulo * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) 930214734Srpaulo * @proto: WPA/WPA2 version (WPA_PROTO_*) 931214734Srpaulo * Returns: Pointer to a text string of the key management suite name 932214734Srpaulo */ 933214734Srpauloconst char * wpa_key_mgmt_txt(int key_mgmt, int proto) 934214734Srpaulo{ 935214734Srpaulo switch (key_mgmt) { 936214734Srpaulo case WPA_KEY_MGMT_IEEE8021X: 937214734Srpaulo if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 938214734Srpaulo return "WPA2+WPA/IEEE 802.1X/EAP"; 939214734Srpaulo return proto == WPA_PROTO_RSN ? 940214734Srpaulo "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; 941214734Srpaulo case WPA_KEY_MGMT_PSK: 942214734Srpaulo if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 943214734Srpaulo return "WPA2-PSK+WPA-PSK"; 944214734Srpaulo return proto == WPA_PROTO_RSN ? 945214734Srpaulo "WPA2-PSK" : "WPA-PSK"; 946214734Srpaulo case WPA_KEY_MGMT_NONE: 947214734Srpaulo return "NONE"; 948214734Srpaulo case WPA_KEY_MGMT_IEEE8021X_NO_WPA: 949214734Srpaulo return "IEEE 802.1X (no WPA)"; 950214734Srpaulo#ifdef CONFIG_IEEE80211R 951214734Srpaulo case WPA_KEY_MGMT_FT_IEEE8021X: 952214734Srpaulo return "FT-EAP"; 953214734Srpaulo case WPA_KEY_MGMT_FT_PSK: 954214734Srpaulo return "FT-PSK"; 955214734Srpaulo#endif /* CONFIG_IEEE80211R */ 956214734Srpaulo#ifdef CONFIG_IEEE80211W 957214734Srpaulo case WPA_KEY_MGMT_IEEE8021X_SHA256: 958214734Srpaulo return "WPA2-EAP-SHA256"; 959214734Srpaulo case WPA_KEY_MGMT_PSK_SHA256: 960214734Srpaulo return "WPA2-PSK-SHA256"; 961214734Srpaulo#endif /* CONFIG_IEEE80211W */ 962214734Srpaulo default: 963214734Srpaulo return "UNKNOWN"; 964214734Srpaulo } 965214734Srpaulo} 966214734Srpaulo 967214734Srpaulo 968214734Srpauloint wpa_compare_rsn_ie(int ft_initial_assoc, 969214734Srpaulo const u8 *ie1, size_t ie1len, 970214734Srpaulo const u8 *ie2, size_t ie2len) 971214734Srpaulo{ 972214734Srpaulo if (ie1 == NULL || ie2 == NULL) 973214734Srpaulo return -1; 974214734Srpaulo 975214734Srpaulo if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) 976214734Srpaulo return 0; /* identical IEs */ 977214734Srpaulo 978214734Srpaulo#ifdef CONFIG_IEEE80211R 979214734Srpaulo if (ft_initial_assoc) { 980214734Srpaulo struct wpa_ie_data ie1d, ie2d; 981214734Srpaulo /* 982214734Srpaulo * The PMKID-List in RSN IE is different between Beacon/Probe 983214734Srpaulo * Response/(Re)Association Request frames and EAPOL-Key 984214734Srpaulo * messages in FT initial mobility domain association. Allow 985214734Srpaulo * for this, but verify that other parts of the RSN IEs are 986214734Srpaulo * identical. 987214734Srpaulo */ 988214734Srpaulo if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || 989214734Srpaulo wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) 990214734Srpaulo return -1; 991214734Srpaulo if (ie1d.proto == ie2d.proto && 992214734Srpaulo ie1d.pairwise_cipher == ie2d.pairwise_cipher && 993214734Srpaulo ie1d.group_cipher == ie2d.group_cipher && 994214734Srpaulo ie1d.key_mgmt == ie2d.key_mgmt && 995214734Srpaulo ie1d.capabilities == ie2d.capabilities && 996214734Srpaulo ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) 997214734Srpaulo return 0; 998214734Srpaulo } 999214734Srpaulo#endif /* CONFIG_IEEE80211R */ 1000214734Srpaulo 1001214734Srpaulo return -1; 1002214734Srpaulo} 1003214734Srpaulo 1004214734Srpaulo 1005214734Srpaulo#ifdef CONFIG_IEEE80211R 1006214734Srpauloint wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) 1007214734Srpaulo{ 1008214734Srpaulo u8 *start, *end, *rpos, *rend; 1009214734Srpaulo int added = 0; 1010214734Srpaulo 1011214734Srpaulo start = ies; 1012214734Srpaulo end = ies + ies_len; 1013214734Srpaulo 1014214734Srpaulo while (start < end) { 1015214734Srpaulo if (*start == WLAN_EID_RSN) 1016214734Srpaulo break; 1017214734Srpaulo start += 2 + start[1]; 1018214734Srpaulo } 1019214734Srpaulo if (start >= end) { 1020214734Srpaulo wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " 1021214734Srpaulo "IEs data"); 1022214734Srpaulo return -1; 1023214734Srpaulo } 1024214734Srpaulo wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", 1025214734Srpaulo start, 2 + start[1]); 1026214734Srpaulo 1027214734Srpaulo /* Find start of PMKID-Count */ 1028214734Srpaulo rpos = start + 2; 1029214734Srpaulo rend = rpos + start[1]; 1030214734Srpaulo 1031214734Srpaulo /* Skip Version and Group Data Cipher Suite */ 1032214734Srpaulo rpos += 2 + 4; 1033214734Srpaulo /* Skip Pairwise Cipher Suite Count and List */ 1034214734Srpaulo rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 1035214734Srpaulo /* Skip AKM Suite Count and List */ 1036214734Srpaulo rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 1037214734Srpaulo 1038214734Srpaulo if (rpos == rend) { 1039214734Srpaulo /* Add RSN Capabilities */ 1040214734Srpaulo os_memmove(rpos + 2, rpos, end - rpos); 1041214734Srpaulo *rpos++ = 0; 1042214734Srpaulo *rpos++ = 0; 1043214734Srpaulo } else { 1044214734Srpaulo /* Skip RSN Capabilities */ 1045214734Srpaulo rpos += 2; 1046214734Srpaulo if (rpos > rend) { 1047214734Srpaulo wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " 1048214734Srpaulo "IEs data"); 1049214734Srpaulo return -1; 1050214734Srpaulo } 1051214734Srpaulo } 1052214734Srpaulo 1053214734Srpaulo if (rpos == rend) { 1054214734Srpaulo /* No PMKID-Count field included; add it */ 1055214734Srpaulo os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); 1056214734Srpaulo WPA_PUT_LE16(rpos, 1); 1057214734Srpaulo rpos += 2; 1058214734Srpaulo os_memcpy(rpos, pmkid, PMKID_LEN); 1059214734Srpaulo added += 2 + PMKID_LEN; 1060214734Srpaulo start[1] += 2 + PMKID_LEN; 1061214734Srpaulo } else { 1062214734Srpaulo /* PMKID-Count was included; use it */ 1063214734Srpaulo if (WPA_GET_LE16(rpos) != 0) { 1064214734Srpaulo wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " 1065214734Srpaulo "in RSN IE in EAPOL-Key data"); 1066214734Srpaulo return -1; 1067214734Srpaulo } 1068214734Srpaulo WPA_PUT_LE16(rpos, 1); 1069214734Srpaulo rpos += 2; 1070214734Srpaulo os_memmove(rpos + PMKID_LEN, rpos, end - rpos); 1071214734Srpaulo os_memcpy(rpos, pmkid, PMKID_LEN); 1072214734Srpaulo added += PMKID_LEN; 1073214734Srpaulo start[1] += PMKID_LEN; 1074214734Srpaulo } 1075214734Srpaulo 1076214734Srpaulo wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " 1077214734Srpaulo "(PMKID inserted)", start, 2 + start[1]); 1078214734Srpaulo 1079214734Srpaulo return added; 1080214734Srpaulo} 1081214734Srpaulo#endif /* CONFIG_IEEE80211R */ 1082252726Srpaulo 1083252726Srpaulo 1084252726Srpauloint wpa_cipher_key_len(int cipher) 1085252726Srpaulo{ 1086252726Srpaulo switch (cipher) { 1087252726Srpaulo case WPA_CIPHER_CCMP: 1088252726Srpaulo case WPA_CIPHER_GCMP: 1089252726Srpaulo return 16; 1090252726Srpaulo case WPA_CIPHER_TKIP: 1091252726Srpaulo return 32; 1092252726Srpaulo case WPA_CIPHER_WEP104: 1093252726Srpaulo return 13; 1094252726Srpaulo case WPA_CIPHER_WEP40: 1095252726Srpaulo return 5; 1096252726Srpaulo } 1097252726Srpaulo 1098252726Srpaulo return 0; 1099252726Srpaulo} 1100252726Srpaulo 1101252726Srpaulo 1102252726Srpauloint wpa_cipher_rsc_len(int cipher) 1103252726Srpaulo{ 1104252726Srpaulo switch (cipher) { 1105252726Srpaulo case WPA_CIPHER_CCMP: 1106252726Srpaulo case WPA_CIPHER_GCMP: 1107252726Srpaulo case WPA_CIPHER_TKIP: 1108252726Srpaulo return 6; 1109252726Srpaulo case WPA_CIPHER_WEP104: 1110252726Srpaulo case WPA_CIPHER_WEP40: 1111252726Srpaulo return 0; 1112252726Srpaulo } 1113252726Srpaulo 1114252726Srpaulo return 0; 1115252726Srpaulo} 1116252726Srpaulo 1117252726Srpaulo 1118252726Srpauloint wpa_cipher_to_alg(int cipher) 1119252726Srpaulo{ 1120252726Srpaulo switch (cipher) { 1121252726Srpaulo case WPA_CIPHER_CCMP: 1122252726Srpaulo return WPA_ALG_CCMP; 1123252726Srpaulo case WPA_CIPHER_GCMP: 1124252726Srpaulo return WPA_ALG_GCMP; 1125252726Srpaulo case WPA_CIPHER_TKIP: 1126252726Srpaulo return WPA_ALG_TKIP; 1127252726Srpaulo case WPA_CIPHER_WEP104: 1128252726Srpaulo case WPA_CIPHER_WEP40: 1129252726Srpaulo return WPA_ALG_WEP; 1130252726Srpaulo } 1131252726Srpaulo return WPA_ALG_NONE; 1132252726Srpaulo} 1133252726Srpaulo 1134252726Srpaulo 1135252726Srpauloint wpa_cipher_valid_pairwise(int cipher) 1136252726Srpaulo{ 1137252726Srpaulo return cipher == WPA_CIPHER_CCMP || 1138252726Srpaulo cipher == WPA_CIPHER_GCMP || 1139252726Srpaulo cipher == WPA_CIPHER_TKIP; 1140252726Srpaulo} 1141252726Srpaulo 1142252726Srpaulo 1143252726Srpaulou32 wpa_cipher_to_suite(int proto, int cipher) 1144252726Srpaulo{ 1145252726Srpaulo if (cipher & WPA_CIPHER_CCMP) 1146252726Srpaulo return (proto == WPA_PROTO_RSN ? 1147252726Srpaulo RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); 1148252726Srpaulo if (cipher & WPA_CIPHER_GCMP) 1149252726Srpaulo return RSN_CIPHER_SUITE_GCMP; 1150252726Srpaulo if (cipher & WPA_CIPHER_TKIP) 1151252726Srpaulo return (proto == WPA_PROTO_RSN ? 1152252726Srpaulo RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); 1153252726Srpaulo if (cipher & WPA_CIPHER_WEP104) 1154252726Srpaulo return (proto == WPA_PROTO_RSN ? 1155252726Srpaulo RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); 1156252726Srpaulo if (cipher & WPA_CIPHER_WEP40) 1157252726Srpaulo return (proto == WPA_PROTO_RSN ? 1158252726Srpaulo RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); 1159252726Srpaulo if (cipher & WPA_CIPHER_NONE) 1160252726Srpaulo return (proto == WPA_PROTO_RSN ? 1161252726Srpaulo RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); 1162252726Srpaulo return 0; 1163252726Srpaulo} 1164252726Srpaulo 1165252726Srpaulo 1166252726Srpauloint rsn_cipher_put_suites(u8 *pos, int ciphers) 1167252726Srpaulo{ 1168252726Srpaulo int num_suites = 0; 1169252726Srpaulo 1170252726Srpaulo if (ciphers & WPA_CIPHER_CCMP) { 1171252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 1172252726Srpaulo pos += RSN_SELECTOR_LEN; 1173252726Srpaulo num_suites++; 1174252726Srpaulo } 1175252726Srpaulo if (ciphers & WPA_CIPHER_GCMP) { 1176252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); 1177252726Srpaulo pos += RSN_SELECTOR_LEN; 1178252726Srpaulo num_suites++; 1179252726Srpaulo } 1180252726Srpaulo if (ciphers & WPA_CIPHER_TKIP) { 1181252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 1182252726Srpaulo pos += RSN_SELECTOR_LEN; 1183252726Srpaulo num_suites++; 1184252726Srpaulo } 1185252726Srpaulo if (ciphers & WPA_CIPHER_NONE) { 1186252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); 1187252726Srpaulo pos += RSN_SELECTOR_LEN; 1188252726Srpaulo num_suites++; 1189252726Srpaulo } 1190252726Srpaulo 1191252726Srpaulo return num_suites; 1192252726Srpaulo} 1193252726Srpaulo 1194252726Srpaulo 1195252726Srpauloint wpa_cipher_put_suites(u8 *pos, int ciphers) 1196252726Srpaulo{ 1197252726Srpaulo int num_suites = 0; 1198252726Srpaulo 1199252726Srpaulo if (ciphers & WPA_CIPHER_CCMP) { 1200252726Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 1201252726Srpaulo pos += WPA_SELECTOR_LEN; 1202252726Srpaulo num_suites++; 1203252726Srpaulo } 1204252726Srpaulo if (ciphers & WPA_CIPHER_TKIP) { 1205252726Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 1206252726Srpaulo pos += WPA_SELECTOR_LEN; 1207252726Srpaulo num_suites++; 1208252726Srpaulo } 1209252726Srpaulo if (ciphers & WPA_CIPHER_NONE) { 1210252726Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); 1211252726Srpaulo pos += WPA_SELECTOR_LEN; 1212252726Srpaulo num_suites++; 1213252726Srpaulo } 1214252726Srpaulo 1215252726Srpaulo return num_suites; 1216252726Srpaulo} 1217