mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
Merge branch 'refactor/remove_esp_wolfssl_from_esp_tls_v6.0' into 'release/v6.0'
feat(esp-tls): Added support to register custom tls stack (v6.0) See merge request espressif/esp-idf!45709
This commit is contained in:
@@ -4,9 +4,9 @@ if(CONFIG_ESP_TLS_USING_MBEDTLS)
|
||||
"esp_tls_mbedtls.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_TLS_USING_WOLFSSL)
|
||||
if(CONFIG_ESP_TLS_CUSTOM_STACK)
|
||||
list(APPEND srcs
|
||||
"esp_tls_wolfssl.c")
|
||||
"esp_tls_custom_stack.c")
|
||||
endif()
|
||||
|
||||
set(priv_req http_parser esp_timer)
|
||||
@@ -17,15 +17,9 @@ endif()
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} esp-tls-crypto
|
||||
PRIV_INCLUDE_DIRS "private_include"
|
||||
# mbedtls is public requirements because esp_tls.h
|
||||
# includes mbedtls header files.
|
||||
REQUIRES mbedtls
|
||||
PRIV_REQUIRES ${priv_req})
|
||||
|
||||
if(CONFIG_ESP_TLS_USING_WOLFSSL)
|
||||
idf_component_get_property(wolfssl esp-wolfssl COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${wolfssl})
|
||||
endif()
|
||||
|
||||
if(NOT ${IDF_TARGET} STREQUAL "linux")
|
||||
# Increase link multiplicity to get some lwip symbols correctly resolved by the linker
|
||||
|
||||
+15
-20
@@ -3,15 +3,23 @@ menu "ESP-TLS"
|
||||
prompt "Choose SSL/TLS library for ESP-TLS (See help for more Info)"
|
||||
default ESP_TLS_USING_MBEDTLS
|
||||
help
|
||||
The ESP-TLS APIs support multiple backend TLS libraries. Currently mbedTLS and WolfSSL are
|
||||
supported. Different TLS libraries may support different features and have different resource
|
||||
usage. Consult the ESP-TLS documentation in ESP-IDF Programming guide for more details.
|
||||
The ESP-TLS APIs support multiple backend TLS libraries. mbedTLS is supported by default.
|
||||
Custom TLS stacks can be registered via esp_tls_register_stack() API when
|
||||
CONFIG_ESP_TLS_CUSTOM_STACK is selected. Different TLS libraries may support different
|
||||
features and have different resource usage. Consult the ESP-TLS documentation in ESP-IDF
|
||||
Programming guide for more details.
|
||||
config ESP_TLS_USING_MBEDTLS
|
||||
bool "mbedTLS"
|
||||
select MBEDTLS_TLS_ENABLED
|
||||
config ESP_TLS_USING_WOLFSSL
|
||||
depends on TLS_STACK_WOLFSSL
|
||||
bool "wolfSSL (License info in wolfSSL directory README)"
|
||||
config ESP_TLS_CUSTOM_STACK
|
||||
bool "Custom TLS stack (register via esp_tls_register_stack())"
|
||||
help
|
||||
When selected, allows external components to register their own TLS stack implementation
|
||||
via esp_tls_register_stack() API. The custom stack must be registered before creating
|
||||
any TLS connections, otherwise TLS operations will fail.
|
||||
|
||||
External components can provide any TLS stack implementation by implementing the
|
||||
esp_tls_stack_ops_t interface.
|
||||
endchoice
|
||||
|
||||
config ESP_TLS_USE_SECURE_ELEMENT
|
||||
@@ -80,7 +88,7 @@ menu "ESP-TLS"
|
||||
select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK if ESP_TLS_USING_MBEDTLS && MBEDTLS_ECDH_C
|
||||
help
|
||||
Enable support for pre shared key ciphers, supported for both mbedTLS as well as
|
||||
wolfSSL TLS library.
|
||||
custom TLS stacks.
|
||||
|
||||
config ESP_TLS_INSECURE
|
||||
bool "Allow potentially insecure options"
|
||||
@@ -101,19 +109,6 @@ menu "ESP-TLS"
|
||||
with a server which has a fake identity, provided that the server certificate
|
||||
is not provided either through API or other mechanism like ca_store etc.
|
||||
|
||||
config ESP_DEBUG_WOLFSSL
|
||||
bool "Enable debug logs for wolfSSL"
|
||||
depends on ESP_TLS_USING_WOLFSSL
|
||||
help
|
||||
Enable detailed debug prints for wolfSSL SSL library.
|
||||
|
||||
config ESP_TLS_OCSP_CHECKALL
|
||||
bool "Enabled full OCSP checks for ESP-TLS"
|
||||
depends on ESP_TLS_USING_WOLFSSL
|
||||
default y
|
||||
help
|
||||
Enable a fuller set of OCSP checks: checking revocation status of intermediate certificates,
|
||||
optional fallbacks to CRLs, etc.
|
||||
|
||||
config ESP_TLS_DYN_BUF_STRATEGY_SUPPORTED
|
||||
bool
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -8,24 +8,21 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
__attribute__((unused)) static const char *TAG = "esp_crypto";
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
|
||||
#if CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
#include "mbedtls/base64.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "psa/crypto.h"
|
||||
#define _esp_crypto_sha1 esp_crypto_sha1_mbedtls
|
||||
#define _esp_crypto_base64_encode esp_crypto_bas64_encode_mbedtls
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
#include "wolfssl/ssl.h" /* SHA functions are listed in wolfssl/ssl.h */
|
||||
#include "wolfssl/wolfcrypt/coding.h"
|
||||
#define _esp_crypto_sha1 esp_crypto_sha1_wolfSSL
|
||||
#define _esp_crypto_base64_encode esp_crypto_base64_encode_woflSSL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
static int esp_crypto_sha1_mbedtls( const unsigned char *input,
|
||||
size_t ilen,
|
||||
unsigned char output[20])
|
||||
#if CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
#include "esp_tls_custom_stack.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
static int esp_crypto_sha1_mbedtls(const unsigned char *input,
|
||||
size_t ilen,
|
||||
unsigned char output[20])
|
||||
{
|
||||
#if CONFIG_MBEDTLS_SHA1_C || CONFIG_MBEDTLS_HARDWARE_SHA
|
||||
psa_hash_operation_t ctx = PSA_HASH_OPERATION_INIT;
|
||||
@@ -48,51 +45,52 @@ exit:
|
||||
psa_hash_abort(&ctx);
|
||||
return status == PSA_SUCCESS ? 0 : -1;
|
||||
#else
|
||||
ESP_LOGE(TAG, "Please enable CONFIG_MBEDTLS_SHA1_C or CONFIG_MBEDTLS_HARDWARE_SHA to support SHA1 operations");
|
||||
ESP_LOGE("esp_crypto", "Please enable CONFIG_MBEDTLS_SHA1_C or CONFIG_MBEDTLS_HARDWARE_SHA to support SHA1 operations");
|
||||
return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
|
||||
#endif /* CONFIG_MBEDTLS_SHA1_C || CONFIG_MBEDTLS_HARDWARE_SHA*/
|
||||
}
|
||||
|
||||
static int esp_crypto_bas64_encode_mbedtls( unsigned char *dst, size_t dlen,
|
||||
size_t *olen, const unsigned char *src,
|
||||
size_t slen)
|
||||
static int esp_crypto_base64_encode_mbedtls(unsigned char *dst, size_t dlen,
|
||||
size_t *olen, const unsigned char *src,
|
||||
size_t slen)
|
||||
{
|
||||
return mbedtls_base64_encode(dst, dlen, olen, src, slen);
|
||||
}
|
||||
#endif /* CONFIG_ESP_TLS_USING_MBEDTLS */
|
||||
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
static int esp_crypto_sha1_wolfSSL( const unsigned char *input,
|
||||
size_t ilen,
|
||||
unsigned char output[20])
|
||||
int esp_crypto_sha1(const unsigned char *input,
|
||||
size_t ilen,
|
||||
unsigned char output[20])
|
||||
{
|
||||
unsigned char *ret = wolfSSL_SHA1(input, ilen, output);
|
||||
if (ret == NULL) {
|
||||
ESP_LOGE(TAG, "Error in calculating sha1 sum");
|
||||
#if CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
return esp_crypto_sha1_mbedtls(input, ilen, output);
|
||||
#elif CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
int ret = esp_tls_custom_stack_crypto_sha1(input, ilen, output);
|
||||
if (ret == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGE("esp_crypto", "Custom TLS stack must implement crypto_sha1 callback");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int esp_crypto_base64_encode_woflSSL(unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen)
|
||||
{
|
||||
*olen = dlen;
|
||||
return Base64_Encode_NoNl((const byte *) src, (word32) slen, (byte *) dst, (word32 *) olen);
|
||||
}
|
||||
|
||||
return ret;
|
||||
#else
|
||||
#error "No TLS/SSL Stack selected"
|
||||
ESP_LOGE("esp_crypto", "No TLS stack configured");
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
int esp_crypto_sha1( const unsigned char *input,
|
||||
size_t ilen,
|
||||
unsigned char output[20])
|
||||
{
|
||||
return _esp_crypto_sha1(input, ilen, output);
|
||||
}
|
||||
|
||||
int esp_crypto_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen )
|
||||
const unsigned char *src, size_t slen)
|
||||
{
|
||||
return _esp_crypto_base64_encode(dst, dlen, olen, src, slen);
|
||||
#if CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
return esp_crypto_base64_encode_mbedtls(dst, dlen, olen, src, slen);
|
||||
#elif CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
int ret = esp_tls_custom_stack_crypto_base64_encode(dst, dlen, olen, src, slen);
|
||||
if (ret == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGE("esp_crypto", "Custom TLS stack must implement crypto_base64_encode callback");
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
#else
|
||||
ESP_LOGE("esp_crypto", "No TLS stack configured");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -22,12 +22,9 @@ extern "C" {
|
||||
* @param[out] output calculated sha1 sum
|
||||
*
|
||||
* @return
|
||||
* mbedtls stack:-
|
||||
* - MBEDTLS_ERR_SHA1_BAD_INPUT_DATA on BAD INPUT.
|
||||
* - 0 on success.
|
||||
* wolfssl stack:-
|
||||
* - -1 on failure.
|
||||
* - 0 on success.
|
||||
* - 0 if successful.
|
||||
* - -1 if error.
|
||||
* - MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED if SHA1 is not supported.
|
||||
*/
|
||||
int esp_crypto_sha1(const unsigned char *input,
|
||||
size_t ilen,
|
||||
@@ -43,12 +40,8 @@ int esp_crypto_sha1(const unsigned char *input,
|
||||
* @param[in] slen src buffer len
|
||||
*
|
||||
* @return
|
||||
* mbedtls stack:-
|
||||
* - MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL if buffer is of insufficient size.
|
||||
* - 0 if successful.
|
||||
* wolfssl stack:-
|
||||
* - <0 on failure.
|
||||
* - 0 if succcessful.
|
||||
*/
|
||||
int esp_crypto_base64_encode(unsigned char *dst, size_t dlen,
|
||||
size_t *olen, const unsigned char *src,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -51,8 +51,8 @@ static const char *TAG = "esp-tls";
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
#include "esp_tls_mbedtls.h"
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
#include "esp_tls_wolfssl.h"
|
||||
#elif CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
#include "esp_tls_custom_stack.h"
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
@@ -80,25 +80,33 @@ static const char *TAG = "esp-tls";
|
||||
#define _esp_tls_server_session_ticket_ctx_free esp_mbedtls_server_session_ticket_ctx_free
|
||||
#define _esp_tls_get_bytes_avail esp_mbedtls_get_bytes_avail
|
||||
#define _esp_tls_init_global_ca_store esp_mbedtls_init_global_ca_store
|
||||
#define _esp_tls_set_global_ca_store esp_mbedtls_set_global_ca_store /*!< Callback function for setting global CA store data for TLS/SSL */
|
||||
#define _esp_tls_set_global_ca_store esp_mbedtls_set_global_ca_store
|
||||
#define _esp_tls_get_global_ca_store esp_mbedtls_get_global_ca_store
|
||||
#define _esp_tls_free_global_ca_store esp_mbedtls_free_global_ca_store /*!< Callback function for freeing global ca store for TLS/SSL */
|
||||
#define _esp_tls_free_global_ca_store esp_mbedtls_free_global_ca_store
|
||||
#define _esp_tls_get_ciphersuites_list esp_mbedtls_get_ciphersuites_list
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */
|
||||
#define _esp_create_ssl_handle esp_create_wolfssl_handle
|
||||
#define _esp_tls_handshake esp_wolfssl_handshake
|
||||
#define _esp_tls_read esp_wolfssl_read
|
||||
#define _esp_tls_write esp_wolfssl_write
|
||||
#define _esp_tls_conn_delete esp_wolfssl_conn_delete
|
||||
#define _esp_tls_net_init esp_wolfssl_net_init
|
||||
#define _esp_tls_server_session_create esp_wolfssl_server_session_create
|
||||
#define _esp_tls_server_session_delete esp_wolfssl_server_session_delete
|
||||
#define _esp_tls_get_bytes_avail esp_wolfssl_get_bytes_avail
|
||||
#define _esp_tls_init_global_ca_store esp_wolfssl_init_global_ca_store
|
||||
#define _esp_tls_set_global_ca_store esp_wolfssl_set_global_ca_store /*!< Callback function for setting global CA store data for TLS/SSL */
|
||||
#define _esp_tls_free_global_ca_store esp_wolfssl_free_global_ca_store /*!< Callback function for freeing global ca store for TLS/SSL */
|
||||
#define _esp_tls_get_ssl_context esp_wolfssl_get_ssl_context
|
||||
#else /* ESP_TLS_USING_WOLFSSL */
|
||||
#elif CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
#define _esp_create_ssl_handle esp_tls_custom_stack_create_ssl_handle
|
||||
#define _esp_tls_handshake esp_tls_custom_stack_handshake
|
||||
#define _esp_tls_read esp_tls_custom_stack_read
|
||||
#define _esp_tls_write esp_tls_custom_stack_write
|
||||
#define _esp_tls_conn_delete esp_tls_custom_stack_conn_delete
|
||||
#define _esp_tls_net_init esp_tls_custom_stack_net_init
|
||||
#define _esp_tls_get_client_session esp_tls_custom_stack_get_client_session
|
||||
#define _esp_tls_free_client_session esp_tls_custom_stack_free_client_session
|
||||
#define _esp_tls_get_ssl_context esp_tls_custom_stack_get_ssl_context
|
||||
#define _esp_tls_server_session_create esp_tls_custom_stack_server_session_create
|
||||
#define _esp_tls_server_session_init esp_tls_custom_stack_server_session_init
|
||||
#define _esp_tls_server_session_continue_async esp_tls_custom_stack_server_session_continue_async
|
||||
#define _esp_tls_server_session_delete esp_tls_custom_stack_server_session_delete
|
||||
#define _esp_tls_server_session_ticket_ctx_init esp_tls_custom_stack_server_session_ticket_ctx_init
|
||||
#define _esp_tls_server_session_ticket_ctx_free esp_tls_custom_stack_server_session_ticket_ctx_free
|
||||
#define _esp_tls_get_bytes_avail esp_tls_custom_stack_get_bytes_avail
|
||||
#define _esp_tls_init_global_ca_store esp_tls_custom_stack_init_global_ca_store
|
||||
#define _esp_tls_set_global_ca_store esp_tls_custom_stack_set_global_ca_store
|
||||
#define _esp_tls_get_global_ca_store esp_tls_custom_stack_get_global_ca_store
|
||||
#define _esp_tls_free_global_ca_store esp_tls_custom_stack_free_global_ca_store
|
||||
#define _esp_tls_get_ciphersuites_list esp_tls_custom_stack_get_ciphersuites_list
|
||||
#else
|
||||
#error "No TLS stack configured"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
#ifdef CONFIG_ESP_TLS_SERVER_SESSION_TICKETS
|
||||
#include "mbedtls/ssl_ticket.h"
|
||||
#endif
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
#include "wolfssl/wolfcrypt/settings.h"
|
||||
#include "wolfssl/ssl.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
|
||||
#include "esp_tls_custom_stack.h"
|
||||
#include "esp_tls_private.h"
|
||||
#include "esp_log.h"
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static const char *TAG = "esp-tls-custom-stack";
|
||||
|
||||
static const esp_tls_stack_ops_t *s_esp_tls_custom_stack = NULL;
|
||||
static void *s_esp_tls_custom_stack_user_ctx = NULL;
|
||||
|
||||
#define CHECK_STACK_REGISTERED(ret_val) \
|
||||
do { \
|
||||
if (s_esp_tls_custom_stack == NULL) { \
|
||||
ESP_LOGE(TAG, "No TLS stack registered. Call esp_tls_register_stack() first."); \
|
||||
return ret_val; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_STACK_REGISTERED_VOID() \
|
||||
do { \
|
||||
if (s_esp_tls_custom_stack == NULL) { \
|
||||
ESP_LOGE(TAG, "No TLS stack registered. Call esp_tls_register_stack() first."); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
esp_err_t esp_tls_register_stack(const esp_tls_stack_ops_t *ops, void *user_ctx)
|
||||
{
|
||||
if (!ops) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Validate version */
|
||||
if (ops->version != ESP_TLS_STACK_OPS_VERSION) {
|
||||
ESP_LOGE(TAG, "Invalid TLS stack version: expected %d, got %" PRIu32,
|
||||
ESP_TLS_STACK_OPS_VERSION, ops->version);
|
||||
return ESP_ERR_INVALID_VERSION;
|
||||
}
|
||||
|
||||
/* Validate required function pointers */
|
||||
if (!ops->create_ssl_handle || !ops->handshake || !ops->read || !ops->write ||
|
||||
!ops->conn_delete || !ops->net_init || !ops->get_ssl_context ||
|
||||
!ops->get_bytes_avail || !ops->init_global_ca_store ||
|
||||
!ops->set_global_ca_store || !ops->get_global_ca_store ||
|
||||
!ops->free_global_ca_store || !ops->get_ciphersuites_list) {
|
||||
ESP_LOGE(TAG, "Invalid TLS stack operations: required function pointers are NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (s_esp_tls_custom_stack != NULL) {
|
||||
ESP_LOGE(TAG, "TLS stack already registered");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
s_esp_tls_custom_stack = ops;
|
||||
s_esp_tls_custom_stack_user_ctx = user_ctx;
|
||||
ESP_LOGI(TAG, "Custom TLS stack registered successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const esp_tls_stack_ops_t *esp_tls_get_registered_stack(void)
|
||||
{
|
||||
return s_esp_tls_custom_stack;
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_unregister_stack(void)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL) {
|
||||
ESP_LOGW(TAG, "No TLS stack registered");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
s_esp_tls_custom_stack = NULL;
|
||||
s_esp_tls_custom_stack_user_ctx = NULL;
|
||||
ESP_LOGI(TAG, "Custom TLS stack unregistered successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_custom_stack_create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls, void *server_params)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(ESP_ERR_INVALID_STATE);
|
||||
return s_esp_tls_custom_stack->create_ssl_handle(s_esp_tls_custom_stack_user_ctx, hostname, hostlen, cfg, tls, server_params);
|
||||
}
|
||||
|
||||
int esp_tls_custom_stack_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(-1);
|
||||
return s_esp_tls_custom_stack->handshake(s_esp_tls_custom_stack_user_ctx, tls, cfg);
|
||||
}
|
||||
|
||||
ssize_t esp_tls_custom_stack_read(esp_tls_t *tls, char *data, size_t datalen)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(-1);
|
||||
return s_esp_tls_custom_stack->read(s_esp_tls_custom_stack_user_ctx, tls, data, datalen);
|
||||
}
|
||||
|
||||
ssize_t esp_tls_custom_stack_write(esp_tls_t *tls, const char *data, size_t datalen)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(-1);
|
||||
return s_esp_tls_custom_stack->write(s_esp_tls_custom_stack_user_ctx, tls, data, datalen);
|
||||
}
|
||||
|
||||
void esp_tls_custom_stack_conn_delete(esp_tls_t *tls)
|
||||
{
|
||||
CHECK_STACK_REGISTERED_VOID();
|
||||
s_esp_tls_custom_stack->conn_delete(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
}
|
||||
|
||||
void esp_tls_custom_stack_net_init(esp_tls_t *tls)
|
||||
{
|
||||
CHECK_STACK_REGISTERED_VOID();
|
||||
s_esp_tls_custom_stack->net_init(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
}
|
||||
|
||||
void *esp_tls_custom_stack_get_ssl_context(esp_tls_t *tls)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(NULL);
|
||||
return s_esp_tls_custom_stack->get_ssl_context(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
}
|
||||
|
||||
ssize_t esp_tls_custom_stack_get_bytes_avail(esp_tls_t *tls)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(-1);
|
||||
return s_esp_tls_custom_stack->get_bytes_avail(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_custom_stack_init_global_ca_store(void)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(ESP_ERR_INVALID_STATE);
|
||||
return s_esp_tls_custom_stack->init_global_ca_store(s_esp_tls_custom_stack_user_ctx);
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_custom_stack_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(ESP_ERR_INVALID_STATE);
|
||||
return s_esp_tls_custom_stack->set_global_ca_store(s_esp_tls_custom_stack_user_ctx, cacert_pem_buf, cacert_pem_bytes);
|
||||
}
|
||||
|
||||
void *esp_tls_custom_stack_get_global_ca_store(void)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(NULL);
|
||||
return s_esp_tls_custom_stack->get_global_ca_store(s_esp_tls_custom_stack_user_ctx);
|
||||
}
|
||||
|
||||
void esp_tls_custom_stack_free_global_ca_store(void)
|
||||
{
|
||||
CHECK_STACK_REGISTERED_VOID();
|
||||
s_esp_tls_custom_stack->free_global_ca_store(s_esp_tls_custom_stack_user_ctx);
|
||||
}
|
||||
|
||||
const int *esp_tls_custom_stack_get_ciphersuites_list(void)
|
||||
{
|
||||
CHECK_STACK_REGISTERED(NULL);
|
||||
return s_esp_tls_custom_stack->get_ciphersuites_list(s_esp_tls_custom_stack_user_ctx);
|
||||
}
|
||||
|
||||
void *esp_tls_custom_stack_get_client_session(esp_tls_t *tls)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->get_client_session) {
|
||||
ESP_LOGE(TAG, "No TLS stack registered or client session not supported.");
|
||||
return NULL;
|
||||
}
|
||||
return s_esp_tls_custom_stack->get_client_session(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
}
|
||||
|
||||
void esp_tls_custom_stack_free_client_session(void *client_session)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->free_client_session) {
|
||||
ESP_LOGE(TAG, "No TLS stack registered or client session not supported.");
|
||||
return;
|
||||
}
|
||||
s_esp_tls_custom_stack->free_client_session(s_esp_tls_custom_stack_user_ctx, client_session);
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_custom_stack_server_session_ticket_ctx_init(void *cfg)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->server_session_ticket_ctx_init) {
|
||||
ESP_LOGE(TAG, "No TLS stack registered or server session tickets not supported.");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
return s_esp_tls_custom_stack->server_session_ticket_ctx_init(s_esp_tls_custom_stack_user_ctx, cfg);
|
||||
}
|
||||
|
||||
void esp_tls_custom_stack_server_session_ticket_ctx_free(void *cfg)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->server_session_ticket_ctx_free) {
|
||||
ESP_LOGE(TAG, "No TLS stack registered or server session tickets not supported.");
|
||||
return;
|
||||
}
|
||||
s_esp_tls_custom_stack->server_session_ticket_ctx_free(s_esp_tls_custom_stack_user_ctx, cfg);
|
||||
}
|
||||
|
||||
int esp_tls_custom_stack_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->server_session_create) {
|
||||
ESP_LOGE(TAG, "No TLS stack registered or server session not supported.");
|
||||
return -1;
|
||||
}
|
||||
return s_esp_tls_custom_stack->server_session_create(s_esp_tls_custom_stack_user_ctx, cfg, sockfd, tls);
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_custom_stack_server_session_init(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->server_session_init) {
|
||||
ESP_LOGE(TAG, "No TLS stack registered or server session not supported.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return s_esp_tls_custom_stack->server_session_init(s_esp_tls_custom_stack_user_ctx, cfg, sockfd, tls);
|
||||
}
|
||||
|
||||
int esp_tls_custom_stack_server_session_continue_async(esp_tls_t *tls)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->server_session_continue_async) {
|
||||
ESP_LOGE(TAG, "No TLS stack registered or server session not supported.");
|
||||
return -1;
|
||||
}
|
||||
return s_esp_tls_custom_stack->server_session_continue_async(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
}
|
||||
|
||||
void esp_tls_custom_stack_server_session_delete(esp_tls_t *tls)
|
||||
{
|
||||
CHECK_STACK_REGISTERED_VOID();
|
||||
if (s_esp_tls_custom_stack->server_session_delete) {
|
||||
s_esp_tls_custom_stack->server_session_delete(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
} else {
|
||||
/* Fall back to conn_delete as documented */
|
||||
s_esp_tls_custom_stack->conn_delete(s_esp_tls_custom_stack_user_ctx, tls);
|
||||
}
|
||||
}
|
||||
|
||||
int esp_tls_custom_stack_crypto_sha1(const unsigned char *input, size_t ilen, unsigned char output[20])
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->crypto_sha1) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
return s_esp_tls_custom_stack->crypto_sha1(s_esp_tls_custom_stack_user_ctx, input, ilen, output);
|
||||
}
|
||||
|
||||
int esp_tls_custom_stack_crypto_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen)
|
||||
{
|
||||
if (s_esp_tls_custom_stack == NULL || !s_esp_tls_custom_stack->crypto_base64_encode) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
return s_esp_tls_custom_stack->crypto_base64_encode(s_esp_tls_custom_stack_user_ctx, dst, dlen, olen, src, slen);
|
||||
}
|
||||
|
||||
#else /* CONFIG_ESP_TLS_CUSTOM_STACK */
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_tls_custom_stack.h"
|
||||
|
||||
/* Stub implementations when custom stack is disabled */
|
||||
esp_err_t esp_tls_register_stack(const esp_tls_stack_ops_t *ops, void *user_ctx)
|
||||
{
|
||||
(void)ops;
|
||||
(void)user_ctx;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
const esp_tls_stack_ops_t *esp_tls_get_registered_stack(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_unregister_stack(void)
|
||||
{
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ESP_TLS_CUSTOM_STACK */
|
||||
@@ -0,0 +1,734 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_assert.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_tls.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Version of the TLS stack operations structure
|
||||
*
|
||||
* This version number must be set in the `version` field of esp_tls_stack_ops_t
|
||||
* when registering a custom TLS stack. It allows ESP-TLS to detect incompatible
|
||||
* interface changes between ESP-IDF versions and custom stack implementations.
|
||||
*/
|
||||
#define ESP_TLS_STACK_OPS_VERSION 1
|
||||
|
||||
/**
|
||||
* @brief TLS stack operations vtable
|
||||
*
|
||||
* This structure defines the interface that external TLS stack implementations
|
||||
* must provide. All function pointers must be non-NULL.
|
||||
*
|
||||
* @note To register a custom TLS stack:
|
||||
* 1. Enable CONFIG_ESP_TLS_CUSTOM_STACK in menuconfig
|
||||
* 2. Implement all required functions in this structure
|
||||
* 3. Call esp_tls_register_stack() with your implementation before creating any TLS connections
|
||||
*
|
||||
* @note The TLS context (esp_tls_t) is managed by ESP-TLS. Your implementation should store
|
||||
* stack-specific data in the appropriate fields of esp_tls_t (e.g., priv_ctx, priv_ssl)
|
||||
* or allocate additional memory and store a pointer to it.
|
||||
*
|
||||
* @note For client connections: hostname and cfg (esp_tls_cfg_t) are provided
|
||||
* @note For server connections: hostname is NULL, cfg is esp_tls_cfg_server_t, server_params is provided
|
||||
*/
|
||||
typedef struct esp_tls_stack_ops {
|
||||
/**
|
||||
* @brief Structure version for compatibility checking
|
||||
*
|
||||
* Must be set to ESP_TLS_STACK_OPS_VERSION. This field allows ESP-TLS to
|
||||
* detect version mismatches between the ESP-IDF version and the custom
|
||||
* TLS stack implementation.
|
||||
*/
|
||||
uint32_t version;
|
||||
|
||||
/**
|
||||
* @brief Create SSL handle for a TLS connection
|
||||
*
|
||||
* This function initializes the TLS stack for a new connection. It should:
|
||||
* - Initialize the TLS/SSL context for the given connection
|
||||
* - Configure certificates, keys, and other TLS parameters from cfg
|
||||
* - Set up the underlying socket (tls->sockfd is already set)
|
||||
* - For client: configure SNI using hostname
|
||||
* - For server: use server_params if provided
|
||||
* - Store stack-specific context in tls->priv_ctx or tls->priv_ssl
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param hostname Hostname for the connection (client only, NULL for server)
|
||||
* @param hostlen Length of hostname (0 for server)
|
||||
* @param cfg TLS configuration:
|
||||
* - For client: pointer to esp_tls_cfg_t
|
||||
* - For server: pointer to esp_tls_cfg_server_t
|
||||
* @param tls TLS context (already allocated, sockfd is set)
|
||||
* @param server_params Server-specific parameters (NULL for client, non-NULL for server)
|
||||
* Contains server configuration callbacks
|
||||
* @return
|
||||
* - ESP_OK: SSL handle created successfully
|
||||
* - ESP_ERR_NO_MEM: Memory allocation failed
|
||||
* - ESP_ERR_INVALID_ARG: Invalid configuration
|
||||
* - Other error codes: Stack-specific errors
|
||||
*/
|
||||
esp_err_t (*create_ssl_handle)(void *user_ctx, const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls, void *server_params);
|
||||
|
||||
/**
|
||||
* @brief Perform TLS handshake
|
||||
*
|
||||
* This function performs the TLS handshake. It should:
|
||||
* - Execute the TLS handshake protocol
|
||||
* - Handle handshake state (may need multiple calls)
|
||||
* - Verify certificates if configured
|
||||
* - Update tls->conn_state appropriately
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context (created by create_ssl_handle)
|
||||
* @param cfg TLS configuration (esp_tls_cfg_t for client, can be used for timeout checks)
|
||||
*
|
||||
* @return
|
||||
* - 1: Handshake completed successfully
|
||||
* - 0: Handshake in progress, call again later
|
||||
* - ESP_TLS_ERR_SSL_WANT_READ: Need to read more data from socket
|
||||
* - ESP_TLS_ERR_SSL_WANT_WRITE: Need to write more data to socket
|
||||
* - Negative value: Handshake failed (error code)
|
||||
*
|
||||
* @note This function may be called multiple times until it returns 1 or a negative error.
|
||||
* The ESP-TLS layer handles retries based on the return value.
|
||||
*/
|
||||
int (*handshake)(void *user_ctx, esp_tls_t *tls, const esp_tls_cfg_t *cfg);
|
||||
|
||||
/**
|
||||
* @brief Read data from TLS connection
|
||||
*
|
||||
* This function reads decrypted application data from the TLS connection.
|
||||
* It should:
|
||||
* - Read encrypted data from tls->sockfd
|
||||
* - Decrypt using the TLS stack
|
||||
* - Return decrypted application data
|
||||
* - Handle partial reads and blocking/non-blocking behavior
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context (handshake must be completed)
|
||||
* @param data Buffer to store decrypted data
|
||||
* @param datalen Maximum number of bytes to read (size of data buffer)
|
||||
*
|
||||
* @return
|
||||
* - Positive value: Number of bytes read (0 < return <= datalen)
|
||||
* - 0: Connection closed by peer
|
||||
* - ESP_TLS_ERR_SSL_WANT_READ: Need to read more encrypted data from socket
|
||||
* - ESP_TLS_ERR_SSL_WANT_WRITE: Need to write data (renegotiation)
|
||||
* - Negative value: Error occurred
|
||||
*
|
||||
* @note This function is called by tls->read() callback, which is set during handshake.
|
||||
* @note The function should handle TLS record boundaries and may need multiple socket reads
|
||||
* to decrypt a single application data record.
|
||||
*/
|
||||
ssize_t (*read)(void *user_ctx, esp_tls_t *tls, char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* @brief Write data to TLS connection
|
||||
*
|
||||
* This function encrypts and writes application data to the TLS connection.
|
||||
* It should:
|
||||
* - Encrypt application data using the TLS stack
|
||||
* - Write encrypted data to tls->sockfd
|
||||
* - Handle partial writes and blocking/non-blocking behavior
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context (handshake must be completed)
|
||||
* @param data Application data to encrypt and send
|
||||
* @param datalen Number of bytes to write
|
||||
*
|
||||
* @return
|
||||
* - Positive value: Number of bytes written (should equal datalen if successful)
|
||||
* - ESP_TLS_ERR_SSL_WANT_READ: Need to read data (renegotiation)
|
||||
* - ESP_TLS_ERR_SSL_WANT_WRITE: Socket buffer full, try again later
|
||||
* - Negative value: Error occurred
|
||||
*
|
||||
* @note This function is called by tls->write() callback, which is set during handshake.
|
||||
* @note The function may write less than datalen if the socket buffer is full (non-blocking mode).
|
||||
* The caller should retry with remaining data.
|
||||
*/
|
||||
ssize_t (*write)(void *user_ctx, esp_tls_t *tls, const char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* @brief Delete TLS connection and free resources
|
||||
*
|
||||
* This function cleans up the TLS connection and frees all resources.
|
||||
* It should:
|
||||
* - Close the TLS/SSL session
|
||||
* - Free any stack-specific context stored in tls->priv_ctx or tls->priv_ssl
|
||||
* - Free any allocated memory
|
||||
* - Note: tls->sockfd is closed separately by ESP-TLS, don't close it here
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context to clean up
|
||||
*
|
||||
* @note This function should be idempotent (safe to call multiple times).
|
||||
* @note After this call, the tls context may be freed, so don't access it afterwards.
|
||||
*/
|
||||
void (*conn_delete)(void *user_ctx, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Initialize network context
|
||||
*
|
||||
* This function initializes any network-related structures needed by the TLS stack.
|
||||
* It should:
|
||||
* - Initialize socket wrappers or network context structures
|
||||
* - Set up any network-related state
|
||||
* - This is typically called once per TLS context before create_ssl_handle
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context (sockfd is already set)
|
||||
*
|
||||
* @note For some stacks, this may be a no-op if network initialization is handled elsewhere.
|
||||
* @note This is called early in the connection setup, before create_ssl_handle.
|
||||
*/
|
||||
void (*net_init)(void *user_ctx, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Get SSL context (stack-specific)
|
||||
*
|
||||
* This function returns the underlying SSL/TLS context object from the stack.
|
||||
* This allows users to access stack-specific APIs directly if needed.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context
|
||||
*
|
||||
* @return Pointer to stack-specific SSL context (e.g., mbedtls_ssl_context*, SSL_CTX*, etc.)
|
||||
* or NULL if not available
|
||||
*
|
||||
* @note The returned pointer is stack-specific and should be cast to the appropriate type
|
||||
* by users who know which stack is registered.
|
||||
* @note This is optional but recommended for advanced users who need stack-specific features.
|
||||
*/
|
||||
void *(*get_ssl_context)(void *user_ctx, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Get bytes available for reading
|
||||
*
|
||||
* This function returns the number of decrypted application data bytes
|
||||
* available to read without blocking.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context
|
||||
*
|
||||
* @return
|
||||
* - Positive value: Number of bytes available to read
|
||||
* - 0: No data available
|
||||
* - Negative value: Error occurred
|
||||
*
|
||||
* @note This checks the TLS stack's internal buffer, not the socket buffer.
|
||||
* @note Useful for non-blocking I/O to check if data is ready before calling read().
|
||||
*/
|
||||
ssize_t (*get_bytes_avail)(void *user_ctx, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Initialize global CA store
|
||||
*
|
||||
* This function initializes a global certificate authority (CA) store that can be
|
||||
* used by all TLS connections. This is useful for applications that want to use
|
||||
* the same CA certificates for multiple connections.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: CA store initialized successfully
|
||||
* - ESP_ERR_NO_MEM: Memory allocation failed
|
||||
* - Other error codes: Stack-specific errors
|
||||
*
|
||||
* @note This is called once at application startup if esp_tls_init_global_ca_store() is used.
|
||||
* @note The global CA store is optional - individual connections can use their own CA certificates.
|
||||
*/
|
||||
esp_err_t (*init_global_ca_store)(void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Set global CA store
|
||||
*
|
||||
* This function loads CA certificates into the global CA store.
|
||||
* The certificates are used for server certificate verification in client connections.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param cacert_pem_buf CA certificate buffer in PEM format (NULL-terminated)
|
||||
* @param cacert_pem_bytes Size of CA certificate buffer (including NULL terminator for PEM)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: CA certificates loaded successfully
|
||||
* - ESP_ERR_INVALID_ARG: Invalid certificate format
|
||||
* - ESP_ERR_NO_MEM: Memory allocation failed
|
||||
* - Other error codes: Stack-specific errors
|
||||
*
|
||||
* @note The buffer should contain one or more PEM-formatted CA certificates.
|
||||
* @note For PEM format, the buffer must be NULL-terminated.
|
||||
* @note This can be called multiple times to add more certificates.
|
||||
*/
|
||||
esp_err_t (*set_global_ca_store)(void *user_ctx, const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes);
|
||||
|
||||
/**
|
||||
* @brief Get global CA store (stack-specific)
|
||||
*
|
||||
* This function returns the underlying CA store object from the stack.
|
||||
* This allows users to access stack-specific CA store APIs directly if needed.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
*
|
||||
* @return Pointer to stack-specific CA store (e.g., mbedtls_x509_crt*, X509_STORE*, etc.)
|
||||
* or NULL if not initialized
|
||||
*
|
||||
* @note The returned pointer is stack-specific and should be cast to the appropriate type.
|
||||
* @note This is optional but useful for advanced users who need stack-specific features.
|
||||
*/
|
||||
void *(*get_global_ca_store)(void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Free global CA store
|
||||
*
|
||||
* This function frees all resources associated with the global CA store.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
*
|
||||
* @note This should free all certificates and memory allocated for the CA store.
|
||||
* @note After this call, the global CA store is no longer usable until reinitialized.
|
||||
*/
|
||||
void (*free_global_ca_store)(void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Get list of supported ciphersuites
|
||||
*
|
||||
* This function returns a list of IANA ciphersuite identifiers supported by the stack.
|
||||
* This is used by esp_tls_get_ciphersuites_list() API.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
*
|
||||
* @return Pointer to zero-terminated array of IANA ciphersuite identifiers (integers)
|
||||
* The array must be terminated with 0.
|
||||
*
|
||||
* @note The returned pointer should point to static/const data (not dynamically allocated).
|
||||
* @note Ciphersuite identifiers are IANA standard values (e.g., 0x0035 for TLS_RSA_WITH_AES_256_CBC_SHA).
|
||||
* @note This list is used for validation when users specify custom ciphersuite lists.
|
||||
*/
|
||||
const int *(*get_ciphersuites_list)(void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Get client session (optional, for session ticket support)
|
||||
*
|
||||
* This function retrieves the client session ticket/session data that can be reused
|
||||
* for subsequent connections to the same server (RFC 5077).
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context (handshake must be completed)
|
||||
*
|
||||
* @return Pointer to client session data (stack-specific type), or NULL if:
|
||||
* - Session tickets are not supported
|
||||
* - No session ticket was received
|
||||
* - Error occurred
|
||||
*
|
||||
* @note The returned session can be stored and reused in future connections to the same server.
|
||||
* @note This is only used if CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is enabled.
|
||||
* @note The session data is stack-specific and opaque to ESP-TLS.
|
||||
* @note Can be NULL if session tickets are not supported by the stack.
|
||||
*/
|
||||
void *(*get_client_session)(void *user_ctx, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Free client session (optional, for session ticket support)
|
||||
*
|
||||
* This function frees resources associated with a client session retrieved by get_client_session().
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param client_session Client session to free (returned by get_client_session())
|
||||
*
|
||||
* @note This should free all memory associated with the session.
|
||||
* @note This is only used if CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is enabled.
|
||||
* @note Can be NULL if session tickets are not supported by the stack.
|
||||
*/
|
||||
void (*free_client_session)(void *user_ctx, void *client_session);
|
||||
|
||||
/**
|
||||
* @brief Initialize server session ticket context (optional, for server session ticket support)
|
||||
*
|
||||
* This function initializes the server-side session ticket context for issuing
|
||||
* and validating session tickets (RFC 5077).
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param cfg Pointer to esp_tls_server_session_ticket_ctx_t structure
|
||||
* Contains ticket encryption keys and configuration
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Session ticket context initialized successfully
|
||||
* - ESP_ERR_INVALID_ARG: Invalid configuration
|
||||
* - ESP_ERR_NO_MEM: Memory allocation failed
|
||||
* - Other error codes: Stack-specific errors
|
||||
*
|
||||
* @note This is called when setting up server session tickets.
|
||||
* @note The context should store encryption keys and other ticket-related state.
|
||||
* @note This is only used if CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is enabled.
|
||||
* @note Can be NULL if server session tickets are not supported by the stack.
|
||||
*/
|
||||
esp_err_t (*server_session_ticket_ctx_init)(void *user_ctx, void *cfg);
|
||||
|
||||
/**
|
||||
* @brief Free server session ticket context (optional, for server session ticket support)
|
||||
*
|
||||
* This function frees resources associated with the server session ticket context.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param cfg Pointer to esp_tls_server_session_ticket_ctx_t structure to free
|
||||
*
|
||||
* @note This should free all memory and clear sensitive data (encryption keys).
|
||||
* @note This is only used if CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is enabled.
|
||||
* @note Can be NULL if server session tickets are not supported by the stack.
|
||||
*/
|
||||
void (*server_session_ticket_ctx_free)(void *user_ctx, void *cfg);
|
||||
|
||||
/**
|
||||
* @brief Create server session (optional, server-side only)
|
||||
*
|
||||
* This function creates a complete TLS server session, performing initialization
|
||||
* and handshake in a blocking manner. This is a convenience function that combines
|
||||
* server_session_init() and server_session_continue_async().
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param cfg Server configuration (esp_tls_cfg_server_t)
|
||||
* @param sockfd Socket file descriptor (already connected)
|
||||
* @param tls TLS context (already allocated)
|
||||
*
|
||||
* @return
|
||||
* - 1: Server session created successfully, handshake completed
|
||||
* - 0: Should not happen (this is a blocking function)
|
||||
* - ESP_TLS_ERR_SSL_WANT_READ: Need to read more data (should retry)
|
||||
* - ESP_TLS_ERR_SSL_WANT_WRITE: Need to write more data (should retry)
|
||||
* - Negative value: Error occurred
|
||||
*
|
||||
* @note This function should handle the complete handshake internally.
|
||||
* @note For non-blocking operation, use server_session_init() + server_session_continue_async() instead.
|
||||
* @note This is optional - if NULL, ESP-TLS will use server_session_init() + server_session_continue_async().
|
||||
*/
|
||||
int (*server_session_create)(void *user_ctx, esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Initialize server session (optional, server-side only)
|
||||
*
|
||||
* This function initializes a TLS server session. It should:
|
||||
* - Set up the TLS context for server mode
|
||||
* - Configure server certificates and keys from cfg
|
||||
* - Prepare for handshake (but don't perform it yet)
|
||||
* - Set tls->read and tls->write callbacks
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param cfg Server configuration (esp_tls_cfg_server_t)
|
||||
* @param sockfd Socket file descriptor (already connected)
|
||||
* @param tls TLS context (already allocated)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Server session initialized successfully
|
||||
* - ESP_ERR_INVALID_ARG: Invalid configuration
|
||||
* - ESP_ERR_NO_MEM: Memory allocation failed
|
||||
* - Other error codes: Stack-specific errors
|
||||
*
|
||||
* @note After this, call server_session_continue_async() to perform the handshake.
|
||||
* @note This is optional - if NULL, server_session_create() must be implemented.
|
||||
*/
|
||||
esp_err_t (*server_session_init)(void *user_ctx, esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Continue async server session handshake (optional, server-side only)
|
||||
*
|
||||
* This function continues the TLS handshake for a server session initialized
|
||||
* with server_session_init(). It should be called repeatedly until it returns 0.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context (initialized by server_session_init)
|
||||
*
|
||||
* @return
|
||||
* - 0: Handshake completed successfully
|
||||
* - ESP_TLS_ERR_SSL_WANT_READ: Need to read more data from client, call again later
|
||||
* - ESP_TLS_ERR_SSL_WANT_WRITE: Need to write data to client, call again later
|
||||
* - Negative value: Handshake failed (error code)
|
||||
*
|
||||
* @note This should be called in a loop until it returns 0 or a negative error.
|
||||
* @note The ESP-TLS layer handles the looping and timeout management.
|
||||
* @note This is optional - if NULL, server_session_create() must be implemented.
|
||||
*/
|
||||
int (*server_session_continue_async)(void *user_ctx, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Delete server session (optional, server-side only)
|
||||
*
|
||||
* This function cleans up a server TLS session. It should:
|
||||
* - Close the TLS session
|
||||
* - Free any server-specific resources
|
||||
* - Note: tls->sockfd is closed separately, don't close it here
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param tls TLS context to clean up
|
||||
*
|
||||
* @note This is similar to conn_delete() but may have server-specific cleanup.
|
||||
* @note If NULL, conn_delete() will be used instead.
|
||||
*/
|
||||
void (*server_session_delete)(void *user_ctx, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* @brief Calculate SHA1 hash (optional, for esp_crypto_sha1 API)
|
||||
*
|
||||
* This function calculates the SHA1 hash of the input data. It is used by
|
||||
* esp_crypto_sha1() API which is needed by components like esp_http_server
|
||||
* for WebSocket key calculation.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param input Input data buffer
|
||||
* @param ilen Length of input data
|
||||
* @param output Output buffer for SHA1 hash (must be at least 20 bytes)
|
||||
*
|
||||
* @return
|
||||
* - 0: Success
|
||||
* - Negative value: Error occurred
|
||||
*
|
||||
* @note If NULL, esp_crypto_sha1() API calls will fail. This callback must be implemented
|
||||
* if your application or any dependent component (e.g., esp_http_server for WebSocket)
|
||||
* uses the esp_crypto_sha1() API.
|
||||
*/
|
||||
int (*crypto_sha1)(void *user_ctx, const unsigned char *input, size_t ilen, unsigned char output[20]);
|
||||
|
||||
/**
|
||||
* @brief Base64 encode data (optional, for esp_crypto_base64_encode API)
|
||||
*
|
||||
* This function performs Base64 encoding of the source data. It is used by
|
||||
* esp_crypto_base64_encode() API which is needed by components like esp_http_server
|
||||
* for WebSocket key encoding.
|
||||
*
|
||||
* @param user_ctx User context pointer passed to esp_tls_register_stack()
|
||||
* @param dst Destination buffer for encoded data
|
||||
* @param dlen Size of destination buffer
|
||||
* @param olen Pointer to store the number of bytes written
|
||||
* @param src Source data buffer
|
||||
* @param slen Length of source data
|
||||
*
|
||||
* @return
|
||||
* - 0: Success
|
||||
* - -0x002A: Buffer too small
|
||||
* - Other negative value: Error occurred
|
||||
*
|
||||
* @note If NULL, esp_crypto_base64_encode() API calls will fail. This callback must be
|
||||
* implemented if your application or any dependent component (e.g., esp_http_server
|
||||
* for WebSocket) uses the esp_crypto_base64_encode() API.
|
||||
*/
|
||||
int (*crypto_base64_encode)(void *user_ctx, unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen);
|
||||
} esp_tls_stack_ops_t;
|
||||
|
||||
/**
|
||||
* Compile-time check to detect structure layout changes.
|
||||
* If this assertion fails, you MUST increment ESP_TLS_STACK_OPS_VERSION.
|
||||
*
|
||||
* Field count: 1 (version) + 23 (function pointers) = 24
|
||||
*/
|
||||
ESP_STATIC_ASSERT(sizeof(esp_tls_stack_ops_t) == 24 * sizeof(void *), "esp_tls_stack_ops_t layout changed - update ESP_TLS_STACK_OPS_VERSION!");
|
||||
|
||||
/**
|
||||
* @brief Register a custom TLS stack implementation
|
||||
*
|
||||
* This function allows an external component to register its TLS stack implementation.
|
||||
* Once registered, all TLS connections created after this call will use the registered stack.
|
||||
*
|
||||
* @note This function must be called before creating any TLS connections (esp_tls_conn_new(), etc.).
|
||||
* @note This function can only be called once. Subsequent calls will return ESP_ERR_INVALID_STATE.
|
||||
* @note If CONFIG_ESP_TLS_CUSTOM_STACK is not enabled, this function will return ESP_ERR_NOT_SUPPORTED.
|
||||
* @note All required function pointers in ops must be non-NULL. Optional functions can be NULL.
|
||||
* @note The ops structure pointer is stored by reference, not copied. The structure must remain
|
||||
* valid in memory for the entire duration of TLS operations (typically the lifetime of the
|
||||
* application). Use a static or global variable, not a stack-allocated or dynamically
|
||||
* allocated structure that may be freed. Using a `const` static structure allows the
|
||||
* compiler to place it in flash (.rodata), saving ~80 bytes of RAM.
|
||||
*
|
||||
* @param ops Pointer to TLS stack operations vtable containing your implementation.
|
||||
* Must point to a static/global structure (not on stack) as it's stored by reference.
|
||||
* Required fields:
|
||||
* - version (must be set to ESP_TLS_STACK_OPS_VERSION)
|
||||
* - create_ssl_handle
|
||||
* - handshake
|
||||
* - read
|
||||
* - write
|
||||
* - conn_delete
|
||||
* - net_init
|
||||
* - get_ssl_context
|
||||
* - get_bytes_avail
|
||||
* - init_global_ca_store
|
||||
* - set_global_ca_store
|
||||
* - get_global_ca_store
|
||||
* - free_global_ca_store
|
||||
* - get_ciphersuites_list
|
||||
* Optional functions (can be NULL if not supported):
|
||||
* - get_client_session (for CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS)
|
||||
* - free_client_session (for CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS)
|
||||
* - server_session_ticket_ctx_init (for CONFIG_ESP_TLS_SERVER_SESSION_TICKETS)
|
||||
* - server_session_ticket_ctx_free (for CONFIG_ESP_TLS_SERVER_SESSION_TICKETS)
|
||||
* - server_session_create (server-side, can be NULL if server_session_init is provided)
|
||||
* - server_session_init (server-side, can be NULL if server_session_create is provided)
|
||||
* - server_session_continue_async (server-side, can be NULL if server_session_create is provided)
|
||||
* - server_session_delete (server-side, can be NULL, conn_delete will be used)
|
||||
* @param user_ctx User context pointer that will be passed to all callbacks as the first parameter.
|
||||
* This allows C++ implementations to avoid singletons by passing instance pointers.
|
||||
* Can be NULL if not needed.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Stack registered successfully
|
||||
* - ESP_ERR_INVALID_ARG: ops is NULL or any required function pointer is NULL
|
||||
* - ESP_ERR_INVALID_VERSION: ops->version does not match ESP_TLS_STACK_OPS_VERSION
|
||||
* - ESP_ERR_INVALID_STATE: A stack is already registered
|
||||
* - ESP_ERR_NOT_SUPPORTED: CONFIG_ESP_TLS_CUSTOM_STACK is not enabled
|
||||
*
|
||||
* @code{.c}
|
||||
* // Example usage:
|
||||
* static const esp_tls_stack_ops_t my_tls_ops = {
|
||||
* .version = ESP_TLS_STACK_OPS_VERSION,
|
||||
* .create_ssl_handle = my_create_ssl_handle,
|
||||
* .handshake = my_handshake,
|
||||
* .read = my_read,
|
||||
* .write = my_write,
|
||||
* .conn_delete = my_conn_delete,
|
||||
* .net_init = my_net_init,
|
||||
* .get_ssl_context = my_get_ssl_context,
|
||||
* .get_bytes_avail = my_get_bytes_avail,
|
||||
* .init_global_ca_store = my_init_global_ca_store,
|
||||
* .set_global_ca_store = my_set_global_ca_store,
|
||||
* .get_global_ca_store = my_get_global_ca_store,
|
||||
* .free_global_ca_store = my_free_global_ca_store,
|
||||
* .get_ciphersuites_list = my_get_ciphersuites_list,
|
||||
* // Optional functions...
|
||||
* };
|
||||
*
|
||||
* void app_main(void) {
|
||||
* esp_err_t ret = esp_tls_register_stack(&my_tls_ops, NULL);
|
||||
* if (ret != ESP_OK) {
|
||||
* ESP_LOGE("APP", "Failed to register TLS stack: %s", esp_err_to_name(ret));
|
||||
* return;
|
||||
* }
|
||||
* // ... create TLS connections as usual ...
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
esp_err_t esp_tls_register_stack(const esp_tls_stack_ops_t *ops, void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Unregister the custom TLS stack implementation
|
||||
*
|
||||
* This function removes the registered TLS stack, allowing a new stack to be registered.
|
||||
* This is primarily useful for testing scenarios where you need to switch between
|
||||
* different TLS stack implementations.
|
||||
*
|
||||
* @note This function should NOT be called while any TLS connections are active.
|
||||
* Ensure all TLS connections are closed before calling this function.
|
||||
* @note If CONFIG_ESP_TLS_CUSTOM_STACK is not enabled, this function will return ESP_ERR_NOT_SUPPORTED.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Stack unregistered successfully
|
||||
* - ESP_ERR_INVALID_STATE: No stack was registered
|
||||
* - ESP_ERR_NOT_SUPPORTED: CONFIG_ESP_TLS_CUSTOM_STACK is not enabled
|
||||
*/
|
||||
esp_err_t esp_tls_unregister_stack(void);
|
||||
|
||||
/**
|
||||
* @brief Get the registered TLS stack operations
|
||||
*
|
||||
* @return Pointer to registered TLS stack operations, or NULL if no stack is registered
|
||||
* or CONFIG_ESP_TLS_CUSTOM_STACK is not enabled
|
||||
*/
|
||||
const esp_tls_stack_ops_t *esp_tls_get_registered_stack(void);
|
||||
|
||||
/**
|
||||
* @brief Internal wrapper functions that call through the registered stack's vtable
|
||||
*
|
||||
* These functions provide a uniform interface to the registered TLS stack implementation.
|
||||
* They forward calls to the appropriate function pointer in the registered esp_tls_stack_ops_t structure.
|
||||
*
|
||||
* @note These are internal functions used by ESP-TLS and should not be called directly by applications.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Create SSL handle for a TLS connection */
|
||||
esp_err_t esp_tls_custom_stack_create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls, void *server_params);
|
||||
|
||||
/** @brief Perform TLS handshake */
|
||||
int esp_tls_custom_stack_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg);
|
||||
|
||||
/** @brief Read data from TLS connection */
|
||||
ssize_t esp_tls_custom_stack_read(esp_tls_t *tls, char *data, size_t datalen);
|
||||
|
||||
/** @brief Write data to TLS connection */
|
||||
ssize_t esp_tls_custom_stack_write(esp_tls_t *tls, const char *data, size_t datalen);
|
||||
|
||||
/** @brief Delete TLS connection and free resources */
|
||||
void esp_tls_custom_stack_conn_delete(esp_tls_t *tls);
|
||||
|
||||
/** @brief Initialize network context for TLS connection */
|
||||
void esp_tls_custom_stack_net_init(esp_tls_t *tls);
|
||||
|
||||
/** @brief Get SSL context (stack-specific) */
|
||||
void *esp_tls_custom_stack_get_ssl_context(esp_tls_t *tls);
|
||||
|
||||
/** @brief Get number of bytes available for reading */
|
||||
ssize_t esp_tls_custom_stack_get_bytes_avail(esp_tls_t *tls);
|
||||
|
||||
/** @brief Initialize global CA certificate store */
|
||||
esp_err_t esp_tls_custom_stack_init_global_ca_store(void);
|
||||
|
||||
/** @brief Set global CA certificate store */
|
||||
esp_err_t esp_tls_custom_stack_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes);
|
||||
|
||||
/** @brief Get global CA certificate store (stack-specific) */
|
||||
void *esp_tls_custom_stack_get_global_ca_store(void);
|
||||
|
||||
/** @brief Free global CA certificate store */
|
||||
void esp_tls_custom_stack_free_global_ca_store(void);
|
||||
|
||||
/** @brief Get list of supported ciphersuites */
|
||||
const int *esp_tls_custom_stack_get_ciphersuites_list(void);
|
||||
|
||||
/** @brief Get client session ticket for reuse */
|
||||
void *esp_tls_custom_stack_get_client_session(esp_tls_t *tls);
|
||||
|
||||
/** @brief Free client session ticket */
|
||||
void esp_tls_custom_stack_free_client_session(void *client_session);
|
||||
|
||||
/** @brief Initialize server session ticket context */
|
||||
esp_err_t esp_tls_custom_stack_server_session_ticket_ctx_init(void *cfg);
|
||||
|
||||
/** @brief Free server session ticket context */
|
||||
void esp_tls_custom_stack_server_session_ticket_ctx_free(void *cfg);
|
||||
|
||||
/** @brief Create server session (blocking) */
|
||||
int esp_tls_custom_stack_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls);
|
||||
|
||||
/** @brief Initialize server session (non-blocking) */
|
||||
esp_err_t esp_tls_custom_stack_server_session_init(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls);
|
||||
|
||||
/** @brief Continue async server session handshake */
|
||||
int esp_tls_custom_stack_server_session_continue_async(esp_tls_t *tls);
|
||||
|
||||
/** @brief Delete server session */
|
||||
void esp_tls_custom_stack_server_session_delete(esp_tls_t *tls);
|
||||
|
||||
/** @brief Calculate SHA1 hash using registered stack's implementation */
|
||||
int esp_tls_custom_stack_crypto_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]);
|
||||
|
||||
/** @brief Base64 encode using registered stack's implementation */
|
||||
int esp_tls_custom_stack_crypto_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -22,10 +22,10 @@ void esp_tls_internal_event_tracker_capture(esp_tls_error_handle_t h, uint32_t t
|
||||
if (type == ESP_TLS_ERR_TYPE_ESP) {
|
||||
storage->parent.last_error = code;
|
||||
} else if (type == ESP_TLS_ERR_TYPE_MBEDTLS ||
|
||||
type == ESP_TLS_ERR_TYPE_WOLFSSL) {
|
||||
type == ESP_TLS_ERR_TYPE_CUSTOM_STACK) {
|
||||
storage->parent.esp_tls_error_code = code;
|
||||
} else if (type == ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS ||
|
||||
type == ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS) {
|
||||
type == ESP_TLS_ERR_TYPE_CUSTOM_STACK_CERT_FLAGS) {
|
||||
storage->parent.esp_tls_flags = code;
|
||||
} else if (type == ESP_TLS_ERR_TYPE_SYSTEM) {
|
||||
storage->sock_errno = code;
|
||||
@@ -58,11 +58,11 @@ esp_err_t esp_tls_get_and_clear_error_type(esp_tls_error_handle_t h, esp_tls_err
|
||||
*code = storage->parent.last_error;
|
||||
storage->parent.last_error = 0;
|
||||
} else if (type == ESP_TLS_ERR_TYPE_MBEDTLS ||
|
||||
type == ESP_TLS_ERR_TYPE_WOLFSSL) {
|
||||
type == ESP_TLS_ERR_TYPE_CUSTOM_STACK) {
|
||||
*code = storage->parent.esp_tls_error_code;
|
||||
storage->parent.esp_tls_error_code = 0;
|
||||
} else if (type == ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS ||
|
||||
type == ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS) {
|
||||
type == ESP_TLS_ERR_TYPE_CUSTOM_STACK_CERT_FLAGS) {
|
||||
*code = storage->parent.esp_tls_flags;
|
||||
storage->parent.esp_tls_flags = 0;
|
||||
} else if (type == ESP_TLS_ERR_TYPE_SYSTEM) {
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
#include "wolfssl/wolfcrypt/settings.h"
|
||||
#include "wolfssl/ssl.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -49,17 +46,6 @@ extern "C" {
|
||||
#define ESP_ERR_MBEDTLS_SSL_TICKET_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1C) /*!< mbedtls api returned failed */
|
||||
#define ESP_ERR_MBEDTLS_SSL_READ_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1D) /*!< mbedtls api returned failed */
|
||||
|
||||
/* wolfssl specific error codes */
|
||||
#define ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x31) /*!< wolfSSL api returned error */
|
||||
#define ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x32) /*!< wolfSSL api returned error */
|
||||
#define ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x33) /*!< wolfSSL api returned error */
|
||||
#define ESP_ERR_WOLFSSL_KEY_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x34) /*!< wolfSSL api returned error */
|
||||
#define ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x35) /*!< wolfSSL api returned failed */
|
||||
#define ESP_ERR_WOLFSSL_CTX_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x36) /*!< wolfSSL api returned failed */
|
||||
#define ESP_ERR_WOLFSSL_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x37) /*!< wolfSSL api returned failed */
|
||||
#define ESP_ERR_WOLFSSL_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x38) /*!< wolfSSL api returned failed */
|
||||
|
||||
|
||||
/**
|
||||
* Definition of errors reported from IO API (potentially non-blocking) in case of error:
|
||||
* - esp_tls_conn_read()
|
||||
@@ -69,11 +55,12 @@ extern "C" {
|
||||
#define ESP_TLS_ERR_SSL_WANT_READ MBEDTLS_ERR_SSL_WANT_READ
|
||||
#define ESP_TLS_ERR_SSL_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
#define ESP_TLS_ERR_SSL_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */
|
||||
#define ESP_TLS_ERR_SSL_WANT_READ -0x6900
|
||||
#define ESP_TLS_ERR_SSL_WANT_WRITE -0x6880
|
||||
#define ESP_TLS_ERR_SSL_TIMEOUT WOLFSSL_CBIO_ERR_TIMEOUT
|
||||
#endif /*CONFIG_ESP_TLS_USING_WOLFSSL */
|
||||
#elif CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
/* For custom stacks, use standard error codes that match mbedTLS conventions */
|
||||
#define ESP_TLS_ERR_SSL_WANT_READ -0x6900 /* SSL wants to read more data */
|
||||
#define ESP_TLS_ERR_SSL_WANT_WRITE -0x6880 /* SSL wants to write more data */
|
||||
#define ESP_TLS_ERR_SSL_TIMEOUT -0x6800 /* SSL operation timed out */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Definition of different types/sources of error codes reported
|
||||
@@ -81,13 +68,13 @@ extern "C" {
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_TLS_ERR_TYPE_UNKNOWN = 0,
|
||||
ESP_TLS_ERR_TYPE_SYSTEM, /*!< System error -- errno */
|
||||
ESP_TLS_ERR_TYPE_MBEDTLS, /*!< Error code from mbedTLS library */
|
||||
ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS, /*!< Certificate flags defined in mbedTLS */
|
||||
ESP_TLS_ERR_TYPE_ESP, /*!< ESP-IDF error type -- esp_err_t */
|
||||
ESP_TLS_ERR_TYPE_WOLFSSL, /*!< Error code from wolfSSL library */
|
||||
ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS, /*!< Certificate flags defined in wolfSSL */
|
||||
ESP_TLS_ERR_TYPE_MAX, /*!< Last err type -- invalid entry */
|
||||
ESP_TLS_ERR_TYPE_SYSTEM, /*!< System error -- errno */
|
||||
ESP_TLS_ERR_TYPE_MBEDTLS, /*!< Error code from mbedTLS library */
|
||||
ESP_TLS_ERR_TYPE_MBEDTLS_CERT_FLAGS, /*!< Certificate flags defined in mbedTLS */
|
||||
ESP_TLS_ERR_TYPE_ESP, /*!< ESP-IDF error type -- esp_err_t */
|
||||
ESP_TLS_ERR_TYPE_CUSTOM_STACK, /*!< Error code from custom TLS stack */
|
||||
ESP_TLS_ERR_TYPE_CUSTOM_STACK_CERT_FLAGS, /*!< Certificate flags from custom TLS stack */
|
||||
ESP_TLS_ERR_TYPE_MAX, /*!< Last err type -- invalid entry */
|
||||
} esp_tls_error_type_t;
|
||||
|
||||
typedef struct esp_tls_last_error* esp_tls_error_handle_t;
|
||||
|
||||
@@ -1,642 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <http_parser.h>
|
||||
#include "esp_tls_wolfssl.h"
|
||||
#include "esp_tls_error_capture_internal.h"
|
||||
#include <errno.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
static unsigned char *global_cacert = NULL;
|
||||
static unsigned int global_cacert_pem_bytes = 0;
|
||||
static const char *TAG = "esp-tls-wolfssl";
|
||||
|
||||
/* Prototypes for the static functions */
|
||||
static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls);
|
||||
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
#include "freertos/semphr.h"
|
||||
static SemaphoreHandle_t tls_conn_lock;
|
||||
static inline unsigned int esp_wolfssl_psk_client_cb(WOLFSSL* ssl, const char* hint, char* identity,
|
||||
unsigned int id_max_len, unsigned char* key,unsigned int key_max_len);
|
||||
static esp_err_t esp_wolfssl_set_cipher_list(WOLFSSL_CTX *ctx);
|
||||
#ifdef WOLFSSL_TLS13
|
||||
#define PSK_MAX_ID_LEN 128
|
||||
#else
|
||||
#define PSK_MAX_ID_LEN 64
|
||||
#endif
|
||||
#define PSK_MAX_KEY_LEN 64
|
||||
|
||||
static char psk_id_str[PSK_MAX_ID_LEN];
|
||||
static uint8_t psk_key_array[PSK_MAX_KEY_LEN];
|
||||
static uint8_t psk_key_max_len = 0;
|
||||
#endif /* CONFIG_ESP_TLS_PSK_VERIFICATION */
|
||||
|
||||
static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls);
|
||||
|
||||
|
||||
/* This function shall return the error message when appropriate log level has been set otherwise this function shall do nothing */
|
||||
static void wolfssl_print_error_msg(int error)
|
||||
{
|
||||
#if (CONFIG_LOG_DEFAULT_LEVEL_DEBUG || CONFIG_LOG_DEFAULT_LEVEL_VERBOSE)
|
||||
static char error_buf[100];
|
||||
ESP_LOGE(TAG, "(%d) : %s", error, ERR_error_string(error, error_buf));
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef enum x509_file_type {
|
||||
FILE_TYPE_CA_CERT = 0, /* CA certificate to authenticate entity at other end */
|
||||
FILE_TYPE_SELF_CERT, /* Self certificate of the entity */
|
||||
FILE_TYPE_SELF_KEY, /* Private key in the self cert-key pair */
|
||||
} x509_file_type_t;
|
||||
|
||||
/* Error type conversion utility so that esp-tls read/write API to return negative number on error */
|
||||
static inline ssize_t esp_tls_convert_wolfssl_err_to_ssize(int wolfssl_error)
|
||||
{
|
||||
switch (wolfssl_error) {
|
||||
case WOLFSSL_ERROR_WANT_READ:
|
||||
return ESP_TLS_ERR_SSL_WANT_READ;
|
||||
case WOLFSSL_ERROR_WANT_WRITE:
|
||||
return ESP_TLS_ERR_SSL_WANT_WRITE;
|
||||
default:
|
||||
// Make sure we return a negative number
|
||||
return wolfssl_error>0 ? -wolfssl_error: wolfssl_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks whether the certificate provided is in pem format or not */
|
||||
static esp_err_t esp_load_wolfssl_verify_buffer(esp_tls_t *tls, const unsigned char *cert_buf, unsigned int cert_len, x509_file_type_t type, int *err_ret)
|
||||
{
|
||||
int wolf_fileformat = WOLFSSL_FILETYPE_DEFAULT;
|
||||
if (type == FILE_TYPE_SELF_KEY) {
|
||||
if (cert_buf[cert_len - 1] == '\0' && strstr( (const char *) cert_buf, "-----BEGIN " )) {
|
||||
wolf_fileformat = WOLFSSL_FILETYPE_PEM;
|
||||
} else {
|
||||
wolf_fileformat = WOLFSSL_FILETYPE_ASN1;
|
||||
}
|
||||
if ((*err_ret = wolfSSL_CTX_use_PrivateKey_buffer( (WOLFSSL_CTX *)tls->priv_ctx, cert_buf, cert_len, wolf_fileformat)) == WOLFSSL_SUCCESS) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
if (cert_buf[cert_len - 1] == '\0' && strstr( (const char *) cert_buf, "-----BEGIN CERTIFICATE-----" )) {
|
||||
wolf_fileformat = WOLFSSL_FILETYPE_PEM;
|
||||
} else {
|
||||
wolf_fileformat = WOLFSSL_FILETYPE_ASN1;
|
||||
}
|
||||
if (type == FILE_TYPE_SELF_CERT) {
|
||||
if ((*err_ret = wolfSSL_CTX_use_certificate_chain_buffer_format( (WOLFSSL_CTX *)tls->priv_ctx, cert_buf, cert_len, wolf_fileformat)) == WOLFSSL_SUCCESS) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
} else if (type == FILE_TYPE_CA_CERT) {
|
||||
if ((*err_ret = wolfSSL_CTX_load_verify_buffer( (WOLFSSL_CTX *)tls->priv_ctx, cert_buf, cert_len, wolf_fileformat)) == WOLFSSL_SUCCESS) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
/* Wrong file type provided */
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *esp_wolfssl_get_ssl_context(esp_tls_t *tls)
|
||||
{
|
||||
if (tls == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid arguments");
|
||||
return NULL;
|
||||
}
|
||||
return (void*)tls->priv_ssl;
|
||||
}
|
||||
|
||||
esp_err_t esp_create_wolfssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls, void *server_params)
|
||||
{
|
||||
#ifdef CONFIG_ESP_DEBUG_WOLFSSL
|
||||
wolfSSL_Debugging_ON();
|
||||
#endif
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
int ret;
|
||||
|
||||
ret = wolfSSL_Init();
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Init wolfSSL failed: 0x%04X", ret);
|
||||
wolfssl_print_error_msg(ret);
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, err);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (tls->role == ESP_TLS_CLIENT) {
|
||||
esp_ret = set_client_config(hostname, hostlen, (esp_tls_cfg_t *)cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set client configurations, [0x%04X] (%s)", esp_ret, esp_err_to_name(esp_ret));
|
||||
goto exit;
|
||||
}
|
||||
} else if (tls->role == ESP_TLS_SERVER) {
|
||||
esp_ret = set_server_config((esp_tls_cfg_server_t *) cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set server configurations, [0x%04X] (%s)", esp_ret, esp_err_to_name(esp_ret));
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(TAG, "tls->role is not valid");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
exit:
|
||||
esp_wolfssl_cleanup(tls);
|
||||
return esp_ret;
|
||||
}
|
||||
|
||||
static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
int ret = WOLFSSL_FAILURE;
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
tls->priv_ctx = (void *)wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
#else
|
||||
tls->priv_ctx = (void *)wolfSSL_CTX_new(wolfTLSv1_2_client_method());
|
||||
#endif
|
||||
|
||||
if (!tls->priv_ctx) {
|
||||
ESP_LOGE(TAG, "Set wolfSSL ctx failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, ret);
|
||||
return ESP_ERR_WOLFSSL_CTX_SETUP_FAILED;
|
||||
}
|
||||
|
||||
if (cfg->crt_bundle_attach != NULL) {
|
||||
ESP_LOGE(TAG,"use_crt_bundle not supported in wolfssl");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (cfg->use_global_ca_store == true) {
|
||||
if ((esp_load_wolfssl_verify_buffer(tls, global_cacert, global_cacert_pem_bytes, FILE_TYPE_CA_CERT, &ret)) != ESP_OK) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "Error in loading certificate verify buffer, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED;
|
||||
}
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, WOLFSSL_VERIFY_PEER, NULL);
|
||||
} else if (cfg->cacert_buf != NULL) {
|
||||
if ((esp_load_wolfssl_verify_buffer(tls, cfg->cacert_buf, cfg->cacert_bytes, FILE_TYPE_CA_CERT, &ret)) != ESP_OK) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "Error in loading certificate verify buffer, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED;
|
||||
}
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, WOLFSSL_VERIFY_PEER, NULL);
|
||||
} else if (cfg->psk_hint_key) {
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
/*** PSK encryption mode is configured only if no certificate supplied and psk pointer not null ***/
|
||||
if(cfg->psk_hint_key->key == NULL || cfg->psk_hint_key->hint == NULL || cfg->psk_hint_key->key_size <= 0) {
|
||||
ESP_LOGE(TAG, "Please provide appropriate key, keysize and hint to use PSK");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* mutex is given back when call back function executes or in case of failure (at cleanup) */
|
||||
if ((xSemaphoreTake(tls_conn_lock, 1000/portTICK_PERIOD_MS) != pdTRUE)) {
|
||||
ESP_LOGE(TAG, "tls_conn_lock could not be obtained in specified time");
|
||||
return -1;
|
||||
}
|
||||
ESP_LOGI(TAG, "setting psk configurations");
|
||||
if((cfg->psk_hint_key->key_size > PSK_MAX_KEY_LEN) || (strlen(cfg->psk_hint_key->hint) > PSK_MAX_ID_LEN)) {
|
||||
ESP_LOGE(TAG, "psk key length should be <= %d and identity hint length should be <= %d", PSK_MAX_KEY_LEN, PSK_MAX_ID_LEN);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
psk_key_max_len = cfg->psk_hint_key->key_size;
|
||||
memset(psk_key_array, 0, sizeof(psk_key_array));
|
||||
memset(psk_id_str, 0, sizeof(psk_id_str));
|
||||
memcpy(psk_key_array, cfg->psk_hint_key->key, psk_key_max_len);
|
||||
memcpy(psk_id_str, cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint));
|
||||
wolfSSL_CTX_set_psk_client_callback( (WOLFSSL_CTX *)tls->priv_ctx, esp_wolfssl_psk_client_cb);
|
||||
if(esp_wolfssl_set_cipher_list( (WOLFSSL_CTX *)tls->priv_ctx) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "error in setting cipher-list");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, WOLFSSL_VERIFY_NONE, NULL);
|
||||
#else
|
||||
ESP_LOGE(TAG, "No server verification option set in esp_tls_cfg_t structure. Check esp_tls API reference");
|
||||
return ESP_ERR_WOLFSSL_SSL_SETUP_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cfg->clientcert_buf != NULL && cfg->clientkey_buf != NULL) {
|
||||
if ((esp_load_wolfssl_verify_buffer(tls,cfg->clientcert_buf, cfg->clientcert_bytes, FILE_TYPE_SELF_CERT, &ret)) != ESP_OK) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "Error in loading certificate verify buffer, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED;
|
||||
}
|
||||
if ((esp_load_wolfssl_verify_buffer(tls,cfg->clientkey_buf, cfg->clientkey_bytes, FILE_TYPE_SELF_KEY, &ret)) != ESP_OK) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "Error in loading private key verify buffer, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED;
|
||||
}
|
||||
} else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) {
|
||||
ESP_LOGE(TAG, "You have to provide both clientcert_buf and clientkey_buf for mutual authentication");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
tls->priv_ssl =(void *)wolfSSL_new( (WOLFSSL_CTX *)tls->priv_ctx);
|
||||
if (!tls->priv_ssl) {
|
||||
ESP_LOGE(TAG, "Create wolfSSL failed");
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, err);
|
||||
return ESP_ERR_WOLFSSL_SSL_SETUP_FAILED;
|
||||
}
|
||||
|
||||
if (!cfg->skip_common_name) {
|
||||
char *use_host = NULL;
|
||||
if (cfg->common_name != NULL) {
|
||||
use_host = strdup(cfg->common_name);
|
||||
} else {
|
||||
use_host = strndup(hostname, hostlen);
|
||||
}
|
||||
if (use_host == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
/* Hostname set here should match CN in server certificate */
|
||||
if ((ret = (wolfSSL_check_domain_name( (WOLFSSL *)tls->priv_ssl, use_host))) != WOLFSSL_SUCCESS) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "wolfSSL_check_domain_name returned %d, error code: %d", ret, err);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, err);
|
||||
free(use_host);
|
||||
return ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED;
|
||||
}
|
||||
/* Mimic the semantics of mbedtls_ssl_set_hostname() */
|
||||
if ((ret = wolfSSL_CTX_UseSNI(tls->priv_ctx, WOLFSSL_SNI_HOST_NAME, use_host, strlen(use_host))) != WOLFSSL_SUCCESS) {
|
||||
ESP_LOGE(TAG, "wolfSSL_CTX_UseSNI failed, returned %d", ret);
|
||||
return ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED;
|
||||
}
|
||||
free(use_host);
|
||||
}
|
||||
|
||||
if (cfg->alpn_protos) {
|
||||
#ifdef CONFIG_WOLFSSL_HAVE_ALPN
|
||||
char **alpn_list = (char **)cfg->alpn_protos;
|
||||
for (; *alpn_list != NULL; alpn_list ++) {
|
||||
ESP_LOGD(TAG, "alpn protocol is %s", *alpn_list);
|
||||
if ((ret = wolfSSL_UseALPN( (WOLFSSL *)tls->priv_ssl, *alpn_list, strlen(*alpn_list), WOLFSSL_ALPN_FAILED_ON_MISMATCH)) != WOLFSSL_SUCCESS) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, err);
|
||||
ESP_LOGE(TAG, "wolfSSL UseALPN failed, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED;
|
||||
}
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "CONFIG_WOLFSSL_HAVE_ALPN not enabled in menuconfig");
|
||||
return ESP_FAIL;
|
||||
#endif /* CONFIG_WOLFSSL_HAVE_ALPN */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WOLFSSL_HAVE_OCSP
|
||||
int ocsp_options = 0;
|
||||
#ifdef ESP_TLS_OCSP_CHECKALL
|
||||
ocsp_options |= WOLFSSL_OCSP_CHECKALL;
|
||||
#endif
|
||||
/* enable OCSP certificate status check for this TLS context */
|
||||
if ((ret = wolfSSL_CTX_EnableOCSP((WOLFSSL_CTX *)tls->priv_ctx, ocsp_options)) != WOLFSSL_SUCCESS) {
|
||||
ESP_LOGE(TAG, "wolfSSL_CTX_EnableOCSP failed, returned %d", ret);
|
||||
return ESP_ERR_WOLFSSL_CTX_SETUP_FAILED;
|
||||
}
|
||||
/* enable OCSP stapling for this TLS context */
|
||||
if ((ret = wolfSSL_CTX_EnableOCSPStapling((WOLFSSL_CTX *)tls->priv_ctx )) != WOLFSSL_SUCCESS) {
|
||||
ESP_LOGE(TAG, "wolfSSL_CTX_EnableOCSPStapling failed, returned %d", ret);
|
||||
return ESP_ERR_WOLFSSL_CTX_SETUP_FAILED;
|
||||
}
|
||||
/* set option to use OCSP v1 stapling with nounce extension */
|
||||
if ((ret = wolfSSL_UseOCSPStapling((WOLFSSL *)tls->priv_ssl, WOLFSSL_CSR_OCSP, WOLFSSL_CSR_OCSP_USE_NONCE)) != WOLFSSL_SUCCESS) {
|
||||
ESP_LOGE(TAG, "wolfSSL_UseOCSPStapling failed, returned %d", ret);
|
||||
return ESP_ERR_WOLFSSL_SSL_SETUP_FAILED;
|
||||
}
|
||||
#endif /* CONFIG_WOLFSSL_HAVE_OCSP */
|
||||
|
||||
wolfSSL_set_fd((WOLFSSL *)tls->priv_ssl, tls->sockfd);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
int ret = WOLFSSL_FAILURE;
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
tls->priv_ctx = (void *)wolfSSL_CTX_new(wolfTLSv1_3_server_method());
|
||||
#else
|
||||
tls->priv_ctx = (void *)wolfSSL_CTX_new(wolfTLSv1_2_server_method());
|
||||
#endif
|
||||
|
||||
if (!tls->priv_ctx) {
|
||||
ESP_LOGE(TAG, "Set wolfSSL ctx failed");
|
||||
return ESP_ERR_WOLFSSL_CTX_SETUP_FAILED;
|
||||
}
|
||||
|
||||
if (cfg->cacert_buf != NULL) {
|
||||
if ((esp_load_wolfssl_verify_buffer(tls,cfg->cacert_buf, cfg->cacert_bytes, FILE_TYPE_CA_CERT, &ret)) != ESP_OK) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "Error in loading certificate verify buffer, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED;
|
||||
}
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
|
||||
ESP_LOGD(TAG," Verify Client for Mutual Auth");
|
||||
} else {
|
||||
ESP_LOGD(TAG," Not verifying Client ");
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, WOLFSSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
|
||||
if (cfg->servercert_buf != NULL && cfg->serverkey_buf != NULL) {
|
||||
if ((esp_load_wolfssl_verify_buffer(tls,cfg->servercert_buf, cfg->servercert_bytes, FILE_TYPE_SELF_CERT, &ret)) != ESP_OK) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "Error in loading certificate verify buffer, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED;
|
||||
}
|
||||
if ((esp_load_wolfssl_verify_buffer(tls,cfg->serverkey_buf, cfg->serverkey_bytes, FILE_TYPE_SELF_KEY, &ret)) != ESP_OK) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "Error in loading private key verify buffer, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "You have to provide both servercert_buf and serverkey_buf for https_server");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
tls->priv_ssl =(void *)wolfSSL_new( (WOLFSSL_CTX *)tls->priv_ctx);
|
||||
if (!tls->priv_ssl) {
|
||||
ESP_LOGE(TAG, "Create wolfSSL failed");
|
||||
return ESP_ERR_WOLFSSL_SSL_SETUP_FAILED;
|
||||
}
|
||||
|
||||
wolfSSL_set_fd((WOLFSSL *)tls->priv_ssl, tls->sockfd);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int esp_wolfssl_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
ret = wolfSSL_connect( (WOLFSSL *)tls->priv_ssl);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
tls->conn_state = ESP_TLS_DONE;
|
||||
return 1;
|
||||
} else {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "wolfSSL_connect returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, err);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED);
|
||||
if (cfg->crt_bundle_attach != NULL || cfg->cacert_buf != NULL || cfg->use_global_ca_store == true) {
|
||||
/* This is to check whether handshake failed due to invalid certificate*/
|
||||
esp_wolfssl_verify_certificate(tls);
|
||||
}
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
/* Irrespective of blocking or non-blocking I/O, we return on getting wolfSSL_want_read
|
||||
or wolfSSL_want_write during handshake */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t esp_wolfssl_read(esp_tls_t *tls, char *data, size_t datalen)
|
||||
{
|
||||
ssize_t ret = wolfSSL_read( (WOLFSSL *)tls->priv_ssl, (unsigned char *)data, datalen);
|
||||
if (ret < 0) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
/* peer sent close notify */
|
||||
if (err == WOLFSSL_ERROR_ZERO_RETURN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, -ret);
|
||||
ESP_LOGE(TAG, "read error :%d:", ret);
|
||||
wolfssl_print_error_msg(ret);
|
||||
}
|
||||
return esp_tls_convert_wolfssl_err_to_ssize(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t esp_wolfssl_write(esp_tls_t *tls, const char *data, size_t datalen)
|
||||
{
|
||||
ssize_t ret = wolfSSL_write( (WOLFSSL *)tls->priv_ssl, (unsigned char *) data, datalen);
|
||||
if (ret <= 0) {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, -err);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, ESP_ERR_WOLFSSL_SSL_WRITE_FAILED);
|
||||
ESP_LOGE(TAG, "write error :%d:", err);
|
||||
wolfssl_print_error_msg(err);
|
||||
}
|
||||
return esp_tls_convert_wolfssl_err_to_ssize(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void esp_wolfssl_verify_certificate(esp_tls_t *tls)
|
||||
{
|
||||
int flags;
|
||||
if ((flags = wolfSSL_get_verify_result( (WOLFSSL *)tls->priv_ssl)) != X509_V_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify peer certificate , returned %d", flags);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL_CERT_FLAGS, flags);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Certificate verified.");
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t esp_wolfssl_get_bytes_avail(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
ESP_LOGE(TAG, "empty arg passed to esp_tls_get_bytes_avail()");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return wolfSSL_pending( (WOLFSSL *)tls->priv_ssl);
|
||||
}
|
||||
|
||||
void esp_wolfssl_conn_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
esp_wolfssl_cleanup(tls);
|
||||
}
|
||||
}
|
||||
|
||||
void esp_wolfssl_cleanup(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_ESP_TLS_PSK_VERIFICATION
|
||||
xSemaphoreGive(tls_conn_lock);
|
||||
#endif /* CONFIG_ESP_TLS_PSK_VERIFICATION */
|
||||
wolfSSL_shutdown( (WOLFSSL *)tls->priv_ssl);
|
||||
wolfSSL_free( (WOLFSSL *)tls->priv_ssl);
|
||||
tls->priv_ssl = NULL;
|
||||
wolfSSL_CTX_free( (WOLFSSL_CTX *)tls->priv_ctx);
|
||||
tls->priv_ctx = NULL;
|
||||
wolfSSL_Cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create TLS/SSL server session
|
||||
*/
|
||||
int esp_wolfssl_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls)
|
||||
{
|
||||
if (tls == NULL || cfg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
tls->role = ESP_TLS_SERVER;
|
||||
tls->sockfd = sockfd;
|
||||
esp_tls_server_params_t server_params = {};
|
||||
server_params.set_server_cfg = &set_server_config;
|
||||
esp_err_t esp_ret = esp_create_wolfssl_handle(NULL, 0, cfg, tls, &server_params);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create_ssl_handle failed, [0x%04X] (%s)", esp_ret, esp_err_to_name(esp_ret));
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, esp_ret);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
tls->read = esp_wolfssl_read;
|
||||
tls->write = esp_wolfssl_write;
|
||||
int ret;
|
||||
while ((ret = wolfSSL_accept((WOLFSSL *)tls->priv_ssl)) != WOLFSSL_SUCCESS) {
|
||||
int err = wolfSSL_get_error((WOLFSSL *)tls->priv_ssl, ret);
|
||||
if (err != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_WOLFSSL, err);
|
||||
ESP_LOGE(TAG, "wolfSSL_accept returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close the server side TLS/SSL connection and free any allocated resources.
|
||||
*/
|
||||
void esp_wolfssl_server_session_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
esp_wolfssl_cleanup(tls);
|
||||
esp_tls_internal_event_tracker_destroy(tls->error_handle);
|
||||
free(tls);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_wolfssl_init_global_ca_store(void)
|
||||
{
|
||||
/* This function is just to provide consistency between function calls of esp_tls.h and wolfssl */
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_wolfssl_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
|
||||
{
|
||||
if (cacert_pem_buf == NULL) {
|
||||
ESP_LOGE(TAG, "cacert_pem_buf is null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (global_cacert != NULL) {
|
||||
esp_wolfssl_free_global_ca_store();
|
||||
}
|
||||
|
||||
global_cacert = (unsigned char *)strndup((const char *)cacert_pem_buf, cacert_pem_bytes);
|
||||
if (!global_cacert) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
global_cacert_pem_bytes = cacert_pem_bytes;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wolfssl_free_global_ca_store(void)
|
||||
{
|
||||
if (global_cacert) {
|
||||
free(global_cacert);
|
||||
global_cacert = NULL;
|
||||
global_cacert_pem_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
static esp_err_t esp_wolfssl_set_cipher_list(WOLFSSL_CTX *ctx)
|
||||
{
|
||||
const char *defaultCipherList;
|
||||
int ret;
|
||||
#if defined(HAVE_AESGCM) && !defined(NO_DH)
|
||||
#ifdef WOLFSSL_TLS13
|
||||
defaultCipherList = "DHE-PSK-AES128-GCM-SHA256:"
|
||||
"TLS13-AES128-GCM-SHA256";
|
||||
#else
|
||||
defaultCipherList = "DHE-PSK-AES128-GCM-SHA256";
|
||||
#endif
|
||||
#elif defined(HAVE_NULL_CIPHER)
|
||||
defaultCipherList = "PSK-NULL-SHA256";
|
||||
#else
|
||||
defaultCipherList = "PSK-AES128-CBC-SHA256";
|
||||
#endif
|
||||
ESP_LOGD(TAG, "cipher list is %s", defaultCipherList);
|
||||
if ((ret = wolfSSL_CTX_set_cipher_list(ctx,defaultCipherList)) != WOLFSSL_SUCCESS) {
|
||||
wolfSSL_CTX_free(ctx);
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
ESP_LOGE(TAG, "can't set cipher list, returned %d, error code: %d", ret, err);
|
||||
wolfssl_print_error_msg(err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* initialize the mutex before app_main() when using PSK */
|
||||
static void __attribute__((constructor))
|
||||
espt_tls_wolfssl_init_conn_lock (void)
|
||||
{
|
||||
if ((tls_conn_lock = xSemaphoreCreateMutex()) == NULL) {
|
||||
ESP_EARLY_LOGE(TAG, "mutex for tls psk connection could not be created");
|
||||
}
|
||||
}
|
||||
|
||||
/* Some callback functions required by PSK */
|
||||
static inline unsigned int esp_wolfssl_psk_client_cb(WOLFSSL* ssl, const char* hint,
|
||||
char* identity, unsigned int id_max_len, unsigned char* key,
|
||||
unsigned int key_max_len)
|
||||
{
|
||||
(void)key_max_len;
|
||||
|
||||
/* see internal.h MAX_PSK_ID_LEN for PSK identity limit */
|
||||
memcpy(identity, psk_id_str, id_max_len);
|
||||
for(int count = 0; count < psk_key_max_len; count ++) {
|
||||
key[count] = psk_key_array[count];
|
||||
}
|
||||
xSemaphoreGive(tls_conn_lock);
|
||||
return psk_key_max_len;
|
||||
/* return length of key in octets or 0 or for error */
|
||||
}
|
||||
#endif /* CONFIG_ESP_TLS_PSK_VERIFICATION */
|
||||
@@ -27,9 +27,6 @@
|
||||
#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
|
||||
#include "psa/crypto.h"
|
||||
#endif
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
#include "wolfssl/wolfcrypt/settings.h"
|
||||
#include "wolfssl/ssl.h"
|
||||
#endif
|
||||
|
||||
struct esp_tls {
|
||||
@@ -65,9 +62,9 @@ struct esp_tls {
|
||||
unsigned char *client_session; /*!< Pointer for the serialized client session ticket context. */
|
||||
size_t client_session_len; /*!< Length of the serialized client session ticket context. */
|
||||
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 && CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS */
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
void *priv_ctx;
|
||||
void *priv_ssl;
|
||||
#elif CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
void *priv_ctx; /*!< Private context for custom TLS stack (e.g., SSL_CTX*) */
|
||||
void *priv_ssl; /*!< Private SSL handle for custom TLS stack (e.g., SSL*) */
|
||||
#endif
|
||||
int sockfd; /*!< Underlying socket file descriptor. */
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "esp_tls.h"
|
||||
#include "esp_tls_private.h"
|
||||
|
||||
/**
|
||||
* Internal Callback for creating ssl handle for wolfssl
|
||||
*/
|
||||
int esp_create_wolfssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls, void *server_params);
|
||||
|
||||
/**
|
||||
* Internal Callback for wolfssl_handshake
|
||||
*/
|
||||
int esp_wolfssl_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg);
|
||||
|
||||
/**
|
||||
* Internal Callback API for wolfssl_ssl_read
|
||||
*/
|
||||
ssize_t esp_wolfssl_read(esp_tls_t *tls, char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* Internal callback API for wolfssl_ssl_write
|
||||
*/
|
||||
ssize_t esp_wolfssl_write(esp_tls_t *tls, const char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* Internal Callback for wolfssl_cleanup , frees up all the memory used by wolfssl
|
||||
*/
|
||||
void esp_wolfssl_cleanup(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for Certificate verification for wolfssl
|
||||
*/
|
||||
void esp_wolfssl_verify_certificate(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for deleting the wolfssl connection
|
||||
*/
|
||||
void esp_wolfssl_conn_delete(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for wolfssl_get_bytes_avail
|
||||
*/
|
||||
ssize_t esp_wolfssl_get_bytes_avail(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Callback function for setting global CA store data for TLS/SSL using wolfssl
|
||||
*/
|
||||
esp_err_t esp_wolfssl_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes);
|
||||
|
||||
/**
|
||||
* Callback function for freeing global ca store for TLS/SSL using wolfssl
|
||||
*/
|
||||
void esp_wolfssl_free_global_ca_store(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* Callback function for Initializing the global ca store for TLS?SSL using wolfssl
|
||||
*/
|
||||
esp_err_t esp_wolfssl_init_global_ca_store(void);
|
||||
|
||||
/**
|
||||
* Return ssl context for wolfSSL stack
|
||||
*/
|
||||
void *esp_wolfssl_get_ssl_context(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* wolfSSL function for Initializing socket wrappers (no-operation for wolfSSL)
|
||||
*/
|
||||
static inline void esp_wolfssl_net_init(esp_tls_t *tls)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to Create ESP-TLS Server session with wolfssl Stack
|
||||
*/
|
||||
int esp_wolfssl_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls);
|
||||
|
||||
/*
|
||||
* Delete Server Session
|
||||
*/
|
||||
void esp_wolfssl_server_session_delete(esp_tls_t *tls);
|
||||
@@ -1,11 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "memory_checks.h"
|
||||
#include "esp_tls.h"
|
||||
#include "esp_tls_custom_stack.h"
|
||||
#include "unity.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
@@ -59,6 +60,7 @@ const char *test_key_pem = "-----BEGIN PRIVATE KEY-----\n"\
|
||||
"Aogx44Fozd1t2hYcozPuZD4s\n"\
|
||||
"-----END PRIVATE KEY-----\n";
|
||||
|
||||
#if CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
TEST_CASE("esp-tls init deinit", "[esp-tls]")
|
||||
{
|
||||
struct esp_tls *tls = esp_tls_init();
|
||||
@@ -94,3 +96,65 @@ TEST_CASE("esp_tls_server session create delete", "[esp-tls]")
|
||||
esp_tls_server_session_delete(tls);
|
||||
|
||||
}
|
||||
#endif /* CONFIG_ESP_TLS_USING_MBEDTLS */
|
||||
|
||||
#if CONFIG_ESP_TLS_CUSTOM_STACK
|
||||
/* Stub functions for testing custom stack registration */
|
||||
static esp_err_t stub_create_ssl_handle(void *user_ctx, const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls, void *server_params) { return ESP_OK; }
|
||||
static int stub_handshake(void *user_ctx, esp_tls_t *tls, const esp_tls_cfg_t *cfg) { return 1; }
|
||||
static ssize_t stub_read(void *user_ctx, esp_tls_t *tls, char *data, size_t datalen) { return 0; }
|
||||
static ssize_t stub_write(void *user_ctx, esp_tls_t *tls, const char *data, size_t datalen) { return (ssize_t)datalen; }
|
||||
static void stub_conn_delete(void *user_ctx, esp_tls_t *tls) { }
|
||||
static void stub_net_init(void *user_ctx, esp_tls_t *tls) { }
|
||||
static void *stub_get_ssl_context(void *user_ctx, esp_tls_t *tls) { return NULL; }
|
||||
static ssize_t stub_get_bytes_avail(void *user_ctx, esp_tls_t *tls) { return 0; }
|
||||
static esp_err_t stub_init_global_ca_store(void *user_ctx) { return ESP_OK; }
|
||||
static esp_err_t stub_set_global_ca_store(void *user_ctx, const unsigned char *buf, const unsigned int len) { return ESP_OK; }
|
||||
static void *stub_get_global_ca_store(void *user_ctx) { return NULL; }
|
||||
static void stub_free_global_ca_store(void *user_ctx) { }
|
||||
static const int stub_ciphersuites[] = { 0 };
|
||||
static const int *stub_get_ciphersuites_list(void *user_ctx) { return stub_ciphersuites; }
|
||||
|
||||
static const esp_tls_stack_ops_t s_stub_ops = {
|
||||
.create_ssl_handle = stub_create_ssl_handle,
|
||||
.handshake = stub_handshake,
|
||||
.read = stub_read,
|
||||
.write = stub_write,
|
||||
.conn_delete = stub_conn_delete,
|
||||
.net_init = stub_net_init,
|
||||
.get_ssl_context = stub_get_ssl_context,
|
||||
.get_bytes_avail = stub_get_bytes_avail,
|
||||
.init_global_ca_store = stub_init_global_ca_store,
|
||||
.set_global_ca_store = stub_set_global_ca_store,
|
||||
.get_global_ca_store = stub_get_global_ca_store,
|
||||
.free_global_ca_store = stub_free_global_ca_store,
|
||||
.get_ciphersuites_list = stub_get_ciphersuites_list,
|
||||
};
|
||||
|
||||
TEST_CASE("esp_tls custom stack registration", "[esp-tls][custom-stack]")
|
||||
{
|
||||
/* Test: registration with NULL should fail */
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_tls_register_stack(NULL, NULL));
|
||||
|
||||
/* Test: no stack registered initially */
|
||||
TEST_ASSERT_NULL(esp_tls_get_registered_stack());
|
||||
|
||||
/* Test: unregister when none registered should fail */
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_tls_unregister_stack());
|
||||
|
||||
/* Test: registration with valid ops should succeed */
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_tls_register_stack(&s_stub_ops, NULL));
|
||||
|
||||
/* Test: get registered stack should return the ops */
|
||||
TEST_ASSERT_EQUAL_PTR(&s_stub_ops, esp_tls_get_registered_stack());
|
||||
|
||||
/* Test: double registration should fail */
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_tls_register_stack(&s_stub_ops, NULL));
|
||||
|
||||
/* Test: unregister should succeed */
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_tls_unregister_stack());
|
||||
|
||||
/* Test: after unregister, no stack should be registered */
|
||||
TEST_ASSERT_NULL(esp_tls_get_registered_stack());
|
||||
}
|
||||
#endif /* CONFIG_ESP_TLS_CUSTOM_STACK */
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Test configuration for custom TLS stack registration feature
|
||||
CONFIG_ESP_TLS_CUSTOM_STACK=y
|
||||
Reference in New Issue
Block a user