From 7e22a13afed5574167bda822ffe6eeac8b93b3a6 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 19 Sep 2023 18:52:45 +0200 Subject: [PATCH] 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*\(+.*?\)+)'