Skip to content

Commit

Permalink
add sni support
Browse files Browse the repository at this point in the history
  • Loading branch information
axos88 committed Sep 26, 2022
1 parent 09f7589 commit b1c5f53
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 19 deletions.
7 changes: 7 additions & 0 deletions components/esp-tls/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +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"
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.

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
19 changes: 19 additions & 0 deletions components/esp-tls/esp_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,24 @@ esp_err_t esp_tls_cfg_server_session_tickets_init(esp_tls_cfg_server_t *cfg)
#endif
}

#ifdef CONFIG_ESP_TLS_SERVER
esp_err_t esp_tls_cfg_server_sni_init(esp_tls_cfg_server_t *cfg, esp_tls_server_sni_callback *cb, void *data)
{
#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK)
if (!cfg) {
return ESP_ERR_INVALID_ARG;
}
cfg->sni_callback = cb;
cfg->sni_callback_p_info = data;

return ESP_OK;
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
#endif

#ifdef CONFIG_ESP_TLS_SERVER
void esp_tls_cfg_server_session_tickets_free(esp_tls_cfg_server_t *cfg)
{
#if defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS)
Expand All @@ -602,6 +620,7 @@ void esp_tls_cfg_server_session_tickets_free(esp_tls_cfg_server_t *cfg)
}
#endif
}
#endif

/**
* @brief Create a server side TLS/SSL connection
Expand Down
36 changes: 36 additions & 0 deletions components/esp-tls/esp_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,18 @@ typedef struct esp_tls_server_session_ticket_ctx {
} esp_tls_server_session_ticket_ctx_t;
#endif

/**
* @brief SNI callback function prototype
* Can be used to configure per-handshake attributes for the TLS connection.
* E.g. Client certificate / Key, Authmode, Client CA verification
*
* @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
*/
typedef int esp_tls_server_sni_callback(void *p_info, mbedtls_ssl_context *ssl, const unsigned char *name, size_t name_len);

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 +271,11 @@ 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_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. */
#endif
} esp_tls_cfg_server_t;

/**
Expand All @@ -279,6 +296,25 @@ typedef struct esp_tls_cfg_server {
*/
esp_err_t esp_tls_cfg_server_session_tickets_init(esp_tls_cfg_server_t *cfg);

/**
* @brief Initialize the server side TLS server name identification hook
*
* This function initializes the server side tls server name identification hook
* which is called during a client connect handshake, and has the ability to check
* the advertised hostname and supply a specific certificate based on that for example.
* Check https://mbed-tls.readthedocs.io/en/latest/kb/how-to/use-sni/#server-side for details.
*
* @param[in] cfg server configuration as esp_tls_cfg_server_t
* @param[in] cb callback function pointer
* @param[in] data pointer to implementation specific data supplied as the first parameter of the callback
* @return
* ESP_OK if setup succeeded
* ESP_ERR_INVALID_ARG if context is NULL
* ESP_ERR_NOT_SUPPORTED if server side sni is not available due to build configuration
* ESP_FAIL if setup failed
*/
esp_err_t esp_tls_cfg_server_sni_init(esp_tls_cfg_server_t *cfg, esp_tls_server_sni_callback *cb, void *data);

/**
* @brief Free the server side TLS session ticket context
*
Expand Down
17 changes: 17 additions & 0 deletions components/esp-tls/esp_tls_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,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_SNI_HOOK)
if ((cfg->sni_callback == NULL)) {
ESP_LOGE(TAG, "Missing server certificate and/or key and no SNI 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!");
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 +796,14 @@ int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp
tls->conn_state = ESP_TLS_FAIL;
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;
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_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. */
#endif
};

typedef struct httpd_ssl_config httpd_ssl_config_t;
Expand Down
87 changes: 68 additions & 19 deletions components/esp_https_server/src/https_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,51 +213,100 @@ static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *con
}
}

#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK)
if (config->sni_callback) {
if (esp_tls_cfg_server_sni_init(cfg, config->sni_callback, config->sni_callback_p_info) != ESP_OK) {
ESP_LOGE(TAG, "Failed to init server side SNI");
free(ssl_ctx);
free(cfg);
return NULL;
};
}
#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");

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");
free(cfg);
free(ssl_ctx);
return NULL;
}
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);
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");
free((void *) cfg->cacert_buf);
free(cfg);
free(ssl_ctx);
return NULL;
}
} else {
#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK)
if (config->sni_callback == 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)
} else {
ESP_LOGW(TAG, "Server certificate not supplied, make sure to supply it in the SNI 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);
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");
free((void *) cfg->servercert_buf);
free((void *) cfg->cacert_buf);
free(cfg);
free(ssl_ctx);
return NULL;
}
} else {
#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK)
if (config->sni_callback == NULL) {
#endif
ESP_LOGE(TAG, "No Server key supplied");
free((void *) cfg->servercert_buf);
free((void *) cfg->cacert_buf);
free(cfg);
free(ssl_ctx);
return NULL;
#if defined(CONFIG_ESP_TLS_SERVER_SNI_HOOK)
} else {
ESP_LOGW(TAG, "Server key not supplied, make sure to supply it in the SNI hook!");
}
#endif
}
}

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

return ssl_ctx;
}

Expand Down

0 comments on commit b1c5f53

Please sign in to comment.