From 1d71fbae922594dee01d2b8c4c1ec6c5bed69adc Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Tue, 29 Mar 2022 11:38:34 +0530 Subject: [PATCH] https_server: Add provision for callback at session close Closes https://github.com/espressif/esp-idf/issues/8288 --- .../include/esp_https_server.h | 11 +++ .../esp_https_server/src/https_server.c | 46 +++++++++++-- .../protocols/https_server/simple/main/main.c | 67 ++++++++++++------- 3 files changed, 95 insertions(+), 29 deletions(-) diff --git a/components/esp_https_server/include/esp_https_server.h b/components/esp_https_server/include/esp_https_server.h index d0db2bf739..7a5cb8fd37 100644 --- a/components/esp_https_server/include/esp_https_server.h +++ b/components/esp_https_server/include/esp_https_server.h @@ -21,10 +21,21 @@ typedef enum { HTTPD_SSL_TRANSPORT_INSECURE // SSL disabled } httpd_ssl_transport_mode_t; +/** + * @brief Indicates the state at which the user callback is executed, + * i.e at session creation or session close + */ +typedef enum { + HTTPD_SSL_USER_CB_SESS_CREATE, + HTTPD_SSL_USER_CB_SESS_CLOSE +} httpd_ssl_user_cb_state_t; + /** * @brief Callback data struct, contains the ESP-TLS connection handle + * and the connection state at which the callback is executed */ typedef struct esp_https_server_user_cb_arg { + httpd_ssl_user_cb_state_t user_cb_state; const esp_tls_t *tls; } esp_https_server_user_cb_arg_t; diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c index 0285ad521a..6fd7218c56 100644 --- a/components/esp_https_server/src/https_server.c +++ b/components/esp_https_server/src/https_server.c @@ -18,6 +18,11 @@ typedef struct httpd_ssl_ctx { esp_https_server_user_cb *user_cb; } httpd_ssl_ctx_t; +typedef struct httpd_ssl_transport_ctx { + esp_tls_t *tls; + httpd_ssl_ctx_t *global_ctx; +} httpd_ssl_transport_ctx_t; + /** * SSL socket close handler * @@ -26,7 +31,20 @@ typedef struct httpd_ssl_ctx { static void httpd_ssl_close(void *ctx) { assert(ctx != NULL); - esp_tls_server_session_delete(ctx); + + httpd_ssl_transport_ctx_t *transport_ctx = (httpd_ssl_transport_ctx_t *)ctx; + httpd_ssl_ctx_t *global_ctx = transport_ctx->global_ctx; + esp_tls_t *tls = transport_ctx->tls; + + if (global_ctx->user_cb) { + esp_https_server_user_cb_arg_t user_cb_data = {0}; + user_cb_data.user_cb_state = HTTPD_SSL_USER_CB_SESS_CLOSE; + user_cb_data.tls = tls; + (global_ctx->user_cb)((void *)&user_cb_data); + } + + esp_tls_server_session_delete(tls); + free(ctx); ESP_LOGD(TAG, "Secure socket closed"); } @@ -39,7 +57,9 @@ static void httpd_ssl_close(void *ctx) */ static int httpd_ssl_pending(httpd_handle_t server, int sockfd) { - esp_tls_t *tls = httpd_sess_get_transport_ctx(server, sockfd); + httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd); + assert(transport_ctx != NULL); + esp_tls_t *tls = transport_ctx->tls; assert(tls != NULL); return esp_tls_get_bytes_avail(tls); } @@ -56,7 +76,9 @@ static int httpd_ssl_pending(httpd_handle_t server, int sockfd) */ static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags) { - esp_tls_t *tls = httpd_sess_get_transport_ctx(server, sockfd); + httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd); + assert(transport_ctx != NULL); + esp_tls_t *tls = transport_ctx->tls; assert(tls != NULL); return esp_tls_conn_read(tls, buf, buf_len); } @@ -73,7 +95,9 @@ static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t b */ static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, size_t buf_len, int flags) { - esp_tls_t *tls = httpd_sess_get_transport_ctx(server, sockfd); + httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd); + assert(transport_ctx != NULL); + esp_tls_t *tls = transport_ctx->tls; assert(tls != NULL); return esp_tls_conn_write(tls, buf, buf_len); } @@ -105,8 +129,18 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd) goto fail; } + // Pass a new structure containing the global context and the tls pointer to httpd_ssl_close + // Store it in the context field of the HTTPD session object + // NOTE: allocated memory will be freed by httpd_ssl_close + httpd_ssl_transport_ctx_t *transport_ctx = (httpd_ssl_transport_ctx_t *)calloc(1, sizeof(httpd_ssl_transport_ctx_t)); + if (!transport_ctx) { + return ESP_ERR_NO_MEM; + } + transport_ctx->tls = tls; + transport_ctx->global_ctx = global_ctx; + // Store the SSL session into the context field of the HTTPD session object - httpd_sess_set_transport_ctx(server, sockfd, tls, httpd_ssl_close); + httpd_sess_set_transport_ctx(server, sockfd, transport_ctx, httpd_ssl_close); // Set rx/tx/pending override functions httpd_sess_set_send_override(server, sockfd, httpd_ssl_send); @@ -114,7 +148,6 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd) httpd_sess_set_pending_override(server, sockfd, httpd_ssl_pending); // all access should now go through SSL - ESP_LOGD(TAG, "Secure socket open"); if (global_ctx->open_fn) { @@ -123,6 +156,7 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd) if (global_ctx->user_cb) { esp_https_server_user_cb_arg_t user_cb_data = {0}; + user_cb_data.user_cb_state = HTTPD_SSL_USER_CB_SESS_CREATE; user_cb_data.tls = tls; (global_ctx->user_cb)((void *)&user_cb_data); } diff --git a/examples/protocols/https_server/simple/main/main.c b/examples/protocols/https_server/simple/main/main.c index 8d4c852c1d..6aca0a8f25 100644 --- a/examples/protocols/https_server/simple/main/main.c +++ b/examples/protocols/https_server/simple/main/main.c @@ -36,9 +36,32 @@ static esp_err_t root_get_handler(httpd_req_t *req) } #if CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK + +void print_peer_cert_info(const mbedtls_ssl_context *ssl) +{ + const mbedtls_x509_crt *cert; + const size_t buf_size = 1024; + char *buf = calloc(buf_size, sizeof(char)); + if (buf == NULL) { + ESP_LOGE(TAG, "Out of memory - Callback execution failed!"); + return; + } + + // Logging the peer certificate info + cert = mbedtls_ssl_get_peer_cert(ssl); + if (cert != NULL) { + mbedtls_x509_crt_info((char *) buf, buf_size - 1, " ", cert); + ESP_LOGI(TAG, "Peer certificate info:\n%s", buf); + } else { + ESP_LOGW(TAG, "Could not obtain the peer certificate!"); + } + + free(buf); +} + /** * Example callback function to get the certificate of connected clients, - * whenever a new SSL connection is created + * whenever a new SSL connection is created and closed * * Can also be used to other information like Socket FD, Connection state, etc. * @@ -51,30 +74,28 @@ static esp_err_t root_get_handler(httpd_req_t *req) */ void https_server_user_callback(esp_https_server_user_cb_arg_t *user_cb) { - ESP_LOGI(TAG, "Session Created!"); - ESP_LOGI(TAG, "Socket FD: %d", user_cb->tls->sockfd); + ESP_LOGI(TAG, "User callback invoked!"); - const mbedtls_x509_crt *cert; - const size_t buf_size = 1024; - char *buf = calloc(buf_size, sizeof(char)); - if (buf == NULL) { - ESP_LOGE(TAG, "Out of memory - Callback execution failed!"); - return; + switch(user_cb->user_cb_state) { + case HTTPD_SSL_USER_CB_SESS_CREATE: + ESP_LOGD(TAG, "At session creation"); + + // Logging the socket FD + ESP_LOGI(TAG, "Socket FD: %d", user_cb->tls->sockfd); + + // Logging the current ciphersuite + ESP_LOGI(TAG, "Current Ciphersuite: %s", mbedtls_ssl_get_ciphersuite(&user_cb->tls->ssl)); + break; + case HTTPD_SSL_USER_CB_SESS_CLOSE: + ESP_LOGD(TAG, "At session close"); + + // Logging the peer certificate + print_peer_cert_info(&user_cb->tls->ssl); + break; + default: + ESP_LOGE(TAG, "Illegal state!"); + return; } - - mbedtls_x509_crt_info((char *) buf, buf_size - 1, " ", &user_cb->tls->servercert); - ESP_LOGI(TAG, "Server certificate info:\n%s", buf); - memset(buf, 0x00, buf_size); - - cert = mbedtls_ssl_get_peer_cert(&user_cb->tls->ssl); - if (cert != NULL) { - mbedtls_x509_crt_info((char *) buf, buf_size - 1, " ", cert); - ESP_LOGI(TAG, "Peer certificate info:\n%s", buf); - } else { - ESP_LOGW(TAG, "Could not obtain the peer certificate!"); - } - - free(buf); } #endif