Skip to content

Commit 5928a87

Browse files
committed
feat(mbedtls): Add configuration to control dynamic buffer strategy in mbedtls
Problem: 1. In low-memory scenarios, the dynamic buffer feature can fail due to memory fragmentation. 2. It requires a contiguous 16KB heap chunk, but continuous allocation and deallocation of the RX buffer can lead to fragmentation. 3. If another component allocates memory between these operations, it can break up the available 16KB block, causing allocation failure. Solution: 1. Introduce configurable strategy for using dynamic buffers in TLS connections. 2. For example, convert RX buffers to static after the TLS handshake. 3. Allow users to select the strategy via a new field in the esp_http_client_cfg_t structure. 4. The strategy can be controlled independently for each TLS session.
1 parent 456ae96 commit 5928a87

File tree

14 files changed

+217
-6
lines changed

14 files changed

+217
-6
lines changed

components/esp-tls/esp_tls.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -91,6 +91,12 @@ typedef enum {
9191
ESP_TLS_VER_TLS_MAX, /* to indicate max */
9292
} esp_tls_proto_ver_t;
9393

94+
typedef enum {
95+
ESP_TLS_DYN_BUF_RX_STATIC = 1, /*!< Strategy to disable dynamic RX buffer allocations and convert to static allocation post-handshake, reducing memory fragmentation */
96+
ESP_TLS_DYN_BUF_STRATEGY_MAX, /*!< to indicate max */
97+
} esp_tls_dyn_buf_strategy_t;
98+
99+
94100
/**
95101
* @brief ESP-TLS configuration parameters
96102
*
@@ -213,6 +219,11 @@ typedef struct esp_tls_cfg {
213219
const int *ciphersuites_list; /*!< Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites.
214220
Please check the list validity by esp_tls_get_ciphersuites_list() API */
215221
esp_tls_proto_ver_t tls_version; /*!< TLS protocol version of the connection, e.g., TLS 1.2, TLS 1.3 (default - no preference) */
222+
223+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
224+
esp_tls_dyn_buf_strategy_t esp_tls_dyn_buf_strategy; /*!< ESP-TLS dynamic buffer strategy */
225+
#endif
226+
216227
} esp_tls_cfg_t;
217228

218229
#if defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS)

components/esp-tls/esp_tls_mbedtls.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include <errno.h>
2121
#include "esp_log.h"
2222
#include "esp_check.h"
23-
23+
#include "mbedtls/esp_mbedtls_dynamic.h"
2424
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
2525
#include "ecdsa/ecdsa_alt.h"
2626
#endif
@@ -115,6 +115,10 @@ esp_err_t esp_create_mbedtls_handle(const char *hostname, size_t hostlen, const
115115

116116
mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg);
117117

118+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
119+
tls->esp_tls_dyn_buf_strategy = ((esp_tls_cfg_t *)cfg)->esp_tls_dyn_buf_strategy;
120+
#endif
121+
118122
if (tls->role == ESP_TLS_CLIENT) {
119123
esp_ret = set_client_config(hostname, hostlen, (esp_tls_cfg_t *)cfg, tls);
120124
if (esp_ret != ESP_OK) {
@@ -256,6 +260,15 @@ int esp_mbedtls_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
256260
#endif
257261
ret = mbedtls_ssl_handshake(&tls->ssl);
258262
if (ret == 0) {
263+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
264+
if (tls->esp_tls_dyn_buf_strategy != 0) {
265+
ret = esp_mbedtls_dynamic_set_rx_buf_static(&tls->ssl);
266+
if (ret != 0) {
267+
ESP_LOGE(TAG, "esp_mbedtls_dynamic_set_rx_buf_static returned -0x%04X", -ret);
268+
return ret;
269+
}
270+
}
271+
#endif
259272
tls->conn_state = ESP_TLS_DONE;
260273

261274
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL

components/esp-tls/private_include/esp_tls_private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ struct esp_tls {
9898

9999
esp_tls_error_handle_t error_handle; /*!< handle to error descriptor */
100100

101+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
102+
esp_tls_dyn_buf_strategy_t esp_tls_dyn_buf_strategy; /*!< ESP-TLS dynamic buffer strategy */
103+
#endif
104+
101105
};
102106

103107
// Function pointer for the server configuration API

components/esp_http_client/esp_http_client.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ static const char *TAG = "HTTP_CLIENT";
3434

3535
ESP_STATIC_ASSERT((int)ESP_HTTP_CLIENT_TLS_VER_ANY == (int)ESP_TLS_VER_ANY, "Enum mismatch in esp_http_client and esp-tls");
3636
ESP_STATIC_ASSERT((int)ESP_HTTP_CLIENT_TLS_VER_MAX <= (int)ESP_TLS_VER_TLS_MAX, "HTTP client supported TLS is not supported in esp-tls");
37+
ESP_STATIC_ASSERT((int)HTTP_TLS_DYN_BUF_RX_STATIC == (int)ESP_TLS_DYN_BUF_RX_STATIC, "Enum mismatch in esp_http_client and esp-tls");
38+
ESP_STATIC_ASSERT((int)HTTP_TLS_DYN_BUF_STRATEGY_MAX <= (int)ESP_TLS_DYN_BUF_STRATEGY_MAX, "HTTP client supported TLS is not supported in esp-tls");
3739

3840
#if CONFIG_ESP_HTTP_CLIENT_EVENT_POST_TIMEOUT == -1
3941
#define ESP_HTTP_CLIENT_EVENT_POST_TIMEOUT portMAX_DELAY
@@ -842,6 +844,14 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
842844
}
843845
esp_transport_ssl_set_tls_version(ssl, config->tls_version);
844846

847+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
848+
/* When tls_dyn_buf_strategy is 0, mbedTLS dynamic buffer allocation uses default behavior.
849+
* No need to call esp_transport_ssl_set_esp_tls_dyn_buf_strategy() in this case */
850+
if (config->tls_dyn_buf_strategy != 0 && config->tls_dyn_buf_strategy < HTTP_TLS_DYN_BUF_STRATEGY_MAX) {
851+
esp_transport_ssl_set_esp_tls_dyn_buf_strategy(ssl, config->tls_dyn_buf_strategy);
852+
}
853+
#endif
854+
845855
#if CONFIG_ESP_TLS_USE_SECURE_ELEMENT
846856
if (config->use_secure_element) {
847857
esp_transport_ssl_use_secure_element(ssl);

components/esp_http_client/include/esp_http_client.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ typedef enum {
138138
HTTP_ADDR_TYPE_INET6 = AF_INET6, /**< IPv6 address family. */
139139
} esp_http_client_addr_type_t;
140140

141+
typedef enum {
142+
HTTP_TLS_DYN_BUF_RX_STATIC = 1, /*!< Strategy to disable dynamic RX buffer allocations and convert to static allocation post-handshake, reducing memory fragmentation */
143+
HTTP_TLS_DYN_BUF_STRATEGY_MAX, /*!< to indicate max */
144+
} esp_http_client_tls_dyn_buf_strategy_t;
145+
141146
/**
142147
* @brief HTTP configuration
143148
*/
@@ -214,6 +219,10 @@ typedef struct {
214219
struct esp_transport_item_t *transport;
215220
#endif
216221
esp_http_client_addr_type_t addr_type; /*!< Address type used in http client configurations */
222+
223+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
224+
esp_http_client_tls_dyn_buf_strategy_t tls_dyn_buf_strategy; /*!< TLS dynamic buffer strategy */
225+
#endif
217226
} esp_http_client_config_t;
218227

219228
/**

components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@
1818

1919
#define TX_IDLE_BUFFER_SIZE (MBEDTLS_SSL_HEADER_LEN + CACHE_BUFFER_SIZE)
2020

21+
#define ESP_MBEDTLS_RETURN_IF_RX_BUF_STATIC(ssl) \
22+
do { \
23+
if (ssl->MBEDTLS_PRIVATE(in_buf)) { \
24+
esp_mbedtls_ssl_buf_states state = esp_mbedtls_get_buf_state(ssl->MBEDTLS_PRIVATE(in_buf)); \
25+
if (state == ESP_MBEDTLS_SSL_BUF_STATIC) { \
26+
return 0; \
27+
} \
28+
} \
29+
} while(0)
30+
31+
2132
static const char *TAG = "Dynamic Impl";
2233

2334
static void esp_mbedtls_set_buf_state(unsigned char *buf, esp_mbedtls_ssl_buf_states state)
@@ -140,6 +151,29 @@ static void init_rx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
140151
ssl->MBEDTLS_PRIVATE(in_left) = 0;
141152
}
142153

154+
esp_err_t esp_mbedtls_dynamic_set_rx_buf_static(mbedtls_ssl_context *ssl)
155+
{
156+
unsigned char cache_buf[16];
157+
memcpy(cache_buf, ssl->MBEDTLS_PRIVATE(in_buf), 16);
158+
esp_mbedtls_reset_free_rx_buffer(ssl);
159+
160+
struct esp_mbedtls_ssl_buf *esp_buf;
161+
int buffer_len = tx_buffer_len(ssl, MBEDTLS_SSL_IN_BUFFER_LEN);
162+
esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + buffer_len);
163+
if (!esp_buf) {
164+
ESP_LOGE(TAG, "rx buf alloc(%d bytes) failed", SSL_BUF_HEAD_OFFSET_SIZE + buffer_len);
165+
return ESP_ERR_NO_MEM;
166+
}
167+
esp_mbedtls_init_ssl_buf(esp_buf, buffer_len);
168+
init_rx_buffer(ssl, esp_buf->buf);
169+
170+
memcpy(ssl->MBEDTLS_PRIVATE(in_ctr), cache_buf, 8);
171+
memcpy(ssl->MBEDTLS_PRIVATE(in_iv), cache_buf + 8, 8);
172+
esp_mbedtls_set_buf_state(ssl->MBEDTLS_PRIVATE(in_buf), ESP_MBEDTLS_SSL_BUF_STATIC);
173+
return ESP_OK;
174+
175+
}
176+
143177
static int esp_mbedtls_alloc_tx_buf(mbedtls_ssl_context *ssl, int len)
144178
{
145179
struct esp_mbedtls_ssl_buf *esp_buf;
@@ -324,6 +358,12 @@ int esp_mbedtls_free_tx_buffer(mbedtls_ssl_context *ssl)
324358

325359
int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl)
326360
{
361+
/*
362+
* If RX buffer is set to static mode, this macro will return early
363+
* and skip dynamic buffer allocation logic below
364+
*/
365+
ESP_MBEDTLS_RETURN_IF_RX_BUF_STATIC(ssl);
366+
327367
int cached = 0;
328368
int ret = 0;
329369
int buffer_len;
@@ -405,6 +445,12 @@ int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl)
405445

406446
int esp_mbedtls_free_rx_buffer(mbedtls_ssl_context *ssl)
407447
{
448+
/*
449+
* If RX buffer is set to static mode, this macro will return early
450+
* and skip dynamic buffer free logic below
451+
*/
452+
ESP_MBEDTLS_RETURN_IF_RX_BUF_STATIC(ssl);
453+
408454
int ret = 0;
409455
unsigned char buf[16];
410456
struct esp_mbedtls_ssl_buf *esp_buf;

components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -26,6 +26,8 @@
2626
#include "esp_log.h"
2727
#include "sdkconfig.h"
2828

29+
#include "mbedtls/esp_mbedtls_dynamic.h"
30+
2931
#define TRACE_CHECK(_fn, _state) \
3032
({ \
3133
ESP_LOGV(TAG, "%d " _state " to do \"%s\"", __LINE__, # _fn); \
@@ -48,8 +50,9 @@
4850
})
4951

5052
typedef enum {
51-
ESP_MBEDTLS_SSL_BUF_CACHED,
53+
ESP_MBEDTLS_SSL_BUF_CACHED = 0,
5254
ESP_MBEDTLS_SSL_BUF_NO_CACHED,
55+
ESP_MBEDTLS_SSL_BUF_STATIC,
5356
} esp_mbedtls_ssl_buf_states;
5457

5558
struct esp_mbedtls_ssl_buf {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include "mbedtls/ssl.h"
10+
#include "esp_err.h"
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/**
17+
* @brief Set the dynamic buffer rx statically after the handshake. This is to avoid frequent allocation and deallocation of dynamic buffer.
18+
*
19+
* @param ssl mbedtls ssl context
20+
* @return esp_err_t
21+
* - ESP_OK: Successfully set the rx buffer to static
22+
* - ESP_ERR_NO_MEM: Failed to allocate memory for the rx buffer
23+
*/
24+
esp_err_t esp_mbedtls_dynamic_set_rx_buf_static(mbedtls_ssl_context *ssl);
25+
26+
#ifdef __cplusplus
27+
}
28+
#endif

components/tcp_transport/include/esp_transport_ssl.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -61,6 +61,15 @@ void esp_transport_ssl_crt_bundle_attach(esp_transport_handle_t t, esp_err_t ((*
6161
*/
6262
void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t);
6363

64+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
65+
/**
66+
* @brief Set ESP-TLS dynamic buffer strategy for ESP-TLS connection
67+
*
68+
* @param t ssl transport
69+
* @param[in] strategy ESP-TLS dynamic buffer strategy
70+
*/
71+
void esp_transport_ssl_set_esp_tls_dyn_buf_strategy(esp_transport_handle_t t, esp_tls_dyn_buf_strategy_t strategy);
72+
#endif
6473
/**
6574
* @brief Set TLS protocol version for ESP-TLS connection
6675
*

components/tcp_transport/transport_ssl.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -365,6 +365,14 @@ void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t)
365365
ssl->cfg.use_global_ca_store = true;
366366
}
367367

368+
#if CONFIG_MBEDTLS_DYNAMIC_BUFFER
369+
void esp_transport_ssl_set_esp_tls_dyn_buf_strategy(esp_transport_handle_t t, esp_tls_dyn_buf_strategy_t strategy)
370+
{
371+
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);
372+
ssl->cfg.esp_tls_dyn_buf_strategy = strategy;
373+
}
374+
#endif
375+
368376
void esp_transport_ssl_set_tls_version(esp_transport_handle_t t, esp_tls_proto_ver_t tls_version)
369377
{
370378
GET_SSL_FROM_TRANSPORT_OR_RETURN(ssl, t);

0 commit comments

Comments
 (0)