From 87ec02b59c118ecb88e64ec391fa5de8150d376b Mon Sep 17 00:00:00 2001 From: Michael Stoll Date: Mon, 3 Mar 2025 18:11:30 +0100 Subject: [PATCH 1/5] feat(esp_wifi): Implement esp_eap_client_set_domain_match --- .../esp_supplicant/include/esp_eap_client.h | 24 +++++++++++++++ .../esp_supplicant/src/crypto/tls_mbedtls.c | 5 ++++ .../esp_supplicant/src/esp_eap_client.c | 30 +++++++++++++++++++ components/wpa_supplicant/src/eap_peer/eap.c | 4 ++- components/wpa_supplicant/src/eap_peer/eap.h | 2 ++ .../wpa_supplicant/src/eap_peer/eap_config.h | 15 ++++++++++ .../src/eap_peer/eap_tls_common.c | 1 + 7 files changed, 80 insertions(+), 1 deletion(-) diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h b/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h index 1cbfac781e..a0ca6d7c3f 100644 --- a/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h +++ b/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h @@ -321,6 +321,30 @@ esp_err_t esp_eap_client_set_fast_params(esp_eap_fast_config config); */ esp_err_t esp_eap_client_use_default_cert_bundle(bool use_default_bundle); +/** + * @brief Set name for certificate domain name validation + * + * Enabling this option will only accept certificate with the provided subject name + * + * @param[in] domain_match The expected domain name + * @param[in] len Length of the domain name (limited to 1~127 bytes). + * + * @return + * - ESP_OK: The identity was set successfully. + * - ESP_ERR_INVALID_ARG: Invalid argument (len <= 0 or len >= 128). + * - ESP_ERR_NO_MEM: Memory allocation failure. + */ +esp_err_t esp_eap_client_set_domain_match(const char *domain_match); + +/** + * @brief Clear the domain name for certificate validation + * + * This function clears the domain name that was previously set for the EAP client. + * After calling this function, the EAP client will no longer use the previously + * configured domain name during the authentication process. + */ +void esp_eap_client_clear_domain_match(void); + #ifdef __cplusplus } #endif diff --git a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c index ff3699b497..55a76a0300 100644 --- a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c +++ b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c @@ -536,6 +536,11 @@ static int set_client_config(const struct tls_connection_params *cfg, tls_contex mbedtls_ssl_set_verify( &tls->ssl, tls_disable_key_usages, NULL ); #endif /*CONFIG_ESP_WIFI_DISABLE_KEY_USAGE_CHECK*/ + if (cfg->domain_match) { + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_set_hostname(&tls->ssl, cfg->domain_match); + } + #ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE if (cfg->flags & TLS_CONN_USE_DEFAULT_CERT_BUNDLE) { wpa_printf(MSG_INFO, "Using default cert bundle"); diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c b/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c index d8d59bb92f..afba2f1c6f 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c @@ -1191,3 +1191,33 @@ esp_err_t esp_eap_client_use_default_cert_bundle(bool use_default_bundle) return ESP_FAIL; #endif } + +#define MAX_DOMAIN_MATCH_LEN 128 +esp_err_t esp_eap_client_set_domain_match(const char *domain_match) +{ + if (g_wpa_domain_match) { + os_free(g_wpa_domain_match); + g_wpa_domain_match = NULL; + } + + int len = os_strlen(domain_match); + if (len > MAX_DOMAIN_MATCH_LEN) { + return ESP_ERR_INVALID_ARG; + } + g_wpa_domain_match = (char *)os_zalloc(len+1); + if (g_wpa_domain_match == NULL) { + return ESP_ERR_NO_MEM; + } + + os_strlcpy(g_wpa_domain_match, domain_match, len+1); + + return ESP_OK; +} + +void esp_eap_client_clear_domain_match(void) +{ + if (g_wpa_domain_match) { + os_free(g_wpa_domain_match); + } + g_wpa_domain_match = NULL; +} \ No newline at end of file diff --git a/components/wpa_supplicant/src/eap_peer/eap.c b/components/wpa_supplicant/src/eap_peer/eap.c index bce12af1fc..7c6739178d 100644 --- a/components/wpa_supplicant/src/eap_peer/eap.c +++ b/components/wpa_supplicant/src/eap_peer/eap.c @@ -67,6 +67,7 @@ bool g_wpa_suiteb_certification; bool g_wpa_default_cert_bundle; int (*esp_crt_bundle_attach_fn)(void *conf); #endif +char *g_wpa_domain_match; void eap_peer_config_deinit(struct eap_sm *sm); void eap_peer_blob_deinit(struct eap_sm *sm); @@ -518,7 +519,7 @@ int eap_peer_config_init( sm->config.identity = NULL; sm->config.password = NULL; sm->config.new_password = NULL; - + sm->config.domain_match = g_wpa_domain_match; sm->config.private_key_passwd = private_key_passwd; sm->config.client_cert = (u8 *)sm->blob[0].name; sm->config.private_key = (u8 *)sm->blob[1].name; @@ -581,6 +582,7 @@ int eap_peer_config_init( sm->config.flags |= TLS_CONN_USE_DEFAULT_CERT_BUNDLE; } #endif + /* To be used only for EAP-FAST */ if (g_wpa_phase1_options) { sm->config.phase1 = g_wpa_phase1_options; diff --git a/components/wpa_supplicant/src/eap_peer/eap.h b/components/wpa_supplicant/src/eap_peer/eap.h index 0651bd5ec5..a11198d78c 100644 --- a/components/wpa_supplicant/src/eap_peer/eap.h +++ b/components/wpa_supplicant/src/eap_peer/eap.h @@ -49,6 +49,8 @@ extern bool g_wpa_suiteb_certification; extern bool g_wpa_default_cert_bundle; extern int (*esp_crt_bundle_attach_fn)(void *conf); +extern char *g_wpa_domain_match; + const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); void eap_deinit_prev_method(struct eap_sm *sm, const char *txt); struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id); diff --git a/components/wpa_supplicant/src/eap_peer/eap_config.h b/components/wpa_supplicant/src/eap_peer/eap_config.h index 60eda8c954..6dee56c7ac 100644 --- a/components/wpa_supplicant/src/eap_peer/eap_config.h +++ b/components/wpa_supplicant/src/eap_peer/eap_config.h @@ -159,6 +159,21 @@ struct eap_peer_config { */ const u8 *private_key_passwd; + /** + * domain_match - Constraint for server domain name + * + * If set, this FQDN is used as a full match requirement for the + * server certificate in SubjectAltName dNSName element(s). If a + * matching dNSName is found, this constraint is met. If no dNSName + * values are present, this constraint is matched against SubjectName CN + * using same full match comparison. This behavior is similar to + * domain_suffix_match, but has the requirement of a full match, i.e., + * no subdomains or wildcard matches are allowed. Case-insensitive + * comparison is used, so "Example.com" matches "example.com", but would + * not match "test.Example.com". + */ + char *domain_match; + /** * Phase 2 */ diff --git a/components/wpa_supplicant/src/eap_peer/eap_tls_common.c b/components/wpa_supplicant/src/eap_peer/eap_tls_common.c index b3ebfa7362..abb2a26749 100644 --- a/components/wpa_supplicant/src/eap_peer/eap_tls_common.c +++ b/components/wpa_supplicant/src/eap_peer/eap_tls_common.c @@ -74,6 +74,7 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params, params->client_cert = (char *) config->client_cert; params->private_key = (char *) config->private_key; params->private_key_passwd = (char *) config->private_key_passwd; + params->domain_match = config->domain_match; eap_tls_params_flags(params, config->phase1); if (wifi_sta_get_enterprise_disable_time_check()) params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; From 4912a7047048b523578c417ca67382c86709abba Mon Sep 17 00:00:00 2001 From: Michael Stoll Date: Fri, 14 Mar 2025 17:17:09 +0100 Subject: [PATCH 2/5] feat: Add domain match to wifi_enterprise example --- examples/wifi/wifi_enterprise/main/Kconfig.projbuild | 12 ++++++++++++ .../wifi/wifi_enterprise/main/wifi_enterprise_main.c | 3 +++ 2 files changed, 15 insertions(+) diff --git a/examples/wifi/wifi_enterprise/main/Kconfig.projbuild b/examples/wifi/wifi_enterprise/main/Kconfig.projbuild index 9b68237e4c..bd82dfb069 100644 --- a/examples/wifi/wifi_enterprise/main/Kconfig.projbuild +++ b/examples/wifi/wifi_enterprise/main/Kconfig.projbuild @@ -98,4 +98,16 @@ menu "Example Configuration" default n help Use default CA certificate bundle for WiFi enterprise connection + + config EXAMPLE_USE_SERVER_DOMAIN_MATCH + bool "Validate server cert domain" + help + Validate the certificate domain + + config EXAMPLE_SERVER_DOMAIN_MATCH_VALUE + string "Server cert domain" + depends on EXAMPLE_USE_SERVER_DOMAIN_MATCH + default "espressif.com" + help + Accept only server certificates matching this domain endmenu diff --git a/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c b/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c index b511c7c20a..16909a9820 100644 --- a/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c +++ b/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c @@ -150,6 +150,9 @@ static void initialise_wifi(void) #endif #ifdef CONFIG_EXAMPLE_USE_DEFAULT_CERT_BUNDLE ESP_ERROR_CHECK(esp_eap_client_use_default_cert_bundle(true)); +#endif +#ifdef CONFIG_EXAMPLE_USE_SERVER_DOMAIN_MATCH + ESP_ERROR_CHECK(esp_eap_client_set_domain_match(CONFIG_EXAMPLE_SERVER_DOMAIN_MATCH_VALUE)); #endif ESP_ERROR_CHECK(esp_wifi_sta_enterprise_enable()); ESP_ERROR_CHECK(esp_wifi_start()); From 4b3a44facec7978b6b3cebbc6d3a27836c13434b Mon Sep 17 00:00:00 2001 From: Michael Stoll Date: Mon, 3 Mar 2025 18:10:54 +0100 Subject: [PATCH 3/5] fix: Force validate when using the default crt bundle --- .../wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c index 55a76a0300..7922b9be7b 100644 --- a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c +++ b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c @@ -543,6 +543,7 @@ static int set_client_config(const struct tls_connection_params *cfg, tls_contex #ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE if (cfg->flags & TLS_CONN_USE_DEFAULT_CERT_BUNDLE) { + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); wpa_printf(MSG_INFO, "Using default cert bundle"); if (esp_crt_bundle_attach_fn) { ret = (*esp_crt_bundle_attach_fn)(&tls->conf); From f3fc894fea4245ff5697b7e2e3aa21f7ec362724 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 11 Mar 2025 12:29:36 +0530 Subject: [PATCH 4/5] fix(esp_wifi): Code cleanup for PR#15550 PR#15551 Closes https://github.com/espressif/esp-idf/pull/15550 Closes https://github.com/espressif/esp-idf/pull/15551 --- .../esp_supplicant/include/esp_eap_client.h | 26 +++----- .../esp_supplicant/src/crypto/tls_mbedtls.c | 12 ++-- .../esp_supplicant/src/esp_eap_client.c | 41 +++++++------ components/wpa_supplicant/port/include/os.h | 59 ++++++++++--------- components/wpa_supplicant/src/eap_peer/eap.c | 5 +- components/wpa_supplicant/src/eap_peer/eap.h | 2 + .../wifi_enterprise/main/Kconfig.projbuild | 17 +++--- .../main/wifi_enterprise_main.c | 7 ++- 8 files changed, 90 insertions(+), 79 deletions(-) diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h b/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h index a0ca6d7c3f..22cfdd293a 100644 --- a/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h +++ b/components/wpa_supplicant/esp_supplicant/include/esp_eap_client.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -322,28 +322,20 @@ esp_err_t esp_eap_client_set_fast_params(esp_eap_fast_config config); esp_err_t esp_eap_client_use_default_cert_bundle(bool use_default_bundle); /** - * @brief Set name for certificate domain name validation + * This function sets the expected domain name for validating the certificate's subject name. + * If the provided domain name does not match the certificate's subject name, validation will fail. * - * Enabling this option will only accept certificate with the provided subject name + * @attention 1. The `domain_name` should be a NULL-terminated string. * - * @param[in] domain_match The expected domain name - * @param[in] len Length of the domain name (limited to 1~127 bytes). + * @param[in] domain_name The expected domain name. Pass `NULL` to clear the domain matching. * * @return - * - ESP_OK: The identity was set successfully. - * - ESP_ERR_INVALID_ARG: Invalid argument (len <= 0 or len >= 128). + * - ESP_OK: The domain match was set successfully. + * - ESP_ERR_INVALID_ARG: Invalid argument (length > 255). * - ESP_ERR_NO_MEM: Memory allocation failure. + * - ESP_ERR_NOT_SUPPORTED: Feature not supported. */ -esp_err_t esp_eap_client_set_domain_match(const char *domain_match); - -/** - * @brief Clear the domain name for certificate validation - * - * This function clears the domain name that was previously set for the EAP client. - * After calling this function, the EAP client will no longer use the previously - * configured domain name during the authentication process. - */ -void esp_eap_client_clear_domain_match(void); +esp_err_t esp_eap_client_set_domain_name(const char *domain_name); #ifdef __cplusplus } diff --git a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c index 7922b9be7b..1e08706669 100644 --- a/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c +++ b/components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -535,11 +535,11 @@ static int set_client_config(const struct tls_connection_params *cfg, tls_contex #ifdef CONFIG_ESP_WIFI_DISABLE_KEY_USAGE_CHECK mbedtls_ssl_set_verify( &tls->ssl, tls_disable_key_usages, NULL ); #endif /*CONFIG_ESP_WIFI_DISABLE_KEY_USAGE_CHECK*/ - - if (cfg->domain_match) { - mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); - mbedtls_ssl_set_hostname(&tls->ssl, cfg->domain_match); - } + ret = mbedtls_ssl_set_hostname(&tls->ssl, cfg->domain_match); + if (ret != 0) { + wpa_printf(MSG_ERROR, "Failed to set hostname"); + return ret; + } #ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE if (cfg->flags & TLS_CONN_USE_DEFAULT_CERT_BUNDLE) { diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c b/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c index afba2f1c6f..3ebd4beb8b 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -932,6 +932,9 @@ esp_err_t esp_eap_client_set_ca_cert(const unsigned char *ca_cert, int ca_cert_l g_wpa_ca_cert_len = ca_cert_len; } + /* CA certs Set/updated, flushing current PMK cache */ + wpa_sm_pmksa_cache_flush(get_wpa_sm(), NULL); + return ESP_OK; } @@ -1192,32 +1195,36 @@ esp_err_t esp_eap_client_use_default_cert_bundle(bool use_default_bundle) #endif } -#define MAX_DOMAIN_MATCH_LEN 128 -esp_err_t esp_eap_client_set_domain_match(const char *domain_match) +#define MAX_DOMAIN_MATCH_LEN 255 /* Maximum host name defined in RFC 1035 */ +esp_err_t esp_eap_client_set_domain_name(const char *domain_name) { +#ifdef CONFIG_TLS_INTERNAL_CLIENT + return ESP_ERR_NOT_SUPPORTED; +#else + int len = domain_name ? os_strnlen(domain_name, MAX_DOMAIN_MATCH_LEN + 1) : 0; + if (len > MAX_DOMAIN_MATCH_LEN) { + return ESP_ERR_INVALID_ARG; + } + if (g_wpa_domain_match && domain_name && os_strcmp(g_wpa_domain_match, domain_name) == 0) { + return ESP_OK; + } if (g_wpa_domain_match) { os_free(g_wpa_domain_match); g_wpa_domain_match = NULL; } - int len = os_strlen(domain_match); - if (len > MAX_DOMAIN_MATCH_LEN) { - return ESP_ERR_INVALID_ARG; + if (!domain_name) { + return ESP_OK; } - g_wpa_domain_match = (char *)os_zalloc(len+1); - if (g_wpa_domain_match == NULL) { + g_wpa_domain_match = os_strdup(domain_name); + if (!g_wpa_domain_match) { return ESP_ERR_NO_MEM; } - os_strlcpy(g_wpa_domain_match, domain_match, len+1); + /* flushing the PMK only needed when going for a better security ie no-domain name to domain name + * or changing the domain name */ + wpa_sm_pmksa_cache_flush(get_wpa_sm(), NULL); return ESP_OK; +#endif } - -void esp_eap_client_clear_domain_match(void) -{ - if (g_wpa_domain_match) { - os_free(g_wpa_domain_match); - } - g_wpa_domain_match = NULL; -} \ No newline at end of file diff --git a/components/wpa_supplicant/port/include/os.h b/components/wpa_supplicant/port/include/os.h index a3442fade9..7b8f7798be 100644 --- a/components/wpa_supplicant/port/include/os.h +++ b/components/wpa_supplicant/port/include/os.h @@ -33,8 +33,8 @@ typedef time_t os_time_t; void os_sleep(os_time_t sec, os_time_t usec); struct os_time { - os_time_t sec; - suseconds_t usec; + os_time_t sec; + suseconds_t usec; }; #define os_reltime os_time @@ -59,17 +59,17 @@ int os_get_time(struct os_time *t); /* Helper macros for handling struct os_time */ #define os_time_before(a, b) \ - ((a)->sec < (b)->sec || \ - ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) + ((a)->sec < (b)->sec || \ + ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) #define os_reltime_before os_time_before #define os_time_sub(a, b, res) do { \ - (res)->sec = (a)->sec - (b)->sec; \ - (res)->usec = (a)->usec - (b)->usec; \ - if ((res)->usec < 0) { \ - (res)->sec--; \ - (res)->usec += 1000000; \ - } \ + (res)->sec = (a)->sec - (b)->sec; \ + (res)->usec = (a)->usec - (b)->usec; \ + if ((res)->usec < 0) { \ + (res)->sec--; \ + (res)->usec += 1000000; \ + } \ } while (0) #define os_reltime_sub os_time_sub @@ -89,7 +89,7 @@ int os_get_time(struct os_time *t); * which is used by POSIX mktime(). */ int os_mktime(int year, int month, int day, int hour, int min, int sec, - os_time_t *t); + os_time_t *t); int os_gmtime(os_time_t t, struct os_tm *tm); @@ -190,7 +190,7 @@ int os_unsetenv(const char *name); /* We don't support file reading support */ static inline char *os_readfile(const char *name, size_t *len) { - return NULL; + return NULL; } /* @@ -230,7 +230,6 @@ static inline char *os_readfile(const char *name, size_t *len) #define os_bzero(s, n) bzero(s, n) #endif - #ifndef os_strdup #ifdef _MSC_VER #define os_strdup(s) _strdup(s) @@ -259,6 +258,9 @@ char * ets_strdup(const char *s); #ifndef os_strlen #define os_strlen(s) strlen(s) #endif +#ifndef os_strnlen +#define os_strnlen(s, n) strnlen((s), (n)) +#endif #ifndef os_strcasecmp #ifdef _MSC_VER #define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) @@ -308,14 +310,15 @@ char * ets_strdup(const char *s); static inline int os_snprintf_error(size_t size, int res) { - return res < 0 || (unsigned int) res >= size; + return res < 0 || (unsigned int) res >= size; } static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size) { - if (size && nmemb > (~(size_t) 0) / size) - return NULL; - return os_realloc(ptr, nmemb * size); + if (size && nmemb > (~(size_t) 0) / size) { + return NULL; + } + return os_realloc(ptr, nmemb * size); } #ifdef CONFIG_CRYPTO_MBEDTLS @@ -334,10 +337,10 @@ static uint8_t forced_memzero_val; static inline void forced_memzero(void *ptr, size_t len) { - memset_func(ptr, 0, len); - if (len) { - forced_memzero_val = ((uint8_t *) ptr)[0]; - } + memset_func(ptr, 0, len); + if (len) { + forced_memzero_val = ((uint8_t *) ptr)[0]; + } } #endif @@ -377,23 +380,23 @@ extern const wifi_osi_funcs_t *wifi_funcs; static inline void os_timer_setfn(void *ptimer, void *pfunction, void *parg) { - return wifi_funcs->_timer_setfn(ptimer, pfunction, parg); + return wifi_funcs->_timer_setfn(ptimer, pfunction, parg); } static inline void os_timer_disarm(void *ptimer) { - return wifi_funcs->_timer_disarm(ptimer); + return wifi_funcs->_timer_disarm(ptimer); } -static inline void os_timer_arm_us(void *ptimer,uint32_t u_seconds,bool repeat_flag) +static inline void os_timer_arm_us(void *ptimer, uint32_t u_seconds, bool repeat_flag) { - return wifi_funcs->_timer_arm_us(ptimer, u_seconds, repeat_flag); + return wifi_funcs->_timer_arm_us(ptimer, u_seconds, repeat_flag); } -static inline void os_timer_arm(void *ptimer,uint32_t milliseconds,bool repeat_flag) +static inline void os_timer_arm(void *ptimer, uint32_t milliseconds, bool repeat_flag) { - return wifi_funcs->_timer_arm(ptimer, milliseconds, repeat_flag); + return wifi_funcs->_timer_arm(ptimer, milliseconds, repeat_flag); } static inline void os_timer_done(void *ptimer) { - return wifi_funcs->_timer_done(ptimer); + return wifi_funcs->_timer_done(ptimer); } #endif /* OS_H */ diff --git a/components/wpa_supplicant/src/eap_peer/eap.c b/components/wpa_supplicant/src/eap_peer/eap.c index 7c6739178d..39bd0247c0 100644 --- a/components/wpa_supplicant/src/eap_peer/eap.c +++ b/components/wpa_supplicant/src/eap_peer/eap.c @@ -67,7 +67,9 @@ bool g_wpa_suiteb_certification; bool g_wpa_default_cert_bundle; int (*esp_crt_bundle_attach_fn)(void *conf); #endif +#ifndef CONFIG_TLS_INTERNAL_CLIENT char *g_wpa_domain_match; +#endif void eap_peer_config_deinit(struct eap_sm *sm); void eap_peer_blob_deinit(struct eap_sm *sm); @@ -519,7 +521,9 @@ int eap_peer_config_init( sm->config.identity = NULL; sm->config.password = NULL; sm->config.new_password = NULL; +#ifndef CONFIG_TLS_INTERNAL_CLIENT sm->config.domain_match = g_wpa_domain_match; +#endif sm->config.private_key_passwd = private_key_passwd; sm->config.client_cert = (u8 *)sm->blob[0].name; sm->config.private_key = (u8 *)sm->blob[1].name; @@ -582,7 +586,6 @@ int eap_peer_config_init( sm->config.flags |= TLS_CONN_USE_DEFAULT_CERT_BUNDLE; } #endif - /* To be used only for EAP-FAST */ if (g_wpa_phase1_options) { sm->config.phase1 = g_wpa_phase1_options; diff --git a/components/wpa_supplicant/src/eap_peer/eap.h b/components/wpa_supplicant/src/eap_peer/eap.h index a11198d78c..93d623d1cc 100644 --- a/components/wpa_supplicant/src/eap_peer/eap.h +++ b/components/wpa_supplicant/src/eap_peer/eap.h @@ -49,7 +49,9 @@ extern bool g_wpa_suiteb_certification; extern bool g_wpa_default_cert_bundle; extern int (*esp_crt_bundle_attach_fn)(void *conf); +#ifndef CONFIG_TLS_INTERNAL_CLIENT extern char *g_wpa_domain_match; +#endif const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); void eap_deinit_prev_method(struct eap_sm *sm, const char *txt); diff --git a/examples/wifi/wifi_enterprise/main/Kconfig.projbuild b/examples/wifi/wifi_enterprise/main/Kconfig.projbuild index bd82dfb069..3776bae400 100644 --- a/examples/wifi/wifi_enterprise/main/Kconfig.projbuild +++ b/examples/wifi/wifi_enterprise/main/Kconfig.projbuild @@ -99,15 +99,18 @@ menu "Example Configuration" help Use default CA certificate bundle for WiFi enterprise connection - config EXAMPLE_USE_SERVER_DOMAIN_MATCH - bool "Validate server cert domain" + config EXAMPLE_VALIDATE_SERVER_CERT_DOMAIN + bool "Enable server certificate domain validation" + depends on EXAMPLE_VALIDATE_SERVER_CERT + default n help - Validate the certificate domain + Enable validation of the server certificate's domain name. - config EXAMPLE_SERVER_DOMAIN_MATCH_VALUE - string "Server cert domain" - depends on EXAMPLE_USE_SERVER_DOMAIN_MATCH + config EXAMPLE_SERVER_CERT_DOMAIN + string "Expected server certificate domain" + depends on EXAMPLE_VALIDATE_SERVER_CERT_DOMAIN default "espressif.com" help - Accept only server certificates matching this domain + Specify the expected domain name for the server certificate. + The connection will be accepted only if the server certificate matches this domain. endmenu diff --git a/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c b/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c index 16909a9820..15026a9953 100644 --- a/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c +++ b/examples/wifi/wifi_enterprise/main/wifi_enterprise_main.c @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2006-2016 ARM Limited - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,6 +33,7 @@ #define EXAMPLE_EAP_ID CONFIG_EXAMPLE_EAP_ID #define EXAMPLE_EAP_USERNAME CONFIG_EXAMPLE_EAP_USERNAME #define EXAMPLE_EAP_PASSWORD CONFIG_EXAMPLE_EAP_PASSWORD +#define EXAMPLE_SERVER_CERT_DOMAIN CONFIG_EXAMPLE_SERVER_CERT_DOMAIN /* FreeRTOS event group to signal when we are connected & ready to make a request */ static EventGroupHandle_t wifi_event_group; @@ -151,8 +152,8 @@ static void initialise_wifi(void) #ifdef CONFIG_EXAMPLE_USE_DEFAULT_CERT_BUNDLE ESP_ERROR_CHECK(esp_eap_client_use_default_cert_bundle(true)); #endif -#ifdef CONFIG_EXAMPLE_USE_SERVER_DOMAIN_MATCH - ESP_ERROR_CHECK(esp_eap_client_set_domain_match(CONFIG_EXAMPLE_SERVER_DOMAIN_MATCH_VALUE)); +#ifdef CONFIG_EXAMPLE_VALIDATE_SERVER_CERT_DOMAIN + ESP_ERROR_CHECK(esp_eap_client_set_domain_name(EXAMPLE_SERVER_CERT_DOMAIN)); #endif ESP_ERROR_CHECK(esp_wifi_sta_enterprise_enable()); ESP_ERROR_CHECK(esp_wifi_start()); From 22dd9dda98b0ecf6f8a2c61167d7973519d272c2 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 8 Apr 2025 12:45:00 +0530 Subject: [PATCH 5/5] fix(esp_wifi): Flush PMK when EAP config is changed --- .../esp_supplicant/src/esp_eap_client.c | 45 ++++++++++++++++--- .../esp_supplicant/src/esp_wpa_main.c | 18 +++++--- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c b/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c index 3ebd4beb8b..1d3e7ff700 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_eap_client.c @@ -38,6 +38,7 @@ #include "esp_wpas_glue.h" #include "esp_eap_client_i.h" #include "esp_eap_client.h" +#include "eloop.h" #define WPA2_VERSION "v2.0" @@ -63,6 +64,7 @@ static void eap_peer_sm_deinit(void); static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid); static int wpa2_start_eapol_internal(void); int wpa2_post(uint32_t sig, uint32_t par); +extern bool g_wpa_config_changed; #ifdef USE_WPA2_TASK #define WPA2_TASK_PRIORITY 7 @@ -73,6 +75,11 @@ static void *s_wpa2_api_lock = NULL; static void *s_wifi_wpa2_sync_sem = NULL; static bool s_disable_time_check = true; +static void config_changed_handler(void *ctx, void *data) +{ + g_wpa_config_changed = true; +} + static void wpa2_api_lock(void) { if (s_wpa2_api_lock == NULL) { @@ -812,6 +819,7 @@ static esp_err_t esp_client_enable_fn(void *arg) wpa_printf(MSG_ERROR, "Register EAP Peer methods Failure"); } #endif + g_wpa_config_changed = true; return ESP_OK; } @@ -861,6 +869,7 @@ static esp_err_t eap_client_disable_fn(void *param) #endif sm->wpa_sm_eap_disable = NULL; + g_wpa_config_changed = true; return ESP_OK; } @@ -908,6 +917,7 @@ esp_err_t esp_eap_client_set_certificate_and_key(const unsigned char *client_cer g_wpa_private_key_passwd = private_key_passwd; g_wpa_private_key_passwd_len = private_key_passwd_len; } + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -923,6 +933,7 @@ void esp_eap_client_clear_certificate_and_key(void) os_free(g_wpa_pac_file); g_wpa_pac_file = NULL; g_wpa_pac_file_len = 0; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); } esp_err_t esp_eap_client_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len) @@ -933,7 +944,7 @@ esp_err_t esp_eap_client_set_ca_cert(const unsigned char *ca_cert, int ca_cert_l } /* CA certs Set/updated, flushing current PMK cache */ - wpa_sm_pmksa_cache_flush(get_wpa_sm(), NULL); + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -942,6 +953,7 @@ void esp_eap_client_clear_ca_cert(void) { g_wpa_ca_cert = NULL; g_wpa_ca_cert_len = 0; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); } #define ANONYMOUS_ID_LEN_MAX 128 @@ -958,23 +970,27 @@ esp_err_t esp_eap_client_set_identity(const unsigned char *identity, int len) g_wpa_anonymous_identity = (u8 *)os_zalloc(len); if (g_wpa_anonymous_identity == NULL) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_ERR_NO_MEM; } os_memcpy(g_wpa_anonymous_identity, identity, len); g_wpa_anonymous_identity_len = len; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } void esp_eap_client_clear_identity(void) { - if (g_wpa_anonymous_identity) { - os_free(g_wpa_anonymous_identity); + if (!g_wpa_anonymous_identity) { + return; } + os_free(g_wpa_anonymous_identity); g_wpa_anonymous_identity = NULL; g_wpa_anonymous_identity_len = 0; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); } #define USERNAME_LEN_MAX 128 @@ -991,11 +1007,13 @@ esp_err_t esp_eap_client_set_username(const unsigned char *username, int len) g_wpa_username = (u8 *)os_zalloc(len); if (g_wpa_username == NULL) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_ERR_NO_MEM; } os_memcpy(g_wpa_username, username, len); g_wpa_username_len = len; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -1008,6 +1026,7 @@ void esp_eap_client_clear_username(void) g_wpa_username = NULL; g_wpa_username_len = 0; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); } esp_err_t esp_eap_client_set_password(const unsigned char *password, int len) @@ -1023,11 +1042,13 @@ esp_err_t esp_eap_client_set_password(const unsigned char *password, int len) g_wpa_password = (u8 *)os_zalloc(len); if (g_wpa_password == NULL) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_ERR_NO_MEM; } os_memcpy(g_wpa_password, password, len); g_wpa_password_len = len; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -1039,6 +1060,7 @@ void esp_eap_client_clear_password(void) } g_wpa_password = NULL; g_wpa_password_len = 0; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); } esp_err_t esp_eap_client_set_new_password(const unsigned char *new_password, int len) @@ -1054,11 +1076,13 @@ esp_err_t esp_eap_client_set_new_password(const unsigned char *new_password, int g_wpa_new_password = (u8 *)os_zalloc(len); if (g_wpa_new_password == NULL) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_ERR_NO_MEM; } os_memcpy(g_wpa_new_password, new_password, len); g_wpa_password_len = len; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -1070,11 +1094,13 @@ void esp_eap_client_clear_new_password(void) } g_wpa_new_password = NULL; g_wpa_new_password_len = 0; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); } esp_err_t esp_eap_client_set_disable_time_check(bool disable) { s_disable_time_check = disable; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -1111,6 +1137,7 @@ esp_err_t esp_eap_client_set_ttls_phase2_method(esp_eap_ttls_phase2_types type) g_wpa_ttls_phase2_type = "auth=MSCHAPV2"; break; } + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -1118,6 +1145,7 @@ esp_err_t esp_eap_client_set_suiteb_192bit_certification(bool enable) { #ifdef CONFIG_SUITEB192 g_wpa_suiteb_certification = enable; + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; #else return ESP_FAIL; @@ -1136,6 +1164,7 @@ esp_err_t esp_eap_client_set_pac_file(const unsigned char *pac_file, int pac_fil } else { // The file contains pac data g_wpa_pac_file = (u8 *)os_zalloc(pac_file_len); if (g_wpa_pac_file == NULL) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_ERR_NO_MEM; } os_memcpy(g_wpa_pac_file, pac_file, pac_file_len); @@ -1144,6 +1173,7 @@ esp_err_t esp_eap_client_set_pac_file(const unsigned char *pac_file, int pac_fil } else { return ESP_FAIL; } + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -1173,9 +1203,11 @@ esp_err_t esp_eap_client_set_fast_params(esp_eap_fast_config config) } g_wpa_phase1_options = (char *)os_zalloc(sizeof(config_for_supplicant)); if (g_wpa_phase1_options == NULL) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_ERR_NO_MEM; } os_memcpy(g_wpa_phase1_options, &config_for_supplicant, sizeof(config_for_supplicant)); + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } @@ -1189,6 +1221,7 @@ esp_err_t esp_eap_client_use_default_cert_bundle(bool use_default_bundle) } else { esp_crt_bundle_attach_fn = NULL; } + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; #else return ESP_FAIL; @@ -1214,16 +1247,16 @@ esp_err_t esp_eap_client_set_domain_name(const char *domain_name) } if (!domain_name) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; } g_wpa_domain_match = os_strdup(domain_name); if (!g_wpa_domain_match) { + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_ERR_NO_MEM; } - /* flushing the PMK only needed when going for a better security ie no-domain name to domain name - * or changing the domain name */ - wpa_sm_pmksa_cache_flush(get_wpa_sm(), NULL); + eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL); return ESP_OK; #endif diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 31734d110a..0587757fed 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -45,6 +45,7 @@ bool g_wpa_pmk_caching_disabled = 0; const wifi_osi_funcs_t *wifi_funcs; struct wpa_funcs *wpa_cb; +bool g_wpa_config_changed; void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, size_t seq_len, u8 *key, size_t key_len, enum key_flag key_flag) @@ -201,11 +202,22 @@ bool wpa_deattach(void) return true; } +static void wpa_config_reload(void) +{ + struct wpa_sm *sm = &gWpaSm; + wpa_sm_pmksa_cache_flush(sm, NULL); +} + int wpa_sta_connect(uint8_t *bssid) { /* use this API to set AP specific IEs during connection */ int ret = 0; ret = wpa_config_profile(bssid); + + if (g_wpa_config_changed) { + wpa_config_reload(); + g_wpa_config_changed = false; + } if (ret == 0) { ret = wpa_config_bss(bssid); if (ret) { @@ -407,12 +419,6 @@ fail: } #endif -static void wpa_config_reload(void) -{ - struct wpa_sm *sm = &gWpaSm; - wpa_sm_pmksa_cache_flush(sm, NULL); -} - int esp_supplicant_init(void) { int ret = ESP_OK;