Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add sni support (IDFGH-8363) #9833

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions components/esp-tls/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ menu "ESP-TLS"
help
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
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
bool "ESP-TLS Server: Set minimum Certificate Verification mode to Optional"
depends on ESP_TLS_SERVER && ESP_TLS_USING_MBEDTLS
Expand Down
22 changes: 22 additions & 0 deletions components/esp-tls/esp_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,20 @@ 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 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;
#endif

typedef struct esp_tls_cfg_server {
const char **alpn_protos; /*!< Application protocols required for HTTP2.
If HTTP2/ALPN support is required, a list
Expand Down Expand Up @@ -259,6 +273,14 @@ typedef struct esp_tls_cfg_server {
Call esp_tls_cfg_server_session_tickets_free
to free the data associated with this context. */
#endif

#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;

/**
Expand Down
19 changes: 19 additions & 0 deletions components/esp-tls/esp_tls_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -566,7 +575,16 @@ 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_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 certificate selection callback is defined. Callback MUST ALWAYS call mbedtls_ssl_set_hs_own_cert, or the handshake will abort!");
return ESP_OK;
}
#else
ESP_LOGE(TAG, "Missing server certificate and/or key");
#endif
return ESP_ERR_INVALID_STATE;
}

Expand Down Expand Up @@ -787,6 +805,7 @@ int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp
tls->conn_state = ESP_TLS_FAIL;
return -1;
}

tls->read = esp_mbedtls_read;
tls->write = esp_mbedtls_write;
int ret;
Expand Down
5 changes: 5 additions & 0 deletions components/esp_https_server/include/esp_https_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ struct httpd_ssl_config {

/** User callback for esp_https_server */
esp_https_server_user_cb *user_cb;

#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;
Expand Down
102 changes: 69 additions & 33 deletions components/esp_https_server/src/https_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,65 +200,101 @@ 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;
}
}

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->user_cb = config->user_cb;

/* 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);
if (!cfg->cacert_buf) {
ESP_LOGE(TAG, "Could not allocate memory");
free(cfg);
free(ssl_ctx);
return NULL;

if (cfg->cacert_buf) {
memcpy((char *) cfg->cacert_buf, config->cacert_pem, config->cacert_len);
cfg->cacert_bytes = config->cacert_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for client certificate authority");
goto free_cfg;
}
memcpy((char *)cfg->cacert_buf, config->cacert_pem, config->cacert_len);
cfg->cacert_bytes = config->cacert_len;
}

/* servercert = cert of server itself */
cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);
if (!cfg->servercert_buf) {
ESP_LOGE(TAG, "Could not allocate memory");
free((void *)cfg->cacert_buf);
free(cfg);
free(ssl_ctx);
return NULL;
if (config->servercert != NULL && config->servercert_len > 0) {
cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);

if (cfg->servercert_buf) {
memcpy((char *) cfg->servercert_buf, config->servercert, config->servercert_len);
cfg->servercert_bytes = config->servercert_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for server certificate");
goto free_cacert;
}
} 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 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 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 */
cfg->use_secure_element = config->use_secure_element;
if (!cfg->use_secure_element) {
cfg->serverkey_buf = (unsigned char *)malloc(config->prvtkey_len);
if (!cfg->serverkey_buf) {
ESP_LOGE(TAG, "Could not allocate memory");
free((void *)cfg->servercert_buf);
free((void *)cfg->cacert_buf);
free(cfg);
free(ssl_ctx);
return NULL;
if (config->prvtkey_pem != NULL && config->prvtkey_len > 0) {
cfg->serverkey_buf = (unsigned char *) malloc(config->prvtkey_len);

if (cfg->serverkey_buf) {
memcpy((char *) cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
cfg->serverkey_bytes = config->prvtkey_len;
} else {
ESP_LOGE(TAG, "Could not allocate memory for server key");
goto free_servercert;
}
} 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 free_servercert;
} 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 free_servercert;
#endif
}
}

memcpy((char *)cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
cfg->serverkey_bytes = config->prvtkey_len;

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 */
Expand Down