Просмотр исходного кода

Merge branch 'feature/OWE_sta' into 'master'

WPA3 OWE support for station

See merge request espressif/esp-idf!16443
Jiang Jiang Jian 3 лет назад
Родитель
Сommit
da54350570

+ 0 - 4
components/esp_rom/esp32c2/ld/esp32c2.rom.ld

@@ -2082,7 +2082,6 @@ wep_decap = 0x40002028;
 dbg_hmac_rxtx_statis_dump = 0x4000202c;
 dbg_hmac_statis_dump = 0x40002030;
 ieee80211_send_action_vendor_spec = 0x40002034;
-ieee80211_send_mgmt = 0x40002038;
 ieee80211_deauth_construct = 0x40002040;
 ieee80211_disassoc_construct = 0x40002044;
 ieee80211_vnd_lora_ie_size = 0x40002048;
@@ -2091,7 +2090,6 @@ ieee80211_add_ssid = 0x40002050;
 ieee80211_add_rates = 0x40002054;
 ieee80211_add_xrates = 0x40002058;
 ieee80211_is_ht_cipher = 0x4000205c;
-ieee80211_assoc_req_construct = 0x40002060;
 ieee80211_assoc_resp_construct = 0x40002064;
 ieee80211_setup_lr_rates = 0x40002068;
 ieee80211_ht_node_init = 0x4000206c;
@@ -2144,10 +2142,8 @@ ieee80211_tx_mgt_cb = 0x4000212c;
 ieee80211_getcapinfo = 0x40002130;
 sta_rx_csa = 0x40002134;
 sta_recv_sa_query_resp = 0x40002144;
-ieee80211_parse_beacon = 0x40002148;
 ieee80211_set_max_rate = 0x4000214c;
 ic_set_sta = 0x40002150;
-ieee80211_match_security = 0x40002154;
 ieee80211_parse_wpa = 0x40002158;
 ieee80211_add_assoc_req_ies = 0x40002160;
 ieee80211_add_probe_req_ies = 0x40002164;

+ 9 - 0
components/esp_wifi/Kconfig

@@ -250,6 +250,15 @@ menu "Wi-Fi"
             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.
 
+    config ESP32_WIFI_ENABLE_WPA3_OWE_STA
+        bool "Enable OWE STA"
+        default y
+        select WPA_MBEDTLS_CRYPTO
+        help
+            Select this option to allow the device to establish OWE 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.
+
     config ESP_WIFI_SLP_IRAM_OPT
         bool "WiFi SLP IRAM speed optimization"
         select PM_SLP_DEFAULT_PARAMS_OPT

+ 5 - 1
components/esp_wifi/include/esp_wifi_types.h

@@ -47,6 +47,8 @@ typedef struct {
     wifi_country_policy_t policy;  /**< country policy */
 } wifi_country_t;
 
+/* Strength of authmodes */
+/* OPEN < WEP < WPA_PSK < OWE < WPA2_PSK = WPA_WPA2_PSK < WAPI_PSK < WPA2_ENTERPRISE < WPA3_PSK = WPA2_WPA3_PSK */
 typedef enum {
     WIFI_AUTH_OPEN = 0,         /**< authenticate mode : open */
     WIFI_AUTH_WEP,              /**< authenticate mode : WEP */
@@ -57,6 +59,7 @@ typedef enum {
     WIFI_AUTH_WPA3_PSK,         /**< authenticate mode : WPA3_PSK */
     WIFI_AUTH_WPA2_WPA3_PSK,    /**< authenticate mode : WPA2_WPA3_PSK */
     WIFI_AUTH_WAPI_PSK,         /**< authenticate mode : WAPI_PSK */
+    WIFI_AUTH_OWE,              /**< authenticate mode : OWE */
     WIFI_AUTH_MAX
 } wifi_auth_mode_t;
 
@@ -250,7 +253,8 @@ typedef struct {
     uint32_t btm_enabled:1;       /**< Whether BSS Transition Management is enabled for the connection */
     uint32_t mbo_enabled:1;       /**< Whether MBO is enabled for the connection */
     uint32_t ft_enabled:1;        /**< Whether FT is enabled for the connection */
-    uint32_t reserved:28;         /**< Reserved for future feature set */
+    uint32_t owe_enabled:1;       /**< Whether OWE is enabled for the connection */
+    uint32_t reserved:27;         /**< Reserved for future feature set */
 } wifi_sta_config_t;
 
 /** @brief Configuration data for ESP32 AP or STA.

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit dd7254fb02c05aaa4d0c5f6f805a6e28998f9ab5
+Subproject commit bf6e8acaa3625cd6bb84a8f1531f0c39f8f4a6f8

+ 6 - 1
components/wpa_supplicant/CMakeLists.txt

@@ -62,7 +62,8 @@ set(esp_srcs "esp_supplicant/src/esp_wpa2.c"
     "esp_supplicant/src/esp_wpas_glue.c"
     "esp_supplicant/src/esp_common.c"
     "esp_supplicant/src/esp_wps.c"
-    "esp_supplicant/src/esp_wpa3.c")
+    "esp_supplicant/src/esp_wpa3.c"
+    "esp_supplicant/src/esp_owe.c")
 if(CONFIG_ESP_WIFI_SOFTAP_SUPPORT)
     set(esp_srcs ${esp_srcs} "esp_supplicant/src/esp_hostap.c")
 endif()
@@ -141,6 +142,7 @@ else()
     "src/crypto/sha1-pbkdf2.c"
     "src/crypto/sha1.c"
     "src/crypto/sha256-internal.c"
+    "src/crypto/sha256.c"
     "src/crypto/sha384-internal.c"
     "src/crypto/sha512-internal.c"
     "src/crypto/sha256.c")
@@ -259,4 +261,7 @@ endif()
 if(CONFIG_WPA_WPS_SOFTAP_REGISTRAR)
     target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPS_REGISTRAR)
 endif()
+if(CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA)
+        target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_OWE_STA)
+endif()
 set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)

+ 197 - 0
components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c

@@ -3,6 +3,9 @@
  *
  * SPDX-License-Identifier: Apache-2.0
  */
+
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+
 #ifdef ESP_PLATFORM
 #include "esp_system.h"
 #include "mbedtls/bignum.h"
@@ -27,6 +30,12 @@
 
 #define ECP_PRV_DER_MAX_BYTES   29 + 3 * MBEDTLS_ECP_MAX_BYTES
 
+#ifdef CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT
+#define ACCESS_ECDH(S, var) S->var
+#else
+#define ACCESS_ECDH(S, var) S->ctx.mbed_ecdh.var
+#endif
+
 #ifdef CONFIG_ECC
 struct crypto_ec {
 	mbedtls_ecp_group group;
@@ -994,4 +1003,192 @@ int crypto_ec_write_pub_key(struct crypto_key *key, unsigned char **key_buf)
 
 	return len;
 }
+
+int crypto_mbedtls_get_grp_id(int group)
+{
+        switch(group) {
+        case IANA_SECP256R1:
+                return MBEDTLS_ECP_DP_SECP256R1;
+        case IANA_SECP384R1:
+                return MBEDTLS_ECP_DP_SECP384R1;
+        case IANA_SECP521R1:
+                return MBEDTLS_ECP_DP_SECP521R1;
+        default:
+                return MBEDTLS_ECP_DP_NONE;
+        }
+}
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+	mbedtls_ecdh_context *ctx = (mbedtls_ecdh_context *)ecdh;
+        if (!ctx) {
+                return;
+        }
+        mbedtls_ecdh_free(ctx);
+        os_free(ctx);
+        ctx = NULL;
+}
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+	mbedtls_ctr_drbg_context ctr_drbg;
+	mbedtls_entropy_context entropy;
+	mbedtls_ecdh_context *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+
+	if (!ctx) {
+		wpa_printf(MSG_ERROR, "Memory allocation failed for ecdh context");
+		goto fail;
+	}
+	mbedtls_ecdh_init(ctx);
+
+	if ((mbedtls_ecp_group_load(ACCESS_ECDH(&ctx, grp), crypto_mbedtls_get_grp_id(group))) != 0) {
+                wpa_printf(MSG_ERROR, "Failed to set up ECDH context with group info");
+                goto fail;
+	}
+
+	/* Initialize CTR_DRBG context */
+	mbedtls_ctr_drbg_init(&ctr_drbg);
+	mbedtls_entropy_init(&entropy);
+
+	/* Seed and setup CTR_DRBG entropy source for future reseeds */
+	if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0) != 0) {
+                wpa_printf(MSG_ERROR, "Seeding entropy source failed");
+                goto fail;
+	}
+
+	/* Generates ECDH keypair on elliptic curve */
+	if (mbedtls_ecdh_gen_public(ACCESS_ECDH(&ctx, grp), ACCESS_ECDH(&ctx, d), ACCESS_ECDH(&ctx, Q), mbedtls_ctr_drbg_random, &ctr_drbg)!=0) {
+                wpa_printf(MSG_ERROR, "ECDH keypair on curve failed");
+                goto fail;
+	}
+	return (struct crypto_ecdh *)ctx;
+fail:
+	return NULL;
+}
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int y)
+{
+	struct wpabuf *public_key = NULL;
+	uint8_t *buf = NULL;
+	mbedtls_ecdh_context *ctx = (mbedtls_ecdh_context *)ecdh;
+	size_t prime_len = ACCESS_ECDH(ctx, grp).pbits/8;
+
+	buf = os_zalloc(y ? prime_len : 2 * prime_len);
+        if (!buf) {
+                wpa_printf(MSG_ERROR, "Memory allocation failed");
+                return NULL;
+        }
+
+	/* Export an MPI into unsigned big endian binary data of fixed size */
+	mbedtls_mpi_write_binary(ACCESS_ECDH(&ctx, Q).X, buf, prime_len);
+	public_key = wpabuf_alloc_copy(buf, 32);
+	os_free(buf);
+	return public_key;
+}
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+                                        const u8 *key, size_t len)
+{
+	uint8_t *secret = 0;
+	size_t olen = 0, len_prime = 0;
+	struct crypto_bignum *bn_x = NULL;
+	struct crypto_ec_point *ec_pt = NULL;
+	uint8_t *px = NULL, *py = NULL, *buf = NULL;
+	struct crypto_key *pkey = NULL;
+	struct wpabuf *sh_secret = NULL;
+	int secret_key = 0;
+
+	mbedtls_ecdh_context *ctx = (mbedtls_ecdh_context *)ecdh;
+
+	mbedtls_ctr_drbg_context ctr_drbg;
+	mbedtls_entropy_context entropy;
+
+	/* Initialize CTR_DRBG context */
+	mbedtls_ctr_drbg_init(&ctr_drbg);
+	mbedtls_entropy_init(&entropy);
+
+	/* Seed and setup CTR_DRBG entropy source for future reseeds */
+	if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0) != 0) {
+		wpa_printf(MSG_ERROR, "Seeding entropy source failed");
+		goto cleanup;
+	}
+	len_prime = ACCESS_ECDH(ctx, grp).pbits/8;
+	bn_x = crypto_bignum_init_set(key, len);
+
+	/* Initialize data for EC point */
+	ec_pt = crypto_ec_point_init((struct crypto_ec*)ACCESS_ECDH(&ctx, grp));
+	if (!ec_pt) {
+		wpa_printf(MSG_ERROR,"Initializing for EC point failed");
+		goto cleanup;
+	}
+
+	if (crypto_ec_point_solve_y_coord((struct crypto_ec*)ACCESS_ECDH(&ctx, grp), ec_pt, bn_x, inc_y) != 0) {
+                wpa_printf(MSG_ERROR,"Failed to solve for y coordinate");
+                goto cleanup;
+	}
+	px = os_zalloc(len);
+	py = os_zalloc(len);
+	buf = os_zalloc(2*len);
+
+        if (!px || !py || !buf) {
+                wpa_printf(MSG_ERROR, "Memory allocation failed");
+                goto cleanup;
+        }
+	if (crypto_ec_point_to_bin((struct crypto_ec*)ACCESS_ECDH(&ctx, grp), ec_pt, px, py) != 0) {
+                wpa_printf(MSG_ERROR,"Failed to write EC point value as binary data");
+                goto cleanup;
+	}
+
+	os_memcpy(buf, px, len);
+	os_memcpy(buf+len, py, len);
+
+	pkey = crypto_ec_set_pubkey_point((struct crypto_ec_group*)ACCESS_ECDH(&ctx, grp), buf, len);
+        if (!pkey) {
+                wpa_printf(MSG_ERROR, "Failed to set point for peer's public key");
+                goto cleanup;
+	}
+
+
+	mbedtls_pk_context *peer = (mbedtls_pk_context*)pkey;
+
+	/* Setup ECDH context from EC key */
+/* Call to mbedtls_ecdh_get_params() will initialize the context when not LEGACY context */
+        if (ctx != NULL && peer != NULL) {
+                mbedtls_ecp_copy( ACCESS_ECDH(&ctx, Qp), &(mbedtls_pk_ec(*peer))->Q );
+#ifndef CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT
+                ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0;
+#endif
+        } else {
+                wpa_printf(MSG_ERROR, "Failed to set peer's ECDH context");
+                goto cleanup;
+        }
+	int len_secret = inc_y ? 2*len : len;
+	secret = os_zalloc(len_secret);
+	if (!secret) {
+		wpa_printf(MSG_ERROR, "Allocation failed for secret");
+		goto cleanup;
+	}
+
+	/* Calculate secret
+	z = F(DH(x,Y)) */
+	secret_key = mbedtls_ecdh_calc_secret(ctx, &olen, secret, len_prime, mbedtls_ctr_drbg_random, &ctr_drbg);
+	if (secret_key != 0) {
+		wpa_printf(MSG_ERROR, "Calculation of secret failed");
+		goto cleanup;
+	}
+	sh_secret = wpabuf_alloc_copy(secret, len_secret);
+
+cleanup:
+	os_free(px);
+	os_free(py);
+	os_free(buf);
+	os_free(secret);
+	crypto_ec_free_key(pkey);
+	crypto_bignum_deinit(bn_x, 1);
+	crypto_ec_point_deinit(ec_pt, 1);
+	return sh_secret;
+}
+
 #endif /* CONFIG_ECC */

+ 34 - 0
components/wpa_supplicant/esp_supplicant/src/esp_owe.c

@@ -0,0 +1,34 @@
+/*
+ * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifdef CONFIG_OWE_STA
+
+#include "crypto/crypto.h"
+#include "esp_owe_i.h"
+#include "rsn_supp/wpa.h"
+
+uint8_t *owe_build_dhie(uint16_t group)
+{
+    struct wpa_sm *sm = NULL;
+    sm = get_wpa_sm();
+    return (uint8_t *)(owe_build_assoc_req(sm, group));
+}
+
+void owe_deinit(void)
+{
+    struct wpa_sm *sm;
+    sm = get_wpa_sm();
+    if (sm->key_mgmt == WPA_KEY_MGMT_OWE) {
+        crypto_ecdh_deinit(sm->owe_ecdh);
+        sm->owe_ecdh = NULL;
+    }
+}
+
+void esp_wifi_register_owe_cb(struct wpa_funcs *wpa_cb)
+{
+    wpa_cb->owe_build_dhie = owe_build_dhie;
+    wpa_cb->owe_process_assoc_resp = owe_process_assoc_resp;
+}
+#endif /* CONFIG_OWE_STA */

+ 23 - 0
components/wpa_supplicant/esp_supplicant/src/esp_owe_i.h

@@ -0,0 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ESP_OWE_H
+#define ESP_OWE_H
+
+#ifdef CONFIG_OWE_STA
+
+#include "esp_wifi_driver.h"
+
+#define OWE_PMK_LEN    32
+#define OWE_PMKID_LEN  16
+#define OWE_DH_GRP19   19
+#define OWE_PRIME_LEN  32
+
+void owe_deinit(void);
+void esp_wifi_register_owe_cb(struct wpa_funcs *wpa_cb);
+
+#endif /* CONFIG_OWE_STA */
+#endif /* ESP_OWE_H  */

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

@@ -71,6 +71,7 @@ enum {
     WAPI_AUTH_CERT      = 0x0c,
     WPA2_AUTH_ENT_SHA384_SUITE_B = 0x0d,
     WPA2_AUTH_FT_PSK    = 0x0e,
+    WPA3_AUTH_OWE       = 0x0f,
     WPA2_AUTH_INVALID
 };
 
@@ -134,6 +135,8 @@ struct wpa_funcs {
     int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status);
     int (*wpa_sta_rx_mgmt)(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf);
     void (*wpa_config_done)(void);
+    uint8_t *(*owe_build_dhie)(uint16_t group);
+    int (*owe_process_assoc_resp)(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_ie, size_t dh_len);
 };
 
 struct wpa2_funcs {
@@ -239,7 +242,7 @@ int esp_wifi_ipc_internal(wifi_ipc_config_t *cfg, bool sync);
 int esp_wifi_register_wpa2_cb_internal(struct wpa2_funcs *cb);
 int esp_wifi_unregister_wpa2_cb_internal(void);
 bool esp_wifi_sta_prof_is_wpa2_internal(void);
-bool esp_wifi_sta_prof_is_wpa3_internal(void);
+bool esp_wifi_sta_prof_is_rsn_internal(void);
 bool esp_wifi_sta_prof_is_wapi_internal(void);
 esp_err_t esp_wifi_sta_wpa2_ent_disable_internal(wifi_wpa2_param_t *param);
 esp_err_t esp_wifi_sta_wpa2_ent_enable_internal(wifi_wpa2_param_t *param);

+ 8 - 1
components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c

@@ -30,6 +30,7 @@
 #include "esp_wpa3_i.h"
 #include "esp_wpa2.h"
 #include "esp_common_i.h"
+#include "esp_owe_i.h"
 
 #include "esp_wps.h"
 #include "eap_server/eap.h"
@@ -83,7 +84,7 @@ int  wpa_config_profile(uint8_t *bssid)
 
     if (esp_wifi_sta_prof_is_wpa_internal()) {
         wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal());
-    } else if (esp_wifi_sta_prof_is_wpa2_internal() || esp_wifi_sta_prof_is_wpa3_internal()) {
+    } else if (esp_wifi_sta_prof_is_rsn_internal()) {
         wpa_set_profile(WPA_PROTO_RSN, esp_wifi_sta_get_prof_authmode_internal());
     } else if (esp_wifi_sta_prof_is_wapi_internal()) {
         wpa_set_profile(WPA_PROTO_WAPI, esp_wifi_sta_get_prof_authmode_internal());
@@ -242,6 +243,9 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code)
         default:
             break;
     }
+#ifdef CONFIG_OWE_STA
+    owe_deinit();
+#endif /* CONFIG_OWE_STA */
 }
 
 #ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT
@@ -339,6 +343,9 @@ int esp_supplicant_init(void)
     wpa_cb->wpa_config_done = wpa_config_done;
 
     esp_wifi_register_wpa3_cb(wpa_cb);
+#ifdef CONFIG_OWE_STA
+    esp_wifi_register_owe_cb(wpa_cb);
+#endif /* CONFIG_OWE_STA */
     eloop_init();
     ret = esp_supplicant_common_init(wpa_cb);
 

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

@@ -47,6 +47,7 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #define WPA_KEY_MGMT_OSEN BIT(15)
 #define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
 #define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
+#define WPA_KEY_MGMT_OWE BIT(22)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
@@ -87,7 +88,8 @@ static inline int wpa_key_mgmt_sha256(int akm)
 			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
 			 WPA_KEY_MGMT_OSEN |
 			 WPA_KEY_MGMT_SAE |
-			 WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+			 WPA_KEY_MGMT_OWE));
 }
 
 static inline int wpa_key_mgmt_sha384(int akm)
@@ -101,11 +103,17 @@ static inline int wpa_key_mgmt_suite_b(int akm)
 			 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
 }
 
+static inline int wpa_key_mgmt_owe(int akm)
+{
+	return akm == WPA_KEY_MGMT_OWE;
+}
+
 static inline int wpa_key_mgmt_wpa(int akm)
 {
 	return wpa_key_mgmt_wpa_ieee8021x(akm) ||
 		wpa_key_mgmt_wpa_psk(akm) ||
-		wpa_key_mgmt_sae(akm);
+		wpa_key_mgmt_sae(akm) ||
+		wpa_key_mgmt_owe(akm);
 }
 
 static inline int wpa_key_mgmt_wpa_any(int akm)

+ 26 - 1
components/wpa_supplicant/src/common/wpa_common.c

@@ -324,6 +324,11 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
 		return WPA_KEY_MGMT_SAE;
 #endif /* CONFIG_WPA3_SAE */
+#ifdef CONFIG_OWE_STA
+	if(RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OWE)
+		return WPA_KEY_MGMT_OWE;
+#endif /* CONFIG_OWE_STA */
+
 	return 0;
 }
 
@@ -853,7 +858,7 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
 	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
 		if (hmac_sha1(key, key_len, buf, len, hash))
 			return -1;
-		memcpy(mic, hash, MD5_MAC_LEN);
+		os_memcpy(mic, hash, MD5_MAC_LEN);
 		break;
 	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
 		return omac1_aes_128(key, buf, len, mic);
@@ -878,7 +883,23 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
 			os_memcpy(mic, hash, 24);
 			break;
 #endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_OWE_STA
+		case WPA_KEY_MGMT_OWE:
+			wpa_printf(MSG_DEBUG,
+			"WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - OWE)",
+			(unsigned int) key_len * 8 * 2);
+			if (key_len == 128 / 8) {
+				if (hmac_sha256(key, key_len, buf, len, hash))
+					return -1;
+			} else {
+				wpa_printf(MSG_INFO,"OWE: Unsupported KCK length: %u",
+				(unsigned int) key_len);
+				return -1;
+                        }
+                        os_memcpy(mic, hash, key_len);
+                        break;
 
+#endif /* CONFIG_OWE_STA */
 #endif /* CONFIG_IEEE80211W */
 		default:
 			return -1;
@@ -1051,6 +1072,10 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 		   const u8 *nonce1, const u8 *nonce2,
 		   struct wpa_ptk *ptk, int akmp, int cipher)
 {
+	if (pmk_len == 0) {
+		wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
+		return -1;
+	}
 	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
 	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
 	size_t ptk_len;

+ 2 - 0
components/wpa_supplicant/src/common/wpa_common.h

@@ -66,6 +66,8 @@
 #define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
 #define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_AUTH_KEY_MGMT_OWE RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
+
 #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
 #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
 #define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)

+ 12 - 0
components/wpa_supplicant/src/crypto/crypto.h

@@ -20,6 +20,7 @@
 
 #ifndef CRYPTO_H
 #define CRYPTO_H
+#include "utils/common.h"
 
 /**
  * md4_vector - MD4 hash for data vector
@@ -1081,4 +1082,15 @@ int crypto_ec_get_priv_key_der(struct crypto_key *key, unsigned char **key_data,
  */
 int crypto_bignum_to_string(const struct crypto_bignum *a,
                          u8 *buf, size_t buflen, size_t padlen);
+
+struct crypto_ecdh;
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
+
+struct crypto_ecdh * crypto_ecdh_init(int group);
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh,int y);
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+                                        const u8 *key, size_t len);
+
 #endif /* CRYPTO_H */

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

@@ -29,9 +29,11 @@
 #include "crypto/sha1.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/ccmp.h"
+#include "crypto/sha256.h"
 #include "esp_rom_sys.h"
 #include "common/bss.h"
 #include "esp_common_i.h"
+#include "esp_owe_i.h"
 
 /**
  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
@@ -284,7 +286,7 @@ static 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_TKIP)
         ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-    else if (sm->key_mgmt == WPA_KEY_MGMT_SAE)
+    else if (sm->key_mgmt == WPA_KEY_MGMT_SAE || sm->key_mgmt == WPA_KEY_MGMT_OWE)
         ver = 0;
     else
         ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -807,7 +809,7 @@ void   wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
             sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
             MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
 
-        if (wpa_key_mgmt_wpa_psk(sm->key_mgmt))
+        if (wpa_key_mgmt_wpa_psk(sm->key_mgmt) || sm->key_mgmt == WPA_KEY_MGMT_OWE)
             eapol_sm_notify_eap_success(TRUE);
         /*
          * Start preauthentication after a short wait to avoid a
@@ -1719,7 +1721,8 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
                ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
                sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
                wpa_key_mgmt_suite_b(sm->key_mgmt) ||
-               sm->key_mgmt == WPA_KEY_MGMT_SAE) {
+               sm->key_mgmt == WPA_KEY_MGMT_SAE ||
+               sm->key_mgmt == WPA_KEY_MGMT_OWE) {
         u8 *buf;
         if (*key_data_len < 8 || *key_data_len % 8) {
             #ifdef DEBUG_PRINT
@@ -1912,6 +1915,9 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)
         sm->key_mgmt != WPA_KEY_MGMT_SAE &&
 #endif
         !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+#ifdef CONFIG_OWE_STA
+        sm->key_mgmt != WPA_KEY_MGMT_OWE &&
+#endif /* CONFIG_OWE_STA */
 #endif
         ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 #ifdef DEBUG_PRINT
@@ -1933,7 +1939,8 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)
         if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
             sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
             !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
-            sm->key_mgmt != WPA_KEY_MGMT_SAE) {
+            sm->key_mgmt != WPA_KEY_MGMT_SAE &&
+            sm->key_mgmt != WPA_KEY_MGMT_OWE) {
             goto out;
         }
     } else
@@ -1942,7 +1949,8 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)
     if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
         !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
         ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
-        sm->key_mgmt != WPA_KEY_MGMT_SAE) {
+        sm->key_mgmt != WPA_KEY_MGMT_SAE &&
+        sm->key_mgmt != WPA_KEY_MGMT_OWE) {
 #ifdef DEBUG_PRINT
         wpa_printf(MSG_DEBUG, "WPA: CCMP is used, but EAPOL-Key "
                "descriptor version (%d) is not 2.", ver);
@@ -2223,6 +2231,8 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
          sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
     } else if (auth_mode == WPA2_AUTH_FT_PSK) {
          sm->key_mgmt = WPA_KEY_MGMT_FT_PSK;
+    } else if (auth_mode == WPA3_AUTH_OWE) {
+         sm->key_mgmt = WPA_KEY_MGMT_OWE;
     } else {
         sm->key_mgmt = WPA_KEY_MGMT_PSK;  /* fixed to PSK for now */
     }
@@ -2274,6 +2284,7 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
     sm->ap_notify_completed_rsne = esp_wifi_sta_is_ap_notify_completed_rsne_internal();
 
     if (sm->key_mgmt == WPA_KEY_MGMT_SAE ||
+        sm->key_mgmt == WPA_KEY_MGMT_OWE ||
         is_wpa2_enterprise_connection()) {
         if (!esp_wifi_skip_supp_pmkcaching() && use_pmk_cache) {
             pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0);
@@ -2374,7 +2385,7 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len)
      *  Here only handle passphrase string.  Need extra step to handle 32B, 64Hex raw
      *    PMK.
      */
-    if (sm->key_mgmt == WPA_KEY_MGMT_SAE)
+    if (sm->key_mgmt == WPA_KEY_MGMT_SAE || sm->key_mgmt == WPA_KEY_MGMT_OWE)
         return;
 
     /* This is really SLOW, so just re cacl while reset param */
@@ -2595,4 +2606,190 @@ void wpa_sta_clear_curr_pmksa(void) {
     pmksa_cache_clear_current(sm);
 }
 
+struct wpa_sm * get_wpa_sm(void)
+{
+    return &gWpaSm;
+}
+
+#ifdef CONFIG_OWE_STA
+struct wpabuf *owe_build_assoc_req(struct wpa_sm *sm, u16 group)
+{
+    struct wpabuf *owe_ie = NULL, *pub = NULL;
+    size_t prime_len;
+
+    if (group == OWE_DH_GRP19) {
+        prime_len = OWE_PRIME_LEN;
+    } else {
+        wpa_printf(MSG_ERROR, "OWE: Unsupported Diffie-Hellman group");
+        return NULL;
+    }
+
+    sm->owe_ecdh = crypto_ecdh_init(group);
+
+    if (!sm->owe_ecdh) {
+        wpa_printf(MSG_ERROR, "Initialization of ecdh failed");
+        return NULL;
+    }
+
+    sm->owe_group = group;
+    /* Get own public key */
+    pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0);
+    pub = wpabuf_zeropad(pub, prime_len);
+
+    if (!pub) {
+        wpa_printf(MSG_ERROR, "Own public key is NULL");
+        goto fail;
+    }
+
+    wpa_hexdump_buf(MSG_DEBUG, "Own public key", pub);
+    owe_ie = wpabuf_alloc(5 + wpabuf_len(pub));
+
+    if (!owe_ie) {
+        wpa_printf(MSG_ERROR, "OWE IE allocation failed");
+        goto fail;
+    }
+
+    /* Constructing the DH IE */
+    wpabuf_put_u8(owe_ie, WLAN_EID_EXTENSION);
+    wpabuf_put_u8(owe_ie, 1 + 2 + wpabuf_len(pub));
+    wpabuf_put_u8(owe_ie, WLAN_EID_EXT_OWE_DH_PARAM);
+    wpabuf_put_le16(owe_ie, group);
+    wpabuf_put_buf(owe_ie, pub);
+    wpabuf_free(pub);
+
+    wpa_hexdump_buf(MSG_DEBUG, "OWE: Diffie-Hellman Parameter element", owe_ie);
+
+    return (struct wpabuf *)wpabuf_head(owe_ie);
+
+fail:
+    wpabuf_free(pub);
+    crypto_ecdh_deinit(sm->owe_ecdh);
+    return NULL;
+}
+
+int owe_process_assoc_resp(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_ie, size_t dh_len)
+{
+    size_t prime_len=0,hash_len=0;
+    struct wpabuf * sh_secret = NULL, *pub = NULL, *hkey = NULL;
+    int res;
+    const char *info = "OWE Key Generation";
+    u8 pmkid[SHA256_MAC_LEN], prk[SHA256_MAC_LEN], pmk[SHA256_MAC_LEN];
+    const u8 *addr[2];
+    size_t len[2];
+    u16 group;
+
+    struct wpa_sm *sm;
+    sm = get_wpa_sm();
+
+    (void)res;
+    struct wpa_ie_data *parsed_rsn_data;
+    parsed_rsn_data = os_zalloc(sizeof(struct wpa_ie_data));
+    if (!parsed_rsn_data) {
+        wpa_printf(MSG_ERROR, "Memory allocation failed");
+        goto fail;
+    }
+
+    if (rsn_ie && rsn_len && wpa_parse_wpa_ie_rsn(rsn_ie, rsn_len + 2, parsed_rsn_data) != 0) {
+        goto fail;
+    }
+    if (!dh_ie && !dh_len && parsed_rsn_data->num_pmkid == 0) {
+        wpa_printf(MSG_ERROR, "OWE: No diffie hellman parameter in response");
+        goto fail;
+    }
+
+    if (!sm->cur_pmksa) { /* No PMK caching */
+        dh_len += 2;
+
+        dh_ie += 3;
+        dh_len -=3;
+        group = WPA_GET_LE16(dh_ie);
+
+        /* Only group 19 is supported */
+        if ((group != sm->owe_group) || (group != OWE_DH_GRP19)) {
+            wpa_printf(MSG_ERROR, "OWE: Unexpected Diffie-Hellman group in response");
+            goto fail;
+        }
+
+        prime_len = OWE_PRIME_LEN;
+
+        /* Set peer's public key point and calculate shared secret */
+        sh_secret = crypto_ecdh_set_peerkey(sm->owe_ecdh, 0, dh_ie+2, dh_len-2);
+        sh_secret = wpabuf_zeropad(sh_secret, prime_len);
+        if (!sh_secret) {
+            wpa_printf(MSG_ERROR, "OWE: Invalid peer DH public key");
+            goto fail;
+        }
+
+        wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", sh_secret);
+        pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0);
+        if (!pub) {
+            wpa_printf(MSG_ERROR, "No own public key");
+            wpabuf_free(sh_secret);
+            goto fail;
+        }
+
+        /* PMKID = Truncate-128(Hash(C | A)) */
+        addr[0] = wpabuf_head(pub);
+        len[0] = wpabuf_len(pub);
+        addr[1] = dh_ie + 2;
+        len[1] = dh_len - 2;
+
+        res = sha256_vector(2, addr, len, pmkid);
+        hash_len = SHA256_MAC_LEN;
+
+        pub = wpabuf_zeropad(pub, prime_len);
+
+        /* prk = HKDF-extract(C | A | group, z) */
+        hkey = wpabuf_alloc(wpabuf_len(pub) + dh_len - 2 + 2);
+
+        wpabuf_put_buf(hkey, pub); /* C */
+        wpabuf_free(pub);
+
+        wpabuf_put_data(hkey, dh_ie + 2, dh_len - 2); /* A */
+        wpabuf_put_le16(hkey, sm->owe_group); /* group */
+
+        res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey), wpabuf_head(sh_secret), wpabuf_len(sh_secret), prk);
+        hash_len = SHA256_MAC_LEN;
+
+        wpabuf_free(hkey);
+        wpabuf_free(sh_secret);
+
+        wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
+
+        /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
+        res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *)info,
+        os_strlen(info), pmk, hash_len);
+
+        forced_memzero(prk, SHA256_MAC_LEN);
+        wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, OWE_PMKID_LEN);
+
+        os_memcpy(sm->pmk,pmk,hash_len);
+        sm->pmk_len = hash_len;
+        wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, sm->pmk_len);
+
+        pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, pmkid, NULL, 0,
+                            sm->bssid, sm->own_addr, sm->network_ctx, sm->key_mgmt);
+        goto done;
+    } else { /* PMK caching */
+        if (parsed_rsn_data && sm->cur_pmksa) {
+            if (parsed_rsn_data->num_pmkid == 1 && parsed_rsn_data->pmkid) {
+                if (os_memcmp(parsed_rsn_data->pmkid, sm->cur_pmksa->pmkid, OWE_PMKID_LEN) == 0) {
+                    wpa_printf(MSG_DEBUG, "OWE: Using PMK caching");
+                    wpa_sm_set_pmk_from_pmksa(sm);
+                    goto done;
+                } else {
+                    wpa_printf(MSG_DEBUG, "OWE : Invalid PMKID in response");
+                    goto fail;
+                }
+            }
+        }
+     }
+done:
+    os_free(parsed_rsn_data);
+    return 0;
+fail:
+    os_free(parsed_rsn_data);
+    return -1;
+}
+#endif // CONFIG_OWE_STA
 #endif // ESP_SUPPLICANT

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

@@ -115,4 +115,12 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 }
 
 #endif /* CONFIG_IEEE80211R */
+struct wpa_sm * get_wpa_sm(void);
+
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
+
+int owe_process_assoc_resp(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_ie, size_t dh_len);
+
+struct wpabuf *owe_build_assoc_req(struct wpa_sm *sm, u16 group);
+
 #endif /* WPA_H */

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

@@ -109,6 +109,10 @@ struct wpa_sm {
     u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
     size_t assoc_resp_ies_len;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_OWE_STA
+    struct crypto_ecdh *owe_ecdh;
+    u16 owe_group;
+#endif /* CONFIG_OWE_STA */
 };
 
 /**

+ 5 - 1
components/wpa_supplicant/src/rsn_supp/wpa_ie.c

@@ -197,6 +197,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
     } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
 #endif /* CONFIG_WPA3_SAE */
+#ifdef CONFIG_OWE_STA
+    } else if (key_mgmt == WPA_KEY_MGMT_OWE) {
+        RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
+#endif /* CONFIG_OWE_STA */
 #endif /* CONFIG_IEEE80211W */
     } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
@@ -214,7 +218,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
 #ifdef CONFIG_IEEE80211W
     if (sm->pmf_cfg.capable) {
         capab |= WPA_CAPABILITY_MFPC;
-        if (sm->pmf_cfg.required || key_mgmt == WPA_KEY_MGMT_SAE) {
+        if (sm->pmf_cfg.required || key_mgmt == WPA_KEY_MGMT_SAE || key_mgmt == WPA_KEY_MGMT_OWE) {
             capab |= WPA_CAPABILITY_MFPR;
         }
     }

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

@@ -474,5 +474,6 @@ void * __hide_aliasing_typecast(void *foo);
 #endif /* CONFIG_VALGRIND */
 
 #define IANA_SECP256R1 19
-
+#define IANA_SECP384R1 20
+#define IANA_SECP521R1 21
 #endif /* COMMON_H */

+ 3 - 0
examples/wifi/scan/main/scan.c

@@ -28,6 +28,9 @@ static void print_auth_mode(int authmode)
     case WIFI_AUTH_OPEN:
         ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN");
         break;
+    case WIFI_AUTH_OWE:
+        ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OWE");
+        break;
     case WIFI_AUTH_WEP:
         ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP");
         break;