18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA/RSN - Shared functions for supplicant and authenticator
3807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/md5.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha256.h"
15807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt#include "crypto/sha384.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11_defs.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "defs.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_common.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtstatic unsigned int wpa_kck_len(int akmp)
24807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt{
25807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
26807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return 24;
27807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	return 16;
28807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt}
29807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
30807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
31807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtstatic unsigned int wpa_kek_len(int akmp)
32807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt{
33807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
34807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return 32;
35807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	return 16;
36807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt}
37807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
38807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
39807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtunsigned int wpa_mic_len(int akmp)
40807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt{
41807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
42807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return 24;
43807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	return 16;
44807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt}
45807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
46807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key: EAPOL-Key Key Confirmation Key (KCK)
50807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @key_len: KCK length in octets
516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @akmp: WPA_KEY_MGMT_* used in key derivation
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Pointer to the beginning of the EAPOL header (version field)
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to be cleared (all zeroes) when calling this function.
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * description of the Key MIC calculation. It includes packet data from the
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * happened during final editing of the standard and the correct behavior is
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * defined in the last draft (IEEE 802.11i/D10).
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
67807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtint wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
68807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		      const u8 *buf, size_t len, u8 *mic)
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
70807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	u8 hash[SHA384_MAC_LEN];
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (ver) {
7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifndef CONFIG_FIPS
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
75807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return hmac_md5(key, key_len, buf, len, mic);
7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_FIPS */
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
78807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		if (hmac_sha1(key, key_len, buf, len, hash))
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(mic, hash, MD5_MAC_LEN);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return omac1_aes_128(key, buf, len, mic);
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
86f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case WPA_KEY_INFO_TYPE_AKM_DEFINED:
876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		switch (akmp) {
886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_HS20
896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		case WPA_KEY_MGMT_OSEN:
906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return omac1_aes_128(key, buf, len, mic);
91f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_HS20 */
926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_SUITEB
936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
94807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			if (hmac_sha256(key, key_len, buf, len, hash))
956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				return -1;
966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memcpy(mic, hash, MD5_MAC_LEN);
976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_SUITEB */
99807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt#ifdef CONFIG_SUITEB192
100807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
101807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			if (hmac_sha384(key, key_len, buf, len, hash))
102807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt				return -1;
103807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			os_memcpy(mic, hash, 24);
104807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			break;
105807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt#endif /* CONFIG_SUITEB192 */
1066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		default:
1076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
1086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
1096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk: Pairwise master key
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk_len: Length of PMK
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @label: Label to use in derivation
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr1: AA or SA
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr2: SA or AA
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @nonce1: ANonce or SNonce
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @nonce2: SNonce or ANonce
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ptk: Buffer for pairwise transient key
128807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @akmp: Negotiated AKM
129807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @cipher: Negotiated pairwise cipher
130807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PTK = PRF-X(PMK, "Pairwise key expansion",
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(AA, SA) || Max(AA, SA) ||
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * STK = PRF-X(SMK, "Peer key expansion",
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(INonce, PNonce) || Max(INonce, PNonce))
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
141807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtint wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
142807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		   const u8 *addr1, const u8 *addr2,
143807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		   const u8 *nonce1, const u8 *nonce2,
144807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		   struct wpa_ptk *ptk, int akmp, int cipher)
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
147807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
148807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	size_t ptk_len;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data, addr1, ETH_ALEN);
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data, addr2, ETH_ALEN);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_NONCE_LEN);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_NONCE_LEN);
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
168807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk->kck_len = wpa_kck_len(akmp);
169807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk->kek_len = wpa_kek_len(akmp);
170807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk->tk_len = wpa_cipher_key_len(cipher);
171807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
172807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
174807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (wpa_key_mgmt_sha256(akmp))
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
176807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			   tmp, ptk_len);
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
179807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len);
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(addr1), MAC2STR(addr2));
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
186807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
187807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
188807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memcpy(ptk->kck, tmp, ptk->kck_len);
189807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
190807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
191807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
192807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
193807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
194807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
195807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
196807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
197807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memset(tmp, 0, sizeof(tmp));
198807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	return 0;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
203807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtint wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
204807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	       const u8 *ap_addr, u8 transaction_seqnum,
205807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	       const u8 *mdie, size_t mdie_len,
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       const u8 *ftie, size_t ftie_len,
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       const u8 *rsnie, size_t rsnie_len,
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       const u8 *ric, size_t ric_len, u8 *mic)
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
210f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	const u8 *addr[9];
211f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	size_t len[9];
212f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	size_t i, num_elem = 0;
213f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	u8 zero_mic[16];
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
215807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (kck_len != 16) {
216807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
217807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			   (unsigned int) kck_len);
218807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return -1;
219807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	}
220807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
221f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	addr[num_elem] = sta_addr;
222f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	len[num_elem] = ETH_ALEN;
223f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	num_elem++;
224f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt
225f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	addr[num_elem] = ap_addr;
226f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	len[num_elem] = ETH_ALEN;
227f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	num_elem++;
228f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt
229f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	addr[num_elem] = &transaction_seqnum;
230f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	len[num_elem] = 1;
231f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	num_elem++;
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rsnie) {
234f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		addr[num_elem] = rsnie;
235f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		len[num_elem] = rsnie_len;
236f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		num_elem++;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mdie) {
239f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		addr[num_elem] = mdie;
240f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		len[num_elem] = mdie_len;
241f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		num_elem++;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ftie) {
244f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		if (ftie_len < 2 + sizeof(struct rsn_ftie))
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
246f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt
247f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		/* IE hdr and mic_control */
248f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		addr[num_elem] = ftie;
249f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		len[num_elem] = 2 + 2;
250f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		num_elem++;
251f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt
252f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		/* MIC field with all zeros */
253f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		os_memset(zero_mic, 0, sizeof(zero_mic));
254f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		addr[num_elem] = zero_mic;
255f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		len[num_elem] = sizeof(zero_mic);
256f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		num_elem++;
257f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt
258f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		/* Rest of FTIE */
259f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		addr[num_elem] = ftie + 2 + 2 + 16;
260f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		len[num_elem] = ftie_len - (2 + 2 + 16);
261f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		num_elem++;
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ric) {
264f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		addr[num_elem] = ric;
265f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		len[num_elem] = ric_len;
266f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		num_elem++;
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
269f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	for (i = 0; i < num_elem; i++)
270f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
271f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
2791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     struct wpa_ft_ies *parse)
2801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *end, *pos;
2821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	parse->ftie = ie;
2841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	parse->ftie_len = ie_len;
2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = ie + sizeof(struct rsn_ftie);
2871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = ie + ie_len;
2881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
2901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		switch (pos[0]) {
2911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_R1KH_ID:
2921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (pos[1] != FT_R1KH_ID_LEN) {
2931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
2941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   "length in FTIE: %d", pos[1]);
2951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
2961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
2971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->r1kh_id = pos + 2;
2981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_GTK:
3001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->gtk = pos + 2;
3011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->gtk_len = pos[1];
3021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_R0KH_ID:
3041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
3051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
3061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   "length in FTIE: %d", pos[1]);
3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
3091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->r0kh_id = pos + 2;
3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->r0kh_id_len = pos[1];
3111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_IEEE80211W
3131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_IGTK:
3141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->igtk = pos + 2;
3151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->igtk_len = pos[1];
3161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_IEEE80211W */
3181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
3191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2 + pos[1];
3211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
3241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
3281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     struct wpa_ft_ies *parse)
3291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
3301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *end, *pos;
3311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_ie_data data;
3321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret;
3331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const struct rsn_ftie *ftie;
3341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int prot_ie_count = 0;
3351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(parse, 0, sizeof(*parse));
3371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ies == NULL)
3381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
3391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = ies;
3411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = ies + ies_len;
3421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		switch (pos[0]) {
3441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_RSN:
3451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->rsn = pos + 2;
3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->rsn_len = pos[1];
3471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
3481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						   parse->rsn_len + 2,
3491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						   &data);
3501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (ret < 0) {
3511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
3521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   "RSN IE: %d", ret);
3531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
3541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
3551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (data.num_pmkid == 1 && data.pmkid)
3561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				parse->rsn_pmkid = data.pmkid;
3571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_MOBILITY_DOMAIN:
3599d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt			if (pos[1] < sizeof(struct rsn_mdie))
3609d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt				return -1;
3611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->mdie = pos + 2;
3621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->mdie_len = pos[1];
3631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_FAST_BSS_TRANSITION:
3651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (pos[1] < sizeof(*ftie))
3661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
3671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ftie = (const struct rsn_ftie *) (pos + 2);
3681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			prot_ie_count = ftie->mic_control[1];
3691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
3701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
3711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_TIMEOUT_INTERVAL:
3739d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt			if (pos[1] != 5)
3749d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt				break;
3751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->tie = pos + 2;
3761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->tie_len = pos[1];
3771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_RIC_DATA:
3791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (parse->ric == NULL)
3801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				parse->ric = pos;
3811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
3821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
3831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2 + pos[1];
3851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count == 0)
3881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0; /* no MIC */
3891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
3911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Check that the protected IE count matches with IEs included in the
3921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * frame.
3931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
3941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (parse->rsn)
3951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
3961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (parse->mdie)
3971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
3981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (parse->ftie)
3991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
4001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count < 0) {
4011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
4021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "the protected IE count");
4031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
4041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count == 0 && parse->ric) {
4071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
4081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "included in protected IE count");
4091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
4101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* Determine the end of the RIC IE(s) */
4131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = parse->ric;
4141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
4151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	       prot_ie_count) {
4161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
4171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2 + pos[1];
4181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	parse->ric_len = pos - parse->ric;
4201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count) {
4211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
4221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "frame", (int) prot_ie_count);
4231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
4241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
4251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
4271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int rsn_selector_to_bitfield(const u8 *s)
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_NONE;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_TKIP;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_CCMP;
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_AES_128_CMAC;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
44361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
44461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return WPA_CIPHER_GCMP;
445fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
446fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
447fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
448fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
449fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
450fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_BIP_GMAC_128;
451fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
452fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_BIP_GMAC_256;
453fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
454fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_BIP_CMAC_256;
455b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
456b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_CIPHER_GTK_NOT_USED;
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int rsn_key_mgmt_to_bitfield(const u8 *s)
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_PSK;
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_FT_IEEE8021X;
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_FT_PSK;
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X_SHA256;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_PSK_SHA256;
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
479d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#ifdef CONFIG_SAE
480d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
481d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return WPA_KEY_MGMT_SAE;
482d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
483d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return WPA_KEY_MGMT_FT_SAE;
484d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#endif /* CONFIG_SAE */
4856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
4866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
487807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
488807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
489912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
490912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		return WPA_KEY_MGMT_OSEN;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
495b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidtstatic int wpa_cipher_valid_group(int cipher)
496b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt{
497b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	return wpa_cipher_valid_pairwise(cipher) ||
498b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_GTK_NOT_USED;
499b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt}
500b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
501b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
502b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt#ifdef CONFIG_IEEE80211W
503b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidtint wpa_cipher_valid_mgmt_group(int cipher)
504b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt{
505b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	return cipher == WPA_CIPHER_AES_128_CMAC ||
506b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_BIP_GMAC_128 ||
507b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_BIP_GMAC_256 ||
508b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_BIP_CMAC_256;
509b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt}
510b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
511b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
512b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_parse_wpa_ie_rsn - Parse RSN IE
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @rsn_ie: Buffer containing RSN IE
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: Pointer to structure that will be filled in with parsed data
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, <0 on failure
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpa_ie_data *data)
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int left;
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, count;
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(data, 0, sizeof(*data));
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->proto = WPA_PROTO_RSN;
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pairwise_cipher = WPA_CIPHER_CCMP;
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->group_cipher = WPA_CIPHER_CCMP;
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->capabilities = 0;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pmkid = NULL;
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->num_pmkid = 0;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_IEEE80211W */
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->mgmt_group_cipher = 0;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rsn_ie_len == 0) {
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* No RSN IE - fail silently */
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, (unsigned long) rsn_ie_len);
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
552912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt	if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
553912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt	    rsn_ie[1] == rsn_ie_len - 2 &&
554912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt	    WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
555912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		pos = rsn_ie + 6;
556912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		left = rsn_ie_len - 6;
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		data->proto = WPA_PROTO_OSEN;
559912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt	} else {
560912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		const struct rsn_ie_hdr *hdr;
561912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt
562912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		hdr = (const struct rsn_ie_hdr *) rsn_ie;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
564912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		if (hdr->elem_id != WLAN_EID_RSN ||
565912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		    hdr->len != rsn_ie_len - 2 ||
566912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
567912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
568912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt				   __func__);
569912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt			return -2;
570912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		}
571912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt
572912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		pos = (const u8 *) (hdr + 1);
573912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt		left = rsn_ie_len - sizeof(*hdr);
574912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt	}
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= RSN_SELECTOR_LEN) {
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->group_cipher = rsn_selector_to_bitfield(pos);
578b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		if (!wpa_cipher_valid_group(data->group_cipher)) {
579b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
580b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt				   __func__, data->group_cipher);
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= RSN_SELECTOR_LEN;
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left > 0) {
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, left);
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -3;
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->pairwise_cipher = 0;
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
5966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -4;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += RSN_SELECTOR_LEN;
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= RSN_SELECTOR_LEN;
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "pairwise cipher", __func__);
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -5;
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->key_mgmt = 0;
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
6246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -6;
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += RSN_SELECTOR_LEN;
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= RSN_SELECTOR_LEN;
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -7;
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->capabilities = WPA_GET_LE16(pos);
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
6476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		u16 num_pmkid = WPA_GET_LE16(pos);
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
6506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (num_pmkid > (unsigned int) left / PMKID_LEN) {
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "(num_pmkid=%u left=%d)",
6536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   __func__, num_pmkid, left);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->num_pmkid = 0;
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -9;
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
6576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			data->num_pmkid = num_pmkid;
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->pmkid = pos;
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += data->num_pmkid * PMKID_LEN;
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= data->num_pmkid * PMKID_LEN;
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 4) {
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
667b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "group cipher 0x%x", __func__,
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   data->mgmt_group_cipher);
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -10;
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= RSN_SELECTOR_LEN;
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left > 0) {
6797d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		wpa_hexdump(MSG_DEBUG,
6807d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    "wpa_parse_wpa_ie_rsn: ignore trailing bytes",
6817d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    pos, left);
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_selector_to_bitfield(const u8 *s)
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_NONE;
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_TKIP;
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_CCMP;
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_key_mgmt_to_bitfield(const u8 *s)
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X;
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_PSK;
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_WPA_NONE;
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpa_ie_data *data)
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct wpa_ie_hdr *hdr;
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int left;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, count;
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(data, 0, sizeof(*data));
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->proto = WPA_PROTO_WPA;
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pairwise_cipher = WPA_CIPHER_TKIP;
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->group_cipher = WPA_CIPHER_TKIP;
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->capabilities = 0;
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pmkid = NULL;
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->num_pmkid = 0;
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->mgmt_group_cipher = 0;
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, (unsigned long) wpa_ie_len);
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (const struct wpa_ie_hdr *) wpa_ie;
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr->len != wpa_ie_len - 2 ||
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -2;
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (hdr + 1);
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	left = wpa_ie_len - sizeof(*hdr);
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= WPA_SELECTOR_LEN) {
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->group_cipher = wpa_selector_to_bitfield(pos);
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= WPA_SELECTOR_LEN;
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left > 0) {
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, left);
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -3;
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->pairwise_cipher = 0;
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
7656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -4;
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += WPA_SELECTOR_LEN;
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= WPA_SELECTOR_LEN;
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -5;
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->key_mgmt = 0;
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
7866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -6;
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += WPA_SELECTOR_LEN;
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= WPA_SELECTOR_LEN;
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -7;
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->capabilities = WPA_GET_LE16(pos);
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left > 0) {
8097d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		wpa_hexdump(MSG_DEBUG,
8107d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    "wpa_parse_wpa_ie_wpa: ignore trailing bytes",
8117d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    pos, left);
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.3
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *ssid, size_t ssid_len,
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8309d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt	u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos, r0_key_data[48], hash[32];
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[2];
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[2];
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                       SSIDlength || SSID || MDID || R0KHlength ||
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                       R0KH-ID || S0KH-ID)
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * XXKey is either the second 256 bits of MSK or PSK.
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMK-R0 = L(R0-Key-Data, 0, 256)
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8449d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt	if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = ssid_len;
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, ssid, ssid_len);
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ssid_len;
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += MOBILITY_DOMAIN_ID_LEN;
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = r0kh_id_len;
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, r0kh_id, r0kh_id_len);
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += r0kh_id_len;
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, s0kh_id, ETH_ALEN);
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   r0_key_data, sizeof(r0_key_data));
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = (const u8 *) "FT-R0N";
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = 6;
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = r0_key_data + PMK_LEN;
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 16;
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(2, addr, len, hash);
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_derive_pmk_r1_name - Derive PMKR1Name
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.4
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *s1kh_id, u8 *pmk_r1_name)
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[32];
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                                  R1KH-ID || S1KH-ID))
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = (const u8 *) "FT-R1N";
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = 6;
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = pmk_r0_name;
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = WPA_PMK_NAME_LEN;
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = r1kh_id;
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = FT_R1KH_ID_LEN;
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = s1kh_id;
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = ETH_ALEN;
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(4, addr, len, hash);
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.4
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *r1kh_id, const u8 *s1kh_id,
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       u8 *pmk_r1, u8 *pmk_r1_name)
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += FT_R1KH_ID_LEN;
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, s1kh_id, ETH_ALEN);
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.5
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
935807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtint wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
936807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		      const u8 *sta_addr, const u8 *bssid,
937807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		      const u8 *pmk_r1_name,
938807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos, hash[32];
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[6];
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[6];
944807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
945807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	size_t ptk_len;
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                  BSSID || STA-ADDR)
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, snonce, WPA_NONCE_LEN);
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += WPA_NONCE_LEN;
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, anonce, WPA_NONCE_LEN);
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += WPA_NONCE_LEN;
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, bssid, ETH_ALEN);
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, sta_addr, ETH_ALEN);
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
961807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk->kck_len = wpa_kck_len(akmp);
962807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk->kek_len = wpa_kek_len(akmp);
963807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk->tk_len = wpa_cipher_key_len(cipher);
964807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
965807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
966807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                                ANonce || BSSID || STA-ADDR))
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = pmk_r1_name;
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPA_PMK_NAME_LEN;
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = (const u8 *) "FT-PTKN";
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 7;
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = snonce;
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = WPA_NONCE_LEN;
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = anonce;
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = WPA_NONCE_LEN;
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[4] = bssid;
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[4] = ETH_ALEN;
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[5] = sta_addr;
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[5] = ETH_ALEN;
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(6, addr, len, hash);
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
987807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
988807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memcpy(ptk->kck, tmp, ptk->kck_len);
989807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
990807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
991807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
992807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
993807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
994807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
995807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
996807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
997807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memset(tmp, 0, sizeof(tmp));
998807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
999807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	return 0;
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * rsn_pmkid - Calculate PMK identifier
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk: Pairwise master key
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk_len: Length of pmk in bytes
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @aa: Authenticator address
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @spa: Supplicant address
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmkid: Buffer for PMKID
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @use_sha256: Whether to use SHA256-based KDF
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       u8 *pmkid, int use_sha256)
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *title = "PMK Name";
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char hash[SHA256_MAC_LEN];
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = (u8 *) title;
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = aa;
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = spa;
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (use_sha256)
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmkid, hash, PMKID_LEN);
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_SUITEB
10406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
10416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
10426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @kck: Key confirmation key
10436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @kck_len: Length of kck in bytes
10446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @aa: Authenticator address
10456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @spa: Supplicant address
10466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @pmkid: Buffer for PMKID
10476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure
10486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
10496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
10506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
10516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
10526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
10536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		      const u8 *spa, u8 *pmkid)
10546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
10556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char *title = "PMK Name";
10566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const u8 *addr[3];
10576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
10586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	unsigned char hash[SHA256_MAC_LEN];
10596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
10606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	addr[0] = (u8 *) title;
10616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	addr[1] = aa;
10626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	addr[2] = spa;
10636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
10646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
10656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
10666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(pmkid, hash, PMKID_LEN);
10676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
10686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
10696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_SUITEB */
10706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
10716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1072807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt#ifdef CONFIG_SUITEB192
1073807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt/**
1074807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
1075807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @kck: Key confirmation key
1076807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @kck_len: Length of kck in bytes
1077807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @aa: Authenticator address
1078807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @spa: Supplicant address
1079807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * @pmkid: Buffer for PMKID
1080807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1081807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt *
1082807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
1083807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
1084807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt */
1085807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtint rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
1086807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			  const u8 *spa, u8 *pmkid)
1087807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt{
1088807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	char *title = "PMK Name";
1089807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	const u8 *addr[3];
1090807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
1091807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	unsigned char hash[SHA384_MAC_LEN];
1092807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
1093807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	addr[0] = (u8 *) title;
1094807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	addr[1] = aa;
1095807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	addr[2] = spa;
1096807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
1097807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
1098807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return -1;
1099807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	os_memcpy(pmkid, hash, PMKID_LEN);
1100807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	return 0;
1101807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt}
1102807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt#endif /* CONFIG_SUITEB192 */
1103807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
1104807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_cipher_txt - Convert cipher suite to a text string
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cipher: Cipher suite (WPA_CIPHER_* enum)
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to a text string of the cipher suite name
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * wpa_cipher_txt(int cipher)
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (cipher) {
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_NONE:
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "NONE";
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_WEP40:
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WEP-40";
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_WEP104:
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WEP-104";
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_TKIP:
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "TKIP";
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_CCMP:
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "CCMP";
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "CCMP+TKIP";
112561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case WPA_CIPHER_GCMP:
112661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return "GCMP";
1127fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
1128fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return "GCMP-256";
1129fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
1130fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return "CCMP-256";
1131fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GTK_NOT_USED:
1132fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return "GTK_NOT_USED";
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "UNKNOWN";
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_key_mgmt_txt - Convert key management suite to a text string
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @proto: WPA/WPA2 version (WPA_PROTO_*)
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to a text string of the key management suite name
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * wpa_key_mgmt_txt(int key_mgmt, int proto)
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (key_mgmt) {
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X:
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return "WPA2+WPA/IEEE 802.1X/EAP";
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return proto == WPA_PROTO_RSN ?
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_PSK:
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return "WPA2-PSK+WPA-PSK";
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return proto == WPA_PROTO_RSN ?
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"WPA2-PSK" : "WPA-PSK";
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_NONE:
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "NONE";
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "IEEE 802.1X (no WPA)";
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_FT_IEEE8021X:
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FT-EAP";
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_FT_PSK:
11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FT-PSK";
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X_SHA256:
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WPA2-EAP-SHA256";
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_PSK_SHA256:
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WPA2-PSK-SHA256";
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
11746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_KEY_MGMT_WPS:
11756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "WPS";
11766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_KEY_MGMT_SAE:
11776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SAE";
11786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_KEY_MGMT_FT_SAE:
11796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "FT-SAE";
11806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_KEY_MGMT_OSEN:
11816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "OSEN";
11826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
11836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "WPA2-EAP-SUITE-B";
1184807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
1185807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return "WPA2-EAP-SUITE-B-192";
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "UNKNOWN";
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
119203658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidtu32 wpa_akm_to_suite(int akm)
119303658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt{
119403658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
119503658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_FT_8021X;
119603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_FT_PSK)
119703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_FT_PSK;
119803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X)
119903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_8021X;
120003658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
120103658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_8021X_SHA256;
120203658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X)
120303658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_8021X;
120403658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_PSK_SHA256)
120503658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_PSK_SHA256;
120603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_PSK)
120703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_PSK;
120803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_CCKM)
120903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_CCKM;
121003658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_OSEN)
121103658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_OSEN;
12126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
12136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_AKM_SUITE_8021X_SUITE_B;
1214807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
1215807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		return WLAN_AKM_SUITE_8021X_SUITE_B_192;
121603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	return 0;
121703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt}
121803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt
121903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_compare_rsn_ie(int ft_initial_assoc,
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *ie1, size_t ie1len,
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *ie2, size_t ie2len)
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ie1 == NULL || ie2 == NULL)
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* identical IEs */
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ft_initial_assoc) {
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_ie_data ie1d, ie2d;
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The PMKID-List in RSN IE is different between Beacon/Probe
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Response/(Re)Association Request frames and EAPOL-Key
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * messages in FT initial mobility domain association. Allow
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * for this, but verify that other parts of the RSN IEs are
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * identical.
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ie1d.proto == ie2d.proto &&
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.group_cipher == ie2d.group_cipher &&
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.key_mgmt == ie2d.key_mgmt &&
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.capabilities == ie2d.capabilities &&
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *start, *end, *rpos, *rend;
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int added = 0;
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = ies;
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = ies + ies_len;
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (start < end) {
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*start == WLAN_EID_RSN)
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start += 2 + start[1];
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (start >= end) {
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "IEs data");
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    start, 2 + start[1]);
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Find start of PMKID-Count */
12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos = start + 2;
12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rend = rpos + start[1];
12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Skip Version and Group Data Cipher Suite */
12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos += 2 + 4;
12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Skip Pairwise Cipher Suite Count and List */
12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Skip AKM Suite Count and List */
12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rpos == rend) {
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Add RSN Capabilities */
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memmove(rpos + 2, rpos, end - rpos);
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*rpos++ = 0;
12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*rpos++ = 0;
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Skip RSN Capabilities */
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rpos += 2;
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (rpos > rend) {
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "IEs data");
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rpos == rend) {
13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* No PMKID-Count field included; add it */
13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_PUT_LE16(rpos, 1);
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rpos += 2;
13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(rpos, pmkid, PMKID_LEN);
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		added += 2 + PMKID_LEN;
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start[1] += 2 + PMKID_LEN;
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* PMKID-Count was included; use it */
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (WPA_GET_LE16(rpos) != 0) {
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "in RSN IE in EAPOL-Key data");
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_PUT_LE16(rpos, 1);
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rpos += 2;
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(rpos, pmkid, PMKID_LEN);
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		added += PMKID_LEN;
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start[1] += PMKID_LEN;
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    "(PMKID inserted)", start, 2 + start[1]);
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return added;
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
13344530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13354530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13364530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_key_len(int cipher)
13374530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
13384530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	switch (cipher) {
1339fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
1340fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
1341b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_256:
1342b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_CMAC_256:
1343fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return 32;
13444530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_CCMP:
13454530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_GCMP:
1346b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_AES_128_CMAC:
1347b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_128:
13484530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 16;
13494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_TKIP:
13504530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 32;
13514530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
13524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
13544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
13554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_rsc_len(int cipher)
13584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
13594530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	switch (cipher) {
1360fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
1361fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
13624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_CCMP:
13634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_GCMP:
13644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_TKIP:
13654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 6;
13664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
13674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
13694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
13704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13724530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_to_alg(int cipher)
13734530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
13744530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	switch (cipher) {
1375fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
1376fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_ALG_CCMP_256;
1377fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
1378fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_ALG_GCMP_256;
13794530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_CCMP:
13804530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return WPA_ALG_CCMP;
13814530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_GCMP:
13824530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return WPA_ALG_GCMP;
13834530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_TKIP:
13844530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return WPA_ALG_TKIP;
1385b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_AES_128_CMAC:
1386b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_IGTK;
1387b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_128:
1388b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_BIP_GMAC_128;
1389b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_256:
1390b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_BIP_GMAC_256;
1391b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_CMAC_256:
1392b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_BIP_CMAC_256;
13934530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
13944530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return WPA_ALG_NONE;
13954530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
13964530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13974530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13984530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_valid_pairwise(int cipher)
13994530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1400fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	return cipher == WPA_CIPHER_CCMP_256 ||
1401fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		cipher == WPA_CIPHER_GCMP_256 ||
1402fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		cipher == WPA_CIPHER_CCMP ||
14034530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		cipher == WPA_CIPHER_GCMP ||
14044530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		cipher == WPA_CIPHER_TKIP;
14054530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
14064530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14074530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14084530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtu32 wpa_cipher_to_suite(int proto, int cipher)
14094530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1410fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cipher & WPA_CIPHER_CCMP_256)
1411fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return RSN_CIPHER_SUITE_CCMP_256;
1412fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cipher & WPA_CIPHER_GCMP_256)
1413fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return RSN_CIPHER_SUITE_GCMP_256;
14144530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_CCMP)
14154530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
14164530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
14174530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_GCMP)
14184530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return RSN_CIPHER_SUITE_GCMP;
14194530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_TKIP)
14204530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
14214530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
14224530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_NONE)
14234530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
14244530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
1425fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cipher & WPA_CIPHER_GTK_NOT_USED)
1426fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
1427b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_AES_128_CMAC)
1428b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_AES_128_CMAC;
1429b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_BIP_GMAC_128)
1430b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_BIP_GMAC_128;
1431b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_BIP_GMAC_256)
1432b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_BIP_GMAC_256;
1433b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_BIP_CMAC_256)
1434b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_BIP_CMAC_256;
14354530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
14364530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
14374530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14384530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14397d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidtint rsn_cipher_put_suites(u8 *start, int ciphers)
14404530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
14417d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	u8 *pos = start;
14424530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1443fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256) {
1444fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
1445fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
1446fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
1447fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256) {
1448fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
1449fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
1450fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
14514530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP) {
14524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
14534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
14544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
14554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP) {
14564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
14574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
14584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
14594530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP) {
14604530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
14614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
14624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
14634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_NONE) {
14644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
14654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
14664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
14674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14687d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	return (pos - start) / RSN_SELECTOR_LEN;
14694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
14704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14727d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidtint wpa_cipher_put_suites(u8 *start, int ciphers)
14734530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
14747d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	u8 *pos = start;
14754530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14764530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP) {
14774530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
14784530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
14794530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
14804530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP) {
14814530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
14824530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
14834530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
14844530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_NONE) {
14854530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
14864530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
14874530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
14884530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
14897d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	return (pos - start) / RSN_SELECTOR_LEN;
14904530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
1491a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1492a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1493a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
1494a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1495fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256)
1496fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
1497fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256)
1498fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
1499a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP)
1500a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_CCMP;
1501a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP)
1502a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_GCMP;
1503a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP)
1504a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_TKIP;
1505a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (none_allowed && (ciphers & WPA_CIPHER_NONE))
1506a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_NONE;
1507a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return -1;
1508a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1509a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1510a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1511a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_pick_group_cipher(int ciphers)
1512a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1513fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256)
1514fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
1515fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256)
1516fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
1517a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP)
1518a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_CCMP;
1519a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP)
1520a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_GCMP;
1521fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GTK_NOT_USED)
1522fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GTK_NOT_USED;
1523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP)
1524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_TKIP;
1525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return -1;
1526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_parse_cipher(const char *value)
1530a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	int val = 0, last;
1532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	char *start, *end, *buf;
1533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1534a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	buf = os_strdup(value);
1535a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (buf == NULL)
1536a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return -1;
1537a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	start = buf;
1538a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1539a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	while (*start != '\0') {
1540a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		while (*start == ' ' || *start == '\t')
1541a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			start++;
1542a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (*start == '\0')
1543a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
1544a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		end = start;
1545a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		while (*end != ' ' && *end != '\t' && *end != '\0')
1546a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			end++;
1547a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		last = *end == '\0';
1548a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		*end = '\0';
1549fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (os_strcmp(start, "CCMP-256") == 0)
1550fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			val |= WPA_CIPHER_CCMP_256;
1551fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		else if (os_strcmp(start, "GCMP-256") == 0)
1552fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			val |= WPA_CIPHER_GCMP_256;
1553fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		else if (os_strcmp(start, "CCMP") == 0)
1554a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_CCMP;
1555a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "GCMP") == 0)
1556a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_GCMP;
1557a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "TKIP") == 0)
1558a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_TKIP;
1559a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "WEP104") == 0)
1560a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_WEP104;
1561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "WEP40") == 0)
1562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_WEP40;
1563a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "NONE") == 0)
1564a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_NONE;
1565fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		else if (os_strcmp(start, "GTK_NOT_USED") == 0)
1566fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			val |= WPA_CIPHER_GTK_NOT_USED;
1567a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else {
1568a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			os_free(buf);
1569a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1570a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		}
1571a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1572a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (last)
1573a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
1574a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		start = end + 1;
1575a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1576a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	os_free(buf);
1577a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1578a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return val;
1579a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1580a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1581a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1582a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
1583a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1584a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	char *pos = start;
1585a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	int ret;
1586a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1587fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256) {
1588fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sCCMP-256",
1589fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				  pos == start ? "" : delim);
15906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, ret))
1591fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return -1;
1592fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += ret;
1593fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
1594fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256) {
1595fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sGCMP-256",
1596fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				  pos == start ? "" : delim);
15976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, ret))
1598fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return -1;
1599fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += ret;
1600fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
1601a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP) {
1602a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sCCMP",
1603a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
16046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, ret))
1605a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1606a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1607a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1608a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP) {
1609a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sGCMP",
1610a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
16116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, ret))
1612a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1613a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1614a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1615a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP) {
1616a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sTKIP",
1617a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
16186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, ret))
1619a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1620a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1621a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1622a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_NONE) {
1623a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sNONE",
1624a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
16256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, ret))
1626a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1627a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1628a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1629a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1630a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return pos - start;
1631a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1632a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1633a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1634a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
1635a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1636a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	int pairwise = 0;
1637a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1638a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	/* Select group cipher based on the enabled pairwise cipher suites */
1639a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (wpa & 1)
1640a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pairwise |= wpa_pairwise;
1641a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (wpa & 2)
1642a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pairwise |= rsn_pairwise;
1643a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1644a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (pairwise & WPA_CIPHER_TKIP)
1645a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_TKIP;
1646a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
1647a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_GCMP;
1648fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
1649fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			 WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
1650fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
1651fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
1652fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			 WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
1653fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
1654a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return WPA_CIPHER_CCMP;
1655a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1656