chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:04:25 +08:00
commit 548b49ebc0
20937 changed files with 5455372 additions and 0 deletions
@@ -0,0 +1,14 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.22)
# Include the default mbedTLS preset configuration
# This provides optimized settings for general-purpose TLS applications
# You can customize these settings using 'idf.py menuconfig' or additional config files
list(APPEND sdkconfig_defaults $ENV{IDF_PATH}/components/mbedtls/config/mbedtls_preset_default.conf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(https_request)
@@ -0,0 +1,89 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# HTTPS Request Example
Uses APIs from `esp-tls` component to make a very simple HTTPS request over a secure connection, including verifying the server TLS certificate.
(See the README.md file in the upper level 'examples' directory for more information about examples.)
### Session Tickets
Session Tickets, specified in [RFC 5077](https://datatracker.ietf.org/doc/html/rfc5077) are a mechanism to distribute encrypted
session-state information to the client in the form of a ticket and a mechanism to present the ticket back to the server. The ticket is created by a TLS server and sent to a TLS client. The TLS client presents the ticket to the TLS server to resume a session. In TLS 1.2, this speeds up handshakes from two to one round-trip.
In ESP-IDF, this feature is supported (for both server and client) when mbedTLS is used as the SSL library.
## How to use example
Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
### Hardware Required
* A development board with ESP32/ESP32-S2/ESP32-C3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for power supply and programming
### Configure the project
```
idf.py menuconfig
```
Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
#### Configuring Client Session Tickets
Note: This example has client session tickets enabled by default.
* Open the project configuration menu (`idf.py menuconfig`)
* In the `Component Config` -> `ESP-TLS` submenu, select the `Enable client session tickets` option.
Ensure that the server has the session tickets feature enabled.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (5634) example_connect: - IPv4 address: 192.168.194.219
I (5634) example_connect: - IPv6 address: fe80:0000:0000:0000:266f:28ff:fe80:2c74, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5644) example: Start https_request example
I (5654) example: https_request using crt bundle
W (6514) wifi:<ba-add>idx:1 (ifx:0, ee:6d:19:60:f6:0e), tid:4, ssn:0, winSize:64
I (7074) esp-x509-crt-bundle: Certificate validated
I (9384) example: Connection established...
I (9384) example: 107 bytes written
I (9384) example: Reading HTTP response...
HTTP/1.1 200 OK
Content-Length: 2091
Access-Control-Allow-Origin: *
Connection: close
Content-Type: application/json
Date: Tue, 07 Sep 2021 08:30:00 GMT
Strict-Transport-Security: max-age=631138519; includeSubdomains; preload
{"given_cipher_suites":["TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_CCM","TLS_DHE_RSA_WITH_AES_256_CCM","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384","TLS_ECDHE_RSA_WITH_AES_
256_CBC_SHA384","TLS_DHE_RSA_WITH_AES_256_CBC_SHA256","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA","TLS_DHE_RSA_WITH_AES_256_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8","TLS_DHE_RSA_WITH_AES_256_CCM_8","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CCM","TLS_DHE_RSA_WITH_AES_128_CCM","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256","TLS_DHE
_RSA_WITH_AES_128_CBC_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA","TLS_DHE_RSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_ECDSA
_WITH_AES_128_CCM_8","TLS_DHE_RSA_WITH_AES_128_CCM_8","TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_256_CCM","TLS_RSA_WITH_AES_256_CBC_SHA256","TLS_RSA_WITH_AES_256_CBC_SHA","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA","TLS_RSA_WITH_AES_256_CCM_8","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_RSA_WITH_AES_128_CCM","TLS_RS
A_WITH_AES_128_CBC_SHA256","TLS_RSA_WITH_AES_128_CBC_SHA","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA","TLS_RSA_WITH_AES_128_CCM_8","TLS_EMPTY_RENEGOTIATION_INFO_SCSV"],"ephemeral_keys_supported":true,"session_ticket_supported":true,"tls_compression_supported":false,"unknown_cipher_suite_supported":false,"beast_vuln":fal
se,"able_to_detect_n_minus_one_splitting":false,"insecure_cipher_suites":{},"tls_version":"TLS 1.2","rating":"Probably Okay"}
I (10204) example: connection closed
I (10204) example: 10...
I (11204) example: 9...
I (12204) example: 8...
I (13204) example: 7...
I (14204) example: 6...
I (15204) example: 5...
I (16204) example: 4...
```
@@ -0,0 +1,90 @@
# This is a test sdkconfig file for only build purpose. It is not intended to be used for the example.
# This disables most of the mbedtls configurations by default.
# If any component using mbedtls does not select respective configurations,
# then this should fail at build stage.
# Few example dependencies need to be enabled by default for the build to succeed
##############
CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=n
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
CONFIG_MBEDTLS_AES_C=y
##############
CONFIG_MBEDTLS_HARDWARE_AES=n
CONFIG_MBEDTLS_HARDWARE_MPI=n
CONFIG_MBEDTLS_HARDWARE_SHA=n
CONFIG_MBEDTLS_ROM_MD5=n
CONFIG_MBEDTLS_HAVE_TIME=n
CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=n
CONFIG_MBEDTLS_SHA512_C=n
CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=n
CONFIG_MBEDTLS_TLS_SERVER=n
CONFIG_MBEDTLS_TLS_CLIENT=n
CONFIG_MBEDTLS_TLS_ENABLED=n
#
# TLS Key Exchange Methods
#
CONFIG_MBEDTLS_PSK_MODES=n
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=n
CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=n
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=n
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=n
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=n
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=n
# end of TLS Key Exchange Methods
CONFIG_MBEDTLS_SSL_RENEGOTIATION=n
CONFIG_MBEDTLS_SSL_PROTO_DTLS=n
CONFIG_MBEDTLS_SSL_ALPN=n
CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=n
CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=n
#
# Symmetric Ciphers
#
CONFIG_MBEDTLS_CAMELLIA_C=n
CONFIG_MBEDTLS_DES_C=n
CONFIG_MBEDTLS_CCM_C=n
CONFIG_MBEDTLS_GCM_C=n
CONFIG_MBEDTLS_NIST_KW_C=n
# end of Symmetric Ciphers
CONFIG_MBEDTLS_RIPEMD160_C=n
#
# Certificates
#
CONFIG_MBEDTLS_PEM_PARSE_C=n
CONFIG_MBEDTLS_PEM_WRITE_C=n
CONFIG_MBEDTLS_X509_CRL_PARSE_C=n
CONFIG_MBEDTLS_X509_CSR_PARSE_C=n
# end of Certificates
CONFIG_MBEDTLS_ECP_C=n
CONFIG_MBEDTLS_ECDH_C=n
CONFIG_MBEDTLS_ECDSA_C=n
CONFIG_MBEDTLS_ECJPAKE_C=n
CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=n
CONFIG_MBEDTLS_ECP_NIST_OPTIM=n
CONFIG_MBEDTLS_POLY1305_C=n
CONFIG_MBEDTLS_CHACHA20_C=n
CONFIG_MBEDTLS_HKDF_C=n
CONFIG_MBEDTLS_THREADING_C=n
CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI=n
# end of mbedTLS
@@ -0,0 +1,7 @@
# Embed the server root certificate into the final binary
#
# (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.)
idf_component_register(SRCS "https_request_example_main.c" "time_sync.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES esp-tls esp_wifi esp_timer nvs_flash
EMBED_TXTFILES server_root_cert.pem local_server_cert.pem)
@@ -0,0 +1,33 @@
menu "Example Configuration"
config EXAMPLE_USING_ESP_TLS_MBEDTLS
bool
depends on ESP_TLS_USING_MBEDTLS
default y
config EXAMPLE_CLIENT_SESSION_TICKETS
bool "Enable Client session ticket support"
default n
select ESP_TLS_CLIENT_SESSION_TICKETS
help
Enable the client session ticket support for the example.
config EXAMPLE_LOCAL_SERVER_URL
string "Local Server URL for testing session tickets"
default "https://192.168.0.106:8070"
depends on EXAMPLE_CLIENT_SESSION_TICKETS
help
The url of the server to which the example is going to connect in order to test the session ticket support.
config EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN
bool
default y if EXAMPLE_LOCAL_SERVER_URL = "FROM_STDIN"
config EXAMPLE_SSL_PROTO_TLS1_3_CLIENT
bool "Enable TLS 1.3 client test"
default n
select MBEDTLS_SSL_PROTO_TLS1_3
help
Enable TLS 1.3 client test support for the example.
endmenu
@@ -0,0 +1,346 @@
/*
* HTTPS GET Example using plain Mbed TLS sockets
*
* Contacts the howsmyssl.com API via TLS v1.2 and reads a JSON
* response.
*
* Adapted from the ssl_client1 example in Mbed TLS.
*
* SPDX-FileCopyrightText: The Mbed TLS Contributors
*
* SPDX-License-Identifier: Apache-2.0
*
* SPDX-FileContributor: 2015-2026 Espressif Systems (Shanghai) CO LTD
*/
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "protocol_examples_common.h"
#include "esp_sntp.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "esp_tls.h"
#include "sdkconfig.h"
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE && CONFIG_EXAMPLE_USING_ESP_TLS_MBEDTLS
#include "esp_crt_bundle.h"
#endif
#include "time_sync.h"
#include "esp_random.h"
/* Constants that aren't configurable in menuconfig */
#ifdef CONFIG_EXAMPLE_SSL_PROTO_TLS1_3_CLIENT
#define WEB_SERVER "tls13.browserleaks.com"
#define WEB_PORT "443"
#define WEB_URL "https://tls13.browserleaks.com/tls"
#else
#define WEB_SERVER "howsmyssl.com"
#define WEB_PORT "443"
#define WEB_URL "https://www.howsmyssl.com/a/check"
#endif
#define SERVER_URL_MAX_SZ 256
static const char *TAG = "example";
/* Timer interval once every day (24 Hours) */
#define TIME_PERIOD (86400000000ULL)
static const char HOWSMYSSL_REQUEST[] = "GET " WEB_URL " HTTP/1.1\r\n"
"Host: "WEB_SERVER"\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static const char LOCAL_SRV_REQUEST[] = "GET " CONFIG_EXAMPLE_LOCAL_SERVER_URL " HTTP/1.1\r\n"
"Host: "WEB_SERVER"\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
#endif
/* Root cert for howsmyssl.com, taken from server_root_cert.pem
The PEM file was extracted from the output of this command:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA root cert is the last cert given in the chain of certs.
To embed it in the app binary, the PEM file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
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");
#if CONFIG_EXAMPLE_USING_ESP_TLS_MBEDTLS
#if defined(CONFIG_EXAMPLE_SSL_PROTO_TLS1_3_CLIENT)
static const int server_supported_ciphersuites[] = {MBEDTLS_TLS1_3_AES_256_GCM_SHA384, MBEDTLS_TLS1_3_AES_128_CCM_SHA256, 0};
static const int server_unsupported_ciphersuites[] = {MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, 0};
#else
static const int server_supported_ciphersuites[] = {MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, 0};
static const int server_unsupported_ciphersuites[] = {MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, 0};
#endif // CONFIG_EXAMPLE_SSL_PROTO_TLS1_3_CLIENT
#endif // CONFIG_EXAMPLE_USING_ESP_TLS_MBEDTLS
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static esp_tls_client_session_t *tls_client_session = NULL;
static bool save_client_session = false;
#endif
static void https_get_request(esp_tls_cfg_t cfg, const char *WEB_SERVER_URL, const char *REQUEST)
{
char buf[512];
int ret, len;
esp_tls_t *tls = esp_tls_init();
if (!tls) {
ESP_LOGE(TAG, "Failed to allocate esp_tls handle!");
goto exit;
}
if (esp_tls_conn_http_new_sync(WEB_SERVER_URL, &cfg, tls) == 1) {
ESP_LOGI(TAG, "Connection established...");
} else {
ESP_LOGE(TAG, "Connection failed...");
int esp_tls_code = 0, esp_tls_flags = 0;
esp_tls_error_handle_t tls_e = NULL;
esp_tls_get_error_handle(tls, &tls_e);
/* Try to get TLS stack level error and certificate failure flags, if any */
ret = esp_tls_get_and_clear_last_error(tls_e, &esp_tls_code, &esp_tls_flags);
if (ret == ESP_OK) {
ESP_LOGE(TAG, "TLS error = -0x%x, TLS flags = -0x%x", esp_tls_code, esp_tls_flags);
}
goto cleanup;
}
size_t written_bytes = 0;
do {
ret = esp_tls_conn_write(tls,
REQUEST + written_bytes,
strlen(REQUEST) - written_bytes);
if (ret >= 0) {
ESP_LOGI(TAG, "%d bytes written", ret);
written_bytes += ret;
} else if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
ESP_LOGE(TAG, "esp_tls_conn_write returned: [0x%02X](%s)", ret, esp_err_to_name(ret));
goto cleanup;
}
} while (written_bytes < strlen(REQUEST));
ESP_LOGI(TAG, "Reading HTTP response...");
do {
len = sizeof(buf) - 1;
memset(buf, 0x00, sizeof(buf));
ret = esp_tls_conn_read(tls, (char *)buf, len);
if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ) {
continue;
} else if (ret < 0) {
ESP_LOGE(TAG, "esp_tls_conn_read returned [-0x%02X](%s)", -ret, esp_err_to_name(ret));
break;
} else if (ret == 0) {
ESP_LOGI(TAG, "connection closed");
break;
}
len = ret;
ESP_LOGD(TAG, "%d bytes read", len);
/* Print response directly to stdout as it is read */
for (int i = 0; i < len; i++) {
putchar(buf[i]);
}
putchar('\n'); // JSON output doesn't have a newline at end
} while (1);
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
/* The TLS session is successfully established, now saving the session ctx for reuse */
if (save_client_session) {
esp_tls_free_client_session(tls_client_session);
tls_client_session = esp_tls_get_client_session(tls);
}
#endif
cleanup:
esp_tls_conn_destroy(tls);
exit:
for (int countdown = 10; countdown >= 0; countdown--) {
ESP_LOGI(TAG, "%d...", countdown);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE && CONFIG_EXAMPLE_USING_ESP_TLS_MBEDTLS
static void https_get_request_using_crt_bundle(void)
{
ESP_LOGI(TAG, "https_request using crt bundle");
esp_tls_cfg_t cfg = {
.crt_bundle_attach = esp_crt_bundle_attach,
};
https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST);
}
#endif // CONFIG_MBEDTLS_CERTIFICATE_BUNDLE && CONFIG_EXAMPLE_USING_ESP_TLS_MBEDTLS
static void https_get_request_using_cacert_buf(void)
{
ESP_LOGI(TAG, "https_request using cacert_buf");
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,
};
https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST);
}
static void https_get_request_using_specified_ciphersuites(void)
{
#if CONFIG_EXAMPLE_USING_ESP_TLS_MBEDTLS
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,
#if defined(CONFIG_EXAMPLE_SSL_PROTO_TLS1_3_CLIENT)
.tls_version = ESP_TLS_VER_TLS_1_3,
#else
.tls_version = ESP_TLS_VER_TLS_1_2,
#endif
};
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);
#endif
}
static void https_get_request_using_global_ca_store(void)
{
esp_err_t esp_ret = ESP_FAIL;
ESP_LOGI(TAG, "https_request using global ca_store");
esp_ret = esp_tls_set_global_ca_store(server_root_cert_pem_start, server_root_cert_pem_end - server_root_cert_pem_start);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Error in setting the global ca store: [%02X] (%s),could not complete the https_request using global_ca_store", esp_ret, esp_err_to_name(esp_ret));
return;
}
esp_tls_cfg_t cfg = {
.use_global_ca_store = true,
};
https_get_request(cfg, WEB_URL, HOWSMYSSL_REQUEST);
esp_tls_free_global_ca_store();
}
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
static void https_get_request_to_local_server(const char* url)
{
ESP_LOGI(TAG, "https_request to local server");
esp_tls_cfg_t cfg = {
.cacert_buf = (const unsigned char *) local_server_cert_pem_start,
.cacert_bytes = local_server_cert_pem_end - local_server_cert_pem_start,
.skip_common_name = true,
};
save_client_session = true;
https_get_request(cfg, url, LOCAL_SRV_REQUEST);
}
static void https_get_request_using_already_saved_session(const char *url)
{
ESP_LOGI(TAG, "https_request using saved client session");
esp_tls_cfg_t cfg = {
.client_session = tls_client_session,
.cacert_buf = (const unsigned char *) local_server_cert_pem_start,
.cacert_bytes = local_server_cert_pem_end - local_server_cert_pem_start,
.skip_common_name = true,
};
https_get_request(cfg, url, LOCAL_SRV_REQUEST);
esp_tls_free_client_session(tls_client_session);
save_client_session = false;
tls_client_session = NULL;
}
#endif
static void https_request_task(void *pvparameters)
{
ESP_LOGI(TAG, "Start https_request example");
#ifdef CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS
char *server_url = NULL;
#ifdef CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN
char url_buf[SERVER_URL_MAX_SZ];
if (strcmp(CONFIG_EXAMPLE_LOCAL_SERVER_URL, "FROM_STDIN") == 0) {
example_configure_stdin_stdout();
fgets(url_buf, SERVER_URL_MAX_SZ, stdin);
int len = strlen(url_buf);
url_buf[len - 1] = '\0';
server_url = url_buf;
} else {
ESP_LOGE(TAG, "Configuration mismatch: invalid url for local server");
abort();
}
printf("\nServer URL obtained is %s\n", url_buf);
#else
server_url = CONFIG_EXAMPLE_LOCAL_SERVER_URL;
#endif /* CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN */
https_get_request_to_local_server(server_url);
https_get_request_using_already_saved_session(server_url);
#endif
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE && CONFIG_EXAMPLE_USING_ESP_TLS_MBEDTLS
https_get_request_using_crt_bundle();
#endif
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);
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
if (esp_reset_reason() == ESP_RST_POWERON) {
ESP_LOGI(TAG, "Updating time from NVS");
ESP_ERROR_CHECK(update_time_from_nvs());
}
const esp_timer_create_args_t nvs_update_timer_args = {
.callback = (void *)&fetch_and_store_time_in_nvs,
};
esp_timer_handle_t nvs_update_timer;
ESP_ERROR_CHECK(esp_timer_create(&nvs_update_timer_args, &nvs_update_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(nvs_update_timer, TIME_PERIOD));
xTaskCreate(&https_request_task, "https_get_task", 8192, NULL, 5, NULL);
}
@@ -0,0 +1,3 @@
dependencies:
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Update the system time from time stored in NVS.
*
*/
esp_err_t update_time_from_nvs(void);
/**
* @brief Fetch the current time from SNTP and stores it in NVS.
*
*/
esp_err_t fetch_and_store_time_in_nvs(void*);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICyDCCAbACCQC4RVDDRrCbrDANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtF
U1AzMiBIVFRQUyByZXF1ZXN0IGV4YW1wbGUwHhcNMjExMTE0MjAxMjQ4WhcNMzEx
MTEyMjAxMjQ4WjAmMSQwIgYDVQQDDBtFU1AzMiBIVFRQUyByZXF1ZXN0IGV4YW1w
bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9eiUPHf31rkkTQ7Pq
EHeefT5pC8VZvfpgQSOz4nQNvX94BysC+Ycv0MTnWn2yKk4fj/gXaf3mhlcmNwZO
CGMIgi9BzACWgOKAlUMXwbo3qOdMXRPgWvv/vv6xM5WdVjWPdC/LJOg41wqYblZ7
FTZhxw5K7wLkjiAZrWcm4bd993Z0Hy7WXWFMaBURjPehORq/E2GeL11o+aLGT/Fi
0c64gBsyiGt+RK5c/QkoS44WM77YwiUbzuKdLd5j4LXNcqc47Ac1oPl7vTSUQta+
4Ixaler/IC8yg9l2f9t1HsYNfL/6O61C1PoHSqwWwMU1eegdW33UYGrA00NSfSNI
7k8XAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADqDXuXa90kwJGmbjyNMgmBdsCvg
0Z+bG085hjKY/TogH76E8bhbN0obXxIbht4LKNdrC76IIE/iY/EF+LRBiWCemUHV
Pgj16REG335R86VU9UTSoGte1oOK3ttmJ10bz1WeBSTOT21OyTqvI0+zWvei9Jel
ADDGck47sJoAbDv2FC6AhFjkmG0YsaoJtXsSAnKmLL+qsJ1z0ZIHxupIO7coG2fe
6ZZMWnLt5ODCopYCY6aVuODoJ4Ywe+Yu3tBPG7AF9em7MfUVngOJCGUrhu4RLCTm
3FT53VgKyMjQKVzeg9hkRvgePWX4oByWCmxzvWAV5oavh41BvpRsW4vBF54=
-----END CERTIFICATE-----
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9eiUPHf31rkkT
Q7PqEHeefT5pC8VZvfpgQSOz4nQNvX94BysC+Ycv0MTnWn2yKk4fj/gXaf3mhlcm
NwZOCGMIgi9BzACWgOKAlUMXwbo3qOdMXRPgWvv/vv6xM5WdVjWPdC/LJOg41wqY
blZ7FTZhxw5K7wLkjiAZrWcm4bd993Z0Hy7WXWFMaBURjPehORq/E2GeL11o+aLG
T/Fi0c64gBsyiGt+RK5c/QkoS44WM77YwiUbzuKdLd5j4LXNcqc47Ac1oPl7vTSU
Qta+4Ixaler/IC8yg9l2f9t1HsYNfL/6O61C1PoHSqwWwMU1eegdW33UYGrA00NS
fSNI7k8XAgMBAAECggEADa5QFrNXrvGSnS16RCBEQtFQPE15Rm2NMn4Bke976bIR
Dh2WYXSa6jzsurex87dSRL0kcKxahNaWXFAEyIWagPbFar7MHBHaSOZ+Ha0DQRmU
+dKOqNho8aJcyXasCtw6qcz91nEnw1LjlPYCkIiLkKvKwGZZkx8f+jqnBAuwMAwa
VZzrtDw2zZAZXBspC9n9fa0IAY4rq7QWCl/HlTEody8VuLng7+WEhFJRJ0F1IK9v
U1NihTdZRuybWQvmcj3fh+44PHBNkljoPPwN361eNR9aYiU/KtTIa8En+ZQPyetH
rmr6rMsd7rBTTbPch6nanN5rsmWCMbQj3bD6LWuEQQKBgQDg50fMK2XQfZukPDjT
3rYBPCSKUdE8uzP5p2xurHLZa+zjrhkVu3895OaP4WHYNAOaaTMnxwTVY2xXMA/F
uoJmDpVzuDjgp1qjqDK96XMPSUs30dwI8LgYCfEm7gKZ7BFSn8QlhxeFIn4fhxwS
w6vBeNp0uL9Pjj/C2ZCDd6iWCQKBgQDXrOigR22OHWksAeDz/TVW/KEQEkFHvuF7
U87YyV+771TYT98fkKZ4zyStIK96eWumxmeBTVSg5zS+8aOFfWO3OL4Bfj45JWaJ
rblh/bgLUsa5J6jrm9ISVATfqN3GiEJw8LhkCjIqI269ku874jQrCifZPVKFffkf
2/1LSswEHwKBgQDU4PYrwnQ32X0GAt7DZM4f8x6fMnx8ILI8wAW56E85j5eFlxg1
Yuk4276FOA+WRv2WHbeHEjF4DgjRqjNztGuTUICULS7hLmdz+1Q0QJFhSb4B0wmU
CM4oKtjxQV6C9VkcPQ+7ediAczqwewHOnRmpIsycqPakxf+CXs8UMaIIiQKBgA8F
30pSz2HH0KydEONN7uo5PKrW6q8pr6EcjFrzY/S+TgWnQp57P+1IWICqty5ryMDc
LxeFoHB4ymbGhCJnQovfqvSFq6XlYggTDsexmaFISclZ5t1KhE58hb5ij9glY6Nk
USO+xhHDWBJiasGcFxAsa+wo5legF7tNYo5dDmr3AoGAQ+i2gtXpZELQZ9ODkIbR
wlvRTlElDkk/+a9O/k18eFv4uyw4locngsWtz6lpzJuXikj+LtnYKMInvZxwmyJT
n4MLb/SNxpaumZHhSZy5xU1x7RgBzR/NyaJIws70eDvc6g9PIe2ahVoDDMSZxtGN
3tplBVJpwQuwwoKFmE2ea9I=
-----END PRIVATE KEY-----
@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
@@ -0,0 +1,132 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_netif.h"
#include "esp_netif_sntp.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "time_sync.h"
static const char *TAG = "time_sync";
#define STORAGE_NAMESPACE "storage"
void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org" ) );
esp_netif_sntp_init(&config);
}
static esp_err_t obtain_time(void)
{
// wait for time to be set
int retry = 0;
const int retry_count = 10;
while (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(2000)) != ESP_OK && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
}
if (retry == retry_count) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t fetch_and_store_time_in_nvs(void *args)
{
nvs_handle_t my_handle = 0;
esp_err_t err;
initialize_sntp();
if (obtain_time() != ESP_OK) {
err = ESP_FAIL;
goto exit;
}
time_t now;
time(&now);
//Open
err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
if (err != ESP_OK) {
goto exit;
}
//Write
err = nvs_set_i64(my_handle, "timestamp", now);
if (err != ESP_OK) {
goto exit;
}
err = nvs_commit(my_handle);
if (err != ESP_OK) {
goto exit;
}
exit:
if (my_handle != 0) {
nvs_close(my_handle);
}
esp_netif_sntp_deinit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error updating time in nvs");
} else {
ESP_LOGI(TAG, "Updated time in NVS");
}
return err;
}
esp_err_t update_time_from_nvs(void)
{
nvs_handle_t my_handle = 0;
esp_err_t err;
err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening NVS");
goto exit;
}
int64_t timestamp = 0;
err = nvs_get_i64(my_handle, "timestamp", &timestamp);
if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGI(TAG, "Time not found in NVS. Syncing time from SNTP server.");
if (fetch_and_store_time_in_nvs(NULL) != ESP_OK) {
err = ESP_FAIL;
} else {
err = ESP_OK;
}
} else if (err == ESP_OK) {
struct timeval get_nvs_time;
get_nvs_time.tv_sec = timestamp;
settimeofday(&get_nvs_time, NULL);
}
exit:
if (my_handle != 0) {
nvs_close(my_handle);
}
return err;
}
@@ -0,0 +1,489 @@
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import http.server
import logging
import multiprocessing
import os
import ssl
import subprocess
import tempfile
import time
from collections.abc import Callable
import esptool
import pexpect
import pytest
from common_test_methods import get_env_config_variable
from common_test_methods import get_host_ip4_by_dest_ip
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
from RangeHTTPServer import RangeRequestHandler
def https_request_handler() -> Callable[..., http.server.BaseHTTPRequestHandler]:
"""
Returns a request handler class that handles broken pipe exception
"""
class RequestHandler(RangeRequestHandler):
protocol_version = 'HTTP/1.1'
def finish(self) -> None:
try:
if not self.wfile.closed:
self.wfile.flush()
self.wfile.close()
except OSError:
pass
self.rfile.close()
def handle(self) -> None:
try:
RangeRequestHandler.handle(self)
except OSError:
pass
def do_GET(self) -> None:
self.close_connection = True
self.send_response(200)
self.end_headers()
return RequestHandler
def start_https_server(server_file: str, key_file: str, server_ip: str, server_port: int) -> None:
requestHandler = https_request_handler()
httpd = http.server.HTTPServer((server_ip, server_port), requestHandler)
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file)
httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True)
httpd.serve_forever()
def write_time_to_nvs(dut: Dut) -> None:
"""Write current host timestamp to the DUT's NVS partition.
This eliminates the need for SNTP time synchronization in CI,
where NTP servers may be unreachable. The firmware reads the
timestamp from NVS key 'storage/timestamp' and uses it to set
the system time for TLS certificate validation.
"""
nvs_offset = dut.app.partition_table['nvs']['offset']
nvs_size = dut.app.partition_table['nvs']['size']
csv_file = os.path.join(tempfile.gettempdir(), 'nvs_time.csv')
bin_file = os.path.join(tempfile.gettempdir(), 'nvs_time.bin')
with open(csv_file, 'w') as f:
f.write('key,type,encoding,value\n')
f.write('storage,namespace,,\n')
f.write(f'timestamp,data,i64,{int(time.time())}\n')
nvs_gen = os.path.join(
os.environ['IDF_PATH'],
'components',
'nvs_flash',
'nvs_partition_generator',
'nvs_partition_gen.py',
)
subprocess.check_call(
['python3', nvs_gen, 'generate', csv_file, bin_file, hex(nvs_size)],
stdout=subprocess.DEVNULL,
)
with dut.serial.disable_redirect_thread():
dut.serial.esp.connect()
esptool.main(
['write-flash', '--no-compress', hex(nvs_offset), bin_file],
esp=dut.serial.esp,
)
settings = dut.serial.proc.get_settings()
dut.serial.esp.hard_reset()
dut.serial.proc.apply_settings(settings)
logging.info('Wrote host timestamp (%d) to NVS at offset %s', int(time.time()), hex(nvs_offset))
@pytest.mark.ethernet
@pytest.mark.parametrize(
'config',
[
'cli_ses_tkt',
],
indirect=True,
)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_examples_protocol_https_request_cli_session_tickets(dut: Dut) -> None:
write_time_to_nvs(dut)
logging.info('Testing for "esp_tls client session tickets"')
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, 'https_request.bin')
bin_size = os.path.getsize(binary_file)
logging.info(f'https_request_bin_size : {bin_size // 1024}KB')
# start https server
server_port = 8070
server_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_cert.pem')
key_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_key.pem')
thread1 = multiprocessing.Process(target=start_https_server, args=(server_file, key_file, '0.0.0.0', server_port))
thread1.daemon = True
thread1.start()
logging.info(f'The server started on localhost:{server_port}')
try:
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
print(f'Connected to AP/Ethernet with IP: {ip_address}')
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
host_ip = get_host_ip4_by_dest_ip(ip_address)
dut.expect('Start https_request example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port)))
dut.write('https://' + host_ip + ':' + str(server_port))
logging.info('Testing for "https_request using saved session"')
# Check for connection using already saved client session
try:
dut.expect('https_request to local server', timeout=30)
dut.expect(
['Connection established...', 'Reading HTTP response...', 'HTTP/1.1 200 OK', 'connection closed'],
expect_all=True,
)
except Exception:
logging.info('Failed to connect to local https server"')
raise
try:
dut.expect('https_request using saved client session', 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 saved client session"')
raise
logging.info('Passed the test for "https_request using saved client session"')
finally:
thread1.terminate()
@pytest.mark.ethernet
@pytest.mark.parametrize(
'config',
[
'ssldyn_tls1_3',
'ssldyn_tls1_3_only',
],
indirect=True,
)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_examples_protocol_https_request_dynamic_buffers_tls1_3(dut: Dut) -> None:
write_time_to_nvs(dut)
# Check for tls 1.3 connection using crt bundle with mbedtls dynamic resource enabled
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, 'https_request.bin')
bin_size = os.path.getsize(binary_file)
logging.info(f'https_request_bin_size : {bin_size // 1024}KB')
# start https server
server_port = 8070
server_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_cert.pem')
key_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_key.pem')
thread1 = multiprocessing.Process(target=start_https_server, args=(server_file, key_file, '0.0.0.0', server_port))
thread1.daemon = True
thread1.start()
logging.info(f'The server started on localhost:{server_port}')
dut.expect('Loaded app from partition at offset', timeout=30)
try:
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
print(f'Connected to AP/Ethernet with IP: {ip_address}')
host_ip = get_host_ip4_by_dest_ip(ip_address)
dut.expect('Start https_request example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port)))
dut.write('https://' + host_ip + ':' + str(server_port))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Check for connection using already saved client session
try:
dut.expect('https_request to local server', timeout=30)
dut.expect(
['Connection established...', 'Reading HTTP response...', 'HTTP/1.1 200 OK', 'connection closed'],
expect_all=True,
)
except Exception:
logging.info('Failed to connect to local https server"')
raise
try:
dut.expect('https_request using saved client session', 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 saved client session"')
raise
# only check if one connection is established
logging.info('Testing for "https_request using crt bundle" with mbedtls dynamic resource enabled')
try:
dut.expect('https_request using crt bundle', timeout=30)
dut.expect(
[
'Connection established...',
'Reading HTTP response...',
'HTTP/1.1 200 OK',
'TLS 1.3',
'connection closed',
],
expect_all=True,
)
except Exception:
logging.info(
'Failed the test for "https_request using crt bundle" with TLS 1.3 '
'when mbedtls dynamic resource was enabled'
)
raise
logging.info(
'Passed the test for "https_request using crt bundle" with TLS 1.3 when '
'mbedtls dynamic resource was enabled'
)
finally:
thread1.terminate()
@pytest.mark.ethernet
@pytest.mark.parametrize(
'config',
[
'ssldyn',
],
indirect=True,
)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_examples_protocol_https_request_dynamic_buffers(dut: Dut) -> None:
write_time_to_nvs(dut)
# Check for connection using crt bundle with mbedtls dynamic resource enabled
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, 'https_request.bin')
bin_size = os.path.getsize(binary_file)
logging.info(f'https_request_bin_size : {bin_size // 1024}KB')
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
print(f'Connected to AP/Ethernet with IP: {ip_address}')
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# only check if one connection is established
logging.info('Testing for "https_request using crt bundle" with mbedtls dynamic resource enabled')
try:
dut.expect('https_request using crt bundle', timeout=30)
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 crt bundle" when mbedtls dynamic resource was enabled')
raise
logging.info('Passed the test for "https_request using crt bundle" when mbedtls dynamic resource was enabled')
@pytest.mark.ethernet
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_examples_protocol_https_request(dut: Dut) -> None:
"""
steps: |
1. join AP
2. establish TLS connection to www.howsmyssl.com:443 with multiple
certificate verification options
3. send http request
"""
write_time_to_nvs(dut)
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, 'https_request.bin')
bin_size = os.path.getsize(binary_file)
logging.info(f'https_request_bin_size : {bin_size // 1024}KB')
logging.info('Starting https_request simple test app')
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
print(f'Connected to AP/Ethernet with IP: {ip_address}')
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Check for connection using crt bundle
logging.info('Testing for "https_request using crt bundle"')
try:
dut.expect('https_request using crt bundle', timeout=30)
dut.expect(
[
'Certificate validated',
'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 crt bundle"')
raise
logging.info('Passed the test for "https_request using crt bundle"')
# Check for connection using cacert_buf
logging.info('Testing for "https_request using cacert_buf"')
try:
dut.expect('https_request using cacert_buf', timeout=20)
dut.expect(
['Connection established...', 'Reading HTTP response...', 'HTTP/1.1 200 OK', 'connection closed'],
expect_all=True,
)
except Exception:
logging.info('Passed the test for "https_request using cacert_buf"')
raise
logging.info('Passed the test for "https_request using cacert_buf"')
# Check for connection using global ca_store
logging.info('Testing for "https_request using global ca_store"')
try:
dut.expect('https_request using global ca_store', 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 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"')
@pytest.mark.wifi_ap
@pytest.mark.esp32c2_rev2
@pytest.mark.xtal_26mhz
@pytest.mark.parametrize(
'config, baud',
[
('esp32c2_rom_mbedtls', '74880'),
],
indirect=True,
)
@idf_parametrize('target', ['esp32c2'], indirect=['target'])
def test_examples_protocol_https_request_rom_impl(dut: Dut) -> None:
write_time_to_nvs(dut)
# Connect to AP
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
dut.expect('Please input ssid password:')
env_name = 'wifi_ap'
ap_ssid = get_env_config_variable(env_name, 'ap_ssid')
ap_password = get_env_config_variable(env_name, 'ap_password')
dut.write(f'{ap_ssid} {ap_password}')
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, 'https_request.bin')
bin_size = os.path.getsize(binary_file)
logging.info(f'https_request_bin_size : {bin_size // 1024}KB')
logging.info('Starting https_request simple test app')
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
print(f'Connected to AP/Ethernet with IP: {ip_address}')
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Check for connection using crt bundle
logging.info('Testing for "https_request using crt bundle"')
try:
dut.expect('https_request using crt bundle', timeout=30)
dut.expect(
[
'Certificate validated',
'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 crt bundle"')
raise
logging.info('Passed the test for "https_request using crt bundle"')
# Check for connection using cacert_buf
logging.info('Testing for "https_request using cacert_buf"')
try:
dut.expect('https_request using cacert_buf', timeout=20)
dut.expect(
['Connection established...', 'Reading HTTP response...', 'HTTP/1.1 200 OK', 'connection closed'],
expect_all=True,
)
except Exception:
logging.info('Passed the test for "https_request using cacert_buf"')
raise
logging.info('Passed the test for "https_request using cacert_buf"')
# Check for connection using global ca_store
logging.info('Testing for "https_request using global ca_store"')
try:
dut.expect('https_request using global ca_store', 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 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"')
@@ -0,0 +1,13 @@
CONFIG_SPIRAM=y
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_ETHERNET_INTERNAL_SUPPORT=y
CONFIG_ETHERNET_PHY_GENERIC=y
CONFIG_ETHERNET_MDC_GPIO=23
CONFIG_ETHERNET_MDIO_GPIO=18
CONFIG_ETHERNET_PHY_RST_GPIO=5
CONFIG_ETHERNET_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS=y
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST=y
@@ -0,0 +1,12 @@
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_ETHERNET_INTERNAL_SUPPORT=y
CONFIG_ETHERNET_PHY_GENERIC=y
CONFIG_ETHERNET_MDC_GPIO=23
CONFIG_ETHERNET_MDIO_GPIO=18
CONFIG_ETHERNET_PHY_RST_GPIO=5
CONFIG_ETHERNET_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS=y
CONFIG_EXAMPLE_LOCAL_SERVER_URL="FROM_STDIN"
CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN=y
@@ -0,0 +1,6 @@
CONFIG_IDF_TARGET="esp32c2"
CONFIG_XTAL_FREQ_26=y
CONFIG_ESP32C2_REV_MIN_200=y
CONFIG_EXAMPLE_CONNECT_WIFI=y
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_MBEDTLS_USE_CRYPTO_ROM_IMPL=y
@@ -0,0 +1,13 @@
CONFIG_SPIRAM=y
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_ETHERNET_INTERNAL_SUPPORT=y
CONFIG_ETHERNET_PHY_GENERIC=y
CONFIG_ETHERNET_MDC_GPIO=23
CONFIG_ETHERNET_MDIO_GPIO=18
CONFIG_ETHERNET_PHY_RST_GPIO=5
CONFIG_ETHERNET_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
@@ -0,0 +1,15 @@
CONFIG_SPIRAM=y
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_ETHERNET_INTERNAL_SUPPORT=y
CONFIG_ETHERNET_PHY_GENERIC=y
CONFIG_ETHERNET_MDC_GPIO=23
CONFIG_ETHERNET_MDIO_GPIO=18
CONFIG_ETHERNET_PHY_RST_GPIO=5
CONFIG_ETHERNET_PHY_ADDR=1
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
CONFIG_EXAMPLE_SSL_PROTO_TLS1_3_CLIENT=y
CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS=y
CONFIG_EXAMPLE_LOCAL_SERVER_URL="FROM_STDIN"
CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN=y
@@ -0,0 +1,16 @@
CONFIG_SPIRAM=y
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_ETHERNET_INTERNAL_SUPPORT=y
CONFIG_ETHERNET_PHY_GENERIC=y
CONFIG_ETHERNET_MDC_GPIO=23
CONFIG_ETHERNET_MDIO_GPIO=18
CONFIG_ETHERNET_PHY_RST_GPIO=5
CONFIG_ETHERNET_PHY_ADDR=1
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
CONFIG_EXAMPLE_SSL_PROTO_TLS1_3_CLIENT=y
CONFIG_EXAMPLE_CLIENT_SESSION_TICKETS=y
CONFIG_EXAMPLE_LOCAL_SERVER_URL="FROM_STDIN"
CONFIG_EXAMPLE_LOCAL_SERVER_URL_FROM_STDIN=y
CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=n
@@ -0,0 +1,5 @@
CONFIG_MBEDTLS_HAVE_TIME_DATE=y
CONFIG_LWIP_SNTP_MAX_SERVERS=2
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
CONFIG_MBEDTLS_CHACHA20_C=y
CONFIG_MBEDTLS_CHACHAPOLY_C=y