fix(esp_wifi): Skip allocation of new buffers during EAP processing

This commit is contained in:
Kapil Gupta
2026-04-23 09:47:38 +05:30
parent 7c1fd3fbbf
commit 8a197ec0ea
@@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -23,7 +23,7 @@
*/ */
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
// located at mbedtls/library/ssl_misc.h // Located in mbedtls/library/ssl_misc.h
#include "ssl_misc.h" #include "ssl_misc.h"
#include "mbedtls/debug.h" #include "mbedtls/debug.h"
@@ -67,15 +67,16 @@
uint32_t tls_instance_count; uint32_t tls_instance_count;
struct tls_data { struct tls_data {
/* Data for mbedlts */ /* Data for mbedtls */
struct wpabuf *in_data; struct wpabuf *in_data;
size_t in_data_off;
/* Data from mbedtls */ /* Data from mbedtls */
struct wpabuf *out_data; struct wpabuf *out_data;
}; };
typedef struct tls_context { typedef struct tls_context {
mbedtls_ssl_context ssl; /*!< TLS/SSL 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; /*!< Container for X.509 CA certificate */
mbedtls_x509_crt *cacert_ptr; /*!< Pointer to the cacert being used. */ mbedtls_x509_crt *cacert_ptr; /*!< Pointer to the cacert being used. */
mbedtls_x509_crt clientcert; /*!< Container for X.509 client certificate */ 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) static int tls_mbedtls_write(void *ctx, const unsigned char *buf, size_t len)
{ {
struct tls_connection *conn = (struct tls_connection *)ctx; 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_connection *conn = (struct tls_connection *)ctx;
struct tls_data *data = &conn->tls_io_data; 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)) { if (data->in_data == NULL ||
/* We don't have suffient buffer available for read */ 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); wpa_printf(MSG_INFO, "len=%zu not available in input", len);
return MBEDTLS_ERR_SSL_WANT_READ; return MBEDTLS_ERR_SSL_WANT_READ;
} }
os_memcpy(buf, wpabuf_head(data->in_data), len); remaining = wpabuf_len(data->in_data) - data->in_data_off;
/* adjust buffer */ if (len > remaining) {
if (len < wpabuf_len(data->in_data)) { /* We don't have sufficient buffer available for read */
/* TODO optimize this operation */ wpa_printf(MSG_INFO, "len=%zu not available in input", len);
local_buf = wpabuf_alloc_copy(wpabuf_mhead_u8(data->in_data) + len, return MBEDTLS_ERR_SSL_WANT_READ;
wpabuf_len(data->in_data) - len); }
wpabuf_free(data->in_data);
data->in_data = local_buf; os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->in_data_off, len);
} else { data->in_data_off += len;
wpabuf_free(data->in_data);
data->in_data = NULL; if (data->in_data_off == wpabuf_len(data->in_data)) {
tls_mbedtls_reset_in_data(data);
} }
return len; return len;
@@ -161,7 +212,7 @@ static int set_pki_context(tls_context_t *tls, const struct tls_connection_param
int ret; int ret;
if (cfg->client_cert_blob == NULL || cfg->private_key_blob == NULL) { 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; 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) 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 #ifdef CONFIG_SUITEB192
if (cfg->flags & TLS_CONN_SUITEB) { if (cfg->flags & TLS_CONN_SUITEB) {
/* cipher suites will be set based on certificate */ /* 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 } else
#endif #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 */ * TODO: public API to set EAP ciphers */
if (tls->ciphersuite[0]) { if (tls->ciphersuite[0]) {
mbedtls_ssl_conf_ciphersuites(&tls->conf, tls->ciphersuite); 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) #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. /* 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); mbedtls_ssl_conf_max_tls_version(&tls->conf, MBEDTLS_SSL_VERSION_TLS1_2);
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 && !CONFIG_TLSV13 */ #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); mbedtls_ssl_conf_cbc_record_splitting(&tls->conf, MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED);
#endif #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) #if defined(CONFIG_MBEDTLS_DEBUG) && defined(ESPRESSIF_USE)
mbedtls_esp_enable_debug_log(&tls->conf, 2); mbedtls_esp_enable_debug_log(&tls->conf, 2);
#endif #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) void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
{ {
/* case: tls init failed */ /* Case: TLS init failed. */
if (!conn) { if (!conn) {
return; 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); tls_mbedtls_conn_delete((tls_context_t *) conn->tls);
os_free(conn->tls); os_free(conn->tls);
conn->tls = NULL; conn->tls = NULL;
/* Data in in ssl ctx, free connection */ /* SSL context data is freed above; free connection. */
os_free(conn); os_free(conn);
} }
@@ -746,10 +800,12 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
int ret = 0; int ret = 0;
struct wpabuf *resp; struct wpabuf *resp;
/* data freed by sender */ /* Data is freed by sender. */
conn->tls_io_data.out_data = NULL; conn->tls_io_data.out_data = NULL;
if (wpabuf_len(in_data)) { if (tls_mbedtls_append_in_data(&conn->tls_io_data, in_data) < 0) {
conn->tls_io_data.in_data = wpabuf_dup(in_data); wpa_printf(MSG_ERROR, "%s: failed to queue TLS input", __func__);
tls_mbedtls_reset_in_data(&conn->tls_io_data);
return NULL;
} }
/* Multiple reads */ /* Multiple reads */
@@ -778,7 +834,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
} }
if (!conn->tls_io_data.out_data) { 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); u8 *dummy = os_zalloc(1);
if (dummy == NULL) { if (dummy == NULL) {
wpa_printf(MSG_INFO, "%s: memory allocation failure. line:%d", __func__, __LINE__); 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 #ifdef CONFIG_TLSV13
if (mbedtls_ssl_get_version_number(&conn->tls->ssl) == MBEDTLS_SSL_VERSION_TLS1_3) { 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) {
if (appl_data == NULL) { *appl_data = wpabuf_alloc_ext_data(dummy, 1);
wpa_printf(MSG_INFO, "%s: memory allocation failure. line:%d", __func__, __LINE__); 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); os_free(dummy);
goto end;
} }
return NULL; return NULL;
} }
@@ -826,13 +886,13 @@ struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct wpabuf *resp; struct wpabuf *resp;
size_t ret; size_t ret;
/* Reset dangling pointer */ /* Clear dangling pointer. */
conn->tls_io_data.out_data = NULL; conn->tls_io_data.out_data = NULL;
ret = mbedtls_ssl_write(&conn->tls->ssl, ret = mbedtls_ssl_write(&conn->tls->ssl,
(unsigned char*) wpabuf_head(in_data), wpabuf_len(in_data)); (unsigned char*) wpabuf_head(in_data), wpabuf_len(in_data));
if (ret < 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__); __func__, __LINE__);
} }
@@ -853,26 +913,25 @@ struct wpabuf *tls_connection_decrypt(void *tls_ctx,
if (!buf) { if (!buf) {
return NULL; 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.out_data = NULL;
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__);
if (!conn->tls_io_data.in_data) { tls_mbedtls_reset_in_data(&conn->tls_io_data);
goto cleanup; goto cleanup;
} }
ret = mbedtls_ssl_read(&conn->tls->ssl, buf, MAX_PHASE2_BUFFER); ret = mbedtls_ssl_read(&conn->tls->ssl, buf, MAX_PHASE2_BUFFER);
if (ret < 0) { 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__); __func__, __LINE__);
goto cleanup; goto cleanup;
} }
out = wpabuf_alloc_copy(buf, ret); out = wpabuf_alloc_copy(buf, ret);
cleanup: 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) { if (conn->tls_io_data.out_data) {
os_free(conn->tls_io_data.out_data); tls_mbedtls_reset_out_data(&conn->tls_io_data);
conn->tls_io_data.out_data = NULL;
} }
os_free(buf); os_free(buf);
@@ -890,8 +949,8 @@ int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
return 0; return 0;
} }
/* cipher array should contain cipher number in mbedtls num as per IANA /* Cipher array should contain cipher numbers in mbedtls format, based on IANA values.
* Please see cipherlist is u8, therefore only initial ones are supported */ * Since cipherlist is u8, only the initial values are supported. */
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers) 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)); tls_context_t *tls = (tls_context_t *)os_zalloc(sizeof(tls_context_t));
if (!tls) { if (!tls) {
wpa_printf(MSG_ERROR, "failed to allocate tls context"); wpa_printf(MSG_ERROR, "failed to allocate TLS context");
return -1; return -1;
} }
if (!params) { 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); ret = tls_create_mbedtls_handle(conn, params, tls);
if (ret < 0) { if (ret < 0) {
wpa_printf(MSG_ERROR, "failed to create ssl handle"); wpa_printf(MSG_ERROR, "failed to create SSL handle");
goto err; goto err;
} }
mbedtls_ssl_set_bio(&tls->ssl, conn, tls_mbedtls_write, tls_mbedtls_read, NULL); 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) { 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; return -1;
} }
if (!mbedtls_ssl_is_handshake_over(ssl)) { 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) int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{ {
if (conn->tls_io_data.in_data) { tls_mbedtls_reset_in_data(&conn->tls_io_data);
wpabuf_free(conn->tls_io_data.in_data);
}
conn->tls_io_data.in_data = NULL;
/* outdata may have dangling pointer */ /* Output buffer ownership is transferred to caller before return. */
conn->tls_io_data.out_data = NULL; conn->tls_io_data.out_data = NULL;
return mbedtls_ssl_session_reset(&conn->tls->ssl); return mbedtls_ssl_session_reset(&conn->tls->ssl);