From 39a6ec0d1c87bd0d2cc06f52f2a42fee6650f4c4 Mon Sep 17 00:00:00 2001 From: Akos Vandra Date: Mon, 10 Oct 2022 17:26:35 +0200 Subject: [PATCH] moved to use the CERTIFICATE SELECTION HOOK instead of the SNI HOOK, since it has access to more information, so the application can make a more informed decision on which certificate to serve (such as alpn value, server certificate type, etc.) --- components/esp-tls/Kconfig | 9 +-- components/esp-tls/esp_tls.h | 23 +++--- components/esp-tls/esp_tls_mbedtls.c | 24 ++++--- .../include/esp_https_server.h | 6 +- .../esp_https_server/src/https_server.c | 72 ++++++++----------- 5 files changed, 65 insertions(+), 69 deletions(-) diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig index 4aacf4cdc94..6c0d7586bc4 100644 --- a/components/esp-tls/Kconfig +++ b/components/esp-tls/Kconfig @@ -57,12 +57,13 @@ menu "ESP-TLS" help Sets the session ticket timeout used in the tls server. - config ESP_TLS_SERVER_SNI_HOOK - bool "Server name identification hook" + config ESP_TLS_SERVER_CERT_SELECT_HOOK + bool "Certificate selection hook" depends on ESP_TLS_USING_MBEDTLS help - Ability to configure and use an SNI Callback during server handshake, - to select a certificate to present to the client for example. + Ability to configure and use a certificate selection callback during server handshake, + to select a certificate to present to the client based on the TLS extensions supplied in + the client hello (alpn, sni, etc). config ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL bool "ESP-TLS Server: Set minimum Certificate Verification mode to Optional" diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 7b4ce26ab37..d018824f136 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -197,17 +197,19 @@ typedef struct esp_tls_server_session_ticket_ctx { } esp_tls_server_session_ticket_ctx_t; #endif + +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) /** - * @brief SNI callback function prototype + * @brief tls handshake callback * Can be used to configure per-handshake attributes for the TLS connection. - * E.g. Client certificate / Key, Authmode, Client CA verification + * E.g. Client certificate / Key, Authmode, Client CA verification, etc. * - * @param p_info Input data provided when registering the callback * @param ssl mbedtls_ssl_context that can be used for changing settings - * @param name advertised server name by the client - * @param len length of the name buffer + * @return The reutn value of the callback must be 0 if successful, + * or a specific MBEDTLS_ERR_XXX code, which will cause the handhsake to abort */ -typedef int esp_tls_server_sni_callback(void *p_info, mbedtls_ssl_context *ssl, const unsigned char *name, size_t name_len); +typedef mbedtls_ssl_hs_cb_t esp_tls_handshake_callback; +#endif typedef struct esp_tls_cfg_server { const char **alpn_protos; /*!< Application protocols required for HTTP2. @@ -272,10 +274,13 @@ typedef struct esp_tls_cfg_server { to free the data associated with this context. */ #endif -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) - esp_tls_server_sni_callback *sni_callback; /*!< Server Name Identification callback to use */ - void *sni_callback_p_info; /*!< Data to pass to the SNI callback. */ +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) + esp_tls_handshake_callback cert_select_cb; /*!< Certificate selection callback that gets called after ClientHello is processed. + Can be used as an SNI callback, but also has access to other + TLS extensions, such as ALPN and server_certificate_type . */ #endif + + void *userdata; /*!< User data to be add to the ssl context. Can be retrieved by callbacks */ } esp_tls_cfg_server_t; /** diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index 418aa75bb36..5f89aebbfa2 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -509,12 +509,21 @@ esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED; } + mbedtls_ssl_conf_set_user_data_p(&tls->conf, cfg->userdata); + #ifdef CONFIG_MBEDTLS_SSL_ALPN if (cfg->alpn_protos) { mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos); } #endif +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) + if (cfg->cert_select_cb != NULL) { + ESP_LOGI(TAG, "Initializing server side certificate selection callback"); + mbedtls_ssl_conf_cert_cb(&tls->conf, cfg->cert_select_cb); + } +#endif + if (cfg->cacert_buf != NULL) { esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes); if (esp_ret != ESP_OK) { @@ -566,11 +575,11 @@ esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) return esp_ret; } } else { -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) - if (cfg->sni_callback == NULL) { - ESP_LOGE(TAG, "Missing server certificate and/or key and no SNI callback is defined"); +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) + if (cfg->cert_select_cb == NULL) { + ESP_LOGE(TAG, "Missing server certificate and/or key and no certificate selection callback is defined"); } else { - ESP_LOGD(TAG, "Missing server certificate and/or key, but SNI callback is defined. Callback MUST ALWAYS call mbedtls_ssl_set_hs_own_cert, or the handshake will abort!"); + ESP_LOGD(TAG, "Missing server certificate and/or key, but certificate selection callback is defined. Callback MUST ALWAYS call mbedtls_ssl_set_hs_own_cert, or the handshake will abort!"); return ESP_OK; } #else @@ -797,13 +806,6 @@ int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp return -1; } -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) - if (cfg->sni_callback != NULL) { - ESP_LOGI(TAG, "Initializing server side SNI callback"); - mbedtls_ssl_conf_sni(&tls->conf, cfg->sni_callback, cfg->sni_callback_p_info); - } -#endif - tls->read = esp_mbedtls_read; tls->write = esp_mbedtls_write; int ret; diff --git a/components/esp_https_server/include/esp_https_server.h b/components/esp_https_server/include/esp_https_server.h index 28afe5911a8..d224a8fa05b 100644 --- a/components/esp_https_server/include/esp_https_server.h +++ b/components/esp_https_server/include/esp_https_server.h @@ -97,10 +97,10 @@ struct httpd_ssl_config { /** User callback for esp_https_server */ esp_https_server_user_cb *user_cb; -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) - esp_tls_server_sni_callback *sni_callback; /*!< Server Name Identification callback to use */ - void *sni_callback_p_info; /*!< Data to pass to the SNI callback. */ +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) + esp_tls_handshake_callback cert_select_cb; /*!< Certificate selection callback to use */ #endif + void *ssl_userdata; /*!< user data to add to the ssl context */ }; typedef struct httpd_ssl_config httpd_ssl_config_t; diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c index 44570f215e8..bfb4ed44672 100644 --- a/components/esp_https_server/src/https_server.c +++ b/components/esp_https_server/src/https_server.c @@ -200,22 +200,20 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con } esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)calloc(1, sizeof(esp_tls_cfg_server_t)); if (!cfg) { - free(ssl_ctx); - return NULL; + goto free_ssl_ctx; } 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; + goto free_cfg; } } -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) - cfg->sni_callback = config->sni_callback; - cfg->sni_callback_p_info = config->sni_callback_p_info; + cfg->userdata = config->ssl_userdata; + +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) + cfg->cert_select_cb = config->cert_select_cb; #endif ssl_ctx->tls_cfg = cfg; @@ -230,9 +228,7 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con cfg->cacert_bytes = config->cacert_len; } else { ESP_LOGE(TAG, "Could not allocate memory for client certificate authority"); - free(cfg); - free(ssl_ctx); - return NULL; + goto free_cfg; } } @@ -245,23 +241,17 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con cfg->servercert_bytes = config->servercert_len; } else { ESP_LOGE(TAG, "Could not allocate memory for server certificate"); - free((void *) cfg->cacert_buf); - free(cfg); - free(ssl_ctx); - return NULL; + goto free_cacert; } } else { -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) - if (config->sni_callback == NULL) { +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) + if (config->cert_select_cb == NULL) { #endif ESP_LOGE(TAG, "No Server certificate supplied"); - free((void *) cfg->cacert_buf); - free(cfg); - free(ssl_ctx); - return NULL; -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) + goto free_cacert; +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) } else { - ESP_LOGW(TAG, "Server certificate not supplied, make sure to supply it in the SNI hook!"); + ESP_LOGW(TAG, "Server certificate not supplied, make sure to supply it in the certificate selection hook!"); } #endif } @@ -277,36 +267,34 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con cfg->serverkey_bytes = config->prvtkey_len; } else { ESP_LOGE(TAG, "Could not allocate memory for server key"); - free((void *) cfg->servercert_buf); - free((void *) cfg->cacert_buf); - free(cfg); - free(ssl_ctx); - return NULL; + goto free_servercert; } } else { -#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK) - if (config->sni_callback == NULL) { - ESP_LOGE(TAG, "No Server key supplied and no SNI hook is present"); - free((void *) cfg->servercert_buf); - free((void *) cfg->cacert_buf); - free(cfg); - free(ssl_ctx); - return NULL; +#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK) + if (config->cert_select_cb == NULL) { + ESP_LOGE(TAG, "No Server key supplied and no certificate selection hook is present"); + goto free_servercert; } else { - ESP_LOGW(TAG, "Server key not supplied, make sure to supply it in the SNI hook"); + 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"); - free((void *) cfg->servercert_buf); - free((void *) cfg->cacert_buf); - free(cfg); - free(ssl_ctx); - return NULL; + goto free_servercert; #endif } } return ssl_ctx; + +free_servercert: + free((void *) cfg->servercert_buf); +free_cacert: + free((void *) cfg->cacert_buf); +free_cfg: + free(cfg); +free_ssl_ctx: + free(ssl_ctx); + return NULL; } /** Start the server */