From 8c9fa80b126161667ea6fb0e58ebab1f335d12e3 Mon Sep 17 00:00:00 2001 From: ecohen Date: Fri, 25 Oct 2019 08:31:26 -0400 Subject: [PATCH 1/3] Added two-way ssl authentication --- src/tiny_websockets/client.hpp | 6 +++++- src/tiny_websockets/network/esp32/esp32_tcp.hpp | 10 +++++++++- src/websockets_client.cpp | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/tiny_websockets/client.hpp b/src/tiny_websockets/client.hpp index c1272de..213fc9a 100644 --- a/src/tiny_websockets/client.hpp +++ b/src/tiny_websockets/client.hpp @@ -81,6 +81,8 @@ namespace websockets { void setFingerprint(const char* fingerprint); #elif defined(ESP32) void setCACert(const char* ca_cert); + void setCertificate(const char* client_ca); + void setPrivateKey(const char* private_key); #endif virtual ~WebsocketsClient(); @@ -102,6 +104,8 @@ namespace websockets { const char* _optional_ssl_fingerprint = nullptr; #elif defined(ESP32) const char* _optional_ssl_ca_cert = nullptr; + const char* _optional_ssl_client_ca = nullptr; + const char* _optional_ssl_private_key = nullptr; #endif void _handlePing(WebsocketsMessage); @@ -110,4 +114,4 @@ namespace websockets { void upgradeToSecuredConnection(); }; -} \ No newline at end of file +} diff --git a/src/tiny_websockets/network/esp32/esp32_tcp.hpp b/src/tiny_websockets/network/esp32/esp32_tcp.hpp index 224158b..9ed5266 100644 --- a/src/tiny_websockets/network/esp32/esp32_tcp.hpp +++ b/src/tiny_websockets/network/esp32/esp32_tcp.hpp @@ -18,6 +18,14 @@ namespace websockets { namespace network { void setCACert(const char* ca_cert) { this->client.setCACert(ca_cert); } + + void setCertificate(const char* client_ca) { + this->client.setCertificate(client_ca); + } + + void setPrivateKey(const char* private_key) { + this->client.setPrivateKey(private_key); + } }; @@ -70,4 +78,4 @@ namespace websockets { namespace network { }; }} // websockets::network -#endif // #ifdef ESP32 \ No newline at end of file +#endif // #ifdef ESP32 diff --git a/src/websockets_client.cpp b/src/websockets_client.cpp index 0e64520..0288196 100644 --- a/src/websockets_client.cpp +++ b/src/websockets_client.cpp @@ -178,6 +178,12 @@ namespace websockets { if(this->_optional_ssl_ca_cert) { client->setCACert(this->_optional_ssl_ca_cert); } + if(this->_optional_ssl_client_ca) { + client->setCertificate(this->_optional_ssl_client_ca); + } + if(this->_optional_ssl_private_key) { + client->setPrivateKey(this->_optional_ssl_private_key); + } #endif this->_client = std::shared_ptr(client); @@ -543,8 +549,18 @@ namespace websockets { this->_optional_ssl_ca_cert = ca_cert; } + void WebsocketsClient::setCertificate(const char* client_ca) { + this->_optional_ssl_client_ca = client_ca; + } + + void WebsocketsClient::setPrivateKey(const char* private_key) { + this->_optional_ssl_private_key = private_key; + } + void WebsocketsClient::setInsecure() { this->_optional_ssl_ca_cert = nullptr; + this->_optional_ssl_client_ca = nullptr; + this->_optional_ssl_private_key = nullptr; } #endif From 0c0e11e3fcf6f502da5a68f5a02e9c58aff355d4 Mon Sep 17 00:00:00 2001 From: Eyal Cohen Date: Fri, 1 Nov 2019 11:04:34 -0400 Subject: [PATCH 2/3] Added two way authentication to ESP8266 --- src/tiny_websockets/client.hpp | 5 ++++ .../network/esp8266/esp8266_tcp.hpp | 11 +++++++- src/websockets_client.cpp | 25 +++++++++++++++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/tiny_websockets/client.hpp b/src/tiny_websockets/client.hpp index 213fc9a..f402698 100644 --- a/src/tiny_websockets/client.hpp +++ b/src/tiny_websockets/client.hpp @@ -79,6 +79,8 @@ namespace websockets { void setInsecure(); #ifdef ESP8266 void setFingerprint(const char* fingerprint); + void setClientRSACert(const X509List *cert, const PrivateKey *sk); + void setTrustAnchors(const X509List *ta); #elif defined(ESP32) void setCACert(const char* ca_cert); void setCertificate(const char* client_ca); @@ -102,6 +104,9 @@ namespace websockets { #ifdef ESP8266 const char* _optional_ssl_fingerprint = nullptr; + const X509List* _optional_ssl_trust_anchors = nullptr; + const X509List* _optional_ssl_cert = nullptr; + const PrivateKey* _optional_ssl_private_key = nullptr; #elif defined(ESP32) const char* _optional_ssl_ca_cert = nullptr; const char* _optional_ssl_client_ca = nullptr; diff --git a/src/tiny_websockets/network/esp8266/esp8266_tcp.hpp b/src/tiny_websockets/network/esp8266/esp8266_tcp.hpp index d624ff5..c114566 100644 --- a/src/tiny_websockets/network/esp8266/esp8266_tcp.hpp +++ b/src/tiny_websockets/network/esp8266/esp8266_tcp.hpp @@ -21,6 +21,15 @@ namespace websockets { namespace network { void setFingerprint(const char* fingerprint) { this->client.setFingerprint(fingerprint); } + + void setClientRSACert(const X509List *cert, const PrivateKey *sk) { + this->client.setClientRSACert(cert, sk); + } + + void setTrustAnchors(const X509List *ta){ + this->client.setTrustAnchors(ta); + } + }; #define DUMMY_PORT 0 @@ -72,4 +81,4 @@ namespace websockets { namespace network { }; }} // websockets::network -#endif // #ifdef ESP8266 \ No newline at end of file +#endif // #ifdef ESP8266 diff --git a/src/websockets_client.cpp b/src/websockets_client.cpp index 0288196..39570e4 100644 --- a/src/websockets_client.cpp +++ b/src/websockets_client.cpp @@ -168,8 +168,16 @@ namespace websockets { auto client = new WSDefaultSecuredTcpClient; #ifdef ESP8266 - if(this->_optional_ssl_fingerprint) { - client->setFingerprint(this->_optional_ssl_fingerprint); + if(this->_optional_ssl_fingerprint || (this->_optional_ssl_cert && this->_optional_ssl_private_key) || this->_optional_ssl_trust_anchors) { + if(this->_optional_ssl_fingerprint) { + client->setFingerprint(this->_optional_ssl_fingerprint); + } + if(this->_optional_ssl_cert && this->_optional_ssl_private_key) { + client->setClientRSACert(this->_optional_ssl_cert, this->_optional_ssl_private_key); + } + if(this->_optional_ssl_trust_anchors) { + client->setTrustAnchors(this->_optional_ssl_trust_anchors); + } } else { client->setInsecure(); @@ -543,7 +551,20 @@ namespace websockets { void WebsocketsClient::setInsecure() { this->_optional_ssl_fingerprint = nullptr; + this->_optional_ssl_cert = nullptr; + this->_optional_ssl_private_key = nullptr; + this->_optional_ssl_trust_anchors = nullptr; } + + void WebsocketsClient::setClientRSACert(const X509List *cert, const PrivateKey *sk) { + this->_optional_ssl_cert = cert; + this->_optional_ssl_private_key = sk; + } + + void WebsocketsClient::setTrustAnchors(const X509List *ta){ + this->_optional_ssl_trust_anchors = ta; + } + #elif defined(ESP32) void WebsocketsClient::setCACert(const char* ca_cert) { this->_optional_ssl_ca_cert = ca_cert; From 785a114e205f4aa3ae543b7c5d1b4dccebd768e7 Mon Sep 17 00:00:00 2001 From: Eyal Cohen Date: Fri, 1 Nov 2019 11:14:15 -0400 Subject: [PATCH 3/3] Added Example File for two way auth using ESP8266 --- .../SecuredTwoWay-Esp8266-Client.ino | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 examples/SecuredTwoWay-Esp8266-Client/SecuredTwoWay-Esp8266-Client.ino diff --git a/examples/SecuredTwoWay-Esp8266-Client/SecuredTwoWay-Esp8266-Client.ino b/examples/SecuredTwoWay-Esp8266-Client/SecuredTwoWay-Esp8266-Client.ino new file mode 100644 index 0000000..9a95336 --- /dev/null +++ b/examples/SecuredTwoWay-Esp8266-Client/SecuredTwoWay-Esp8266-Client.ino @@ -0,0 +1,168 @@ +/* + Secured Esp8266 Websockets Client + + This sketch: + 1. Connects to a WiFi network + 2. Connects to a Websockets server (using WSS) + 3. Sends the websockets server a message ("Hello Server") + 4. Sends the websocket server a "ping" + 5. Prints all incoming messages while the connection is open + + NOTE: + The sketch dosen't check or indicate about errors while connecting to + WiFi or to the websockets server. For full example you might want + to try the example named "Esp8266-Client" (And use the ssl methods). + + Hardware: + For this sketch you only need an ESP8266 board. + + Created 15/02/2019 + By Gil Maimon + https://github.com/gilmaimon/ArduinoWebsockets + +*/ + +#include +#include + +const char* ssid = "ssid"; //Enter SSID +const char* password = "password"; //Enter Password + +const char* websockets_connection_string = "wss://echo.websocket.org/"; //Enter server adress + +// The hardcoded certificate authority for this example. +// Don't use it on your own apps!!!!! +const char ca_cert[] PROGMEM = R"EOF( +-----BEGIN CERTIFICATE----- +MIIC1TCCAb2gAwIBAgIJAMPt1Ms37+hLMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV +BAYTAlVTMRIwEAYDVQQDDAkxMjcuMC4wLjMwHhcNMTgwMzE0MDQyMTU0WhcNMjkw +NTMxMDQyMTU0WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAwwJMTI3LjAuMC4zMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxsa4qU/tlzN4YTcnn/I/ffsi +jOPc8QRcwClKzasIZNFEye4uThl+LGZWFIFb8X8Dc+xmmBaWlPJbqtphgFKStpar +DdduHSW1ud6Y1FVKxljo3UwCMrYm76Q/jNzXJvGs6Z1MDNsVZzGJaoqit2H2Hkvk +y+7kk3YbEDlcyVsLOw0zCKL4cd2DSNDyhIZxWo2a8Qn5IdjWAYtsTnW6MvLk/ya4 +abNeRfSZwi+r37rqi9CIs++NpL5ynqkKKEMrbeLactWgHbWrZeaMyLpuUEL2GF+w +MRaAwaj7ERwT5gFJRqYwj6bbfIdx5PC7h7ucbyp272MbrDa6WNBCMwQO222t4wID +AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmXfrC42nW +IpL3JDkB8YlB2QUvD9JdMp98xxo33+xE69Gov0e6984F1Gluao0p6sS7KF+q3YLS +4hjnzuGzF9GJMimIB7NMQ20yXKfKpmKJ7YugMaKTDWDhHn5679mKVbLSQxHCUMEe +tEnMT93/UaDbWBjV6zu876q5vjPMYgDHODqO295ySaA71UkijaCn6UwKUT49286T +V9ZtzgabNGHXfklHgUPWoShyze+G3g29I1BR0qABoJI63zaNu8ua42v5g1RldxsW +X8yKI14mFOGxuvcygG8L2xxysW7Zq+9g+O7gW0Pm6RDYnUQmIwY83h1KFCtYCJdS +2PgozwkkUNyP +-----END CERTIFICATE----- +)EOF"; + +// The client's private key which must be kept secret +const char client_private_key[] PROGMEM = R"EOF( +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAsRNVTvqP++YUh8NrbXwE83xVsDqcB3F76xcXNKFDERfVd2P/ +LvyDovCcoQtT0UCRgPcxRp894EuPH/Ru6Z2Lu85sV//i7ce27tc2WRFSfuhlRxHP +LJWHxTl1CEfXp/owkECQ4MB3pw6Ekc16iTEPiezTG+T+mQ/BkiIwcIK6CMlpR9DI +eYUTqv0f9NrUfAjdBrqlEO2gpgFvLFrkDEU2ntAIc4aPOP7yDOym/xzfy6TiG8Wo +7nlh6M97xTZGfbEPCH9rZDjo5istym1HzF5P+COq+OTSPscjFGXoi978o6hZwa7i +zxorg4h5a5lGnshRu2Gl+Ybfa14OwnIrv/yCswIDAQABAoIBAHxwgbsHCriTcEoY +Yx6F0VTrQ6ydA5mXfuYvS/eIfIE+pp1IgMScYEXZobjrJPQg1CA1l0NyFSHS97oV +JPy34sMQxcLx6KABgeVHCMJ/EeJtnv7a3SUP0GIhhsVS95Lsl8RIG4hWub+EzFVK +eZqAB9N9wr4Pp3wZPodbz37B38rb1QPyMFmQOLlHjKTOmoxsXhL2ot+R3+aLYSur +oPO1kQo7/d0UAZoy8h9OQN4a2EXvawh4O2EvFGbc5X/yXwAdEQ4NPp9VZhkNIRkV ++XZ3FcIqEVOploKtRF/tVBTz3g61/lFz21L9PMmV5y8tvSafr2SpJugGVmp2rrVQ +VNyGlIECgYEA10JSI5gmeCU3zK6kvOfBp54hY/5dDrSUpjKkMxpmm7WZQ6Il/k7A +hMcLeMzHiriT7WhRIXF8AOr2MoEkHkH3DhVNN4ccieVZx2SE5P5mVkItZGLrrpfU +dysR/ARAI1HYegGUiKacZtf9SrRavU0m7fOVOiYwbFRhjyX+MyuteYkCgYEA0pbz +4ZosetScP68uZx1sGlTfkcqLl7i15DHk3gnj6jKlfhvC2MjeLMhNDtKeUAuY7rLQ +guZ0CCghWAv0Glh5eYdfIiPhgqFfX4P5F3Om4zQHVPYj8xHfHG4ZP7dKQTndrO1Q +fLdGDTQLVXabAUSp2YGrijC8J9idSW1pYClvF1sCgYEAjkDn41nzYkbGP1/Swnwu +AEWCL4Czoro32jVxScxSrugt5wJLNWp508VukWBTJhugtq3Pn9hNaJXeKbYqVkyl +pgrxwpZph7+nuxt0r5hnrO2C7eppcjIoWLB/7BorAKxf8REGReBFT7nBTBMwPBW2 +el4U6h6+tXh2GJG1Eb/1nnECgYAydVb0THOx7rWNkNUGggc/++why61M6kYy6j2T +cj05BW+f2tkCBoctpcTI83BZb53yO8g4RS2yMqNirGKN2XspwmTqEjzbhv0KLt4F +X4GyWOoU0nFksXiLIFpOaQWSwWG7KJWrfGJ9kWXR0Xxsfl5QLoDCuNCsn3t4d43T +K7phlwKBgHDzF+50+/Wez3YHCy2a/HgSbHCpLQjkknvgwkOh1z7YitYBUm72HP8Z +Ge6b4wEfNuBdlZll/y9BQQOZJLFvJTE5t51X9klrkGrOb+Ftwr7eI/H5xgcadI52 +tPYglR5fjuRF/wnt3oX9JlQ2RtSbs+3naXH8JoherHaqNn8UpH0t +-----END RSA PRIVATE KEY----- +)EOF"; + +// The clint's public certificate which must be shared +const char client_cert[] PROGMEM = R"EOF( +-----BEGIN CERTIFICATE----- +MIIDTzCCAjcCCQDPXvMRYOpeuDANBgkqhkiG9w0BAQsFADCBpjESMBAGA1UEAwwJ +MTI3LjAuMC4xMQswCQYDVQQGEwJVUzElMCMGA1UECgwcTXkgT3duIENlcnRpZmlj +YXRlIEF1dGhvcml0eTEUMBIGA1UECAwLQXJkdWlub0xhbmQxFTATBgNVBAcMDEFy +ZHVpbm9WaWxsZTEVMBMGA1UECgwMRVNQODI2NlVzZXJzMRgwFgYDVQQLDA9FU1A4 +MjY2LUFyZHVpbm8wHhcNMTgwMzE0MDQwMDAwWhcNMjkwMjI0MDQwMDAwWjAsMRYw +FAYDVQQKDA1NeSBTZXJ2ZXIgT3JnMRIwEAYDVQQDDAkxMjcuMC4wLjMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxE1VO+o/75hSHw2ttfATzfFWwOpwH +cXvrFxc0oUMRF9V3Y/8u/IOi8JyhC1PRQJGA9zFGnz3gS48f9G7pnYu7zmxX/+Lt +x7bu1zZZEVJ+6GVHEc8slYfFOXUIR9en+jCQQJDgwHenDoSRzXqJMQ+J7NMb5P6Z +D8GSIjBwgroIyWlH0Mh5hROq/R/02tR8CN0GuqUQ7aCmAW8sWuQMRTae0Ahzho84 +/vIM7Kb/HN/LpOIbxajueWHoz3vFNkZ9sQ8If2tkOOjmKy3KbUfMXk/4I6r45NI+ +xyMUZeiL3vyjqFnBruLPGiuDiHlrmUaeyFG7YaX5ht9rXg7Cciu//IKzAgMBAAEw +DQYJKoZIhvcNAQELBQADggEBAEnG+FNyNCOkBvzHiUpHHpScxZqM2f+XDcewJgeS +L6HkYEDIZZDNnd5gduSvkHpdJtWgsvJ7dJZL40w7Ba5sxpZHPIgKJGl9hzMkG+aA +z5GMkjys9h2xpQZx9KL3q7G6A+C0bll7ODZlwBtY07CFMykT4Mp2oMRrQKRucMSV +AB1mKujLAnMRKJ3NM89RQJH4GYiRps9y/HvM5lh7EIK/J0/nEZeJxY5hJngskPKb +oPPdmkR97kaQnll4KNsC3owVlHVU2fMftgYkgQLzyeWgzcNa39AF3B6JlcOzNyQY +seoK24dHmt6tWmn/sbxX7Aa6TL/4mVlFoOgcaTJyVaY/BrY= +-----END CERTIFICATE----- +)EOF"; + +using namespace websockets; + +void onMessageCallback(WebsocketsMessage message) { + Serial.print("Got Message: "); + Serial.println(message.data()); +} + +void onEventsCallback(WebsocketsEvent event, String data) { + if(event == WebsocketsEvent::ConnectionOpened) { + Serial.println("Connnection Opened"); + } else if(event == WebsocketsEvent::ConnectionClosed) { + Serial.println("Connnection Closed"); + } else if(event == WebsocketsEvent::GotPing) { + Serial.println("Got a Ping!"); + } else if(event == WebsocketsEvent::GotPong) { + Serial.println("Got a Pong!"); + } +} + +WebsocketsClient client; +void setup() { + Serial.begin(115200); + // Connect to wifi + WiFi.begin(ssid, password); + + // Wait some time to connect to wifi + for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) { + Serial.print("."); + delay(1000); + } + + // run callback when messages are received + client.onMessage(onMessageCallback); + + // run callback when events are occuring + client.onEvent(onEventsCallback); + + // Before connecting, set the ssl certificates and key of the server + X509List cert(ca_cert); + client.setTrustAnchors(&cert); + + X509List *serverCertList = new X509List(client_cert); + PrivateKey *serverPrivKey = new PrivateKey(client_private_key); + client.setClientRSACert(serverCertList, serverPrivKey); + + // Connect to server + client.connect(websockets_connection_string); + + // Send a message + client.send("Hello Server"); + + // Send a ping + client.ping(); +} + +void loop() { + client.poll(); +}