components/mbedtls/port/dynamic/dynamic_buffer_architecture.md
ESP-IDF implements a dynamic buffer management system for mbedTLS to optimize memory usage during TLS/SSL connections. This architecture significantly reduces RAM requirements on memory-constrained ESP devices by intelligently allocating buffers only when needed and sizing them according to actual message requirements rather than worst-case scenarios.
Standard TLS implementations allocate large static buffers that:
On memory-constrained IoT devices like ESP32, this traditional approach is inefficient and limits the number of concurrent connections possible.
Instead of static allocation, our system:
[Small idle buffer] → [Right-sized TX buffer] → [Back to small buffer]
[No buffer] → [Header buffer] → [Right-sized RX buffer] → [Small cache buffer]
Our implementation follows these steps for each operation:
We use a custom buffer structure that includes metadata:
struct esp_mbedtls_ssl_buf {
esp_mbedtls_ssl_buf_states state; // CACHED or NOT_CACHED
unsigned int len; // Buffer size
unsigned char buf[0]; // Flexible array for actual data
};
This structure allows us to:
The state tracking is critical for maintaining TLS protocol security while optimizing memory.
When replacing large buffers with small cache buffers, we preserve:
These small amounts of cryptographic state must be maintained between operations to keep the TLS connection secure.
| Function | Purpose |
|---|---|
esp_mbedtls_add_tx_buffer() | Allocates a transmission buffer sized for the outgoing message |
esp_mbedtls_free_tx_buffer() | Replaces TX buffer with small cache buffer after transmission |
esp_mbedtls_add_rx_buffer() | Reads record header and allocates right-sized reception buffer |
esp_mbedtls_free_rx_buffer() | Replaces RX buffer with small cache buffer after processing |
We intercept key mbedTLS functions using GCC's function wrapping:
int __wrap_mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len) {
// 1. Allocate right-sized buffer
// 2. Call original function
// 3. Free buffer when done
}
This allows seamless integration without modifying the mbedTLS source code.
During TLS handshaking, memory needs change dramatically between steps. Our system tracks the handshake state and manages memory accordingly:
| Handshake Step | Memory Action |
|---|---|
| Client Hello | Allocate TX buffer |
| Server Hello | Allocate RX buffer |
| Server Certificate | Allocate RX buffer |
| Certificate Verify | Allocate TX buffer |
| Free certificate resources | Release CA certificates |
| Client Key Exchange | Allocate TX buffer |
| Change Cipher Spec | Small buffer |
| Finished | Small buffers |
The dynamic buffer allocation for SSL read operations follows this design:
// Read just the header to determine full message size
ssl->in_hdr = msg_head;
ssl->in_len = msg_head + 3;
mbedtls_ssl_fetch_input(ssl, mbedtls_ssl_in_hdr_len(ssl));
// Parse header to get message length
esp_mbedtls_parse_record_header(ssl);
in_msglen = ssl->in_msglen;
// Allocate buffer of right size
buffer_len = in_msglen + overhead; // Add necessary TLS overhead
esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + buffer_len);
// Initialize and set up buffer
esp_mbedtls_init_ssl_buf(esp_buf, buffer_len);
init_rx_buffer(ssl, esp_buf->buf);
// Save critical state (counters and IVs)
memcpy(buf, ssl->in_ctr, 8);
memcpy(buf + 8, ssl->in_iv, 8);
// Free large buffer
esp_mbedtls_free_buf(ssl->in_buf);
// Allocate small cache buffer
esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + 16);
esp_mbedtls_init_ssl_buf(esp_buf, 16);
// Restore critical state in small buffer
memcpy(esp_buf->buf, buf, 16);
The dynamic buffer system includes configurable options:
CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT: Free CA certificates after verificationCONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA: Free DHM parameters and key material when no longer neededThese can be enabled in ESP-IDF's menuconfig system.
The implementation uses function wrapping to seamlessly integrate with mbedTLS:
Application → mbedTLS API → Our Wrapper Functions → Original mbedTLS Functions
Key wrapped functions include:
mbedtls_ssl_setup: Initialize with minimal buffersmbedtls_ssl_read/mbedtls_ssl_write: Dynamic buffer management during I/Ombedtls_ssl_handshake_client_step: Handshake-aware memory managementmbedtls_ssl_free: Clean up all allocated memoryThe dynamic buffer management design provides several key benefits:
The dynamic buffer management system in ESP-IDF's mbedTLS port follows a sophisticated architecture that:
This architecture enables more efficient use of RAM on memory-constrained devices while maintaining the security guarantees of the TLS protocol.