Implement server session ticket support with mbedtls

Closes https://github.com/espressif/esp-idf/pull/7048

Signed-off-by: Aditya Patwardhan <aditya.patwardhan@espressif.com>
This commit is contained in:
Daniel Bahrdt
2021-05-19 17:16:59 +02:00
committed by Aditya Patwardhan
parent 8f283421da
commit 7e886ca9ed
8 changed files with 207 additions and 12 deletions

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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 */
/**

View File

@@ -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:

View File

@@ -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 */

View File

@@ -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
/**

View File

@@ -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, \
}
/**

View File

@@ -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) {