From 957313d4c303c6f6beb9fa33f3d1b2d82c85994e Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Wed, 1 Apr 2026 14:24:38 +0530 Subject: [PATCH] fix(esp_wifi): Skip allocation of new buffers during EAP processing --- .../esp_supplicant/src/crypto/tls_mbedtls.c | 164 ++++++++++++------ 1 file changed, 110 insertions(+), 54 deletions(-) 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 d6644da586..93907ac1db 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-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,7 +23,7 @@ */ #define MBEDTLS_ALLOW_PRIVATE_ACCESS -// located at mbedtls/library/ssl_misc.h +// Located in mbedtls/library/ssl_misc.h #include "ssl_misc.h" #include "mbedtls/debug.h" @@ -67,15 +67,16 @@ uint32_t tls_instance_count; struct tls_data { - /* Data for mbedlts */ + /* Data for mbedtls */ struct wpabuf *in_data; + size_t in_data_off; /* Data from mbedtls */ struct wpabuf *out_data; }; typedef struct tls_context { mbedtls_ssl_context ssl; /*!< TLS/SSL context */ - mbedtls_ssl_config conf; /*!< TLS/SSL config to be shared structures */ + mbedtls_ssl_config conf; /*!< TLS/SSL config shared across structures */ mbedtls_x509_crt cacert; /*!< Container for X.509 CA certificate */ mbedtls_x509_crt *cacert_ptr; /*!< Pointer to the cacert being used. */ mbedtls_x509_crt clientcert; /*!< Container for X.509 client certificate */ @@ -114,6 +115,54 @@ static void tls_mbedtls_conn_delete(tls_context_t *tls) } } +static void tls_mbedtls_reset_in_data(struct tls_data *data) +{ + if (data->in_data) { + wpabuf_free(data->in_data); + } + + data->in_data = NULL; + data->in_data_off = 0; +} + +static void tls_mbedtls_reset_out_data(struct tls_data *data) +{ + if (data->out_data) { + wpabuf_free(data->out_data); + } + + data->out_data = NULL; +} + +static int tls_mbedtls_append_in_data(struct tls_data *data, + const struct wpabuf *in_data) +{ + size_t len; + + if (in_data == NULL) { + return 0; + } + + len = wpabuf_len(in_data); + if (len == 0) { + return 0; + } + + if (data->in_data == NULL || + data->in_data_off == wpabuf_len(data->in_data)) { + tls_mbedtls_reset_in_data(data); + data->in_data = wpabuf_dup(in_data); + return data->in_data ? 0 : -1; + } + + if (wpabuf_resize(&data->in_data, len) < 0) { + return -1; + } + + wpabuf_put_data(data->in_data, wpabuf_head(in_data), len); + return 0; +} + static int tls_mbedtls_write(void *ctx, const unsigned char *buf, size_t len) { struct tls_connection *conn = (struct tls_connection *)ctx; @@ -132,25 +181,27 @@ static int tls_mbedtls_read(void *ctx, unsigned char *buf, size_t len) { struct tls_connection *conn = (struct tls_connection *)ctx; struct tls_data *data = &conn->tls_io_data; - struct wpabuf *local_buf; + size_t remaining; - if (data->in_data == NULL || len > wpabuf_len(data->in_data)) { - /* We don't have suffient buffer available for read */ + if (data->in_data == NULL || + data->in_data_off > wpabuf_len(data->in_data)) { + /* We don't have sufficient buffer available for read */ wpa_printf(MSG_INFO, "len=%zu not available in input", len); return MBEDTLS_ERR_SSL_WANT_READ; } - os_memcpy(buf, wpabuf_head(data->in_data), len); - /* adjust buffer */ - if (len < wpabuf_len(data->in_data)) { - /* TODO optimize this operation */ - local_buf = wpabuf_alloc_copy(wpabuf_mhead_u8(data->in_data) + len, - wpabuf_len(data->in_data) - len); - wpabuf_free(data->in_data); - data->in_data = local_buf; - } else { - wpabuf_free(data->in_data); - data->in_data = NULL; + remaining = wpabuf_len(data->in_data) - data->in_data_off; + if (len > remaining) { + /* We don't have sufficient buffer available for read */ + wpa_printf(MSG_INFO, "len=%zu not available in input", len); + return MBEDTLS_ERR_SSL_WANT_READ; + } + + os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->in_data_off, len); + data->in_data_off += len; + + if (data->in_data_off == wpabuf_len(data->in_data)) { + tls_mbedtls_reset_in_data(data); } return len; @@ -161,7 +212,7 @@ static int set_pki_context(tls_context_t *tls, const struct tls_connection_param int ret; if (cfg->client_cert_blob == NULL || cfg->private_key_blob == NULL) { - wpa_printf(MSG_ERROR, "%s: config not correct", __func__); + wpa_printf(MSG_ERROR, "%s: invalid configuration", __func__); return -1; } @@ -443,7 +494,7 @@ static const int suiteb_ciphersuite_preference[] = { static void tls_set_ciphersuite(const struct tls_connection_params *cfg, tls_context_t *tls) { - /* Only set ciphersuite if cert's key length is high or ciphersuites are set by user */ + /* Only set ciphersuite if cert key length is high or ciphersuites are set by user. */ #ifdef CONFIG_SUITEB192 if (cfg->flags & TLS_CONN_SUITEB) { /* cipher suites will be set based on certificate */ @@ -462,7 +513,7 @@ static void tls_set_ciphersuite(const struct tls_connection_params *cfg, tls_con } } else #endif - /* Set cipher suites if User has explicitly set those + /* Set cipher suites if user has explicitly set them. * TODO: public API to set EAP ciphers */ if (tls->ciphersuite[0]) { mbedtls_ssl_conf_ciphersuites(&tls->conf, tls->ciphersuite); @@ -606,7 +657,7 @@ static int tls_create_mbedtls_handle(struct tls_connection *conn, #if defined(CONFIG_MBEDTLS_SSL_PROTO_TLS1_3) && !defined(CONFIG_TLSV13) /* Disable TLSv1.3 even when enabled in MbedTLS and not enabled in WiFi config. - * TODO: Remove Kconfig option for TLSv1.3 when it is matured enough */ + * TODO: Remove Kconfig option for TLSv1.3 when it is mature enough */ mbedtls_ssl_conf_max_tls_version(&tls->conf, MBEDTLS_SSL_VERSION_TLS1_2); #endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 && !CONFIG_TLSV13 */ @@ -621,7 +672,7 @@ static int tls_create_mbedtls_handle(struct tls_connection *conn, mbedtls_ssl_conf_cbc_record_splitting(&tls->conf, MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED); #endif - /* Enable debug prints in case supplicant's prints are enabled */ + /* Enable debug prints if supplicant logging is enabled. */ #if defined(CONFIG_MBEDTLS_DEBUG) && defined(ESPRESSIF_USE) mbedtls_esp_enable_debug_log(&tls->conf, 2); #endif @@ -655,15 +706,18 @@ struct tls_connection * tls_connection_init(void *tls_ctx) void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) { - /* case: tls init failed */ + /* Case: TLS init failed. */ if (!conn) { return; } - /* Free ssl ctx and data */ + tls_mbedtls_reset_in_data(&conn->tls_io_data); + /* Output buffer ownership is transferred to caller before return. */ + conn->tls_io_data.out_data = NULL; + /* Free SSL context and data. */ tls_mbedtls_conn_delete((tls_context_t *) conn->tls); os_free(conn->tls); conn->tls = NULL; - /* Data in in ssl ctx, free connection */ + /* SSL context data is freed above; free connection. */ os_free(conn); } @@ -746,10 +800,12 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx, int ret = 0; struct wpabuf *resp; - /* data freed by sender */ + /* Data is freed by sender. */ conn->tls_io_data.out_data = NULL; - if (wpabuf_len(in_data)) { - conn->tls_io_data.in_data = wpabuf_dup(in_data); + if (tls_mbedtls_append_in_data(&conn->tls_io_data, in_data) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to queue TLS input", __func__); + tls_mbedtls_reset_in_data(&conn->tls_io_data); + return NULL; } /* Multiple reads */ @@ -778,7 +834,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx, } if (!conn->tls_io_data.out_data) { - wpa_printf(MSG_INFO, "application data is null, adding one byte for ack"); + wpa_printf(MSG_INFO, "Application data is NULL; adding one byte for ACK"); u8 *dummy = os_zalloc(1); if (dummy == NULL) { wpa_printf(MSG_INFO, "%s: memory allocation failure. line:%d", __func__, __LINE__); @@ -787,11 +843,15 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx, #ifdef CONFIG_TLSV13 if (mbedtls_ssl_get_version_number(&conn->tls->ssl) == MBEDTLS_SSL_VERSION_TLS1_3) { - *appl_data = wpabuf_alloc_ext_data(dummy, 1); - if (appl_data == NULL) { - wpa_printf(MSG_INFO, "%s: memory allocation failure. line:%d", __func__, __LINE__); + if (appl_data) { + *appl_data = wpabuf_alloc_ext_data(dummy, 1); + if (*appl_data == NULL) { + wpa_printf(MSG_INFO, "%s: memory allocation failure. line:%d", __func__, __LINE__); + os_free(dummy); + goto end; + } + } else { os_free(dummy); - goto end; } return NULL; } @@ -826,13 +886,13 @@ struct wpabuf * tls_connection_encrypt(void *tls_ctx, struct wpabuf *resp; size_t ret; - /* Reset dangling pointer */ + /* Clear dangling pointer. */ conn->tls_io_data.out_data = NULL; ret = mbedtls_ssl_write(&conn->tls->ssl, (unsigned char*) wpabuf_head(in_data), wpabuf_len(in_data)); if (ret < wpabuf_len(in_data)) { - wpa_printf(MSG_ERROR, "%s:%d, not able to write whole data", + wpa_printf(MSG_ERROR, "%s:%d, unable to write all data", __func__, __LINE__); } @@ -853,26 +913,25 @@ struct wpabuf *tls_connection_decrypt(void *tls_ctx, if (!buf) { return NULL; } - /* Reset dangling output buffer before setting data, data was freed by caller */ + /* Clear dangling output buffer before setting data; it was freed by caller. */ conn->tls_io_data.out_data = NULL; - conn->tls_io_data.in_data = wpabuf_dup(in_data); - - if (!conn->tls_io_data.in_data) { + if (tls_mbedtls_append_in_data(&conn->tls_io_data, in_data) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to queue TLS input", __func__); + tls_mbedtls_reset_in_data(&conn->tls_io_data); goto cleanup; } ret = mbedtls_ssl_read(&conn->tls->ssl, buf, MAX_PHASE2_BUFFER); if (ret < 0) { - wpa_printf(MSG_ERROR, "%s:%d, not able to read data", + wpa_printf(MSG_ERROR, "%s:%d, unable to read data", __func__, __LINE__); goto cleanup; } out = wpabuf_alloc_copy(buf, ret); cleanup: - /* there may be some error written in output buffer */ + /* There may be an error written to output buffer. */ if (conn->tls_io_data.out_data) { - os_free(conn->tls_io_data.out_data); - conn->tls_io_data.out_data = NULL; + tls_mbedtls_reset_out_data(&conn->tls_io_data); } os_free(buf); @@ -890,8 +949,8 @@ int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) return 0; } -/* cipher array should contain cipher number in mbedtls num as per IANA - * Please see cipherlist is u8, therefore only initial ones are supported */ +/* Cipher array should contain cipher numbers in mbedtls format, based on IANA values. + * Since cipherlist is u8, only the initial values are supported. */ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, u8 *ciphers) { @@ -972,7 +1031,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, tls_context_t *tls = (tls_context_t *)os_zalloc(sizeof(tls_context_t)); if (!tls) { - wpa_printf(MSG_ERROR, "failed to allocate tls context"); + wpa_printf(MSG_ERROR, "failed to allocate TLS context"); return -1; } if (!params) { @@ -983,7 +1042,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, ret = tls_create_mbedtls_handle(conn, params, tls); if (ret < 0) { - wpa_printf(MSG_ERROR, "failed to create ssl handle"); + wpa_printf(MSG_ERROR, "failed to create SSL handle"); goto err; } mbedtls_ssl_set_bio(&tls->ssl, conn, tls_mbedtls_write, tls_mbedtls_read, NULL); @@ -1031,7 +1090,7 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } if (!ssl) { - wpa_printf(MSG_ERROR, "TLS: %s, session ingo is null", __func__); + wpa_printf(MSG_ERROR, "TLS: %s, session info is null", __func__); return -1; } if (!mbedtls_ssl_is_handshake_over(ssl)) { @@ -1160,12 +1219,9 @@ int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) { - if (conn->tls_io_data.in_data) { - wpabuf_free(conn->tls_io_data.in_data); - } - conn->tls_io_data.in_data = NULL; + tls_mbedtls_reset_in_data(&conn->tls_io_data); - /* outdata may have dangling pointer */ + /* Output buffer ownership is transferred to caller before return. */ conn->tls_io_data.out_data = NULL; return mbedtls_ssl_session_reset(&conn->tls->ssl);