Przeglądaj źródła

Merge branch 'feature/support_pmf' into 'master'

Feature/support pmf

See merge request espressif/esp-idf!5708
Jiang Jiang Jian 6 lat temu
rodzic
commit
54eeb77a56

+ 44 - 0
components/esp_wifi/include/esp_wifi_crypto_types.h

@@ -315,6 +315,47 @@ typedef void * (*esp_aes_decrypt_init_t)(const unsigned char *key, unsigned int
  */
 typedef void (*esp_aes_decrypt_deinit_t)(void *ctx);
 
+/**
+ * @brief One-Key CBC MAC (OMAC1) hash with AES-128 for MIC computation
+ *
+ * @key: 128-bit key for the hash operation
+ * @data: Data buffer for which a MIC is computed
+ * @data_len: Length of data buffer in bytes
+ * @mic: Buffer for MIC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+typedef int (*esp_omac1_aes_128_t)(const uint8_t *key, const uint8_t *data, size_t data_len,
+                                   uint8_t *mic);
+
+/**
+ * @brief Decrypt data using CCMP (Counter Mode CBC-MAC Protocol OR
+ *        Counter Mode Cipher Block Chaining Message Authentication
+ *        Code Protocol) which is used in IEEE 802.11i RSN standard.
+ * @tk: 128-bit Temporal Key for obtained during 4-way handshake
+ * @hdr: Pointer to IEEE802.11 frame headeri needed for AAD
+ * @data: Pointer to encrypted data buffer
+ * @data_len: Encrypted data length in bytes
+ * @decrypted_len: Length of decrypted data
+ * Returns: Pointer to decrypted data on success, NULL on failure
+ */
+typedef uint8_t * (*esp_ccmp_decrypt_t)(const uint8_t *tk, const uint8_t *ieee80211_hdr,
+                                        const uint8_t *data, size_t data_len, size_t *decrypted_len);
+
+/**
+ * @brief Encrypt data using CCMP (Counter Mode CBC-MAC Protocol OR
+ *        Counter Mode Cipher Block Chaining Message Authentication
+ *        Code Protocol) which is used in IEEE 802.11i RSN standard.
+ * @tk: 128-bit Temporal Key for obtained during 4-way handshake
+ * @frame: Pointer to IEEE802.11 frame including header
+ * @len: Length of the frame including header
+ * @hdrlen: Length of the header
+ * @pn: Packet Number counter
+ * @keyid: Key ID to be mentioned in CCMP Vector
+ * @encrypted_len: Length of the encrypted frame including header
+ */
+typedef uint8_t * (*esp_ccmp_encrypt_t)(const uint8_t *tk, uint8_t *frame, size_t len, size_t hdrlen,
+                                        uint8_t *pn, int keyid, size_t *encrypted_len);
+
 /**
   * @brief The crypto callback function structure used when do station security connect.
   *        The structure can be set as software crypto or the crypto optimized by ESP32
@@ -342,6 +383,9 @@ typedef struct {
     esp_aes_decrypt_t aes_decrypt;
     esp_aes_decrypt_init_t aes_decrypt_init;
     esp_aes_decrypt_deinit_t aes_decrypt_deinit;
+    esp_omac1_aes_128_t omac1_aes_128;
+    esp_ccmp_decrypt_t ccmp_decrypt;
+    esp_ccmp_encrypt_t ccmp_encrypt;
 }wpa_crypto_funcs_t;
 
 /**

+ 8 - 0
components/esp_wifi/include/esp_wifi_types.h

@@ -134,6 +134,7 @@ typedef enum {
     WIFI_CIPHER_TYPE_TKIP,       /**< the cipher type is TKIP */
     WIFI_CIPHER_TYPE_CCMP,       /**< the cipher type is CCMP */
     WIFI_CIPHER_TYPE_TKIP_CCMP,  /**< the cipher type is TKIP and CCMP */
+    WIFI_CIPHER_TYPE_AES_CMAC128,/**< the cipher type is AES-CMAC-128 */
     WIFI_CIPHER_TYPE_UNKNOWN,    /**< the cipher type is unknown */
 } wifi_cipher_type_t;
 
@@ -199,6 +200,12 @@ typedef enum {
     WIFI_BW_HT40,     /* Bandwidth is HT40 */
 } wifi_bandwidth_t;
 
+/** Configuration structure for Protected Management Frame */
+typedef struct {
+    bool capable;            /**< Advertizes support for Protected Management Frame. Device will prefer to connect in PMF mode if other device also advertizes PMF capability. */
+    bool required;           /**< Advertizes that Protected Management Frame is required. Device will not associate to non-PMF capable devices. */
+} wifi_pmf_config_t;
+
 /** @brief Soft-AP configuration settings for the ESP32 */
 typedef struct {
     uint8_t ssid[32];           /**< SSID of ESP32 soft-AP. If ssid_len field is 0, this must be a Null terminated string. Otherwise, length is set according to ssid_len. */
@@ -222,6 +229,7 @@ typedef struct {
     uint16_t listen_interval;   /**< Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. */
     wifi_sort_method_t sort_method;    /**< sort the connect AP in the list by rssi or security mode */
     wifi_scan_threshold_t  threshold;     /**< When sort_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */
+    wifi_pmf_config_t pmf_cfg;    /**< Configuration for Protected Management Frame. Will be advertized in RSN Capabilities in RSN IE. */
 } wifi_sta_config_t;
 
 /** @brief Configuration data for ESP32 AP or STA.

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit f3c39df1c428b065e05a431c6f8685790531baf5
+Subproject commit d88a262fbdf35e5abb372280eb08008749c3faa0

+ 4 - 0
components/wpa_supplicant/CMakeLists.txt

@@ -5,12 +5,15 @@ set(srcs "port/os_xtensa.c"
     "src/ap/wpa_auth_ie.c"
     "src/common/wpa_common.c"
     "src/crypto/aes-cbc.c"
+    "src/crypto/aes-ccm.c"
     "src/crypto/aes-internal-dec.c"
     "src/crypto/aes-internal-enc.c"
     "src/crypto/aes-internal.c"
     "src/crypto/aes-unwrap.c"
     "src/crypto/aes-wrap.c"
+    "src/crypto/aes-omac1.c"
     "src/crypto/bignum.c"
+    "src/crypto/ccmp.c"
     "src/crypto/crypto_mbedtls.c"
     "src/crypto/crypto_ops.c"
     "src/crypto/crypto_internal-cipher.c"
@@ -103,4 +106,5 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
     ESPRESSIF_USE
     ESP32_WORKAROUND
     CONFIG_ECC
+    CONFIG_IEEE80211W
     )

+ 1 - 1
components/wpa_supplicant/component.mk

@@ -2,4 +2,4 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant
 COMPONENT_PRIV_INCLUDEDIRS := src
 COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/rsn_supp src/tls src/utils src/esp_supplicant src/wps
 
-CFLAGS += -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing
+CFLAGS += -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing

+ 1 - 2
components/wpa_supplicant/src/common/defs.h

@@ -22,7 +22,7 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #define WPA_CIPHER_WEP104               BIT(8)
 #define WPA_CIPHER_TKIP                 BIT(1)
 #define WPA_CIPHER_CCMP                 BIT(3)
-#define WPA_CIPHER_AES_128_CMAC         BIT(2)
+#define WPA_CIPHER_AES_128_CMAC         BIT(5)
 #define WPA_CIPHER_GCMP                 BIT(6)
 
 #define WPA_KEY_MGMT_IEEE8021X BIT(0)
@@ -304,7 +304,6 @@ enum wpa_states {
 #define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
 #define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
 
-
 /**
  * enum mfp_options - Management frame protection (IEEE 802.11w) options
  */

+ 5 - 0
components/wpa_supplicant/src/common/wpa_common.c

@@ -22,6 +22,7 @@
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "crypto/md5.h"
+#include "crypto/aes.h"
  
 #define MD5_MAC_LEN 16
 
@@ -388,6 +389,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
 			return -1;
 		memcpy(mic, hash, MD5_MAC_LEN);
 		break;
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
+		return omac1_aes_128(key, buf, len, mic);
+#endif
 	default:
 		return -1;
 	}

+ 215 - 0
components/wpa_supplicant/src/crypto/aes-ccm.c

@@ -0,0 +1,215 @@
+/*
+ * Counter with CBC-MAC (CCM) with AES
+ *
+ * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifdef CONFIG_IEEE80211W
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+
+static void xor_aes_block(u8 *dst, const u8 *src)
+{
+	u32 *d = (u32 *) dst;
+	u32 *s = (u32 *) src;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+}
+
+
+static void aes_ccm_auth_start(void *aes, size_t M, size_t L, const u8 *nonce,
+			       const u8 *aad, size_t aad_len, size_t plain_len,
+			       u8 *x)
+{
+	u8 aad_buf[2 * AES_BLOCK_SIZE];
+	u8 b[AES_BLOCK_SIZE];
+
+	/* Authentication */
+	/* B_0: Flags | Nonce N | l(m) */
+	b[0] = aad_len ? 0x40 : 0 /* Adata */;
+	b[0] |= (((M - 2) / 2) /* M' */ << 3);
+	b[0] |= (L - 1) /* L' */;
+	os_memcpy(&b[1], nonce, 15 - L);
+	WPA_PUT_BE16(&b[AES_BLOCK_SIZE - L], plain_len);
+
+	wpa_hexdump_key(MSG_DEBUG, "CCM B_0", b, AES_BLOCK_SIZE);
+	aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */
+
+	if (!aad_len)
+		return;
+
+	WPA_PUT_BE16(aad_buf, aad_len);
+	os_memcpy(aad_buf + 2, aad, aad_len);
+	os_memset(aad_buf + 2 + aad_len, 0, sizeof(aad_buf) - 2 - aad_len);
+
+	xor_aes_block(aad_buf, x);
+	aes_encrypt(aes, aad_buf, x); /* X_2 = E(K, X_1 XOR B_1) */
+
+	if (aad_len > AES_BLOCK_SIZE - 2) {
+		xor_aes_block(&aad_buf[AES_BLOCK_SIZE], x);
+		/* X_3 = E(K, X_2 XOR B_2) */
+		aes_encrypt(aes, &aad_buf[AES_BLOCK_SIZE], x);
+	}
+}
+
+
+static void aes_ccm_auth(void *aes, const u8 *data, size_t len, u8 *x)
+{
+	size_t last = len % AES_BLOCK_SIZE;
+	size_t i;
+
+	for (i = 0; i < len / AES_BLOCK_SIZE; i++) {
+		/* X_i+1 = E(K, X_i XOR B_i) */
+		xor_aes_block(x, data);
+		data += AES_BLOCK_SIZE;
+		aes_encrypt(aes, x, x);
+	}
+	if (last) {
+		/* XOR zero-padded last block */
+		for (i = 0; i < last; i++)
+			x[i] ^= *data++;
+		aes_encrypt(aes, x, x);
+	}
+}
+
+
+static void aes_ccm_encr_start(size_t L, const u8 *nonce, u8 *a)
+{
+	/* A_i = Flags | Nonce N | Counter i */
+	a[0] = L - 1; /* Flags = L' */
+	os_memcpy(&a[1], nonce, 15 - L);
+}
+
+
+static void aes_ccm_encr(void *aes, size_t L, const u8 *in, size_t len, u8 *out,
+			 u8 *a)
+{
+	size_t last = len % AES_BLOCK_SIZE;
+	size_t i;
+
+	/* crypt = msg XOR (S_1 | S_2 | ... | S_n) */
+	for (i = 1; i <= len / AES_BLOCK_SIZE; i++) {
+		WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
+		/* S_i = E(K, A_i) */
+		aes_encrypt(aes, a, out);
+		xor_aes_block(out, in);
+		out += AES_BLOCK_SIZE;
+		in += AES_BLOCK_SIZE;
+	}
+	if (last) {
+		WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
+		aes_encrypt(aes, a, out);
+		/* XOR zero-padded last block */
+		for (i = 0; i < last; i++)
+			*out++ ^= *in++;
+	}
+}
+
+
+static void aes_ccm_encr_auth(void *aes, size_t M, u8 *x, u8 *a, u8 *auth)
+{
+	size_t i;
+	u8 tmp[AES_BLOCK_SIZE];
+
+	wpa_hexdump_key(MSG_DEBUG, "CCM T", x, M);
+	/* U = T XOR S_0; S_0 = E(K, A_0) */
+	WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
+	aes_encrypt(aes, a, tmp);
+	for (i = 0; i < M; i++)
+		auth[i] = x[i] ^ tmp[i];
+	wpa_hexdump_key(MSG_DEBUG, "CCM U", auth, M);
+}
+
+
+static void aes_ccm_decr_auth(void *aes, size_t M, u8 *a, const u8 *auth, u8 *t)
+{
+	size_t i;
+	u8 tmp[AES_BLOCK_SIZE];
+
+	wpa_hexdump_key(MSG_DEBUG, "CCM U", auth, M);
+	/* U = T XOR S_0; S_0 = E(K, A_0) */
+	WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
+	aes_encrypt(aes, a, tmp);
+	for (i = 0; i < M; i++)
+		t[i] = auth[i] ^ tmp[i];
+	wpa_hexdump_key(MSG_DEBUG, "CCM T", t, M);
+}
+
+
+/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
+int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
+	       size_t M, const u8 *plain, size_t plain_len,
+	       const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth)
+{
+	const size_t L = 2;
+	void *aes;
+	u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
+
+	if (aad_len > 30 || M > AES_BLOCK_SIZE)
+		return -1;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return -1;
+
+	aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, plain_len, x);
+	aes_ccm_auth(aes, plain, plain_len, x);
+
+	/* Encryption */
+	aes_ccm_encr_start(L, nonce, a);
+	aes_ccm_encr(aes, L, plain, plain_len, crypt, a);
+	aes_ccm_encr_auth(aes, M, x, a, auth);
+
+	aes_encrypt_deinit(aes);
+
+	return 0;
+}
+
+
+/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
+int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+	       size_t M, const u8 *crypt, size_t crypt_len,
+	       const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain)
+{
+	const size_t L = 2;
+	void *aes;
+	u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
+	u8 t[AES_BLOCK_SIZE];
+
+	if (aad_len > 30 || M > AES_BLOCK_SIZE)
+		return -1;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return -1;
+
+	/* Decryption */
+	aes_ccm_encr_start(L, nonce, a);
+	aes_ccm_decr_auth(aes, M, a, auth, t);
+
+	/* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */
+	aes_ccm_encr(aes, L, crypt, crypt_len, plain, a);
+
+	aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x);
+	aes_ccm_auth(aes, plain, crypt_len, x);
+
+	aes_encrypt_deinit(aes);
+
+	if (os_memcmp(x, t, M) != 0) {
+		wpa_printf(MSG_DEBUG, "CCM: Auth mismatch");
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211W */

+ 169 - 0
components/wpa_supplicant/src/crypto/aes-omac1.c

@@ -0,0 +1,169 @@
+/*
+ * One-key CBC MAC (OMAC1) hash with AES
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+
+#include "utils/common.h"
+#include "crypto/aes.h"
+#include "crypto/aes_wrap.h"
+
+static void gf_mulx(u8 *pad)
+{
+	int i, carry;
+
+	carry = pad[0] & 0x80;
+	for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+		pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+	pad[AES_BLOCK_SIZE - 1] <<= 1;
+	if (carry)
+		pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+/**
+ * omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES
+ * @key: Key for the hash operation
+ * @key_len: Key length in octets
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	void *ctx;
+	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
+	const u8 *pos, *end;
+	size_t i, e, left, total_len;
+
+	ctx = aes_encrypt_init(key, key_len);
+	if (ctx == NULL)
+		return -1;
+	os_memset(cbc, 0, AES_BLOCK_SIZE);
+
+	total_len = 0;
+	for (e = 0; e < num_elem; e++)
+		total_len += len[e];
+	left = total_len;
+
+	e = 0;
+	pos = addr[0];
+	end = pos + len[0];
+
+	while (left >= AES_BLOCK_SIZE) {
+		for (i = 0; i < AES_BLOCK_SIZE; i++) {
+			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				/*
+				 * Stop if there are no more bytes to process
+				 * since there are no more entries in the array.
+				 */
+				if (i + 1 == AES_BLOCK_SIZE &&
+				    left == AES_BLOCK_SIZE)
+					break;
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
+		if (left > AES_BLOCK_SIZE)
+			aes_encrypt(ctx, cbc, cbc);
+		left -= AES_BLOCK_SIZE;
+	}
+
+	os_memset(pad, 0, AES_BLOCK_SIZE);
+	aes_encrypt(ctx, pad, pad);
+	gf_mulx(pad);
+
+	if (left || total_len == 0) {
+		for (i = 0; i < left; i++) {
+			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				/*
+				 * Stop if there are no more bytes to process
+				 * since there are no more entries in the array.
+				 */
+				if (i + 1 == left)
+					break;
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
+		cbc[left] ^= 0x80;
+		gf_mulx(pad);
+	}
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		pad[i] ^= cbc[i];
+	aes_encrypt(ctx, pad, mac);
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
+
+
+/**
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 128-bit key for the hash operation
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+/**
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+/**
+ * omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC)
+ * @key: 256-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}

+ 9 - 0
components/wpa_supplicant/src/crypto/aes.h

@@ -24,4 +24,13 @@ void * aes_decrypt_init(const u8 *key, size_t len);
 void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
 void aes_decrypt_deinit(void *ctx);
 
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
+
+int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
+               size_t M, const u8 *plain, size_t plain_len,
+               const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth);
+int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+               size_t M, const u8 *crypt, size_t crypt_len,
+               const u8 *aad, size_t aad_len, const u8 *auth,
+               u8 *plain);
 #endif /* AES_H */

+ 354 - 0
components/wpa_supplicant/src/crypto/ccmp.c

@@ -0,0 +1,354 @@
+/*
+ * CTR with CBC-MAC Protocol (CCMP)
+ * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifdef CONFIG_IEEE80211W
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
+			   u8 *aad, size_t *aad_len, u8 *nonce)
+{
+	u16 fc, stype, seq;
+	int qos = 0, addr4 = 0;
+	u8 *pos;
+
+	nonce[0] = 0;
+
+	fc = le_to_host16(hdr->frame_control);
+	stype = WLAN_FC_GET_STYPE(fc);
+	if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
+	    (WLAN_FC_TODS | WLAN_FC_FROMDS))
+		addr4 = 1;
+
+	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
+		fc &= ~0x0070; /* Mask subtype bits */
+		if (stype & 0x08) {
+			const u8 *qc;
+			qos = 1;
+			fc &= ~WLAN_FC_ORDER;
+			qc = (const u8 *) (hdr + 1);
+			if (addr4)
+				qc += ETH_ALEN;
+			nonce[0] = qc[0] & 0x0f;
+		}
+	} else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
+		nonce[0] |= 0x10; /* Management */
+
+	fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
+	fc |= WLAN_FC_ISWEP;
+	WPA_PUT_LE16(aad, fc);
+	pos = aad + 2;
+	os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN);
+	pos += 3 * ETH_ALEN;
+	seq = le_to_host16(hdr->seq_ctrl);
+	seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */
+	WPA_PUT_LE16(pos, seq);
+	pos += 2;
+
+	os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2);
+	pos += addr4 * ETH_ALEN;
+	if (qos) {
+		pos[0] &= ~0x70;
+		if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
+			pos[0] &= ~0x80;
+		pos++;
+		*pos++ = 0x00;
+	}
+
+	*aad_len = pos - aad;
+
+	os_memcpy(nonce + 1, hdr->addr2, ETH_ALEN);
+	nonce[7] = data[7]; /* PN5 */
+	nonce[8] = data[6]; /* PN4 */
+	nonce[9] = data[5]; /* PN3 */
+	nonce[10] = data[4]; /* PN2 */
+	nonce[11] = data[1]; /* PN1 */
+	nonce[12] = data[0]; /* PN0 */
+}
+
+
+static void ccmp_aad_nonce_pv1(const u8 *hdr, const u8 *a1, const u8 *a2,
+			       const u8 *a3, const u8 *pn,
+			       u8 *aad, size_t *aad_len, u8 *nonce)
+{
+	u16 fc, type;
+	u8 *pos;
+
+	nonce[0] = BIT(5); /* PV1 */
+	/* TODO: Priority for QMF; 0 is used for Data frames */
+
+	fc = WPA_GET_LE16(hdr);
+	type = (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2;
+
+	if (type == 1)
+		nonce[0] |= 0x10; /* Management */
+
+	fc &= ~(BIT(10) | BIT(11) | BIT(13) | BIT(14) | BIT(15));
+	fc |= BIT(12);
+	WPA_PUT_LE16(aad, fc);
+	pos = aad + 2;
+	if (type == 0 || type == 3) {
+		const u8 *sc;
+
+		os_memcpy(pos, a1, ETH_ALEN);
+		pos += ETH_ALEN;
+		os_memcpy(pos, a2, ETH_ALEN);
+		pos += ETH_ALEN;
+
+		if (type == 0) {
+			/* Either A1 or A2 contains SID */
+			sc = hdr + 2 + 2 + ETH_ALEN;
+		} else {
+			/* Both A1 and A2 contain full addresses */
+			sc = hdr + 2 + 2 * ETH_ALEN;
+		}
+		/* SC with Sequence Number subfield (bits 4-15 of the Sequence
+		 * Control field) masked to 0. */
+		*pos++ = *sc & 0x0f;
+		*pos++ = 0;
+
+		if (a3) {
+			os_memcpy(pos, a3, ETH_ALEN);
+			pos += ETH_ALEN;
+		}
+	}
+
+	*aad_len = pos - aad;
+
+	os_memcpy(nonce + 1, a2, ETH_ALEN);
+	nonce[7] = pn[5]; /* PN5 */
+	nonce[8] = pn[4]; /* PN4 */
+	nonce[9] = pn[3]; /* PN3 */
+	nonce[10] = pn[2]; /* PN2 */
+	nonce[11] = pn[1]; /* PN1 */
+	nonce[12] = pn[0]; /* PN0 */
+}
+
+
+u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
+		  size_t data_len, size_t *decrypted_len)
+{
+	u8 aad[30], nonce[13];
+	size_t aad_len;
+	size_t mlen;
+	u8 *plain;
+
+	if (data_len < 8 + 8)
+		return NULL;
+
+	plain = os_malloc(data_len + AES_BLOCK_SIZE);
+	if (plain == NULL)
+		return NULL;
+
+	mlen = data_len - 8 - 8;
+
+	os_memset(aad, 0, sizeof(aad));
+	ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce);
+	//wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
+	//wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13);
+
+	if (aes_ccm_ad(tk, 16, nonce, 8, data + 8, mlen, aad, aad_len,
+		       data + 8 + mlen, plain) < 0) {
+		os_free(plain);
+		return NULL;
+	}
+	//wpa_hexdump(MSG_DEBUG, "CCMP decrypted", plain, mlen);
+
+	*decrypted_len = mlen;
+	return plain;
+}
+
+
+void ccmp_get_pn(u8 *pn, const u8 *data)
+{
+	pn[0] = data[7]; /* PN5 */
+	pn[1] = data[6]; /* PN4 */
+	pn[2] = data[5]; /* PN3 */
+	pn[3] = data[4]; /* PN2 */
+	pn[4] = data[1]; /* PN1 */
+	pn[5] = data[0]; /* PN0 */
+}
+
+
+u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
+		  u8 *pn, int keyid, size_t *encrypted_len)
+{
+	u8 aad[30], nonce[13];
+	size_t aad_len, plen;
+	u8 *crypt, *pos;
+	struct ieee80211_hdr *hdr;
+
+	if (len < hdrlen || hdrlen < 24)
+		return NULL;
+	plen = len - hdrlen;
+
+	crypt = os_malloc(hdrlen + 8 + plen + 8 + AES_BLOCK_SIZE);
+	if (crypt == NULL)
+		return NULL;
+
+	os_memcpy(crypt, frame, hdrlen);
+	hdr = (struct ieee80211_hdr *) crypt;
+	hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	pos = crypt + hdrlen;
+	*pos++ = pn[5]; /* PN0 */
+	*pos++ = pn[4]; /* PN1 */
+	*pos++ = 0x00; /* Rsvd */
+	*pos++ = 0x20 | (keyid << 6);
+	*pos++ = pn[3]; /* PN2 */
+	*pos++ = pn[2]; /* PN3 */
+	*pos++ = pn[1]; /* PN4 */
+	*pos++ = pn[0]; /* PN5 */
+
+	os_memset(aad, 0, sizeof(aad));
+	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
+	wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
+	wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13);
+
+	if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
+		       pos, pos + plen) < 0) {
+		os_free(crypt);
+		return NULL;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "CCMP encrypted", crypt + hdrlen + 8, plen);
+
+	*encrypted_len = hdrlen + 8 + plen + 8;
+
+	return crypt;
+}
+
+
+u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
+		      const u8 *frame, size_t len,
+		      size_t hdrlen, const u8 *pn, int keyid,
+		      size_t *encrypted_len)
+{
+	u8 aad[24], nonce[13];
+	size_t aad_len, plen;
+	u8 *crypt, *pos;
+	struct ieee80211_hdr *hdr;
+
+	if (len < hdrlen || hdrlen < 12)
+		return NULL;
+	plen = len - hdrlen;
+
+	crypt = os_malloc(hdrlen + plen + 8 + AES_BLOCK_SIZE);
+	if (crypt == NULL)
+		return NULL;
+
+	os_memcpy(crypt, frame, hdrlen);
+	hdr = (struct ieee80211_hdr *) crypt;
+	hdr->frame_control |= host_to_le16(BIT(12)); /* Protected Frame */
+	pos = crypt + hdrlen;
+
+	os_memset(aad, 0, sizeof(aad));
+	ccmp_aad_nonce_pv1(crypt, a1, a2, a3, pn, aad, &aad_len, nonce);
+	wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
+	wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, sizeof(nonce));
+
+	if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
+		       pos, pos + plen) < 0) {
+		os_free(crypt);
+		return NULL;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "CCMP encrypted", crypt + hdrlen, plen);
+
+	*encrypted_len = hdrlen + plen + 8;
+
+	return crypt;
+}
+
+
+u8 * ccmp_256_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
+		      size_t data_len, size_t *decrypted_len)
+{
+	u8 aad[30], nonce[13];
+	size_t aad_len;
+	size_t mlen;
+	u8 *plain;
+
+	if (data_len < 8 + 16)
+		return NULL;
+
+	plain = os_malloc(data_len + AES_BLOCK_SIZE);
+	if (plain == NULL)
+		return NULL;
+
+	mlen = data_len - 8 - 16;
+
+	os_memset(aad, 0, sizeof(aad));
+	ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce);
+	wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len);
+	wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13);
+
+	if (aes_ccm_ad(tk, 32, nonce, 16, data + 8, mlen, aad, aad_len,
+		       data + 8 + mlen, plain) < 0) {
+		os_free(plain);
+		return NULL;
+	}
+	wpa_hexdump(MSG_DEBUG, "CCMP-256 decrypted", plain, mlen);
+
+	*decrypted_len = mlen;
+	return plain;
+}
+
+
+u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
+		      u8 *pn, int keyid, size_t *encrypted_len)
+{
+	u8 aad[30], nonce[13];
+	size_t aad_len, plen;
+	u8 *crypt, *pos;
+	struct ieee80211_hdr *hdr;
+
+	if (len < hdrlen || hdrlen < 24)
+		return NULL;
+	plen = len - hdrlen;
+
+	crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE);
+	if (crypt == NULL)
+		return NULL;
+
+	os_memcpy(crypt, frame, hdrlen);
+	hdr = (struct ieee80211_hdr *) crypt;
+	hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	pos = crypt + hdrlen;
+	*pos++ = pn[5]; /* PN0 */
+	*pos++ = pn[4]; /* PN1 */
+	*pos++ = 0x00; /* Rsvd */
+	*pos++ = 0x20 | (keyid << 6);
+	*pos++ = pn[3]; /* PN2 */
+	*pos++ = pn[2]; /* PN3 */
+	*pos++ = pn[1]; /* PN4 */
+	*pos++ = pn[0]; /* PN5 */
+
+	os_memset(aad, 0, sizeof(aad));
+	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
+	wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len);
+	wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13);
+
+	if (aes_ccm_ae(tk, 32, nonce, 16, frame + hdrlen, plen, aad, aad_len,
+		       pos, pos + plen) < 0) {
+		os_free(crypt);
+		return NULL;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "CCMP-256 encrypted", crypt + hdrlen + 8,
+		    plen);
+
+	*encrypted_len = hdrlen + 8 + plen + 16;
+
+	return crypt;
+}
+#endif /* CONFIG_IEEE80211W */

+ 28 - 0
components/wpa_supplicant/src/crypto/ccmp.h

@@ -0,0 +1,28 @@
+/*
+ * wlantest - IEEE 802.11 protocol monitoring and testing tool
+ * Copyright (c) 2010-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifdef CONFIG_IEEE80211W
+#ifndef CCMP_H
+#define CCMP_H
+
+u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
+		  size_t data_len, size_t *decrypted_len);
+u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
+		  u8 *pn, int keyid, size_t *encrypted_len);
+u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
+		      const u8 *frame, size_t len,
+		      size_t hdrlen, const u8 *pn, int keyid,
+		      size_t *encrypted_len);
+void ccmp_get_pn(u8 *pn, const u8 *data);
+u8 * ccmp_256_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
+		      size_t data_len, size_t *decrypted_len);
+u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
+		      u8 *pn, int keyid, size_t *encrypted_len);
+
+#endif /* CCMP_H */
+#endif /* CONFIG_IEEE80211W */

+ 5 - 1
components/wpa_supplicant/src/crypto/crypto_ops.c

@@ -20,6 +20,7 @@
 #include "sha1.h"
 #include "aes.h"
 #include "esp_wpa.h"
+#include "ccmp.h"
 
 /* 
  * This structure is used to set the cyrpto callback function for station to connect when in security mode.
@@ -48,7 +49,10 @@ const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = {
     .aes_encrypt_deinit = (esp_aes_encrypt_deinit_t)aes_encrypt_deinit,
     .aes_decrypt = (esp_aes_decrypt_t)aes_decrypt,
     .aes_decrypt_init = (esp_aes_decrypt_init_t)aes_decrypt_init,
-    .aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit
+    .aes_decrypt_deinit = (esp_aes_decrypt_deinit_t)aes_decrypt_deinit,
+    .omac1_aes_128 = (esp_omac1_aes_128_t)omac1_aes_128,
+    .ccmp_decrypt = (esp_ccmp_decrypt_t)ccmp_decrypt,
+    .ccmp_encrypt = (esp_ccmp_encrypt_t)ccmp_encrypt
 };
 
 const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs = {

+ 12 - 1
components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h

@@ -63,7 +63,8 @@ enum {
     WPA2_AUTH_PSK       = 0x05,
     WPA_AUTH_CCKM       = 0x06,
     WPA2_AUTH_CCKM      = 0x07,
-    WPA2_AUTH_INVALID   = 0x08,
+    WPA2_AUTH_PSK_SHA256= 0x08,
+    WPA2_AUTH_INVALID   = 0x09,
 };
 
 typedef enum {
@@ -163,6 +164,13 @@ typedef struct {
     uint32_t arg_size;
 } wifi_ipc_config_t;
 
+#define WPA_IGTK_LEN 16
+typedef struct {
+    uint8_t keyid[2];
+    uint8_t pn[6];
+    uint8_t igtk[WPA_IGTK_LEN];
+} wifi_wpa_igtk_t;
+
 uint8_t *esp_wifi_ap_get_prof_pmk_internal(void);
 struct wifi_ssid *esp_wifi_ap_get_prof_ap_ssid_internal(void);
 uint8_t esp_wifi_ap_get_prof_authmode_internal(void);
@@ -217,5 +225,8 @@ esp_err_t esp_wifi_internal_supplicant_header_md5_check(const char *md5);
 int esp_wifi_sta_update_ap_info_internal(void);
 uint8_t *esp_wifi_sta_get_ap_info_prof_pmk_internal(void);
 esp_err_t esp_wifi_set_wps_start_flag_internal(bool start);
+uint16_t esp_wifi_sta_pmf_enabled(void);
+wifi_cipher_type_t esp_wifi_sta_get_mgmt_group_cipher(void);
+int esp_wifi_set_igtk_internal(uint8_t if_index, const wifi_wpa_igtk_t *igtk);
 
 #endif /* _ESP_WIFI_DRIVER_H_ */

+ 3 - 29
components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c

@@ -158,32 +158,6 @@ void  wpa_sta_connect(uint8_t *bssid)
     WPA_ASSERT(ret == 0);
 }
 
-int cipher_type_map(int wpa_cipher)
-{
-    switch (wpa_cipher) {
-    case WPA_CIPHER_NONE:
-        return WIFI_CIPHER_TYPE_NONE;
-
-    case WPA_CIPHER_WEP40:
-        return WIFI_CIPHER_TYPE_WEP40;
-
-    case WPA_CIPHER_WEP104:
-        return WIFI_CIPHER_TYPE_WEP104;
-
-    case WPA_CIPHER_TKIP:
-        return WIFI_CIPHER_TYPE_TKIP;
-
-    case WPA_CIPHER_CCMP:
-        return WIFI_CIPHER_TYPE_CCMP;
-
-    case WPA_CIPHER_CCMP|WPA_CIPHER_TKIP:
-        return WIFI_CIPHER_TYPE_TKIP_CCMP;
-
-    default:
-        return WIFI_CIPHER_TYPE_UNKNOWN;
-    }
-}
-
 int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data)
 {
     struct wpa_ie_data ie;
@@ -191,12 +165,12 @@ int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t
 
     ret = wpa_parse_wpa_ie(wpa_ie, wpa_ie_len, &ie);
     data->proto = ie.proto;
-    data->pairwise_cipher = cipher_type_map(ie.pairwise_cipher);
-    data->group_cipher = cipher_type_map(ie.group_cipher);
+    data->pairwise_cipher = cipher_type_map_supp_to_public(ie.pairwise_cipher);
+    data->group_cipher = cipher_type_map_supp_to_public(ie.group_cipher);
     data->key_mgmt = ie.key_mgmt;
     data->capabilities = ie.capabilities;
     data->pmkid = ie.pmkid;
-    data->mgmt_group_cipher = cipher_type_map(ie.mgmt_group_cipher);
+    data->mgmt_group_cipher = cipher_type_map_supp_to_public(ie.mgmt_group_cipher);
 
     return ret;
 }

+ 113 - 6
components/wpa_supplicant/src/rsn_supp/wpa.c

@@ -27,6 +27,7 @@
 #include "crypto/crypto.h"
 #include "crypto/sha1.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/ccmp.h"
 
 /**
  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
@@ -46,7 +47,7 @@
 /* fix buf for tx for now */
 #define WPA_TX_MSG_BUFF_MAXLEN 200
 
-#define ASSOC_IE_LEN 24 + 2 + PMKID_LEN
+#define ASSOC_IE_LEN 24 + 2 + PMKID_LEN + RSN_SELECTOR_LEN
 u8 assoc_ie_buf[ASSOC_IE_LEN+2]; 
 
 void set_assoc_ie(u8 * assoc_buf);
@@ -76,6 +77,65 @@ void   eapol_sm_notify_eap_success(Boolean success)
 {
 
 }
+
+wifi_cipher_type_t cipher_type_map_supp_to_public(uint32_t wpa_cipher)
+{
+    switch (wpa_cipher) {
+    case WPA_CIPHER_NONE:
+        return WIFI_CIPHER_TYPE_NONE;
+
+    case WPA_CIPHER_WEP40:
+        return WIFI_CIPHER_TYPE_WEP40;
+
+    case WPA_CIPHER_WEP104:
+        return WIFI_CIPHER_TYPE_WEP104;
+
+    case WPA_CIPHER_TKIP:
+        return WIFI_CIPHER_TYPE_TKIP;
+
+    case WPA_CIPHER_CCMP:
+        return WIFI_CIPHER_TYPE_CCMP;
+
+    case WPA_CIPHER_CCMP|WPA_CIPHER_TKIP:
+        return WIFI_CIPHER_TYPE_TKIP_CCMP;
+
+    case WPA_CIPHER_AES_128_CMAC:
+        return WIFI_CIPHER_TYPE_AES_CMAC128;
+
+    default:
+        return WIFI_CIPHER_TYPE_UNKNOWN;
+    }
+}
+
+uint32_t cipher_type_map_public_to_supp(wifi_cipher_type_t cipher)
+{
+    switch (cipher) {
+    case WIFI_CIPHER_TYPE_NONE:
+        return WPA_CIPHER_NONE;
+
+    case WIFI_CIPHER_TYPE_WEP40:
+        return WPA_CIPHER_WEP40;
+
+    case WIFI_CIPHER_TYPE_WEP104:
+        return WPA_CIPHER_WEP104;
+
+    case WIFI_CIPHER_TYPE_TKIP:
+        return WPA_CIPHER_TKIP;
+
+    case WIFI_CIPHER_TYPE_CCMP:
+        return WPA_CIPHER_CCMP;
+
+    case WIFI_CIPHER_TYPE_TKIP_CCMP:
+        return WPA_CIPHER_CCMP|WPA_CIPHER_TKIP;
+
+    case WIFI_CIPHER_TYPE_AES_CMAC128:
+        return WPA_CIPHER_AES_128_CMAC;
+
+    default:
+        return WPA_CIPHER_NONE;
+    }
+}
+
 /**
  * get_bssid - Get the current BSSID
  * @priv: private driver interface data
@@ -622,7 +682,7 @@ int   wpa_supplicant_install_ptk(struct wpa_sm *sm)
         #endif    
         return -1;
     }
-       
+
     if (sm->wpa_ptk_rekey) {
         eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
         eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@@ -932,7 +992,29 @@ void wpa_report_ie_mismatch(struct wpa_sm *sm, const u8 *src_addr,
 int   ieee80211w_set_keys(struct wpa_sm *sm,
                    struct wpa_eapol_ie_parse *ie)
 {
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+		return -1;
+	}
+
+	if (ie->igtk) {
+		const wifi_wpa_igtk_t *igtk;
+		uint16_t keyidx;
+
+		if (ie->igtk_len != sizeof(*igtk)) {
+			return -1;
+		}
+		igtk = (const wifi_wpa_igtk_t*)ie->igtk;
+		keyidx = WPA_GET_LE16(igtk->keyid);
+		if (keyidx > 4095) {
+			return -1;
+		}
+		return esp_wifi_set_igtk_internal(ESP_IF_WIFI_STA, igtk);
+	}
+	return 0;
+#else
      return 0;
+#endif
 }
 
   int   wpa_supplicant_validate_ie(struct wpa_sm *sm,
@@ -1169,7 +1251,7 @@ int   ieee80211w_set_keys(struct wpa_sm *sm,
         }
     }
     
-    if (ieee80211w_set_keys(sm, &ie) < 0) {
+    if (sm->pmf_cfg.capable && ieee80211w_set_keys(sm, &ie) < 0) {
         #ifdef DEBUG_PRINT    
         wpa_printf(MSG_DEBUG, "RSN: Failed to configure IGTK");
         #endif    
@@ -1746,7 +1828,11 @@ int   wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)
     }
     key_info = WPA_GET_BE16(key->key_info);
     ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+
     if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+#ifdef CONFIG_IEEE80211W
+        ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+#endif
         ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 #ifdef DEBUG_PRINT    
         wpa_printf(MSG_DEBUG, "WPA: Unsupported EAPOL-Key descriptor "
@@ -1755,6 +1841,14 @@ int   wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)
         goto out;
     }
 
+#ifdef CONFIG_IEEE80211W
+    if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
+        if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+            goto out;
+        }
+    } else
+#endif
+
     if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
         ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 #ifdef DEBUG_PRINT    
@@ -1977,10 +2071,13 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
     struct wpa_sm *sm = &gWpaSm;
 
     sm->proto = wpa_proto;
-    if (auth_mode == WPA2_AUTH_ENT)
+    if (auth_mode == WPA2_AUTH_ENT) {
         sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X; /* for wpa2 enterprise */
-    else
+    } else if (auth_mode == WPA2_AUTH_PSK) {
         sm->key_mgmt = WPA_KEY_MGMT_PSK;  /* fixed to PSK for now */
+    } else if (auth_mode == WPA2_AUTH_PSK_SHA256) {
+        sm->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+    }
 }
 
 void wpa_set_pmk(uint8_t *pmk)
@@ -2011,6 +2108,16 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
         pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0);
         wpa_sm_set_pmk_from_pmksa(sm);
     }
+
+#ifdef CONFIG_IEEE80211W
+    if (esp_wifi_sta_pmf_enabled()) {
+        wifi_config_t wifi_cfg;
+
+        esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg);
+        sm->pmf_cfg = wifi_cfg.sta.pmf_cfg;
+        sm->mgmt_group_cipher = cipher_type_map_public_to_supp(esp_wifi_sta_get_mgmt_group_cipher());
+    }
+#endif
     set_assoc_ie(assoc_ie_buf); /* use static buffer */
     res = wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
     if (res < 0) 
@@ -2234,10 +2341,10 @@ bool wpa_sta_in_4way_handshake(void)
     return false;
 }
 
-
 bool wpa_sta_is_cur_pmksa_set(void) {
     struct wpa_sm *sm = &gWpaSm;
     return (pmksa_cache_get_current(sm) != NULL);
 }
+
 #endif // ESP_SUPPLICANT
 

+ 5 - 0
components/wpa_supplicant/src/rsn_supp/wpa.h

@@ -25,6 +25,7 @@
 #include "utils/common.h"
 #include "common/defs.h"
 #include "common/wpa_common.h"
+#include "esp_wifi_types.h"
 #include "esp_wifi_crypto_types.h"
 #include "wpa_i.h"
 
@@ -128,5 +129,9 @@ char * dup_binstr(const void *src, size_t len);
 
 int wpa_michael_mic_failure(u16 isunicast);
 
+wifi_cipher_type_t cipher_type_map_supp_to_public(uint32_t wpa_cipher);
+
+uint32_t cipher_type_map_supp_to_public(wifi_cipher_type_t cipher);
+
 #endif /* WPA_H */
 

+ 1 - 0
components/wpa_supplicant/src/rsn_supp/wpa_i.h

@@ -89,6 +89,7 @@ struct wpa_sm {
     u16 key_info;       //used for txcallback param
     u16 txcb_flags;
     bool   ap_notify_completed_rsne;
+    wifi_pmf_config_t pmf_cfg;
 };
 
 /**

+ 16 - 4
components/wpa_supplicant/src/rsn_supp/wpa_ie.c

@@ -214,10 +214,12 @@ static int  wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
     /* RSN Capabilities */
     capab = 0;
 #ifdef CONFIG_IEEE80211W
-    if (sm->mfp)
+    if (sm->pmf_cfg.capable) {
         capab |= WPA_CAPABILITY_MFPC;
-    if (sm->mfp == 2)
-        capab |= WPA_CAPABILITY_MFPR;
+        if (sm->pmf_cfg.required) {
+            capab |= WPA_CAPABILITY_MFPR;
+	}
+    }
 #endif /* CONFIG_IEEE80211W */
     WPA_PUT_LE16(pos, capab);
     pos += 2;
@@ -234,7 +236,7 @@ static int  wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
 #ifdef CONFIG_IEEE80211W
     if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
         if (!sm->cur_pmksa) {
-            /* PMKID Count */
+            /* 0 PMKID Count */
             WPA_PUT_LE16(pos, 0);
             pos += 2;
         }
@@ -329,6 +331,16 @@ static int  wpa_parse_generic(const u8 *pos, const u8 *end,
 			    pos, pos[1] + 2);
 		return 0;
 	}
+#ifdef CONFIG_IEEE80211W
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+#endif
 	return 0;
 }