mirror of
https://github.com/espressif/esp-idf.git
synced 2024-09-20 00:36:01 -04:00
Merge branch 'feature/esp_tls_add_cert_selection_callback' into 'master'
esp-tls: Add support for the CERTIFICATE SELECTION HOOK. The hook has access... Closes IDFGH-8363 and IDFGH-8340 Closes https://github.com/espressif/esp-idf/issues/9815 See merge request espressif/esp-idf!20690
This commit is contained in:
commit
4b6d9c8ad3
@ -40,6 +40,7 @@ menu "ESP-TLS"
|
|||||||
|
|
||||||
config ESP_TLS_SERVER
|
config ESP_TLS_SERVER
|
||||||
bool "Enable ESP-TLS Server"
|
bool "Enable ESP-TLS Server"
|
||||||
|
depends on (ESP_TLS_USING_MBEDTLS && MBEDTLS_TLS_SERVER) || ESP_TLS_USING_WOLFSSL
|
||||||
help
|
help
|
||||||
Enable support for creating server side SSL/TLS session, available for mbedTLS
|
Enable support for creating server side SSL/TLS session, available for mbedTLS
|
||||||
as well as wolfSSL TLS library.
|
as well as wolfSSL TLS library.
|
||||||
@ -57,6 +58,14 @@ menu "ESP-TLS"
|
|||||||
help
|
help
|
||||||
Sets the session ticket timeout used in the tls server.
|
Sets the session ticket timeout used in the tls server.
|
||||||
|
|
||||||
|
config ESP_TLS_SERVER_CERT_SELECT_HOOK
|
||||||
|
bool "Certificate selection hook"
|
||||||
|
depends on ESP_TLS_USING_MBEDTLS && ESP_TLS_SERVER
|
||||||
|
help
|
||||||
|
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
|
config ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
|
||||||
bool "ESP-TLS Server: Set minimum Certificate Verification mode to Optional"
|
bool "ESP-TLS Server: Set minimum Certificate Verification mode to Optional"
|
||||||
depends on ESP_TLS_SERVER && ESP_TLS_USING_MBEDTLS
|
depends on ESP_TLS_SERVER && ESP_TLS_USING_MBEDTLS
|
||||||
|
@ -197,6 +197,18 @@ typedef struct esp_tls_server_session_ticket_ctx {
|
|||||||
} esp_tls_server_session_ticket_ctx_t;
|
} esp_tls_server_session_ticket_ctx_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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, etc.
|
||||||
|
*
|
||||||
|
* @param ssl mbedtls_ssl_context that can be used for changing settings
|
||||||
|
* @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 mbedtls_ssl_hs_cb_t esp_tls_handshake_callback;
|
||||||
|
|
||||||
typedef struct esp_tls_cfg_server {
|
typedef struct esp_tls_cfg_server {
|
||||||
const char **alpn_protos; /*!< Application protocols required for HTTP2.
|
const char **alpn_protos; /*!< Application protocols required for HTTP2.
|
||||||
If HTTP2/ALPN support is required, a list
|
If HTTP2/ALPN support is required, a list
|
||||||
@ -259,6 +271,15 @@ typedef struct esp_tls_cfg_server {
|
|||||||
Call esp_tls_cfg_server_session_tickets_free
|
Call esp_tls_cfg_server_session_tickets_free
|
||||||
to free the data associated with this context. */
|
to free the data associated with this context. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void *userdata; /*!< User data to be added to the ssl context.
|
||||||
|
Can be retrieved by callbacks */
|
||||||
|
#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
|
||||||
|
|
||||||
} esp_tls_cfg_server_t;
|
} esp_tls_cfg_server_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -512,12 +512,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;
|
return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_set_user_data_p(&tls->conf, cfg->userdata);
|
||||||
|
|
||||||
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
||||||
if (cfg->alpn_protos) {
|
if (cfg->alpn_protos) {
|
||||||
mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos);
|
mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
|
||||||
|
if (cfg->cert_select_cb != NULL) {
|
||||||
|
ESP_LOGI(TAG, "Initializing server side cert selection cb");
|
||||||
|
mbedtls_ssl_conf_cert_cb(&tls->conf, cfg->cert_select_cb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (cfg->cacert_buf != NULL) {
|
if (cfg->cacert_buf != NULL) {
|
||||||
esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
|
esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
|
||||||
if (esp_ret != ESP_OK) {
|
if (esp_ret != ESP_OK) {
|
||||||
@ -569,7 +578,17 @@ esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
|
|||||||
return esp_ret;
|
return esp_ret;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
|
||||||
|
if (cfg->cert_select_cb == NULL) {
|
||||||
|
ESP_LOGE(TAG, "No cert select cb is defined");
|
||||||
|
} else {
|
||||||
|
/* At this point Callback MUST ALWAYS call mbedtls_ssl_set_hs_own_cert, or the handshake will abort! */
|
||||||
|
ESP_LOGD(TAG, "Missing server cert and/or key, but cert selection cb is defined.");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#else
|
||||||
ESP_LOGE(TAG, "Missing server certificate and/or key");
|
ESP_LOGE(TAG, "Missing server certificate and/or key");
|
||||||
|
#endif
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,6 +809,7 @@ int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp
|
|||||||
tls->conn_state = ESP_TLS_FAIL;
|
tls->conn_state = ESP_TLS_FAIL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls->read = esp_mbedtls_read;
|
tls->read = esp_mbedtls_read;
|
||||||
tls->write = esp_mbedtls_write;
|
tls->write = esp_mbedtls_write;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -96,6 +96,9 @@ struct httpd_ssl_config {
|
|||||||
|
|
||||||
/** User callback for esp_https_server */
|
/** User callback for esp_https_server */
|
||||||
esp_https_server_user_cb *user_cb;
|
esp_https_server_user_cb *user_cb;
|
||||||
|
|
||||||
|
void *ssl_userdata; /*!< user data to add to the ssl context */
|
||||||
|
esp_tls_handshake_callback cert_select_cb; /*!< Certificate selection callback to use */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct httpd_ssl_config httpd_ssl_config_t;
|
typedef struct httpd_ssl_config httpd_ssl_config_t;
|
||||||
@ -145,6 +148,8 @@ typedef struct httpd_ssl_config httpd_ssl_config_t;
|
|||||||
.session_tickets = false, \
|
.session_tickets = false, \
|
||||||
.use_secure_element = false, \
|
.use_secure_element = false, \
|
||||||
.user_cb = NULL, \
|
.user_cb = NULL, \
|
||||||
|
.ssl_userdata = NULL, \
|
||||||
|
.cert_select_cb = NULL \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,65 +200,98 @@ 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));
|
esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)calloc(1, sizeof(esp_tls_cfg_server_t));
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
free(ssl_ctx);
|
goto exit;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->session_tickets) {
|
if (config->session_tickets) {
|
||||||
if ( esp_tls_cfg_server_session_tickets_init(cfg) != ESP_OK ) {
|
if ( esp_tls_cfg_server_session_tickets_init(cfg) != ESP_OK ) {
|
||||||
ESP_LOGE(TAG, "Failed to init session ticket support");
|
ESP_LOGE(TAG, "Failed to init session ticket support");
|
||||||
free(ssl_ctx);
|
goto exit;
|
||||||
free(cfg);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
ssl_ctx->tls_cfg = cfg;
|
||||||
ssl_ctx->user_cb = config->user_cb;
|
ssl_ctx->user_cb = config->user_cb;
|
||||||
|
|
||||||
/* cacert = CA which signs client cert, or client cert itself */
|
/* cacert = CA which signs client cert, or client cert itself */
|
||||||
if(config->cacert_pem != NULL) {
|
if (config->cacert_pem != NULL && config->cacert_len > 0) {
|
||||||
cfg->cacert_buf = (unsigned char *)malloc(config->cacert_len);
|
cfg->cacert_buf = (unsigned char *)malloc(config->cacert_len);
|
||||||
if (!cfg->cacert_buf) {
|
|
||||||
ESP_LOGE(TAG, "Could not allocate memory");
|
if (cfg->cacert_buf) {
|
||||||
free(cfg);
|
memcpy((char *) cfg->cacert_buf, config->cacert_pem, config->cacert_len);
|
||||||
free(ssl_ctx);
|
cfg->cacert_bytes = config->cacert_len;
|
||||||
return NULL;
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Could not allocate memory for client certificate authority");
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
memcpy((char *)cfg->cacert_buf, config->cacert_pem, config->cacert_len);
|
|
||||||
cfg->cacert_bytes = config->cacert_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* servercert = cert of server itself */
|
/* servercert = cert of server itself */
|
||||||
cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);
|
if (config->servercert != NULL && config->servercert_len > 0) {
|
||||||
if (!cfg->servercert_buf) {
|
cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);
|
||||||
ESP_LOGE(TAG, "Could not allocate memory");
|
|
||||||
free((void *)cfg->cacert_buf);
|
if (cfg->servercert_buf) {
|
||||||
free(cfg);
|
memcpy((char *) cfg->servercert_buf, config->servercert, config->servercert_len);
|
||||||
free(ssl_ctx);
|
cfg->servercert_bytes = config->servercert_len;
|
||||||
return NULL;
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Could not allocate memory for server certificate");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
|
||||||
|
if (config->cert_select_cb == NULL) {
|
||||||
|
#endif
|
||||||
|
ESP_LOGE(TAG, "No Server certificate supplied");
|
||||||
|
goto exit;
|
||||||
|
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "Server certificate not supplied, make sure to supply it in the certificate selection hook!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
memcpy((char *)cfg->servercert_buf, config->servercert, config->servercert_len);
|
|
||||||
cfg->servercert_bytes = config->servercert_len;
|
|
||||||
|
|
||||||
/* Pass on secure element boolean */
|
/* Pass on secure element boolean */
|
||||||
cfg->use_secure_element = config->use_secure_element;
|
cfg->use_secure_element = config->use_secure_element;
|
||||||
if (!cfg->use_secure_element) {
|
if (!cfg->use_secure_element) {
|
||||||
cfg->serverkey_buf = (unsigned char *)malloc(config->prvtkey_len);
|
if (config->prvtkey_pem != NULL && config->prvtkey_len > 0) {
|
||||||
if (!cfg->serverkey_buf) {
|
cfg->serverkey_buf = malloc(config->prvtkey_len);
|
||||||
ESP_LOGE(TAG, "Could not allocate memory");
|
|
||||||
free((void *)cfg->servercert_buf);
|
if (cfg->serverkey_buf) {
|
||||||
free((void *)cfg->cacert_buf);
|
memcpy((char *) cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
|
||||||
free(cfg);
|
cfg->serverkey_bytes = config->prvtkey_len;
|
||||||
free(ssl_ctx);
|
} else {
|
||||||
return NULL;
|
ESP_LOGE(TAG, "Could not allocate memory for server key");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#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 exit;
|
||||||
|
} else {
|
||||||
|
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");
|
||||||
|
goto exit;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy((char *)cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
|
|
||||||
cfg->serverkey_bytes = config->prvtkey_len;
|
|
||||||
|
|
||||||
return ssl_ctx;
|
return ssl_ctx;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
free((void *) cfg->servercert_buf);
|
||||||
|
free((void *) cfg->cacert_buf);
|
||||||
|
free(cfg);
|
||||||
|
free(ssl_ctx);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start the server */
|
/** Start the server */
|
||||||
|
@ -57,6 +57,23 @@ The ESP-TLS provides multiple options for TLS server verification on the client
|
|||||||
* **skip server verification**: This is an insecure option provided in the ESP-TLS for testing purpose. The option can be set by enabling :ref:`CONFIG_ESP_TLS_INSECURE` and :ref:`CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY` in the ESP-TLS menuconfig. When this option is enabled the ESP-TLS will skip server verification by default when no other options for server verification are selected in the :cpp:type:`esp_tls_cfg_t` structure.
|
* **skip server verification**: This is an insecure option provided in the ESP-TLS for testing purpose. The option can be set by enabling :ref:`CONFIG_ESP_TLS_INSECURE` and :ref:`CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY` in the ESP-TLS menuconfig. When this option is enabled the ESP-TLS will skip server verification by default when no other options for server verification are selected in the :cpp:type:`esp_tls_cfg_t` structure.
|
||||||
*WARNING:Enabling this option comes with a potential risk of establishing a TLS connection with a server which has a fake identity, provided that the server certificate is not provided either through API or other mechanism like ca_store etc.*
|
*WARNING:Enabling this option comes with a potential risk of establishing a TLS connection with a server which has a fake identity, provided that the server certificate is not provided either through API or other mechanism like ca_store etc.*
|
||||||
|
|
||||||
|
ESP-TLS Server cert selection hook
|
||||||
|
----------------------------------
|
||||||
|
The ESP-TLS component provides an option to set the server cert selection hook when using the mbedTLS stack. This provides an 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). To enable this feature, please enable :ref:`CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK` in the ESP-TLS menuconfig.
|
||||||
|
The certificate selection callback can be configured in the :cpp:type:`esp_tls_cfg_t` structure as follows:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int cert_selection_callback(mbedtls_ssl_context *ssl)
|
||||||
|
{
|
||||||
|
/* Code that the callback should execute */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_tls_cfg_t cfg = {
|
||||||
|
cert_select_cb = cert_section_callback,
|
||||||
|
};
|
||||||
|
|
||||||
.. _esp_tls_wolfssl:
|
.. _esp_tls_wolfssl:
|
||||||
|
|
||||||
Underlying SSL/TLS Library Options
|
Underlying SSL/TLS Library Options
|
||||||
|
Loading…
Reference in New Issue
Block a user