diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 799c30acf61b..1461728ab1d3 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -74,6 +74,7 @@ static const char *TAG = "esp-tls"; #define _esp_tls_set_global_ca_store esp_mbedtls_set_global_ca_store /*!< Callback function for setting global CA store data for TLS/SSL */ #define _esp_tls_get_global_ca_store esp_mbedtls_get_global_ca_store #define _esp_tls_free_global_ca_store esp_mbedtls_free_global_ca_store /*!< Callback function for freeing global ca store for TLS/SSL */ +#define _esp_tls_get_ciphersuites_list esp_mbedtls_get_ciphersuites_list #elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */ #define _esp_create_ssl_handle esp_create_wolfssl_handle #define _esp_tls_handshake esp_wolfssl_handshake @@ -617,6 +618,10 @@ mbedtls_x509_crt *esp_tls_get_global_ca_store(void) return _esp_tls_get_global_ca_store(); } +const int *esp_tls_get_ciphersuites_list(void) +{ + return _esp_tls_get_ciphersuites_list(); +} #endif /* CONFIG_ESP_TLS_USING_MBEDTLS */ #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 555caed37d7a..5543b0d0f427 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -193,6 +193,8 @@ typedef struct esp_tls_cfg { #endif /* CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS */ esp_tls_addr_family_t addr_family; /*!< The address family to use when connecting to a host. */ + const int *ciphersuites_list; /*!< Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites. + Please check the list validity by esp_tls_get_ciphersuites_list() API */ } esp_tls_cfg_t; #ifdef CONFIG_ESP_TLS_SERVER @@ -649,6 +651,15 @@ esp_err_t esp_tls_get_error_handle(esp_tls_t *tls, esp_tls_error_handle_t *error */ mbedtls_x509_crt *esp_tls_get_global_ca_store(void); +/** + * @brief Get supported TLS ciphersuites list. + * + * See https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4 for the list of ciphersuites + * + * @return Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites. + * + */ +const int *esp_tls_get_ciphersuites_list(void); #endif /* CONFIG_ESP_TLS_USING_MBEDTLS */ #ifdef CONFIG_ESP_TLS_SERVER /** diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index 6448845186e5..e84173abe99e 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -804,6 +804,11 @@ esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t ESP_LOGE(TAG, "You have to provide both clientcert_buf and clientkey_buf for mutual authentication"); return ESP_ERR_INVALID_STATE; } + + if (cfg->ciphersuites_list != NULL && cfg->ciphersuites_list[0] != 0) { + ESP_LOGD(TAG, "Set the ciphersuites list"); + mbedtls_ssl_conf_ciphersuites(&tls->conf, cfg->ciphersuites_list); + } return ESP_OK; } @@ -911,6 +916,11 @@ void esp_mbedtls_free_global_ca_store(void) } } +const int *esp_mbedtls_get_ciphersuites_list(void) +{ + return mbedtls_ssl_list_ciphersuites(); +} + #ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT static esp_err_t esp_init_atecc608a(uint8_t i2c_addr) { diff --git a/components/esp-tls/private_include/esp_tls_mbedtls.h b/components/esp-tls/private_include/esp_tls_mbedtls.h index 3eb46a080750..5526bba98c20 100644 --- a/components/esp-tls/private_include/esp_tls_mbedtls.h +++ b/components/esp-tls/private_include/esp_tls_mbedtls.h @@ -136,3 +136,8 @@ mbedtls_x509_crt *esp_mbedtls_get_global_ca_store(void); * Callback function for freeing global ca store for TLS/SSL using mbedtls */ void esp_mbedtls_free_global_ca_store(void); + +/** + * Internal Callback for esp_tls_get_ciphersuites_list + */ +const int *esp_mbedtls_get_ciphersuites_list(void); diff --git a/docs/en/api-reference/protocols/esp_tls.rst b/docs/en/api-reference/protocols/esp_tls.rst index a05f3da1b469..03f54da940a7 100644 --- a/docs/en/api-reference/protocols/esp_tls.rst +++ b/docs/en/api-reference/protocols/esp_tls.rst @@ -192,6 +192,25 @@ SSL/TLS libraries and with all respective configurations set to default. * An example of mutual authentication with the DS peripheral can be found at :example:`ssl mutual auth` which internally uses (ESP-TLS) for the TLS connection. +TLS Ciphersuites +------------------------------------ +ESP-TLS provides an ability to set a ciphersuites list in the client mode. TLS ciphersuites list helps to inform the server about the supported ciphersuites for the specific TLS connection (irrespective of the TLS stack configuration). If the server supports any ciphersuite from this list then the TLS connection shall succeed, otherwise it would fail. + +You can set ``ciphersuites_list`` in the :cpp:type:`esp_tls_cfg_t` structure during client connection as follows: + +.. code-block:: c + + /* ciphersuites_list must end with 0 and must be available in the memory scope active during the entire TLS connection */ + static const int ciphersuites_list[] = {MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 0}; + esp_tls_cfg_t cfg = { + .ciphersuites_list = ciphersuites_list, + }; + +ESP-TLS will not check the validity of ``ciphersuites_list`` that was set, you should call :cpp:func:`esp_tls_get_ciphersuites_list` to get ciphersuites list supported in the TLS stack and cross-check it against the supplied list. + +.. note:: + This feature is supported only in the mbedTLS stack. + API Reference ------------- diff --git a/examples/protocols/https_request/main/https_request_example_main.c b/examples/protocols/https_request/main/https_request_example_main.c index f386ed4e2a12..c0d22b4fe984 100644 --- a/examples/protocols/https_request/main/https_request_example_main.c +++ b/examples/protocols/https_request/main/https_request_example_main.c @@ -84,7 +84,8 @@ extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_ extern const uint8_t local_server_cert_pem_start[] asm("_binary_local_server_cert_pem_start"); extern const uint8_t local_server_cert_pem_end[] asm("_binary_local_server_cert_pem_end"); - +static const int server_supported_ciphersuites[] = {MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 0}; +static const int server_unsupported_ciphersuites[] = {MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, 0}; #ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS static esp_tls_client_session_t *tls_client_session = NULL; static bool save_client_session = false; @@ -185,6 +186,24 @@ static void https_get_request_using_cacert_buf(void) https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST); } +static void https_get_request_using_specified_ciphersuites(void) +{ + ESP_LOGI(TAG, "https_request using server supported ciphersuites"); + esp_tls_cfg_t cfg = { + .cacert_buf = (const unsigned char *) server_root_cert_pem_start, + .cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start, + .ciphersuites_list = server_supported_ciphersuites, + }; + + https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST); + + ESP_LOGI(TAG, "https_request using server unsupported ciphersuites"); + + cfg.ciphersuites_list = server_unsupported_ciphersuites; + + https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST); +} + static void https_get_request_using_global_ca_store(void) { esp_err_t esp_ret = ESP_FAIL; @@ -259,6 +278,7 @@ static void https_request_task(void *pvparameters) ESP_LOGI(TAG, "Minimum free heap size: %" PRIu32 " bytes", esp_get_minimum_free_heap_size()); https_get_request_using_cacert_buf(); https_get_request_using_global_ca_store(); + https_get_request_using_specified_ciphersuites(); ESP_LOGI(TAG, "Finish https_request example"); vTaskDelete(NULL); } diff --git a/examples/protocols/https_request/pytest_https_request.py b/examples/protocols/https_request/pytest_https_request.py index bf8922b93032..0afcda609e52 100644 --- a/examples/protocols/https_request/pytest_https_request.py +++ b/examples/protocols/https_request/pytest_https_request.py @@ -211,3 +211,26 @@ def test_examples_protocol_https_request(dut: Dut) -> None: logging.info("Failed the test for \"https_request using global ca_store\"") raise logging.info("Passed the test for \"https_request using global ca_store\"") + + # Check for connection using specified server supported ciphersuites + logging.info("Testing for \"https_request using server supported ciphersuites\"") + try: + dut.expect('https_request using server supported ciphersuites', timeout=20) + dut.expect(['Connection established...', + 'Reading HTTP response...', + 'HTTP/1.1 200 OK', + 'connection closed'], expect_all=True) + except Exception: + logging.info("Failed the test for \"https_request using server supported ciphersuites\"") + raise + logging.info("Passed the test for \"https_request using server supported ciphersuites\"") + + # Check for connection using specified server unsupported ciphersuites + logging.info("Testing for \"https_request using server unsupported ciphersuites\"") + try: + dut.expect('https_request using server unsupported ciphersuites', timeout=20) + dut.expect('Connection failed...', timeout=30) + except Exception: + logging.info("Failed the test for \"https_request using server unsupported ciphersuites\"") + raise + logging.info("Passed the test for \"https_request using server unsupported ciphersuites\"")