diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig index 8dbaae4001..2ef819b411 100644 --- a/components/esp-tls/Kconfig +++ b/components/esp-tls/Kconfig @@ -41,6 +41,20 @@ menu "ESP-TLS" Enable support for creating server side SSL/TLS session, available for mbedTLS as well as wolfSSL TLS library. + config ESP_TLS_SERVER_SESSION_TICKETS + bool "Enable session tickets" + depends on ESP_TLS_SERVER && ESP_TLS_USING_MBEDTLS && MBEDTLS_SERVER_SSL_SESSION_TICKETS + default n + help + Enable session ticket support as specified in RFC5077 + + config ESP_TLS_SERVER_SESSION_TICKET_TIMEOUT + int "Server session ticket timeout in seconds" + depends on ESP_TLS_SERVER_SESSION_TICKETS + default 86400 + help + Sets the session ticket timeout used in the tls server. + config ESP_TLS_PSK_VERIFICATION bool "Enable PSK verification" select MBEDTLS_PSK_MODES if ESP_TLS_USING_MBEDTLS diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 867e1012d9..d8c760d446 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -41,6 +41,8 @@ static const char *TAG = "esp-tls"; #ifdef CONFIG_ESP_TLS_SERVER #define _esp_tls_server_session_create esp_mbedtls_server_session_create #define _esp_tls_server_session_delete esp_mbedtls_server_session_delete +#define _esp_tls_session_ticket_ctx_init esp_mbedtls_session_ticket_ctx_init +#define _esp_tls_session_ticket_ctx_free esp_mbedtls_session_ticket_ctx_free #endif /* CONFIG_ESP_TLS_SERVER */ #define _esp_tls_get_bytes_avail esp_mbedtls_get_bytes_avail #define _esp_tls_init_global_ca_store esp_mbedtls_init_global_ca_store @@ -569,6 +571,32 @@ mbedtls_x509_crt *esp_tls_get_global_ca_store(void) #endif /* CONFIG_ESP_TLS_USING_MBEDTLS */ #ifdef CONFIG_ESP_TLS_SERVER + +esp_err_t esp_tls_cfg_server_session_tickets_init(esp_tls_cfg_server_t *cfg) +{ +#if defined(CONFIG_ESP_TLS_USING_MBEDTLS) && defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS) + if (!cfg || cfg->ticket_ctx) { + return ESP_ERR_INVALID_ARG; + } + cfg->ticket_ctx = calloc(1, sizeof(esp_tls_session_ticket_ctx_t)); + if (!cfg->ticket_ctx) { + return ESP_ERR_NO_MEM; + } + return _esp_tls_session_ticket_ctx_init(cfg->ticket_ctx); +#else + return ESP_ERR_NOT_SUPPORTED; +#endif +} + +void esp_tls_cfg_server_session_tickets_free(esp_tls_cfg_server_t *cfg) +{ +#if defined(CONFIG_ESP_TLS_USING_MBEDTLS) && defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS) + if (cfg && cfg->ticket_ctx) { + _esp_tls_session_ticket_ctx_free(cfg->ticket_ctx); + } +#endif +} + /** * @brief Create a server side TLS/SSL connection */ diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 9330f9dd69..89a2fae0d2 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -20,6 +20,9 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/error.h" #include "mbedtls/certs.h" +#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" @@ -171,6 +174,20 @@ typedef struct esp_tls_cfg { } esp_tls_cfg_t; #ifdef CONFIG_ESP_TLS_SERVER +#if defined(CONFIG_ESP_TLS_USING_MBEDTLS) && defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS) +/** + * @brief Data structures necessary to support TLS session tickets according to RFC5077 + */ +typedef struct esp_tls_session_ticket_ctx { + mbedtls_entropy_context entropy; /*!< mbedTLS entropy context structure */ + + mbedtls_ctr_drbg_context ctr_drbg; /*!< mbedTLS ctr drbg context structure. + CTR_DRBG is deterministic random + bit generation based on AES-256 */ + mbedtls_ssl_ticket_context ticket_ctx; /*!< Session ticket generation context */ +} esp_tls_session_ticket_ctx_t; +#endif + typedef struct esp_tls_cfg_server { const char **alpn_protos; /*!< Application protocols required for HTTP2. If HTTP2/ALPN support is required, a list @@ -222,7 +239,37 @@ typedef struct esp_tls_cfg_server { unsigned int serverkey_password_len; /*!< String length of the password pointed to by serverkey_password */ +#if defined(CONFIG_ESP_TLS_USING_MBEDTLS) && defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS) + esp_tls_session_ticket_ctx_t * ticket_ctx; /*!< Session ticket generation context. + You have to call esp_tls_cfg_server_session_tickets_init + to use it. + Call esp_tls_cfg_server_session_tickets_free + to free the data associated with this context. */ +#endif } esp_tls_cfg_server_t; + +/** + * @brief Initialize the server side TLS session ticket context + * + * This function initializes the server side tls session ticket context + * which holds all necessary data structures to enable tls session tickets + * according to RFC5077. + * Use esp_tls_cfg_server_session_tickets_free to free the data. + * + * @param[in] cfg server configuration as esp_tls_cfg_server_t + * @return + * ESP_OK if setup succeeded + * ESP_ERR_INVALID_ARG if context is already initialized + * ESP_ERR_NO_MEM if memory allocation failed + * ESP_ERR_NOT_SUPPORTED if session tickets are not available due to build configuration + * ESP_FAIL if setup failed + */ +esp_err_t esp_tls_cfg_server_session_tickets_init(esp_tls_cfg_server_t *cfg); + +/** + * @brief Free the server side TLS session ticket context + */ +void esp_tls_cfg_server_session_tickets_free(esp_tls_cfg_server_t *cfg); #endif /* ! CONFIG_ESP_TLS_SERVER */ /** diff --git a/components/esp-tls/esp_tls_errors.h b/components/esp-tls/esp_tls_errors.h index 5dfe74791c..7c3cd875cf 100644 --- a/components/esp-tls/esp_tls_errors.h +++ b/components/esp-tls/esp_tls_errors.h @@ -31,18 +31,19 @@ extern "C" { #define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */ #define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */ #define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */ -#define ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT (ESP_ERR_ESP_TLS_BASE + 0x12) /*!< new connection in esp_tls_low_level_conn connection timeouted */ -#define ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x13) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x14) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x15) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_KEY_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x16) /*!< wolfSSL api returned error */ -#define ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x17) /*!< wolfSSL api returned failed */ -#define ESP_ERR_WOLFSSL_CTX_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x18) /*!< wolfSSL api returned failed */ -#define ESP_ERR_WOLFSSL_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x19) /*!< wolfSSL api returned failed */ -#define ESP_ERR_WOLFSSL_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1A) /*!< wolfSSL api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_SESSION_TICKET_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x12) /*!< mbedtls api returned failed */ +#define ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT (ESP_ERR_ESP_TLS_BASE + 0x13) /*!< new connection in esp_tls_low_level_conn connection timeouted */ +#define ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x14) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x15) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_CERT_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x16) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_KEY_VERIFY_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x17) /*!< wolfSSL api returned error */ +#define ESP_ERR_WOLFSSL_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x18) /*!< wolfSSL api returned failed */ +#define ESP_ERR_WOLFSSL_CTX_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x19) /*!< wolfSSL api returned failed */ +#define ESP_ERR_WOLFSSL_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1A) /*!< wolfSSL api returned failed */ +#define ESP_ERR_WOLFSSL_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1B) /*!< wolfSSL api returned failed */ -#define ESP_ERR_ESP_TLS_SE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1B) /*< esp-tls use Secure Element returned failed */ -#define ESP_ERR_ESP_TLS_TCP_CLOSED_FIN (ESP_ERR_ESP_TLS_BASE + 0x1C) /*< esp-tls's TPC transport connection has benn closed (in a clean way) */ +#define ESP_ERR_ESP_TLS_SE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x1C) /*< esp-tls use Secure Element returned failed */ +#define ESP_ERR_ESP_TLS_TCP_CLOSED_FIN (ESP_ERR_ESP_TLS_BASE + 0x1D) /*< esp-tls's TPC transport connection has benn closed (in a clean way) */ /** * Definition of errors reported from IO API (potentially non-blocking) in case of error: diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index 35064399c9..172227d657 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -368,8 +368,70 @@ static esp_err_t set_global_ca_store(esp_tls_t *tls) return ESP_OK; } - #ifdef CONFIG_ESP_TLS_SERVER +#ifdef CONFIG_ESP_TLS_SERVER_SESSION_TICKETS +int esp_mbedtls_session_ticket_write(void *p_ticket, const mbedtls_ssl_session *session, unsigned char *start, const unsigned char *end, size_t *tlen, uint32_t *lifetime) +{ + int ret = mbedtls_ssl_ticket_write(p_ticket, session, start, end, tlen, lifetime); +#ifndef NDEBUG + if (ret != 0) { + ESP_LOGE(TAG, "Writing session ticket resulted in error code -0x%04X", -ret); + mbedtls_print_error_msg(ret); + } +#endif + return ret; +} + +int esp_mbedtls_session_ticket_parse(void *p_ticket, mbedtls_ssl_session *session, unsigned char *buf, size_t len) +{ + int ret = mbedtls_ssl_ticket_parse(p_ticket, session, buf, len); +#ifndef NDEBUG + if (ret != 0) { + ESP_LOGD(TAG, "Parsing session ticket resulted in error code -0x%04X", -ret); + mbedtls_print_error_msg(ret); + } +#endif + return ret; +} + +esp_err_t esp_mbedtls_session_ticket_ctx_init(esp_tls_session_ticket_ctx_t *ctx) +{ + if (!ctx) { + return ESP_ERR_INVALID_ARG; + } + mbedtls_ctr_drbg_init(&ctx->ctr_drbg); + mbedtls_entropy_init(&ctx->entropy); + mbedtls_ssl_ticket_init(&ctx->ticket_ctx); + int ret; + if ((ret = mbedtls_ctr_drbg_seed(&ctx->ctr_drbg, + mbedtls_entropy_func, &ctx->entropy, NULL, 0)) != 0) { + ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04X", -ret); + mbedtls_print_error_msg(ret); + return ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED; + } + + if( ( ret = mbedtls_ssl_ticket_setup( &ctx->ticket_ctx, + mbedtls_ctr_drbg_random, &ctx->ctr_drbg, + MBEDTLS_CIPHER_AES_256_GCM, + CONFIG_ESP_TLS_SERVER_SESSION_TICKET_TIMEOUT ) ) != 0 ) + { + ESP_LOGE(TAG, "mbedtls_ssl_ticket_setup returned -0x%04X", -ret); + mbedtls_print_error_msg(ret); + return ESP_ERR_MBEDTLS_SSL_SESSION_TICKET_SETUP_FAILED; + } + return ESP_OK; +} + +void esp_mbedtls_session_ticket_ctx_free(esp_tls_session_ticket_ctx_t *ctx) +{ + if (ctx) { + mbedtls_ssl_ticket_free(&ctx->ticket_ctx); + mbedtls_ctr_drbg_init(&ctx->ctr_drbg); + mbedtls_entropy_free(&ctx->entropy); + } +} +#endif + esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) { assert(cfg != NULL); @@ -421,6 +483,18 @@ esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) ESP_LOGE(TAG, "Missing server certificate and/or key"); return ESP_ERR_INVALID_STATE; } + +#ifdef CONFIG_ESP_TLS_SERVER_SESSION_TICKETS + if (cfg->ticket_ctx) { + ESP_LOGD(TAG, "Enabling server-side tls session ticket support"); + + mbedtls_ssl_conf_session_tickets_cb( &tls->conf, + esp_mbedtls_session_ticket_write, + esp_mbedtls_session_ticket_parse, + &cfg->ticket_ctx->ticket_ctx ); + } +#endif + return ESP_OK; } #endif /* ! CONFIG_ESP_TLS_SERVER */ diff --git a/components/esp-tls/private_include/esp_tls_mbedtls.h b/components/esp-tls/private_include/esp_tls_mbedtls.h index 78694fc858..f81e2dc33b 100644 --- a/components/esp-tls/private_include/esp_tls_mbedtls.h +++ b/components/esp-tls/private_include/esp_tls_mbedtls.h @@ -76,6 +76,22 @@ int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp * /note :- The function can only be used with mbedtls ssl library */ void esp_mbedtls_server_session_delete(esp_tls_t *tls); + +#ifdef CONFIG_ESP_TLS_SERVER_SESSION_TICKETS +/** + * Internal function to setup server side session ticket context + * + * /note :- The function can only be used with mbedtls ssl library + */ +esp_err_t esp_mbedtls_session_ticket_ctx_init(esp_tls_session_ticket_ctx_t *cfg); + +/** + * Internal function to free server side session ticket context + * + * /note :- The function can only be used with mbedtls ssl library + */ +void esp_mbedtls_session_ticket_ctx_free(esp_tls_session_ticket_ctx_t *cfg); +#endif #endif /** diff --git a/components/esp_https_server/include/esp_https_server.h b/components/esp_https_server/include/esp_https_server.h index 52f9dc2132..00565a963a 100644 --- a/components/esp_https_server/include/esp_https_server.h +++ b/components/esp_https_server/include/esp_https_server.h @@ -63,6 +63,9 @@ struct httpd_ssl_config { /** Port used when transport mode is insecure (default 80) */ uint16_t port_insecure; + + /** Enable tls session tickets */ + bool session_tickets; }; typedef struct httpd_ssl_config httpd_ssl_config_t; @@ -109,6 +112,7 @@ typedef struct httpd_ssl_config httpd_ssl_config_t; .transport_mode = HTTPD_SSL_TRANSPORT_SECURE, \ .port_secure = 443, \ .port_insecure = 80, \ + .session_tickets = false, \ } /** diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c index 6949bf52af..9864ead3b2 100644 --- a/components/esp_https_server/src/https_server.c +++ b/components/esp_https_server/src/https_server.c @@ -145,6 +145,7 @@ static void free_secure_context(void *ctx) if (cfg->serverkey_buf) { free((void *)cfg->serverkey_buf); } + esp_tls_cfg_server_session_tickets_free(cfg); free(cfg); free(ssl_ctx); } @@ -160,6 +161,16 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con free(ssl_ctx); return NULL; } + + if (config->session_tickets) { + if ( esp_tls_cfg_server_session_tickets_init(cfg) != ESP_OK ) { + ESP_LOGE(TAG, "Failed to init session ticket support"); + free(ssl_ctx); + free(cfg); + return NULL; + } + } + ssl_ctx->tls_cfg = cfg; /* cacert = CA which signs client cert, or client cert itself , which is mapped to client_verify_cert_pem */ if(config->client_verify_cert_pem != NULL) {