diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig index 3420ebd698..36574b2975 100644 --- a/components/esp-tls/Kconfig +++ b/components/esp-tls/Kconfig @@ -63,13 +63,14 @@ menu "ESP-TLS" config ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL bool "ESP-TLS Server: Set minimum Certificate Verification mode to Optional" depends on ESP_TLS_USING_MBEDTLS + default n help - When this option is enabled, the peer (here, the client) certificate is checked by the server, - however the handshake continues even if verification failed. By default, the - peer certificate is not checked and ignored by the server. + When this option is enabled, the ESP-TLS server can be configured to + request client certificates optionally. This is done by setting the + client_cert_authmode_optional field in the esp_https_server_config_t structure. mbedtls_ssl_get_verify_result() can be called after the handshake is complete to - retrieve status of verification. + retrieve status of verification of the client certificate, if presented. config ESP_TLS_PSK_VERIFICATION bool "Enable PSK verification" diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 03801cd8bb..1e2c57340f 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -297,6 +297,10 @@ typedef struct esp_tls_cfg_server { unsigned int cacert_pem_bytes; /*!< Size of client CA certificate legacy name */ }; +#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL + bool client_cert_authmode_optional; /*!< Set client certificate authentication mode to optional. + By default, client certificate authentication mode is set to required */ +#endif // CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL union { const unsigned char *servercert_buf; /*!< Server certificate in a buffer This buffer should be NULL terminated */ diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index ec6137bc54..73bee131a3 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -757,12 +757,11 @@ static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) if (esp_ret != ESP_OK) { return esp_ret; } - } else { #ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL - mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); -#else - mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); -#endif + if (cfg->client_cert_authmode_optional) { + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + } +#endif // CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL } if (cfg->use_secure_element) { diff --git a/components/esp_https_server/include/esp_https_server.h b/components/esp_https_server/include/esp_https_server.h index c0154d0c70..98659ffd79 100644 --- a/components/esp_https_server/include/esp_https_server.h +++ b/components/esp_https_server/include/esp_https_server.h @@ -91,6 +91,11 @@ struct httpd_ssl_config { /** CA certificate byte length */ size_t cacert_len; +#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL + /** Client certificate authentication mode */ + bool client_cert_authmode_optional; +#endif // CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL + /** Private key */ const uint8_t *prvtkey_pem; @@ -154,6 +159,16 @@ struct httpd_ssl_config { typedef struct httpd_ssl_config httpd_ssl_config_t; +/** + * Helper macro for optional client certificate authentication field + */ +#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL +#define HTTPD_SSL_CONFIG_CLIENT_AUTH_OPTIONAL_INIT \ + .client_cert_authmode_optional = false, +#else +#define HTTPD_SSL_CONFIG_CLIENT_AUTH_OPTIONAL_INIT +#endif + /** * Default config struct init * Notes: @@ -197,6 +212,7 @@ typedef struct httpd_ssl_config httpd_ssl_config_t; .servercert_len = 0, \ .cacert_pem = NULL, \ .cacert_len = 0, \ + HTTPD_SSL_CONFIG_CLIENT_AUTH_OPTIONAL_INIT \ .prvtkey_pem = NULL, \ .prvtkey_len = 0, \ .use_ecdsa_peripheral = false, \ diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c index 5940bfa595..431063d865 100644 --- a/components/esp_https_server/src/https_server.c +++ b/components/esp_https_server/src/https_server.c @@ -278,6 +278,9 @@ static esp_err_t create_secure_context(const struct httpd_ssl_config *config, ht cfg->userdata = config->ssl_userdata; cfg->alpn_protos = config->alpn_protos; cfg->tls_handshake_timeout_ms = config->tls_handshake_timeout_ms; +#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL + cfg->client_cert_authmode_optional = config->client_cert_authmode_optional; +#endif // CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL cfg->tls_version = config->tls_version; cfg->ciphersuites_list = config->ciphersuites_list; diff --git a/examples/protocols/https_server/simple/main/CMakeLists.txt b/examples/protocols/https_server/simple/main/CMakeLists.txt index 058cd558ac..5f1c94e3a6 100644 --- a/examples/protocols/https_server/simple/main/CMakeLists.txt +++ b/examples/protocols/https_server/simple/main/CMakeLists.txt @@ -2,4 +2,6 @@ idf_component_register(SRCS "main.c" INCLUDE_DIRS "." PRIV_REQUIRES esp_https_server esp_wifi nvs_flash esp_eth EMBED_TXTFILES "certs/servercert.pem" - "certs/prvtkey.pem") + "certs/prvtkey.pem" + "certs/cacert.pem" + "certs/cakey.pem") diff --git a/examples/protocols/https_server/simple/main/Kconfig.projbuild b/examples/protocols/https_server/simple/main/Kconfig.projbuild index d3df06027a..8d6e37aca9 100644 --- a/examples/protocols/https_server/simple/main/Kconfig.projbuild +++ b/examples/protocols/https_server/simple/main/Kconfig.projbuild @@ -2,7 +2,6 @@ menu "Example Configuration" config EXAMPLE_ENABLE_HTTPS_USER_CALLBACK bool "Enable user callback with HTTPS Server" - select ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL 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 @@ -33,5 +32,14 @@ menu "Example Configuration" 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 diff --git a/examples/protocols/https_server/simple/main/certs/README.md b/examples/protocols/https_server/simple/main/certs/README.md new file mode 100644 index 0000000000..7233a693cd --- /dev/null +++ b/examples/protocols/https_server/simple/main/certs/README.md @@ -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 diff --git a/examples/protocols/https_server/simple/main/certs/cacert.pem b/examples/protocols/https_server/simple/main/certs/cacert.pem new file mode 100644 index 0000000000..d3faa2929b --- /dev/null +++ b/examples/protocols/https_server/simple/main/certs/cacert.pem @@ -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----- diff --git a/examples/protocols/https_server/simple/main/certs/cakey.pem b/examples/protocols/https_server/simple/main/certs/cakey.pem new file mode 100644 index 0000000000..70d29078c4 --- /dev/null +++ b/examples/protocols/https_server/simple/main/certs/cakey.pem @@ -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----- diff --git a/examples/protocols/https_server/simple/main/certs/client_cert.conf b/examples/protocols/https_server/simple/main/certs/client_cert.conf new file mode 100644 index 0000000000..9839dbb84c --- /dev/null +++ b/examples/protocols/https_server/simple/main/certs/client_cert.conf @@ -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 diff --git a/examples/protocols/https_server/simple/main/certs/client_cert.pem b/examples/protocols/https_server/simple/main/certs/client_cert.pem new file mode 100644 index 0000000000..69dadb1283 --- /dev/null +++ b/examples/protocols/https_server/simple/main/certs/client_cert.pem @@ -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----- diff --git a/examples/protocols/https_server/simple/main/certs/client_key.pem b/examples/protocols/https_server/simple/main/certs/client_key.pem new file mode 100644 index 0000000000..da17373aa6 --- /dev/null +++ b/examples/protocols/https_server/simple/main/certs/client_key.pem @@ -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----- diff --git a/examples/protocols/https_server/simple/main/certs/prvtkey.pem b/examples/protocols/https_server/simple/main/certs/prvtkey.pem index 70d29078c4..8290e90be4 100644 --- a/examples/protocols/https_server/simple/main/certs/prvtkey.pem +++ b/examples/protocols/https_server/simple/main/certs/prvtkey.pem @@ -1,28 +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 +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----- diff --git a/examples/protocols/https_server/simple/main/certs/server_cert.conf b/examples/protocols/https_server/simple/main/certs/server_cert.conf new file mode 100644 index 0000000000..beb50e9fbe --- /dev/null +++ b/examples/protocols/https_server/simple/main/certs/server_cert.conf @@ -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 diff --git a/examples/protocols/https_server/simple/main/certs/servercert.pem b/examples/protocols/https_server/simple/main/certs/servercert.pem index d3faa2929b..4d7bef30a4 100644 --- a/examples/protocols/https_server/simple/main/certs/servercert.pem +++ b/examples/protocols/https_server/simple/main/certs/servercert.pem @@ -1,20 +1,21 @@ -----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 +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----- diff --git a/examples/protocols/https_server/simple/main/main.c b/examples/protocols/https_server/simple/main/main.c index 9dbcd9b9f0..3d1488af92 100644 --- a/examples/protocols/https_server/simple/main/main.c +++ b/examples/protocols/https_server/simple/main/main.c @@ -155,9 +155,19 @@ static httpd_handle_t start_webserver(void) 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"); conf.prvtkey_pem = prvtkey_pem_start; diff --git a/examples/protocols/https_server/simple/pytest_https_server_simple.py b/examples/protocols/https_server/simple/pytest_https_server_simple.py index d736610a05..f7dec5f275 100644 --- a/examples/protocols/https_server/simple/pytest_https_server_simple.py +++ b/examples/protocols/https_server/simple/pytest_https_server_simple.py @@ -12,87 +12,11 @@ from common_test_methods import get_env_config_variable from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize -server_cert_pem = ( - '-----BEGIN CERTIFICATE-----\n' - 'MIIDOzCCAiOgAwIBAgIUG/S51QF4EeUkdaqg54oogqIKBZkwDQYJKoZIhvcNAQEL\n' - 'BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMjUw\n' - 'NDAyMDcwMzI2WhcNMzUwMzMxMDcwMzI2WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ\n' - 'UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n' - 'ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T\n' - 'sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k\n' - 'qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd\n' - 'GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4\n' - 'sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb\n' - 'jAn4PCuR2akdF4G8WLUeDWECAwEAAaNjMGEwHQYDVR0OBBYEFMnmdJKOEepXrHI/\n' - 'ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud\n' - 'EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQBP\n' - 'AgAagM33DqsDi+UArUxEoqmov1rH0PHXnd/a6Ct/IvNzr0qUH8hW4Lv0tWHfOJY8\n' - 'pCf7bkejxXlhP/QHb6M+sobN9tN/WupEaeqNg4pCWi+6Caj2uFW9vkQQf2j50lMg\n' - 'R0oxnd6SMEQArzy3f3yYRp8rliPERY6F2Rtb9HJNh53K51FE60xONPLZ/1dtSgDB\n' - 'KcJseZfhg6oAUSLjFCYJEn5xa7CsIuQ8Jx2xMo4IkU44BJ8TJS4zw/hP1/vVjjvS\n' - 'uU2Z0ZOUCQ78/3eMnsFfLMtDUYqXPyhNogm51GeHOR6dk+ICQ+c5gCDkJUnOTqzg\n' - 'G2JUmXAXxJoUZDfalijl\n' - '-----END CERTIFICATE-----\n' -) +CURRENT_FILE_PATH = os.path.dirname(__file__) -client_cert_pem = ( - '-----BEGIN CERTIFICATE-----\n' - 'MIID7TCCAtWgAwIBAgIUBdm7RStsshnl3CCpknSJhXQK4GcwDQYJKoZIhvcNAQEL\n' - 'BQAwgYUxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdKaWFuZ3N1MQ8wDQYDVQQHDAZT\n' - 'dXpob3UxEjAQBgNVBAoMCUVzcHJlc3NpZjEMMAoGA1UECwwDY29tMRIwEAYDVQQD\n' - 'DAkxMjcuMC4wLjExHTAbBgkqhkiG9w0BCQEWDmVzcDMyeEBlc3AuY29tMB4XDTIx\n' - 'MTAwNTExMTMxMFoXDTMxMTAwMzExMTMxMFowgYUxCzAJBgNVBAYTAkNOMRAwDgYD\n' - 'VQQIDAdKaWFuZ3N1MQ8wDQYDVQQHDAZTdXpob3UxEjAQBgNVBAoMCUVzcHJlc3Np\n' - 'ZjEMMAoGA1UECwwDY29tMRIwEAYDVQQDDAkxMjcuMC4wLjExHTAbBgkqhkiG9w0B\n' - 'CQEWDmVzcDMyeEBlc3AuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n' - 'AQEAu2nP0HPtgKvRUwFuOs72caf4oyeK33OVfa6fGGttr/QYyw9PrwtdFDyEWEiI\n' - '4P4hnxNC+bvNSYtJUzF9EmkqrUtKxhBsRVTKWOqumcgtiMWOxpdVKl0936ne2Pqh\n' - 'SweddrQwvPDFuB3hRikRX11+d5vkjFBV9FoZobKHWemDkXSc2R99xRie5PJoEfoz\n' - 'rmu5zjCaPHxzkyZsmH4MILfTuhUGc/Eye9Nl+lpY5KLjM14ZMQLK1CHRuI/oqCN6\n' - '1WQrgUY5EyXGe0jXHTVhlL2RN8njxJ/4r3JnK/BQkcXTIMPOP8jIv9Sy1HhxfXKy\n' - 'HzLqOBn0Ft+mOADrpAWX8WnwUQIDAQABo1MwUTAdBgNVHQ4EFgQUpu4d8d+IywjB\n' - 'HMiKX84L+1ri8BIwHwYDVR0jBBgwFoAUpu4d8d+IywjBHMiKX84L+1ri8BIwDwYD\n' - 'VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAXm5Hn/aKKO3RnHqqfxok\n' - 'Hbw5yA2L2T6VPj2puI0Sh5GW62INjM0Kszy3L5mQqLUSsjcEcFAZmpeo14ytPRLG\n' - 'o6+WG/4er3hBA7D8oDni7hp8Qs+/EtNuEuoU+qQiKsT2DvA5rafT7laNfvjgqaoJ\n' - 'YMTCvzKLnMBaglB+qC9grgvJwMN0RTzHyY6UySdNZmcf5QXWLWjsX8E8/u4iSq8l\n' - 'eZlddTjh7HGGEOim7AkvKR9VYAvKGOV+FvUzCxPpoTr6kS2NGwnR7QnvKADECtLj\n' - 'gf+hW1FalMn0yTVspg4+BNbIThh0thbsvPDUTekMNfaRKKHZpJP2Ty3LkCbANLBR\n' - 'tQ==\n' - '-----END CERTIFICATE-----\n' -) - - -client_key_pem = ( - '-----BEGIN PRIVATE KEY-----\n' - 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7ac/Qc+2Aq9FT\n' - 'AW46zvZxp/ijJ4rfc5V9rp8Ya22v9BjLD0+vC10UPIRYSIjg/iGfE0L5u81Ji0lT\n' - 'MX0SaSqtS0rGEGxFVMpY6q6ZyC2IxY7Gl1UqXT3fqd7Y+qFLB512tDC88MW4HeFG\n' - 'KRFfXX53m+SMUFX0WhmhsodZ6YORdJzZH33FGJ7k8mgR+jOua7nOMJo8fHOTJmyY\n' - 'fgwgt9O6FQZz8TJ702X6WljkouMzXhkxAsrUIdG4j+ioI3rVZCuBRjkTJcZ7SNcd\n' - 'NWGUvZE3yePEn/ivcmcr8FCRxdMgw84/yMi/1LLUeHF9crIfMuo4GfQW36Y4AOuk\n' - 'BZfxafBRAgMBAAECggEBAJuJZ1UCwRtGfUS8LTVVSiZtVuZhDNoB3REfeR4VGkUq\n' - '+eCcZm9JqQgAaX2zRRYlEtYocC8+c1MT69jFe51p9mc302ipfJHVmtFMg3dRMKkP\n' - '/DxIn/+2voD/Q9kjt/TC7yXyyXglApKZCbrmnmpc93ZgxL7GdW+Dzz3pIne2WuC9\n' - 'T6ie71R8X60sau6ApMgkUq6On0f21v/VLkNU67tQJGBF6Q1HE8PK7Ptun3WSBVNm\n' - 'FNNJKRBwiqfWXe9hPlqqCWayYBrojSqJJXn5Xd6n5XzLDPzAXuPlkPF3VwWeXGam\n' - '3RBZA26gwv50E1PeiUQOipkR57J+O9j/oA07AnhsxPkCgYEA8RMvE3ImZTkPVqdX\n' - '72E2A5ScJswVvZelnRS/mG8U+8UlvevAu5MYr717DHKHy3yOw/u7wbkqk6KEIcyz\n' - 'ctNPBPqTweaZ28eEY/+lXSdQaWLD2UgZC8JIcMOSeFugghEHeBaxLzUYBNDToE3q\n' - '1El2HJ7W14QuTA+CEtCEb+tc7ssCgYEAxwQkBTT8A7mOEE0phfUACqaBuAXld+zu\n' - 'I3PNJDIhg1ZABEJ9vo9+3duFDoEHVsJOetijrBBxf/XAvi3bTJ+gAjcA54cGpkxz\n' - '6ssbFWZeC9exyo0ILKn33o716GrCvQn1kmuF2gasmAcrOVsMygawR7P02oasDP/X\n' - 'UckbZdqofdMCgYEAom0GfteePv0e9Idzm/mnZuot+4Xt7/vIvflIze+p96hxMXEy\n' - 'Pi9xppbH3S8dh2C44Bsv+epEYYxR8mP1VBxDVVtvSmmQqJ/Y93c7d3QRna/JvQ/y\n' - 'sBWKsU9T1HwHvRq0KZlAcEoZkMUSkSNuYPHN/qKWpkaM2vpn7T1Ivg+aYdkCgYA/\n' - 'CGO0NnzfXSTOqvHM2LVDqksJkuyD2Enwdpvxq+MLawTplHmpIl/HOuDgoCNH6lDa\n' - '/cSRGcApDBgY5ANCOIiASxWBPzXu8+X+5odUdtCwpYdNJPAC3W6BUfw2uaGmKAJc\n' - 'dqu1S0nc+OBK0Tiyv/2TKD8T+3WAxINZBv4je2bEOwKBgEavm5zTN9NILJsJCf9k\n' - 'te7+uDFuyoNWkL1vmMPuJYVC1QMVq1yr3DSaxA19BG9P4ZyOMOwVlPVWA+LofD4D\n' - 'S+w4Jjl2KDI4tSLUr6bsAJWdDfmrmGmRN3Kpds4RXaymV3rjj7qRk1J+ivtwo89s\n' - 'Vj+VslYzxw7FKKmnBgh/qGbJ\n' - '-----END PRIVATE KEY-----\n' -) +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 = '

Hello Secure World!

' @@ -128,21 +52,36 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None: 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') + # 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() - CLIENT_CERT_FILE = 'client_cert.pem' - CLIENT_KEY_FILE = 'client_key.pem' + 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(cadata=server_cert_pem) + ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH) - with open(CLIENT_CERT_FILE, 'w', encoding='utf-8') as cert, open(CLIENT_KEY_FILE, 'w', encoding='utf-8') as key: - cert.write(client_cert_pem) - key.write(client_key_pem) - - ssl_context.load_cert_chain(certfile=CLIENT_CERT_FILE, keyfile=CLIENT_KEY_FILE) + 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') @@ -154,10 +93,12 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None: logging.info('Response obtained does not match with correct response') raise RuntimeError('Failed to test SSL connection') - if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True: + 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] @@ -169,9 +110,6 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None: logging.info(f'Serial No. {serial_number}') logging.info(f'Issuer Name {issuer_name}') logging.info(f'Expires on {expiry}') - - # Close the connection - conn.close() logging.info('Correct response obtained') logging.info('SSL connection test successful\nClosing the connection') @@ -208,18 +146,12 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None logging.info('Performing GET request over an SSL connection with the server') - CLIENT_CERT_FILE = 'client_cert.pem' - CLIENT_KEY_FILE = 'client_key.pem' - 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(cadata=server_cert_pem) + ssl_context.load_verify_locations(cafile=CACERT_FILE_PATH) - ssl_context.load_cert_chain(certfile=CLIENT_CERT_FILE, keyfile=CLIENT_KEY_FILE) - - os.remove(CLIENT_CERT_FILE) - os.remove(CLIENT_KEY_FILE) + 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') @@ -231,10 +163,13 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None logging.info('Response obtained does not match with correct response') raise RuntimeError('Failed to test SSL connection') - if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True: + 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] @@ -247,8 +182,6 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None logging.info(f'Issuer Name : {issuer_name}') logging.info(f'Expires on : {expiry}') - # Close the connection - conn.close() logging.info('Correct response obtained') logging.info('SSL connection test successful\nClosing the connection') @@ -276,17 +209,38 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None: 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') - CLIENT_CERT_FILE = 'client_cert.pem' - CLIENT_KEY_FILE = 'client_key.pem' + # 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) - with open(CLIENT_CERT_FILE, 'w', encoding='utf-8') as cert, open(CLIENT_KEY_FILE, 'w', encoding='utf-8') as key: - cert.write(client_cert_pem) - key.write(client_key_pem) + 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) @@ -294,8 +248,8 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None: 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(cadata=server_cert_pem) - ssl_context.load_cert_chain(certfile=CLIENT_CERT_FILE, keyfile=CLIENT_KEY_FILE) + 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', '/') @@ -308,9 +262,6 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None: ssl_context.minimum_version = ssl.TLSVersion.TLSv1_3 ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3 - os.remove(CLIENT_CERT_FILE) - os.remove(CLIENT_KEY_FILE) - conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context) logging.info('Performing SSL handshake with the server') conn.request('GET', '/') @@ -321,10 +272,12 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None: logging.info('Response obtained does not match with correct response') raise RuntimeError('Failed to test SSL connection') - if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True: + 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] @@ -338,8 +291,6 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None: logging.info(f'Issuer Name : {issuer_name}') logging.info(f'Expires on : {expiry}') - # Close the connection - conn.close() logging.info('Correct response obtained') logging.info('SSL connection test successful\nClosing the connection') @@ -371,21 +322,15 @@ def test_examples_protocol_https_server_tls1_2_only(dut: Dut) -> None: logging.info(f'Got Port : {got_port}') logging.info('Performing GET request over an SSL connection with the server using TLSv1.2') - CLIENT_CERT_FILE = 'client_cert.pem' - CLIENT_KEY_FILE = 'client_key.pem' - - with open(CLIENT_CERT_FILE, 'w', encoding='utf-8') as cert, open(CLIENT_KEY_FILE, 'w', encoding='utf-8') as key: - cert.write(client_cert_pem) - key.write(client_key_pem) - # 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(cadata=server_cert_pem) - ssl_context.load_cert_chain(certfile=CLIENT_CERT_FILE, keyfile=CLIENT_KEY_FILE) + 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', '/') @@ -419,9 +364,6 @@ def test_examples_protocol_https_server_tls1_2_only(dut: Dut) -> None: # Now try with the matching ciphersuite ssl_context.set_ciphers('DHE-RSA-AES128-SHA256') - os.remove(CLIENT_CERT_FILE) - os.remove(CLIENT_KEY_FILE) - conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context) logging.info('Performing SSL handshake with the server') conn.request('GET', '/') @@ -432,7 +374,7 @@ def test_examples_protocol_https_server_tls1_2_only(dut: Dut) -> None: logging.info('Response obtained does not match with correct response') raise RuntimeError('Failed to test SSL connection') - if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True: + 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}') @@ -449,7 +391,5 @@ def test_examples_protocol_https_server_tls1_2_only(dut: Dut) -> None: logging.info(f'Issuer Name : {issuer_name}') logging.info(f'Expires on : {expiry}') - # Close the connection - conn.close() logging.info('Correct response obtained') logging.info('SSL connection test successful\nClosing the connection') diff --git a/examples/protocols/https_server/simple/sdkconfig.ci b/examples/protocols/https_server/simple/sdkconfig.ci index d12b3d37a6..5fd8cee2a2 100644 --- a/examples/protocols/https_server/simple/sdkconfig.ci +++ b/examples/protocols/https_server/simple/sdkconfig.ci @@ -2,3 +2,4 @@ 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 diff --git a/examples/protocols/https_server/simple/sdkconfig.ci.dynamic_buffer b/examples/protocols/https_server/simple/sdkconfig.ci.dynamic_buffer index 3abca03116..a5e63901b0 100644 --- a/examples/protocols/https_server/simple/sdkconfig.ci.dynamic_buffer +++ b/examples/protocols/https_server/simple/sdkconfig.ci.dynamic_buffer @@ -4,3 +4,4 @@ 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 diff --git a/examples/protocols/https_server/simple/sdkconfig.ci.srv_ses_tkt b/examples/protocols/https_server/simple/sdkconfig.ci.srv_ses_tkt index a0ff28b5cd..b51b00b673 100644 --- a/examples/protocols/https_server/simple/sdkconfig.ci.srv_ses_tkt +++ b/examples/protocols/https_server/simple/sdkconfig.ci.srv_ses_tkt @@ -1,2 +1,3 @@ CONFIG_ESP_HTTPS_SERVER_ENABLE=y CONFIG_ESP_TLS_SERVER_SESSION_TICKETS=y +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y diff --git a/examples/protocols/https_server/simple/sdkconfig.ci.tls1_2_only b/examples/protocols/https_server/simple/sdkconfig.ci.tls1_2_only index 2dc708b7f4..89843bfb8d 100644 --- a/examples/protocols/https_server/simple/sdkconfig.ci.tls1_2_only +++ b/examples/protocols/https_server/simple/sdkconfig.ci.tls1_2_only @@ -3,3 +3,4 @@ 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 diff --git a/examples/protocols/https_server/simple/sdkconfig.ci.tls1_3 b/examples/protocols/https_server/simple/sdkconfig.ci.tls1_3 index 2f9b090741..4de1e68d8d 100644 --- a/examples/protocols/https_server/simple/sdkconfig.ci.tls1_3 +++ b/examples/protocols/https_server/simple/sdkconfig.ci.tls1_3 @@ -7,3 +7,5 @@ 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