1189251Ssam/* 2189251Ssam * WPA/RSN - Shared functions for supplicant and authenticator 3346981Scy * Copyright (c) 2002-2018, 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" 15281806Srpaulo#include "crypto/sha384.h" 16346981Scy#include "crypto/sha512.h" 17214734Srpaulo#include "crypto/aes_wrap.h" 18214734Srpaulo#include "crypto/crypto.h" 19189251Ssam#include "ieee802_11_defs.h" 20189251Ssam#include "defs.h" 21189251Ssam#include "wpa_common.h" 22189251Ssam 23189251Ssam 24346981Scystatic unsigned int wpa_kck_len(int akmp, size_t pmk_len) 25281806Srpaulo{ 26346981Scy switch (akmp) { 27346981Scy case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: 28346981Scy case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: 29281806Srpaulo return 24; 30346981Scy case WPA_KEY_MGMT_FILS_SHA256: 31346981Scy case WPA_KEY_MGMT_FT_FILS_SHA256: 32346981Scy case WPA_KEY_MGMT_FILS_SHA384: 33346981Scy case WPA_KEY_MGMT_FT_FILS_SHA384: 34346981Scy return 0; 35346981Scy case WPA_KEY_MGMT_DPP: 36346981Scy return pmk_len / 2; 37346981Scy case WPA_KEY_MGMT_OWE: 38346981Scy return pmk_len / 2; 39346981Scy default: 40346981Scy return 16; 41346981Scy } 42281806Srpaulo} 43281806Srpaulo 44281806Srpaulo 45346981Scy#ifdef CONFIG_IEEE80211R 46346981Scystatic unsigned int wpa_kck2_len(int akmp) 47281806Srpaulo{ 48346981Scy switch (akmp) { 49346981Scy case WPA_KEY_MGMT_FT_FILS_SHA256: 50346981Scy return 16; 51346981Scy case WPA_KEY_MGMT_FT_FILS_SHA384: 52346981Scy return 24; 53346981Scy default: 54346981Scy return 0; 55346981Scy } 56346981Scy} 57346981Scy#endif /* CONFIG_IEEE80211R */ 58346981Scy 59346981Scy 60346981Scystatic unsigned int wpa_kek_len(int akmp, size_t pmk_len) 61346981Scy{ 62346981Scy switch (akmp) { 63346981Scy case WPA_KEY_MGMT_FILS_SHA384: 64346981Scy case WPA_KEY_MGMT_FT_FILS_SHA384: 65346981Scy return 64; 66346981Scy case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: 67346981Scy case WPA_KEY_MGMT_FILS_SHA256: 68346981Scy case WPA_KEY_MGMT_FT_FILS_SHA256: 69346981Scy case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: 70281806Srpaulo return 32; 71346981Scy case WPA_KEY_MGMT_DPP: 72346981Scy return pmk_len <= 32 ? 16 : 32; 73346981Scy case WPA_KEY_MGMT_OWE: 74346981Scy return pmk_len <= 32 ? 16 : 32; 75346981Scy default: 76346981Scy return 16; 77346981Scy } 78281806Srpaulo} 79281806Srpaulo 80281806Srpaulo 81346981Scy#ifdef CONFIG_IEEE80211R 82346981Scystatic unsigned int wpa_kek2_len(int akmp) 83281806Srpaulo{ 84346981Scy switch (akmp) { 85346981Scy case WPA_KEY_MGMT_FT_FILS_SHA256: 86346981Scy return 16; 87346981Scy case WPA_KEY_MGMT_FT_FILS_SHA384: 88346981Scy return 32; 89346981Scy default: 90346981Scy return 0; 91346981Scy } 92346981Scy} 93346981Scy#endif /* CONFIG_IEEE80211R */ 94346981Scy 95346981Scy 96346981Scyunsigned int wpa_mic_len(int akmp, size_t pmk_len) 97346981Scy{ 98346981Scy switch (akmp) { 99346981Scy case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: 100346981Scy case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: 101281806Srpaulo return 24; 102346981Scy case WPA_KEY_MGMT_FILS_SHA256: 103346981Scy case WPA_KEY_MGMT_FILS_SHA384: 104346981Scy case WPA_KEY_MGMT_FT_FILS_SHA256: 105346981Scy case WPA_KEY_MGMT_FT_FILS_SHA384: 106346981Scy return 0; 107346981Scy case WPA_KEY_MGMT_DPP: 108346981Scy return pmk_len / 2; 109346981Scy case WPA_KEY_MGMT_OWE: 110346981Scy return pmk_len / 2; 111346981Scy default: 112346981Scy return 16; 113346981Scy } 114281806Srpaulo} 115281806Srpaulo 116281806Srpaulo 117189251Ssam/** 118346981Scy * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used 119346981Scy * @akmp: WPA_KEY_MGMT_* used in key derivation 120346981Scy * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise 121346981Scy */ 122346981Scyint wpa_use_akm_defined(int akmp) 123346981Scy{ 124346981Scy return akmp == WPA_KEY_MGMT_OSEN || 125346981Scy akmp == WPA_KEY_MGMT_OWE || 126346981Scy akmp == WPA_KEY_MGMT_DPP || 127346981Scy akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 || 128346981Scy wpa_key_mgmt_sae(akmp) || 129346981Scy wpa_key_mgmt_suite_b(akmp) || 130346981Scy wpa_key_mgmt_fils(akmp); 131346981Scy} 132346981Scy 133346981Scy 134346981Scy/** 135346981Scy * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC 136346981Scy * @akmp: WPA_KEY_MGMT_* used in key derivation 137346981Scy * Returns: 1 if CMAC is used; 0 otherwise 138346981Scy */ 139346981Scyint wpa_use_cmac(int akmp) 140346981Scy{ 141346981Scy return akmp == WPA_KEY_MGMT_OSEN || 142346981Scy akmp == WPA_KEY_MGMT_OWE || 143346981Scy akmp == WPA_KEY_MGMT_DPP || 144346981Scy wpa_key_mgmt_ft(akmp) || 145346981Scy wpa_key_mgmt_sha256(akmp) || 146346981Scy wpa_key_mgmt_sae(akmp) || 147346981Scy wpa_key_mgmt_suite_b(akmp); 148346981Scy} 149346981Scy 150346981Scy 151346981Scy/** 152346981Scy * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data 153346981Scy * @akmp: WPA_KEY_MGMT_* used in key derivation 154346981Scy * Returns: 1 if AES Keywrap is used; 0 otherwise 155346981Scy * 156346981Scy * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether 157346981Scy * to use AES Keywrap based on the negotiated pairwise cipher. This function 158346981Scy * does not cover those special cases. 159346981Scy */ 160346981Scyint wpa_use_aes_key_wrap(int akmp) 161346981Scy{ 162346981Scy return akmp == WPA_KEY_MGMT_OSEN || 163346981Scy akmp == WPA_KEY_MGMT_OWE || 164346981Scy akmp == WPA_KEY_MGMT_DPP || 165346981Scy wpa_key_mgmt_ft(akmp) || 166346981Scy wpa_key_mgmt_sha256(akmp) || 167346981Scy wpa_key_mgmt_sae(akmp) || 168346981Scy wpa_key_mgmt_suite_b(akmp); 169346981Scy} 170346981Scy 171346981Scy 172346981Scy/** 173189251Ssam * wpa_eapol_key_mic - Calculate EAPOL-Key MIC 174189251Ssam * @key: EAPOL-Key Key Confirmation Key (KCK) 175281806Srpaulo * @key_len: KCK length in octets 176281806Srpaulo * @akmp: WPA_KEY_MGMT_* used in key derivation 177189251Ssam * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) 178189251Ssam * @buf: Pointer to the beginning of the EAPOL header (version field) 179189251Ssam * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) 180189251Ssam * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written 181189251Ssam * Returns: 0 on success, -1 on failure 182189251Ssam * 183189251Ssam * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has 184189251Ssam * to be cleared (all zeroes) when calling this function. 185189251Ssam * 186189251Ssam * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the 187189251Ssam * description of the Key MIC calculation. It includes packet data from the 188189251Ssam * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change 189189251Ssam * happened during final editing of the standard and the correct behavior is 190189251Ssam * defined in the last draft (IEEE 802.11i/D10). 191189251Ssam */ 192281806Srpauloint wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, 193281806Srpaulo const u8 *buf, size_t len, u8 *mic) 194189251Ssam{ 195346981Scy u8 hash[SHA512_MAC_LEN]; 196189251Ssam 197346981Scy if (key_len == 0) { 198346981Scy wpa_printf(MSG_DEBUG, 199346981Scy "WPA: KCK not set - cannot calculate MIC"); 200346981Scy return -1; 201346981Scy } 202346981Scy 203189251Ssam switch (ver) { 204252726Srpaulo#ifndef CONFIG_FIPS 205189251Ssam case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: 206346981Scy wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-MD5"); 207281806Srpaulo return hmac_md5(key, key_len, buf, len, mic); 208252726Srpaulo#endif /* CONFIG_FIPS */ 209189251Ssam case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: 210346981Scy wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-SHA1"); 211281806Srpaulo if (hmac_sha1(key, key_len, buf, len, hash)) 212214734Srpaulo return -1; 213189251Ssam os_memcpy(mic, hash, MD5_MAC_LEN); 214189251Ssam break; 215209158Srpaulo#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) 216189251Ssam case WPA_KEY_INFO_TYPE_AES_128_CMAC: 217346981Scy wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC"); 218189251Ssam return omac1_aes_128(key, buf, len, mic); 219209158Srpaulo#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ 220281806Srpaulo case WPA_KEY_INFO_TYPE_AKM_DEFINED: 221281806Srpaulo switch (akmp) { 222346981Scy#ifdef CONFIG_SAE 223346981Scy case WPA_KEY_MGMT_SAE: 224346981Scy case WPA_KEY_MGMT_FT_SAE: 225346981Scy wpa_printf(MSG_DEBUG, 226346981Scy "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)"); 227346981Scy return omac1_aes_128(key, buf, len, mic); 228346981Scy#endif /* CONFIG_SAE */ 229281806Srpaulo#ifdef CONFIG_HS20 230281806Srpaulo case WPA_KEY_MGMT_OSEN: 231346981Scy wpa_printf(MSG_DEBUG, 232346981Scy "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - OSEN)"); 233281806Srpaulo return omac1_aes_128(key, buf, len, mic); 234281806Srpaulo#endif /* CONFIG_HS20 */ 235281806Srpaulo#ifdef CONFIG_SUITEB 236281806Srpaulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B: 237346981Scy wpa_printf(MSG_DEBUG, 238346981Scy "WPA: EAPOL-Key MIC using HMAC-SHA256 (AKM-defined - Suite B)"); 239281806Srpaulo if (hmac_sha256(key, key_len, buf, len, hash)) 240281806Srpaulo return -1; 241281806Srpaulo os_memcpy(mic, hash, MD5_MAC_LEN); 242281806Srpaulo break; 243281806Srpaulo#endif /* CONFIG_SUITEB */ 244281806Srpaulo#ifdef CONFIG_SUITEB192 245281806Srpaulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: 246346981Scy wpa_printf(MSG_DEBUG, 247346981Scy "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - Suite B 192-bit)"); 248281806Srpaulo if (hmac_sha384(key, key_len, buf, len, hash)) 249281806Srpaulo return -1; 250281806Srpaulo os_memcpy(mic, hash, 24); 251281806Srpaulo break; 252281806Srpaulo#endif /* CONFIG_SUITEB192 */ 253346981Scy#ifdef CONFIG_OWE 254346981Scy case WPA_KEY_MGMT_OWE: 255346981Scy wpa_printf(MSG_DEBUG, 256346981Scy "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - OWE)", 257346981Scy (unsigned int) key_len * 8 * 2); 258346981Scy if (key_len == 128 / 8) { 259346981Scy if (hmac_sha256(key, key_len, buf, len, hash)) 260346981Scy return -1; 261346981Scy } else if (key_len == 192 / 8) { 262346981Scy if (hmac_sha384(key, key_len, buf, len, hash)) 263346981Scy return -1; 264346981Scy } else if (key_len == 256 / 8) { 265346981Scy if (hmac_sha512(key, key_len, buf, len, hash)) 266346981Scy return -1; 267346981Scy } else { 268346981Scy wpa_printf(MSG_INFO, 269346981Scy "OWE: Unsupported KCK length: %u", 270346981Scy (unsigned int) key_len); 271346981Scy return -1; 272346981Scy } 273346981Scy os_memcpy(mic, hash, key_len); 274346981Scy break; 275346981Scy#endif /* CONFIG_OWE */ 276346981Scy#ifdef CONFIG_DPP 277346981Scy case WPA_KEY_MGMT_DPP: 278346981Scy wpa_printf(MSG_DEBUG, 279346981Scy "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - DPP)", 280346981Scy (unsigned int) key_len * 8 * 2); 281346981Scy if (key_len == 128 / 8) { 282346981Scy if (hmac_sha256(key, key_len, buf, len, hash)) 283346981Scy return -1; 284346981Scy } else if (key_len == 192 / 8) { 285346981Scy if (hmac_sha384(key, key_len, buf, len, hash)) 286346981Scy return -1; 287346981Scy } else if (key_len == 256 / 8) { 288346981Scy if (hmac_sha512(key, key_len, buf, len, hash)) 289346981Scy return -1; 290346981Scy } else { 291346981Scy wpa_printf(MSG_INFO, 292346981Scy "DPP: Unsupported KCK length: %u", 293346981Scy (unsigned int) key_len); 294346981Scy return -1; 295346981Scy } 296346981Scy os_memcpy(mic, hash, key_len); 297346981Scy break; 298346981Scy#endif /* CONFIG_DPP */ 299346981Scy#if defined(CONFIG_IEEE80211R) && defined(CONFIG_SHA384) 300346981Scy case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: 301346981Scy wpa_printf(MSG_DEBUG, 302346981Scy "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - FT 802.1X SHA384)"); 303346981Scy if (hmac_sha384(key, key_len, buf, len, hash)) 304346981Scy return -1; 305346981Scy os_memcpy(mic, hash, 24); 306346981Scy break; 307346981Scy#endif /* CONFIG_IEEE80211R && CONFIG_SHA384 */ 308281806Srpaulo default: 309346981Scy wpa_printf(MSG_DEBUG, 310346981Scy "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)", 311346981Scy akmp); 312281806Srpaulo return -1; 313281806Srpaulo } 314281806Srpaulo break; 315189251Ssam default: 316346981Scy wpa_printf(MSG_DEBUG, 317346981Scy "WPA: EAPOL-Key MIC algorithm not known (ver=%d)", 318346981Scy ver); 319189251Ssam return -1; 320189251Ssam } 321189251Ssam 322189251Ssam return 0; 323189251Ssam} 324189251Ssam 325189251Ssam 326189251Ssam/** 327189251Ssam * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces 328189251Ssam * @pmk: Pairwise master key 329189251Ssam * @pmk_len: Length of PMK 330189251Ssam * @label: Label to use in derivation 331189251Ssam * @addr1: AA or SA 332189251Ssam * @addr2: SA or AA 333189251Ssam * @nonce1: ANonce or SNonce 334189251Ssam * @nonce2: SNonce or ANonce 335189251Ssam * @ptk: Buffer for pairwise transient key 336281806Srpaulo * @akmp: Negotiated AKM 337281806Srpaulo * @cipher: Negotiated pairwise cipher 338281806Srpaulo * Returns: 0 on success, -1 on failure 339189251Ssam * 340189251Ssam * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy 341189251Ssam * PTK = PRF-X(PMK, "Pairwise key expansion", 342189251Ssam * Min(AA, SA) || Max(AA, SA) || 343346981Scy * Min(ANonce, SNonce) || Max(ANonce, SNonce) 344346981Scy * [ || Z.x ]) 345189251Ssam * 346346981Scy * The optional Z.x component is used only with DPP and that part is not defined 347346981Scy * in IEEE 802.11. 348189251Ssam */ 349281806Srpauloint wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, 350281806Srpaulo const u8 *addr1, const u8 *addr2, 351281806Srpaulo const u8 *nonce1, const u8 *nonce2, 352346981Scy struct wpa_ptk *ptk, int akmp, int cipher, 353346981Scy const u8 *z, size_t z_len) 354189251Ssam{ 355346981Scy#define MAX_Z_LEN 66 /* with NIST P-521 */ 356346981Scy u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN]; 357346981Scy size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN; 358281806Srpaulo u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; 359281806Srpaulo size_t ptk_len; 360189251Ssam 361346981Scy if (pmk_len == 0) { 362346981Scy wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation"); 363346981Scy return -1; 364346981Scy } 365346981Scy 366346981Scy if (z_len > MAX_Z_LEN) 367346981Scy return -1; 368346981Scy 369189251Ssam if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { 370189251Ssam os_memcpy(data, addr1, ETH_ALEN); 371189251Ssam os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); 372189251Ssam } else { 373189251Ssam os_memcpy(data, addr2, ETH_ALEN); 374189251Ssam os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); 375189251Ssam } 376189251Ssam 377189251Ssam if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { 378189251Ssam os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); 379189251Ssam os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, 380189251Ssam WPA_NONCE_LEN); 381189251Ssam } else { 382189251Ssam os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); 383189251Ssam os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, 384189251Ssam WPA_NONCE_LEN); 385189251Ssam } 386189251Ssam 387346981Scy if (z && z_len) { 388346981Scy os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len); 389346981Scy data_len += z_len; 390346981Scy } 391346981Scy 392346981Scy ptk->kck_len = wpa_kck_len(akmp, pmk_len); 393346981Scy ptk->kek_len = wpa_kek_len(akmp, pmk_len); 394281806Srpaulo ptk->tk_len = wpa_cipher_key_len(cipher); 395346981Scy if (ptk->tk_len == 0) { 396346981Scy wpa_printf(MSG_ERROR, 397346981Scy "WPA: Unsupported cipher (0x%x) used in PTK derivation", 398346981Scy cipher); 399346981Scy return -1; 400346981Scy } 401281806Srpaulo ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len; 402281806Srpaulo 403346981Scy if (wpa_key_mgmt_sha384(akmp)) { 404346981Scy#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS) 405346981Scy wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)"); 406346981Scy if (sha384_prf(pmk, pmk_len, label, data, data_len, 407346981Scy tmp, ptk_len) < 0) 408346981Scy return -1; 409346981Scy#else /* CONFIG_SUITEB192 || CONFIG_FILS */ 410346981Scy return -1; 411346981Scy#endif /* CONFIG_SUITEB192 || CONFIG_FILS */ 412346981Scy } else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) { 413346981Scy#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS) 414346981Scy wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); 415346981Scy if (sha256_prf(pmk, pmk_len, label, data, data_len, 416346981Scy tmp, ptk_len) < 0) 417346981Scy return -1; 418346981Scy#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */ 419346981Scy return -1; 420346981Scy#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */ 421346981Scy#ifdef CONFIG_DPP 422346981Scy } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) { 423346981Scy wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); 424346981Scy if (sha256_prf(pmk, pmk_len, label, data, data_len, 425346981Scy tmp, ptk_len) < 0) 426346981Scy return -1; 427346981Scy } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) { 428346981Scy wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)"); 429346981Scy if (sha384_prf(pmk, pmk_len, label, data, data_len, 430346981Scy tmp, ptk_len) < 0) 431346981Scy return -1; 432346981Scy } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) { 433346981Scy wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)"); 434346981Scy if (sha512_prf(pmk, pmk_len, label, data, data_len, 435346981Scy tmp, ptk_len) < 0) 436346981Scy return -1; 437346981Scy } else if (akmp == WPA_KEY_MGMT_DPP) { 438346981Scy wpa_printf(MSG_INFO, "DPP: Unknown PMK length %u", 439346981Scy (unsigned int) pmk_len); 440346981Scy return -1; 441346981Scy#endif /* CONFIG_DPP */ 442346981Scy } else { 443346981Scy wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)"); 444346981Scy if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp, 445346981Scy ptk_len) < 0) 446346981Scy return -1; 447346981Scy } 448189251Ssam 449189251Ssam wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, 450189251Ssam MAC2STR(addr1), MAC2STR(addr2)); 451252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); 452252726Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); 453346981Scy if (z && z_len) 454346981Scy wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len); 455189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); 456281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len); 457281806Srpaulo 458281806Srpaulo os_memcpy(ptk->kck, tmp, ptk->kck_len); 459281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len); 460281806Srpaulo 461281806Srpaulo os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); 462281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len); 463281806Srpaulo 464281806Srpaulo os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); 465281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len); 466281806Srpaulo 467346981Scy ptk->kek2_len = 0; 468346981Scy ptk->kck2_len = 0; 469346981Scy 470281806Srpaulo os_memset(tmp, 0, sizeof(tmp)); 471346981Scy os_memset(data, 0, data_len); 472281806Srpaulo return 0; 473189251Ssam} 474189251Ssam 475346981Scy#ifdef CONFIG_FILS 476189251Ssam 477346981Scyint fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len, 478346981Scy const u8 *snonce, const u8 *anonce, const u8 *dh_ss, 479346981Scy size_t dh_ss_len, u8 *pmk, size_t *pmk_len) 480346981Scy{ 481346981Scy u8 nonces[2 * FILS_NONCE_LEN]; 482346981Scy const u8 *addr[2]; 483346981Scy size_t len[2]; 484346981Scy size_t num_elem; 485346981Scy int res; 486346981Scy 487346981Scy /* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */ 488346981Scy wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation"); 489346981Scy 490346981Scy if (wpa_key_mgmt_sha384(akmp)) 491346981Scy *pmk_len = SHA384_MAC_LEN; 492346981Scy else if (wpa_key_mgmt_sha256(akmp)) 493346981Scy *pmk_len = SHA256_MAC_LEN; 494346981Scy else 495346981Scy return -1; 496346981Scy 497346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len); 498346981Scy wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN); 499346981Scy wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN); 500346981Scy wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len); 501346981Scy 502346981Scy os_memcpy(nonces, snonce, FILS_NONCE_LEN); 503346981Scy os_memcpy(&nonces[FILS_NONCE_LEN], anonce, FILS_NONCE_LEN); 504346981Scy addr[0] = rmsk; 505346981Scy len[0] = rmsk_len; 506346981Scy num_elem = 1; 507346981Scy if (dh_ss) { 508346981Scy addr[1] = dh_ss; 509346981Scy len[1] = dh_ss_len; 510346981Scy num_elem++; 511346981Scy } 512346981Scy if (wpa_key_mgmt_sha384(akmp)) 513346981Scy res = hmac_sha384_vector(nonces, 2 * FILS_NONCE_LEN, num_elem, 514346981Scy addr, len, pmk); 515346981Scy else 516346981Scy res = hmac_sha256_vector(nonces, 2 * FILS_NONCE_LEN, num_elem, 517346981Scy addr, len, pmk); 518346981Scy if (res == 0) 519346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len); 520346981Scy else 521346981Scy *pmk_len = 0; 522346981Scy return res; 523346981Scy} 524346981Scy 525346981Scy 526346981Scyint fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len, 527346981Scy u8 *pmkid) 528346981Scy{ 529346981Scy const u8 *addr[1]; 530346981Scy size_t len[1]; 531346981Scy u8 hash[SHA384_MAC_LEN]; 532346981Scy int res; 533346981Scy 534346981Scy /* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */ 535346981Scy addr[0] = reauth; 536346981Scy len[0] = reauth_len; 537346981Scy if (wpa_key_mgmt_sha384(akmp)) 538346981Scy res = sha384_vector(1, addr, len, hash); 539346981Scy else if (wpa_key_mgmt_sha256(akmp)) 540346981Scy res = sha256_vector(1, addr, len, hash); 541346981Scy else 542346981Scy return -1; 543346981Scy if (res) 544346981Scy return res; 545346981Scy os_memcpy(pmkid, hash, PMKID_LEN); 546346981Scy wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN); 547346981Scy return 0; 548346981Scy} 549346981Scy 550346981Scy 551346981Scyint fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa, 552346981Scy const u8 *snonce, const u8 *anonce, const u8 *dhss, 553346981Scy size_t dhss_len, struct wpa_ptk *ptk, 554346981Scy u8 *ick, size_t *ick_len, int akmp, int cipher, 555346981Scy u8 *fils_ft, size_t *fils_ft_len) 556346981Scy{ 557346981Scy u8 *data, *pos; 558346981Scy size_t data_len; 559346981Scy u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + 560346981Scy FILS_FT_MAX_LEN]; 561346981Scy size_t key_data_len; 562346981Scy const char *label = "FILS PTK Derivation"; 563346981Scy int ret = -1; 564346981Scy 565346981Scy /* 566346981Scy * FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation", 567346981Scy * SPA || AA || SNonce || ANonce [ || DHss ]) 568346981Scy * ICK = L(FILS-Key-Data, 0, ICK_bits) 569346981Scy * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits) 570346981Scy * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits) 571346981Scy * If doing FT initial mobility domain association: 572346981Scy * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits, 573346981Scy * FILS-FT_bits) 574346981Scy */ 575346981Scy data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len; 576346981Scy data = os_malloc(data_len); 577346981Scy if (!data) 578346981Scy goto err; 579346981Scy pos = data; 580346981Scy os_memcpy(pos, spa, ETH_ALEN); 581346981Scy pos += ETH_ALEN; 582346981Scy os_memcpy(pos, aa, ETH_ALEN); 583346981Scy pos += ETH_ALEN; 584346981Scy os_memcpy(pos, snonce, FILS_NONCE_LEN); 585346981Scy pos += FILS_NONCE_LEN; 586346981Scy os_memcpy(pos, anonce, FILS_NONCE_LEN); 587346981Scy pos += FILS_NONCE_LEN; 588346981Scy if (dhss) 589346981Scy os_memcpy(pos, dhss, dhss_len); 590346981Scy 591346981Scy ptk->kck_len = 0; 592346981Scy ptk->kek_len = wpa_kek_len(akmp, pmk_len); 593346981Scy ptk->tk_len = wpa_cipher_key_len(cipher); 594346981Scy if (wpa_key_mgmt_sha384(akmp)) 595346981Scy *ick_len = 48; 596346981Scy else if (wpa_key_mgmt_sha256(akmp)) 597346981Scy *ick_len = 32; 598346981Scy else 599346981Scy goto err; 600346981Scy key_data_len = *ick_len + ptk->kek_len + ptk->tk_len; 601346981Scy 602346981Scy if (fils_ft && fils_ft_len) { 603346981Scy if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) { 604346981Scy *fils_ft_len = 32; 605346981Scy } else if (akmp == WPA_KEY_MGMT_FT_FILS_SHA384) { 606346981Scy *fils_ft_len = 48; 607346981Scy } else { 608346981Scy *fils_ft_len = 0; 609346981Scy fils_ft = NULL; 610346981Scy } 611346981Scy key_data_len += *fils_ft_len; 612346981Scy } 613346981Scy 614346981Scy if (wpa_key_mgmt_sha384(akmp)) { 615346981Scy wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA384)"); 616346981Scy if (sha384_prf(pmk, pmk_len, label, data, data_len, 617346981Scy tmp, key_data_len) < 0) 618346981Scy goto err; 619346981Scy } else { 620346981Scy wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA256)"); 621346981Scy if (sha256_prf(pmk, pmk_len, label, data, data_len, 622346981Scy tmp, key_data_len) < 0) 623346981Scy goto err; 624346981Scy } 625346981Scy 626346981Scy wpa_printf(MSG_DEBUG, "FILS: PTK derivation - SPA=" MACSTR 627346981Scy " AA=" MACSTR, MAC2STR(spa), MAC2STR(aa)); 628346981Scy wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN); 629346981Scy wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN); 630346981Scy if (dhss) 631346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: DHss", dhss, dhss_len); 632346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, pmk_len); 633346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len); 634346981Scy 635346981Scy os_memcpy(ick, tmp, *ick_len); 636346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len); 637346981Scy 638346981Scy os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len); 639346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len); 640346981Scy 641346981Scy os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len); 642346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len); 643346981Scy 644346981Scy if (fils_ft && fils_ft_len) { 645346981Scy os_memcpy(fils_ft, tmp + *ick_len + ptk->kek_len + ptk->tk_len, 646346981Scy *fils_ft_len); 647346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT", 648346981Scy fils_ft, *fils_ft_len); 649346981Scy } 650346981Scy 651346981Scy ptk->kek2_len = 0; 652346981Scy ptk->kck2_len = 0; 653346981Scy 654346981Scy os_memset(tmp, 0, sizeof(tmp)); 655346981Scy ret = 0; 656346981Scyerr: 657346981Scy bin_clear_free(data, data_len); 658346981Scy return ret; 659346981Scy} 660346981Scy 661346981Scy 662346981Scyint fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce, 663346981Scy const u8 *anonce, const u8 *sta_addr, const u8 *bssid, 664346981Scy const u8 *g_sta, size_t g_sta_len, 665346981Scy const u8 *g_ap, size_t g_ap_len, 666346981Scy int akmp, u8 *key_auth_sta, u8 *key_auth_ap, 667346981Scy size_t *key_auth_len) 668346981Scy{ 669346981Scy const u8 *addr[6]; 670346981Scy size_t len[6]; 671346981Scy size_t num_elem = 4; 672346981Scy int res; 673346981Scy 674346981Scy wpa_printf(MSG_DEBUG, "FILS: Key-Auth derivation: STA-MAC=" MACSTR 675346981Scy " AP-BSSID=" MACSTR, MAC2STR(sta_addr), MAC2STR(bssid)); 676346981Scy wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, ick_len); 677346981Scy wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN); 678346981Scy wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN); 679346981Scy wpa_hexdump(MSG_DEBUG, "FILS: gSTA", g_sta, g_sta_len); 680346981Scy wpa_hexdump(MSG_DEBUG, "FILS: gAP", g_ap, g_ap_len); 681346981Scy 682346981Scy /* 683346981Scy * For (Re)Association Request frame (STA->AP): 684346981Scy * Key-Auth = HMAC-Hash(ICK, SNonce || ANonce || STA-MAC || AP-BSSID 685346981Scy * [ || gSTA || gAP ]) 686346981Scy */ 687346981Scy addr[0] = snonce; 688346981Scy len[0] = FILS_NONCE_LEN; 689346981Scy addr[1] = anonce; 690346981Scy len[1] = FILS_NONCE_LEN; 691346981Scy addr[2] = sta_addr; 692346981Scy len[2] = ETH_ALEN; 693346981Scy addr[3] = bssid; 694346981Scy len[3] = ETH_ALEN; 695346981Scy if (g_sta && g_ap_len && g_ap && g_ap_len) { 696346981Scy addr[4] = g_sta; 697346981Scy len[4] = g_sta_len; 698346981Scy addr[5] = g_ap; 699346981Scy len[5] = g_ap_len; 700346981Scy num_elem = 6; 701346981Scy } 702346981Scy 703346981Scy if (wpa_key_mgmt_sha384(akmp)) { 704346981Scy *key_auth_len = 48; 705346981Scy res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len, 706346981Scy key_auth_sta); 707346981Scy } else if (wpa_key_mgmt_sha256(akmp)) { 708346981Scy *key_auth_len = 32; 709346981Scy res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len, 710346981Scy key_auth_sta); 711346981Scy } else { 712346981Scy return -1; 713346981Scy } 714346981Scy if (res < 0) 715346981Scy return res; 716346981Scy 717346981Scy /* 718346981Scy * For (Re)Association Response frame (AP->STA): 719346981Scy * Key-Auth = HMAC-Hash(ICK, ANonce || SNonce || AP-BSSID || STA-MAC 720346981Scy * [ || gAP || gSTA ]) 721346981Scy */ 722346981Scy addr[0] = anonce; 723346981Scy addr[1] = snonce; 724346981Scy addr[2] = bssid; 725346981Scy addr[3] = sta_addr; 726346981Scy if (g_sta && g_ap_len && g_ap && g_ap_len) { 727346981Scy addr[4] = g_ap; 728346981Scy len[4] = g_ap_len; 729346981Scy addr[5] = g_sta; 730346981Scy len[5] = g_sta_len; 731346981Scy } 732346981Scy 733346981Scy if (wpa_key_mgmt_sha384(akmp)) 734346981Scy res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len, 735346981Scy key_auth_ap); 736346981Scy else if (wpa_key_mgmt_sha256(akmp)) 737346981Scy res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len, 738346981Scy key_auth_ap); 739346981Scy if (res < 0) 740346981Scy return res; 741346981Scy 742346981Scy wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (STA)", 743346981Scy key_auth_sta, *key_auth_len); 744346981Scy wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (AP)", 745346981Scy key_auth_ap, *key_auth_len); 746346981Scy 747346981Scy return 0; 748346981Scy} 749346981Scy 750346981Scy#endif /* CONFIG_FILS */ 751346981Scy 752346981Scy 753189251Ssam#ifdef CONFIG_IEEE80211R 754281806Srpauloint wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, 755281806Srpaulo const u8 *ap_addr, u8 transaction_seqnum, 756281806Srpaulo const u8 *mdie, size_t mdie_len, 757189251Ssam const u8 *ftie, size_t ftie_len, 758189251Ssam const u8 *rsnie, size_t rsnie_len, 759189251Ssam const u8 *ric, size_t ric_len, u8 *mic) 760189251Ssam{ 761289549Srpaulo const u8 *addr[9]; 762289549Srpaulo size_t len[9]; 763289549Srpaulo size_t i, num_elem = 0; 764346981Scy u8 zero_mic[24]; 765346981Scy size_t mic_len, fte_fixed_len; 766189251Ssam 767346981Scy if (kck_len == 16) { 768346981Scy mic_len = 16; 769346981Scy#ifdef CONFIG_SHA384 770346981Scy } else if (kck_len == 24) { 771346981Scy mic_len = 24; 772346981Scy#endif /* CONFIG_SHA384 */ 773346981Scy } else { 774281806Srpaulo wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u", 775281806Srpaulo (unsigned int) kck_len); 776281806Srpaulo return -1; 777281806Srpaulo } 778281806Srpaulo 779346981Scy fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len; 780346981Scy 781289549Srpaulo addr[num_elem] = sta_addr; 782289549Srpaulo len[num_elem] = ETH_ALEN; 783289549Srpaulo num_elem++; 784189251Ssam 785289549Srpaulo addr[num_elem] = ap_addr; 786289549Srpaulo len[num_elem] = ETH_ALEN; 787289549Srpaulo num_elem++; 788289549Srpaulo 789289549Srpaulo addr[num_elem] = &transaction_seqnum; 790289549Srpaulo len[num_elem] = 1; 791289549Srpaulo num_elem++; 792289549Srpaulo 793189251Ssam if (rsnie) { 794289549Srpaulo addr[num_elem] = rsnie; 795289549Srpaulo len[num_elem] = rsnie_len; 796289549Srpaulo num_elem++; 797189251Ssam } 798189251Ssam if (mdie) { 799289549Srpaulo addr[num_elem] = mdie; 800289549Srpaulo len[num_elem] = mdie_len; 801289549Srpaulo num_elem++; 802189251Ssam } 803189251Ssam if (ftie) { 804346981Scy if (ftie_len < 2 + fte_fixed_len) 805189251Ssam return -1; 806289549Srpaulo 807289549Srpaulo /* IE hdr and mic_control */ 808289549Srpaulo addr[num_elem] = ftie; 809289549Srpaulo len[num_elem] = 2 + 2; 810289549Srpaulo num_elem++; 811289549Srpaulo 812289549Srpaulo /* MIC field with all zeros */ 813346981Scy os_memset(zero_mic, 0, mic_len); 814289549Srpaulo addr[num_elem] = zero_mic; 815346981Scy len[num_elem] = mic_len; 816289549Srpaulo num_elem++; 817289549Srpaulo 818289549Srpaulo /* Rest of FTIE */ 819346981Scy addr[num_elem] = ftie + 2 + 2 + mic_len; 820346981Scy len[num_elem] = ftie_len - (2 + 2 + mic_len); 821289549Srpaulo num_elem++; 822189251Ssam } 823189251Ssam if (ric) { 824289549Srpaulo addr[num_elem] = ric; 825289549Srpaulo len[num_elem] = ric_len; 826289549Srpaulo num_elem++; 827189251Ssam } 828189251Ssam 829289549Srpaulo for (i = 0; i < num_elem; i++) 830289549Srpaulo wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]); 831346981Scy#ifdef CONFIG_SHA384 832346981Scy if (kck_len == 24) { 833346981Scy u8 hash[SHA384_MAC_LEN]; 834346981Scy 835346981Scy if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash)) 836346981Scy return -1; 837346981Scy os_memcpy(mic, hash, 24); 838346981Scy } 839346981Scy#endif /* CONFIG_SHA384 */ 840346981Scy if (kck_len == 16 && 841346981Scy omac1_aes_128_vector(kck, num_elem, addr, len, mic)) 842189251Ssam return -1; 843189251Ssam 844189251Ssam return 0; 845189251Ssam} 846252726Srpaulo 847252726Srpaulo 848252726Srpaulostatic int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, 849346981Scy struct wpa_ft_ies *parse, int use_sha384) 850252726Srpaulo{ 851252726Srpaulo const u8 *end, *pos; 852252726Srpaulo 853252726Srpaulo parse->ftie = ie; 854252726Srpaulo parse->ftie_len = ie_len; 855252726Srpaulo 856346981Scy pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) : 857346981Scy sizeof(struct rsn_ftie)); 858252726Srpaulo end = ie + ie_len; 859346981Scy wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos); 860252726Srpaulo 861337817Scy while (end - pos >= 2) { 862337817Scy u8 id, len; 863337817Scy 864337817Scy id = *pos++; 865337817Scy len = *pos++; 866346981Scy if (len > end - pos) { 867346981Scy wpa_printf(MSG_DEBUG, "FT: Truncated subelement"); 868337817Scy break; 869346981Scy } 870337817Scy 871337817Scy switch (id) { 872252726Srpaulo case FTIE_SUBELEM_R1KH_ID: 873337817Scy if (len != FT_R1KH_ID_LEN) { 874337817Scy wpa_printf(MSG_DEBUG, 875337817Scy "FT: Invalid R1KH-ID length in FTIE: %d", 876337817Scy len); 877252726Srpaulo return -1; 878252726Srpaulo } 879337817Scy parse->r1kh_id = pos; 880252726Srpaulo break; 881252726Srpaulo case FTIE_SUBELEM_GTK: 882337817Scy parse->gtk = pos; 883337817Scy parse->gtk_len = len; 884252726Srpaulo break; 885252726Srpaulo case FTIE_SUBELEM_R0KH_ID: 886337817Scy if (len < 1 || len > FT_R0KH_ID_MAX_LEN) { 887337817Scy wpa_printf(MSG_DEBUG, 888337817Scy "FT: Invalid R0KH-ID length in FTIE: %d", 889337817Scy len); 890252726Srpaulo return -1; 891252726Srpaulo } 892337817Scy parse->r0kh_id = pos; 893337817Scy parse->r0kh_id_len = len; 894252726Srpaulo break; 895252726Srpaulo#ifdef CONFIG_IEEE80211W 896252726Srpaulo case FTIE_SUBELEM_IGTK: 897337817Scy parse->igtk = pos; 898337817Scy parse->igtk_len = len; 899252726Srpaulo break; 900252726Srpaulo#endif /* CONFIG_IEEE80211W */ 901346981Scy#ifdef CONFIG_OCV 902346981Scy case FTIE_SUBELEM_OCI: 903346981Scy parse->oci = pos; 904346981Scy parse->oci_len = len; 905346981Scy break; 906346981Scy#endif /* CONFIG_OCV */ 907346981Scy default: 908346981Scy wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id); 909346981Scy break; 910252726Srpaulo } 911252726Srpaulo 912337817Scy pos += len; 913252726Srpaulo } 914252726Srpaulo 915252726Srpaulo return 0; 916252726Srpaulo} 917252726Srpaulo 918252726Srpaulo 919252726Srpauloint wpa_ft_parse_ies(const u8 *ies, size_t ies_len, 920346981Scy struct wpa_ft_ies *parse, int use_sha384) 921252726Srpaulo{ 922252726Srpaulo const u8 *end, *pos; 923252726Srpaulo struct wpa_ie_data data; 924252726Srpaulo int ret; 925252726Srpaulo const struct rsn_ftie *ftie; 926252726Srpaulo int prot_ie_count = 0; 927346981Scy int update_use_sha384 = 0; 928252726Srpaulo 929346981Scy if (use_sha384 < 0) { 930346981Scy use_sha384 = 0; 931346981Scy update_use_sha384 = 1; 932346981Scy } 933346981Scy 934252726Srpaulo os_memset(parse, 0, sizeof(*parse)); 935252726Srpaulo if (ies == NULL) 936252726Srpaulo return 0; 937252726Srpaulo 938252726Srpaulo pos = ies; 939252726Srpaulo end = ies + ies_len; 940337817Scy while (end - pos >= 2) { 941337817Scy u8 id, len; 942337817Scy 943337817Scy id = *pos++; 944337817Scy len = *pos++; 945337817Scy if (len > end - pos) 946337817Scy break; 947337817Scy 948337817Scy switch (id) { 949252726Srpaulo case WLAN_EID_RSN: 950346981Scy wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len); 951337817Scy parse->rsn = pos; 952337817Scy parse->rsn_len = len; 953252726Srpaulo ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, 954252726Srpaulo parse->rsn_len + 2, 955252726Srpaulo &data); 956252726Srpaulo if (ret < 0) { 957252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Failed to parse " 958252726Srpaulo "RSN IE: %d", ret); 959252726Srpaulo return -1; 960252726Srpaulo } 961252726Srpaulo if (data.num_pmkid == 1 && data.pmkid) 962252726Srpaulo parse->rsn_pmkid = data.pmkid; 963346981Scy parse->key_mgmt = data.key_mgmt; 964346981Scy parse->pairwise_cipher = data.pairwise_cipher; 965346981Scy if (update_use_sha384) { 966346981Scy use_sha384 = 967346981Scy wpa_key_mgmt_sha384(parse->key_mgmt); 968346981Scy update_use_sha384 = 0; 969346981Scy } 970252726Srpaulo break; 971252726Srpaulo case WLAN_EID_MOBILITY_DOMAIN: 972346981Scy wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len); 973337817Scy if (len < sizeof(struct rsn_mdie)) 974289549Srpaulo return -1; 975337817Scy parse->mdie = pos; 976337817Scy parse->mdie_len = len; 977252726Srpaulo break; 978252726Srpaulo case WLAN_EID_FAST_BSS_TRANSITION: 979346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len); 980346981Scy if (use_sha384) { 981346981Scy const struct rsn_ftie_sha384 *ftie_sha384; 982346981Scy 983346981Scy if (len < sizeof(*ftie_sha384)) 984346981Scy return -1; 985346981Scy ftie_sha384 = 986346981Scy (const struct rsn_ftie_sha384 *) pos; 987346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", 988346981Scy ftie_sha384->mic_control, 2); 989346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", 990346981Scy ftie_sha384->mic, 991346981Scy sizeof(ftie_sha384->mic)); 992346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce", 993346981Scy ftie_sha384->anonce, 994346981Scy WPA_NONCE_LEN); 995346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce", 996346981Scy ftie_sha384->snonce, 997346981Scy WPA_NONCE_LEN); 998346981Scy prot_ie_count = ftie_sha384->mic_control[1]; 999346981Scy if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0) 1000346981Scy return -1; 1001346981Scy break; 1002346981Scy } 1003346981Scy 1004337817Scy if (len < sizeof(*ftie)) 1005252726Srpaulo return -1; 1006337817Scy ftie = (const struct rsn_ftie *) pos; 1007346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", 1008346981Scy ftie->mic_control, 2); 1009346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", 1010346981Scy ftie->mic, sizeof(ftie->mic)); 1011346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce", 1012346981Scy ftie->anonce, WPA_NONCE_LEN); 1013346981Scy wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce", 1014346981Scy ftie->snonce, WPA_NONCE_LEN); 1015252726Srpaulo prot_ie_count = ftie->mic_control[1]; 1016346981Scy if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0) 1017252726Srpaulo return -1; 1018252726Srpaulo break; 1019252726Srpaulo case WLAN_EID_TIMEOUT_INTERVAL: 1020346981Scy wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval", 1021346981Scy pos, len); 1022337817Scy if (len != 5) 1023289549Srpaulo break; 1024337817Scy parse->tie = pos; 1025337817Scy parse->tie_len = len; 1026252726Srpaulo break; 1027252726Srpaulo case WLAN_EID_RIC_DATA: 1028252726Srpaulo if (parse->ric == NULL) 1029337817Scy parse->ric = pos - 2; 1030252726Srpaulo break; 1031252726Srpaulo } 1032252726Srpaulo 1033337817Scy pos += len; 1034252726Srpaulo } 1035252726Srpaulo 1036252726Srpaulo if (prot_ie_count == 0) 1037252726Srpaulo return 0; /* no MIC */ 1038252726Srpaulo 1039252726Srpaulo /* 1040252726Srpaulo * Check that the protected IE count matches with IEs included in the 1041252726Srpaulo * frame. 1042252726Srpaulo */ 1043252726Srpaulo if (parse->rsn) 1044252726Srpaulo prot_ie_count--; 1045252726Srpaulo if (parse->mdie) 1046252726Srpaulo prot_ie_count--; 1047252726Srpaulo if (parse->ftie) 1048252726Srpaulo prot_ie_count--; 1049252726Srpaulo if (prot_ie_count < 0) { 1050252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " 1051252726Srpaulo "the protected IE count"); 1052252726Srpaulo return -1; 1053252726Srpaulo } 1054252726Srpaulo 1055252726Srpaulo if (prot_ie_count == 0 && parse->ric) { 1056252726Srpaulo wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " 1057252726Srpaulo "included in protected IE count"); 1058252726Srpaulo return -1; 1059252726Srpaulo } 1060252726Srpaulo 1061252726Srpaulo /* Determine the end of the RIC IE(s) */ 1062337817Scy if (parse->ric) { 1063337817Scy pos = parse->ric; 1064337817Scy while (end - pos >= 2 && 2 + pos[1] <= end - pos && 1065337817Scy prot_ie_count) { 1066337817Scy prot_ie_count--; 1067337817Scy pos += 2 + pos[1]; 1068337817Scy } 1069337817Scy parse->ric_len = pos - parse->ric; 1070252726Srpaulo } 1071252726Srpaulo if (prot_ie_count) { 1072252726Srpaulo wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " 1073252726Srpaulo "frame", (int) prot_ie_count); 1074252726Srpaulo return -1; 1075252726Srpaulo } 1076252726Srpaulo 1077252726Srpaulo return 0; 1078252726Srpaulo} 1079189251Ssam#endif /* CONFIG_IEEE80211R */ 1080189251Ssam 1081189251Ssam 1082189251Ssamstatic int rsn_selector_to_bitfield(const u8 *s) 1083189251Ssam{ 1084189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) 1085189251Ssam return WPA_CIPHER_NONE; 1086189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) 1087189251Ssam return WPA_CIPHER_TKIP; 1088189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) 1089189251Ssam return WPA_CIPHER_CCMP; 1090189251Ssam#ifdef CONFIG_IEEE80211W 1091189251Ssam if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) 1092189251Ssam return WPA_CIPHER_AES_128_CMAC; 1093189251Ssam#endif /* CONFIG_IEEE80211W */ 1094252726Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) 1095252726Srpaulo return WPA_CIPHER_GCMP; 1096281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256) 1097281806Srpaulo return WPA_CIPHER_CCMP_256; 1098281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256) 1099281806Srpaulo return WPA_CIPHER_GCMP_256; 1100281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128) 1101281806Srpaulo return WPA_CIPHER_BIP_GMAC_128; 1102281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256) 1103281806Srpaulo return WPA_CIPHER_BIP_GMAC_256; 1104281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) 1105281806Srpaulo return WPA_CIPHER_BIP_CMAC_256; 1106281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED) 1107281806Srpaulo return WPA_CIPHER_GTK_NOT_USED; 1108189251Ssam return 0; 1109189251Ssam} 1110189251Ssam 1111189251Ssam 1112189251Ssamstatic int rsn_key_mgmt_to_bitfield(const u8 *s) 1113189251Ssam{ 1114189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) 1115189251Ssam return WPA_KEY_MGMT_IEEE8021X; 1116189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) 1117189251Ssam return WPA_KEY_MGMT_PSK; 1118189251Ssam#ifdef CONFIG_IEEE80211R 1119189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) 1120189251Ssam return WPA_KEY_MGMT_FT_IEEE8021X; 1121189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) 1122189251Ssam return WPA_KEY_MGMT_FT_PSK; 1123346981Scy#ifdef CONFIG_SHA384 1124346981Scy if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384) 1125346981Scy return WPA_KEY_MGMT_FT_IEEE8021X_SHA384; 1126346981Scy#endif /* CONFIG_SHA384 */ 1127189251Ssam#endif /* CONFIG_IEEE80211R */ 1128189251Ssam#ifdef CONFIG_IEEE80211W 1129189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) 1130189251Ssam return WPA_KEY_MGMT_IEEE8021X_SHA256; 1131189251Ssam if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) 1132189251Ssam return WPA_KEY_MGMT_PSK_SHA256; 1133189251Ssam#endif /* CONFIG_IEEE80211W */ 1134252726Srpaulo#ifdef CONFIG_SAE 1135252726Srpaulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE) 1136252726Srpaulo return WPA_KEY_MGMT_SAE; 1137252726Srpaulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE) 1138252726Srpaulo return WPA_KEY_MGMT_FT_SAE; 1139252726Srpaulo#endif /* CONFIG_SAE */ 1140281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B) 1141281806Srpaulo return WPA_KEY_MGMT_IEEE8021X_SUITE_B; 1142281806Srpaulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192) 1143281806Srpaulo return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; 1144346981Scy if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA256) 1145346981Scy return WPA_KEY_MGMT_FILS_SHA256; 1146346981Scy if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA384) 1147346981Scy return WPA_KEY_MGMT_FILS_SHA384; 1148346981Scy if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA256) 1149346981Scy return WPA_KEY_MGMT_FT_FILS_SHA256; 1150346981Scy if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA384) 1151346981Scy return WPA_KEY_MGMT_FT_FILS_SHA384; 1152346981Scy#ifdef CONFIG_OWE 1153346981Scy if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OWE) 1154346981Scy return WPA_KEY_MGMT_OWE; 1155346981Scy#endif /* CONFIG_OWE */ 1156346981Scy#ifdef CONFIG_DPP 1157346981Scy if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_DPP) 1158346981Scy return WPA_KEY_MGMT_DPP; 1159346981Scy#endif /* CONFIG_DPP */ 1160289549Srpaulo if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN) 1161289549Srpaulo return WPA_KEY_MGMT_OSEN; 1162189251Ssam return 0; 1163189251Ssam} 1164189251Ssam 1165189251Ssam 1166289549Srpauloint wpa_cipher_valid_group(int cipher) 1167281806Srpaulo{ 1168281806Srpaulo return wpa_cipher_valid_pairwise(cipher) || 1169281806Srpaulo cipher == WPA_CIPHER_GTK_NOT_USED; 1170281806Srpaulo} 1171281806Srpaulo 1172281806Srpaulo 1173281806Srpaulo#ifdef CONFIG_IEEE80211W 1174281806Srpauloint wpa_cipher_valid_mgmt_group(int cipher) 1175281806Srpaulo{ 1176281806Srpaulo return cipher == WPA_CIPHER_AES_128_CMAC || 1177281806Srpaulo cipher == WPA_CIPHER_BIP_GMAC_128 || 1178281806Srpaulo cipher == WPA_CIPHER_BIP_GMAC_256 || 1179281806Srpaulo cipher == WPA_CIPHER_BIP_CMAC_256; 1180281806Srpaulo} 1181281806Srpaulo#endif /* CONFIG_IEEE80211W */ 1182281806Srpaulo 1183281806Srpaulo 1184189251Ssam/** 1185189251Ssam * wpa_parse_wpa_ie_rsn - Parse RSN IE 1186189251Ssam * @rsn_ie: Buffer containing RSN IE 1187189251Ssam * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) 1188189251Ssam * @data: Pointer to structure that will be filled in with parsed data 1189189251Ssam * Returns: 0 on success, <0 on failure 1190189251Ssam */ 1191189251Ssamint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, 1192189251Ssam struct wpa_ie_data *data) 1193189251Ssam{ 1194189251Ssam const u8 *pos; 1195189251Ssam int left; 1196189251Ssam int i, count; 1197189251Ssam 1198189251Ssam os_memset(data, 0, sizeof(*data)); 1199189251Ssam data->proto = WPA_PROTO_RSN; 1200189251Ssam data->pairwise_cipher = WPA_CIPHER_CCMP; 1201189251Ssam data->group_cipher = WPA_CIPHER_CCMP; 1202189251Ssam data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 1203189251Ssam data->capabilities = 0; 1204189251Ssam data->pmkid = NULL; 1205189251Ssam data->num_pmkid = 0; 1206189251Ssam#ifdef CONFIG_IEEE80211W 1207189251Ssam data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; 1208189251Ssam#else /* CONFIG_IEEE80211W */ 1209189251Ssam data->mgmt_group_cipher = 0; 1210189251Ssam#endif /* CONFIG_IEEE80211W */ 1211189251Ssam 1212189251Ssam if (rsn_ie_len == 0) { 1213189251Ssam /* No RSN IE - fail silently */ 1214189251Ssam return -1; 1215189251Ssam } 1216189251Ssam 1217189251Ssam if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { 1218189251Ssam wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 1219189251Ssam __func__, (unsigned long) rsn_ie_len); 1220189251Ssam return -1; 1221189251Ssam } 1222189251Ssam 1223289549Srpaulo if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 && 1224289549Srpaulo rsn_ie[1] == rsn_ie_len - 2 && 1225289549Srpaulo WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) { 1226289549Srpaulo pos = rsn_ie + 6; 1227289549Srpaulo left = rsn_ie_len - 6; 1228189251Ssam 1229346981Scy data->group_cipher = WPA_CIPHER_GTK_NOT_USED; 1230346981Scy data->has_group = 1; 1231346981Scy data->key_mgmt = WPA_KEY_MGMT_OSEN; 1232289549Srpaulo data->proto = WPA_PROTO_OSEN; 1233289549Srpaulo } else { 1234289549Srpaulo const struct rsn_ie_hdr *hdr; 1235289549Srpaulo 1236289549Srpaulo hdr = (const struct rsn_ie_hdr *) rsn_ie; 1237289549Srpaulo 1238289549Srpaulo if (hdr->elem_id != WLAN_EID_RSN || 1239289549Srpaulo hdr->len != rsn_ie_len - 2 || 1240289549Srpaulo WPA_GET_LE16(hdr->version) != RSN_VERSION) { 1241289549Srpaulo wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 1242289549Srpaulo __func__); 1243289549Srpaulo return -2; 1244289549Srpaulo } 1245289549Srpaulo 1246289549Srpaulo pos = (const u8 *) (hdr + 1); 1247289549Srpaulo left = rsn_ie_len - sizeof(*hdr); 1248189251Ssam } 1249189251Ssam 1250189251Ssam if (left >= RSN_SELECTOR_LEN) { 1251189251Ssam data->group_cipher = rsn_selector_to_bitfield(pos); 1252346981Scy data->has_group = 1; 1253281806Srpaulo if (!wpa_cipher_valid_group(data->group_cipher)) { 1254337817Scy wpa_printf(MSG_DEBUG, 1255337817Scy "%s: invalid group cipher 0x%x (%08x)", 1256337817Scy __func__, data->group_cipher, 1257337817Scy WPA_GET_BE32(pos)); 1258189251Ssam return -1; 1259189251Ssam } 1260189251Ssam pos += RSN_SELECTOR_LEN; 1261189251Ssam left -= RSN_SELECTOR_LEN; 1262189251Ssam } else if (left > 0) { 1263189251Ssam wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 1264189251Ssam __func__, left); 1265189251Ssam return -3; 1266189251Ssam } 1267189251Ssam 1268189251Ssam if (left >= 2) { 1269189251Ssam data->pairwise_cipher = 0; 1270189251Ssam count = WPA_GET_LE16(pos); 1271189251Ssam pos += 2; 1272189251Ssam left -= 2; 1273281806Srpaulo if (count == 0 || count > left / RSN_SELECTOR_LEN) { 1274189251Ssam wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 1275189251Ssam "count %u left %u", __func__, count, left); 1276189251Ssam return -4; 1277189251Ssam } 1278346981Scy if (count) 1279346981Scy data->has_pairwise = 1; 1280189251Ssam for (i = 0; i < count; i++) { 1281189251Ssam data->pairwise_cipher |= rsn_selector_to_bitfield(pos); 1282189251Ssam pos += RSN_SELECTOR_LEN; 1283189251Ssam left -= RSN_SELECTOR_LEN; 1284189251Ssam } 1285189251Ssam#ifdef CONFIG_IEEE80211W 1286189251Ssam if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { 1287189251Ssam wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " 1288189251Ssam "pairwise cipher", __func__); 1289189251Ssam return -1; 1290189251Ssam } 1291189251Ssam#endif /* CONFIG_IEEE80211W */ 1292189251Ssam } else if (left == 1) { 1293189251Ssam wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 1294189251Ssam __func__); 1295189251Ssam return -5; 1296189251Ssam } 1297189251Ssam 1298189251Ssam if (left >= 2) { 1299189251Ssam data->key_mgmt = 0; 1300189251Ssam count = WPA_GET_LE16(pos); 1301189251Ssam pos += 2; 1302189251Ssam left -= 2; 1303281806Srpaulo if (count == 0 || count > left / RSN_SELECTOR_LEN) { 1304189251Ssam wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 1305189251Ssam "count %u left %u", __func__, count, left); 1306189251Ssam return -6; 1307189251Ssam } 1308189251Ssam for (i = 0; i < count; i++) { 1309189251Ssam data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); 1310189251Ssam pos += RSN_SELECTOR_LEN; 1311189251Ssam left -= RSN_SELECTOR_LEN; 1312189251Ssam } 1313189251Ssam } else if (left == 1) { 1314189251Ssam wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 1315189251Ssam __func__); 1316189251Ssam return -7; 1317189251Ssam } 1318189251Ssam 1319189251Ssam if (left >= 2) { 1320189251Ssam data->capabilities = WPA_GET_LE16(pos); 1321189251Ssam pos += 2; 1322189251Ssam left -= 2; 1323189251Ssam } 1324189251Ssam 1325189251Ssam if (left >= 2) { 1326281806Srpaulo u16 num_pmkid = WPA_GET_LE16(pos); 1327189251Ssam pos += 2; 1328189251Ssam left -= 2; 1329281806Srpaulo if (num_pmkid > (unsigned int) left / PMKID_LEN) { 1330189251Ssam wpa_printf(MSG_DEBUG, "%s: PMKID underflow " 1331281806Srpaulo "(num_pmkid=%u left=%d)", 1332281806Srpaulo __func__, num_pmkid, left); 1333189251Ssam data->num_pmkid = 0; 1334189251Ssam return -9; 1335189251Ssam } else { 1336281806Srpaulo data->num_pmkid = num_pmkid; 1337189251Ssam data->pmkid = pos; 1338189251Ssam pos += data->num_pmkid * PMKID_LEN; 1339189251Ssam left -= data->num_pmkid * PMKID_LEN; 1340189251Ssam } 1341189251Ssam } 1342189251Ssam 1343189251Ssam#ifdef CONFIG_IEEE80211W 1344189251Ssam if (left >= 4) { 1345189251Ssam data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); 1346281806Srpaulo if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) { 1347337817Scy wpa_printf(MSG_DEBUG, 1348337817Scy "%s: Unsupported management group cipher 0x%x (%08x)", 1349337817Scy __func__, data->mgmt_group_cipher, 1350337817Scy WPA_GET_BE32(pos)); 1351189251Ssam return -10; 1352189251Ssam } 1353189251Ssam pos += RSN_SELECTOR_LEN; 1354189251Ssam left -= RSN_SELECTOR_LEN; 1355189251Ssam } 1356189251Ssam#endif /* CONFIG_IEEE80211W */ 1357189251Ssam 1358189251Ssam if (left > 0) { 1359281806Srpaulo wpa_hexdump(MSG_DEBUG, 1360281806Srpaulo "wpa_parse_wpa_ie_rsn: ignore trailing bytes", 1361281806Srpaulo pos, left); 1362189251Ssam } 1363189251Ssam 1364189251Ssam return 0; 1365189251Ssam} 1366189251Ssam 1367189251Ssam 1368252726Srpaulostatic int wpa_selector_to_bitfield(const u8 *s) 1369252726Srpaulo{ 1370252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) 1371252726Srpaulo return WPA_CIPHER_NONE; 1372252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) 1373252726Srpaulo return WPA_CIPHER_TKIP; 1374252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) 1375252726Srpaulo return WPA_CIPHER_CCMP; 1376252726Srpaulo return 0; 1377252726Srpaulo} 1378252726Srpaulo 1379252726Srpaulo 1380252726Srpaulostatic int wpa_key_mgmt_to_bitfield(const u8 *s) 1381252726Srpaulo{ 1382252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) 1383252726Srpaulo return WPA_KEY_MGMT_IEEE8021X; 1384252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) 1385252726Srpaulo return WPA_KEY_MGMT_PSK; 1386252726Srpaulo if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) 1387252726Srpaulo return WPA_KEY_MGMT_WPA_NONE; 1388252726Srpaulo return 0; 1389252726Srpaulo} 1390252726Srpaulo 1391252726Srpaulo 1392252726Srpauloint wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, 1393252726Srpaulo struct wpa_ie_data *data) 1394252726Srpaulo{ 1395252726Srpaulo const struct wpa_ie_hdr *hdr; 1396252726Srpaulo const u8 *pos; 1397252726Srpaulo int left; 1398252726Srpaulo int i, count; 1399252726Srpaulo 1400252726Srpaulo os_memset(data, 0, sizeof(*data)); 1401252726Srpaulo data->proto = WPA_PROTO_WPA; 1402252726Srpaulo data->pairwise_cipher = WPA_CIPHER_TKIP; 1403252726Srpaulo data->group_cipher = WPA_CIPHER_TKIP; 1404252726Srpaulo data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; 1405252726Srpaulo data->capabilities = 0; 1406252726Srpaulo data->pmkid = NULL; 1407252726Srpaulo data->num_pmkid = 0; 1408252726Srpaulo data->mgmt_group_cipher = 0; 1409252726Srpaulo 1410252726Srpaulo if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { 1411252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", 1412252726Srpaulo __func__, (unsigned long) wpa_ie_len); 1413252726Srpaulo return -1; 1414252726Srpaulo } 1415252726Srpaulo 1416252726Srpaulo hdr = (const struct wpa_ie_hdr *) wpa_ie; 1417252726Srpaulo 1418252726Srpaulo if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || 1419252726Srpaulo hdr->len != wpa_ie_len - 2 || 1420252726Srpaulo RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || 1421252726Srpaulo WPA_GET_LE16(hdr->version) != WPA_VERSION) { 1422252726Srpaulo wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", 1423252726Srpaulo __func__); 1424252726Srpaulo return -2; 1425252726Srpaulo } 1426252726Srpaulo 1427252726Srpaulo pos = (const u8 *) (hdr + 1); 1428252726Srpaulo left = wpa_ie_len - sizeof(*hdr); 1429252726Srpaulo 1430252726Srpaulo if (left >= WPA_SELECTOR_LEN) { 1431252726Srpaulo data->group_cipher = wpa_selector_to_bitfield(pos); 1432252726Srpaulo pos += WPA_SELECTOR_LEN; 1433252726Srpaulo left -= WPA_SELECTOR_LEN; 1434252726Srpaulo } else if (left > 0) { 1435252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", 1436252726Srpaulo __func__, left); 1437252726Srpaulo return -3; 1438252726Srpaulo } 1439252726Srpaulo 1440252726Srpaulo if (left >= 2) { 1441252726Srpaulo data->pairwise_cipher = 0; 1442252726Srpaulo count = WPA_GET_LE16(pos); 1443252726Srpaulo pos += 2; 1444252726Srpaulo left -= 2; 1445281806Srpaulo if (count == 0 || count > left / WPA_SELECTOR_LEN) { 1446252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " 1447252726Srpaulo "count %u left %u", __func__, count, left); 1448252726Srpaulo return -4; 1449252726Srpaulo } 1450252726Srpaulo for (i = 0; i < count; i++) { 1451252726Srpaulo data->pairwise_cipher |= wpa_selector_to_bitfield(pos); 1452252726Srpaulo pos += WPA_SELECTOR_LEN; 1453252726Srpaulo left -= WPA_SELECTOR_LEN; 1454252726Srpaulo } 1455252726Srpaulo } else if (left == 1) { 1456252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", 1457252726Srpaulo __func__); 1458252726Srpaulo return -5; 1459252726Srpaulo } 1460252726Srpaulo 1461252726Srpaulo if (left >= 2) { 1462252726Srpaulo data->key_mgmt = 0; 1463252726Srpaulo count = WPA_GET_LE16(pos); 1464252726Srpaulo pos += 2; 1465252726Srpaulo left -= 2; 1466281806Srpaulo if (count == 0 || count > left / WPA_SELECTOR_LEN) { 1467252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " 1468252726Srpaulo "count %u left %u", __func__, count, left); 1469252726Srpaulo return -6; 1470252726Srpaulo } 1471252726Srpaulo for (i = 0; i < count; i++) { 1472252726Srpaulo data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); 1473252726Srpaulo pos += WPA_SELECTOR_LEN; 1474252726Srpaulo left -= WPA_SELECTOR_LEN; 1475252726Srpaulo } 1476252726Srpaulo } else if (left == 1) { 1477252726Srpaulo wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", 1478252726Srpaulo __func__); 1479252726Srpaulo return -7; 1480252726Srpaulo } 1481252726Srpaulo 1482252726Srpaulo if (left >= 2) { 1483252726Srpaulo data->capabilities = WPA_GET_LE16(pos); 1484252726Srpaulo pos += 2; 1485252726Srpaulo left -= 2; 1486252726Srpaulo } 1487252726Srpaulo 1488252726Srpaulo if (left > 0) { 1489281806Srpaulo wpa_hexdump(MSG_DEBUG, 1490281806Srpaulo "wpa_parse_wpa_ie_wpa: ignore trailing bytes", 1491281806Srpaulo pos, left); 1492252726Srpaulo } 1493252726Srpaulo 1494252726Srpaulo return 0; 1495252726Srpaulo} 1496252726Srpaulo 1497252726Srpaulo 1498346981Scyint wpa_default_rsn_cipher(int freq) 1499346981Scy{ 1500346981Scy if (freq > 56160) 1501346981Scy return WPA_CIPHER_GCMP; /* DMG */ 1502346981Scy 1503346981Scy return WPA_CIPHER_CCMP; 1504346981Scy} 1505346981Scy 1506346981Scy 1507189251Ssam#ifdef CONFIG_IEEE80211R 1508189251Ssam 1509189251Ssam/** 1510189251Ssam * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name 1511189251Ssam * 1512189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.3 1513189251Ssam */ 1514346981Scyint wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, 1515346981Scy const u8 *ssid, size_t ssid_len, 1516346981Scy const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, 1517346981Scy const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name, 1518346981Scy int use_sha384) 1519189251Ssam{ 1520289549Srpaulo u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + 1521189251Ssam FT_R0KH_ID_MAX_LEN + ETH_ALEN]; 1522346981Scy u8 *pos, r0_key_data[64], hash[48]; 1523189251Ssam const u8 *addr[2]; 1524189251Ssam size_t len[2]; 1525346981Scy size_t q = use_sha384 ? 48 : 32; 1526346981Scy size_t r0_key_data_len = q + 16; 1527189251Ssam 1528189251Ssam /* 1529189251Ssam * R0-Key-Data = KDF-384(XXKey, "FT-R0", 1530189251Ssam * SSIDlength || SSID || MDID || R0KHlength || 1531189251Ssam * R0KH-ID || S0KH-ID) 1532346981Scy * XXKey is either the second 256 bits of MSK or PSK; or the first 1533346981Scy * 384 bits of MSK for FT-EAP-SHA384. 1534346981Scy * PMK-R0 = L(R0-Key-Data, 0, Q) 1535346981Scy * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128) 1536346981Scy * Q = 384 for FT-EAP-SHA384; otherwise, 256 1537189251Ssam */ 1538289549Srpaulo if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) 1539346981Scy return -1; 1540346981Scy wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s", 1541346981Scy use_sha384 ? "SHA384" : "SHA256"); 1542346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len); 1543346981Scy wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len); 1544346981Scy wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN); 1545346981Scy wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len); 1546346981Scy wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id)); 1547189251Ssam pos = buf; 1548189251Ssam *pos++ = ssid_len; 1549189251Ssam os_memcpy(pos, ssid, ssid_len); 1550189251Ssam pos += ssid_len; 1551189251Ssam os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); 1552189251Ssam pos += MOBILITY_DOMAIN_ID_LEN; 1553189251Ssam *pos++ = r0kh_id_len; 1554189251Ssam os_memcpy(pos, r0kh_id, r0kh_id_len); 1555189251Ssam pos += r0kh_id_len; 1556189251Ssam os_memcpy(pos, s0kh_id, ETH_ALEN); 1557189251Ssam pos += ETH_ALEN; 1558189251Ssam 1559346981Scy#ifdef CONFIG_SHA384 1560346981Scy if (use_sha384) { 1561346981Scy if (xxkey_len != SHA384_MAC_LEN) { 1562346981Scy wpa_printf(MSG_ERROR, 1563346981Scy "FT: Unexpected XXKey length %d (expected %d)", 1564346981Scy (int) xxkey_len, SHA384_MAC_LEN); 1565346981Scy return -1; 1566346981Scy } 1567346981Scy if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, 1568346981Scy r0_key_data, r0_key_data_len) < 0) 1569346981Scy return -1; 1570346981Scy } 1571346981Scy#endif /* CONFIG_SHA384 */ 1572346981Scy if (!use_sha384) { 1573346981Scy if (xxkey_len != PMK_LEN) { 1574346981Scy wpa_printf(MSG_ERROR, 1575346981Scy "FT: Unexpected XXKey length %d (expected %d)", 1576346981Scy (int) xxkey_len, PMK_LEN); 1577346981Scy return -1; 1578346981Scy } 1579346981Scy if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, 1580346981Scy r0_key_data, r0_key_data_len) < 0) 1581346981Scy return -1; 1582346981Scy } 1583346981Scy os_memcpy(pmk_r0, r0_key_data, q); 1584346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q); 1585346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16); 1586189251Ssam 1587189251Ssam /* 1588346981Scy * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt) 1589189251Ssam */ 1590189251Ssam addr[0] = (const u8 *) "FT-R0N"; 1591189251Ssam len[0] = 6; 1592346981Scy addr[1] = &r0_key_data[q]; 1593189251Ssam len[1] = 16; 1594189251Ssam 1595346981Scy#ifdef CONFIG_SHA384 1596346981Scy if (use_sha384 && sha384_vector(2, addr, len, hash) < 0) 1597346981Scy return -1; 1598346981Scy#endif /* CONFIG_SHA384 */ 1599346981Scy if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0) 1600346981Scy return -1; 1601189251Ssam os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); 1602346981Scy os_memset(r0_key_data, 0, sizeof(r0_key_data)); 1603346981Scy return 0; 1604189251Ssam} 1605189251Ssam 1606189251Ssam 1607189251Ssam/** 1608189251Ssam * wpa_derive_pmk_r1_name - Derive PMKR1Name 1609189251Ssam * 1610189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4 1611189251Ssam */ 1612346981Scyint wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, 1613346981Scy const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384) 1614189251Ssam{ 1615346981Scy u8 hash[48]; 1616189251Ssam const u8 *addr[4]; 1617189251Ssam size_t len[4]; 1618189251Ssam 1619189251Ssam /* 1620346981Scy * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name || 1621346981Scy * R1KH-ID || S1KH-ID)) 1622189251Ssam */ 1623189251Ssam addr[0] = (const u8 *) "FT-R1N"; 1624189251Ssam len[0] = 6; 1625189251Ssam addr[1] = pmk_r0_name; 1626189251Ssam len[1] = WPA_PMK_NAME_LEN; 1627189251Ssam addr[2] = r1kh_id; 1628189251Ssam len[2] = FT_R1KH_ID_LEN; 1629189251Ssam addr[3] = s1kh_id; 1630189251Ssam len[3] = ETH_ALEN; 1631189251Ssam 1632346981Scy#ifdef CONFIG_SHA384 1633346981Scy if (use_sha384 && sha384_vector(4, addr, len, hash) < 0) 1634346981Scy return -1; 1635346981Scy#endif /* CONFIG_SHA384 */ 1636346981Scy if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0) 1637346981Scy return -1; 1638189251Ssam os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); 1639346981Scy return 0; 1640189251Ssam} 1641189251Ssam 1642189251Ssam 1643189251Ssam/** 1644189251Ssam * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 1645189251Ssam * 1646189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4 1647189251Ssam */ 1648346981Scyint wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len, 1649346981Scy const u8 *pmk_r0_name, 1650346981Scy const u8 *r1kh_id, const u8 *s1kh_id, 1651346981Scy u8 *pmk_r1, u8 *pmk_r1_name) 1652189251Ssam{ 1653189251Ssam u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; 1654189251Ssam u8 *pos; 1655189251Ssam 1656189251Ssam /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ 1657346981Scy wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s", 1658346981Scy pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256"); 1659346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len); 1660346981Scy wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN); 1661346981Scy wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id)); 1662189251Ssam pos = buf; 1663189251Ssam os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); 1664189251Ssam pos += FT_R1KH_ID_LEN; 1665189251Ssam os_memcpy(pos, s1kh_id, ETH_ALEN); 1666189251Ssam pos += ETH_ALEN; 1667189251Ssam 1668346981Scy#ifdef CONFIG_SHA384 1669346981Scy if (pmk_r0_len == SHA384_MAC_LEN && 1670346981Scy sha384_prf(pmk_r0, pmk_r0_len, "FT-R1", 1671346981Scy buf, pos - buf, pmk_r1, pmk_r0_len) < 0) 1672346981Scy return -1; 1673346981Scy#endif /* CONFIG_SHA384 */ 1674346981Scy if (pmk_r0_len == PMK_LEN && 1675346981Scy sha256_prf(pmk_r0, pmk_r0_len, "FT-R1", 1676346981Scy buf, pos - buf, pmk_r1, pmk_r0_len) < 0) 1677346981Scy return -1; 1678346981Scy if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) { 1679346981Scy wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d", 1680346981Scy (int) pmk_r0_len); 1681346981Scy return -1; 1682346981Scy } 1683346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len); 1684189251Ssam 1685346981Scy return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, 1686346981Scy pmk_r1_name, 1687346981Scy pmk_r0_len == SHA384_MAC_LEN); 1688189251Ssam} 1689189251Ssam 1690189251Ssam 1691189251Ssam/** 1692189251Ssam * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 1693189251Ssam * 1694189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.5 1695189251Ssam */ 1696346981Scyint wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, 1697346981Scy const u8 *snonce, const u8 *anonce, 1698281806Srpaulo const u8 *sta_addr, const u8 *bssid, 1699281806Srpaulo const u8 *pmk_r1_name, 1700281806Srpaulo struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher) 1701189251Ssam{ 1702189251Ssam u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; 1703189251Ssam u8 *pos, hash[32]; 1704189251Ssam const u8 *addr[6]; 1705189251Ssam size_t len[6]; 1706346981Scy u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; 1707346981Scy size_t ptk_len, offset; 1708346981Scy int use_sha384 = wpa_key_mgmt_sha384(akmp); 1709189251Ssam 1710189251Ssam /* 1711189251Ssam * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || 1712189251Ssam * BSSID || STA-ADDR) 1713189251Ssam */ 1714346981Scy wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s", 1715346981Scy use_sha384 ? "SHA384" : "SHA256"); 1716346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len); 1717346981Scy wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN); 1718346981Scy wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN); 1719346981Scy wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR, 1720346981Scy MAC2STR(bssid), MAC2STR(sta_addr)); 1721189251Ssam pos = buf; 1722189251Ssam os_memcpy(pos, snonce, WPA_NONCE_LEN); 1723189251Ssam pos += WPA_NONCE_LEN; 1724189251Ssam os_memcpy(pos, anonce, WPA_NONCE_LEN); 1725189251Ssam pos += WPA_NONCE_LEN; 1726189251Ssam os_memcpy(pos, bssid, ETH_ALEN); 1727189251Ssam pos += ETH_ALEN; 1728189251Ssam os_memcpy(pos, sta_addr, ETH_ALEN); 1729189251Ssam pos += ETH_ALEN; 1730189251Ssam 1731346981Scy ptk->kck_len = wpa_kck_len(akmp, PMK_LEN); 1732346981Scy ptk->kck2_len = wpa_kck2_len(akmp); 1733346981Scy ptk->kek_len = wpa_kek_len(akmp, PMK_LEN); 1734346981Scy ptk->kek2_len = wpa_kek2_len(akmp); 1735281806Srpaulo ptk->tk_len = wpa_cipher_key_len(cipher); 1736346981Scy ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + 1737346981Scy ptk->kck2_len + ptk->kek2_len; 1738189251Ssam 1739346981Scy#ifdef CONFIG_SHA384 1740346981Scy if (use_sha384) { 1741346981Scy if (pmk_r1_len != SHA384_MAC_LEN) { 1742346981Scy wpa_printf(MSG_ERROR, 1743346981Scy "FT: Unexpected PMK-R1 length %d (expected %d)", 1744346981Scy (int) pmk_r1_len, SHA384_MAC_LEN); 1745346981Scy return -1; 1746346981Scy } 1747346981Scy if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK", 1748346981Scy buf, pos - buf, tmp, ptk_len) < 0) 1749346981Scy return -1; 1750346981Scy } 1751346981Scy#endif /* CONFIG_SHA384 */ 1752346981Scy if (!use_sha384) { 1753346981Scy if (pmk_r1_len != PMK_LEN) { 1754346981Scy wpa_printf(MSG_ERROR, 1755346981Scy "FT: Unexpected PMK-R1 length %d (expected %d)", 1756346981Scy (int) pmk_r1_len, PMK_LEN); 1757346981Scy return -1; 1758346981Scy } 1759346981Scy if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK", 1760346981Scy buf, pos - buf, tmp, ptk_len) < 0) 1761346981Scy return -1; 1762346981Scy } 1763346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len); 1764281806Srpaulo 1765189251Ssam /* 1766189251Ssam * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || 1767189251Ssam * ANonce || BSSID || STA-ADDR)) 1768189251Ssam */ 1769346981Scy wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN); 1770189251Ssam addr[0] = pmk_r1_name; 1771189251Ssam len[0] = WPA_PMK_NAME_LEN; 1772189251Ssam addr[1] = (const u8 *) "FT-PTKN"; 1773189251Ssam len[1] = 7; 1774189251Ssam addr[2] = snonce; 1775189251Ssam len[2] = WPA_NONCE_LEN; 1776189251Ssam addr[3] = anonce; 1777189251Ssam len[3] = WPA_NONCE_LEN; 1778189251Ssam addr[4] = bssid; 1779189251Ssam len[4] = ETH_ALEN; 1780189251Ssam addr[5] = sta_addr; 1781189251Ssam len[5] = ETH_ALEN; 1782189251Ssam 1783346981Scy if (sha256_vector(6, addr, len, hash) < 0) 1784346981Scy return -1; 1785189251Ssam os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); 1786281806Srpaulo 1787281806Srpaulo os_memcpy(ptk->kck, tmp, ptk->kck_len); 1788346981Scy offset = ptk->kck_len; 1789346981Scy os_memcpy(ptk->kek, tmp + offset, ptk->kek_len); 1790346981Scy offset += ptk->kek_len; 1791346981Scy os_memcpy(ptk->tk, tmp + offset, ptk->tk_len); 1792346981Scy offset += ptk->tk_len; 1793346981Scy os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len); 1794346981Scy offset += ptk->kck2_len; 1795346981Scy os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len); 1796281806Srpaulo 1797281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len); 1798281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len); 1799346981Scy if (ptk->kck2_len) 1800346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: KCK2", 1801346981Scy ptk->kck2, ptk->kck2_len); 1802346981Scy if (ptk->kek2_len) 1803346981Scy wpa_hexdump_key(MSG_DEBUG, "FT: KEK2", 1804346981Scy ptk->kek2, ptk->kek2_len); 1805281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len); 1806281806Srpaulo wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); 1807281806Srpaulo 1808281806Srpaulo os_memset(tmp, 0, sizeof(tmp)); 1809281806Srpaulo 1810281806Srpaulo return 0; 1811189251Ssam} 1812189251Ssam 1813189251Ssam#endif /* CONFIG_IEEE80211R */ 1814214734Srpaulo 1815214734Srpaulo 1816214734Srpaulo/** 1817214734Srpaulo * rsn_pmkid - Calculate PMK identifier 1818214734Srpaulo * @pmk: Pairwise master key 1819214734Srpaulo * @pmk_len: Length of pmk in bytes 1820214734Srpaulo * @aa: Authenticator address 1821214734Srpaulo * @spa: Supplicant address 1822214734Srpaulo * @pmkid: Buffer for PMKID 1823346981Scy * @akmp: Negotiated key management protocol 1824214734Srpaulo * 1825346981Scy * IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy 1826346981Scy * AKM: 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16 1827346981Scy * PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA)) 1828346981Scy * AKM: 00-0F-AC:11 1829346981Scy * See rsn_pmkid_suite_b() 1830346981Scy * AKM: 00-0F-AC:12 1831346981Scy * See rsn_pmkid_suite_b_192() 1832346981Scy * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17 1833346981Scy * PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA)) 1834346981Scy * Otherwise: 1835346981Scy * PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA)) 1836214734Srpaulo */ 1837214734Srpaulovoid rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, 1838346981Scy u8 *pmkid, int akmp) 1839214734Srpaulo{ 1840214734Srpaulo char *title = "PMK Name"; 1841214734Srpaulo const u8 *addr[3]; 1842214734Srpaulo const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 1843346981Scy unsigned char hash[SHA384_MAC_LEN]; 1844214734Srpaulo 1845214734Srpaulo addr[0] = (u8 *) title; 1846214734Srpaulo addr[1] = aa; 1847214734Srpaulo addr[2] = spa; 1848214734Srpaulo 1849346981Scy if (0) { 1850346981Scy#if defined(CONFIG_FILS) || defined(CONFIG_SHA384) 1851346981Scy } else if (wpa_key_mgmt_sha384(akmp)) { 1852346981Scy wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384"); 1853346981Scy hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash); 1854346981Scy#endif /* CONFIG_FILS || CONFIG_SHA384 */ 1855346981Scy#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 1856346981Scy } else if (wpa_key_mgmt_sha256(akmp)) { 1857346981Scy wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256"); 1858214734Srpaulo hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); 1859346981Scy#endif /* CONFIG_IEEE80211W || CONFIG_FILS */ 1860346981Scy } else { 1861346981Scy wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1"); 1862214734Srpaulo hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); 1863346981Scy } 1864346981Scy wpa_hexdump(MSG_DEBUG, "RSN: Derived PMKID", hash, PMKID_LEN); 1865214734Srpaulo os_memcpy(pmkid, hash, PMKID_LEN); 1866214734Srpaulo} 1867214734Srpaulo 1868214734Srpaulo 1869281806Srpaulo#ifdef CONFIG_SUITEB 1870214734Srpaulo/** 1871281806Srpaulo * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM 1872281806Srpaulo * @kck: Key confirmation key 1873281806Srpaulo * @kck_len: Length of kck in bytes 1874281806Srpaulo * @aa: Authenticator address 1875281806Srpaulo * @spa: Supplicant address 1876281806Srpaulo * @pmkid: Buffer for PMKID 1877281806Srpaulo * Returns: 0 on success, -1 on failure 1878281806Srpaulo * 1879281806Srpaulo * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy 1880281806Srpaulo * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA)) 1881281806Srpaulo */ 1882281806Srpauloint rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa, 1883281806Srpaulo const u8 *spa, u8 *pmkid) 1884281806Srpaulo{ 1885281806Srpaulo char *title = "PMK Name"; 1886281806Srpaulo const u8 *addr[3]; 1887281806Srpaulo const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 1888281806Srpaulo unsigned char hash[SHA256_MAC_LEN]; 1889281806Srpaulo 1890281806Srpaulo addr[0] = (u8 *) title; 1891281806Srpaulo addr[1] = aa; 1892281806Srpaulo addr[2] = spa; 1893281806Srpaulo 1894281806Srpaulo if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0) 1895281806Srpaulo return -1; 1896281806Srpaulo os_memcpy(pmkid, hash, PMKID_LEN); 1897281806Srpaulo return 0; 1898281806Srpaulo} 1899281806Srpaulo#endif /* CONFIG_SUITEB */ 1900281806Srpaulo 1901281806Srpaulo 1902281806Srpaulo#ifdef CONFIG_SUITEB192 1903281806Srpaulo/** 1904281806Srpaulo * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM 1905281806Srpaulo * @kck: Key confirmation key 1906281806Srpaulo * @kck_len: Length of kck in bytes 1907281806Srpaulo * @aa: Authenticator address 1908281806Srpaulo * @spa: Supplicant address 1909281806Srpaulo * @pmkid: Buffer for PMKID 1910281806Srpaulo * Returns: 0 on success, -1 on failure 1911281806Srpaulo * 1912281806Srpaulo * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy 1913281806Srpaulo * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA)) 1914281806Srpaulo */ 1915281806Srpauloint rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa, 1916281806Srpaulo const u8 *spa, u8 *pmkid) 1917281806Srpaulo{ 1918281806Srpaulo char *title = "PMK Name"; 1919281806Srpaulo const u8 *addr[3]; 1920281806Srpaulo const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 1921281806Srpaulo unsigned char hash[SHA384_MAC_LEN]; 1922281806Srpaulo 1923281806Srpaulo addr[0] = (u8 *) title; 1924281806Srpaulo addr[1] = aa; 1925281806Srpaulo addr[2] = spa; 1926281806Srpaulo 1927281806Srpaulo if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0) 1928281806Srpaulo return -1; 1929281806Srpaulo os_memcpy(pmkid, hash, PMKID_LEN); 1930281806Srpaulo return 0; 1931281806Srpaulo} 1932281806Srpaulo#endif /* CONFIG_SUITEB192 */ 1933281806Srpaulo 1934281806Srpaulo 1935281806Srpaulo/** 1936214734Srpaulo * wpa_cipher_txt - Convert cipher suite to a text string 1937214734Srpaulo * @cipher: Cipher suite (WPA_CIPHER_* enum) 1938214734Srpaulo * Returns: Pointer to a text string of the cipher suite name 1939214734Srpaulo */ 1940214734Srpauloconst char * wpa_cipher_txt(int cipher) 1941214734Srpaulo{ 1942214734Srpaulo switch (cipher) { 1943214734Srpaulo case WPA_CIPHER_NONE: 1944214734Srpaulo return "NONE"; 1945214734Srpaulo case WPA_CIPHER_WEP40: 1946214734Srpaulo return "WEP-40"; 1947214734Srpaulo case WPA_CIPHER_WEP104: 1948214734Srpaulo return "WEP-104"; 1949214734Srpaulo case WPA_CIPHER_TKIP: 1950214734Srpaulo return "TKIP"; 1951214734Srpaulo case WPA_CIPHER_CCMP: 1952214734Srpaulo return "CCMP"; 1953214734Srpaulo case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: 1954214734Srpaulo return "CCMP+TKIP"; 1955252726Srpaulo case WPA_CIPHER_GCMP: 1956252726Srpaulo return "GCMP"; 1957281806Srpaulo case WPA_CIPHER_GCMP_256: 1958281806Srpaulo return "GCMP-256"; 1959281806Srpaulo case WPA_CIPHER_CCMP_256: 1960281806Srpaulo return "CCMP-256"; 1961346981Scy case WPA_CIPHER_AES_128_CMAC: 1962346981Scy return "BIP"; 1963346981Scy case WPA_CIPHER_BIP_GMAC_128: 1964346981Scy return "BIP-GMAC-128"; 1965346981Scy case WPA_CIPHER_BIP_GMAC_256: 1966346981Scy return "BIP-GMAC-256"; 1967346981Scy case WPA_CIPHER_BIP_CMAC_256: 1968346981Scy return "BIP-CMAC-256"; 1969281806Srpaulo case WPA_CIPHER_GTK_NOT_USED: 1970281806Srpaulo return "GTK_NOT_USED"; 1971214734Srpaulo default: 1972214734Srpaulo return "UNKNOWN"; 1973214734Srpaulo } 1974214734Srpaulo} 1975214734Srpaulo 1976214734Srpaulo 1977214734Srpaulo/** 1978214734Srpaulo * wpa_key_mgmt_txt - Convert key management suite to a text string 1979214734Srpaulo * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) 1980214734Srpaulo * @proto: WPA/WPA2 version (WPA_PROTO_*) 1981214734Srpaulo * Returns: Pointer to a text string of the key management suite name 1982214734Srpaulo */ 1983214734Srpauloconst char * wpa_key_mgmt_txt(int key_mgmt, int proto) 1984214734Srpaulo{ 1985214734Srpaulo switch (key_mgmt) { 1986214734Srpaulo case WPA_KEY_MGMT_IEEE8021X: 1987214734Srpaulo if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 1988214734Srpaulo return "WPA2+WPA/IEEE 802.1X/EAP"; 1989214734Srpaulo return proto == WPA_PROTO_RSN ? 1990214734Srpaulo "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; 1991214734Srpaulo case WPA_KEY_MGMT_PSK: 1992214734Srpaulo if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) 1993214734Srpaulo return "WPA2-PSK+WPA-PSK"; 1994214734Srpaulo return proto == WPA_PROTO_RSN ? 1995214734Srpaulo "WPA2-PSK" : "WPA-PSK"; 1996214734Srpaulo case WPA_KEY_MGMT_NONE: 1997214734Srpaulo return "NONE"; 1998337817Scy case WPA_KEY_MGMT_WPA_NONE: 1999337817Scy return "WPA-NONE"; 2000214734Srpaulo case WPA_KEY_MGMT_IEEE8021X_NO_WPA: 2001214734Srpaulo return "IEEE 802.1X (no WPA)"; 2002214734Srpaulo#ifdef CONFIG_IEEE80211R 2003214734Srpaulo case WPA_KEY_MGMT_FT_IEEE8021X: 2004214734Srpaulo return "FT-EAP"; 2005346981Scy case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: 2006346981Scy return "FT-EAP-SHA384"; 2007214734Srpaulo case WPA_KEY_MGMT_FT_PSK: 2008214734Srpaulo return "FT-PSK"; 2009214734Srpaulo#endif /* CONFIG_IEEE80211R */ 2010214734Srpaulo#ifdef CONFIG_IEEE80211W 2011214734Srpaulo case WPA_KEY_MGMT_IEEE8021X_SHA256: 2012214734Srpaulo return "WPA2-EAP-SHA256"; 2013214734Srpaulo case WPA_KEY_MGMT_PSK_SHA256: 2014214734Srpaulo return "WPA2-PSK-SHA256"; 2015214734Srpaulo#endif /* CONFIG_IEEE80211W */ 2016281806Srpaulo case WPA_KEY_MGMT_WPS: 2017281806Srpaulo return "WPS"; 2018281806Srpaulo case WPA_KEY_MGMT_SAE: 2019281806Srpaulo return "SAE"; 2020281806Srpaulo case WPA_KEY_MGMT_FT_SAE: 2021281806Srpaulo return "FT-SAE"; 2022281806Srpaulo case WPA_KEY_MGMT_OSEN: 2023281806Srpaulo return "OSEN"; 2024281806Srpaulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B: 2025281806Srpaulo return "WPA2-EAP-SUITE-B"; 2026281806Srpaulo case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: 2027281806Srpaulo return "WPA2-EAP-SUITE-B-192"; 2028346981Scy case WPA_KEY_MGMT_FILS_SHA256: 2029346981Scy return "FILS-SHA256"; 2030346981Scy case WPA_KEY_MGMT_FILS_SHA384: 2031346981Scy return "FILS-SHA384"; 2032346981Scy case WPA_KEY_MGMT_FT_FILS_SHA256: 2033346981Scy return "FT-FILS-SHA256"; 2034346981Scy case WPA_KEY_MGMT_FT_FILS_SHA384: 2035346981Scy return "FT-FILS-SHA384"; 2036346981Scy case WPA_KEY_MGMT_OWE: 2037346981Scy return "OWE"; 2038346981Scy case WPA_KEY_MGMT_DPP: 2039346981Scy return "DPP"; 2040214734Srpaulo default: 2041214734Srpaulo return "UNKNOWN"; 2042214734Srpaulo } 2043214734Srpaulo} 2044214734Srpaulo 2045214734Srpaulo 2046281806Srpaulou32 wpa_akm_to_suite(int akm) 2047281806Srpaulo{ 2048346981Scy if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) 2049346981Scy return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; 2050281806Srpaulo if (akm & WPA_KEY_MGMT_FT_IEEE8021X) 2051346981Scy return RSN_AUTH_KEY_MGMT_FT_802_1X; 2052281806Srpaulo if (akm & WPA_KEY_MGMT_FT_PSK) 2053346981Scy return RSN_AUTH_KEY_MGMT_FT_PSK; 2054281806Srpaulo if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256) 2055346981Scy return RSN_AUTH_KEY_MGMT_802_1X_SHA256; 2056281806Srpaulo if (akm & WPA_KEY_MGMT_IEEE8021X) 2057346981Scy return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; 2058281806Srpaulo if (akm & WPA_KEY_MGMT_PSK_SHA256) 2059346981Scy return RSN_AUTH_KEY_MGMT_PSK_SHA256; 2060281806Srpaulo if (akm & WPA_KEY_MGMT_PSK) 2061346981Scy return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; 2062281806Srpaulo if (akm & WPA_KEY_MGMT_CCKM) 2063346981Scy return RSN_AUTH_KEY_MGMT_CCKM; 2064281806Srpaulo if (akm & WPA_KEY_MGMT_OSEN) 2065346981Scy return RSN_AUTH_KEY_MGMT_OSEN; 2066281806Srpaulo if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B) 2067346981Scy return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; 2068281806Srpaulo if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) 2069346981Scy return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; 2070346981Scy if (akm & WPA_KEY_MGMT_FILS_SHA256) 2071346981Scy return RSN_AUTH_KEY_MGMT_FILS_SHA256; 2072346981Scy if (akm & WPA_KEY_MGMT_FILS_SHA384) 2073346981Scy return RSN_AUTH_KEY_MGMT_FILS_SHA384; 2074346981Scy if (akm & WPA_KEY_MGMT_FT_FILS_SHA256) 2075346981Scy return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; 2076346981Scy if (akm & WPA_KEY_MGMT_FT_FILS_SHA384) 2077346981Scy return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; 2078351611Scy if (akm & WPA_KEY_MGMT_SAE) 2079351611Scy return RSN_AUTH_KEY_MGMT_SAE; 2080351611Scy if (akm & WPA_KEY_MGMT_FT_SAE) 2081351611Scy return RSN_AUTH_KEY_MGMT_FT_SAE; 2082351611Scy if (akm & WPA_KEY_MGMT_OWE) 2083351611Scy return RSN_AUTH_KEY_MGMT_OWE; 2084351611Scy if (akm & WPA_KEY_MGMT_DPP) 2085351611Scy return RSN_AUTH_KEY_MGMT_DPP; 2086351611Scy if (akm & WPA_KEY_MGMT_OSEN) 2087351611Scy return RSN_AUTH_KEY_MGMT_OSEN; 2088281806Srpaulo return 0; 2089281806Srpaulo} 2090281806Srpaulo 2091281806Srpaulo 2092214734Srpauloint wpa_compare_rsn_ie(int ft_initial_assoc, 2093214734Srpaulo const u8 *ie1, size_t ie1len, 2094214734Srpaulo const u8 *ie2, size_t ie2len) 2095214734Srpaulo{ 2096214734Srpaulo if (ie1 == NULL || ie2 == NULL) 2097214734Srpaulo return -1; 2098214734Srpaulo 2099214734Srpaulo if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) 2100214734Srpaulo return 0; /* identical IEs */ 2101214734Srpaulo 2102214734Srpaulo#ifdef CONFIG_IEEE80211R 2103214734Srpaulo if (ft_initial_assoc) { 2104214734Srpaulo struct wpa_ie_data ie1d, ie2d; 2105214734Srpaulo /* 2106214734Srpaulo * The PMKID-List in RSN IE is different between Beacon/Probe 2107214734Srpaulo * Response/(Re)Association Request frames and EAPOL-Key 2108214734Srpaulo * messages in FT initial mobility domain association. Allow 2109214734Srpaulo * for this, but verify that other parts of the RSN IEs are 2110214734Srpaulo * identical. 2111214734Srpaulo */ 2112214734Srpaulo if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || 2113214734Srpaulo wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) 2114214734Srpaulo return -1; 2115214734Srpaulo if (ie1d.proto == ie2d.proto && 2116214734Srpaulo ie1d.pairwise_cipher == ie2d.pairwise_cipher && 2117214734Srpaulo ie1d.group_cipher == ie2d.group_cipher && 2118214734Srpaulo ie1d.key_mgmt == ie2d.key_mgmt && 2119214734Srpaulo ie1d.capabilities == ie2d.capabilities && 2120214734Srpaulo ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) 2121214734Srpaulo return 0; 2122214734Srpaulo } 2123214734Srpaulo#endif /* CONFIG_IEEE80211R */ 2124214734Srpaulo 2125214734Srpaulo return -1; 2126214734Srpaulo} 2127214734Srpaulo 2128214734Srpaulo 2129346981Scy#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) 2130337817Scyint wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid) 2131214734Srpaulo{ 2132214734Srpaulo u8 *start, *end, *rpos, *rend; 2133214734Srpaulo int added = 0; 2134214734Srpaulo 2135214734Srpaulo start = ies; 2136337817Scy end = ies + *ies_len; 2137214734Srpaulo 2138214734Srpaulo while (start < end) { 2139214734Srpaulo if (*start == WLAN_EID_RSN) 2140214734Srpaulo break; 2141214734Srpaulo start += 2 + start[1]; 2142214734Srpaulo } 2143214734Srpaulo if (start >= end) { 2144214734Srpaulo wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " 2145214734Srpaulo "IEs data"); 2146214734Srpaulo return -1; 2147214734Srpaulo } 2148214734Srpaulo wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", 2149214734Srpaulo start, 2 + start[1]); 2150214734Srpaulo 2151214734Srpaulo /* Find start of PMKID-Count */ 2152214734Srpaulo rpos = start + 2; 2153214734Srpaulo rend = rpos + start[1]; 2154214734Srpaulo 2155214734Srpaulo /* Skip Version and Group Data Cipher Suite */ 2156214734Srpaulo rpos += 2 + 4; 2157214734Srpaulo /* Skip Pairwise Cipher Suite Count and List */ 2158214734Srpaulo rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 2159214734Srpaulo /* Skip AKM Suite Count and List */ 2160214734Srpaulo rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; 2161214734Srpaulo 2162214734Srpaulo if (rpos == rend) { 2163214734Srpaulo /* Add RSN Capabilities */ 2164214734Srpaulo os_memmove(rpos + 2, rpos, end - rpos); 2165214734Srpaulo *rpos++ = 0; 2166214734Srpaulo *rpos++ = 0; 2167289549Srpaulo added += 2; 2168289549Srpaulo start[1] += 2; 2169289549Srpaulo rend = rpos; 2170214734Srpaulo } else { 2171214734Srpaulo /* Skip RSN Capabilities */ 2172214734Srpaulo rpos += 2; 2173214734Srpaulo if (rpos > rend) { 2174214734Srpaulo wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " 2175214734Srpaulo "IEs data"); 2176214734Srpaulo return -1; 2177214734Srpaulo } 2178214734Srpaulo } 2179214734Srpaulo 2180214734Srpaulo if (rpos == rend) { 2181214734Srpaulo /* No PMKID-Count field included; add it */ 2182289549Srpaulo os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos); 2183214734Srpaulo WPA_PUT_LE16(rpos, 1); 2184214734Srpaulo rpos += 2; 2185214734Srpaulo os_memcpy(rpos, pmkid, PMKID_LEN); 2186214734Srpaulo added += 2 + PMKID_LEN; 2187214734Srpaulo start[1] += 2 + PMKID_LEN; 2188214734Srpaulo } else { 2189337817Scy u16 num_pmkid; 2190337817Scy 2191337817Scy if (rend - rpos < 2) 2192337817Scy return -1; 2193337817Scy num_pmkid = WPA_GET_LE16(rpos); 2194214734Srpaulo /* PMKID-Count was included; use it */ 2195337817Scy if (num_pmkid != 0) { 2196337817Scy u8 *after; 2197337817Scy 2198337817Scy if (num_pmkid * PMKID_LEN > rend - rpos - 2) 2199337817Scy return -1; 2200337817Scy /* 2201337817Scy * PMKID may have been included in RSN IE in 2202337817Scy * (Re)Association Request frame, so remove the old 2203337817Scy * PMKID(s) first before adding the new one. 2204337817Scy */ 2205337817Scy wpa_printf(MSG_DEBUG, 2206337817Scy "FT: Remove %u old PMKID(s) from RSN IE", 2207337817Scy num_pmkid); 2208337817Scy after = rpos + 2 + num_pmkid * PMKID_LEN; 2209337817Scy os_memmove(rpos + 2, after, rend - after); 2210337817Scy start[1] -= num_pmkid * PMKID_LEN; 2211337817Scy added -= num_pmkid * PMKID_LEN; 2212214734Srpaulo } 2213214734Srpaulo WPA_PUT_LE16(rpos, 1); 2214214734Srpaulo rpos += 2; 2215289549Srpaulo os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos); 2216214734Srpaulo os_memcpy(rpos, pmkid, PMKID_LEN); 2217214734Srpaulo added += PMKID_LEN; 2218214734Srpaulo start[1] += PMKID_LEN; 2219214734Srpaulo } 2220214734Srpaulo 2221214734Srpaulo wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " 2222214734Srpaulo "(PMKID inserted)", start, 2 + start[1]); 2223214734Srpaulo 2224337817Scy *ies_len += added; 2225337817Scy 2226337817Scy return 0; 2227214734Srpaulo} 2228346981Scy#endif /* CONFIG_IEEE80211R || CONFIG_FILS */ 2229252726Srpaulo 2230252726Srpaulo 2231252726Srpauloint wpa_cipher_key_len(int cipher) 2232252726Srpaulo{ 2233252726Srpaulo switch (cipher) { 2234281806Srpaulo case WPA_CIPHER_CCMP_256: 2235281806Srpaulo case WPA_CIPHER_GCMP_256: 2236281806Srpaulo case WPA_CIPHER_BIP_GMAC_256: 2237281806Srpaulo case WPA_CIPHER_BIP_CMAC_256: 2238281806Srpaulo return 32; 2239252726Srpaulo case WPA_CIPHER_CCMP: 2240252726Srpaulo case WPA_CIPHER_GCMP: 2241281806Srpaulo case WPA_CIPHER_AES_128_CMAC: 2242281806Srpaulo case WPA_CIPHER_BIP_GMAC_128: 2243252726Srpaulo return 16; 2244252726Srpaulo case WPA_CIPHER_TKIP: 2245252726Srpaulo return 32; 2246252726Srpaulo } 2247252726Srpaulo 2248252726Srpaulo return 0; 2249252726Srpaulo} 2250252726Srpaulo 2251252726Srpaulo 2252252726Srpauloint wpa_cipher_rsc_len(int cipher) 2253252726Srpaulo{ 2254252726Srpaulo switch (cipher) { 2255281806Srpaulo case WPA_CIPHER_CCMP_256: 2256281806Srpaulo case WPA_CIPHER_GCMP_256: 2257252726Srpaulo case WPA_CIPHER_CCMP: 2258252726Srpaulo case WPA_CIPHER_GCMP: 2259252726Srpaulo case WPA_CIPHER_TKIP: 2260252726Srpaulo return 6; 2261252726Srpaulo } 2262252726Srpaulo 2263252726Srpaulo return 0; 2264252726Srpaulo} 2265252726Srpaulo 2266252726Srpaulo 2267346981Scyenum wpa_alg wpa_cipher_to_alg(int cipher) 2268252726Srpaulo{ 2269252726Srpaulo switch (cipher) { 2270281806Srpaulo case WPA_CIPHER_CCMP_256: 2271281806Srpaulo return WPA_ALG_CCMP_256; 2272281806Srpaulo case WPA_CIPHER_GCMP_256: 2273281806Srpaulo return WPA_ALG_GCMP_256; 2274252726Srpaulo case WPA_CIPHER_CCMP: 2275252726Srpaulo return WPA_ALG_CCMP; 2276252726Srpaulo case WPA_CIPHER_GCMP: 2277252726Srpaulo return WPA_ALG_GCMP; 2278252726Srpaulo case WPA_CIPHER_TKIP: 2279252726Srpaulo return WPA_ALG_TKIP; 2280281806Srpaulo case WPA_CIPHER_AES_128_CMAC: 2281281806Srpaulo return WPA_ALG_IGTK; 2282281806Srpaulo case WPA_CIPHER_BIP_GMAC_128: 2283281806Srpaulo return WPA_ALG_BIP_GMAC_128; 2284281806Srpaulo case WPA_CIPHER_BIP_GMAC_256: 2285281806Srpaulo return WPA_ALG_BIP_GMAC_256; 2286281806Srpaulo case WPA_CIPHER_BIP_CMAC_256: 2287281806Srpaulo return WPA_ALG_BIP_CMAC_256; 2288252726Srpaulo } 2289252726Srpaulo return WPA_ALG_NONE; 2290252726Srpaulo} 2291252726Srpaulo 2292252726Srpaulo 2293252726Srpauloint wpa_cipher_valid_pairwise(int cipher) 2294252726Srpaulo{ 2295281806Srpaulo return cipher == WPA_CIPHER_CCMP_256 || 2296281806Srpaulo cipher == WPA_CIPHER_GCMP_256 || 2297281806Srpaulo cipher == WPA_CIPHER_CCMP || 2298252726Srpaulo cipher == WPA_CIPHER_GCMP || 2299252726Srpaulo cipher == WPA_CIPHER_TKIP; 2300252726Srpaulo} 2301252726Srpaulo 2302252726Srpaulo 2303252726Srpaulou32 wpa_cipher_to_suite(int proto, int cipher) 2304252726Srpaulo{ 2305281806Srpaulo if (cipher & WPA_CIPHER_CCMP_256) 2306281806Srpaulo return RSN_CIPHER_SUITE_CCMP_256; 2307281806Srpaulo if (cipher & WPA_CIPHER_GCMP_256) 2308281806Srpaulo return RSN_CIPHER_SUITE_GCMP_256; 2309252726Srpaulo if (cipher & WPA_CIPHER_CCMP) 2310252726Srpaulo return (proto == WPA_PROTO_RSN ? 2311252726Srpaulo RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); 2312252726Srpaulo if (cipher & WPA_CIPHER_GCMP) 2313252726Srpaulo return RSN_CIPHER_SUITE_GCMP; 2314252726Srpaulo if (cipher & WPA_CIPHER_TKIP) 2315252726Srpaulo return (proto == WPA_PROTO_RSN ? 2316252726Srpaulo RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); 2317252726Srpaulo if (cipher & WPA_CIPHER_NONE) 2318252726Srpaulo return (proto == WPA_PROTO_RSN ? 2319252726Srpaulo RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); 2320281806Srpaulo if (cipher & WPA_CIPHER_GTK_NOT_USED) 2321281806Srpaulo return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; 2322281806Srpaulo if (cipher & WPA_CIPHER_AES_128_CMAC) 2323281806Srpaulo return RSN_CIPHER_SUITE_AES_128_CMAC; 2324281806Srpaulo if (cipher & WPA_CIPHER_BIP_GMAC_128) 2325281806Srpaulo return RSN_CIPHER_SUITE_BIP_GMAC_128; 2326281806Srpaulo if (cipher & WPA_CIPHER_BIP_GMAC_256) 2327281806Srpaulo return RSN_CIPHER_SUITE_BIP_GMAC_256; 2328281806Srpaulo if (cipher & WPA_CIPHER_BIP_CMAC_256) 2329281806Srpaulo return RSN_CIPHER_SUITE_BIP_CMAC_256; 2330252726Srpaulo return 0; 2331252726Srpaulo} 2332252726Srpaulo 2333252726Srpaulo 2334281806Srpauloint rsn_cipher_put_suites(u8 *start, int ciphers) 2335252726Srpaulo{ 2336281806Srpaulo u8 *pos = start; 2337252726Srpaulo 2338281806Srpaulo if (ciphers & WPA_CIPHER_CCMP_256) { 2339281806Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256); 2340281806Srpaulo pos += RSN_SELECTOR_LEN; 2341281806Srpaulo } 2342281806Srpaulo if (ciphers & WPA_CIPHER_GCMP_256) { 2343281806Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256); 2344281806Srpaulo pos += RSN_SELECTOR_LEN; 2345281806Srpaulo } 2346252726Srpaulo if (ciphers & WPA_CIPHER_CCMP) { 2347252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 2348252726Srpaulo pos += RSN_SELECTOR_LEN; 2349252726Srpaulo } 2350252726Srpaulo if (ciphers & WPA_CIPHER_GCMP) { 2351252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); 2352252726Srpaulo pos += RSN_SELECTOR_LEN; 2353252726Srpaulo } 2354252726Srpaulo if (ciphers & WPA_CIPHER_TKIP) { 2355252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 2356252726Srpaulo pos += RSN_SELECTOR_LEN; 2357252726Srpaulo } 2358252726Srpaulo if (ciphers & WPA_CIPHER_NONE) { 2359252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); 2360252726Srpaulo pos += RSN_SELECTOR_LEN; 2361252726Srpaulo } 2362252726Srpaulo 2363281806Srpaulo return (pos - start) / RSN_SELECTOR_LEN; 2364252726Srpaulo} 2365252726Srpaulo 2366252726Srpaulo 2367281806Srpauloint wpa_cipher_put_suites(u8 *start, int ciphers) 2368252726Srpaulo{ 2369281806Srpaulo u8 *pos = start; 2370252726Srpaulo 2371252726Srpaulo if (ciphers & WPA_CIPHER_CCMP) { 2372252726Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 2373252726Srpaulo pos += WPA_SELECTOR_LEN; 2374252726Srpaulo } 2375252726Srpaulo if (ciphers & WPA_CIPHER_TKIP) { 2376252726Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 2377252726Srpaulo pos += WPA_SELECTOR_LEN; 2378252726Srpaulo } 2379252726Srpaulo if (ciphers & WPA_CIPHER_NONE) { 2380252726Srpaulo RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); 2381252726Srpaulo pos += WPA_SELECTOR_LEN; 2382252726Srpaulo } 2383252726Srpaulo 2384281806Srpaulo return (pos - start) / RSN_SELECTOR_LEN; 2385252726Srpaulo} 2386281806Srpaulo 2387281806Srpaulo 2388281806Srpauloint wpa_pick_pairwise_cipher(int ciphers, int none_allowed) 2389281806Srpaulo{ 2390281806Srpaulo if (ciphers & WPA_CIPHER_CCMP_256) 2391281806Srpaulo return WPA_CIPHER_CCMP_256; 2392281806Srpaulo if (ciphers & WPA_CIPHER_GCMP_256) 2393281806Srpaulo return WPA_CIPHER_GCMP_256; 2394281806Srpaulo if (ciphers & WPA_CIPHER_CCMP) 2395281806Srpaulo return WPA_CIPHER_CCMP; 2396281806Srpaulo if (ciphers & WPA_CIPHER_GCMP) 2397281806Srpaulo return WPA_CIPHER_GCMP; 2398281806Srpaulo if (ciphers & WPA_CIPHER_TKIP) 2399281806Srpaulo return WPA_CIPHER_TKIP; 2400281806Srpaulo if (none_allowed && (ciphers & WPA_CIPHER_NONE)) 2401281806Srpaulo return WPA_CIPHER_NONE; 2402281806Srpaulo return -1; 2403281806Srpaulo} 2404281806Srpaulo 2405281806Srpaulo 2406281806Srpauloint wpa_pick_group_cipher(int ciphers) 2407281806Srpaulo{ 2408281806Srpaulo if (ciphers & WPA_CIPHER_CCMP_256) 2409281806Srpaulo return WPA_CIPHER_CCMP_256; 2410281806Srpaulo if (ciphers & WPA_CIPHER_GCMP_256) 2411281806Srpaulo return WPA_CIPHER_GCMP_256; 2412281806Srpaulo if (ciphers & WPA_CIPHER_CCMP) 2413281806Srpaulo return WPA_CIPHER_CCMP; 2414281806Srpaulo if (ciphers & WPA_CIPHER_GCMP) 2415281806Srpaulo return WPA_CIPHER_GCMP; 2416281806Srpaulo if (ciphers & WPA_CIPHER_GTK_NOT_USED) 2417281806Srpaulo return WPA_CIPHER_GTK_NOT_USED; 2418281806Srpaulo if (ciphers & WPA_CIPHER_TKIP) 2419281806Srpaulo return WPA_CIPHER_TKIP; 2420281806Srpaulo return -1; 2421281806Srpaulo} 2422281806Srpaulo 2423281806Srpaulo 2424281806Srpauloint wpa_parse_cipher(const char *value) 2425281806Srpaulo{ 2426281806Srpaulo int val = 0, last; 2427281806Srpaulo char *start, *end, *buf; 2428281806Srpaulo 2429281806Srpaulo buf = os_strdup(value); 2430281806Srpaulo if (buf == NULL) 2431281806Srpaulo return -1; 2432281806Srpaulo start = buf; 2433281806Srpaulo 2434281806Srpaulo while (*start != '\0') { 2435281806Srpaulo while (*start == ' ' || *start == '\t') 2436281806Srpaulo start++; 2437281806Srpaulo if (*start == '\0') 2438281806Srpaulo break; 2439281806Srpaulo end = start; 2440281806Srpaulo while (*end != ' ' && *end != '\t' && *end != '\0') 2441281806Srpaulo end++; 2442281806Srpaulo last = *end == '\0'; 2443281806Srpaulo *end = '\0'; 2444281806Srpaulo if (os_strcmp(start, "CCMP-256") == 0) 2445281806Srpaulo val |= WPA_CIPHER_CCMP_256; 2446281806Srpaulo else if (os_strcmp(start, "GCMP-256") == 0) 2447281806Srpaulo val |= WPA_CIPHER_GCMP_256; 2448281806Srpaulo else if (os_strcmp(start, "CCMP") == 0) 2449281806Srpaulo val |= WPA_CIPHER_CCMP; 2450281806Srpaulo else if (os_strcmp(start, "GCMP") == 0) 2451281806Srpaulo val |= WPA_CIPHER_GCMP; 2452281806Srpaulo else if (os_strcmp(start, "TKIP") == 0) 2453281806Srpaulo val |= WPA_CIPHER_TKIP; 2454281806Srpaulo else if (os_strcmp(start, "WEP104") == 0) 2455281806Srpaulo val |= WPA_CIPHER_WEP104; 2456281806Srpaulo else if (os_strcmp(start, "WEP40") == 0) 2457281806Srpaulo val |= WPA_CIPHER_WEP40; 2458281806Srpaulo else if (os_strcmp(start, "NONE") == 0) 2459281806Srpaulo val |= WPA_CIPHER_NONE; 2460281806Srpaulo else if (os_strcmp(start, "GTK_NOT_USED") == 0) 2461281806Srpaulo val |= WPA_CIPHER_GTK_NOT_USED; 2462346981Scy else if (os_strcmp(start, "AES-128-CMAC") == 0) 2463346981Scy val |= WPA_CIPHER_AES_128_CMAC; 2464346981Scy else if (os_strcmp(start, "BIP-GMAC-128") == 0) 2465346981Scy val |= WPA_CIPHER_BIP_GMAC_128; 2466346981Scy else if (os_strcmp(start, "BIP-GMAC-256") == 0) 2467346981Scy val |= WPA_CIPHER_BIP_GMAC_256; 2468346981Scy else if (os_strcmp(start, "BIP-CMAC-256") == 0) 2469346981Scy val |= WPA_CIPHER_BIP_CMAC_256; 2470281806Srpaulo else { 2471281806Srpaulo os_free(buf); 2472281806Srpaulo return -1; 2473281806Srpaulo } 2474281806Srpaulo 2475281806Srpaulo if (last) 2476281806Srpaulo break; 2477281806Srpaulo start = end + 1; 2478281806Srpaulo } 2479281806Srpaulo os_free(buf); 2480281806Srpaulo 2481281806Srpaulo return val; 2482281806Srpaulo} 2483281806Srpaulo 2484281806Srpaulo 2485281806Srpauloint wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) 2486281806Srpaulo{ 2487281806Srpaulo char *pos = start; 2488281806Srpaulo int ret; 2489281806Srpaulo 2490281806Srpaulo if (ciphers & WPA_CIPHER_CCMP_256) { 2491281806Srpaulo ret = os_snprintf(pos, end - pos, "%sCCMP-256", 2492281806Srpaulo pos == start ? "" : delim); 2493281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2494281806Srpaulo return -1; 2495281806Srpaulo pos += ret; 2496281806Srpaulo } 2497281806Srpaulo if (ciphers & WPA_CIPHER_GCMP_256) { 2498281806Srpaulo ret = os_snprintf(pos, end - pos, "%sGCMP-256", 2499281806Srpaulo pos == start ? "" : delim); 2500281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2501281806Srpaulo return -1; 2502281806Srpaulo pos += ret; 2503281806Srpaulo } 2504281806Srpaulo if (ciphers & WPA_CIPHER_CCMP) { 2505281806Srpaulo ret = os_snprintf(pos, end - pos, "%sCCMP", 2506281806Srpaulo pos == start ? "" : delim); 2507281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2508281806Srpaulo return -1; 2509281806Srpaulo pos += ret; 2510281806Srpaulo } 2511281806Srpaulo if (ciphers & WPA_CIPHER_GCMP) { 2512281806Srpaulo ret = os_snprintf(pos, end - pos, "%sGCMP", 2513281806Srpaulo pos == start ? "" : delim); 2514281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2515281806Srpaulo return -1; 2516281806Srpaulo pos += ret; 2517281806Srpaulo } 2518281806Srpaulo if (ciphers & WPA_CIPHER_TKIP) { 2519281806Srpaulo ret = os_snprintf(pos, end - pos, "%sTKIP", 2520281806Srpaulo pos == start ? "" : delim); 2521281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2522281806Srpaulo return -1; 2523281806Srpaulo pos += ret; 2524281806Srpaulo } 2525346981Scy if (ciphers & WPA_CIPHER_AES_128_CMAC) { 2526346981Scy ret = os_snprintf(pos, end - pos, "%sAES-128-CMAC", 2527346981Scy pos == start ? "" : delim); 2528346981Scy if (os_snprintf_error(end - pos, ret)) 2529346981Scy return -1; 2530346981Scy pos += ret; 2531346981Scy } 2532346981Scy if (ciphers & WPA_CIPHER_BIP_GMAC_128) { 2533346981Scy ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-128", 2534346981Scy pos == start ? "" : delim); 2535346981Scy if (os_snprintf_error(end - pos, ret)) 2536346981Scy return -1; 2537346981Scy pos += ret; 2538346981Scy } 2539346981Scy if (ciphers & WPA_CIPHER_BIP_GMAC_256) { 2540346981Scy ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-256", 2541346981Scy pos == start ? "" : delim); 2542346981Scy if (os_snprintf_error(end - pos, ret)) 2543346981Scy return -1; 2544346981Scy pos += ret; 2545346981Scy } 2546346981Scy if (ciphers & WPA_CIPHER_BIP_CMAC_256) { 2547346981Scy ret = os_snprintf(pos, end - pos, "%sBIP-CMAC-256", 2548346981Scy pos == start ? "" : delim); 2549346981Scy if (os_snprintf_error(end - pos, ret)) 2550346981Scy return -1; 2551346981Scy pos += ret; 2552346981Scy } 2553281806Srpaulo if (ciphers & WPA_CIPHER_NONE) { 2554281806Srpaulo ret = os_snprintf(pos, end - pos, "%sNONE", 2555281806Srpaulo pos == start ? "" : delim); 2556281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2557281806Srpaulo return -1; 2558281806Srpaulo pos += ret; 2559281806Srpaulo } 2560281806Srpaulo 2561281806Srpaulo return pos - start; 2562281806Srpaulo} 2563281806Srpaulo 2564281806Srpaulo 2565281806Srpauloint wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise) 2566281806Srpaulo{ 2567281806Srpaulo int pairwise = 0; 2568281806Srpaulo 2569281806Srpaulo /* Select group cipher based on the enabled pairwise cipher suites */ 2570281806Srpaulo if (wpa & 1) 2571281806Srpaulo pairwise |= wpa_pairwise; 2572281806Srpaulo if (wpa & 2) 2573281806Srpaulo pairwise |= rsn_pairwise; 2574281806Srpaulo 2575281806Srpaulo if (pairwise & WPA_CIPHER_TKIP) 2576281806Srpaulo return WPA_CIPHER_TKIP; 2577281806Srpaulo if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP) 2578281806Srpaulo return WPA_CIPHER_GCMP; 2579281806Srpaulo if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP | 2580281806Srpaulo WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256) 2581281806Srpaulo return WPA_CIPHER_GCMP_256; 2582281806Srpaulo if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP | 2583281806Srpaulo WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256) 2584281806Srpaulo return WPA_CIPHER_CCMP_256; 2585281806Srpaulo return WPA_CIPHER_CCMP; 2586281806Srpaulo} 2587346981Scy 2588346981Scy 2589346981Scy#ifdef CONFIG_FILS 2590346981Scyint fils_domain_name_hash(const char *domain, u8 *hash) 2591346981Scy{ 2592346981Scy char buf[255], *wpos = buf; 2593346981Scy const char *pos = domain; 2594346981Scy size_t len; 2595346981Scy const u8 *addr[1]; 2596346981Scy u8 mac[SHA256_MAC_LEN]; 2597346981Scy 2598346981Scy for (len = 0; len < sizeof(buf) && *pos; len++) { 2599346981Scy if (isalpha(*pos) && isupper(*pos)) 2600346981Scy *wpos++ = tolower(*pos); 2601346981Scy else 2602346981Scy *wpos++ = *pos; 2603346981Scy pos++; 2604346981Scy } 2605346981Scy 2606346981Scy addr[0] = (const u8 *) buf; 2607346981Scy if (sha256_vector(1, addr, &len, mac) < 0) 2608346981Scy return -1; 2609346981Scy os_memcpy(hash, mac, 2); 2610346981Scy return 0; 2611346981Scy} 2612346981Scy#endif /* CONFIG_FILS */ 2613