diff --git a/components/esp_websocket_client/examples/target/README.md b/components/esp_websocket_client/examples/target/README.md index 56870ea1292..15b1755cde1 100644 --- a/components/esp_websocket_client/examples/target/README.md +++ b/components/esp_websocket_client/examples/target/README.md @@ -13,6 +13,53 @@ This example can be executed on any ESP32 board, the only required interface is * Open the project configuration menu (`idf.py menuconfig`) * Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. * Configure the websocket endpoint URI under "Example Configuration", if "WEBSOCKET_URI_FROM_STDIN" is selected then the example application will connect to the URI it reads from stdin (used for testing) +* In order to test websocket client example over the TLS please enable configurations `CONFIG_WS_OVER_TLS_MUTUAL_AUTH` or `CONFIG_WS_OVER_TLS_SERVER_AUTH` (Needs only for python script executation over the TLS) + +### Server Certificate Verification + +* Mutual Authentication: When `CONFIG_WS_OVER_TLS_MUTUAL_AUTH=y` is enabled, it's essential to provide valid certificates for both the server and client. + This ensures a secure two-way verification process. +* Server-Only Authentication: To perform verification of the server's certificate only (without requiring a client certificate), set `CONFIG_WS_OVER_TLS_SERVER_AUTH=y`. + This method skips client certificate verification. +* Example below demonstrates how to generate a new self signed certificates for the server and client using the OpenSSL command line tool + +### Generating a self signed Certificates with OpenSSL +* The example below outlines the process for creating new certificates for both the server and client using OpenSSL, a widely-used command line tool for implementing TLS protocol: + +``` +Generate the CA's Private Key; +openssl genrsa -out ca_key.pem 2048 + +Create the CA's Certificate +openssl req -new -x509 -days 3650 -key ca_key.pem -out ca_cert.pem + +Generate the Server's Private Key +openssl genrsa -out server_key.pem 2048 + +Generate a Certificate Signing Request (CSR) for the Server +openssl req -new -key server_key.pem -out server_csr.pem + +Sign the Server's CSR with the CA's Certificate +openssl x509 -req -days 365 -in server_csr.pem -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out server_cert.pem + +Generate the Client's Private Key +openssl genrsa -out client_key.pem 2048 + +Generate a Certificate Signing Request (CSR) for the Client +openssl req -new -key client_key.pem -out client_csr.pem + +Sign the Client's CSR with the CA's Certificate +openssl x509 -req -days 365 -in client_csr.pem -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out client_cert.pem + +Please note: In the outlined steps, we are omitting the configuration of the CN (Common Name) field due to the context of a testing environment. However, it's important to recognize that the CN field is a critical element of SSL/TLS certificates, significantly influencing the security and efficacy of HTTPS communications. This field facilitates the verification of a website's identity, enhancing trust and security in web interactions. In practical deployments beyond testing scenarios, ensuring the CN field is accurately set is paramount for maintaining the integrity and reliability of secure communications +``` + +Expiry time and metadata fields can be adjusted in the invocation. + +Please see the openssl man pages (man openssl) for more details. + +It is **strongly recommended** to not reuse the example certificate in your application; +it is included only for demonstration. ### Build and Flash diff --git a/components/esp_websocket_client/examples/target/main/CMakeLists.txt b/components/esp_websocket_client/examples/target/main/CMakeLists.txt index bff26f10886..4b06b73f39e 100644 --- a/components/esp_websocket_client/examples/target/main/CMakeLists.txt +++ b/components/esp_websocket_client/examples/target/main/CMakeLists.txt @@ -1,2 +1,21 @@ -idf_component_register(SRCS "websocket_example.c" - INCLUDE_DIRS ".") +set(SRC_FILES "websocket_example.c") # Define source files +set(INCLUDE_DIRS ".") # Define include directories +set(EMBED_FILES "") # Initialize an empty list for files to embed + +# Conditionally append files to the list based on configuration +#if(CONFIG_WS_OVER_TLS_MUTAL_AUTH) + list(APPEND EMBED_FILES + "certs/client_cert.pem" + "certs/ca_cert.pem" + "certs/client_key.pem") +#endif() + +#if(CONFIG_PUBLIC_DOMAIN_AUTHENTIFICATION) + list(APPEND EMBED_FILES + "certs/ca_certificate_public_domain.pem") +#endif() + +# Register the component with source files, include dirs, and any conditionally added embedded files +idf_component_register(SRCS "${SRC_FILES}" + INCLUDE_DIRS "${INCLUDE_DIRS}" + EMBED_TXTFILES "${EMBED_FILES}") diff --git a/components/esp_websocket_client/examples/target/main/Kconfig.projbuild b/components/esp_websocket_client/examples/target/main/Kconfig.projbuild index 49ad49effdd..09b139eafbc 100644 --- a/components/esp_websocket_client/examples/target/main/Kconfig.projbuild +++ b/components/esp_websocket_client/examples/target/main/Kconfig.projbuild @@ -20,6 +20,20 @@ menu "Example Configuration" help URL of websocket endpoint this example connects to and sends echo + config PUBLIC_DOMAIN_AUTHENTIFICATION + bool "Enable WebSocket over TLS with Server Certificate Verification Only" + default n + help + Enables WebSocket connections over TLS (WSS) with server certificate verification. + This setting mandates the client to verify the servers certificate, while the server + does not require client certificate verification. + + config WS_OVER_TLS_MUTUAL_AUTH + bool "Enable WebSocket over TLS with Server Client Mutual Authentification" + default n + help + Enables WebSocket connections over TLS (WSS) with server and client mutual certificate verification. + if CONFIG_IDF_TARGET = "linux" config GCOV_ENABLED bool "Coverage analyzer" diff --git a/components/esp_websocket_client/examples/target/main/certs/ca_cert.pem b/components/esp_websocket_client/examples/target/main/certs/ca_cert.pem new file mode 100644 index 00000000000..4e461dd70ab --- /dev/null +++ b/components/esp_websocket_client/examples/target/main/certs/ca_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDazCCAlOgAwIBAgIUe0LEmAMsFmKAg2DuDwXmcWXS5p8wDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMTExNjI3MTlaFw0zNDAy +MDgxNjI3MTlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCvyjh5fJb8j50UzDCka7UqFLn5rdaixkyr++Pnkcqd +JL0URs5aG7m+PQHz8iFEQhcU4O8vkaeXK2V/vbFOBU0kNios0SUmzjcDTdmiJpVD ++yOM0Zvk9j5t9Y4WxL03FEqN9/kqw1XBJdJbVTLZgQ2eLWo0wMJwbL+M+EQJmk8A +6kDkEOZi0R1j8mAkjvqzWJcQMuVvQHTn/yOPYAeE8kC7lfUjNPR+QBu7e2j9q+zU +pomD7MiRnqtODRbikAyPnp+fjcrYQLxI2bNjJTIAErRSrECtEoqRAzJWZqTPpMEl +ArnuTADuSElqYsr6l+6ZJgodp6uUiwYQBHpizV2WCZD3AgMBAAGjUzBRMB0GA1Ud +DgQWBBSgvrq2q7WW4zdQMamqMmaSo/3YmTAfBgNVHSMEGDAWgBSgvrq2q7WW4zdQ +MamqMmaSo/3YmTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBO +wk8vaGfuuJ2jTUZ83t6io691KH2Wg3i/sQBAmFGI4cEccdIiiDeL5T2OW73uo9eY +HnFAcaoefDLGvgg/ABYLk+oZiKDw5Vxiu2hJehd1buVQ8PjMf13ZqtwVjwXaJuT8 +NU7pKo1LUyPDel6BbeOlCYa2LZPg2ZQhydkAz7jcfrh7h1QvMZmqPKlOIegZTtqx +vBnZKDyQtpkgWo+2NlBfPtDTNA2nKzicPL/YaMePYaUvcXrQQN0BURlbQyWlpW8m +Xoj/D8TMUSQiRtHDxSJhLbZDixx5lDwEeXcvB+pYBCUED7HFHKgo8KulIyiJgK1V +YZC2ha3nNU8uh90QPDnR +-----END CERTIFICATE----- diff --git a/components/esp_websocket_client/examples/target/main/certs/ca_certificate_public_domain.pem b/components/esp_websocket_client/examples/target/main/certs/ca_certificate_public_domain.pem new file mode 100644 index 00000000000..43b222a60a5 --- /dev/null +++ b/components/esp_websocket_client/examples/target/main/certs/ca_certificate_public_domain.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- diff --git a/components/esp_websocket_client/examples/target/main/certs/ca_key.pem b/components/esp_websocket_client/examples/target/main/certs/ca_key.pem new file mode 100644 index 00000000000..d09407b8d16 --- /dev/null +++ b/components/esp_websocket_client/examples/target/main/certs/ca_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCvyjh5fJb8j50U +zDCka7UqFLn5rdaixkyr++PnkcqdJL0URs5aG7m+PQHz8iFEQhcU4O8vkaeXK2V/ +vbFOBU0kNios0SUmzjcDTdmiJpVD+yOM0Zvk9j5t9Y4WxL03FEqN9/kqw1XBJdJb +VTLZgQ2eLWo0wMJwbL+M+EQJmk8A6kDkEOZi0R1j8mAkjvqzWJcQMuVvQHTn/yOP +YAeE8kC7lfUjNPR+QBu7e2j9q+zUpomD7MiRnqtODRbikAyPnp+fjcrYQLxI2bNj +JTIAErRSrECtEoqRAzJWZqTPpMElArnuTADuSElqYsr6l+6ZJgodp6uUiwYQBHpi +zV2WCZD3AgMBAAECggEAIA0BwPy7Vq8kl78m+0N8E4EV63ULlkALiKvzgKwvQfmJ +0+GZDArUEeBzs7Oo5xYZuT/NvGGVKdXKusCuTChhSUHq7KLxYCLnGt4d2RepzWxD +rhAlmVhgR5Im5vXV/e3gLgRRVL+qqf2oXeipzche4EEthRLEINVjE2PMm+ebkfHW +QDts8CqZQgnvi24PKjVxgjaBMr4jK7myjCkrFZSWC4Hj5ezumsSXiGVDRgeRpaqu +crP+mB2q2skNeqrwe+7iFVORY254skD/FCp+VjCbO1BCUVcS/VVnzWunoAQmWWKM +buHUk9R/SMwhFdoNs6MDWAu4iknUf9ipSr8EirM54QKBgQDrLzIgkGaazqYogmjT +pX6GZwuHmPPJ8TLeD/Fq96//n4XUQAX1eI/+HAL5eiTSMt6QK4PNz4DXfkcJ4/IY +18MhMnqug0h9u3EJaosM6ecUBMQCzbfi9U9Vr7Fx/8V7loyTLqVpxp9Tr89zjSA8 +PdUuc2swvkhbmLclPReqS8G/kQKBgQC/WUQ2rETmtQXpUcXxvpcIwzSek4it7G5t +Q7T8QomggqpwjBjaeohIBaXRzXd4nZ4msUpWFote9AwPW3YZcwNSSY98P7g/OPBm +2FMiOPb/tXZQkClDspNLP2O98vLeAD+m0HwTGi61ulS98Za6kaH+HTg0LdtXMkTu +aJyKvWYUBwKBgQDc3MOshS92bl7oaB/dsutxeNABFYjMuvDUThCgLd9gpgTeYQm3 +jvNa5h98/lIZ/J+6sMLkwtvyg6pfBWxUHDwprug7fxrSyPbMqvvOstLJn/gb0enB +ADLy+z4fGt3wxF9b0VCSV29E/jRKBdyh9kd/ifC+I9R8AJzuIcNZsC9RoQKBgQCN +KLJMzvspYyPQQtYPB7Xt7eu0jEwJWmEAVDGA4ykacyp/SqrPChPdZeU1CCl5nnVc +P/AB4DHCw7Dd53ARSCqMGt4yH+OxKDUY+b8igPmeHGUC+8alPWix2zqel0qZgX9z +dVwCz47j22jGkyHJ0sO5bh7XR3kHM3tskVnic+SJIwKBgAjMSXyL1wuticxy7SqB +1JODo2hIj6mvfZqq/mXY8M3lm4jiKNcJSccd6x8ViYCBYPmMTIafvQI/QWK+8Sok +ERCbhO0dpKeKLpj1a5POQK7CL1uQEfFNhK8ttEoYgx+kVWOVYNY2INv7TBC5hiSM +yTSwhRBb2qDUihf1ulFHxk3X +-----END PRIVATE KEY----- diff --git a/components/esp_websocket_client/examples/target/main/certs/client_cert.pem b/components/esp_websocket_client/examples/target/main/certs/client_cert.pem new file mode 100644 index 00000000000..5de3d00485d --- /dev/null +++ b/components/esp_websocket_client/examples/target/main/certs/client_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIUIF2nSdS4dXQzd77Uzk8h7ApClKEwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMTExNjI4MzBaFw0yNTAy +MTAxNjI4MzBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQD4xRrf6yyNcwHKKZ03zReTcSaUieQyWL06uFLNhrBh +H7SZ/pmB3Y0ZNCVSIk0+Aw8XmJVYYOdaINXQS9LCS42csffQZCT7iJVdIPVQxiv8 +uvOJsdB/DM+Ui318vl0pv99snC9bsemCAa6IheWwvmCX/OgCfOiYBvNFOBDrIxpT +sJ0epd+vNSrKOzWFVMzArn3R/Kd8Qu8n5oAAZLzxnLN8MViKwr7/qATjlZioXrrL +mzmjq7NpPVXU+29XuenGazFq/87R3ukwGUOznBySNPbdz+eVyYDgVEkKtBvSRkGL +7TJ980l1tt5pxcrLT7/ildOsnqB4SGiLSvotWTJDRZQVAgMBAAGjQjBAMB0GA1Ud +DgQWBBSqPcUCOLmV1vU5kjFidC2TqPUsdjAfBgNVHSMEGDAWgBSgvrq2q7WW4zdQ +MamqMmaSo/3YmTANBgkqhkiG9w0BAQsFAAOCAQEAj75PgAxXvNz07q+cl3Y3XuN3 +/K6ix5B8iQDUg/sG22ZaKK0XmRWJSnfJay6emHJdHKuqHR3omjM5A7i7kiIatmbH +mN7dA17Y0yT+Sv6qR0dl+0iucF4tsDQmPZQCGKMpnNQoirTMAk4lcCcY69I6xHa6 +q9QhW/R5ueJkiHx+eg7ShH1KIqLsmvN9OM9+RTceC2qCKStPt9kldfnjmwvRzP6S +VgU5tUZJp10+bwV4yjoSsvO1xAXO4A4y6yU1RBSFyFZOaeKI24nIE9hT4uvc3wgb +mUuQfGAixj9a809YvgMquQAuVPi+iQe9b68qMgW5sil13xUeIzh7i/LkW2BN5Q== +-----END CERTIFICATE----- diff --git a/components/esp_websocket_client/examples/target/main/certs/client_key.pem b/components/esp_websocket_client/examples/target/main/certs/client_key.pem new file mode 100644 index 00000000000..7de83815929 --- /dev/null +++ b/components/esp_websocket_client/examples/target/main/certs/client_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD4xRrf6yyNcwHK +KZ03zReTcSaUieQyWL06uFLNhrBhH7SZ/pmB3Y0ZNCVSIk0+Aw8XmJVYYOdaINXQ +S9LCS42csffQZCT7iJVdIPVQxiv8uvOJsdB/DM+Ui318vl0pv99snC9bsemCAa6I +heWwvmCX/OgCfOiYBvNFOBDrIxpTsJ0epd+vNSrKOzWFVMzArn3R/Kd8Qu8n5oAA +ZLzxnLN8MViKwr7/qATjlZioXrrLmzmjq7NpPVXU+29XuenGazFq/87R3ukwGUOz +nBySNPbdz+eVyYDgVEkKtBvSRkGL7TJ980l1tt5pxcrLT7/ildOsnqB4SGiLSvot +WTJDRZQVAgMBAAECggEABwbNxqKw/wTrsj4fHAopLvstbDylSWwZIYjNEX5nik+k +SAxZYaWps37EO4qPKGqT7MZAUaZLDUH9gPbjTmxKHep8glJY7KAcxiUTSMcB9iu6 +i34AC2TdPXY09Lwp/X060BtszpKsyAUPsk4nq5pYjXJ1EkskBPHw3gM0SOjblRCg +bCS67jo+jj4lKKH2DzEYi6VFlVHhStuY0X94986nezsGfpAoDUvTPTQTfRHyO9bG +JCf9cFcpjl2vxGeDgoR177oITvQTztTR5L+zTk5plk/ILIHP9EjSmf8nCvt5+WHt +AplMox/piOn8eUK8rphDArD5iEHpfRPZQHmONXFy8QKBgQD8l9CunnOFWgdJS4jy ++EQDr3+6IXPJYwCcCF60rA2WgRbgt2ViPN+kEHaNI1MDEJdPsJTNBC7y0vKF09ga +zGgpKtPSD5boOCUnxpy8Cfobg01hZe9iYvl4HUIZSqAB7ZTtn2acXxeAw+f+dSEx +Fc5IKGvOIU2EKgw1Yu2AEPCq7wKBgQD8IBbHjU46+cldTiPNk4zfQ6xkbAgxttKS +7hZo3udpy/tvjdm2XBenrI4EDAIKhbWEvg7floN12cHfFZdTRlrdI1lnoeXFMQde +xEWfn+bpNLRGKY3HGrg2QvIkiClX1vevQOF63+eOlRdiC6xKosqkXrUIv/oY8ups +qs71hBDBOwKBgEXrTDOZ3sZR9mReiUkgWctfYA7IxcFAK2IFmxmN6rD3iLqpaWH5 +EbrbZ8WHuqnFhOzlJztc5hYHOGS9EDvSyx5iIYIrGI2tRPOusaIHbPkCrn/AdLQa +S43pI2vW0VXXSvs/vWqZk+rrz6MLDyYEMDafIcBMTaXA8eIxQSbLCaN3AoGBALq7 +nYOAoc9GT6B+jj/lJ3H4skbSSKNhb8aI9ioH5cdS38+4dOX+gTqbr7dJmX1nmJBP +H77zwDvZ4yAx4pk3w3aDhuUdYItTC81hetuF18UjVt2cSziLDqKJpMPv4QcA3QN8 +/0M9cEgHHoFsedfxiDqDNnvbjAVMbNm9DHmErdAfAoGAM2DlwjUnY4s6ebI52BRa +67FJshdOovr+5XpK3LuIOP/9d25lHElSW5KlRAP/PYd1gU0Aq21blJ8KrSg3Y83m +aEZQp7ga76uOEjDP2vY3jsMjyTP45ZvuKuf8t76FPKq1t0v2zNo4zfSScsnTKljh +u8E01zO1UDIhlc7tqf3r5NQ= +-----END PRIVATE KEY----- diff --git a/components/esp_websocket_client/examples/target/main/certs/server_cert.pem b/components/esp_websocket_client/examples/target/main/certs/server_cert.pem new file mode 100644 index 00000000000..af730d98f96 --- /dev/null +++ b/components/esp_websocket_client/examples/target/main/certs/server_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIUIF2nSdS4dXQzd77Uzk8h7ApClKAwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMTExNjI3NTFaFw0yNTAy +MTAxNjI3NTFaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC1BwoL3EQ0VCoN2T6dlOLbyzlLg42suEOWPk+Jx/yP +fMzp/Q1W0NWkNfqiHWi+8RAXiPeIzh1ex04rUKNY/+fZ7WJWiOiChm/HUWAYte14 +tic3/mkbw8+C1kkdQPGKsVUTMY5QhpBkRyKl6jaqzAEJI/QfqfMnLBxqnPpAYqmr +LCwjGPDmSjy0X3FeyZS6MNRkbgwd4zSz/rBVGAWTqrs8ipK2sMZlahhagmuqpVCd +EtPRf1WZDqVAXzI4LDbbX0FECfN8rHak7r1Oc/dT/AVAT0dq+F0vichLRsRRljkt +Sa7gmQNKfpZFd7vvqw6bxv3f/xP+rZb290kH1AvOgXFFAgMBAAGjQjBAMB0GA1Ud +DgQWBBSTcEPA+NXnhhSWQO02g2RWgeTJpTAfBgNVHSMEGDAWgBSgvrq2q7WW4zdQ +MamqMmaSo/3YmTANBgkqhkiG9w0BAQsFAAOCAQEAplo6DrvER6y+fMDCqVD1lnBz +tlwmjCr8sHQTYUi6prIvUQ3r5al+bCUxBD2K80sPjd7LDN4SVIma12qaLGbVUqDd +k4FGA6Man7dHdwVgcW6XFHcKGhdH+vMEHitccm7RsvDLxS33/kXo4hSgtQfbXHwD +7cgYF+6oN1JISOvMe0TuxFm8+48/++5KtaqYwPgRHgRbCq1ePowLEJN94qPv0EDb +ZTiVcK3cy+lZPpXOlhPtu+9GCcAnmC2Ho2QazPTgcdFO1aNqLp1CCRcg2l/QNLjr +QKw7rXoMSnnoIfAUdgkrzXVmo7qQ33GR8OW5Y+JfCBYx6L/jbvAkbWuxmgyX3Q== +-----END CERTIFICATE----- diff --git a/components/esp_websocket_client/examples/target/main/certs/server_key.pem b/components/esp_websocket_client/examples/target/main/certs/server_key.pem new file mode 100644 index 00000000000..3776b71a822 --- /dev/null +++ b/components/esp_websocket_client/examples/target/main/certs/server_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1BwoL3EQ0VCoN +2T6dlOLbyzlLg42suEOWPk+Jx/yPfMzp/Q1W0NWkNfqiHWi+8RAXiPeIzh1ex04r +UKNY/+fZ7WJWiOiChm/HUWAYte14tic3/mkbw8+C1kkdQPGKsVUTMY5QhpBkRyKl +6jaqzAEJI/QfqfMnLBxqnPpAYqmrLCwjGPDmSjy0X3FeyZS6MNRkbgwd4zSz/rBV +GAWTqrs8ipK2sMZlahhagmuqpVCdEtPRf1WZDqVAXzI4LDbbX0FECfN8rHak7r1O +c/dT/AVAT0dq+F0vichLRsRRljktSa7gmQNKfpZFd7vvqw6bxv3f/xP+rZb290kH +1AvOgXFFAgMBAAECggEALPvuUasvIafGeYGCD0uHoiGaf7rVklWJqgSa5DyXdJqJ +Gx4gWfH0HOWy/eT7+fLSUl7dUBgT8VDqilXz+XJCDYPxO1qzGHhKv4dnr0xKEgSF +s2LbgKREZRlVutjADPxrDSVz3WvK5rhMklkks4WVPk26ZMHpI9NQzmdqwmQiEGAz +Jjs+LuysRaeJAma9MH/5JW4k6xN0V507pK5jJgyC2s+/1HMItSfY0EISc9nXKwKu +bypGGc0grgWkWkDh5CKhvaI7PctiUpF7A+qz5Pxp/igEw47BIxTi53z/UXwlShSy +gtjICiXwbcFssRvyvrefw8oSTYoODMnrlDDcYONY8wKBgQDbyqfSjJNbQBrBSaU1 +A1mWIGPxEM6f9FHY7dx8YVw27AdVMr4KyJWaPN0C7NStgD4ipVBkQjSmCXulmUWb +B9MXadUef9/a2GszMeO7wOXKhMVdKWP6DGFHFJ/W0YR977yGVd863S626BD/qyq2 +MuPHLzS5bcr5EVsB486hGMUBZwKBgQDS2ZJJvdOIxHbir0aaB6LxL8vJvxEFmRUk +5tnTfunHqN7P4myurCfcjJCT1nNhgnW1NQGwoPUjD3WT3nmDV8ub/tFKSTm7RycT +eGCrIAPkmLA7jGNzCkojCDPVIqQVY2Nx+ZE0bdC7YT06mMuEsF/Ccjq5I/+aJng4 +LIrFrL2wcwKBgQCEDi7nAi9HFCz/FRB92ZVp7eweWsrKsDC89a0TzitplEaTmfk0 +4W+BTDA+Ia1m0TaD+m9izaR0Xh48UOrRStI5rwytVodZJc7C46bAmBV4qG0snEHF +asrHukyO9TN1tyS+Ubnd1CbNHoGYG29+KPVSJ7q17pGVNChJ6mWrxQYY4QKBgQDF +uga3ZG5EqYibV6crttGUwC+pR6Ycy8vKSTooXbG57KDV7g3hV8whxSenm8mjvYXI +oqatDqQTduHaAx2Mj/5+kV2O/lBHUZhRZ+evUlyUOKO7lBGGxjVz2LNSwiOBcyzE +qzcCJaFCtxOGKddg3U1PuXNcP2fpFP5UH2EbsrxIBQKBgDaa8d1P4xA+n+eC8K9V +A3ovi1558isAyKbqGf8PW9rARAjFjmefPPlhBVYD4zvRQOPcaGYfupCjXoT+Vd29 +LrpCMXa4HajSzXqtuXoab4bGouKpXUKCyL5dynHnbuXCTETiopy6urvTpiem3199 +OE6HvS5pTjx2qxVjxRzkSapF +-----END PRIVATE KEY----- diff --git a/components/esp_websocket_client/examples/target/main/websocket_example.c b/components/esp_websocket_client/examples/target/main/websocket_example.c index 5984bb021e8..60fefe28bb7 100644 --- a/components/esp_websocket_client/examples/target/main/websocket_example.c +++ b/components/esp_websocket_client/examples/target/main/websocket_example.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -91,7 +91,7 @@ static void websocket_event_handler(void *handler_args, esp_event_base_t base, i if (data->op_code == 0x08 && data->data_len == 2) { ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]); } else { - ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr); + ESP_LOGW(TAG, "Received=%.*s\n\n", data->data_len, (char *)data->data_ptr); } // If received data contains json structure it succeed to parse @@ -139,8 +139,27 @@ static void websocket_app_start(void) websocket_cfg.uri = line; ESP_LOGI(TAG, "Endpoint uri: %s\n", line); +#if CONFIG_WS_OVER_TLS_MUTUAL_AUTH + extern const char cacert_start[] asm("_binary_ca_cert_pem_start"); // CA certificate + extern const char cert_start[] asm("_binary_client_cert_pem_start"); // Client certificate + extern const char cert_end[] asm("_binary_client_cert_pem_end"); + extern const char key_start[] asm("_binary_client_key_pem_start"); // Client private key + extern const char key_end[] asm("_binary_client_key_pem_end"); + + // Please note if you don't use server over TLS scheme (wss), the certificates are not required + websocket_cfg.cert_pem = cacert_start; + websocket_cfg.client_cert = cert_start; + websocket_cfg.client_cert_len = cert_end - cert_start; + websocket_cfg.client_key = key_start; + websocket_cfg.client_key_len = key_end - key_start; + websocket_cfg.skip_cert_common_name_check = true; +#endif /* CONFIG_WS_OVER_TLS_MUTUAL_AUTH */ #else websocket_cfg.uri = CONFIG_WEBSOCKET_URI; +#if CONFIG_PUBLIC_DOMAIN_AUTHENTIFICATION + extern const char cacert_start[] asm("_binary_ca_certificate_public_domain_pem_start"); // CA cert of wss://echo.websocket.event, modify it if using another public domain + websocket_cfg.cert_pem = cacert_start; +#endif #endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */ ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri); diff --git a/components/esp_websocket_client/examples/target/pytest_websocket.py b/components/esp_websocket_client/examples/target/pytest_websocket.py index 9d6f3159926..167fbb578af 100644 --- a/components/esp_websocket_client/examples/target/pytest_websocket.py +++ b/components/esp_websocket_client/examples/target/pytest_websocket.py @@ -1,13 +1,16 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import json import random import re import socket +import ssl import string +import sys from threading import Event, Thread -from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket +from SimpleWebSocketServer import (SimpleSSLWebSocketServer, + SimpleWebSocketServer, WebSocket) def get_my_ip(): @@ -27,7 +30,7 @@ class WebsocketTestEcho(WebSocket): def handleMessage(self): self.sendMessage(self.data) - print('Server sent: {}'.format(self.data)) + print('\n Server sent: {}\n'.format(self.data)) def handleConnected(self): print('Connection from: {}'.format(self.address)) @@ -44,12 +47,23 @@ def send_data(self, data): conn.sendMessage(data) def run(self): - self.server = SimpleWebSocketServer('', self.port, WebsocketTestEcho) + if self.use_tls is True: + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile='main/certs/server_cert.pem', keyfile='main/certs/server_key.pem') + if self.serv_client_verify is True: + ssl_context.load_verify_locations(cafile='main/certs/ca_cert.pem') + ssl_context.verify_mode = ssl.CERT_REQUIRED + ssl_context.check_hostname = False + self.server = SimpleSSLWebSocketServer('', self.port, WebsocketTestEcho, ssl_context=ssl_context) + else: + self.server = SimpleWebSocketServer('', self.port, WebsocketTestEcho) while not self.exit_event.is_set(): self.server.serveonce() - def __init__(self, port): + def __init__(self, port, use_tls, serv_client_verify): self.port = port + self.use_tls = use_tls + self.serv_client_verify = serv_client_verify self.exit_event = Event() self.thread = Thread(target=self.run) self.thread.start() @@ -77,6 +91,7 @@ def test_echo(dut): for i in range(0, 5): dut.expect(re.compile(b'Received=hello (\\d)')) print('All echos received') + sys.stdout.flush() def test_close(dut): code = dut.expect( @@ -103,7 +118,8 @@ def test_json(dut, websocket): match = dut.expect( re.compile(b'Json=({[a-zA-Z0-9]*).*}')).group(0).decode()[5:] if match == str(data[0]): - print('Sent message and received message are equal') + print('Sent message and received message are equal \n') + sys.stdout.flush() else: raise ValueError( 'DUT received string do not match sent string, \nexpected: {}\nwith length {}\ @@ -126,7 +142,8 @@ def test_recv_long_msg(dut, websocket, msg_len, repeats): recv_msg += match if recv_msg == send_msg: - print('Sent message and received message are equal') + print('Sent message and received message are equal \n') + sys.stdout.flush() else: raise ValueError( 'DUT received string do not match sent string, \nexpected: {}\nwith length {}\ @@ -145,14 +162,23 @@ def test_fragmented_msg(dut): uri = dut.app.sdkconfig['WEBSOCKET_URI'] uri_from_stdin = False + if dut.app.sdkconfig.get('WS_OVER_TLS_MUTUAL_AUTH') is True: + use_tls = True + serv_client_verify = True + else: + use_tls = False + except Exception: print('ENV_TEST_FAILURE: Cannot find uri settings in sdkconfig') raise if uri_from_stdin: server_port = 8080 - with Websocket(server_port) as ws: - uri = 'ws://{}:{}'.format(get_my_ip(), server_port) + with Websocket(server_port, use_tls, serv_client_verify) as ws: + if use_tls is True: + uri = 'wss://{}:{}'.format(get_my_ip(), server_port) + else: + uri = 'ws://{}:{}'.format(get_my_ip(), server_port) print('DUT connecting to {}'.format(uri)) dut.expect('Please enter uri of websocket endpoint', timeout=30) dut.write(uri) diff --git a/components/esp_websocket_client/examples/target/sdkconfig.ci.tls_mutual_auth b/components/esp_websocket_client/examples/target/sdkconfig.ci.tls_mutual_auth new file mode 100644 index 00000000000..69bf6f8ee82 --- /dev/null +++ b/components/esp_websocket_client/examples/target/sdkconfig.ci.tls_mutual_auth @@ -0,0 +1,14 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_LINUX=n +CONFIG_WEBSOCKET_URI_FROM_STDIN=y +CONFIG_WEBSOCKET_URI_FROM_STRING=n +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_WS_OVER_TLS_MUTUAL_AUTH=y diff --git a/components/esp_websocket_client/examples/target/sdkconfig.ci.tls_servert_auth b/components/esp_websocket_client/examples/target/sdkconfig.ci.tls_servert_auth new file mode 100644 index 00000000000..4279a476b93 --- /dev/null +++ b/components/esp_websocket_client/examples/target/sdkconfig.ci.tls_servert_auth @@ -0,0 +1,15 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_LINUX=n +CONFIG_WEBSOCKET_URI_FROM_STDIN=n +CONFIG_WEBSOCKET_URI_FROM_STRING=y +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_WEBSOCKET_URI="wss://echo.websocket.events" +CONFIG_PUBLIC_DOMAIN_AUTHENTIFICATION=y