Merge branch 'feat/eap_domain_check_v5.2' into 'release/v5.2'

esp_wifi: Add EAP domain validation support (v5.2)

See merge request espressif/esp-idf!38281
This commit is contained in:
Jiang Jiang Jian
2025-04-14 14:26:59 +08:00
11 changed files with 186 additions and 41 deletions

View File

@ -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
*/
@ -321,6 +321,22 @@ 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);
/**
* 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.
*
* @attention 1. The `domain_name` should be a NULL-terminated string.
*
* @param[in] domain_name The expected domain name. Pass `NULL` to clear the domain matching.
*
* @return
* - 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_name(const char *domain_name);
#ifdef __cplusplus
}
#endif

View File

@ -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,9 +535,15 @@ 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*/
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) {
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);

View File

@ -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
*/
@ -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)
@ -932,6 +943,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 */
eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL);
return ESP_OK;
}
@ -939,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
@ -955,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
@ -988,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;
}
@ -1005,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)
@ -1020,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;
}
@ -1036,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)
@ -1051,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;
}
@ -1067,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;
}
@ -1108,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;
}
@ -1115,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;
@ -1133,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);
@ -1141,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;
}
@ -1170,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;
}
@ -1186,8 +1221,43 @@ 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;
#endif
}
#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;
}
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;
}
eloop_register_timeout(0, 0, config_changed_handler, NULL, NULL);
return ESP_OK;
#endif
}

View File

@ -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) {
@ -413,12 +425,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;

View File

@ -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 */

View File

@ -67,6 +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);
@ -518,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;

View File

@ -49,6 +49,10 @@ 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);
struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id);

View File

@ -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
*/

View File

@ -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;

View File

@ -98,4 +98,19 @@ menu "Example Configuration"
default n
help
Use default CA certificate bundle for WiFi enterprise connection
config EXAMPLE_VALIDATE_SERVER_CERT_DOMAIN
bool "Enable server certificate domain validation"
depends on EXAMPLE_VALIDATE_SERVER_CERT
default n
help
Enable validation of the server certificate's domain name.
config EXAMPLE_SERVER_CERT_DOMAIN
string "Expected server certificate domain"
depends on EXAMPLE_VALIDATE_SERVER_CERT_DOMAIN
default "espressif.com"
help
Specify the expected domain name for the server certificate.
The connection will be accepted only if the server certificate matches this domain.
endmenu

View File

@ -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;
@ -150,6 +151,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_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());