feat(esp_http): migrate esp_http to PSA API

This commit is contained in:
Ashish Sharma
2025-08-04 18:33:10 +08:00
parent d76364c2a4
commit acf89924c8
27 changed files with 400 additions and 58 deletions
+1
View File
@@ -743,3 +743,4 @@ mainmenu "Espressif IoT Development Framework Configuration"
- CONFIG_LIBC_PICOLIBC
- CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION
- CONFIG_I3C_MASTER_ENABLED
- CONFIG_MBEDTLS_ESP_IDF_USE_PSA_CRYPTO
@@ -4,10 +4,17 @@ else()
set(req linux esp_event)
endif()
if(CONFIG_ESP_HTTP_CLIENT_PSA_CRYPTO_MIGRATE)
set(HTTP_CRYPTO_SRC "lib/http_crypto_psa.c")
else()
set(HTTP_CRYPTO_SRC "lib/http_crypto_mbedtls.c")
endif()
idf_component_register(SRCS "esp_http_client.c"
"lib/http_auth.c"
"lib/http_header.c"
"lib/http_utils.c"
${HTTP_CRYPTO_SRC}
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "lib/include"
# lwip is a public requirement because esp_http_client.h includes sys/socket.h
+7
View File
@@ -41,4 +41,11 @@ menu "ESP HTTP client"
help
This config option helps in setting the time in millisecond to wait for event to be posted to the
system default event loop. Set it to -1 if you need to set timeout to portMAX_DELAY.
config ESP_HTTP_CLIENT_PSA_CRYPTO_MIGRATE
depends on MBEDTLS_ESP_IDF_USE_PSA_CRYPTO
bool "Migrate ESP HTTP Client to use PSA Crypto"
default y
help
Migrate ESP HTTP Client to use PSA Crypto.
endmenu
+6 -15
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -12,17 +12,15 @@
#include "sys/socket.h"
#include "esp_rom_md5.h"
#include "esp_tls_crypto.h"
#include "mbedtls/sha256.h"
#include "esp_log.h"
#include "esp_check.h"
#include "http_utils.h"
#include "http_auth.h"
#include "http_crypto.h"
#define MD5_MAX_LEN (33)
#define SHA256_LEN (32)
#define SHA256_HEX_LEN (65)
#define HTTP_AUTH_BUF_LEN (1024)
static const char *TAG = "HTTP_AUTH";
@@ -85,19 +83,13 @@ static int sha256_sprintf(char *sha, const char *fmt, ...)
}
int ret = 0;
mbedtls_sha256_context sha256;
mbedtls_sha256_init(&sha256);
if (mbedtls_sha256_starts(&sha256, 0) != 0) {
goto exit;
}
if (mbedtls_sha256_update(&sha256, buf, len) != 0) {
goto exit;
}
if (mbedtls_sha256_finish(&sha256, digest) != 0) {
esp_err_t err = http_crypto_sha256(buf, len, digest);
if (err != ESP_OK) {
goto exit;
}
for (i = 0; i < 32; ++i) {
for (i = 0; i < SHA256_LEN; ++i) {
sprintf(&sha[i * 2], "%02x", (unsigned int)digest[i]);
}
sha[SHA256_HEX_LEN - 1] = '\0';
@@ -105,7 +97,6 @@ static int sha256_sprintf(char *sha, const char *fmt, ...)
exit:
free(buf);
mbedtls_sha256_free(&sha256);
va_end(ap);
return ret;
}
@@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "http_crypto.h"
#include "esp_rom_md5.h"
#include "esp_err.h"
#include "mbedtls/sha256.h"
#include "esp_log.h"
static const char *TAG = "http_crypto_mbedtls";
esp_err_t http_crypto_sha256(const uint8_t *data, size_t data_len, uint8_t *hash)
{
if (data == NULL || data_len == 0 || hash == NULL) {
ESP_LOGE(TAG, "Invalid input parameters");
return ESP_FAIL;
}
esp_err_t err = ESP_FAIL;
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
if (mbedtls_sha256_starts(&ctx, false) != 0) {
ESP_LOGE(TAG, "Failed to start SHA-256 hash");
goto exit;
}
if (mbedtls_sha256_update(&ctx, data, data_len) != 0) {
ESP_LOGE(TAG, "Failed to update SHA-256 hash");
goto exit;
}
if (mbedtls_sha256_finish(&ctx, hash) != 0) {
ESP_LOGE(TAG, "Failed to finish SHA-256 hash");
goto exit;
}
err = ESP_OK;
exit:
mbedtls_sha256_free(&ctx);
return err;
}
@@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "esp_err.h"
#include "http_crypto.h"
#include "psa/crypto.h"
#include "esp_log.h"
static const char *TAG = "http_crypto_psa";
esp_err_t http_crypto_sha256(const uint8_t *data, size_t data_len, uint8_t *hash)
{
if (data == NULL || data_len == 0 || hash == NULL) {
ESP_LOGE(TAG, "Invalid input parameters");
return ESP_FAIL;
}
size_t hash_len = 0;
psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256, data, data_len, hash, SHA256_LEN, &hash_len);
if (status != PSA_SUCCESS || hash_len != SHA256_LEN) {
ESP_LOGE(TAG, "Failed to compute SHA-256 hash");
return ESP_FAIL;
}
return ESP_OK;
}
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include "esp_err.h"
#define SHA256_LEN (32)
#define SHA256_HEX_LEN (65)
esp_err_t http_crypto_sha256(const uint8_t *data, size_t data_len, uint8_t *hash);
#ifdef __cplusplus
}
#endif
@@ -2,12 +2,19 @@ set(priv_req mbedtls lwip esp_timer)
set(priv_inc_dir "src/util" "src/port/esp32")
set(requires http_parser esp_event)
if(CONFIG_HTTPD_SERVER_PSA_CRYPTO_MIGRATE)
set(HTTPD_CRYPTO_SRC "src/httpd_crypto_psa.c")
else()
set(HTTPD_CRYPTO_SRC "src/httpd_crypto_mbedtls.c")
endif()
idf_component_register(SRCS "src/httpd_main.c"
"src/httpd_parse.c"
"src/httpd_sess.c"
"src/httpd_txrx.c"
"src/httpd_uri.c"
"src/httpd_ws.c"
${HTTPD_CRYPTO_SRC}
"src/util/ctrl_sock.c"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS ${priv_inc_dir}
+7
View File
@@ -72,4 +72,11 @@ menu "HTTP Server"
Enable this option to use WebSocket pre-handshake callback. This will allow the server to register
a callback function that will be called before the WebSocket handshake is processed i.e. before switching
to the WebSocket protocol.
config HTTPD_SERVER_PSA_CRYPTO_MIGRATE
depends on MBEDTLS_ESP_IDF_USE_PSA_CRYPTO
bool "Migrate ESP HTTP Server to use PSA Crypto"
default y
help
Migrate ESP HTTP Server to use PSA Crypto.
endmenu
@@ -593,6 +593,8 @@ esp_err_t httpd_sess_trigger_close_(httpd_handle_t handle, struct sock_db *sessi
*/
void esp_http_server_dispatch_event(int32_t event_id, const void* event_data, size_t event_data_size);
esp_err_t httpd_crypto_sha1(const uint8_t *data, size_t data_len, uint8_t *hash);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "mbedtls/sha1.h"
#include "esp_err.h"
#include "esp_log.h"
static const char *TAG = "httpd_crypto_mbedtls";
#define SHA1_LEN (20)
esp_err_t httpd_crypto_sha1(const uint8_t *data, size_t data_len, uint8_t *hash)
{
if (data == NULL || data_len == 0 || hash == NULL) {
ESP_LOGE(TAG, "Invalid input parameters");
return ESP_FAIL;
}
esp_err_t err = ESP_FAIL;
mbedtls_sha1_context ctx;
mbedtls_sha1_init(&ctx);
if (mbedtls_sha1_starts(&ctx) != 0) {
ESP_LOGE(TAG, "Failed to start SHA-1 hash");
goto exit;
}
if (mbedtls_sha1_update(&ctx, data, data_len) != 0) {
ESP_LOGE(TAG, "Failed to update SHA-1 hash");
goto exit;
}
if (mbedtls_sha1_finish(&ctx, hash) != 0) {
ESP_LOGE(TAG, "Failed to finish SHA-1 hash");
goto exit;
}
err = ESP_OK;
exit:
mbedtls_sha1_free(&ctx);
return err;
}
@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "psa/crypto.h"
#include "esp_err.h"
#include "esp_log.h"
static const char *TAG = "httpd_crypto_psa";
#define SHA1_LEN (20)
esp_err_t httpd_crypto_sha1(const uint8_t *data, size_t data_len, uint8_t *hash)
{
if (data == NULL || data_len == 0 || hash == NULL) {
ESP_LOGE(TAG, "Invalid input parameters");
return ESP_FAIL;
}
size_t hash_len = 0;
psa_status_t status = psa_hash_compute(PSA_ALG_SHA_1, data, data_len, hash, SHA1_LEN, &hash_len);
if (status != PSA_SUCCESS || hash_len != SHA1_LEN) {
ESP_LOGE(TAG, "Failed to compute SHA-1 hash");
return ESP_FAIL;
}
return ESP_OK;
}
+6 -26
View File
@@ -11,7 +11,7 @@
#include <sys/random.h>
#include <esp_log.h>
#include <esp_err.h>
#include <mbedtls/sha1.h>
#include <mbedtls/base64.h>
#include <mbedtls/error.h>
@@ -143,35 +143,15 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *suppor
ESP_LOGD(TAG, LOG_FMT("Server key before encoding: %s"), server_raw_text);
/* Generate SHA-1 first and then encode to Base64 */
size_t key_len = strlen(server_raw_text);
#if CONFIG_MBEDTLS_SHA1_C || CONFIG_MBEDTLS_HARDWARE_SHA
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_sha1_context ctx;
mbedtls_sha1_init(&ctx);
if ((ret = mbedtls_sha1_starts(&ctx)) != 0) {
goto sha_end;
}
if ((ret = mbedtls_sha1_update(&ctx, (uint8_t *)server_raw_text, key_len)) != 0) {
goto sha_end;
}
if ((ret = mbedtls_sha1_finish(&ctx, server_key_hash)) != 0) {
goto sha_end;
}
sha_end:
mbedtls_sha1_free(&ctx);
if (ret != 0) {
ESP_LOGE(TAG, "Error in calculating SHA1 sum , returned 0x%02X", ret);
return ESP_FAIL;
esp_err_t err = httpd_crypto_sha1((const uint8_t *)server_raw_text, strlen(server_raw_text), server_key_hash);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to compute SHA-1 hash");
return err;
}
#else
ESP_LOGE(TAG, "Please enable CONFIG_MBEDTLS_SHA1_C or CONFIG_MBEDTLS_HARDWARE_SHA to support SHA1 operations");
return ESP_FAIL;
return ESP_ERR_NOT_SUPPORTED;
#endif /* CONFIG_MBEDTLS_SHA1_C || CONFIG_MBEDTLS_HARDWARE_SHA */
size_t encoded_len = 0;
+3
View File
@@ -79,6 +79,9 @@ SECONDARY: 102: init_rng in components/esp_hw_support/hw_random.c on BIT(0)
# Security specific initializations
SECONDARY: 103: esp_security_init in components/esp_security/src/init.c on BIT(0)
# PSA Crypto initialization (must happen after esp_security_init for hardware crypto support)
SECONDARY: 104: mbedtls_psa_crypto_init_fn in components/mbedtls/port/esp_psa_crypto_init.c on BIT(0)
# esp_sleep doesn't have init dependencies
SECONDARY: 105: esp_sleep_startup_init in components/esp_hw_support/sleep_gpio.c on BIT(0)
SECONDARY: 106: sleep_clock_startup_init in components/esp_hw_support/lowpower/port/esp32c5/sleep_clock.c on BIT(0)
+9 -2
View File
@@ -167,6 +167,10 @@ list(APPEND mbedtls_targets everest p256m)
set(mbedtls_target_sources "${COMPONENT_DIR}/port/mbedtls_debug.c"
"${COMPONENT_DIR}/port/esp_platform_time.c")
if(CONFIG_MBEDTLS_ESP_IDF_USE_PSA_CRYPTO)
list(APPEND mbedtls_target_sources "${COMPONENT_DIR}/port/esp_psa_crypto_init.c")
endif()
if(CONFIG_MBEDTLS_DYNAMIC_BUFFER)
set(mbedtls_target_sources ${mbedtls_target_sources}
"${COMPONENT_DIR}/port/dynamic/esp_mbedtls_dynamic_impl.c"
@@ -357,14 +361,14 @@ foreach(target ${mbedtls_targets})
endif()
if(CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_SIZE)
target_compile_options(${target} PRIVATE "-Os")
elseif(CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_SPEED)
elseif(CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_PERF)
target_compile_options(${target} PRIVATE "-O2")
endif()
endforeach()
if(CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_SIZE)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Os")
elseif(CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_SPEED)
elseif(CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_PERF)
target_compile_options(${COMPONENT_LIB} PRIVATE "-O2")
endif()
@@ -398,6 +402,9 @@ endif()
target_link_libraries(${COMPONENT_LIB} ${linkage_type} ${mbedtls_targets})
# Ensure PSA crypto initialization is included in the build
target_link_libraries(${COMPONENT_LIB} ${linkage_type} "-u mbedtls_psa_crypto_init_include_impl")
if(CONFIG_ESP_TLS_USE_DS_PERIPHERAL)
# The linker seems to be unable to resolve all the dependencies without increasing this
set_property(TARGET mbedcrypto APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 6)
+9
View File
@@ -1,6 +1,15 @@
menu "mbedTLS"
menu "Core Configuration"
config MBEDTLS_ESP_IDF_USE_PSA_CRYPTO
depends on IDF_EXPERIMENTAL_FEATURES
bool "Enable the Platform Security Architecture (PSA) cryptography API for ESP-IDF"
default y
help
Enable the Platform Security Architecture (PSA) cryptography API for ESP-IDF.
This option migrates from mbedtls API to PSA Crypto API. This increases code size.
choice MBEDTLS_COMPILER_OPTIMIZATION
prompt "Compiler optimization level"
default MBEDTLS_COMPILER_OPTIMIZATION_NONE
+34 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,6 +10,9 @@
#include <stdio.h>
#include "esp_random.h"
#include "mbedtls/esp_mbedtls_random.h"
#if defined(MBEDTLS_PLATFORM_GET_ENTROPY_ALT)
#include "psa/crypto.h"
#endif
#include <entropy_poll.h>
@@ -31,3 +34,33 @@ int mbedtls_esp_random(void *ctx, unsigned char *buf, size_t len)
esp_fill_random(buf, len);
return 0;
}
#if defined(MBEDTLS_PLATFORM_GET_ENTROPY_ALT)
int mbedtls_platform_get_entropy(unsigned char *output, size_t output_size,
size_t *output_len, size_t *entropy_content);
psa_status_t mbedtls_psa_external_get_random(
mbedtls_psa_external_random_context_t *context,
uint8_t *output, size_t output_size, size_t *output_length)
{
if (context == NULL || output == NULL || output_length == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
esp_fill_random(output, output_size);
*output_length = output_size;
return PSA_SUCCESS;
}
int mbedtls_platform_get_entropy(unsigned char *output, size_t output_size,
size_t *output_len, size_t *entropy_content)
{
if (output == NULL || output_size == 0 || output_len == NULL || entropy_content == NULL) {
return -1;
}
esp_fill_random(output, output_size);
*output_len = output_size;
*entropy_content = 8 * output_size;
return 0;
}
#endif // MBEDTLS_PLATFORM_GET_ENTROPY_ALT
@@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_private/startup_internal.h"
#include "psa/crypto.h"
#include "esp_err.h"
#include "esp_log.h"
#include "sdkconfig.h"
void mbedtls_psa_crypto_init_include_impl(void);
/**
* @brief Initialize PSA Crypto library at system startup
*
* This function is called during the SECONDARY initialization stage with priority 104,
* which ensures it runs after esp_security_init (priority 103). This ordering guarantees
* that hardware crypto support is fully initialized before PSA crypto initialization.
*/
ESP_SYSTEM_INIT_FN(mbedtls_psa_crypto_init_fn, SECONDARY, BIT(0), 104)
{
psa_status_t status = psa_crypto_init();
if (status != PSA_SUCCESS) {
return ESP_FAIL;
}
return ESP_OK;
}
void mbedtls_psa_crypto_init_include_impl(void)
{
// Linker hook, exists for no other purpose
}
@@ -36,6 +36,12 @@
* \{
*/
#ifndef CONFIG_IDF_TARGET_LINUX
#define MBEDTLS_PLATFORM_GET_ENTROPY_ALT
#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
#endif // !CONFIG_IDF_TARGET_LINUX
#define MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS
/**
* \def MBEDTLS_HAVE_TIME
*
@@ -9,16 +9,31 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.httpbin
@pytest.mark.parametrize(
'config',
[
'default', # mbedTLS crypto backend
'psa', # PSA crypto backend (tests system integration, HTTPS stack usage)
],
indirect=True,
)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_examples_protocol_esp_http_client(dut: Dut) -> None:
"""
steps: |
1. join AP/Ethernet
2. Send HTTP request to httpbin.org
Tests both mbedTLS and PSA crypto backends.
The PSA config specifically tests:
- PSA crypto initialization
- HTTPS with PSA (stack/heap usage)
- SHA256 Digest Auth with PSA
- Full integration under real workload
"""
binary_file = os.path.join(dut.app.binary_path, 'esp_http_client_example.bin')
bin_size = os.path.getsize(binary_file)
logging.info('esp_http_client_bin_size : {}KB'.format(bin_size // 1024))
logging.info(f'esp_http_client_bin_size : {bin_size // 1024}KB')
# start test
dut.expect('Connected to AP, begin http example', timeout=30)
dut.expect(r'HTTP GET Status = 200, content_length = (\d)')
@@ -46,7 +61,7 @@ def test_examples_protocol_esp_http_client(dut: Dut) -> None:
dut.expect(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
dut.expect(r'HTTP Stream reader Status = 200, content_length = (\d)')
dut.expect(r'HTTPS Status = 200, content_length = (\d)')
dut.expect(r'HTTPS Status = 200, content_length = (-?\d)')
dut.expect(r'HTTPS Status = 200, content_length = (\d)')
dut.expect(r'Last esp error code: 0x8001')
dut.expect(r'HTTP GET Status = 200, content_length = (\d)')
@@ -71,8 +86,7 @@ def test_examples_protocol_esp_http_client_dynamic_buffer(dut: Dut) -> None:
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, 'esp_http_client_example.bin')
bin_size = os.path.getsize(binary_file)
logging.info('esp_http_client_bin_size : {}KB'.format(bin_size // 1024))
logging.info(f'esp_http_client_bin_size : {bin_size // 1024}KB')
dut.expect('Connected to AP, begin http example', timeout=30)
dut.expect(r'HTTP GET Status = 200, content_length = (\d)')
dut.expect(r'HTTP POST Status = 200, content_length = (\d)')
@@ -11,3 +11,4 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y
CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y
CONFIG_EXAMPLE_HTTP_ENDPOINT="httpbin.espressif.cn"
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_CROSS_SIGNED_VERIFY=y
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=y
@@ -0,0 +1,19 @@
# HTTP Client Example with PSA Crypto API
# This config tests the PSA crypto backend instead of direct mbedTLS
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_GENERIC=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_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y
CONFIG_EXAMPLE_HTTP_ENDPOINT="httpbin.espressif.cn"
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=y
# PSA Crypto Configuration
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_MBEDTLS_ESP_IDF_USE_PSA_CRYPTO=y
CONFIG_ESP_HTTP_CLIENT_PSA_CRYPTO_MIGRATE=y
@@ -12,3 +12,4 @@ CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
CONFIG_MBEDTLS_DHM_C=y
CONFIG_EXAMPLE_HTTP_ENDPOINT="httpbin.espressif.cn"
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=y
@@ -2,7 +2,7 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.22)
list(APPEND sdkconfig_defaults ${CMAKE_CURRENT_LIST_DIR}/ws_echo_server_mbedtls_config.conf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
@@ -30,7 +30,7 @@ class WsClient:
self.uri = uri
def __enter__(self): # type: ignore
self.ws.connect('ws://{}:{}/{}'.format(self.ip, self.port, self.uri))
self.ws.connect(f'ws://{self.ip}:{self.port}/{self.uri}')
return self
def __exit__(self, exc_type, exc_value, traceback): # type: ignore
@@ -48,12 +48,24 @@ class WsClient:
@pytest.mark.wifi_router
@pytest.mark.parametrize(
'config',
[
'default', # mbedTLS crypto backend
'psa', # PSA crypto backend (tests SHA-1 for WebSocket handshake)
],
indirect=True,
)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_examples_protocol_http_ws_echo_server(dut: Dut) -> None:
"""
Test WebSocket echo server with both mbedTLS and PSA crypto backends.
This specifically tests the SHA-1 computation used in WebSocket handshake (RFC 6455).
"""
# Get binary file
binary_file = os.path.join(dut.app.binary_path, 'ws_echo_server.bin')
bin_size = os.path.getsize(binary_file)
logging.info('http_ws_server_bin_size : {}KB'.format(bin_size // 1024))
logging.info(f'http_ws_server_bin_size : {bin_size // 1024}KB')
logging.info('Starting ws-echo-server test app based on http_server')
@@ -68,8 +80,8 @@ def test_examples_protocol_http_ws_echo_server(dut: Dut) -> None:
got_ip = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
got_port = dut.expect(r"Starting server on port: '(\d+)'", timeout=30)[1].decode()
logging.info('Got IP : {}'.format(got_ip))
logging.info('Got Port : {}'.format(got_port))
logging.info(f'Got IP : {got_ip}')
logging.info(f'Got Port : {got_port}')
# Start ws server test
with WsClient(got_ip, int(got_port), uri='ws') as ws:
@@ -77,32 +89,41 @@ def test_examples_protocol_http_ws_echo_server(dut: Dut) -> None:
for expected_opcode in [OPCODE_TEXT, OPCODE_BIN, OPCODE_PING]:
ws.write(data=DATA, opcode=expected_opcode)
opcode, data = ws.read()
logging.info('Testing opcode {}: Received opcode:{}, data:{}'.format(expected_opcode, opcode, data))
logging.info(f'Testing opcode {expected_opcode}: Received opcode:{opcode}, data:{data}')
data = data.decode()
if expected_opcode == OPCODE_PING:
dut.expect('Got a WS PING frame, Replying PONG')
if opcode != OPCODE_PONG or data != DATA:
raise RuntimeError('Failed to receive correct opcode:{} or data:{}'.format(opcode, data))
raise RuntimeError(f'Failed to receive correct opcode:{opcode} or data:{data}')
continue
dut_data = dut.expect(r'Got packet with message: ([A-Za-z0-9_]*)')[1]
dut_opcode = dut.expect(r'Packet type: ([0-9]*)')[1].decode()
if opcode != expected_opcode or data != DATA or opcode != int(dut_opcode) or (data not in str(dut_data)):
raise RuntimeError('Failed to receive correct opcode:{} or data:{}'.format(opcode, data))
raise RuntimeError(f'Failed to receive correct opcode:{opcode} or data:{data}')
ws.write(data='Trigger async', opcode=OPCODE_TEXT)
opcode, data = ws.read()
logging.info('Testing async send: Received opcode:{}, data:{}'.format(opcode, data))
logging.info(f'Testing async send: Received opcode:{opcode}, data:{data}')
data = data.decode()
if opcode != OPCODE_TEXT or data != 'Async data':
raise RuntimeError('Failed to receive correct opcode:{} or data:{}'.format(opcode, data))
raise RuntimeError(f'Failed to receive correct opcode:{opcode} or data:{data}')
@pytest.mark.wifi_router
@pytest.mark.parametrize(
'config',
[
'default', # mbedTLS crypto backend
'psa', # PSA crypto backend (tests SHA-1 for WebSocket handshake)
],
indirect=True,
)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_ws_auth_handshake(dut: Dut) -> None:
"""
Test that connecting to /ws does NOT print the handshake success log.
This is used to verify ws_pre_handshake_cb can reject the handshake.
Tests both mbedTLS and PSA crypto backends.
"""
# Wait for device to connect and start server
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
@@ -0,0 +1,8 @@
# WebSocket Echo Server Example with PSA Crypto API
# This config tests the PSA crypto backend for WebSocket handshake (SHA-1)
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
# PSA Crypto Configuration
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_MBEDTLS_ESP_IDF_USE_PSA_CRYPTO=y
CONFIG_HTTPD_SERVER_PSA_CRYPTO_MIGRATE=y
@@ -0,0 +1,8 @@
CONFIG_MBEDTLS_TLS_ENABLED=n
CONFIG_MBEDTLS_MD5_C=n
CONFIG_MBEDTLS_SHA224_C=n
CONFIG_MBEDTLS_SHA256_C=n
CONFIG_MBEDTLS_SHA384_C=n
CONFIG_MBEDTLS_SHA512_C=n
CONFIG_MBEDTLS_SHA3_C=n
CONFIG_MBEDTLS_ROM_MD5=n