Skip to content

Commit

Permalink
Merge pull request #49 from Oofnik/ssldual
Browse files Browse the repository at this point in the history
Added two-way ssl authentication
  • Loading branch information
gilmaimon authored Apr 21, 2020
2 parents f942285 + 785a114 commit 8de0ada
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 5 deletions.
168 changes: 168 additions & 0 deletions examples/SecuredTwoWay-Esp8266-Client/SecuredTwoWay-Esp8266-Client.ino
Original file line number Diff line number Diff line change
@@ -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 <ArduinoWebsockets.h>
#include <ESP8266WiFi.h>

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();
}
11 changes: 10 additions & 1 deletion src/tiny_websockets/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,12 @@ 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);
void setPrivateKey(const char* private_key);
#endif

virtual ~WebsocketsClient();
Expand All @@ -100,8 +104,13 @@ 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;
const char* _optional_ssl_private_key = nullptr;
#endif

void _handlePing(WebsocketsMessage);
Expand All @@ -110,4 +119,4 @@ namespace websockets {

void upgradeToSecuredConnection();
};
}
}
10 changes: 9 additions & 1 deletion src/tiny_websockets/network/esp32/esp32_tcp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
};


Expand Down Expand Up @@ -70,4 +78,4 @@ namespace websockets { namespace network {
};
}} // websockets::network

#endif // #ifdef ESP32
#endif // #ifdef ESP32
11 changes: 10 additions & 1 deletion src/tiny_websockets/network/esp8266/esp8266_tcp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -72,4 +81,4 @@ namespace websockets { namespace network {
};
}} // websockets::network

#endif // #ifdef ESP8266
#endif // #ifdef ESP8266
41 changes: 39 additions & 2 deletions src/websockets_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,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();
Expand All @@ -180,6 +188,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<WSDefaultSecuredTcpClient>(client);
Expand Down Expand Up @@ -539,14 +553,37 @@ 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;
}

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

Expand Down

0 comments on commit 8de0ada

Please sign in to comment.