Skip to content

Commit 4b6d9c8

Browse files
committed
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 #9815 See merge request espressif/esp-idf!20690
2 parents 4c8f4ff + 14e6478 commit 4b6d9c8

File tree

6 files changed

+138
-33
lines changed

6 files changed

+138
-33
lines changed

components/esp-tls/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ menu "ESP-TLS"
4040

4141
config ESP_TLS_SERVER
4242
bool "Enable ESP-TLS Server"
43+
depends on (ESP_TLS_USING_MBEDTLS && MBEDTLS_TLS_SERVER) || ESP_TLS_USING_WOLFSSL
4344
help
4445
Enable support for creating server side SSL/TLS session, available for mbedTLS
4546
as well as wolfSSL TLS library.
@@ -57,6 +58,14 @@ menu "ESP-TLS"
5758
help
5859
Sets the session ticket timeout used in the tls server.
5960

61+
config ESP_TLS_SERVER_CERT_SELECT_HOOK
62+
bool "Certificate selection hook"
63+
depends on ESP_TLS_USING_MBEDTLS && ESP_TLS_SERVER
64+
help
65+
Ability to configure and use a certificate selection callback during server handshake,
66+
to select a certificate to present to the client based on the TLS extensions supplied in
67+
the client hello (alpn, sni, etc).
68+
6069
config ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
6170
bool "ESP-TLS Server: Set minimum Certificate Verification mode to Optional"
6271
depends on ESP_TLS_SERVER && ESP_TLS_USING_MBEDTLS

components/esp-tls/esp_tls.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,18 @@ typedef struct esp_tls_server_session_ticket_ctx {
197197
} esp_tls_server_session_ticket_ctx_t;
198198
#endif
199199

200+
201+
/**
202+
* @brief tls handshake callback
203+
* Can be used to configure per-handshake attributes for the TLS connection.
204+
* E.g. Client certificate / Key, Authmode, Client CA verification, etc.
205+
*
206+
* @param ssl mbedtls_ssl_context that can be used for changing settings
207+
* @return The reutn value of the callback must be 0 if successful,
208+
* or a specific MBEDTLS_ERR_XXX code, which will cause the handhsake to abort
209+
*/
210+
typedef mbedtls_ssl_hs_cb_t esp_tls_handshake_callback;
211+
200212
typedef struct esp_tls_cfg_server {
201213
const char **alpn_protos; /*!< Application protocols required for HTTP2.
202214
If HTTP2/ALPN support is required, a list
@@ -259,6 +271,15 @@ typedef struct esp_tls_cfg_server {
259271
Call esp_tls_cfg_server_session_tickets_free
260272
to free the data associated with this context. */
261273
#endif
274+
275+
void *userdata; /*!< User data to be added to the ssl context.
276+
Can be retrieved by callbacks */
277+
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
278+
esp_tls_handshake_callback cert_select_cb; /*!< Certificate selection callback that gets called after ClientHello is processed.
279+
Can be used as an SNI callback, but also has access to other
280+
TLS extensions, such as ALPN and server_certificate_type . */
281+
#endif
282+
262283
} esp_tls_cfg_server_t;
263284

264285
/**

components/esp-tls/esp_tls_mbedtls.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,12 +512,21 @@ esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
512512
return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED;
513513
}
514514

515+
mbedtls_ssl_conf_set_user_data_p(&tls->conf, cfg->userdata);
516+
515517
#ifdef CONFIG_MBEDTLS_SSL_ALPN
516518
if (cfg->alpn_protos) {
517519
mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos);
518520
}
519521
#endif
520522

523+
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
524+
if (cfg->cert_select_cb != NULL) {
525+
ESP_LOGI(TAG, "Initializing server side cert selection cb");
526+
mbedtls_ssl_conf_cert_cb(&tls->conf, cfg->cert_select_cb);
527+
}
528+
#endif
529+
521530
if (cfg->cacert_buf != NULL) {
522531
esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
523532
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)
569578
return esp_ret;
570579
}
571580
} else {
581+
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
582+
if (cfg->cert_select_cb == NULL) {
583+
ESP_LOGE(TAG, "No cert select cb is defined");
584+
} else {
585+
/* At this point Callback MUST ALWAYS call mbedtls_ssl_set_hs_own_cert, or the handshake will abort! */
586+
ESP_LOGD(TAG, "Missing server cert and/or key, but cert selection cb is defined.");
587+
return ESP_OK;
588+
}
589+
#else
572590
ESP_LOGE(TAG, "Missing server certificate and/or key");
591+
#endif
573592
return ESP_ERR_INVALID_STATE;
574593
}
575594

@@ -790,6 +809,7 @@ int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp
790809
tls->conn_state = ESP_TLS_FAIL;
791810
return -1;
792811
}
812+
793813
tls->read = esp_mbedtls_read;
794814
tls->write = esp_mbedtls_write;
795815
int ret;

components/esp_https_server/include/esp_https_server.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ struct httpd_ssl_config {
9696

9797
/** User callback for esp_https_server */
9898
esp_https_server_user_cb *user_cb;
99+
100+
void *ssl_userdata; /*!< user data to add to the ssl context */
101+
esp_tls_handshake_callback cert_select_cb; /*!< Certificate selection callback to use */
99102
};
100103

101104
typedef struct httpd_ssl_config httpd_ssl_config_t;
@@ -145,6 +148,8 @@ typedef struct httpd_ssl_config httpd_ssl_config_t;
145148
.session_tickets = false, \
146149
.use_secure_element = false, \
147150
.user_cb = NULL, \
151+
.ssl_userdata = NULL, \
152+
.cert_select_cb = NULL \
148153
}
149154

150155
/**

components/esp_https_server/src/https_server.c

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -200,65 +200,98 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con
200200
}
201201
esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)calloc(1, sizeof(esp_tls_cfg_server_t));
202202
if (!cfg) {
203-
free(ssl_ctx);
204-
return NULL;
203+
goto exit;
205204
}
206205

207206
if (config->session_tickets) {
208207
if ( esp_tls_cfg_server_session_tickets_init(cfg) != ESP_OK ) {
209208
ESP_LOGE(TAG, "Failed to init session ticket support");
210-
free(ssl_ctx);
211-
free(cfg);
212-
return NULL;
209+
goto exit;
213210
}
214211
}
215212

213+
cfg->userdata = config->ssl_userdata;
214+
215+
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
216+
cfg->cert_select_cb = config->cert_select_cb;
217+
#endif
218+
216219
ssl_ctx->tls_cfg = cfg;
217220
ssl_ctx->user_cb = config->user_cb;
218221

219222
/* cacert = CA which signs client cert, or client cert itself */
220-
if(config->cacert_pem != NULL) {
223+
if (config->cacert_pem != NULL && config->cacert_len > 0) {
221224
cfg->cacert_buf = (unsigned char *)malloc(config->cacert_len);
222-
if (!cfg->cacert_buf) {
223-
ESP_LOGE(TAG, "Could not allocate memory");
224-
free(cfg);
225-
free(ssl_ctx);
226-
return NULL;
225+
226+
if (cfg->cacert_buf) {
227+
memcpy((char *) cfg->cacert_buf, config->cacert_pem, config->cacert_len);
228+
cfg->cacert_bytes = config->cacert_len;
229+
} else {
230+
ESP_LOGE(TAG, "Could not allocate memory for client certificate authority");
231+
goto exit;
227232
}
228-
memcpy((char *)cfg->cacert_buf, config->cacert_pem, config->cacert_len);
229-
cfg->cacert_bytes = config->cacert_len;
230233
}
231234

232235
/* servercert = cert of server itself */
233-
cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);
234-
if (!cfg->servercert_buf) {
235-
ESP_LOGE(TAG, "Could not allocate memory");
236-
free((void *)cfg->cacert_buf);
237-
free(cfg);
238-
free(ssl_ctx);
239-
return NULL;
236+
if (config->servercert != NULL && config->servercert_len > 0) {
237+
cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);
238+
239+
if (cfg->servercert_buf) {
240+
memcpy((char *) cfg->servercert_buf, config->servercert, config->servercert_len);
241+
cfg->servercert_bytes = config->servercert_len;
242+
} else {
243+
ESP_LOGE(TAG, "Could not allocate memory for server certificate");
244+
goto exit;
245+
}
246+
} else {
247+
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
248+
if (config->cert_select_cb == NULL) {
249+
#endif
250+
ESP_LOGE(TAG, "No Server certificate supplied");
251+
goto exit;
252+
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
253+
} else {
254+
ESP_LOGW(TAG, "Server certificate not supplied, make sure to supply it in the certificate selection hook!");
255+
}
256+
#endif
240257
}
241-
memcpy((char *)cfg->servercert_buf, config->servercert, config->servercert_len);
242-
cfg->servercert_bytes = config->servercert_len;
243258

244259
/* Pass on secure element boolean */
245260
cfg->use_secure_element = config->use_secure_element;
246261
if (!cfg->use_secure_element) {
247-
cfg->serverkey_buf = (unsigned char *)malloc(config->prvtkey_len);
248-
if (!cfg->serverkey_buf) {
249-
ESP_LOGE(TAG, "Could not allocate memory");
250-
free((void *)cfg->servercert_buf);
251-
free((void *)cfg->cacert_buf);
252-
free(cfg);
253-
free(ssl_ctx);
254-
return NULL;
262+
if (config->prvtkey_pem != NULL && config->prvtkey_len > 0) {
263+
cfg->serverkey_buf = malloc(config->prvtkey_len);
264+
265+
if (cfg->serverkey_buf) {
266+
memcpy((char *) cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
267+
cfg->serverkey_bytes = config->prvtkey_len;
268+
} else {
269+
ESP_LOGE(TAG, "Could not allocate memory for server key");
270+
goto exit;
271+
}
272+
} else {
273+
#if defined(CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK)
274+
if (config->cert_select_cb == NULL) {
275+
ESP_LOGE(TAG, "No Server key supplied and no certificate selection hook is present");
276+
goto exit;
277+
} else {
278+
ESP_LOGW(TAG, "Server key not supplied, make sure to supply it in the certificate selection hook");
279+
}
280+
#else
281+
ESP_LOGE(TAG, "No Server key supplied");
282+
goto exit;
283+
#endif
255284
}
256285
}
257286

258-
memcpy((char *)cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
259-
cfg->serverkey_bytes = config->prvtkey_len;
260-
261287
return ssl_ctx;
288+
289+
exit:
290+
free((void *) cfg->servercert_buf);
291+
free((void *) cfg->cacert_buf);
292+
free(cfg);
293+
free(ssl_ctx);
294+
return NULL;
262295
}
263296

264297
/** Start the server */

docs/en/api-reference/protocols/esp_tls.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,23 @@ The ESP-TLS provides multiple options for TLS server verification on the client
5757
* **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.
5858
*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.*
5959

60+
ESP-TLS Server cert selection hook
61+
----------------------------------
62+
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.
63+
The certificate selection callback can be configured in the :cpp:type:`esp_tls_cfg_t` structure as follows:
64+
65+
.. code-block:: c
66+
67+
int cert_selection_callback(mbedtls_ssl_context *ssl)
68+
{
69+
/* Code that the callback should execute */
70+
return 0;
71+
}
72+
73+
esp_tls_cfg_t cfg = {
74+
cert_select_cb = cert_section_callback,
75+
};
76+
6077
.. _esp_tls_wolfssl:
6178

6279
Underlying SSL/TLS Library Options

0 commit comments

Comments
 (0)