18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA/RSN - Shared functions for supplicant and authenticator
3a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Copyright (c) 2002-2013, 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"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
170207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt#include "drivers/driver.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11_defs.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "defs.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_common.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key: EAPOL-Key Key Confirmation Key (KCK)
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Pointer to the beginning of the EAPOL header (version field)
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to be cleared (all zeroes) when calling this function.
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * description of the Key MIC calculation. It includes packet data from the
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * happened during final editing of the standard and the correct behavior is
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * defined in the last draft (IEEE 802.11i/D10).
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      u8 *mic)
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (ver) {
4761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifndef CONFIG_FIPS
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return hmac_md5(key, 16, buf, len, mic);
5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_FIPS */
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (hmac_sha1(key, 16, buf, len, hash))
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(mic, hash, MD5_MAC_LEN);
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return omac1_aes_128(key, buf, len, mic);
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
60f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_HS20
61f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case WPA_KEY_INFO_TYPE_AKM_DEFINED:
62f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		/* FIX: This should be based on negotiated AKM */
63f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return omac1_aes_128(key, buf, len, mic);
64f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_HS20 */
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk: Pairwise master key
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk_len: Length of PMK
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @label: Label to use in derivation
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr1: AA or SA
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr2: SA or AA
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @nonce1: ANonce or SNonce
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @nonce2: SNonce or ANonce
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ptk: Buffer for pairwise transient key
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ptk_len: Length of PTK
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @use_sha256: Whether to use SHA256-based KDF
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PTK = PRF-X(PMK, "Pairwise key expansion",
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(AA, SA) || Max(AA, SA) ||
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * STK = PRF-X(SMK, "Peer key expansion",
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *             Min(INonce, PNonce) || Max(INonce, PNonce))
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    const u8 *addr1, const u8 *addr2,
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    const u8 *nonce1, const u8 *nonce2,
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    u8 *ptk, size_t ptk_len, int use_sha256)
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data, addr1, ETH_ALEN);
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data, addr2, ETH_ALEN);
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_NONCE_LEN);
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_NONCE_LEN);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (use_sha256)
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ptk, ptk_len);
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 ptk_len);
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(addr1), MAC2STR(addr2));
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       const u8 *ftie, size_t ftie_len,
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       const u8 *rsnie, size_t rsnie_len,
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       const u8 *ric, size_t ric_len, u8 *mic)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *buf, *pos;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t buf_len;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = os_malloc(buf_len);
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, sta_addr, ETH_ALEN);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, ap_addr, ETH_ALEN);
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = transaction_seqnum;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rsnie) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, rsnie, rsnie_len);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += rsnie_len;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mdie) {
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, mdie, mdie_len);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += mdie_len;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ftie) {
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct rsn_ftie *_ftie;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, ftie, ftie_len);
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ftie_len < 2 + sizeof(*_ftie)) {
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(buf);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		_ftie = (struct rsn_ftie *) (pos + 2);
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ftie_len;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ric) {
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, ric, ric_len);
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ric_len;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
1961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     struct wpa_ft_ies *parse)
1971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *end, *pos;
1991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	parse->ftie = ie;
2011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	parse->ftie_len = ie_len;
2021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = ie + sizeof(struct rsn_ftie);
2041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = ie + ie_len;
2051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
2071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		switch (pos[0]) {
2081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_R1KH_ID:
2091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (pos[1] != FT_R1KH_ID_LEN) {
2101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
2111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   "length in FTIE: %d", pos[1]);
2121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
2131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
2141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->r1kh_id = pos + 2;
2151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_GTK:
2171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->gtk = pos + 2;
2181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->gtk_len = pos[1];
2191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_R0KH_ID:
2211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
2221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
2231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   "length in FTIE: %d", pos[1]);
2241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
2251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
2261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->r0kh_id = pos + 2;
2271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->r0kh_id_len = pos[1];
2281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_IEEE80211W
2301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case FTIE_SUBELEM_IGTK:
2311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->igtk = pos + 2;
2321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->igtk_len = pos[1];
2331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_IEEE80211W */
2351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
2361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2 + pos[1];
2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
2411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
2421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
2451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     struct wpa_ft_ies *parse)
2461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *end, *pos;
2481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_ie_data data;
2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret;
2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const struct rsn_ftie *ftie;
2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int prot_ie_count = 0;
2521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(parse, 0, sizeof(*parse));
2541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ies == NULL)
2551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
2561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = ies;
2581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = ies + ies_len;
2591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
2601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		switch (pos[0]) {
2611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_RSN:
2621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->rsn = pos + 2;
2631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->rsn_len = pos[1];
2641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
2651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						   parse->rsn_len + 2,
2661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						   &data);
2671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (ret < 0) {
2681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
2691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   "RSN IE: %d", ret);
2701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
2711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
2721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (data.num_pmkid == 1 && data.pmkid)
2731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				parse->rsn_pmkid = data.pmkid;
2741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_MOBILITY_DOMAIN:
2761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->mdie = pos + 2;
2771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->mdie_len = pos[1];
2781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_FAST_BSS_TRANSITION:
2801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (pos[1] < sizeof(*ftie))
2811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
2821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ftie = (const struct rsn_ftie *) (pos + 2);
2831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			prot_ie_count = ftie->mic_control[1];
2841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return -1;
2861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_TIMEOUT_INTERVAL:
2881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->tie = pos + 2;
2891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			parse->tie_len = pos[1];
2901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		case WLAN_EID_RIC_DATA:
2921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (parse->ric == NULL)
2931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				parse->ric = pos;
2941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
2951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
2961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2 + pos[1];
2981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count == 0)
3011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0; /* no MIC */
3021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
3041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Check that the protected IE count matches with IEs included in the
3051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * frame.
3061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (parse->rsn)
3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
3091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (parse->mdie)
3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
3111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (parse->ftie)
3121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
3131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count < 0) {
3141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
3151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "the protected IE count");
3161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
3171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count == 0 && parse->ric) {
3201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
3211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "included in protected IE count");
3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
3231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* Determine the end of the RIC IE(s) */
3261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = parse->ric;
3271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
3281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	       prot_ie_count) {
3291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot_ie_count--;
3301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos += 2 + pos[1];
3311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	parse->ric_len = pos - parse->ric;
3331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (prot_ie_count) {
3341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
3351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "frame", (int) prot_ie_count);
3361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
3371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
3381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
3401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int rsn_selector_to_bitfield(const u8 *s)
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_NONE;
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_WEP40;
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_TKIP;
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_CCMP;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_WEP104;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_AES_128_CMAC;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
36061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
36161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return WPA_CIPHER_GCMP;
362fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
363fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
364fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
365fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
366fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
367fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_BIP_GMAC_128;
368fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
369fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_BIP_GMAC_256;
370fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
371fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_BIP_CMAC_256;
372b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
373b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_CIPHER_GTK_NOT_USED;
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int rsn_key_mgmt_to_bitfield(const u8 *s)
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_PSK;
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_FT_IEEE8021X;
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_FT_PSK;
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X_SHA256;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_PSK_SHA256;
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
396d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#ifdef CONFIG_SAE
397d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
398d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return WPA_KEY_MGMT_SAE;
399d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
400d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return WPA_KEY_MGMT_FT_SAE;
401d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#endif /* CONFIG_SAE */
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
406b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidtstatic int wpa_cipher_valid_group(int cipher)
407b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt{
408b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	return wpa_cipher_valid_pairwise(cipher) ||
409b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_WEP104 ||
410b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_WEP40 ||
411b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_GTK_NOT_USED;
412b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt}
413b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
414b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
415b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt#ifdef CONFIG_IEEE80211W
416b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidtint wpa_cipher_valid_mgmt_group(int cipher)
417b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt{
418b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	return cipher == WPA_CIPHER_AES_128_CMAC ||
419b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_BIP_GMAC_128 ||
420b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_BIP_GMAC_256 ||
421b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		cipher == WPA_CIPHER_BIP_CMAC_256;
422b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt}
423b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
424b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
425b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_parse_wpa_ie_rsn - Parse RSN IE
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @rsn_ie: Buffer containing RSN IE
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: Pointer to structure that will be filled in with parsed data
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, <0 on failure
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpa_ie_data *data)
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct rsn_ie_hdr *hdr;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int left;
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, count;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(data, 0, sizeof(*data));
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->proto = WPA_PROTO_RSN;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pairwise_cipher = WPA_CIPHER_CCMP;
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->group_cipher = WPA_CIPHER_CCMP;
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->capabilities = 0;
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pmkid = NULL;
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->num_pmkid = 0;
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_IEEE80211W */
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->mgmt_group_cipher = 0;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rsn_ie_len == 0) {
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* No RSN IE - fail silently */
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, (unsigned long) rsn_ie_len);
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (const struct rsn_ie_hdr *) rsn_ie;
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->elem_id != WLAN_EID_RSN ||
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr->len != rsn_ie_len - 2 ||
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -2;
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (hdr + 1);
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	left = rsn_ie_len - sizeof(*hdr);
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= RSN_SELECTOR_LEN) {
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->group_cipher = rsn_selector_to_bitfield(pos);
481b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		if (!wpa_cipher_valid_group(data->group_cipher)) {
482b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
483b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt				   __func__, data->group_cipher);
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= RSN_SELECTOR_LEN;
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left > 0) {
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, left);
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -3;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->pairwise_cipher = 0;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -4;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += RSN_SELECTOR_LEN;
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= RSN_SELECTOR_LEN;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "pairwise cipher", __func__);
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -5;
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->key_mgmt = 0;
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -6;
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += RSN_SELECTOR_LEN;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= RSN_SELECTOR_LEN;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -7;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->capabilities = WPA_GET_LE16(pos);
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->num_pmkid = WPA_GET_LE16(pos);
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (left < (int) data->num_pmkid * PMKID_LEN) {
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "(num_pmkid=%lu left=%d)",
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   __func__, (unsigned long) data->num_pmkid,
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   left);
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->num_pmkid = 0;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -9;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->pmkid = pos;
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += data->num_pmkid * PMKID_LEN;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= data->num_pmkid * PMKID_LEN;
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 4) {
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
570b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "group cipher 0x%x", __func__,
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   data->mgmt_group_cipher);
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -10;
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= RSN_SELECTOR_LEN;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left > 0) {
5827d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		wpa_hexdump(MSG_DEBUG,
5837d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    "wpa_parse_wpa_ie_rsn: ignore trailing bytes",
5847d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    pos, left);
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_selector_to_bitfield(const u8 *s)
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_NONE;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_WEP40;
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_TKIP;
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_CCMP;
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_CIPHER_WEP104;
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_key_mgmt_to_bitfield(const u8 *s)
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X;
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_PSK;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPA_KEY_MGMT_WPA_NONE;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpa_ie_data *data)
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct wpa_ie_hdr *hdr;
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int left;
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, count;
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(data, 0, sizeof(*data));
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->proto = WPA_PROTO_WPA;
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pairwise_cipher = WPA_CIPHER_TKIP;
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->group_cipher = WPA_CIPHER_TKIP;
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->capabilities = 0;
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->pmkid = NULL;
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->num_pmkid = 0;
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->mgmt_group_cipher = 0;
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_ie_len == 0) {
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* No WPA IE - fail silently */
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, (unsigned long) wpa_ie_len);
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (const struct wpa_ie_hdr *) wpa_ie;
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr->len != wpa_ie_len - 2 ||
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -2;
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (const u8 *) (hdr + 1);
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	left = wpa_ie_len - sizeof(*hdr);
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= WPA_SELECTOR_LEN) {
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->group_cipher = wpa_selector_to_bitfield(pos);
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= WPA_SELECTOR_LEN;
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left > 0) {
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, left);
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -3;
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->pairwise_cipher = 0;
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -4;
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += WPA_SELECTOR_LEN;
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= WPA_SELECTOR_LEN;
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -5;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->key_mgmt = 0;
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = WPA_GET_LE16(pos);
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "count %u left %u", __func__, count, left);
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -6;
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < count; i++) {
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += WPA_SELECTOR_LEN;
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= WPA_SELECTOR_LEN;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (left == 1) {
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -7;
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left >= 2) {
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->capabilities = WPA_GET_LE16(pos);
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= 2;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (left > 0) {
7217d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		wpa_hexdump(MSG_DEBUG,
7227d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    "wpa_parse_wpa_ie_wpa: ignore trailing bytes",
7237d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt			    pos, left);
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.3
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *ssid, size_t ssid_len,
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos, r0_key_data[48], hash[32];
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[2];
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[2];
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                       SSIDlength || SSID || MDID || R0KHlength ||
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                       R0KH-ID || S0KH-ID)
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * XXKey is either the second 256 bits of MSK or PSK.
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMK-R0 = L(R0-Key-Data, 0, 256)
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = ssid_len;
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, ssid, ssid_len);
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ssid_len;
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += MOBILITY_DOMAIN_ID_LEN;
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = r0kh_id_len;
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, r0kh_id, r0kh_id_len);
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += r0kh_id_len;
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, s0kh_id, ETH_ALEN);
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   r0_key_data, sizeof(r0_key_data));
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = (const u8 *) "FT-R0N";
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = 6;
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = r0_key_data + PMK_LEN;
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 16;
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(2, addr, len, hash);
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_derive_pmk_r1_name - Derive PMKR1Name
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.4
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *s1kh_id, u8 *pmk_r1_name)
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[32];
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                                  R1KH-ID || S1KH-ID))
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = (const u8 *) "FT-R1N";
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = 6;
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = pmk_r0_name;
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = WPA_PMK_NAME_LEN;
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = r1kh_id;
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = FT_R1KH_ID_LEN;
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = s1kh_id;
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = ETH_ALEN;
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(4, addr, len, hash);
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.4
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *r1kh_id, const u8 *s1kh_id,
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       u8 *pmk_r1, u8 *pmk_r1_name)
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += FT_R1KH_ID_LEN;
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, s1kh_id, ETH_ALEN);
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.5
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *sta_addr, const u8 *bssid,
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *pmk_r1_name,
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos, hash[32];
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[6];
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[6];
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                  BSSID || STA-ADDR)
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, snonce, WPA_NONCE_LEN);
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += WPA_NONCE_LEN;
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, anonce, WPA_NONCE_LEN);
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += WPA_NONCE_LEN;
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, bssid, ETH_ALEN);
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, sta_addr, ETH_ALEN);
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *                                ANonce || BSSID || STA-ADDR))
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = pmk_r1_name;
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPA_PMK_NAME_LEN;
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = (const u8 *) "FT-PTKN";
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 7;
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = snonce;
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = WPA_NONCE_LEN;
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = anonce;
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = WPA_NONCE_LEN;
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[4] = bssid;
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[4] = ETH_ALEN;
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[5] = sta_addr;
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[5] = ETH_ALEN;
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(6, addr, len, hash);
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * rsn_pmkid - Calculate PMK identifier
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk: Pairwise master key
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk_len: Length of pmk in bytes
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @aa: Authenticator address
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @spa: Supplicant address
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmkid: Buffer for PMKID
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @use_sha256: Whether to use SHA256-based KDF
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       u8 *pmkid, int use_sha256)
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *title = "PMK Name";
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char hash[SHA256_MAC_LEN];
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = (u8 *) title;
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = aa;
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = spa;
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (use_sha256)
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pmkid, hash, PMKID_LEN);
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_cipher_txt - Convert cipher suite to a text string
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cipher: Cipher suite (WPA_CIPHER_* enum)
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to a text string of the cipher suite name
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * wpa_cipher_txt(int cipher)
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (cipher) {
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_NONE:
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "NONE";
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_WEP40:
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WEP-40";
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_WEP104:
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WEP-104";
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_TKIP:
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "TKIP";
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_CCMP:
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "CCMP";
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "CCMP+TKIP";
95161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case WPA_CIPHER_GCMP:
95261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return "GCMP";
953fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
954fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return "GCMP-256";
955fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
956fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return "CCMP-256";
957fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GTK_NOT_USED:
958fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return "GTK_NOT_USED";
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "UNKNOWN";
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_key_mgmt_txt - Convert key management suite to a text string
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @proto: WPA/WPA2 version (WPA_PROTO_*)
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to a text string of the key management suite name
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * wpa_key_mgmt_txt(int key_mgmt, int proto)
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (key_mgmt) {
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X:
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return "WPA2+WPA/IEEE 802.1X/EAP";
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return proto == WPA_PROTO_RSN ?
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_PSK:
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return "WPA2-PSK+WPA-PSK";
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return proto == WPA_PROTO_RSN ?
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"WPA2-PSK" : "WPA-PSK";
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_NONE:
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "NONE";
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "IEEE 802.1X (no WPA)";
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_FT_IEEE8021X:
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FT-EAP";
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_FT_PSK:
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FT-PSK";
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_IEEE8021X_SHA256:
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WPA2-EAP-SHA256";
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_KEY_MGMT_PSK_SHA256:
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WPA2-PSK-SHA256";
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "UNKNOWN";
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
100603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidtu32 wpa_akm_to_suite(int akm)
100703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt{
100803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
100903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_FT_8021X;
101003658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_FT_PSK)
101103658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_FT_PSK;
101203658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X)
101303658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_8021X;
101403658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
101503658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_8021X_SHA256;
101603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_IEEE8021X)
101703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_8021X;
101803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_PSK_SHA256)
101903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_PSK_SHA256;
102003658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_PSK)
102103658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_PSK;
102203658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_CCKM)
102303658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_CCKM;
102403658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	if (akm & WPA_KEY_MGMT_OSEN)
102503658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		return WLAN_AKM_SUITE_OSEN;
102603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt	return 0;
102703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt}
102803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt
102903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_compare_rsn_ie(int ft_initial_assoc,
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *ie1, size_t ie1len,
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *ie2, size_t ie2len)
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ie1 == NULL || ie2 == NULL)
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* identical IEs */
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ft_initial_assoc) {
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_ie_data ie1d, ie2d;
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The PMKID-List in RSN IE is different between Beacon/Probe
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Response/(Re)Association Request frames and EAPOL-Key
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * messages in FT initial mobility domain association. Allow
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * for this, but verify that other parts of the RSN IEs are
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * identical.
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ie1d.proto == ie2d.proto &&
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.group_cipher == ie2d.group_cipher &&
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.key_mgmt == ie2d.key_mgmt &&
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.capabilities == ie2d.capabilities &&
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211R
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *start, *end, *rpos, *rend;
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int added = 0;
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = ies;
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = ies + ies_len;
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (start < end) {
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*start == WLAN_EID_RSN)
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start += 2 + start[1];
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (start >= end) {
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "IEs data");
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    start, 2 + start[1]);
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Find start of PMKID-Count */
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos = start + 2;
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rend = rpos + start[1];
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Skip Version and Group Data Cipher Suite */
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos += 2 + 4;
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Skip Pairwise Cipher Suite Count and List */
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Skip AKM Suite Count and List */
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rpos == rend) {
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Add RSN Capabilities */
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memmove(rpos + 2, rpos, end - rpos);
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*rpos++ = 0;
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*rpos++ = 0;
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Skip RSN Capabilities */
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rpos += 2;
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (rpos > rend) {
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "IEs data");
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rpos == rend) {
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* No PMKID-Count field included; add it */
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_PUT_LE16(rpos, 1);
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rpos += 2;
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(rpos, pmkid, PMKID_LEN);
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		added += 2 + PMKID_LEN;
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start[1] += 2 + PMKID_LEN;
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* PMKID-Count was included; use it */
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (WPA_GET_LE16(rpos) != 0) {
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "in RSN IE in EAPOL-Key data");
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_PUT_LE16(rpos, 1);
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rpos += 2;
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(rpos, pmkid, PMKID_LEN);
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		added += PMKID_LEN;
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start[1] += PMKID_LEN;
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    "(PMKID inserted)", start, 2 + start[1]);
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return added;
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211R */
11444530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11454530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11464530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_key_len(int cipher)
11474530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
11484530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	switch (cipher) {
1149fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
1150fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
1151b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_256:
1152b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_CMAC_256:
1153fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return 32;
11544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_CCMP:
11554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_GCMP:
1156b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_AES_128_CMAC:
1157b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_128:
11584530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 16;
11594530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_TKIP:
11604530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 32;
11614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_WEP104:
11624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 13;
11634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_WEP40:
11644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 5;
11654530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
11664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11674530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
11684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
11694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_rsc_len(int cipher)
11724530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
11734530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	switch (cipher) {
1174fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
1175fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
11764530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_CCMP:
11774530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_GCMP:
11784530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_TKIP:
11794530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 6;
11804530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_WEP104:
11814530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_WEP40:
11824530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return 0;
11834530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
11844530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11854530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
11864530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
11874530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11884530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
11894530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_to_alg(int cipher)
11904530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
11914530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	switch (cipher) {
1192fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_CCMP_256:
1193fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_ALG_CCMP_256;
1194fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	case WPA_CIPHER_GCMP_256:
1195fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_ALG_GCMP_256;
11964530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_CCMP:
11974530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return WPA_ALG_CCMP;
11984530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_GCMP:
11994530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return WPA_ALG_GCMP;
12004530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_TKIP:
12014530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return WPA_ALG_TKIP;
12024530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_WEP104:
12034530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	case WPA_CIPHER_WEP40:
12044530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return WPA_ALG_WEP;
1205b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_AES_128_CMAC:
1206b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_IGTK;
1207b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_128:
1208b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_BIP_GMAC_128;
1209b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_GMAC_256:
1210b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_BIP_GMAC_256;
1211b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	case WPA_CIPHER_BIP_CMAC_256:
1212b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return WPA_ALG_BIP_CMAC_256;
12134530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
12144530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return WPA_ALG_NONE;
12154530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
12164530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12174530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12184530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtint wpa_cipher_valid_pairwise(int cipher)
12194530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1220fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	return cipher == WPA_CIPHER_CCMP_256 ||
1221fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		cipher == WPA_CIPHER_GCMP_256 ||
1222fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		cipher == WPA_CIPHER_CCMP ||
12234530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		cipher == WPA_CIPHER_GCMP ||
12244530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		cipher == WPA_CIPHER_TKIP;
12254530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
12264530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12274530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12284530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtu32 wpa_cipher_to_suite(int proto, int cipher)
12294530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
1230fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cipher & WPA_CIPHER_CCMP_256)
1231fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return RSN_CIPHER_SUITE_CCMP_256;
1232fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cipher & WPA_CIPHER_GCMP_256)
1233fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return RSN_CIPHER_SUITE_GCMP_256;
12344530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_CCMP)
12354530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
12364530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
12374530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_GCMP)
12384530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return RSN_CIPHER_SUITE_GCMP;
12394530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_TKIP)
12404530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
12414530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
12424530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_WEP104)
12434530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
12444530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
12454530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_WEP40)
12464530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
12474530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
12484530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (cipher & WPA_CIPHER_NONE)
12494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		return (proto == WPA_PROTO_RSN ?
12504530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
1251fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cipher & WPA_CIPHER_GTK_NOT_USED)
1252fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
1253b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_AES_128_CMAC)
1254b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_AES_128_CMAC;
1255b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_BIP_GMAC_128)
1256b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_BIP_GMAC_128;
1257b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_BIP_GMAC_256)
1258b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_BIP_GMAC_256;
1259b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt	if (cipher & WPA_CIPHER_BIP_CMAC_256)
1260b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt		return RSN_CIPHER_SUITE_BIP_CMAC_256;
12614530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	return 0;
12624530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
12634530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12644530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12657d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidtint rsn_cipher_put_suites(u8 *start, int ciphers)
12664530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
12677d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	u8 *pos = start;
12684530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
1269fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256) {
1270fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
1271fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
1272fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
1273fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256) {
1274fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
1275fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
1276fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
12774530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP) {
12784530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
12794530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
12804530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
12814530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP) {
12824530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
12834530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
12844530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
12854530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP) {
12864530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
12874530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
12884530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
12894530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_NONE) {
12904530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
12914530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += RSN_SELECTOR_LEN;
12924530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
12934530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12947d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	return (pos - start) / RSN_SELECTOR_LEN;
12954530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
12964530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12974530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
12987d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidtint wpa_cipher_put_suites(u8 *start, int ciphers)
12994530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
13007d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	u8 *pos = start;
13014530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13024530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP) {
13034530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
13044530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
13054530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
13064530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP) {
13074530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
13084530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
13094530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
13104530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (ciphers & WPA_CIPHER_NONE) {
13114530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
13124530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		pos += WPA_SELECTOR_LEN;
13134530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	}
13144530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
13157d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	return (pos - start) / RSN_SELECTOR_LEN;
13164530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
1317a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1318a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1319a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
1320a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1321fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256)
1322fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
1323fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256)
1324fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
1325a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP)
1326a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_CCMP;
1327a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP)
1328a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_GCMP;
1329a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP)
1330a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_TKIP;
1331a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (none_allowed && (ciphers & WPA_CIPHER_NONE))
1332a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_NONE;
1333a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return -1;
1334a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1335a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1336a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1337a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_pick_group_cipher(int ciphers)
1338a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1339fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256)
1340fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
1341fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256)
1342fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
1343a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP)
1344a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_CCMP;
1345a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP)
1346a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_GCMP;
1347fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GTK_NOT_USED)
1348fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GTK_NOT_USED;
1349a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP)
1350a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_TKIP;
1351a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_WEP104)
1352a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_WEP104;
1353a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_WEP40)
1354a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_WEP40;
1355a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return -1;
1356a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1357a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1358a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1359a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_parse_cipher(const char *value)
1360a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1361a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	int val = 0, last;
1362a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	char *start, *end, *buf;
1363a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1364a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	buf = os_strdup(value);
1365a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (buf == NULL)
1366a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return -1;
1367a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	start = buf;
1368a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1369a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	while (*start != '\0') {
1370a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		while (*start == ' ' || *start == '\t')
1371a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			start++;
1372a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (*start == '\0')
1373a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
1374a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		end = start;
1375a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		while (*end != ' ' && *end != '\t' && *end != '\0')
1376a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			end++;
1377a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		last = *end == '\0';
1378a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		*end = '\0';
1379fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (os_strcmp(start, "CCMP-256") == 0)
1380fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			val |= WPA_CIPHER_CCMP_256;
1381fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		else if (os_strcmp(start, "GCMP-256") == 0)
1382fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			val |= WPA_CIPHER_GCMP_256;
1383fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		else if (os_strcmp(start, "CCMP") == 0)
1384a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_CCMP;
1385a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "GCMP") == 0)
1386a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_GCMP;
1387a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "TKIP") == 0)
1388a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_TKIP;
1389a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "WEP104") == 0)
1390a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_WEP104;
1391a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "WEP40") == 0)
1392a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_WEP40;
1393a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else if (os_strcmp(start, "NONE") == 0)
1394a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			val |= WPA_CIPHER_NONE;
1395fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		else if (os_strcmp(start, "GTK_NOT_USED") == 0)
1396fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			val |= WPA_CIPHER_GTK_NOT_USED;
1397a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		else {
1398a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			os_free(buf);
1399a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1400a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		}
1401a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1402a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (last)
1403a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
1404a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		start = end + 1;
1405a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1406a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	os_free(buf);
1407a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1408a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return val;
1409a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1410a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1411a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1412a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
1413a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1414a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	char *pos = start;
1415a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	int ret;
1416a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1417fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP_256) {
1418fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sCCMP-256",
1419fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				  pos == start ? "" : delim);
1420fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1421fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return -1;
1422fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += ret;
1423fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
1424fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP_256) {
1425fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sGCMP-256",
1426fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				  pos == start ? "" : delim);
1427fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1428fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return -1;
1429fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		pos += ret;
1430fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
1431a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_CCMP) {
1432a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sCCMP",
1433a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
1434a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1435a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1436a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1437a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1438a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_GCMP) {
1439a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sGCMP",
1440a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
1441a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1442a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1443a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1444a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1445a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_TKIP) {
1446a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sTKIP",
1447a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
1448a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1449a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1450a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1451a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1452a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_WEP104) {
1453a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sWEP104",
1454a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
1455a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1456a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1457a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1458a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1459a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_WEP40) {
1460a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sWEP40",
1461a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
1462a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1463a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1464a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1465a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1466a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (ciphers & WPA_CIPHER_NONE) {
1467a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ret = os_snprintf(pos, end - pos, "%sNONE",
1468a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				  pos == start ? "" : delim);
1469a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (ret < 0 || ret >= end - pos)
1470a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
1471a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pos += ret;
1472a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
1473a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1474a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return pos - start;
1475a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
1476a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1477a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1478a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
1479a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
1480a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	int pairwise = 0;
1481a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1482a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	/* Select group cipher based on the enabled pairwise cipher suites */
1483a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (wpa & 1)
1484a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pairwise |= wpa_pairwise;
1485a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (wpa & 2)
1486a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		pairwise |= rsn_pairwise;
1487a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1488a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (pairwise & WPA_CIPHER_TKIP)
1489a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_TKIP;
1490a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
1491a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return WPA_CIPHER_GCMP;
1492fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
1493fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			 WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
1494fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_GCMP_256;
1495fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
1496fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			 WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
1497fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return WPA_CIPHER_CCMP_256;
1498a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return WPA_CIPHER_CCMP;
1499a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
15000207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15010207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15020207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidtstatic int wpa_check_wowlan_trigger(const char *start, const char *trigger,
15030207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt				    int capa_trigger, u8 *param_trigger)
15040207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt{
15050207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	if (os_strcmp(start, trigger) != 0)
15060207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		return 0;
15070207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	if (!capa_trigger)
15080207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		return 0;
15090207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15100207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	*param_trigger = 1;
15110207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	return 1;
15120207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt}
15130207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15140207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15150207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidtstruct wowlan_triggers *wpa_get_wowlan_triggers(const char *wowlan_triggers,
15160207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt						struct wpa_driver_capa *capa)
15170207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt{
15180207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	struct wowlan_triggers *triggers;
15190207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	char *start, *end, *buf;
15200207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	int last;
15210207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15220207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	if (!wowlan_triggers)
15230207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		return NULL;
15240207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15250207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	buf = os_strdup(wowlan_triggers);
15260207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	if (buf == NULL)
15270207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		return NULL;
15280207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15290207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	triggers = os_zalloc(sizeof(*triggers));
15300207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	if (triggers == NULL)
15310207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		goto out;
15320207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15330207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt#define CHECK_TRIGGER(trigger) \
15340207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	wpa_check_wowlan_trigger(start, #trigger,			\
15350207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt				  capa->wowlan_triggers.trigger,	\
15360207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt				  &triggers->trigger)
15370207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15380207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	start = buf;
15390207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	while (*start != '\0') {
15400207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		while (isblank(*start))
15410207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			start++;
15420207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		if (*start == '\0')
15430207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			break;
15440207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		end = start;
15450207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		while (!isblank(*end) && *end != '\0')
15460207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			end++;
15470207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		last = *end == '\0';
15480207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		*end = '\0';
15490207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15500207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		if (!CHECK_TRIGGER(any) &&
15510207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		    !CHECK_TRIGGER(disconnect) &&
15520207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		    !CHECK_TRIGGER(magic_pkt) &&
15530207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		    !CHECK_TRIGGER(gtk_rekey_failure) &&
15540207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		    !CHECK_TRIGGER(eap_identity_req) &&
15550207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		    !CHECK_TRIGGER(four_way_handshake) &&
15560207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		    !CHECK_TRIGGER(rfkill_release)) {
15570207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			wpa_printf(MSG_DEBUG,
15580207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt				   "Unknown/unsupported wowlan trigger '%s'",
15590207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt				   start);
15600207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			os_free(triggers);
15610207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			triggers = NULL;
15620207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			goto out;
15630207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		}
15640207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15650207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		if (last)
15660207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt			break;
15670207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt		start = end + 1;
15680207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	}
15690207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt#undef CHECK_TRIGGER
15700207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt
15710207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidtout:
15720207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	os_free(buf);
15730207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt	return triggers;
15740207e233ee2e741f7b2c124c1366e905ebb634c8Dmitry Shmidt}
1575