From 7e22a13afed5574167bda822ffe6eeac8b93b3a6 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 19 Sep 2023 18:52:45 +0200 Subject: [PATCH 1/2] feat(http_client): Add support for TLS session tickets --- components/esp_http_client/esp_http_client.c | 29 +++++++++++++++ .../esp_http_client/include/esp_http_client.h | 5 ++- .../tcp_transport/include/esp_transport_ssl.h | 22 ++++++++++++ components/tcp_transport/transport_ssl.c | 35 +++++++++++++++++++ .../mocks/tcp_transport/mock/mock_config.yaml | 2 ++ 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 8f91ef3b05..1baa912dee 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -88,6 +88,13 @@ typedef enum { HTTP_STATE_RES_COMPLETE_DATA, HTTP_STATE_CLOSE } esp_http_state_t; + +typedef enum { + SESSION_TICKET_UNUSED = 0, + SESSION_TICKET_NOT_SAVED, + SESSION_TICKET_SAVED, +} session_ticket_state_t; + /** * HTTP client class */ @@ -127,6 +134,9 @@ struct esp_http_client { esp_transport_keep_alive_t keep_alive_cfg; struct ifreq *if_name; unsigned cache_data_in_fetch_hdr: 1; +#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + session_ticket_state_t session_ticket_state; +#endif }; typedef struct esp_http_client esp_http_client_t; @@ -742,6 +752,12 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co } #endif +#if CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + if (config->save_client_session) { + client->session_ticket_state = SESSION_TICKET_NOT_SAVED; + } +#endif + if (config->client_key_pem) { if (!config->client_key_len) { esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); @@ -1384,6 +1400,12 @@ static esp_err_t esp_http_client_connect(esp_http_client_handle_t client) if (client->state < HTTP_STATE_CONNECTED) { ESP_LOGD(TAG, "Begin connect to: %s://%s:%d", client->connection_info.scheme, client->connection_info.host, client->connection_info.port); client->transport = esp_transport_list_get_transport(client->transport_list, client->connection_info.scheme); + +#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + if (client->session_ticket_state == SESSION_TICKET_SAVED) { + esp_transport_ssl_session_ticket_operation(client->transport, ESP_TRANSPORT_SESSION_TICKET_USE); + } +#endif if (client->transport == NULL) { ESP_LOGE(TAG, "No transport found"); #ifndef CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS @@ -1415,6 +1437,13 @@ static esp_err_t esp_http_client_connect(esp_http_client_handle_t client) client->state = HTTP_STATE_CONNECTED; http_dispatch_event(client, HTTP_EVENT_ON_CONNECTED, NULL, 0); http_dispatch_event_to_event_loop(HTTP_EVENT_ON_CONNECTED, &client, sizeof(esp_http_client_handle_t)); +#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + if (client->session_ticket_state != SESSION_TICKET_UNUSED) { + esp_transport_ssl_session_ticket_operation(client->transport, ESP_TRANSPORT_SESSION_TICKET_SAVE); + client->session_ticket_state = SESSION_TICKET_SAVED; + } +#endif + } return ESP_OK; } diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 06bee3dda8..29a91468e5 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -178,6 +178,9 @@ typedef struct { #if CONFIG_ESP_TLS_USE_DS_PERIPHERAL void *ds_data; /*!< Pointer for digital signature peripheral context, see ESP-TLS Documentation for more details */ #endif +#if CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + bool save_client_session; +#endif } esp_http_client_config_t; /** diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index 00a76e043b..61e54bea71 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/components/tcp_transport/include/esp_transport_ssl.h @@ -211,6 +211,28 @@ void esp_transport_ssl_set_keep_alive(esp_transport_handle_t t, esp_transport_ke */ void esp_transport_ssl_set_interface_name(esp_transport_handle_t t, struct ifreq *if_name); +#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS +/** + * @brief Session ticket operation + */ +typedef enum { + ESP_TRANSPORT_SESSION_TICKET_INIT, /*!< Allocate and initialize a TLS session */ + ESP_TRANSPORT_SESSION_TICKET_SAVE, /*!< Save TLS session so it can be restored for the next handshake */ + ESP_TRANSPORT_SESSION_TICKET_USE, /*!< Use already saved session to reconnect faster */ + ESP_TRANSPORT_SESSION_TICKET_FREE /*!< Deallocate and deinit the TLS session */ +} esp_transport_session_ticket_operation_t; + +/** + * @brief Perform desired session ticket operation (init, save, use) + * + * @param[in] t The transport handle + * @param[in] operation Operation to perform with TLS session + * + * @note This operation is only available if CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS=y + */ +esp_err_t esp_transport_ssl_session_ticket_operation(esp_transport_handle_t t, esp_transport_session_ticket_operation_t operation); +#endif // CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 0d5228442c..547c82f484 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -38,6 +38,9 @@ typedef struct transport_esp_tls { bool ssl_initialized; transport_ssl_conn_state_t conn_state; int sockfd; +#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + esp_tls_client_session_t *session_ticket; +#endif } transport_esp_tls_t; /** @@ -523,6 +526,9 @@ esp_transport_handle_t esp_transport_ssl_init(void) void esp_transport_esp_tls_destroy(struct transport_esp_tls *transport_esp_tls) { +#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS + esp_tls_free_client_session(transport_esp_tls->session_ticket); +#endif free(transport_esp_tls); } @@ -548,3 +554,32 @@ void esp_transport_tcp_set_interface_name(esp_transport_handle_t t, struct ifreq { return esp_transport_ssl_set_interface_name(t, if_name); } + +#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS +esp_err_t esp_transport_ssl_session_ticket_operation(esp_transport_handle_t t, esp_transport_session_ticket_operation_t operation) +{ + transport_esp_tls_t *ssl = ssl_get_context_data(t); + if (!ssl) { + return ESP_FAIL; + } + switch (operation) { + case ESP_TRANSPORT_SESSION_TICKET_INIT: + break; + case ESP_TRANSPORT_SESSION_TICKET_SAVE: + esp_tls_free_client_session(ssl->session_ticket); + ssl->session_ticket = esp_tls_get_client_session(ssl->tls); + break; + case ESP_TRANSPORT_SESSION_TICKET_USE: + if (ssl->session_ticket == NULL) { + return ESP_ERR_INVALID_STATE; + } + ssl->cfg.client_session = ssl->session_ticket; + break; + case ESP_TRANSPORT_SESSION_TICKET_FREE: + esp_tls_free_client_session(ssl->session_ticket); + ssl->session_ticket = NULL; + break; + } + return ESP_OK; +} +#endif // CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS diff --git a/tools/mocks/tcp_transport/mock/mock_config.yaml b/tools/mocks/tcp_transport/mock/mock_config.yaml index fcf2722bc1..0d7150e201 100644 --- a/tools/mocks/tcp_transport/mock/mock_config.yaml +++ b/tools/mocks/tcp_transport/mock/mock_config.yaml @@ -7,3 +7,5 @@ - ignore_arg - callback :when_ptr: :compare_ptr + :strippables: + - '(?:esp_transport_ssl_session_ticket_operation\s*\(+.*?\)+)' From 96069eef3be808f587d3c9f1fff1461ebe0a23bb Mon Sep 17 00:00:00 2001 From: David Cermak Date: Sun, 19 Nov 2023 18:32:00 +0100 Subject: [PATCH 2/2] feat(http_client): Add support for using custom tcp_transport --- components/esp_http_client/Kconfig | 8 ++++++++ components/esp_http_client/esp_http_client.c | 17 +++++++++++++++-- .../esp_http_client/include/esp_http_client.h | 8 ++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/components/esp_http_client/Kconfig b/components/esp_http_client/Kconfig index b7ea8ed68c..355b591c8f 100644 --- a/components/esp_http_client/Kconfig +++ b/components/esp_http_client/Kconfig @@ -21,4 +21,12 @@ menu "ESP HTTP client" This option will enable HTTP Digest Authentication. It is enabled by default, but use of this configuration is not recommended as the password can be derived from the exchange, so it introduces a vulnerability when not using TLS + + config ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT + bool "Enable custom transport" + default n + help + This option will enable injection of a custom tcp_transport handle, so the http operation + will be performed on top of the user defined transport abstraction (if configured) + endmenu diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 1baa912dee..fbb0bfcaf8 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -758,6 +758,12 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co } #endif +#if CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT + if (config->transport) { + client->transport = config->transport; + } +#endif + if (config->client_key_pem) { if (!config->client_key_len) { esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); @@ -1398,8 +1404,15 @@ static esp_err_t esp_http_client_connect(esp_http_client_handle_t client) } if (client->state < HTTP_STATE_CONNECTED) { - ESP_LOGD(TAG, "Begin connect to: %s://%s:%d", client->connection_info.scheme, client->connection_info.host, client->connection_info.port); - client->transport = esp_transport_list_get_transport(client->transport_list, client->connection_info.scheme); +#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT + // If the custom transport is enabled and defined, we skip the selection of appropriate transport from the list + // based on the scheme, since we already have the transport + if (!client->transport) +#endif + { + ESP_LOGD(TAG, "Begin connect to: %s://%s:%d", client->connection_info.scheme, client->connection_info.host, client->connection_info.port); + client->transport = esp_transport_list_get_transport(client->transport_list, client->connection_info.scheme); + } #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS if (client->session_ticket_state == SESSION_TICKET_SAVED) { diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 29a91468e5..1c50a1fa5a 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -24,6 +24,11 @@ ESP_EVENT_DECLARE_BASE(ESP_HTTP_CLIENT_EVENT); typedef struct esp_http_client *esp_http_client_handle_t; typedef struct esp_http_client_event *esp_http_client_event_handle_t; +#if CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT +// Forward declares transport handle item to keep the dependency private (even if ENABLE_CUSTOM_TRANSPORT=y) +struct esp_transport_item_t; +#endif + /** * @brief HTTP Client events id */ @@ -181,6 +186,9 @@ typedef struct { #if CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS bool save_client_session; #endif +#if CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT + struct esp_transport_item_t *transport; +#endif } esp_http_client_config_t; /**