Explorar el Código

feat(mbedtls): add dynamic buffer and local resource managment to decrease SSL heap cost

Dong Heng hace 5 años
padre
commit
3d57bf30a2

+ 29 - 2
components/mbedtls/CMakeLists.txt

@@ -67,9 +67,19 @@ set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls})
 
 set(mbedtls_targets mbedtls mbedcrypto mbedx509)
 
+set(mbedtls_target_sources "${COMPONENT_DIR}/port/mbedtls_debug.c"
+                           "${COMPONENT_DIR}/port/net_sockets.c")
+
+if(CONFIG_MBEDTLS_DYNAMIC_BUFFER)
+set(mbedtls_target_sources ${mbedtls_target_sources}
+                           "${COMPONENT_DIR}/port/dynamic/esp_mbedtls_dynamic_impl.c"
+                           "${COMPONENT_DIR}/port/dynamic/esp_ssl_cli.c"
+                           "${COMPONENT_DIR}/port/dynamic/esp_ssl_srv.c"
+                           "${COMPONENT_DIR}/port/dynamic/esp_ssl_tls.c")
+endif()
+
 # Add port files to mbedtls targets
-target_sources(mbedtls PRIVATE  "${COMPONENT_DIR}/port/mbedtls_debug.c"
-                                "${COMPONENT_DIR}/port/net_sockets.c")
+target_sources(mbedtls PRIVATE ${mbedtls_target_sources})
 
 
 
@@ -90,6 +100,23 @@ foreach(target ${mbedtls_targets})
     target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h")
 endforeach()
 
+if(CONFIG_MBEDTLS_DYNAMIC_BUFFER)
+    set(WRAP_FUNCTIONS
+        mbedtls_ssl_handshake_client_step
+        mbedtls_ssl_handshake_server_step
+        mbedtls_ssl_read
+        mbedtls_ssl_write
+        mbedtls_ssl_session_reset
+        mbedtls_ssl_free
+        mbedtls_ssl_setup
+        mbedtls_ssl_send_alert_message
+        mbedtls_ssl_close_notify)
+
+    foreach(wrap ${WRAP_FUNCTIONS})
+        target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}")
+    endforeach()
+endif()
+
 set_property(TARGET mbedcrypto APPEND PROPERTY LINK_INTERFACE_LIBRARIES mbedtls)
 
 # Link mbedtls libraries to component library

+ 34 - 0
components/mbedtls/Kconfig

@@ -92,6 +92,40 @@ menu "mbedTLS"
             This defines maximum outgoing fragment length, overriding default
             maximum content length (MBEDTLS_SSL_MAX_CONTENT_LEN).
 
+    config MBEDTLS_DYNAMIC_BUFFER
+        bool "Using dynamic TX/RX buffer"
+        default n
+        select MBEDTLS_ASYMMETRIC_CONTENT_LEN
+        help
+            Using dynamic TX/RX buffer. After enabling this option, mbedTLS will
+            allocate TX buffer when need to send data and then free it if all data
+            is sent, allocate RX buffer when need to receive data and then free it
+            when all data is used or read by upper layer.
+
+            By default, when SSL is initialized, mbedTLS also allocate TX and
+            RX buffer with the default value of "MBEDTLS_SSL_OUT_CONTENT_LEN" or
+            "MBEDTLS_SSL_IN_CONTENT_LEN", so to save more heap, users can set
+            the options to be an appropriate value.
+
+    config MBEDTLS_DYNAMIC_FREE_PEER_CERT
+        bool "Free SSL peer certificate after its usage"
+        default n
+        depends on MBEDTLS_DYNAMIC_BUFFER
+        help
+            Free peer certificate after its usage in handshake process.
+
+    config MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+        bool "Free certificate, key and DHM data after its usage"
+        default n
+        depends on MBEDTLS_DYNAMIC_BUFFER
+        help
+            Free certificate, private key and DHM data after its usage in handshake process.
+
+            The option will decrease heap cost when handshake, but also lead to problem:
+
+            Becasue all certificate, private key and DHM data are freed so users should register
+            certificate and private key to ssl config object again.
+
     config MBEDTLS_DEBUG
         bool "Enable mbedTLS debugging"
         default n

+ 19 - 0
components/mbedtls/component.mk

@@ -43,3 +43,22 @@ COMPONENT_EMBED_FILES := $(X509_CERTIFICATE_BUNDLE)
 
 endif
 
+ifdef CONFIG_MBEDTLS_DYNAMIC_BUFFER
+
+WRAP_FUNCTIONS = mbedtls_ssl_handshake_client_step \
+                 mbedtls_ssl_handshake_server_step \
+                 mbedtls_ssl_read \
+                 mbedtls_ssl_write \
+                 mbedtls_ssl_session_reset \
+                 mbedtls_ssl_free \
+                 mbedtls_ssl_setup \
+                 mbedtls_ssl_send_alert_message \
+                 mbedtls_ssl_close_notify
+
+WRAP_ARGUMENT := -Wl,--wrap=
+
+COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) $(addprefix $(WRAP_ARGUMENT),$(WRAP_FUNCTIONS))
+
+COMPONENT_SRCDIRS += port/dynamic
+
+endif

+ 518 - 0
components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.c

@@ -0,0 +1,518 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+#include "esp_mbedtls_dynamic_impl.h"
+
+#define COUNTER_SIZE (8)
+#define CACHE_IV_SIZE (16)
+#define CACHE_BUFFER_SIZE (CACHE_IV_SIZE + COUNTER_SIZE)
+
+#define TX_IDLE_BUFFER_SIZE (MBEDTLS_SSL_HEADER_LEN + CACHE_BUFFER_SIZE)
+
+static const char *TAG = "Dynamic Impl";
+
+static void esp_mbedtls_parse_record_header(mbedtls_ssl_context *ssl)
+{
+    ssl->in_msgtype =  ssl->in_hdr[0];
+    ssl->in_msglen = (ssl->in_len[0] << 8) | ssl->in_len[1];
+}
+
+static int tx_buffer_len(mbedtls_ssl_context *ssl, int len)
+{
+    (void)ssl;
+
+    if (!len) {
+        return MBEDTLS_SSL_OUT_BUFFER_LEN;
+    } else {
+        return len + MBEDTLS_SSL_HEADER_LEN
+                   + MBEDTLS_SSL_COMPRESSION_ADD
+                   + MBEDTLS_MAX_IV_LENGTH
+                   + MBEDTLS_SSL_MAC_ADD
+                   + MBEDTLS_SSL_PADDING_ADD;
+    }
+}
+
+static void init_tx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
+{
+    /**
+     * In mbedtls, ssl->out_msg = ssl->out_buf + offset;
+     */
+    if (!buf) {
+        int out_msg_off = (int)ssl->out_msg - (int)ssl->out_buf;
+
+        if (!out_msg_off) {
+            out_msg_off = MBEDTLS_SSL_HEADER_LEN;
+        }
+
+        ssl->out_buf = NULL;
+        ssl->out_ctr = NULL;
+        ssl->out_hdr = NULL;
+        ssl->out_len = NULL;
+        ssl->out_iv  = NULL;
+        ssl->out_msg = (unsigned char *)out_msg_off;
+    } else {
+        int out_msg_off = (int)ssl->out_msg;
+
+        ssl->out_buf = buf;
+        ssl->out_ctr = ssl->out_buf;
+        ssl->out_hdr = ssl->out_buf +  8;
+        ssl->out_len = ssl->out_buf + 11;
+        ssl->out_iv  = ssl->out_buf + MBEDTLS_SSL_HEADER_LEN;
+        ssl->out_msg = ssl->out_buf + out_msg_off;
+
+        ESP_LOGV(TAG, "out msg offset is %d", out_msg_off);
+    }
+
+    ssl->out_msgtype = 0;
+    ssl->out_msglen = 0;
+    ssl->out_left = 0;
+}
+
+static void init_rx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
+{
+    /**
+     * In mbedtls, ssl->in_msg = ssl->in_buf + offset;
+     */
+    if (!buf) {
+        int in_msg_off = (int)ssl->in_msg - (int)ssl->in_buf;
+
+        if (!in_msg_off) {
+            in_msg_off = MBEDTLS_SSL_HEADER_LEN;
+        }
+
+        ssl->in_buf = NULL;
+        ssl->in_ctr = NULL;
+        ssl->in_hdr = NULL;
+        ssl->in_len = NULL;
+        ssl->in_iv  = NULL;
+        ssl->in_msg = (unsigned char *)in_msg_off;
+    } else {
+        int in_msg_off = (int)ssl->in_msg;
+
+        ssl->in_buf = buf;
+        ssl->in_ctr = ssl->in_buf;
+        ssl->in_hdr = ssl->in_buf +  8;
+        ssl->in_len = ssl->in_buf + 11;
+        ssl->in_iv  = ssl->in_buf + MBEDTLS_SSL_HEADER_LEN;
+        ssl->in_msg = ssl->in_buf + in_msg_off;
+
+        ESP_LOGV(TAG, "in msg offset is %d", in_msg_off);
+    }
+
+    ssl->in_msgtype = 0;
+    ssl->in_msglen = 0;
+    ssl->in_left = 0;
+}
+
+static int esp_mbedtls_alloc_tx_buf(mbedtls_ssl_context *ssl, int len)
+{
+    unsigned char *buf;
+
+    if (ssl->out_buf) {
+        mbedtls_free(ssl->out_buf);
+        ssl->out_buf = NULL;
+    }
+
+    buf = mbedtls_calloc(1, len);
+    if (!buf) {
+        ESP_LOGE(TAG, "alloc(%d bytes) failed", len);
+        return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+    }
+
+    ESP_LOGV(TAG, "add out buffer %d bytes @ %p", len, buf);
+
+    /**
+     * Mark the out_msg offset from ssl->out_buf.
+     * 
+     * In mbedtls, ssl->out_msg = ssl->out_buf + offset;
+     */
+    ssl->out_msg = (unsigned char *)MBEDTLS_SSL_HEADER_LEN;
+
+    init_tx_buffer(ssl, buf);
+
+    return 0;
+}
+
+int esp_mbedtls_setup_tx_buffer(mbedtls_ssl_context *ssl)
+{
+    CHECK_OK(esp_mbedtls_alloc_tx_buf(ssl, TX_IDLE_BUFFER_SIZE));
+
+    /* mark the out buffer has no data cached */
+    ssl->out_iv = NULL;
+
+    return 0;
+}
+
+void esp_mbedtls_setup_rx_buffer(mbedtls_ssl_context *ssl)
+{
+    ssl->in_msg = ssl->in_buf = NULL;
+    init_rx_buffer(ssl, NULL);
+}
+
+int esp_mbedtls_reset_add_tx_buffer(mbedtls_ssl_context *ssl)
+{
+    return esp_mbedtls_alloc_tx_buf(ssl, MBEDTLS_SSL_OUT_BUFFER_LEN);
+}
+
+int esp_mbedtls_reset_free_tx_buffer(mbedtls_ssl_context *ssl)
+{
+    ESP_LOGV(TAG, "free out buffer @ %p", ssl->out_buf);
+
+    mbedtls_free(ssl->out_buf);
+
+    init_tx_buffer(ssl, NULL);
+
+    CHECK_OK(esp_mbedtls_setup_tx_buffer(ssl));
+
+    return 0;
+}
+
+int esp_mbedtls_reset_add_rx_buffer(mbedtls_ssl_context *ssl)
+{
+    unsigned char *buf;
+
+    if (ssl->in_buf) {
+        mbedtls_free(ssl->in_buf);
+        ssl->in_buf = NULL;
+    }
+
+    buf = mbedtls_calloc(1, MBEDTLS_SSL_IN_BUFFER_LEN);
+    if (!buf) {
+        ESP_LOGE(TAG, "alloc(%d bytes) failed", MBEDTLS_SSL_IN_BUFFER_LEN);
+        return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+    }
+
+    ESP_LOGV(TAG, "add in buffer %d bytes @ %p", MBEDTLS_SSL_IN_BUFFER_LEN, buf);
+
+    /**
+     * Mark the in_msg offset from ssl->in_buf.
+     * 
+     * In mbedtls, ssl->in_msg = ssl->in_buf + offset;
+     */
+    ssl->in_msg = (unsigned char *)MBEDTLS_SSL_HEADER_LEN;
+
+    init_rx_buffer(ssl, buf);
+
+    return 0;  
+}
+
+void esp_mbedtls_reset_free_rx_buffer(mbedtls_ssl_context *ssl)
+{
+    ESP_LOGV(TAG, "free in buffer @ %p", ssl->in_buf);
+
+    mbedtls_free(ssl->in_buf);
+
+    init_rx_buffer(ssl, NULL);    
+}
+
+int esp_mbedtls_add_tx_buffer(mbedtls_ssl_context *ssl, size_t buffer_len)
+{
+    int ret = 0;
+    int cached = 0;
+    unsigned char *buf;
+    unsigned char cache_buf[CACHE_BUFFER_SIZE];
+
+    ESP_LOGV(TAG, "--> add out");
+
+    if (ssl->out_buf) {
+        if (ssl->out_iv) {
+            ESP_LOGV(TAG, "out buffer is not empty");
+            ret = 0;
+            goto exit;
+        } else {
+            memcpy(cache_buf, ssl->out_buf, CACHE_BUFFER_SIZE);
+
+            mbedtls_free(ssl->out_buf);
+            init_tx_buffer(ssl, NULL);
+            cached = 1;
+        }
+    }
+
+    buffer_len = tx_buffer_len(ssl, buffer_len);
+
+    buf = mbedtls_calloc(1, buffer_len);
+    if (!buf) {
+        ESP_LOGE(TAG, "alloc(%d bytes) failed", buffer_len);
+        ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        goto exit;
+    }
+
+    ESP_LOGV(TAG, "add out buffer %d bytes @ %p", buffer_len, buf);
+    init_tx_buffer(ssl, buf);
+
+    if (cached) {
+        memcpy(ssl->out_ctr, cache_buf, COUNTER_SIZE);
+        memcpy(ssl->out_iv, cache_buf + COUNTER_SIZE, CACHE_IV_SIZE);
+    }
+
+    ESP_LOGV(TAG, "ssl->out_buf=%p ssl->out_msg=%p", ssl->out_buf, ssl->out_msg);
+
+exit:
+    ESP_LOGV(TAG, "<-- add out");
+
+    return ret;
+}
+
+
+int esp_mbedtls_free_tx_buffer(mbedtls_ssl_context *ssl)
+{
+    int ret = 0;
+    unsigned char buf[CACHE_BUFFER_SIZE];
+    unsigned char *pdata;
+
+    ESP_LOGV(TAG, "--> free out");
+
+    if (!ssl->out_buf || (ssl->out_buf && !ssl->out_iv)) {
+        ret = 0;
+        goto exit;
+    }
+
+    memcpy(buf, ssl->out_ctr, COUNTER_SIZE);
+    memcpy(buf + COUNTER_SIZE, ssl->out_iv, CACHE_IV_SIZE);
+
+    ESP_LOGV(TAG, "free out buffer @ %p", ssl->out_buf);
+
+    mbedtls_free(ssl->out_buf);
+
+    init_tx_buffer(ssl, NULL);
+
+    pdata = mbedtls_calloc(1, TX_IDLE_BUFFER_SIZE);
+    if (!pdata) {
+        ESP_LOGE(TAG, "alloc(%d bytes) failed", TX_IDLE_BUFFER_SIZE);
+        return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+    }
+
+    memcpy(pdata, buf, CACHE_BUFFER_SIZE);
+    init_tx_buffer(ssl, pdata);
+    ssl->out_iv = NULL;
+
+exit:
+    ESP_LOGV(TAG, "<-- free out");
+
+    return ret;
+}
+
+int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl)
+{
+    int cached = 0;
+    int ret = 0;
+    int buffer_len;
+    unsigned char *buf;
+    unsigned char cache_buf[16];
+    unsigned char msg_head[5];
+    size_t in_msglen, in_left;
+
+    ESP_LOGV(TAG, "--> add rx");
+
+    if (ssl->in_buf) {
+        ESP_LOGV(TAG, "in buffer is not empty");
+        ret = 0;
+        goto exit;
+    }
+
+    ssl->in_hdr = msg_head;
+    ssl->in_len = msg_head + 3;
+
+    if ((ret = mbedtls_ssl_fetch_input(ssl, mbedtls_ssl_hdr_len(ssl))) != 0) {
+        if (ret == MBEDTLS_ERR_SSL_TIMEOUT) {
+            ESP_LOGD(TAG, "mbedtls_ssl_fetch_input reads data times out");
+        } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
+            ESP_LOGD(TAG, "mbedtls_ssl_fetch_input wants to read more data");
+        } else {
+            ESP_LOGE(TAG, "mbedtls_ssl_fetch_input error=-0x%x", -ret);
+        }
+        
+        goto exit;
+    }
+
+    esp_mbedtls_parse_record_header(ssl);
+
+    in_left = ssl->in_left;
+    in_msglen = ssl->in_msglen;
+    buffer_len = tx_buffer_len(ssl, in_msglen);
+
+    ESP_LOGV(TAG, "message length is %d RX buffer length should be %d left is %d",
+                (int)in_msglen, (int)buffer_len, (int)ssl->in_left);
+
+    buf = mbedtls_calloc(1, buffer_len);
+    if (!buf) {
+        ESP_LOGE(TAG, "alloc(%d bytes) failed", buffer_len);
+        ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        goto exit;
+    }
+
+    ESP_LOGV(TAG, "add in buffer %d bytes @ %p", buffer_len, buf);
+
+    if (ssl->in_ctr) {
+        memcpy(cache_buf, ssl->in_ctr, 16);
+        mbedtls_free(ssl->in_ctr);
+        cached = 1;
+    }
+
+    init_rx_buffer(ssl, buf);
+
+    if (cached) {
+        memcpy(ssl->in_ctr, cache_buf, 8);
+        memcpy(ssl->in_iv, cache_buf + 8, 8);
+    }
+
+    memcpy(ssl->in_hdr, msg_head, in_left);
+    ssl->in_left = in_left;
+    ssl->in_msglen = 0;
+
+exit:
+    ESP_LOGV(TAG, "<-- add rx");
+
+    return ret; 
+}
+
+int esp_mbedtls_free_rx_buffer(mbedtls_ssl_context *ssl)
+{
+    int ret = 0;
+    unsigned char buf[16];
+    unsigned char *pdata;
+
+    ESP_LOGV(TAG, "--> free rx");
+
+    /**
+     * When have read multi messages once, can't free the input buffer directly.
+     */
+    if (!ssl->in_buf || (ssl->in_hslen && (ssl->in_hslen < ssl->in_msglen))) {
+        ret = 0;
+        goto exit;
+    }
+
+    /**
+     * The previous processing is just skipped, so "ssl->in_msglen = 0"
+     */
+    if (!ssl->in_msgtype) {
+        goto exit;
+    }
+
+    memcpy(buf, ssl->in_ctr, 8);
+    memcpy(buf + 8, ssl->in_iv, 8);
+
+    ESP_LOGV(TAG, "free in buffer @ %p", ssl->out_buf);
+
+    mbedtls_free(ssl->in_buf);
+
+    init_rx_buffer(ssl, NULL);
+
+    pdata = mbedtls_calloc(1, 16);
+    if (!pdata) {
+        ESP_LOGE(TAG, "alloc(%d bytes) failed", 16);
+        ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        goto exit;
+    }
+
+    memcpy(pdata, buf, 16);
+    ssl->in_ctr = pdata;
+
+exit:
+    ESP_LOGV(TAG, "<-- free rx");
+
+    return ret;
+}
+
+size_t esp_mbedtls_get_crt_size(mbedtls_x509_crt *cert, size_t *num)
+{
+    size_t n = 0;
+    size_t bytes = 0;
+
+    while (cert) {
+        bytes += cert->raw.len;
+        n++;
+    
+        cert = cert->next;
+    }
+
+    *num = n;
+
+    return bytes;
+}
+
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+void esp_mbedtls_free_dhm(mbedtls_ssl_context *ssl)
+{
+    mbedtls_mpi_free((mbedtls_mpi *)&ssl->conf->dhm_P);
+    mbedtls_mpi_free((mbedtls_mpi *)&ssl->conf->dhm_G);
+}
+
+void esp_mbedtls_free_keycert(mbedtls_ssl_context *ssl)
+{
+    mbedtls_ssl_config *conf = (mbedtls_ssl_config *)ssl->conf;
+    mbedtls_ssl_key_cert *keycert = conf->key_cert, *next;
+
+    while (keycert) {
+        next = keycert->next;
+
+        if (keycert) {
+            mbedtls_free(keycert);
+        }
+
+        keycert = next;
+    }
+
+    conf->key_cert = NULL;
+}
+
+void esp_mbedtls_free_keycert_key(mbedtls_ssl_context *ssl)
+{
+    mbedtls_ssl_key_cert *keycert = ssl->conf->key_cert;
+
+    while (keycert) {
+        if (keycert->key) {
+            mbedtls_pk_free(keycert->key);
+            keycert->key = NULL;
+        }
+        keycert = keycert->next;
+    }
+}
+
+void esp_mbedtls_free_keycert_cert(mbedtls_ssl_context *ssl)
+{
+    mbedtls_ssl_key_cert *keycert = ssl->conf->key_cert;
+
+    while (keycert) {
+        if (keycert->cert) {
+            mbedtls_x509_crt_free(keycert->cert);
+            keycert->cert = NULL;
+        }
+        keycert = keycert->next;
+    }
+}
+
+void esp_mbedtls_free_cacert(mbedtls_ssl_context *ssl)
+{
+    if (ssl->conf->ca_chain) {
+        mbedtls_ssl_config *conf = (mbedtls_ssl_config *)ssl->conf;
+
+        mbedtls_x509_crt_free(conf->ca_chain);
+        conf->ca_chain = NULL;
+    }
+}
+
+#endif
+
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT
+void esp_mbedtls_free_peer_cert(mbedtls_ssl_context *ssl)
+{
+    if (ssl->session_negotiate->peer_cert) {
+        mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert );
+        mbedtls_free( ssl->session_negotiate->peer_cert );
+        ssl->session_negotiate->peer_cert = NULL;
+    }
+}
+#endif

+ 85 - 0
components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.h

@@ -0,0 +1,85 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+
+#ifndef _DYNAMIC_IMPL_H_
+#define _DYNAMIC_IMPL_H_
+
+#include <stddef.h>
+#include "mbedtls/ssl.h"
+#include "mbedtls/ssl_internal.h"
+#include "mbedtls/platform.h"
+#include "esp_log.h"
+
+#define TRACE_CHECK(_fn, _state) \
+({ \
+    ESP_LOGV(TAG, "%d " _state " to do \"%s\"", __LINE__, # _fn); \
+})
+
+#define CHECK_OK(_fn) \
+({ \
+    int _ret; \
+ \
+    TRACE_CHECK(_fn, "state"); \
+ \
+    if ((_ret = _fn) != 0) { \
+        ESP_LOGV(TAG, "\"%s\" result is -0x%x", # _fn, -_ret); \
+        if (_ret == MBEDTLS_ERR_SSL_CONN_EOF) {\
+            return 0; \
+        } \
+        TRACE_CHECK(_fn, "fail"); \
+        return _ret; \
+    } \
+ \
+    TRACE_CHECK(_fn, "end"); \
+ \
+})
+
+int esp_mbedtls_setup_tx_buffer(mbedtls_ssl_context *ssl);
+
+void esp_mbedtls_setup_rx_buffer(mbedtls_ssl_context *ssl);
+
+int esp_mbedtls_reset_add_tx_buffer(mbedtls_ssl_context *ssl);
+
+int esp_mbedtls_reset_add_rx_buffer(mbedtls_ssl_context *ssl);
+
+int esp_mbedtls_reset_free_tx_buffer(mbedtls_ssl_context *ssl);
+
+void esp_mbedtls_reset_free_rx_buffer(mbedtls_ssl_context *ssl);
+
+int esp_mbedtls_add_tx_buffer(mbedtls_ssl_context *ssl, size_t buffer_len);
+
+int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl);
+
+int esp_mbedtls_free_tx_buffer(mbedtls_ssl_context *ssl);
+
+int esp_mbedtls_free_rx_buffer(mbedtls_ssl_context *ssl);
+
+size_t esp_mbedtls_get_crt_size(mbedtls_x509_crt *cert, size_t *num);
+
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+void esp_mbedtls_free_dhm(mbedtls_ssl_context *ssl);
+
+void esp_mbedtls_free_keycert(mbedtls_ssl_context *ssl);
+
+void esp_mbedtls_free_keycert_cert(mbedtls_ssl_context *ssl);
+
+void esp_mbedtls_free_keycert_key(mbedtls_ssl_context *ssl);
+
+void esp_mbedtls_free_cacert(mbedtls_ssl_context *ssl);
+#endif
+
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT
+void esp_mbedtls_free_peer_cert(mbedtls_ssl_context *ssl);
+#endif
+
+#endif /* _DYNAMIC_IMPL_H_ */

+ 202 - 0
components/mbedtls/port/dynamic/esp_ssl_cli.c

@@ -0,0 +1,202 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+
+#include <sys/param.h>
+#include <stdbool.h>
+#include "esp_mbedtls_dynamic_impl.h"
+
+int __real_mbedtls_ssl_handshake_client_step(mbedtls_ssl_context *ssl);
+
+int __wrap_mbedtls_ssl_handshake_client_step(mbedtls_ssl_context *ssl);
+
+static const char *TAG = "SSL client";
+
+static int manage_resource(mbedtls_ssl_context *ssl, bool add)
+{
+    int state = add ? ssl->state : ssl->state - 1;
+
+    if (ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL) {
+        return 0;
+    }
+
+    if (!add) {
+        if (!ssl->out_left) {
+            CHECK_OK(esp_mbedtls_free_tx_buffer(ssl));
+        }
+    }
+
+    switch (state) {
+        case MBEDTLS_SSL_HELLO_REQUEST:
+            break;
+        case MBEDTLS_SSL_CLIENT_HELLO:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+
+
+        case MBEDTLS_SSL_SERVER_HELLO:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_CERTIFICATE:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+                esp_mbedtls_free_cacert(ssl);
+#endif
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                if (!ssl->keep_current_message) {
+                    CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+                }
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT
+                esp_mbedtls_free_peer_cert(ssl);
+#endif
+            }
+            break;
+        case MBEDTLS_SSL_CERTIFICATE_REQUEST:
+            if (add) {
+                if (!ssl->keep_current_message) {
+                    CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+                }
+            } else {
+                if (!ssl->keep_current_message) {
+                    CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+                }
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_HELLO_DONE:
+            if (add) {
+                if (!ssl->keep_current_message) {
+                    CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+                }
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+
+
+        case MBEDTLS_SSL_CLIENT_CERTIFICATE:
+            if (add) {
+                size_t buffer_len = 3;
+                mbedtls_ssl_key_cert *key_cert = ssl->conf->key_cert;
+
+                while (key_cert && key_cert->cert) {
+                    size_t num;
+
+                    buffer_len += esp_mbedtls_get_crt_size(key_cert->cert, &num);
+                    buffer_len += num * 3;
+
+                    key_cert = key_cert->next;
+                }
+
+                buffer_len = MAX(buffer_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+        case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+        case MBEDTLS_SSL_CERTIFICATE_VERIFY:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            } else {
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+                esp_mbedtls_free_dhm(ssl);
+                esp_mbedtls_free_keycert_key(ssl);
+                esp_mbedtls_free_keycert(ssl);
+#endif
+            }
+            break;
+        case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+        case MBEDTLS_SSL_CLIENT_FINISHED:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+        case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+#endif
+
+
+        case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_FINISHED:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+        case MBEDTLS_SSL_FLUSH_BUFFERS:
+            break;
+        case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
+            break;
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+int __wrap_mbedtls_ssl_handshake_client_step(mbedtls_ssl_context *ssl)
+{
+    CHECK_OK(manage_resource(ssl, true));
+
+    CHECK_OK(__real_mbedtls_ssl_handshake_client_step(ssl));
+
+    CHECK_OK(manage_resource(ssl, false));
+
+    return 0;
+}

+ 188 - 0
components/mbedtls/port/dynamic/esp_ssl_srv.c

@@ -0,0 +1,188 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+
+#include <sys/param.h>
+#include "esp_mbedtls_dynamic_impl.h"
+
+int __real_mbedtls_ssl_handshake_server_step(mbedtls_ssl_context *ssl);
+
+int __wrap_mbedtls_ssl_handshake_server_step(mbedtls_ssl_context *ssl);
+
+static const char *TAG = "SSL Server";
+
+static int manage_resource(mbedtls_ssl_context *ssl, bool add)
+{
+    int state = add ? ssl->state : ssl->state - 1;
+
+    if (ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL) {
+        return 0;
+    }
+
+    if (!add) {
+        if (!ssl->out_left) {
+            CHECK_OK(esp_mbedtls_free_tx_buffer(ssl));
+        }
+    }
+
+    switch (state) {
+        case MBEDTLS_SSL_HELLO_REQUEST:
+            ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3;
+            break;
+        case MBEDTLS_SSL_CLIENT_HELLO:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+
+
+        case MBEDTLS_SSL_SERVER_HELLO:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_CERTIFICATE:
+            if (add) {
+                size_t buffer_len = 3;
+                mbedtls_ssl_key_cert *key_cert = ssl->conf->key_cert;
+
+                while (key_cert && key_cert->cert) {
+                    size_t num;
+
+                    buffer_len += esp_mbedtls_get_crt_size(key_cert->cert, &num);
+                    buffer_len += num * 3;
+
+                    key_cert = key_cert->next;
+                }
+
+                buffer_len = MAX(buffer_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            } else {
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+                esp_mbedtls_free_keycert_cert(ssl);
+#endif
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            } else {
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+                esp_mbedtls_free_dhm(ssl);
+                esp_mbedtls_free_keycert_key(ssl);
+                esp_mbedtls_free_keycert(ssl);
+#endif
+            }
+            break;
+        case MBEDTLS_SSL_CERTIFICATE_REQUEST:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_HELLO_DONE:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+
+
+        case MBEDTLS_SSL_CLIENT_CERTIFICATE:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA
+                esp_mbedtls_free_cacert(ssl);
+#endif
+            }
+            break;
+        case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+        case MBEDTLS_SSL_CERTIFICATE_VERIFY:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+        case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+
+#ifdef CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT
+                esp_mbedtls_free_peer_cert(ssl);
+#endif
+            }
+            break;
+        case MBEDTLS_SSL_CLIENT_FINISHED:
+            if (add) {
+                CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+            } else {
+                CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+            }
+            break;
+
+
+        case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+        case MBEDTLS_SSL_SERVER_FINISHED:
+            if (add) {
+                size_t buffer_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
+
+                CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, buffer_len));
+            }
+            break;
+        case MBEDTLS_SSL_FLUSH_BUFFERS:
+            break;
+        case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
+            break;
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+int __wrap_mbedtls_ssl_handshake_server_step(mbedtls_ssl_context *ssl)
+{
+    CHECK_OK(manage_resource(ssl, true));
+
+    CHECK_OK(__real_mbedtls_ssl_handshake_server_step(ssl));
+
+    CHECK_OK(manage_resource(ssl, false));
+
+    return 0;
+}

+ 158 - 0
components/mbedtls/port/dynamic/esp_ssl_tls.c

@@ -0,0 +1,158 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+
+#include <sys/param.h>
+#include "esp_mbedtls_dynamic_impl.h"
+
+int __real_mbedtls_ssl_write(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len);
+int __real_mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len);
+void __real_mbedtls_ssl_free(mbedtls_ssl_context *ssl);
+int __real_mbedtls_ssl_session_reset(mbedtls_ssl_context *ssl);
+int __real_mbedtls_ssl_setup(mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf);
+int __real_mbedtls_ssl_send_alert_message(mbedtls_ssl_context *ssl, unsigned char level, unsigned char message);
+int __real_mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl);
+
+int __wrap_mbedtls_ssl_write(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len);
+int __wrap_mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len);
+void __wrap_mbedtls_ssl_free(mbedtls_ssl_context *ssl);
+int __wrap_mbedtls_ssl_session_reset(mbedtls_ssl_context *ssl);
+int __wrap_mbedtls_ssl_setup(mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf);
+int __wrap_mbedtls_ssl_send_alert_message(mbedtls_ssl_context *ssl, unsigned char level, unsigned char message);
+int __wrap_mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl);
+
+static const char *TAG = "SSL TLS";
+
+static int tx_done(mbedtls_ssl_context *ssl)
+{
+    if (!ssl->out_left)
+        return 1;
+
+    return 0;
+}
+
+static int rx_done(mbedtls_ssl_context *ssl)
+{
+    if (!ssl->in_msglen) {
+        return 1;
+    }
+
+    ESP_LOGD(TAG, "RX left %d bytes", ssl->in_msglen);
+
+    return 0;
+}
+
+int __wrap_mbedtls_ssl_setup(mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf)
+{
+    CHECK_OK(__real_mbedtls_ssl_setup(ssl, conf));
+
+    mbedtls_free(ssl->out_buf);
+    ssl->out_buf = NULL;
+    CHECK_OK(esp_mbedtls_setup_tx_buffer(ssl));
+
+    mbedtls_free(ssl->in_buf);
+    ssl->in_buf = NULL;
+    esp_mbedtls_setup_rx_buffer(ssl);
+
+    return 0;
+}
+
+int __wrap_mbedtls_ssl_write(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
+{
+    int ret;
+
+    CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, 0));
+
+    ret = __real_mbedtls_ssl_write(ssl, buf, len);
+
+    if (tx_done(ssl)) {
+        CHECK_OK(esp_mbedtls_free_tx_buffer(ssl));
+    }
+
+    return ret;
+}
+
+int __wrap_mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
+{
+    int ret;
+
+    CHECK_OK(esp_mbedtls_add_rx_buffer(ssl));
+
+    ret = __real_mbedtls_ssl_read(ssl, buf, len);
+
+    if (rx_done(ssl)) {
+        CHECK_OK(esp_mbedtls_free_rx_buffer(ssl));
+    }
+
+    return ret;
+}
+
+void __wrap_mbedtls_ssl_free(mbedtls_ssl_context *ssl)
+{
+    if (ssl->out_buf) {
+        mbedtls_free(ssl->out_buf);
+        ssl->out_buf = NULL;
+    }
+
+    if (ssl->in_buf) {
+        mbedtls_free(ssl->in_buf);
+        ssl->in_buf = NULL;
+    }
+
+    __real_mbedtls_ssl_free(ssl);
+}
+
+int __wrap_mbedtls_ssl_session_reset(mbedtls_ssl_context *ssl)
+{
+    CHECK_OK(esp_mbedtls_reset_add_tx_buffer(ssl));
+
+    CHECK_OK(esp_mbedtls_reset_add_rx_buffer(ssl));
+
+    CHECK_OK(__real_mbedtls_ssl_session_reset(ssl));
+
+    CHECK_OK(esp_mbedtls_reset_free_tx_buffer(ssl));
+
+    esp_mbedtls_reset_free_rx_buffer(ssl);
+
+    return 0;
+}
+
+int __wrap_mbedtls_ssl_send_alert_message(mbedtls_ssl_context *ssl, unsigned char level, unsigned char message)
+{
+    int ret;
+
+    CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, 0));
+
+    ret = __real_mbedtls_ssl_send_alert_message(ssl, level, message);
+
+    if (tx_done(ssl)) {
+        CHECK_OK(esp_mbedtls_free_tx_buffer(ssl));
+    }
+
+    return ret;
+}
+
+int __wrap_mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl)
+{
+    int ret;
+
+    CHECK_OK(esp_mbedtls_add_tx_buffer(ssl, 0));
+
+    ret = __real_mbedtls_ssl_close_notify(ssl);
+
+    if (tx_done(ssl)) {
+        CHECK_OK(esp_mbedtls_free_tx_buffer(ssl));
+    }
+
+    return ret;
+}
+

+ 29 - 0
examples/protocols/esp_http_client/esp_http_client_test.py

@@ -39,6 +39,35 @@ def test_examples_protocol_esp_http_client(env, extra_data):
     dut1.expect(re.compile(r"Last esp error code: 0x8001"))
     dut1.expect("Finish http example")
 
+    # test mbedtls dynamic resource
+    dut1 = env.get_dut("esp_http_client", "examples/protocols/esp_http_client", dut_class=ttfw_idf.ESP32DUT, app_config_name='ssldyn')
+    # check and log bin size
+    binary_file = os.path.join(dut1.app.binary_path, "esp-http-client-example.bin")
+    bin_size = os.path.getsize(binary_file)
+    ttfw_idf.log_performance("esp_http_client_bin_size", "{}KB".format(bin_size // 1024))
+    ttfw_idf.check_performance("esp_http_client_bin_size", bin_size // 1024, dut1.TARGET)
+    # start test
+    dut1.start_app()
+    dut1.expect("Connected to AP, begin http example", timeout=30)
+    dut1.expect(re.compile(r"HTTP GET Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP POST Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP PUT Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP PATCH Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP DELETE Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP HEAD Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP Basic Auth Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP Basic Auth redirect Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP Digest Auth Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP Relative path redirect Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP Absolute path redirect Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTPS Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"HTTP redirect to HTTPS Status = 200, content_length = (\d)"), timeout=10)
+    dut1.expect(re.compile(r"HTTP chunk encoding Status = 200, content_length = (-?\d)"))
+    # content-len for chunked encoding is typically -1, could be a positive length in some cases
+    dut1.expect(re.compile(r"HTTP Stream reader Status = 200, content_length = (\d)"))
+    dut1.expect(re.compile(r"Last esp error code: 0x8001"))
+    dut1.expect("Finish http example")
+
 
 if __name__ == '__main__':
     test_examples_protocol_esp_http_client()

+ 12 - 0
examples/protocols/esp_http_client/sdkconfig.ci.ssldyn

@@ -0,0 +1,12 @@
+CONFIG_EXAMPLE_CONNECT_ETHERNET=y
+CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
+CONFIG_EXAMPLE_ETH_PHY_IP101=y
+CONFIG_EXAMPLE_ETH_MDC_GPIO=23
+CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
+CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
+CONFIG_EXAMPLE_ETH_PHY_ADDR=1
+CONFIG_EXAMPLE_CONNECT_IPV6=y
+CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y
+CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
+CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y
+CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y

+ 13 - 0
examples/protocols/https_request/example_test.py

@@ -24,6 +24,19 @@ def test_examples_protocol_https_request(env, extra_data):
     dut1.expect("Reading HTTP response...")
     dut1.expect(re.compile(r"Completed (\d) requests"))
 
+    # test mbedtls dynamic resource
+    dut1 = env.get_dut("https_request", "examples/protocols/https_request", dut_class=ttfw_idf.ESP32DUT, app_config_name='ssldyn')
+    # check and log bin size
+    binary_file = os.path.join(dut1.app.binary_path, "https_request.bin")
+    bin_size = os.path.getsize(binary_file)
+    ttfw_idf.log_performance("https_request_bin_size", "{}KB".format(bin_size // 1024))
+    ttfw_idf.check_performance("https_request_bin_size", bin_size // 1024, dut1.TARGET)
+    # start test
+    dut1.start_app()
+    dut1.expect("Connection established...", timeout=30)
+    dut1.expect("Reading HTTP response...")
+    dut1.expect(re.compile(r"Completed (\d) requests"))
+
 
 if __name__ == '__main__':
     test_examples_protocol_https_request()

+ 13 - 0
examples/protocols/https_request/sdkconfig.ci.ssldyn

@@ -0,0 +1,13 @@
+CONFIG_ESP32_SPIRAM_SUPPORT=y
+CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
+CONFIG_EXAMPLE_CONNECT_ETHERNET=y
+CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
+CONFIG_EXAMPLE_ETH_PHY_IP101=y
+CONFIG_EXAMPLE_ETH_MDC_GPIO=23
+CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
+CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
+CONFIG_EXAMPLE_ETH_PHY_ADDR=1
+CONFIG_EXAMPLE_CONNECT_IPV6=y
+CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
+CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y
+CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y

+ 13 - 0
examples/protocols/https_x509_bundle/example_test.py

@@ -23,6 +23,19 @@ def test_examples_protocol_https_x509_bundle(env, extra_data):
     dut1.expect(re.compile(r"Connection established to ([\s\S]*)"), timeout=30)
     dut1.expect("Completed {} connections".format(num_URLS[0]), timeout=60)
 
+    # test mbedtls dynamic resource
+    dut1 = env.get_dut("https_x509_bundle", "examples/protocols/https_x509_bundle", app_config_name='ssldyn')
+    # check and log bin size
+    binary_file = os.path.join(dut1.app.binary_path, "https_x509_bundle.bin")
+    bin_size = os.path.getsize(binary_file)
+    ttfw_idf.log_performance("https_x509_bundle_bin_size", "{}KB".format(bin_size // 1024))
+    ttfw_idf.check_performance("https_x509_bundle_bin_size", bin_size // 1024, dut1.TARGET)
+    # start test
+    dut1.start_app()
+    num_URLS = dut1.expect(re.compile(r"Connecting to (\d+) URLs"), timeout=30)
+    dut1.expect(re.compile(r"Connection established to ([\s\S]*)"), timeout=30)
+    dut1.expect("Completed {} connections".format(num_URLS[0]), timeout=60)
+
 
 if __name__ == '__main__':
     test_examples_protocol_https_x509_bundle()

+ 3 - 0
examples/protocols/https_x509_bundle/sdkconfig.ci

@@ -0,0 +1,3 @@
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE=y
+CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="certs"

+ 6 - 0
examples/protocols/https_x509_bundle/sdkconfig.ci.ssldyn

@@ -0,0 +1,6 @@
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE=y
+CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="certs"
+CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
+CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y
+CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y