chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# The following 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($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_server)
|
||||
@@ -0,0 +1,75 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# HTTPS server
|
||||
|
||||
This example creates an HTTPS server with SSL/TLS support using **ESP-TLS** that serves a simple HTML page when you visit its root URL.
|
||||
|
||||
For more information, refer to the [esp_https_server component documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_https_server.html).
|
||||
|
||||
## How to use example
|
||||
Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
|
||||
|
||||
### 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.
|
||||
|
||||
### 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.
|
||||
|
||||
## Certificates
|
||||
|
||||
You will need to approve a security exception in your browser. This is because of a self signed
|
||||
certificate; this will be always the case, unless you preload the CA root into your browser/system
|
||||
as trusted.
|
||||
|
||||
You can generate a new certificate using the OpenSSL command line tool:
|
||||
|
||||
```
|
||||
openssl req -newkey rsa:2048 -nodes -keyout prvtkey.pem -x509 -days 3650 -out servercert.pem -subj "/CN=ESP32 HTTPS server example" -addext "keyUsage=critical,digitalSignature,keyEncipherment" -addext "subjectAltName=IP:<server_ip_address>"
|
||||
```
|
||||
|
||||
Replace `<server_ip_address>` with your ESP32's actual IP address (e.g., `192.168.20.178`). The Subject Alternative Name (SAN) extension is required for modern browsers to validate the certificate when connecting via IP address.
|
||||
|
||||
**Important:** Use a static IP address for your ESP32. If the device uses a dynamic IP address, the IP may change, and you will need to regenerate the certificate with the new IP address each time it changes.
|
||||
|
||||
**Note:** The pre-generated certificates in the `main/certs` directory do not include the SAN extension and will not work with modern browsers. You must generate new certificates with the SAN field containing your server's IP address for browser compatibility.
|
||||
|
||||
Expiry time and metadata fields can be adjusted in the invocation.
|
||||
|
||||
Please see the openssl man pages (man openssl-req) for more details.
|
||||
|
||||
It is **strongly recommended** to not reuse the example certificate in your application;
|
||||
it is included only for demonstration.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (8596) example: Starting server
|
||||
I (8596) esp_https_server: Starting server
|
||||
I (8596) esp_https_server: Server listening on port 443
|
||||
I (8596) example: Registering URI handlers
|
||||
I (8606) esp_netif_handlers: example_connect: sta ip: 192.168.194.219, mask: 255.255.255.0, gw: 192.168.194.27
|
||||
I (8616) example_connect: Got IPv4 event: Interface "example_connect: sta" address: 192.168.194.219
|
||||
I (9596) example_connect: Got IPv6 event: Interface "example_connect: sta" address: fe80:0000:0000:0000:266f:28ff:fe80:2c74, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (9596) example_connect: Connected to example_connect: sta
|
||||
W (9606) wifi:<ba-add>idx:0 (ifx:0, ee:6d:19:60:f6:0e), tid:0, ssn:2, winSize:64
|
||||
I (9616) example_connect: - IPv4 address: 192.168.194.219
|
||||
I (9616) example_connect: - IPv6 address: fe80:0000:0000:0000:266f:28ff:fe80:2c74, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
W (14426) wifi:<ba-add>idx:1 (ifx:0, ee:6d:19:60:f6:0e), tid:4, ssn:0, winSize:64
|
||||
I (84896) esp_https_server: performing session handshake
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
set(requires esp_https_server nvs_flash)
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
list(APPEND requires esp_stubs protocol_examples_common)
|
||||
else()
|
||||
list(APPEND requires esp_wifi esp_eth)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES ${requires}
|
||||
EMBED_TXTFILES "certs/servercert.pem"
|
||||
"certs/prvtkey.pem"
|
||||
"certs/cacert.pem"
|
||||
"certs/cakey.pem")
|
||||
@@ -0,0 +1,45 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_ENABLE_HTTPS_USER_CALLBACK
|
||||
bool "Enable user callback with HTTPS Server"
|
||||
help
|
||||
Enable user callback for esp_https_server which can be used to get SSL context (connection information)
|
||||
E.g. Certificate of the connected client
|
||||
|
||||
choice EXAMPLE_ENABLE_HTTPS_SERVER_TLS_VERSION
|
||||
prompt "Choose TLS version"
|
||||
default EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY
|
||||
config EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY
|
||||
bool "TLS 1.2"
|
||||
select MBEDTLS_SSL_PROTO_TLS1_2
|
||||
help
|
||||
Enable HTTPS server TLS 1.2
|
||||
config EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY
|
||||
bool "TLS 1.3"
|
||||
select MBEDTLS_SSL_PROTO_TLS1_3
|
||||
help
|
||||
Enable HTTPS server TLS 1.3
|
||||
config EXAMPLE_ENABLE_HTTPS_SERVER_TLS_ANY
|
||||
bool "TLS 1.3 and 1.2"
|
||||
select MBEDTLS_SSL_PROTO_TLS1_3
|
||||
select MBEDTLS_SSL_PROTO_TLS1_2
|
||||
help
|
||||
Enable HTTPS server TLS 1.3 and 1.2
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||
bool "Enable HTTPS server custom ciphersuites"
|
||||
default n
|
||||
help
|
||||
Enable HTTPS server custom ciphersuites
|
||||
config EXAMPLE_ENABLE_SKIP_CLIENT_CERT
|
||||
bool "Skip client certificate (WARNING: ONLY FOR TESTING PURPOSE, READ HELP)"
|
||||
default n
|
||||
select ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
|
||||
help
|
||||
Allow clients to connect without providing a client certificate.
|
||||
This is useful for testing purposes. When enabled, the server request
|
||||
client certificates but does not require them for the connection to be established.
|
||||
If a client certificate is provided, it will be verified.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,120 @@
|
||||
# Certificate Generation Guide
|
||||
|
||||
This directory contains certificates for the HTTPS server example. This guide explains how to generate new server and client certificates signed by the existing CA certificate.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- OpenSSL installed on your system
|
||||
- Existing CA certificate (`cacert.pem`) and CA private key (`cakey.pem`)
|
||||
- Configuration files for certificate extensions (`server_cert.conf` and `client_cert.conf`)
|
||||
|
||||
## Generating Server Certificate
|
||||
|
||||
Follow these steps to create a new server certificate signed by the CA:
|
||||
|
||||
### 1. Generate Server Private Key
|
||||
|
||||
```bash
|
||||
openssl genpkey -algorithm RSA -out new_server.key -pkeyopt rsa_keygen_bits:2048
|
||||
```
|
||||
|
||||
This creates a 2048-bit RSA private key for the server.
|
||||
|
||||
### 2. Create Certificate Signing Request (CSR)
|
||||
|
||||
```bash
|
||||
openssl req -new -key new_server.key -out new_server.csr -config server_cert.conf
|
||||
```
|
||||
|
||||
This generates a CSR using the server's private key and the configuration specified in `server_cert.conf`.
|
||||
|
||||
### 3. Sign the Server Certificate with CA
|
||||
|
||||
```bash
|
||||
openssl x509 -req -in new_server.csr -CA cacert.pem -CAkey cakey.pem -CAcreateserial -out new_server.pem -days 3650 -extensions v3_req -extfile server_cert.conf
|
||||
```
|
||||
|
||||
This creates the server certificate (`new_server.pem`) valid for 10 years (3650 days), signed by the CA certificate.
|
||||
|
||||
## Generating Client Certificate
|
||||
|
||||
Follow these steps to create a new client certificate signed by the CA:
|
||||
|
||||
### 4. Generate Client Private Key
|
||||
|
||||
```bash
|
||||
openssl genpkey -algorithm RSA -out new_client.key -pkeyopt rsa_keygen_bits:2048
|
||||
```
|
||||
|
||||
This creates a 2048-bit RSA private key for the client.
|
||||
|
||||
### 5. Create Certificate Signing Request (CSR)
|
||||
|
||||
```bash
|
||||
openssl req -new -key new_client.key -out new_client.csr -config client_cert.conf
|
||||
```
|
||||
|
||||
This generates a CSR using the client's private key and the configuration specified in `client_cert.conf`.
|
||||
|
||||
### 6. Sign the Client Certificate with CA
|
||||
|
||||
```bash
|
||||
openssl x509 -req -in new_client.csr -CA cacert.pem -CAkey cakey.pem -CAcreateserial -out new_client.pem -days 3650 -extensions v3_req -extfile client_cert.conf
|
||||
```
|
||||
|
||||
This creates the client certificate (`new_client.pem`) valid for 10 years (3650 days), signed by the CA certificate.
|
||||
|
||||
## Installing the Certificates
|
||||
|
||||
### 7. Copy Certificates to Expected Locations
|
||||
|
||||
```bash
|
||||
cp new_server.pem servercert.pem && \
|
||||
cp new_server.key prvtkey.pem && \
|
||||
cp new_client.pem client_cert.pem && \
|
||||
cp new_client.key client_key.pem
|
||||
```
|
||||
|
||||
This copies the newly generated certificates and keys to the filenames expected by the example application.
|
||||
|
||||
## File Naming Convention
|
||||
|
||||
The example application expects the following files:
|
||||
|
||||
- `servercert.pem` - Server certificate
|
||||
- `prvtkey.pem` - Server private key
|
||||
- `client_cert.pem` - Client certificate
|
||||
- `client_key.pem` - Client private key
|
||||
- `cacert.pem` - CA certificate (for verification)
|
||||
|
||||
## Security Notes
|
||||
|
||||
⚠️ **Important Security Considerations:**
|
||||
|
||||
- The private keys (`prvtkey.pem`, `client_key.pem`, `cakey.pem`) should be kept secure. As these are for demonstration purposes, they are included here, but in a production environment, ensure they are stored securely and access is restricted.
|
||||
- The certificates in this example directory are for **demonstration purposes only**
|
||||
- For production use, generate new certificates with appropriate security parameters
|
||||
- Consider using shorter validity periods for production certificates
|
||||
- Store private keys with restricted file permissions (e.g., `chmod 600`)
|
||||
|
||||
## Verifying Generated Certificates
|
||||
|
||||
You can verify the generated certificates using:
|
||||
|
||||
```bash
|
||||
# Verify server certificate
|
||||
openssl x509 -in servercert.pem -text -noout
|
||||
|
||||
# Verify client certificate
|
||||
openssl x509 -in client_cert.pem -text -noout
|
||||
|
||||
# Verify certificate chain
|
||||
openssl verify -CAfile cacert.pem servercert.pem
|
||||
openssl verify -CAfile cacert.pem client_cert.pem
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If certificate verification fails, ensure the CA certificate and key are valid and match
|
||||
- Check that the configuration files (`server_cert.conf`, `client_cert.conf`) contain appropriate Subject Alternative Names (SANs) and extensions
|
||||
- Ensure OpenSSL version is up to date for best compatibility
|
||||
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDOzCCAiOgAwIBAgIUG/S51QF4EeUkdaqg54oogqIKBZkwDQYJKoZIhvcNAQEL
|
||||
BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMjUw
|
||||
NDAyMDcwMzI2WhcNMzUwMzMxMDcwMzI2WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ
|
||||
UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T
|
||||
sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k
|
||||
qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd
|
||||
GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4
|
||||
sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb
|
||||
jAn4PCuR2akdF4G8WLUeDWECAwEAAaNjMGEwHQYDVR0OBBYEFMnmdJKOEepXrHI/
|
||||
ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQBP
|
||||
AgAagM33DqsDi+UArUxEoqmov1rH0PHXnd/a6Ct/IvNzr0qUH8hW4Lv0tWHfOJY8
|
||||
pCf7bkejxXlhP/QHb6M+sobN9tN/WupEaeqNg4pCWi+6Caj2uFW9vkQQf2j50lMg
|
||||
R0oxnd6SMEQArzy3f3yYRp8rliPERY6F2Rtb9HJNh53K51FE60xONPLZ/1dtSgDB
|
||||
KcJseZfhg6oAUSLjFCYJEn5xa7CsIuQ8Jx2xMo4IkU44BJ8TJS4zw/hP1/vVjjvS
|
||||
uU2Z0ZOUCQ78/3eMnsFfLMtDUYqXPyhNogm51GeHOR6dk+ICQ+c5gCDkJUnOTqzg
|
||||
G2JUmXAXxJoUZDfalijl
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH
|
||||
JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw
|
||||
h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT
|
||||
aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al
|
||||
3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg
|
||||
0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB
|
||||
vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui
|
||||
f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9
|
||||
Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y
|
||||
JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX
|
||||
49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc
|
||||
+3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6
|
||||
pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D
|
||||
0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG
|
||||
YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV
|
||||
MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL
|
||||
CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin
|
||||
7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1
|
||||
noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8
|
||||
4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g
|
||||
Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/
|
||||
nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3
|
||||
q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2
|
||||
lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB
|
||||
jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr
|
||||
v/t+MeGJP/0Zw8v/X2CFll96
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,16 @@
|
||||
[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
prompt = no
|
||||
|
||||
[req_distinguished_name]
|
||||
C = SG
|
||||
ST = SG
|
||||
L = SG
|
||||
O = ESP32 Client
|
||||
CN = ESP32 Test Client
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = clientAuth
|
||||
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDfDCCAmSgAwIBAgIUeWALux8MJqS983GSSUHotYp9OxgwDQYJKoZIhvcNAQEL
|
||||
BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMjUx
|
||||
MDEwMDIzOTIxWhcNMzUxMDA4MDIzOTIxWjBaMQswCQYDVQQGEwJTRzELMAkGA1UE
|
||||
CAwCU0cxCzAJBgNVBAcMAlNHMRUwEwYDVQQKDAxFU1AzMiBDbGllbnQxGjAYBgNV
|
||||
BAMMEUVTUDMyIFRlc3QgQ2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAsWm6XLeoa2dVtUn+hEZMULUSS0RqcE9kPHBQCwRNSlDs6eUSy4Y45SO0
|
||||
P5aqDLd7vMcDg41YPDbXp6JhvKov2Q7pAVbwhrLzn+M6O7XS+7i8J9PzgjBTKMhC
|
||||
rLkGBYbyW04STIbgHmQ0G98y6deyXnkqg/d0OzNaB4XgOiRbuxw1IaPX2loTS5aV
|
||||
hnuo/5tdcyiNMAjio/P1GrkE1OPSUwbdxROjmZW5peFkD4sogW/XH0oMYpMKwyWZ
|
||||
cHiuj5E4IxeazqaJqzjbXIj7+hTywE2kXZDVK1o02JbkDRhig5NkXv38DyNu8R8W
|
||||
dvh3GBczZS7lIn+2fjr3soILMOJ/NwIDAQABo28wbTAJBgNVHRMEAjAAMAsGA1Ud
|
||||
DwQEAwIF4DATBgNVHSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUubkj5sTevwdf
|
||||
SMd2J5WyKkrqtfIwHwYDVR0jBBgwFoAUyeZ0ko4R6lescj+K8zqZWomABfwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAJmjtzv5aMkNKw8+EwDrdOHJsw6czOtPeVLTmIy02+Pv
|
||||
4rvn+4VDCzogM7oBbFzFFGwUmBXqfdmP4wteqtfdCwHboiCzZySPw0O+OMbhQmEF
|
||||
mCE+k+sCUEWrb3tiraVWh1aipoqOqE0WNcyZ1ZwY1OCMaVYsfFXw3lcND/7VXjp6
|
||||
13WSO46avn3WvesTS/GhLg8yTJiQ8iPXMEEKhf7BTAn461ZsGR3hnz+DPtWTTOaI
|
||||
9fCdjvvYsL4+k3+Y10LWUSsmB6kjyzCmx7/I4NeUEGmMAD4PD5dkkksw+TZBobsb
|
||||
APf44t+dQGYc0dhfym7b+qeW8MTvmx40ZYL52HG7XCU=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxabpct6hrZ1W1
|
||||
Sf6ERkxQtRJLRGpwT2Q8cFALBE1KUOzp5RLLhjjlI7Q/lqoMt3u8xwODjVg8Nten
|
||||
omG8qi/ZDukBVvCGsvOf4zo7tdL7uLwn0/OCMFMoyEKsuQYFhvJbThJMhuAeZDQb
|
||||
3zLp17JeeSqD93Q7M1oHheA6JFu7HDUho9faWhNLlpWGe6j/m11zKI0wCOKj8/Ua
|
||||
uQTU49JTBt3FE6OZlbml4WQPiyiBb9cfSgxikwrDJZlweK6PkTgjF5rOpomrONtc
|
||||
iPv6FPLATaRdkNUrWjTYluQNGGKDk2Re/fwPI27xHxZ2+HcYFzNlLuUif7Z+Ovey
|
||||
ggsw4n83AgMBAAECggEAMLZZg7yvwzG/0EOtXQ9aQ+y7xavW19iMqqWh7Kx1NlsK
|
||||
+du6ceR8Obo4cx9AuLYmhPpV5iiImhvq0a3dzSojciNMaeA/sZRwHS4MXrm5YQFj
|
||||
tEHXgh8XrkJyQC+bTigz4ksI7jc4UU/tGNwLhDaD1LnLKSnoIZsjdJ5XJ0+1WiXa
|
||||
pyTy5KBtKyhhLzy+toFeheNMbHV2yf2dFEFYM+76DKgXyMwNF1NzDUNhmxJrc/8H
|
||||
0qb4P/gFgWe1H3ZveY/iOyLzqmqBQw02blug+YHxLfC9Gc7Wz6aY86YxGg1bKjvi
|
||||
AG1GxtCKhUzBZMH7gGZSQJ+6Beq5cNReEgbSJu2N1QKBgQDnlz6cy22SMORCqUc9
|
||||
CO+NwzZeywruY8wjhZYx0kKqeC/g5Ama1+2THL7DVR+dgTJOuRvBgBtps/jfQKdz
|
||||
BpVeIfAH2n6x+62tjnHW274BwQy8SEf7nc4hvEY/PKUSqZ4JAeNISghHgfCMtcoW
|
||||
Lv7Ehbx+uA1AJPsGwIgCmlxBlQKBgQDEHKoZ2jeLlouYFsJlgEpqcLRQA+z8QsR7
|
||||
DSNjBZmuC4kKkQuoWhRoyvvgZIxT5xLkKG0eUh7kKsOdJ7Fv448rr6I9A03z9dDw
|
||||
bGrDl+vKlHSyo+9rfw8HXPG8G1b2X0K9LI8t6wBKHSPt8Bv5CXL9exJVQ33CndMW
|
||||
iIfpns0imwKBgANqyOK5YbGBhSyyoLl200oNMlUtu8iOsmlnxDKR/qfTRCmWU8n0
|
||||
G65LA0mQjPne+SYONymgwUbLAAYTRyU8WKHd8FO9Vpc7tnFUI7ve3CvcdFqm2mEN
|
||||
EAiRZZvzQiBHXmyVmYvsg7jCYxFAcW3oXZv6uTBJePCUWxvbZWZcbrYNAoGAcgWY
|
||||
gN93XBlzoEHbVNh6a9iLfdpKd4D6a/D/mhsvdxoN267pcECvjR43xAex7zZyrWUz
|
||||
zGVCwLZ8dWsWp09Pdr7vPTomoKlTifX/PSmfVnFqSFM4aO++9TD8+7mJnkVUsFiw
|
||||
BqqTyIOY2Ea6fNkZmndr+Vb8T6Mjj/5hx1slOfECgYEAttRU86Duvm8gypIux5xY
|
||||
CZeYiNCbZ/4+mR5yvfhVpMk2BJyOvtmoe6PnM+VLm+pNjZdK6mkPevXC6ownbyTl
|
||||
WOOmoxnl0lbZiKBmreNrdSKuAgezAATLQdipzuV8R4Udsko0lF03ZT1uMTBqI0Fs
|
||||
Kid3fvAzqQtoCLPyRsfKAr0=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+8VU37LjhtI2p
|
||||
/O8QCBdhFzzYv/+3VipAySD7TCCO6coHEs8PyV6z+uQ868PRmkyqBJgbW0/WdSt4
|
||||
RCTyCraTNMDIWEuoxbFHSLObT6fiMU9vlYcNlZkCMFIEqgd4r5657tQi1ROZ8gOD
|
||||
Jx3zpW9M5Yl5+jSDzLP7oAJWgbf3rTK/ePk4AU7SWAJGQXcD/C8RLsryyWE0Lps/
|
||||
X/B24GTXEj+u4Gp761KilDX8M3wLeLvYBb9DZ3rDwCXPJ8ukVc7ui5VZgGTOykVz
|
||||
u8YUnc0jJI7ptaOMv4oDniJ6aqfGaV8ghwo1xq3Rpbo0jOOeFgjOgM8JyCtbK/4r
|
||||
sRHiep3rAgMBAAECggEAH3x+V/2CMz3pymk6JsOez1TcpMVsbpgX2Z0RAj94cvic
|
||||
ZvQ0Dt9e7YDm2CDspoiyMasWRhSVosCpjWh3Sy53Euk1DRR6TXdkF2Qmseq9vW/y
|
||||
MG1Q2u2bUKAVNk2vc7hKDVETzDakx9L/v0XZC49xPhXvyJx4wm8kEs8883TqmD2/
|
||||
T5d7Xs7Rxkwo3iduqwHs3jWgJWwi44Il+ATfySAbymTZcPCXxOtWjvStAjgjtMEm
|
||||
KQYvvb0ZJIpqiPDH0Inq4D8U1AE0i16RlRteN6UB7avEP1v0SHFg1P2hTzWrwjZD
|
||||
lpgQ5JU6WO8tdtddMuR3u4hO5g6MJ2k5wkdLOjLTuQKBgQDm0ijy2/mCiqvKxaVp
|
||||
4hdAaTssHxT/+hDtWlcpqqYCgmNX7KRIzfTWLDg3qhENLcrxdBNt8bnhas2/E0/I
|
||||
IA8NyB9tkQlEXv5DYfUHG7ZFUndBgIftFRLM0Ibfx4A58PjQWwe9jtqSpQJdrEL6
|
||||
WRXsSBuveAqB4BTMtimUfxRH1wKBgQDTxYt1tij+x+ApVE4k//Vf+loKWOXDO/Bm
|
||||
R+O1e0mYEViEjpHd2QCEyy6JTYkTktO9yLt2A5rpZiDIA2wqnl0VMUXTbUOvsLNH
|
||||
UXOpy2rebWgEEZkTq/aFkhH4juLfimT6lJzZ18navPuFIj5Nj1emFU5NHQSOZ/EA
|
||||
6OPo5eXIDQKBgEDudd57yyDR6anNF89Fbs0LzT2IMNwheImMlGCARNsH2vJs+3oP
|
||||
lgR5xAbErK9MZn6t7JlNGsEyzlYmFJdzjUiPN2gXGMhHALfr4oXxYcD2hd3DTnl/
|
||||
KB69unNRJ90k0JmsQe0tNodyK8w2HVFXpjclwcQGvM30P2WnCONhLE9ZAoGAHcKz
|
||||
OJWi6Ts5m1VHrhdyakyKfs3DbE5uGFGeBJEQ5Jf7cpV+lki6s+7B2XXV/7QwoYkm
|
||||
Hw2epZI+pR0mBE9BEYtdHrtKOdSBPVKLCJ+Xoy6I4Zl/g6409Mx0ThP2eie+zSA5
|
||||
crvKmDzas/j9/HRagvKXkGq1izW8Pr572O0F/7kCgYANIGZ2YyGbuRdDxtNd1B/F
|
||||
MhK9Njbwee8FN5Emxyq/nJJe13gyNDRCmDqUlTDbCXVCyT3fWg6dLVZu0igf3Zf2
|
||||
+Z8lHBOD1VVBRdsYtRyZ/OvYksjOtBnZ5l4rMMt7MGxhA1Dm/oO/3ub0/dhrXnb+
|
||||
MD6TRIZ3GhAZ1SPeuhEF5w==
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,20 @@
|
||||
[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
prompt = no
|
||||
|
||||
[req_distinguished_name]
|
||||
C = SG
|
||||
ST = SG
|
||||
L = SG
|
||||
O = ESP32
|
||||
CN = ESP32 HTTPS Server
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = esp32-server
|
||||
DNS.2 = localhost
|
||||
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDhTCCAm2gAwIBAgIUeWALux8MJqS983GSSUHotYp9OxcwDQYJKoZIhvcNAQEL
|
||||
BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMjUx
|
||||
MDEwMDIzOTAwWhcNMzUxMDA4MDIzOTAwWjBUMQswCQYDVQQGEwJTRzELMAkGA1UE
|
||||
CAwCU0cxCzAJBgNVBAcMAlNHMQ4wDAYDVQQKDAVFU1AzMjEbMBkGA1UEAwwSRVNQ
|
||||
MzIgSFRUUFMgU2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
vvFVN+y44bSNqfzvEAgXYRc82L//t1YqQMkg+0wgjunKBxLPD8les/rkPOvD0ZpM
|
||||
qgSYG1tP1nUreEQk8gq2kzTAyFhLqMWxR0izm0+n4jFPb5WHDZWZAjBSBKoHeK+e
|
||||
ue7UItUTmfIDgycd86VvTOWJefo0g8yz+6ACVoG3960yv3j5OAFO0lgCRkF3A/wv
|
||||
ES7K8slhNC6bP1/wduBk1xI/ruBqe+tSopQ1/DN8C3i72AW/Q2d6w8AlzyfLpFXO
|
||||
7ouVWYBkzspFc7vGFJ3NIySO6bWjjL+KA54iemqnxmlfIIcKNcat0aW6NIzjnhYI
|
||||
zoDPCcgrWyv+K7ER4nqd6wIDAQABo34wfDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF
|
||||
4DAiBgNVHREEGzAZggxlc3AzMi1zZXJ2ZXKCCWxvY2FsaG9zdDAdBgNVHQ4EFgQU
|
||||
U2FQtf+ar/qQtk5hBObVuW/VAjMwHwYDVR0jBBgwFoAUyeZ0ko4R6lescj+K8zqZ
|
||||
WomABfwwDQYJKoZIhvcNAQELBQADggEBAHS3Nr8OTEWV6s5srMDxnvjry4XmBOU2
|
||||
gvNxLe7xci6DShCpFK+S+W/Vqmv0I17TEW5cV8Z/P5HKtiYAvNI7Ptc6BTK20Q83
|
||||
jKC6kSYMlK54zW4ZNbnvI/zwtMNh4YLiLVjSQxMe11qaTu7eOqI49qEmgNP82VPu
|
||||
JmFvO4W05McdUJ3xxVJVJk3l8ZTjgOTPfL/bbqibYSvewsyJlo2ihIHezP4Au/4Z
|
||||
2Wpzj1scBDSucDTsWBkXMGdV4tUpUuDYLJF2XqKwIm39IkoxdPnHANC62OtcLawh
|
||||
FOjfM34YqanizzWwfjNl6OD8vWP4ztIf3J4jONiDnnpVIo6skAGYTyQ=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
esp_stubs:
|
||||
path: ${IDF_PATH}/examples/protocols/linux_stubs/esp_stubs
|
||||
rules:
|
||||
- if: "target in [linux]"
|
||||
@@ -0,0 +1,324 @@
|
||||
/* Simple HTTP + SSL Server Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#if !CONFIG_IDF_TARGET_LINUX
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_system.h>
|
||||
#include "esp_eth.h"
|
||||
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||
|
||||
#include <esp_https_server.h>
|
||||
#include "esp_tls.h"
|
||||
#include "esp_key_config.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||
#include "mbedtls/ssl_ciphersuites.h"
|
||||
#endif // CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||
|
||||
/* A simple example that demonstrates how to create GET and POST
|
||||
* handlers and start an HTTPS server.
|
||||
*/
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
#ifdef CONFIG_ESP_HTTPS_SERVER_EVENTS
|
||||
/* Event handler for catching system events */
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
if (event_base == ESP_HTTPS_SERVER_EVENT) {
|
||||
if (event_id == HTTPS_SERVER_EVENT_ERROR) {
|
||||
esp_https_server_last_error_t *last_error = (esp_tls_last_error_t *) event_data;
|
||||
ESP_LOGE(TAG, "Error event triggered: last_error = %s, last_tls_err = %d, tls_flag = %d", esp_err_to_name(last_error->last_error), last_error->esp_tls_error_code, last_error->esp_tls_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_ESP_HTTPS_SERVER_EVENTS
|
||||
|
||||
/* An HTTP GET handler */
|
||||
static esp_err_t root_get_handler(httpd_req_t *req)
|
||||
{
|
||||
httpd_resp_set_type(req, "text/html");
|
||||
httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
static 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);
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* Example callback function to get the certificate of connected clients,
|
||||
* whenever a new SSL connection is created and closed
|
||||
*
|
||||
* Can also be used to other information like Socket FD, Connection state, etc.
|
||||
*
|
||||
* NOTE: This callback will not be able to obtain the client certificate if the
|
||||
* following config `Set minimum Certificate Verification mode to Optional` is
|
||||
* not enabled (enabled by default in this example).
|
||||
*
|
||||
* The config option is found here - Component config → ESP-TLS
|
||||
*
|
||||
*/
|
||||
static void https_server_user_callback(esp_https_server_user_cb_arg_t *user_cb)
|
||||
{
|
||||
ESP_LOGI(TAG, "User callback invoked!");
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
mbedtls_ssl_context *ssl_ctx = NULL;
|
||||
#endif
|
||||
switch(user_cb->user_cb_state) {
|
||||
case HTTPD_SSL_USER_CB_SESS_CREATE:
|
||||
ESP_LOGD(TAG, "At session creation");
|
||||
|
||||
// Logging the socket FD
|
||||
int sockfd = -1;
|
||||
esp_err_t esp_ret;
|
||||
esp_ret = esp_tls_get_conn_sockfd(user_cb->tls, &sockfd);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error in obtaining the sockfd from tls context");
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket FD: %d", sockfd);
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
ssl_ctx = (mbedtls_ssl_context *) esp_tls_get_ssl_context(user_cb->tls);
|
||||
if (ssl_ctx == NULL) {
|
||||
ESP_LOGE(TAG, "Error in obtaining ssl context");
|
||||
break;
|
||||
}
|
||||
// Logging the current ciphersuite
|
||||
ESP_LOGI(TAG, "Current Ciphersuite: %s", mbedtls_ssl_get_ciphersuite(ssl_ctx));
|
||||
#endif
|
||||
break;
|
||||
|
||||
case HTTPD_SSL_USER_CB_SESS_CLOSE:
|
||||
ESP_LOGD(TAG, "At session close");
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
// Logging the peer certificate
|
||||
ssl_ctx = (mbedtls_ssl_context *) esp_tls_get_ssl_context(user_cb->tls);
|
||||
if (ssl_ctx == NULL) {
|
||||
ESP_LOGE(TAG, "Error in obtaining ssl context");
|
||||
break;
|
||||
}
|
||||
print_peer_cert_info(ssl_ctx);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case HTTPD_SSL_USER_CB_SESS_ERROR:
|
||||
ESP_LOGD(TAG, "At session error (handshake failed)");
|
||||
// Get socket FD to log failing client IP address
|
||||
sockfd = -1;
|
||||
esp_ret = esp_tls_get_conn_sockfd(user_cb->tls, &sockfd);
|
||||
if (esp_ret == ESP_OK && sockfd >= 0) {
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
if (getpeername(sockfd, (struct sockaddr*)&addr, &len) == 0) {
|
||||
char ip_str[INET6_ADDRSTRLEN];
|
||||
if (addr.ss_family == AF_INET) {
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in*)&addr)->sin_addr, ip_str, sizeof(ip_str));
|
||||
} else if (addr.ss_family == AF_INET6) {
|
||||
inet_ntop(AF_INET6, &((struct sockaddr_in6*)&addr)->sin6_addr, ip_str, sizeof(ip_str));
|
||||
} else {
|
||||
strcpy(ip_str, "unknown");
|
||||
}
|
||||
ESP_LOGW(TAG, "SSL handshake failed from client IP: %s", ip_str);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(TAG, "Illegal state!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const httpd_uri_t root = {
|
||||
.uri = "/",
|
||||
.method = HTTP_GET,
|
||||
.handler = root_get_handler
|
||||
};
|
||||
|
||||
static httpd_handle_t start_webserver(void)
|
||||
{
|
||||
httpd_handle_t server = NULL;
|
||||
|
||||
// Start the httpd server
|
||||
ESP_LOGI(TAG, "Starting server");
|
||||
|
||||
httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
|
||||
|
||||
#if CONFIG_IDF_TARGET_LINUX
|
||||
/* Use non-privileged port on Linux since port 443 requires root */
|
||||
conf.port_secure = 8443;
|
||||
#endif
|
||||
|
||||
extern const unsigned char servercert_start[] asm("_binary_servercert_pem_start");
|
||||
extern const unsigned char servercert_end[] asm("_binary_servercert_pem_end");
|
||||
|
||||
extern const unsigned char cacert_start[] asm("_binary_cacert_pem_start");
|
||||
extern const unsigned char cacert_end[] asm("_binary_cacert_pem_end");
|
||||
conf.servercert = servercert_start;
|
||||
conf.servercert_len = servercert_end - servercert_start;
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_SKIP_CLIENT_CERT
|
||||
conf.client_cert_authmode_optional = true;
|
||||
#endif // EXAMPLE_ENABLE_SKIP_CLIENT_CERT
|
||||
|
||||
conf.cacert_pem = cacert_start;
|
||||
conf.cacert_len = cacert_end - cacert_start;
|
||||
|
||||
extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
|
||||
extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
|
||||
static esp_key_config_t server_key = {
|
||||
.source = ESP_KEY_SOURCE_BUFFER,
|
||||
.buffer = {
|
||||
.data = prvtkey_pem_start,
|
||||
}
|
||||
};
|
||||
server_key.buffer.len = prvtkey_pem_end - prvtkey_pem_start;
|
||||
conf.server_key = &server_key;
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||
static const int ciphersuites_to_use[] = {
|
||||
MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||
MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||
MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||
0,
|
||||
};
|
||||
conf.ciphersuites_list = ciphersuites_to_use;
|
||||
#else
|
||||
conf.ciphersuites_list = NULL;
|
||||
#endif // CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY
|
||||
conf.tls_version = ESP_TLS_VER_TLS_1_3;
|
||||
#elif CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY
|
||||
conf.tls_version = ESP_TLS_VER_TLS_1_2;
|
||||
#else
|
||||
conf.tls_version = ESP_TLS_VER_ANY;
|
||||
#endif // CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK
|
||||
conf.user_cb = https_server_user_callback;
|
||||
#endif
|
||||
esp_err_t ret = httpd_ssl_start(&server, &conf);
|
||||
if (ESP_OK != ret) {
|
||||
ESP_LOGI(TAG, "Error starting server!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set URI handlers
|
||||
ESP_LOGI(TAG, "Registering URI handlers");
|
||||
httpd_register_uri_handler(server, &root);
|
||||
return server;
|
||||
}
|
||||
|
||||
#if !CONFIG_IDF_TARGET_LINUX
|
||||
static esp_err_t stop_webserver(httpd_handle_t server)
|
||||
{
|
||||
// Stop the httpd server
|
||||
return httpd_ssl_stop(server);
|
||||
}
|
||||
|
||||
static void disconnect_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
httpd_handle_t* server = (httpd_handle_t*) arg;
|
||||
if (*server) {
|
||||
if (stop_webserver(*server) == ESP_OK) {
|
||||
*server = NULL;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to stop https server");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
httpd_handle_t* server = (httpd_handle_t*) arg;
|
||||
if (*server == NULL) {
|
||||
*server = start_webserver();
|
||||
}
|
||||
}
|
||||
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
static httpd_handle_t server = NULL;
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* Register event handlers to start server when Wi-Fi or Ethernet is connected,
|
||||
* and stop server when disconnection happens.
|
||||
*/
|
||||
|
||||
#if !CONFIG_IDF_TARGET_LINUX
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server));
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||
#ifdef CONFIG_ESP_HTTPS_SERVER_EVENTS
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(ESP_HTTPS_SERVER_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
#endif // CONFIG_ESP_HTTPS_SERVER_EVENTS
|
||||
|
||||
/* 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 CONFIG_IDF_TARGET_LINUX
|
||||
/* On Linux, start the server directly since there are no WiFi/Ethernet events */
|
||||
server = start_webserver();
|
||||
while (server) {
|
||||
sleep(5);
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_LINUX
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import http.client
|
||||
import logging
|
||||
import os
|
||||
import ssl
|
||||
|
||||
import pytest
|
||||
from common_test_methods import get_env_config_variable
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
CURRENT_FILE_PATH = os.path.dirname(__file__)
|
||||
|
||||
CACERT_FILE_PATH = os.path.join(CURRENT_FILE_PATH, './main/certs/cacert.pem')
|
||||
CLIENT_CERT_PATH = os.path.join(CURRENT_FILE_PATH, './main/certs/client_cert.pem')
|
||||
CLIENT_KEY_PATH = os.path.join(CURRENT_FILE_PATH, './main/certs/client_key.pem')
|
||||
|
||||
success_response = '<h1>Hello Secure World!</h1>'
|
||||
|
||||
|
||||
@pytest.mark.wifi_router
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3', 'esp32s3'], indirect=['target'])
|
||||
def test_examples_protocol_https_server_simple(dut: Dut) -> None:
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
2. connect to www.howsmyssl.com:443
|
||||
3. send http request
|
||||
"""
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'https_server.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info(f'https_server_simple_bin_size : {bin_size // 1024}KB')
|
||||
# start test
|
||||
logging.info('Waiting to connect with AP')
|
||||
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
||||
dut.expect('Please input ssid password:')
|
||||
env_name = 'wifi_router'
|
||||
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}')
|
||||
# Parse IP address and port of the server
|
||||
dut.expect(r'Starting server')
|
||||
got_port = int(dut.expect(r'Server listening on port (\d+)', timeout=30)[1].decode())
|
||||
got_ip = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
|
||||
|
||||
# Expected logs
|
||||
|
||||
logging.info(f'Got IP : {got_ip}')
|
||||
logging.info(f'Got Port : {got_port}')
|
||||
|
||||
# Try requesting without client certificate and it should fail if client cert is required
|
||||
logging.info('Performing GET request over an SSL connection with the server without client certificate')
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
# Load the CA certificate from the path
|
||||
ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH)
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
logging.info('Performing SSL handshake with the server without client certificate')
|
||||
try:
|
||||
conn.request('GET', '/')
|
||||
resp = conn.getresponse()
|
||||
resp.read().decode('utf-8')
|
||||
except Exception as e:
|
||||
if dut.app.sdkconfig.get('EXAMPLE_ENABLE_SKIP_CLIENT_CERT') is True:
|
||||
logging.info('SSL handshake failed without client certificate but was expected to be successful')
|
||||
raise RuntimeError('Failed to test SSL connection') from e
|
||||
else:
|
||||
logging.info('SSL handshake failed without client certificate as expected')
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
logging.info('Performing GET request over an SSL connection with the server')
|
||||
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH)
|
||||
|
||||
ssl_context.load_cert_chain(certfile=CLIENT_CERT_PATH, keyfile=CLIENT_KEY_PATH)
|
||||
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
logging.info('Performing SSL handshake with the server')
|
||||
conn.request('GET', '/')
|
||||
resp = conn.getresponse()
|
||||
dut.expect('performing session handshake')
|
||||
got_resp = resp.read().decode('utf-8')
|
||||
if got_resp != success_response:
|
||||
logging.info('Response obtained does not match with correct response')
|
||||
raise RuntimeError('Failed to test SSL connection')
|
||||
|
||||
if dut.app.sdkconfig.get('EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||
|
||||
conn.close()
|
||||
|
||||
logging.info('Checking user callback: Obtaining client certificate...')
|
||||
|
||||
serial_number = dut.expect(r'serial number\s*:([^\n]*)', timeout=5)[0]
|
||||
issuer_name = dut.expect(r'issuer name\s*:([^\n]*)', timeout=5)[0]
|
||||
expiry = dut.expect(r'expires on ((.*)\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])*)', timeout=5)[
|
||||
1
|
||||
].decode()
|
||||
|
||||
logging.info(f'Serial No. {serial_number}')
|
||||
logging.info(f'Issuer Name {issuer_name}')
|
||||
logging.info(f'Expires on {expiry}')
|
||||
logging.info('Correct response obtained')
|
||||
logging.info('SSL connection test successful\nClosing the connection')
|
||||
|
||||
|
||||
@pytest.mark.wifi_router
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'dynamic_buffer',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3', 'esp32s3'], indirect=['target'])
|
||||
def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None:
|
||||
# Test with mbedTLS dynamic buffer feature
|
||||
|
||||
# start test
|
||||
logging.info('Waiting to connect with AP')
|
||||
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
||||
dut.expect('Please input ssid password:')
|
||||
env_name = 'wifi_router'
|
||||
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}')
|
||||
# Parse IP address and port of the server
|
||||
dut.expect(r'Starting server')
|
||||
got_port = int(dut.expect(r'Server listening on port (\d+)', timeout=30)[1].decode())
|
||||
got_ip = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
|
||||
|
||||
# Expected logs
|
||||
|
||||
logging.info(f'Got IP : {got_ip}')
|
||||
logging.info(f'Got Port : {got_port}')
|
||||
|
||||
logging.info('Performing GET request over an SSL connection with the server')
|
||||
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH)
|
||||
|
||||
ssl_context.load_cert_chain(certfile=CLIENT_CERT_PATH, keyfile=CLIENT_KEY_PATH)
|
||||
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
logging.info('Performing SSL handshake with the server')
|
||||
conn.request('GET', '/')
|
||||
resp = conn.getresponse()
|
||||
dut.expect('performing session handshake')
|
||||
got_resp = resp.read().decode('utf-8')
|
||||
if got_resp != success_response:
|
||||
logging.info('Response obtained does not match with correct response')
|
||||
raise RuntimeError('Failed to test SSL connection')
|
||||
|
||||
if dut.app.sdkconfig.get('EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||
|
||||
# Close the connection
|
||||
conn.close()
|
||||
|
||||
logging.info('Checking user callback: Obtaining client certificate...')
|
||||
|
||||
serial_number = dut.expect(r'serial number\s*:([^\n]*)', timeout=5)[0]
|
||||
issuer_name = dut.expect(r'issuer name\s*:([^\n]*)', timeout=5)[0]
|
||||
expiry = dut.expect(r'expires on\s*:((.*)\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])*)', timeout=5)[
|
||||
1
|
||||
].decode()
|
||||
|
||||
logging.info(f'Serial No. : {serial_number}')
|
||||
logging.info(f'Issuer Name : {issuer_name}')
|
||||
logging.info(f'Expires on : {expiry}')
|
||||
|
||||
logging.info('Correct response obtained')
|
||||
logging.info('SSL connection test successful\nClosing the connection')
|
||||
|
||||
|
||||
@pytest.mark.wifi_router
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'tls1_3',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3', 'esp32s3'], indirect=['target'])
|
||||
def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
|
||||
logging.info('Waiting to connect with AP')
|
||||
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
||||
dut.expect('Please input ssid password:')
|
||||
env_name = 'wifi_router'
|
||||
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}')
|
||||
# Parse IP address and port of the server
|
||||
dut.expect(r'Starting server')
|
||||
got_port = int(dut.expect(r'Server listening on port (\d+)', timeout=30)[1].decode())
|
||||
got_ip = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
|
||||
|
||||
# Expected logs
|
||||
logging.info(f'Got IP : {got_ip}')
|
||||
logging.info(f'Got Port : {got_port}')
|
||||
logging.info('Performing GET request over an SSL connection with the server using TLSv1.3')
|
||||
|
||||
# First try requesting without client certificate and it should also pass if client cert is optional or none
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_3
|
||||
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH)
|
||||
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
logging.info('Performing SSL handshake with the server without client certificate')
|
||||
try:
|
||||
conn.request('GET', '/')
|
||||
resp = conn.getresponse()
|
||||
resp.read().decode('utf-8')
|
||||
if dut.app.sdkconfig.get('EXAMPLE_ENABLE_SKIP_CLIENT_CERT') is True:
|
||||
dut.expect('performing session handshake')
|
||||
logging.info('SSL handshake successful without client certificate as expected')
|
||||
else:
|
||||
logging.info('SSL handshake successful without client certificate but was expected to fail')
|
||||
raise RuntimeError('Failed to test SSL connection')
|
||||
except Exception as e:
|
||||
if dut.app.sdkconfig.get('EXAMPLE_ENABLE_SKIP_CLIENT_CERT') is True:
|
||||
logging.info(f'SSL handshake failed without client certificate but was expected to be successful: {e}')
|
||||
raise RuntimeError('Failed to test SSL connection')
|
||||
else:
|
||||
logging.info('SSL handshake failed without client certificate as expected')
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
# First try with TLSv1.2 and that should fail
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_2
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH)
|
||||
ssl_context.load_cert_chain(certfile=CLIENT_CERT_PATH, keyfile=CLIENT_KEY_PATH)
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
try:
|
||||
conn.request('GET', '/')
|
||||
except ssl.SSLError as e:
|
||||
logging.info(f'SSL handshake failed with TLSv1.2: {e}')
|
||||
else:
|
||||
logging.info('SSL handshake succeeded with TLSv1.2')
|
||||
raise RuntimeError('This should have failed')
|
||||
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_3
|
||||
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3
|
||||
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
logging.info('Performing SSL handshake with the server')
|
||||
conn.request('GET', '/')
|
||||
resp = conn.getresponse()
|
||||
dut.expect('performing session handshake')
|
||||
got_resp = resp.read().decode('utf-8')
|
||||
if got_resp != success_response:
|
||||
logging.info('Response obtained does not match with correct response')
|
||||
raise RuntimeError('Failed to test SSL connection')
|
||||
|
||||
if dut.app.sdkconfig.get('EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||
|
||||
conn.close()
|
||||
|
||||
logging.info('Checking user callback: Obtaining client certificate...')
|
||||
|
||||
serial_number = dut.expect(r'serial number\s*:([^\n]*)', timeout=5)[0]
|
||||
issuer_name = dut.expect(r'issuer name\s*:([^\n]*)', timeout=5)[0]
|
||||
expiry = dut.expect(
|
||||
r'expires on\s*:((.*)\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])*)',
|
||||
timeout=5,
|
||||
)[1].decode()
|
||||
|
||||
logging.info(f'Serial No. : {serial_number}')
|
||||
logging.info(f'Issuer Name : {issuer_name}')
|
||||
logging.info(f'Expires on : {expiry}')
|
||||
|
||||
logging.info('Correct response obtained')
|
||||
logging.info('SSL connection test successful\nClosing the connection')
|
||||
|
||||
|
||||
@pytest.mark.wifi_router
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'tls1_2_only',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3', 'esp32s3'], indirect=['target'])
|
||||
def test_examples_protocol_https_server_tls1_2_only(dut: Dut) -> None:
|
||||
logging.info('Waiting to connect with AP')
|
||||
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
||||
dut.expect('Please input ssid password:')
|
||||
env_name = 'wifi_router'
|
||||
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}')
|
||||
# Parse IP address and port of the server
|
||||
dut.expect(r'Starting server')
|
||||
got_port = int(dut.expect(r'Server listening on port (\d+)', timeout=30)[1].decode())
|
||||
got_ip = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode()
|
||||
|
||||
# Expected logs
|
||||
logging.info(f'Got IP : {got_ip}')
|
||||
logging.info(f'Got Port : {got_port}')
|
||||
logging.info('Performing GET request over an SSL connection with the server using TLSv1.2')
|
||||
|
||||
# First try with TLSv1.3 and that should fail
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_3
|
||||
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH)
|
||||
# ssl_context.load_verify_locations(cadata=server_cert_pem)
|
||||
ssl_context.load_cert_chain(certfile=CLIENT_CERT_PATH, keyfile=CLIENT_KEY_PATH)
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
try:
|
||||
conn.request('GET', '/')
|
||||
except ssl.SSLError as e:
|
||||
logging.info(f'SSL handshake failed with TLSv1.3: {e}')
|
||||
else:
|
||||
logging.info('SSL handshake succeeded with TLSv1.3')
|
||||
raise RuntimeError('This should have failed')
|
||||
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_2
|
||||
|
||||
# Also now with TLS1.2, try with a non matching ciphersuite and that should fail
|
||||
# Server only accepts: DHE-RSA-AES128-SHA256, DHE-RSA-AES256-SHA256,
|
||||
# ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES128-SHA256
|
||||
# Try AES128-GCM-SHA256 which is NOT in the list
|
||||
ssl_context.set_ciphers('AES128-GCM-SHA256')
|
||||
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
try:
|
||||
logging.info('Trying SSL handshake with non-matching ciphersuite (should fail)')
|
||||
conn.request('GET', '/')
|
||||
except ssl.SSLError as e:
|
||||
logging.info(f'SSL handshake failed with non-matching ciphersuite (expected): {e}')
|
||||
else:
|
||||
logging.info('SSL handshake succeeded with non-matching ciphersuite')
|
||||
raise RuntimeError('This should have failed - custom ciphersuites not enforced')
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
# Now try with the matching ciphersuite
|
||||
ssl_context.set_ciphers('ECDHE-RSA-AES128-SHA256')
|
||||
|
||||
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||
logging.info('Performing SSL handshake with the server')
|
||||
conn.request('GET', '/')
|
||||
resp = conn.getresponse()
|
||||
dut.expect('performing session handshake')
|
||||
got_resp = resp.read().decode('utf-8')
|
||||
if got_resp != success_response:
|
||||
logging.info('Response obtained does not match with correct response')
|
||||
raise RuntimeError('Failed to test SSL connection')
|
||||
|
||||
if dut.app.sdkconfig.get('EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||
|
||||
logging.info('Checking user callback: Obtaining client certificate...')
|
||||
|
||||
serial_number = dut.expect(r'serial number\s*:([^\n]*)', timeout=5)[0]
|
||||
issuer_name = dut.expect(r'issuer name\s*:([^\n]*)', timeout=5)[0]
|
||||
expiry = dut.expect(
|
||||
r'expires on\s*:((.*)\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])*)',
|
||||
timeout=5,
|
||||
)[1].decode()
|
||||
|
||||
logging.info(f'Serial No. : {serial_number}')
|
||||
logging.info(f'Issuer Name : {issuer_name}')
|
||||
logging.info(f'Expires on : {expiry}')
|
||||
|
||||
logging.info('Correct response obtained')
|
||||
logging.info('SSL connection test successful\nClosing the connection')
|
||||
@@ -0,0 +1,5 @@
|
||||
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
|
||||
CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK=y
|
||||
CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
|
||||
@@ -0,0 +1,7 @@
|
||||
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
|
||||
CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT=y
|
||||
CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
|
||||
@@ -0,0 +1,3 @@
|
||||
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
|
||||
CONFIG_ESP_TLS_SERVER_SESSION_TICKETS=y
|
||||
CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
|
||||
@@ -0,0 +1,6 @@
|
||||
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
|
||||
CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY=y
|
||||
CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES=y
|
||||
CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
|
||||
@@ -0,0 +1,11 @@
|
||||
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
|
||||
CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=y
|
||||
CONFIG_MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE=y
|
||||
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_PSK=y
|
||||
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_EPHEMERAL=y
|
||||
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_PSK_EPHEMERAL=y
|
||||
CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY=y
|
||||
CONFIG_EXAMPLE_ENABLE_SKIP_CLIENT_CERT=y
|
||||
CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
Reference in New Issue
Block a user