diff --git a/components/esp_wifi/include/esp_wifi_crypto_types.h b/components/esp_wifi/include/esp_wifi_crypto_types.h index df2388259b..b626845c67 100644 --- a/components/esp_wifi/include/esp_wifi_crypto_types.h +++ b/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; /** diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index ad29f93bdd..fd79a1b743 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/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. diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index f3c39df1c4..d88a262fbd 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit f3c39df1c428b065e05a431c6f8685790531baf5 +Subproject commit d88a262fbdf35e5abb372280eb08008749c3faa0 diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 27728d1d62..364fe6b063 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/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 ) diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index e85e9979fb..8553cedc87 100644 --- a/components/wpa_supplicant/component.mk +++ b/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 diff --git a/components/wpa_supplicant/src/common/defs.h b/components/wpa_supplicant/src/common/defs.h index 2f4360ba98..f2fd1f6172 100644 --- a/components/wpa_supplicant/src/common/defs.h +++ b/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 */ diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index c04307052d..1eee98a0cf 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/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; } diff --git a/components/wpa_supplicant/src/crypto/aes-ccm.c b/components/wpa_supplicant/src/crypto/aes-ccm.c new file mode 100644 index 0000000000..ca3acc26e9 --- /dev/null +++ b/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 + * + * 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 */ diff --git a/components/wpa_supplicant/src/crypto/aes-omac1.c b/components/wpa_supplicant/src/crypto/aes-omac1.c new file mode 100644 index 0000000000..415b7955b3 --- /dev/null +++ b/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 + * + * 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); +} diff --git a/components/wpa_supplicant/src/crypto/aes.h b/components/wpa_supplicant/src/crypto/aes.h index ba384a9dae..309d24dbac 100644 --- a/components/wpa_supplicant/src/crypto/aes.h +++ b/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 */ diff --git a/components/wpa_supplicant/src/crypto/ccmp.c b/components/wpa_supplicant/src/crypto/ccmp.c new file mode 100644 index 0000000000..f5814a7844 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/ccmp.c @@ -0,0 +1,354 @@ +/* + * CTR with CBC-MAC Protocol (CCMP) + * Copyright (c) 2010-2012, Jouni Malinen + * + * 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 */ diff --git a/components/wpa_supplicant/src/crypto/ccmp.h b/components/wpa_supplicant/src/crypto/ccmp.h new file mode 100644 index 0000000000..aeca06022e --- /dev/null +++ b/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 + * + * 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 */ diff --git a/components/wpa_supplicant/src/crypto/crypto_ops.c b/components/wpa_supplicant/src/crypto/crypto_ops.c index f46d823dfe..ee1aee9401 100644 --- a/components/wpa_supplicant/src/crypto/crypto_ops.c +++ b/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 = { diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index 8ca0d91a36..4d26514168 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/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_ */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index 2cfc3e0d4a..326de38d7c 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/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; } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index cb9220fb74..432d591710 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/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 diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa.h index 73da8d67ba..ef958d72eb 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.h +++ b/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 */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_i.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h index 7bd78bd7e7..09b0072dff 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_i.h +++ b/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; }; /** diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index 5559392cab..dc1a1616bc 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/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; }