chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:04:25 +08:00
commit 548b49ebc0
20937 changed files with 5455372 additions and 0 deletions
@@ -0,0 +1,7 @@
set(src "src/https_server.c")
set(inc "include")
idf_component_register(SRCS ${src}
INCLUDE_DIRS ${inc}
REQUIRES esp_http_server esp-tls esp_event
PRIV_REQUIRES lwip)
+35
View File
@@ -0,0 +1,35 @@
menu "ESP HTTPS server"
config ESP_HTTPS_SERVER_ENABLE
bool "Enable ESP_HTTPS_SERVER component"
depends on (ESP_TLS_USING_MBEDTLS && MBEDTLS_TLS_SERVER)
help
Enable ESP HTTPS server component
config ESP_HTTPS_SERVER_EVENTS
bool "Enable ESP_HTTPS_SERVER_EVENT event type"
depends on ESP_HTTPS_SERVER_ENABLE
default y
help
This enables the ESP_HTTPS_SERVER_EVENT event type. Generating these eventes adds some overhead.
If you are not using this event type, you can disable it to save some memory.
config ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT
int "Time in millisecond to wait for posting event"
depends on (ESP_HTTPS_SERVER_ENABLE && ESP_HTTPS_SERVER_EVENTS)
default 2000
help
This config option helps in setting the time in millisecond to wait for event to be posted to the
system default event loop. Set it to -1 if you need to set timeout to portMAX_DELAY.
config ESP_HTTPS_SERVER_CERT_SELECT_HOOK
select ESP_TLS_SERVER_CERT_SELECT_HOOK
bool "Enable certificate selection hook"
default n
help
Enable certificate selection hook for ESP HTTPS Server. When enabled, this allows the server to
dynamically select the appropriate certificate based on the client's Server Name Indication (SNI).
This is useful for hosting multiple domains on a single server with different SSL certificates.
endmenu
@@ -0,0 +1,265 @@
/*
* SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_HTTPS_SERVER_H_
#define _ESP_HTTPS_SERVER_H_
#include <stdbool.h>
#include "esp_err.h"
#include "esp_http_server.h"
#include "esp_tls.h"
#include "esp_event.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_ESP_HTTPS_SERVER_EVENTS || __DOXYGEN__
ESP_EVENT_DECLARE_BASE(ESP_HTTPS_SERVER_EVENT);
#endif // CONFIG_ESP_HTTPS_SERVER_EVENTS || __DOXYGEN__
typedef enum {
HTTPS_SERVER_EVENT_ERROR = 0, /*!< This event occurs when there are any errors during execution */
HTTPS_SERVER_EVENT_START, /*!< This event occurs when HTTPS Server is started */
HTTPS_SERVER_EVENT_ON_CONNECTED, /*!< Once the HTTPS Server has been connected to the client */
HTTPS_SERVER_EVENT_ON_DATA, /*!< Occurs when receiving data from the client */
HTTPS_SERVER_EVENT_SENT_DATA, /*!< Occurs when an ESP HTTPS server sends data to the client */
HTTPS_SERVER_EVENT_DISCONNECTED, /*!< The connection has been disconnected */
HTTPS_SERVER_EVENT_STOP, /*!< This event occurs when HTTPS Server is stopped */
} esp_https_server_event_id_t;
typedef enum {
HTTPD_SSL_TRANSPORT_SECURE, // SSL Enabled
HTTPD_SSL_TRANSPORT_INSECURE // SSL disabled
} httpd_ssl_transport_mode_t;
/**
* @brief Indicates the state at which the user callback is executed,
* i.e at session creation, session close, or session error
*/
typedef enum {
HTTPD_SSL_USER_CB_SESS_CREATE,
HTTPD_SSL_USER_CB_SESS_CLOSE,
HTTPD_SSL_USER_CB_SESS_ERROR
} httpd_ssl_user_cb_state_t;
typedef esp_tls_handshake_callback esp_https_server_cert_select_cb;
/**
* @brief Callback data struct, contains the ESP-TLS connection handle
* and the connection state at which the callback is executed
*/
typedef struct esp_https_server_user_cb_arg {
httpd_ssl_user_cb_state_t user_cb_state; /*!< State of user callback */
esp_tls_t *tls; /*!< ESP-TLS connection handle */
} esp_https_server_user_cb_arg_t;
typedef esp_tls_last_error_t esp_https_server_last_error_t;
/**
* @brief Callback function prototype
* Can be used to get connection or client information (SSL context)
* E.g. Client certificate, Socket FD, Connection state, etc.
*
* @param user_cb Callback data struct
*/
typedef void esp_https_server_user_cb(esp_https_server_user_cb_arg_t *user_cb);
/**
* HTTPS server config struct
*
* Please use HTTPD_SSL_CONFIG_DEFAULT() to initialize it.
*/
struct httpd_ssl_config {
/**
* Underlying HTTPD server config
*
* Parameters like task stack size and priority can be adjusted here.
*/
httpd_config_t httpd;
/** Server certificate */
const uint8_t *servercert;
/** Server certificate byte length */
size_t servercert_len;
/** CA certificate ((CA used to sign clients, or client cert itself) */
const uint8_t *cacert_pem;
/** CA certificate byte length */
size_t cacert_len;
#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
/** Client certificate authentication mode */
bool client_cert_authmode_optional;
#endif // CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
/** Private key */
const uint8_t *prvtkey_pem;
/** Private key byte length */
size_t prvtkey_len;
/** Unified key config. Takes precedence over prvtkey_pem when set */
const esp_key_config_t *server_key;
/** Use ECDSA peripheral to use private key */
bool use_ecdsa_peripheral;
/** The efuse block where ECDSA key is stored. For SECP384R1 curve, if two blocks are used, set this to the low block and use ecdsa_key_efuse_blk_high for the high block. */
uint8_t ecdsa_key_efuse_blk;
/** The high efuse block for ECDSA key (used only for SECP384R1 curve). If not set (0), only ecdsa_key_efuse_blk is used. */
uint8_t ecdsa_key_efuse_blk_high;
/** ECDSA curve to use (SECP256R1 or SECP384R1) */
esp_tls_ecdsa_curve_t ecdsa_curve;
/** Transport Mode (default secure) */
httpd_ssl_transport_mode_t transport_mode;
/** Port used when transport mode is secure (default 443) */
uint16_t port_secure;
/** Port used when transport mode is insecure (default 80) */
uint16_t port_insecure;
/** Enable tls session tickets */
bool session_tickets;
/** User callback for esp_https_server */
esp_https_server_user_cb *user_cb;
/** User data to add to the ssl context */
void *ssl_userdata;
/** Certificate selection callback to use.
* The callback is only applicable when CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK is enabled in menuconfig */
esp_https_server_cert_select_cb cert_select_cb;
/** Application protocols the server supports in order of preference.
* Used for negotiating during the TLS handshake, first one the client supports is selected.
* The data structure must live as long as the https server itself */
const char** alpn_protos;
/** TLS handshake timeout in milliseconds, default timeout is 10 seconds if not set */
uint32_t tls_handshake_timeout_ms;
/** TLS protocol version for this server, e.g., TLS 1.2, TLS 1.3
* (default - no preference). Enables per-server TLS version control. */
esp_tls_proto_ver_t tls_version;
/** Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites.
* Please check the list validity by esp_tls_get_ciphersuites_list() API.
* This allows per-server cipher suite configuration. */
const int *ciphersuites_list;
};
typedef struct httpd_ssl_config httpd_ssl_config_t;
/**
* Helper macro for optional client certificate authentication field
*/
#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
#define HTTPD_SSL_CONFIG_CLIENT_AUTH_OPTIONAL_INIT \
.client_cert_authmode_optional = false,
#else
#define HTTPD_SSL_CONFIG_CLIENT_AUTH_OPTIONAL_INIT
#endif
/**
* Default config struct init
* Notes:
* - port is set when starting the server, according to 'transport_mode'
* - one socket uses ~ 40kB RAM with SSL, we reduce the default socket count to 4
* - SSL sockets are usually long-lived, closing LRU prevents pool exhaustion DOS
* - Stack size may need adjustments depending on the user application
*/
#define HTTPD_SSL_CONFIG_DEFAULT() { \
.httpd = { \
.task_priority = tskIDLE_PRIORITY+5, \
.stack_size = 10240, \
.core_id = tskNO_AFFINITY, \
.task_caps = (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT), \
.max_req_hdr_len = CONFIG_HTTPD_MAX_REQ_HDR_LEN, \
.max_uri_len = CONFIG_HTTPD_MAX_URI_LEN, \
.server_port = 0, \
.ctrl_port = ESP_HTTPD_DEF_CTRL_PORT+1, \
.max_open_sockets = 4, \
.max_uri_handlers = 8, \
.max_resp_headers = 8, \
.backlog_conn = 5, \
.lru_purge_enable = true, \
.recv_wait_timeout = 5, \
.send_wait_timeout = 5, \
.global_user_ctx = NULL, \
.global_user_ctx_free_fn = NULL, \
.global_transport_ctx = NULL, \
.global_transport_ctx_free_fn = NULL, \
.enable_so_linger = false, \
.linger_timeout = 0, \
.keep_alive_enable = false, \
.keep_alive_idle = 0, \
.keep_alive_interval = 0, \
.keep_alive_count = 0, \
.if_name = NULL, \
.open_fn = NULL, \
.close_fn = NULL, \
.uri_match_fn = NULL \
}, \
.servercert = NULL, \
.servercert_len = 0, \
.cacert_pem = NULL, \
.cacert_len = 0, \
HTTPD_SSL_CONFIG_CLIENT_AUTH_OPTIONAL_INIT \
.prvtkey_pem = NULL, \
.prvtkey_len = 0, \
.server_key = NULL, \
.use_ecdsa_peripheral = false, \
.ecdsa_key_efuse_blk = 0, \
.ecdsa_key_efuse_blk_high = 0, \
.ecdsa_curve = ESP_TLS_ECDSA_CURVE_SECP256R1, \
.transport_mode = HTTPD_SSL_TRANSPORT_SECURE, \
.port_secure = 443, \
.port_insecure = 80, \
.session_tickets = false, \
.user_cb = NULL, \
.ssl_userdata = NULL, \
.cert_select_cb = NULL, \
.alpn_protos = NULL, \
.tls_handshake_timeout_ms = 0, \
.tls_version = ESP_TLS_VER_ANY, \
.ciphersuites_list = NULL, \
}
/**
* Create a SSL capable HTTP server (secure mode may be disabled in config)
*
* @param[in,out] config - server config, must not be const. Does not have to stay valid after
* calling this function.
* @param[out] handle - storage for the server handle, must be a valid pointer
* @return success
*/
esp_err_t httpd_ssl_start(httpd_handle_t *handle, httpd_ssl_config_t *config);
/**
* Stop the server. Blocks until the server is shut down.
*
* @param[in] handle
* @return
* - ESP_OK: Server stopped successfully
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_FAIL: Failure to shut down server
*/
esp_err_t httpd_ssl_stop(httpd_handle_t handle);
#ifdef __cplusplus
}
#endif
#endif // _ESP_HTTPS_SERVER_H_
@@ -0,0 +1,475 @@
/*
* SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_https_server.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_tls.h"
const static char *TAG = "esp_https_server";
typedef struct httpd_ssl_ctx {
esp_tls_cfg_server_t *tls_cfg;
httpd_open_func_t open_fn;
esp_https_server_user_cb *user_cb;
} httpd_ssl_ctx_t;
typedef struct httpd_ssl_transport_ctx {
esp_tls_t *tls;
httpd_ssl_ctx_t *global_ctx;
} httpd_ssl_transport_ctx_t;
#ifdef CONFIG_ESP_HTTPS_SERVER_EVENTS
ESP_EVENT_DEFINE_BASE(ESP_HTTPS_SERVER_EVENT);
#if CONFIG_ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT == -1
#define ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT portMAX_DELAY
#else
#define ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT pdMS_TO_TICKS(CONFIG_ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT)
#endif
static void http_dispatch_event_to_event_loop(int32_t event_id, const void* event_data, size_t event_data_size)
{
esp_err_t err = esp_event_post(ESP_HTTPS_SERVER_EVENT, event_id, event_data, event_data_size, ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to post http_client event: %"PRId32", error: %s", event_id, esp_err_to_name(err));
}
}
#else // CONFIG_ESP_HTTPS_SERVER_EVENTS
static void http_dispatch_event_to_event_loop(int32_t event_id, const void* event_data, size_t event_data_size)
{
// Events disabled, do nothing
(void) event_id;
(void) event_data;
(void) event_data_size;
}
#endif // CONFIG_ESP_HTTPS_SERVER_EVENTS
/**
* SSL socket close handler
*
* @param[in] ctx - session transport context (SSL context we stored there)
*/
static void httpd_ssl_close(void *ctx)
{
assert(ctx != NULL);
httpd_ssl_transport_ctx_t *transport_ctx = (httpd_ssl_transport_ctx_t *)ctx;
httpd_ssl_ctx_t *global_ctx = transport_ctx->global_ctx;
esp_tls_t *tls = transport_ctx->tls;
if (global_ctx->user_cb) {
esp_https_server_user_cb_arg_t user_cb_data = {0};
user_cb_data.user_cb_state = HTTPD_SSL_USER_CB_SESS_CLOSE;
user_cb_data.tls = tls;
(global_ctx->user_cb)((void *)&user_cb_data);
}
esp_tls_server_session_delete(tls);
free(ctx);
ESP_LOGD(TAG, "Secure socket closed");
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_DISCONNECTED, NULL, 0);
}
/**
* SSL socket pending-check function
*
* @param server
* @param sockfd
* @return number of pending bytes, negative on error
*/
static int httpd_ssl_pending(httpd_handle_t server, int sockfd)
{
httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd);
assert(transport_ctx != NULL);
esp_tls_t *tls = transport_ctx->tls;
assert(tls != NULL);
int ret = esp_tls_get_bytes_avail(tls);
if (ret < 0) {
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
}
return ret;
}
/**
* Receive from a SSL socket
*
* @param server
* @param sockfd
* @param buf
* @param buf_len
* @param flags
* @return bytes read, negative on error
*/
static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags)
{
httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd);
assert(transport_ctx != NULL);
esp_tls_t *tls = transport_ctx->tls;
assert(tls != NULL);
int ret = esp_tls_conn_read(tls, buf, buf_len);
if (ret < 0) {
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
} else {
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ON_DATA, &ret, sizeof(int));
}
return ret;
}
/**
* Send to a SSL socket
*
* @param server
* @param sockfd
* @param buf
* @param buf_len
* @param flags
* @return bytes sent, negative on error
*/
static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, size_t buf_len, int flags)
{
httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd);
assert(transport_ctx != NULL);
esp_tls_t *tls = transport_ctx->tls;
assert(tls != NULL);
int ret = esp_tls_conn_write(tls, buf, buf_len);
if (ret < 0) {
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
} else {
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_SENT_DATA, NULL, 0);
}
return ret;
}
/**
* Open a SSL socket for the server.
* The fd is already open and ready to read / write raw data.
*
* @param server
* @param sockfd - raw socket fd
* @return success
*/
static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
{
assert(server != NULL);
// Retrieve the SSL context from the global context field (set in config)
httpd_ssl_ctx_t *global_ctx = httpd_get_global_transport_ctx(server);
assert(global_ctx != NULL);
esp_tls_t *tls = esp_tls_init();
if (!tls) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = ESP_ERR_NO_MEM;
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
return ESP_ERR_NO_MEM;
}
ESP_LOGI(TAG, "performing session handshake");
int ret = esp_tls_server_session_create(global_ctx->tls_cfg, sockfd, tls);
if (ret != 0) {
ESP_LOGE(TAG, "esp_tls_create_server_session failed, 0x%04x", -ret);
goto fail;
}
// Pass a new structure containing the global context and the tls pointer to httpd_ssl_close
// Store it in the context field of the HTTPD session object
// NOTE: allocated memory will be freed by httpd_ssl_close
httpd_ssl_transport_ctx_t *transport_ctx = (httpd_ssl_transport_ctx_t *)calloc(1, sizeof(httpd_ssl_transport_ctx_t));
if (!transport_ctx) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = ESP_ERR_NO_MEM;
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
/* The TLS session (and its underlying socket fd) is already established; free it
* before returning so a failed connection under memory pressure does not leak the
* SSL context and the socket (CWE-401 / CWE-772). */
esp_tls_server_session_delete(tls);
return ESP_ERR_NO_MEM;
}
transport_ctx->tls = tls;
transport_ctx->global_ctx = global_ctx;
// Store the SSL session into the context field of the HTTPD session object
httpd_sess_set_transport_ctx(server, sockfd, transport_ctx, httpd_ssl_close);
// Set rx/tx/pending override functions
httpd_sess_set_send_override(server, sockfd, httpd_ssl_send);
httpd_sess_set_recv_override(server, sockfd, httpd_ssl_recv);
httpd_sess_set_pending_override(server, sockfd, httpd_ssl_pending);
// all access should now go through SSL
ESP_LOGD(TAG, "Secure socket open");
if (global_ctx->open_fn) {
(global_ctx->open_fn)(server, sockfd);
}
if (global_ctx->user_cb) {
esp_https_server_user_cb_arg_t user_cb_data = {0};
user_cb_data.user_cb_state = HTTPD_SSL_USER_CB_SESS_CREATE;
user_cb_data.tls = tls;
(global_ctx->user_cb)((void *)&user_cb_data);
}
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ON_CONNECTED, NULL, 0);
return ESP_OK;
fail:
{
esp_tls_error_handle_t error_handle;
if (esp_tls_get_error_handle(tls, &error_handle) == ESP_OK) {
esp_https_server_last_error_t last_error = {0};
last_error.last_error = esp_tls_get_and_clear_last_error(error_handle, &last_error.esp_tls_error_code, &last_error.esp_tls_flags);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_ERROR, &last_error, sizeof(last_error));
}
// Call user callback if configured, allowing user to log failures
if (global_ctx->user_cb) {
esp_https_server_user_cb_arg_t user_cb_data = {0};
user_cb_data.user_cb_state = HTTPD_SSL_USER_CB_SESS_ERROR;
user_cb_data.tls = tls;
(global_ctx->user_cb)((void *)&user_cb_data);
}
esp_tls_server_session_delete(tls);
}
return ESP_FAIL;
}
/**
* Tear down the HTTPD global transport context
*
* @param ctx
*/
static void free_secure_context(void *ctx)
{
assert(ctx != NULL);
httpd_ssl_ctx_t *ssl_ctx = ctx;
esp_tls_cfg_server_t *cfg = ssl_ctx->tls_cfg;
ESP_LOGI(TAG, "Server shuts down, releasing SSL context");
if (cfg->cacert_buf) {
free((void *)cfg->cacert_buf);
}
if (cfg->servercert_buf) {
free((void *)cfg->servercert_buf);
}
if (cfg->serverkey_buf) {
free((void *)cfg->serverkey_buf);
}
esp_tls_cfg_server_session_tickets_free(cfg);
free(cfg);
free(ssl_ctx);
}
static esp_err_t create_secure_context(const struct httpd_ssl_config *config, httpd_ssl_ctx_t **ssl_ctx)
{
if (!ssl_ctx || !*ssl_ctx) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)calloc(1, sizeof(esp_tls_cfg_server_t));
if (!cfg) {
ret = ESP_ERR_NO_MEM;
goto exit;
}
if (config->session_tickets) {
ret = esp_tls_cfg_server_session_tickets_init(cfg);
if ( ret != ESP_OK ) {
ESP_LOGE(TAG, "Failed to init session ticket support. error: %s", esp_err_to_name(ret));
goto exit;
}
}
cfg->userdata = config->ssl_userdata;
cfg->alpn_protos = config->alpn_protos;
cfg->tls_handshake_timeout_ms = config->tls_handshake_timeout_ms;
#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
cfg->client_cert_authmode_optional = config->client_cert_authmode_optional;
#endif // CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
cfg->tls_version = config->tls_version;
cfg->ciphersuites_list = config->ciphersuites_list;
#if defined(CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK)
cfg->cert_select_cb = config->cert_select_cb;
#endif
(*ssl_ctx)->tls_cfg = cfg;
(*ssl_ctx)->user_cb = config->user_cb;
/* cacert = CA which signs client cert, or client cert itself */
if (config->cacert_pem != NULL && config->cacert_len > 0) {
cfg->cacert_buf = (unsigned char *)malloc(config->cacert_len);
if (cfg->cacert_buf) {
memcpy((char *) cfg->cacert_buf, config->cacert_pem, config->cacert_len);
cfg->cacert_bytes = config->cacert_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for client certificate authority");
ret = ESP_ERR_NO_MEM;
goto exit;
}
}
/* servercert = cert of server itself */
if (config->servercert != NULL && config->servercert_len > 0) {
cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);
if (cfg->servercert_buf) {
memcpy((char *) cfg->servercert_buf, config->servercert, config->servercert_len);
cfg->servercert_bytes = config->servercert_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for server certificate");
ret = ESP_ERR_NO_MEM;
goto exit;
}
} else {
#if defined(CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK)
if (config->cert_select_cb == NULL) {
#endif
ESP_LOGE(TAG, "No Server certificate supplied");
ret = ESP_ERR_INVALID_ARG;
goto exit;
#if defined(CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK)
} else {
ESP_LOGW(TAG, "Server certificate not supplied, make sure to supply it in the certificate selection hook!");
}
#endif
}
if (config->use_ecdsa_peripheral) {
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN
(*ssl_ctx)->tls_cfg->use_ecdsa_peripheral = config->use_ecdsa_peripheral;
(*ssl_ctx)->tls_cfg->ecdsa_key_efuse_blk = config->ecdsa_key_efuse_blk;
#if SOC_ECDSA_SUPPORT_CURVE_P384
(*ssl_ctx)->tls_cfg->ecdsa_key_efuse_blk_high = config->ecdsa_key_efuse_blk_high;
#endif
(*ssl_ctx)->tls_cfg->ecdsa_curve = config->ecdsa_curve;
#else
ESP_LOGE(TAG, "Please enable the support for signing using ECDSA peripheral in menuconfig.");
ret = ESP_ERR_NOT_SUPPORTED;
goto exit;
#endif
} else if (config->server_key != NULL) {
/* Unified key config - pass directly to esp_tls */
cfg->server_key = config->server_key;
} else if (config->prvtkey_pem != NULL && config->prvtkey_len > 0) {
cfg->serverkey_buf = malloc(config->prvtkey_len);
if (cfg->serverkey_buf) {
memcpy((char *) cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
cfg->serverkey_bytes = config->prvtkey_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for server key");
ret = ESP_ERR_NO_MEM;
goto exit;
}
} else {
#if defined(CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK)
if (config->cert_select_cb == NULL) {
ESP_LOGE(TAG, "No Server key supplied and no certificate selection hook is present");
ret = ESP_ERR_INVALID_ARG;
goto exit;
} else {
ESP_LOGW(TAG, "Server key not supplied, make sure to supply it in the certificate selection hook");
}
#else
ESP_LOGE(TAG, "No Server key supplied");
ret = ESP_ERR_INVALID_ARG;
goto exit;
#endif
}
return ret;
exit:
if (cfg) {
free((void *) cfg->servercert_buf);
free((void *) cfg->cacert_buf);
}
free(cfg);
return ret;
}
/** Start the server */
esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *config)
{
assert(config != NULL);
assert(pHandle != NULL);
ESP_LOGI(TAG, "Starting server");
esp_err_t ret = ESP_OK;
httpd_ssl_ctx_t *ssl_ctx = NULL;
if (HTTPD_SSL_TRANSPORT_SECURE == config->transport_mode) {
ssl_ctx = calloc(1, sizeof(httpd_ssl_ctx_t));
if (!ssl_ctx) {
return ESP_ERR_NO_MEM;
}
ret = create_secure_context(config, &ssl_ctx);
if (ret != ESP_OK) {
free(ssl_ctx);
return ret;
}
ESP_LOGD(TAG, "SSL context ready");
// set SSL specific config
config->httpd.global_transport_ctx = ssl_ctx;
config->httpd.global_transport_ctx_free_fn = free_secure_context;
if (config->httpd.open_fn) {
// since the httpd's open_fn is used for opening the SSL session, we save the configured
// user pointer and call it upon opening the ssl socket
ssl_ctx->open_fn = config->httpd.open_fn;
}
config->httpd.open_fn = httpd_ssl_open; // the open function configures the created SSL sessions
config->httpd.server_port = config->port_secure;
} else {
ESP_LOGD(TAG, "SSL disabled, using plain HTTP");
config->httpd.server_port = config->port_insecure;
}
httpd_handle_t handle = NULL;
ret = httpd_start(&handle, &config->httpd);
if (ret != ESP_OK) {
if (ssl_ctx) {
free_secure_context(ssl_ctx);
}
return ret;
}
*pHandle = handle;
ESP_LOGI(TAG, "Server listening on port %d", config->httpd.server_port);
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_START, NULL, 0);
return ESP_OK;
}
/** Stop the server */
esp_err_t httpd_ssl_stop(httpd_handle_t handle)
{
esp_err_t ret = httpd_stop(handle);
if (ret == ESP_OK) {
http_dispatch_event_to_event_loop(HTTPS_SERVER_EVENT_STOP, NULL, 0);
}
return ret;
}