From 7e87a8e7b4601a771fce55b19cb56af8646680bc Mon Sep 17 00:00:00 2001 From: Suren Gabrielyan Date: Tue, 6 Feb 2024 22:55:06 +0400 Subject: [PATCH] feat(websocket): Expanded example to demonstrate the transfer over TLS --- .../examples/target/README.md | 47 +++++++++++++++++ .../examples/target/main/CMakeLists.txt | 6 +++ .../examples/target/main/Kconfig.projbuild | 14 ++++++ .../examples/target/main/certs/ca_cert.pem | 21 ++++++++ .../examples/target/main/certs/ca_key.pem | 28 +++++++++++ .../target/main/certs/client_cert.pem | 20 ++++++++ .../examples/target/main/certs/client_key.pem | 28 +++++++++++ .../target/main/certs/server_cert.pem | 20 ++++++++ .../examples/target/main/certs/server_key.pem | 28 +++++++++++ .../examples/target/main/websocket_example.c | 19 ++++++- .../examples/target/pytest_websocket.py | 50 +++++++++++++++---- .../target/sdkconfig.ci.tls_mutual_auth | 14 ++++++ .../target/sdkconfig.ci.tls_servert_auth | 14 ++++++ 13 files changed, 298 insertions(+), 11 deletions(-) create mode 100644 components/esp_websocket_client/examples/target/main/certs/ca_cert.pem create mode 100644 components/esp_websocket_client/examples/target/main/certs/ca_key.pem create mode 100644 components/esp_websocket_client/examples/target/main/certs/client_cert.pem create mode 100644 components/esp_websocket_client/examples/target/main/certs/client_key.pem create mode 100644 components/esp_websocket_client/examples/target/main/certs/server_cert.pem create mode 100644 components/esp_websocket_client/examples/target/main/certs/server_key.pem create mode 100644 components/esp_websocket_client/examples/target/sdkconfig.ci.tls_mutual_auth create mode 100644 components/esp_websocket_client/examples/target/sdkconfig.ci.tls_servert_auth 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..9a15c370aad 100644 --- a/components/esp_websocket_client/examples/target/main/CMakeLists.txt +++ b/components/esp_websocket_client/examples/target/main/CMakeLists.txt @@ -1,2 +1,8 @@ idf_component_register(SRCS "websocket_example.c" INCLUDE_DIRS ".") + +if(CONFIG_WS_OVER_TLS_SERVER_AUTH OR CONFIG_WS_OVER_TLS_MUTUAL_AUTH) + idf_component_register(EMBED_TXTFILES "certs/client_cert.pem" + "certs/ca_cert.pem" + "certs/client_key.pem") +endif() diff --git a/components/esp_websocket_client/examples/target/main/Kconfig.projbuild b/components/esp_websocket_client/examples/target/main/Kconfig.projbuild index 49ad49effdd..552dd7b83a0 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 WS_OVER_TLS_SERVER_AUTH + 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 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_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..a44477f6d54 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 @@ -143,6 +143,21 @@ static void websocket_app_start(void) websocket_cfg.uri = CONFIG_WEBSOCKET_URI; #endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */ +#if CONFIG_WS_OVER_TLS_SERVER_AUTH || 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 ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri); esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg); diff --git a/components/esp_websocket_client/examples/target/pytest_websocket.py b/components/esp_websocket_client/examples/target/pytest_websocket.py index 9d6f3159926..f7e823874f1 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,25 @@ 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_verify is True: + ssl_context.load_verify_locations(cafile='main/certs/ca_cert.pem') + ssl_context.verify_mode = ssl.CERT_REQUIRED + else: + ssl_context.verify_mode = ssl.CERT_NONE + 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, verify): self.port = port + self.use_tls = use_tls + self.serv_verify = verify self.exit_event = Event() self.thread = Thread(target=self.run) self.thread.start() @@ -77,6 +93,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 +120,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 +144,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 +164,27 @@ 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_verify = True + elif dut.app.sdkconfig.get('WS_OVER_TLS_SERVER_AUTH') is True: + use_tls = True + serv_verify = False + else: + use_tls = False + serv_verify = 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_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..e7e272fa4fd --- /dev/null +++ b/components/esp_websocket_client/examples/target/sdkconfig.ci.tls_servert_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_SERVER_AUTH=y