From d36663b79884d864e80ddd57d90c6e0c18468362 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Wed, 29 Apr 2020 18:47:23 +0530 Subject: [PATCH] wpa_supplicant: Support WPA3 4-way handshake, add config option 1. Add changes in 4-way handshake path to allow SAE key mgmt. 2. Support for configuring WAP3 at init time, added Kconfig option. 3. Handle and propagate error conditions properly. --- components/esp_wifi/Kconfig | 8 + components/esp_wifi/include/esp_wifi.h | 5 + components/esp_wifi/src/wifi_init.c | 7 + components/wpa_supplicant/component.mk | 2 +- components/wpa_supplicant/src/common/defs.h | 2 + components/wpa_supplicant/src/common/sae.c | 211 +++++++++++------- components/wpa_supplicant/src/common/sae.h | 4 +- .../wpa_supplicant/src/common/wpa_common.c | 5 +- .../wpa_supplicant/src/common/wpa_common.h | 1 + .../wpa_supplicant/src/crypto/aes_wrap.h | 5 + .../src/esp_supplicant/esp_wpa3.c | 48 ++-- components/wpa_supplicant/src/rsn_supp/wpa.c | 16 +- components/wpa_supplicant/test/test_sae.c | 14 +- 13 files changed, 210 insertions(+), 118 deletions(-) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 306dfc8f0c..0dd122d611 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -295,6 +295,14 @@ menu "Wi-Fi" When this option is disabled, more than 17Kbytes of IRAM memory will be saved but Wi-Fi performance will be reduced. + config ESP32_WIFI_ENABLE_WPA3_SAE + bool "Enable WPA3-Personal" + default n + help + Select this option to allow the device to establish a WPA3-Personal connection with eligible AP's. + PMF (Protected Management Frames) is a prerequisite feature for a WPA3 connection, it needs to be + explicitly configured before attempting connection. Please refer to the Wi-Fi Driver API Guide for details. + endmenu # Wi-Fi menu "PHY" diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index be481ee27c..05dd7df568 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -110,6 +110,7 @@ typedef struct { int wifi_task_core_id; /**< WiFi Task Core ID */ int beacon_max_len; /**< WiFi softAP maximum length of the beacon */ int mgmt_sbuf_num; /**< WiFi management short buffer number, the minimum value is 6, the maximum value is 32 */ + uint64_t feature_caps; /**< Enables additional WiFi features and capabilities */ int magic; /**< WiFi init magic number, it should be the last field */ } wifi_init_config_t; @@ -156,6 +157,7 @@ typedef struct { #endif extern const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs; +extern uint64_t g_wifi_feature_caps; #define WIFI_INIT_CONFIG_MAGIC 0x1F2F3F4F @@ -189,6 +191,8 @@ extern const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs; #define WIFI_MGMT_SBUF_NUM 32 #endif +#define CONFIG_FEATURE_WPA3_SAE_BIT (1<<0) + #define WIFI_INIT_CONFIG_DEFAULT() { \ .event_handler = &esp_event_send, \ .osi_funcs = &g_wifi_osi_funcs, \ @@ -208,6 +212,7 @@ extern const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs; .wifi_task_core_id = WIFI_TASK_CORE_ID,\ .beacon_max_len = WIFI_SOFTAP_BEACON_MAX_LEN, \ .mgmt_sbuf_num = WIFI_MGMT_SBUF_NUM, \ + .feature_caps = g_wifi_feature_caps, \ .magic = WIFI_INIT_CONFIG_MAGIC\ }; diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 610dbff458..6e54e523b9 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -37,6 +37,13 @@ static esp_pm_lock_handle_t s_wifi_modem_sleep_lock; /* Callback function to update WiFi MAC time */ wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb = NULL; +/* Set additional WiFi features and capabilities */ +uint64_t g_wifi_feature_caps = +#if CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE + CONFIG_FEATURE_WPA3_SAE_BIT | +#endif +0; + static const char* TAG = "wifi_init"; static void __attribute__((constructor)) s_set_default_wifi_log_level() diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index 8553cedc87..dc319339b7 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 += -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 +CFLAGS += -DCONFIG_WPA3_SAE -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 f2fd1f6172..ec4e69ab05 100644 --- a/components/wpa_supplicant/src/common/defs.h +++ b/components/wpa_supplicant/src/common/defs.h @@ -50,6 +50,7 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_CCKM | WPA_KEY_MGMT_OSEN | + WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_IEEE8021X_SUITE_B | WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)); @@ -82,6 +83,7 @@ static inline int wpa_key_mgmt_sha256(int akm) return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_OSEN | + WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_IEEE8021X_SUITE_B)); } diff --git a/components/wpa_supplicant/src/common/sae.c b/components/wpa_supplicant/src/common/sae.c index 3283c334fe..66f5f3fed2 100644 --- a/components/wpa_supplicant/src/common/sae.c +++ b/components/wpa_supplicant/src/common/sae.c @@ -42,7 +42,7 @@ int sae_set_group(struct sae_data *sae, int group) sae_clear_data(sae); tmp = sae->tmp = os_zalloc(sizeof(*tmp)); if (tmp == NULL) - return -1; + return ESP_FAIL; /* First, check if this is an ECC group */ tmp->ec = crypto_ec_init(group); @@ -53,7 +53,7 @@ int sae_set_group(struct sae_data *sae, int group) tmp->prime_len = crypto_ec_prime_len(tmp->ec); tmp->prime = crypto_ec_get_prime(tmp->ec); tmp->order = crypto_ec_get_order(tmp->ec); - return 0; + return ESP_OK; } /* Not an ECC group, check FFC */ @@ -65,14 +65,14 @@ int sae_set_group(struct sae_data *sae, int group) tmp->prime_len = tmp->dh->prime_len; if (tmp->prime_len > SAE_MAX_PRIME_LEN) { sae_clear_data(sae); - return -1; + return ESP_FAIL; } tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime, tmp->prime_len); if (tmp->prime_buf == NULL) { sae_clear_data(sae); - return -1; + return ESP_FAIL; } tmp->prime = tmp->prime_buf; @@ -80,17 +80,17 @@ int sae_set_group(struct sae_data *sae, int group) tmp->dh->order_len); if (tmp->order_buf == NULL) { sae_clear_data(sae); - return -1; + return ESP_FAIL; } tmp->order = tmp->order_buf; - return 0; + return ESP_OK; } /* Unsupported group */ wpa_printf(MSG_DEBUG, "SAE: Group %d not supported by the crypto library", group); - return -1; + return ESP_FAIL; } void sae_clear_temp_data(struct sae_data *sae) @@ -236,7 +236,7 @@ static int is_quadratic_residue_blind(struct sae_data *sae, */ r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd); if (!r) - return -1; + return ESP_FAIL; num = crypto_bignum_init(); if (!num || @@ -293,22 +293,22 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, bits = crypto_ec_prime_len_bits(sae->tmp->ec); if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", prime, sae->tmp->prime_len, pwd_value, bits) < 0) - return -1; + return ESP_FAIL; if (bits % 8) buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, sae->tmp->prime_len); if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0) - return 0; + return ESP_OK; x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); if (!x_cand) - return -1; + return ESP_FAIL; y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand); if (!y_sqr) { crypto_bignum_deinit(x_cand, 1); - return -1; + return ESP_FAIL; } res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr); @@ -337,14 +337,14 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value, bits) < 0) - return -1; + return ESP_FAIL; wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, sae->tmp->prime_len); if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0) { wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p"); - return 0; + return ESP_OK; } /* PWE = pwd-value^((p-1)/r) modulo p */ @@ -380,13 +380,13 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, if (res < 0) { wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE"); - return -1; + return ESP_FAIL; } /* if (PWE > 1) --> found */ if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) { wpa_printf(MSG_DEBUG, "SAE: PWE <= 1"); - return 0; + return ESP_OK; } wpa_printf(MSG_DEBUG, "SAE: PWE found"); @@ -450,12 +450,12 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, if (dummy_password_len > sizeof(dummy_password)) dummy_password_len = sizeof(dummy_password); if (random_get_bytes(dummy_password, dummy_password_len) < 0) - return -1; + return ESP_FAIL; prime_len = sae->tmp->prime_len; if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), prime_len) < 0) - return -1; + return ESP_FAIL; bits = crypto_ec_prime_len_bits(sae->tmp->ec); /* @@ -464,7 +464,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, */ if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits, &qr, &qnr) < 0) - return -1; + return ESP_FAIL; wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", password, password_len); @@ -579,7 +579,7 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, if (sae->tmp->pwe_ffc == NULL) { sae->tmp->pwe_ffc = crypto_bignum_init(); if (sae->tmp->pwe_ffc == NULL) - return -1; + return ESP_FAIL; } wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", @@ -638,7 +638,7 @@ static int sae_derive_commit_element_ecc(struct sae_data *sae, sae->tmp->own_commit_element_ecc = crypto_ec_point_init(sae->tmp->ec); if (!sae->tmp->own_commit_element_ecc) - return -1; + return ESP_FAIL; } if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask, @@ -646,10 +646,10 @@ static int sae_derive_commit_element_ecc(struct sae_data *sae, crypto_ec_point_invert(sae->tmp->ec, sae->tmp->own_commit_element_ecc) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } static int sae_derive_commit_element_ffc(struct sae_data *sae, @@ -659,7 +659,7 @@ static int sae_derive_commit_element_ffc(struct sae_data *sae, if (!sae->tmp->own_commit_element_ffc) { sae->tmp->own_commit_element_ffc = crypto_bignum_init(); if (!sae->tmp->own_commit_element_ffc) - return -1; + return ESP_FAIL; } if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime, @@ -668,10 +668,10 @@ static int sae_derive_commit_element_ffc(struct sae_data *sae, sae->tmp->prime, sae->tmp->own_commit_element_ffc) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } static int sae_derive_commit(struct sae_data *sae) @@ -689,13 +689,13 @@ static int sae_derive_commit(struct sae_data *sae) * theoretical infinite loop, break out after 100 * attemps. */ - return -1; + return ESP_FAIL; } mask = sae_get_rand_and_mask(sae); if (mask == NULL) { wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask"); - return -1; + return ESP_FAIL; } /* commit-scalar = (rand + mask) modulo r */ @@ -733,8 +733,8 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2, password_len, identifier) < 0) || sae_derive_commit(sae) < 0) - return -1; - return 0; + return ESP_FAIL; + return ESP_OK; } static int sae_derive_k_ecc(struct sae_data *sae, u8 *k) @@ -861,17 +861,17 @@ int sae_process_commit(struct sae_data *sae) (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) || (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) || sae_derive_keys(sae, k) < 0) - return -1; - return 0; + return ESP_FAIL; + return ESP_OK; } -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, +int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, const struct wpabuf *token, const char *identifier) { u8 *pos; if (sae->tmp == NULL) - return; + return ESP_FAIL; wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */ if (token) { @@ -880,23 +880,32 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, wpabuf_head(token), wpabuf_len(token)); } pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, - sae->tmp->prime_len, sae->tmp->prime_len); + if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, + sae->tmp->prime_len, sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum operation on own commit scalar"); + return ESP_FAIL; + } wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar", pos, sae->tmp->prime_len); if (sae->tmp->ec) { pos = wpabuf_put(buf, 2 * sae->tmp->prime_len); - crypto_ec_point_to_bin(sae->tmp->ec, - sae->tmp->own_commit_element_ecc, - pos, pos + sae->tmp->prime_len); + if (crypto_ec_point_to_bin(sae->tmp->ec, + sae->tmp->own_commit_element_ecc, + pos, pos + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point"); + return ESP_FAIL; + } wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)", pos, sae->tmp->prime_len); wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)", pos + sae->tmp->prime_len, sae->tmp->prime_len); } else { pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, - sae->tmp->prime_len, sae->tmp->prime_len); + if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, + sae->tmp->prime_len, sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum operation on commit elem ffc"); + return ESP_FAIL; + } wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", pos, sae->tmp->prime_len); } @@ -910,6 +919,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s", identifier); } + return ESP_OK; } u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group) @@ -1299,7 +1309,7 @@ static void sae_cn_confirm(struct sae_data *sae, const u8 *sc, confirm); } -static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, +static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, const struct crypto_bignum *scalar1, const struct crypto_ec_point *element1, const struct crypto_bignum *scalar2, @@ -1309,40 +1319,54 @@ static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN]; u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN]; - crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1, - element_b1 + sae->tmp->prime_len); - crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2, - element_b2 + sae->tmp->prime_len); + if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1, + element_b1 + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point"); + return ESP_FAIL; + } + if (crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2, + element_b2 + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point"); + return ESP_FAIL; + } sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len, scalar2, element_b2, 2 * sae->tmp->prime_len, confirm); + return ESP_OK; } -static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc, - const struct crypto_bignum *scalar1, - const struct crypto_bignum *element1, - const struct crypto_bignum *scalar2, - const struct crypto_bignum *element2, - u8 *confirm) +static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc, + const struct crypto_bignum *scalar1, + const struct crypto_bignum *element1, + const struct crypto_bignum *scalar2, + const struct crypto_bignum *element2, + u8 *confirm) { u8 element_b1[SAE_MAX_PRIME_LEN]; u8 element_b2[SAE_MAX_PRIME_LEN]; - crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1), - sae->tmp->prime_len); - crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2), - sae->tmp->prime_len); + if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1), + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while generating SAE confirm - e1"); + return ESP_FAIL; + } + if (crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2), + sae->tmp->prime_len) < 0) { + wpa_printf(MSG_ERROR, "SAE: failed bignum op while generating SAE confirm - e2"); + return ESP_FAIL; + } sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len, scalar2, element_b2, sae->tmp->prime_len, confirm); + return ESP_OK; } -void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) +int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) { const u8 *sc; if (sae->tmp == NULL) - return; + return ESP_FAIL; /* Send-Confirm */ sc = wpabuf_put(buf, 0); @@ -1350,18 +1374,26 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) if (sae->send_confirm < 0xffff) sae->send_confirm++; - if (sae->tmp->ec) - sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ecc, - sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ecc, - wpabuf_put(buf, SHA256_MAC_LEN)); - else - sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ffc, - sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ffc, - wpabuf_put(buf, SHA256_MAC_LEN)); + if (sae->tmp->ec) { + if (sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ecc, + sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ecc, + wpabuf_put(buf, SHA256_MAC_LEN))) { + wpa_printf(MSG_ERROR, "SAE: failed generate SAE confirm (ecc)"); + return ESP_FAIL; + } + } else { + if (sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ffc, + sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ffc, + wpabuf_put(buf, SHA256_MAC_LEN))) { + wpa_printf(MSG_ERROR, "SAE: failed generate SAE confirm (ffc)"); + return ESP_FAIL; + } + } + return ESP_OK; } int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) @@ -1370,28 +1402,35 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) if (len < 2 + SHA256_MAC_LEN) { wpa_printf(MSG_DEBUG, "SAE: Too short confirm message"); - return -1; + return ESP_FAIL; } wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data)); if (sae->tmp == NULL) { wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available"); - return -1; + return ESP_FAIL; } - if (sae->tmp->ec) - sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ecc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ecc, - verifier); - else - sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ffc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ffc, - verifier); + if (sae->tmp->ec) { + if (sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ecc, + sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ecc, + verifier)) { + wpa_printf(MSG_ERROR, "SAE: failed to check SAE confirm (ecc)"); + return ESP_FAIL; + } + } else { + if (sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, + sae->tmp->peer_commit_element_ffc, + sae->tmp->own_commit_scalar, + sae->tmp->own_commit_element_ffc, + verifier)) { + wpa_printf(MSG_ERROR, "SAE: failed check SAE confirm (ffc)"); + return ESP_FAIL; + } + } if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) { wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); @@ -1399,10 +1438,10 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) data + 2, SHA256_MAC_LEN); wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier", verifier, SHA256_MAC_LEN); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } const char * sae_state_txt(enum sae_state state) diff --git a/components/wpa_supplicant/src/common/sae.h b/components/wpa_supplicant/src/common/sae.h index b0160c458b..6c99a73cec 100644 --- a/components/wpa_supplicant/src/common/sae.h +++ b/components/wpa_supplicant/src/common/sae.h @@ -77,11 +77,11 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2, const u8 *password, size_t password_len, const char *identifier, struct sae_data *sae); int sae_process_commit(struct sae_data *sae); -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, +int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, const struct wpabuf *token, const char *identifier); u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups); -void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); +int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf); int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len); u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group); const char * sae_state_txt(enum sae_state state); diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index 765590042d..ba909fee26 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/components/wpa_supplicant/src/common/wpa_common.c @@ -394,6 +394,9 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, memcpy(mic, hash, MD5_MAC_LEN); break; #ifdef CONFIG_IEEE80211W +#ifdef CONFIG_WPA3_SAE + case WPA_KEY_INFO_TYPE_AKM_DEFINED: +#endif case WPA_KEY_INFO_TYPE_AES_128_CMAC: return omac1_aes_128(key, buf, len, mic); #endif @@ -514,13 +517,11 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, WPA_NONCE_LEN); } -#ifdef CONFIG_IEEE80211W if (use_sha256) { sha256_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); } else -#endif /* CONFIG_IEEE80211W */ { sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); } diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index 12a13e1a08..f88e8a6fac 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -121,6 +121,7 @@ /* IEEE 802.11, 8.5.2 EAPOL-Key frames */ #define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) +#define WPA_KEY_INFO_TYPE_AKM_DEFINED 0 #define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) #define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) #define WPA_KEY_INFO_TYPE_AES_128_CMAC 3 diff --git a/components/wpa_supplicant/src/crypto/aes_wrap.h b/components/wpa_supplicant/src/crypto/aes_wrap.h index e6912054f0..d25d113b44 100644 --- a/components/wpa_supplicant/src/crypto/aes_wrap.h +++ b/components/wpa_supplicant/src/crypto/aes_wrap.h @@ -24,11 +24,16 @@ int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); +int __must_check omac1_aes_vector(const u8 *key, size_t key_len, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac); +int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, + u8 *mac); int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, u8 *data, size_t data_len); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c index d98436a1b7..014cabb0de 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3.c @@ -14,7 +14,7 @@ #ifdef CONFIG_WPA3_SAE -#include "../common/sae.h" +#include "common/sae.h" #include "esp_wifi_driver.h" #include "rsn_supp/wpa.h" @@ -47,11 +47,17 @@ static struct wpabuf *wpa3_build_sae_commit(u8 *bssid) return NULL; } - // For reuse PWE after retry case - // memcpy(g_sae_data.tmp->bssid, bssid, ETH_ALEN); - buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); - sae_write_commit(&g_sae_data, buf, NULL, NULL); //no token + if (!buf) { + wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for commit msg"); + return NULL; + } + + if (sae_write_commit(&g_sae_data, buf, NULL, NULL) != ESP_OK) { + wpa_printf(MSG_ERROR, "wpa3: failed to write SAE commit msg"); + wpabuf_free(buf); + return NULL; + } g_sae_data.state = SAE_COMMITTED; return buf; @@ -65,7 +71,16 @@ static struct wpabuf *wpa3_build_sae_confirm(void) return NULL; buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); - sae_write_confirm(&g_sae_data, buf); + if (!buf) { + wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for confirm msg"); + return NULL; + } + + if (sae_write_confirm(&g_sae_data, buf) != ESP_OK) { + wpa_printf(MSG_ERROR, "wpa3: failed to write SAE confirm msg"); + wpabuf_free(buf); + return NULL; + } g_sae_data.state = SAE_CONFIRMED; return buf; @@ -100,22 +115,22 @@ static int wpa3_parse_sae_commit(u8 *buf, u32 len) if (g_sae_data.state != SAE_COMMITTED) { wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", g_sae_data.state); - return -1; + return ESP_FAIL; } ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups); if (ret) { wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret); - return -1; + return ESP_FAIL; } ret = sae_process_commit(&g_sae_data); if (ret) { wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret); - return -1; + return ESP_FAIL; } - return 0; + return ESP_OK; } static int wpa3_parse_sae_confirm(u8 *buf, u32 len) @@ -123,21 +138,24 @@ static int wpa3_parse_sae_confirm(u8 *buf, u32 len) if (g_sae_data.state != SAE_CONFIRMED) { wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!", g_sae_data.state); - return -1; + return ESP_FAIL; } - sae_check_confirm(&g_sae_data, buf, len); + if (sae_check_confirm(&g_sae_data, buf, len) != ESP_OK) { + wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE confirm"); + return ESP_FAIL; + } g_sae_data.state = SAE_ACCEPTED; wpa_set_pmk(g_sae_data.pmk); memcpy(esp_wifi_sta_get_ap_info_prof_pmk_internal(), g_sae_data.pmk, PMK_LEN); - return 0; + return ESP_OK; } static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type) { - int ret = 0; + int ret = ESP_OK; switch (sae_msg_type) { case SAE_MSG_COMMIT: @@ -149,7 +167,7 @@ static int wpa3_parse_sae_msg(u8 *buf, u32 len, u32 sae_msg_type) default: wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%d)!", sae_msg_type); - ret = -1; + ret = ESP_FAIL; break; } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 97fe59bf05..91dd50c170 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -245,6 +245,8 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; else if (sm->pairwise_cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; + else if (sm->key_mgmt == WPA_KEY_MGMT_SAE) + ver = 0; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; @@ -1661,7 +1663,8 @@ failed: return -1; } } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { + ver == WPA_KEY_INFO_TYPE_AES_128_CMAC || + sm->key_mgmt == WPA_KEY_MGMT_SAE) { u8 *buf; if (keydatalen % 8) { #ifdef DEBUG_PRINT @@ -1832,6 +1835,9 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && #ifdef CONFIG_IEEE80211W ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && +#ifdef CONFIG_WPA3_SAE + sm->key_mgmt != WPA_KEY_MGMT_SAE && +#endif #endif ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { #ifdef DEBUG_PRINT @@ -1843,14 +1849,16 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) #ifdef CONFIG_IEEE80211W if (wpa_key_mgmt_sha256(sm->key_mgmt)) { - if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { + if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && + sm->key_mgmt != WPA_KEY_MGMT_SAE) { goto out; } } else #endif if (sm->pairwise_cipher == WPA_CIPHER_CCMP && - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && + sm->key_mgmt != WPA_KEY_MGMT_SAE) { #ifdef DEBUG_PRINT wpa_printf(MSG_DEBUG, "WPA: CCMP is used, but EAPOL-Key " "descriptor version (%d) is not 2.", ver); @@ -2073,8 +2081,6 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode) sm->proto = wpa_proto; if (auth_mode == WPA2_AUTH_ENT) { sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X; /* for wpa2 enterprise */ - } 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; } else if (auth_mode == WPA3_AUTH_PSK) { diff --git a/components/wpa_supplicant/test/test_sae.c b/components/wpa_supplicant/test/test_sae.c index b87783d5fc..b5d244de72 100644 --- a/components/wpa_supplicant/test/test_sae.c +++ b/components/wpa_supplicant/test/test_sae.c @@ -85,7 +85,7 @@ TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") TEST_ASSERT( buf != NULL); - sae_write_commit(&sae, buf, NULL);// No anti-clogging token + sae_write_commit(&sae, buf, NULL, NULL);// No anti-clogging token /* Parsing commit created by self will be detected as reflection attack*/ TEST_ASSERT(sae_parse_commit(&sae, @@ -125,14 +125,14 @@ TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") /* STA1 creates commit msg buffer*/ buf1 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf1 != NULL); - sae_write_commit(&sae1, buf1, NULL);// No anti-clogging token + sae_write_commit(&sae1, buf1, NULL, NULL);// No anti-clogging token ESP_LOG_BUFFER_HEXDUMP("SAE: Commit1", wpabuf_mhead_u8(buf1), wpabuf_len(buf1), ESP_LOG_INFO); /* STA2 creates commit msg buffer*/ buf2 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf2 != NULL); - sae_write_commit(&sae2, buf2, NULL);// No anti-clogging token + sae_write_commit(&sae2, buf2, NULL, NULL);// No anti-clogging token ESP_LOG_BUFFER_HEXDUMP("SAE: Commit2", wpabuf_mhead_u8(buf2), wpabuf_len(buf2), ESP_LOG_INFO); sae1.state = SAE_COMMITTED; @@ -205,20 +205,20 @@ TEST_CASE("Test SAE functionality with ECC group", "[wpa3_sae]") TEST_ASSERT(sae_set_group(&sae2, IANA_SECP256R1) == 0); /* STA1 prepares for commit*/ - TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd1, strlen((const char *)pwd), NULL, &sae1) == 0); + TEST_ASSERT(sae_prepare_commit(addr1, addr2, pwd1, strlen((const char *)pwd1), NULL, &sae1) == 0); /* STA2 prepares for commit*/ - TEST_ASSERT(sae_prepare_commit(addr2, addr1, pwd2, strlen((const char *)pwd), NULL, &sae2) == 0); + TEST_ASSERT(sae_prepare_commit(addr2, addr1, pwd2, strlen((const char *)pwd2), NULL, &sae2) == 0); /* STA1 creates commit msg buffer*/ buf1 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf1 != NULL); - sae_write_commit(&sae1, buf1, NULL);// No anti-clogging token + sae_write_commit(&sae1, buf1, NULL, NULL);// No anti-clogging token /* STA2 creates commit msg buffer*/ buf2 = wpabuf_alloc2(SAE_COMMIT_MAX_LEN); TEST_ASSERT( buf2 != NULL); - sae_write_commit(&sae2, buf2, NULL);// No anti-clogging token + sae_write_commit(&sae2, buf2, NULL, NULL);// No anti-clogging token sae1.state = SAE_COMMITTED; sae2.state = SAE_COMMITTED;