Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSL bug-fixing, implemented public-key certificate validation & EC Certificates for client-side #85

Merged
merged 3 commits into from
Jul 23, 2020

Conversation

adelin-mcbsoft
Copy link
Contributor

Hi @gilmaimon ,

In this pull request I addressed issue #84 and also implemented server public-key certificate validation (using setKnownKey method) and EC certificate validation for client-side authentication using setClientECCert method, all for ESP8266, inherited from the official BearSSL library.

Also, I've corrected the SecuredTwoWay-Example for ESP8266 and updated readme.md accordingly .

Let me know if you need any more info regarding this PR,

All the best,
Adelin

PS: A lot of white-space is shown in the diff, not sure why.

… not sent if used along with setTrustAnchors]
-SSL Public Key certificate verification (setKnownKey method)
-EC Client Certificates (setClientECCert method)
@gilmaimon
Copy link
Owner

Hi @adelin-mcbsoft !

First I should say this library is in perseverance-state as far as I'm concerned. Meaning, I do my best to help users and fix small bugs but try to avoid adding features (I don't really have the time for it these days.

That being said, I really appreciate the donation and the effort you put into it. I want to merge this, can you please ensure few things:

  1. Make a last quick sanity check using only your branch (ensure no other changes are present) and see that the code is working as you expect in esp8266
  2. Ensure that the code compiles for esp32 without errors (although the CI will do that anyway)

After that, I'll happily merge.

Gil.

@adelin-mcbsoft
Copy link
Contributor Author

Hi @gilmaimon ,

Good to hear from you! Hope you are doing well!
So, I confirm I made tests which ran successfully for the newly implemented items on ESP8266 (setKnownKey for setting public key certificate and setClientECCert for setting Eliptic Curve Certificates) along with the setTrustAnchors bug-fix.

Also, regression tests were made both for ESP8266 and ESP32, both compile without any troubles.
I will attach the code used for testing below, along with the compilation status, both for ESP32 and ESP8266.

One thing to mention: For CA, ESP32 requires minimum 2048bit certificates, while ESP8266 is fine with 1024bit.

Hope this is enough in order to have the PR merged and a new version released.

Looking forward to hearing from you,
All the best,

Adelin

ESP8266

Code used for testing:

#include <ArduinoWebsockets.h>
#include <ESP8266WiFi.h>

const char* ssid = "[Your WiFi Name]"; //Enter SSID
const char* password = "[Your WiFi Password]"; //Enter Password

const char* websockets_connection_string = "wss://192.168.0.123/ws/"; // Enter server adress

const char ca_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
[Your min-1024bit CA Certificate]
-----END CERTIFICATE-----
)EOF";

/****************************************************************/

// The client's private key which must be kept secret
const char client_private_key[] PROGMEM = R"EOF(
-----BEGIN EC PARAMETERS-----
[Your EC Params]
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
[Your Private Key]
-----END EC PRIVATE KEY-----
)EOF";

// The client's public certificate which must be shared
const char client_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
[Your Client Certificate]
-----END CERTIFICATE-----
)EOF";

using namespace websockets;

const char *ntp1 = "time.windows.com";
const char *ntp2 = "pool.ntp.org";
time_t now;

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
      while(WiFi.status() != WL_CONNECTED) {
          Serial.print(".");
          delay(1000);
      }
    
      Serial.println("Connected to Wifi, setting time... ");
    
      configTime(2 * 3600, 1, ntp1, ntp2);
      while(now < 2 * 3600) {
        Serial.print(".");
        delay(500);
        now = time(nullptr);
      }
      Serial.println("");
      Serial.println("Time set, connecting to server...");

    // run callback when messages are received
    client.onMessage(onMessageCallback);
    
    // run callback when events are occuring
    client.onEvent(onEventsCallback);

    X509List *caCertList = new X509List(ca_cert);
    client.setTrustAnchors(caCertList);
    
    X509List *serverCertList = new X509List(client_cert);
    PrivateKey *serverPrivKey = new PrivateKey(client_private_key);
    client.setClientECCert(serverCertList, serverPrivKey);
    
    // Connect to server
    client.connect(websockets_connection_string);

    // Send a message
    client.send("Hello Server");

    // Send a ping
    client.ping();

    Serial.print("Connected, sent.");
}

void loop() {
    client.poll();
}

Compilation Status:

Executable segment sizes:
IROM   : 378344          - code in flash         (default or ICACHE_FLASH_ATTR) 
IRAM   : 27080   / 32768 - code in IRAM          (ICACHE_RAM_ATTR, ISRs...) 
DATA   : 1360  )         - initialized variables (global, static) in RAM/HEAP 
RODATA : 1924  ) / 81920 - constants             (global, static) in RAM/HEAP 
BSS    : 25136 )         - zeroed variables      (global, static) in RAM/HEAP 
Using library ArduinoWebsockets at version 0.4.17 in folder: C:\Users\Adelin\Documents\Arduino\libraries\ArduinoWebsockets 
[...]
Sketch uses 408708 bytes (42%) of program storage space. Maximum is 958448 bytes.
Global variables use 28420 bytes (34%) of dynamic memory, leaving 53500 bytes for local variables. Maximum is 81920 bytes.

ESP32

Code used for testing:

#include <ArduinoWebsockets.h>
#include <WiFi.h>

const char* ssid = "[Your WiFi Name]"; //Enter SSID
const char* password = "[Your WiFi Password]"; //Enter Password

const char* websockets_connection_string = "wss://192.168.0.123/ws/"; //Enter server adress

const char ca_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
[Your min-2048bit CA Certificate]
-----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-----
[Your RSA Private Key]
-----END RSA PRIVATE KEY-----
)EOF";

// The clint's public certificate which must be shared
const char client_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
[Your RSA Certificate]
-----END CERTIFICATE-----
)EOF";

using namespace websockets;

const char *ntp1 = "time.windows.com";
const char *ntp2 = "pool.ntp.org";
time_t now;

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
      while(WiFi.status() != WL_CONNECTED) {
          Serial.print(".");
          delay(1000);
      }
    
      Serial.println("Connected to Wifi, setting time... ");
    
      configTime(2 * 3600, 1, ntp1, ntp2);
      while(now < 2 * 3600) {
        Serial.print(".");
        delay(500);
        now = time(nullptr);
      }
      Serial.println("");
      Serial.println("Time set, connecting to server...");

    // run callback when messages are received
    client.onMessage(onMessageCallback);
    
    // run callback when events are occuring
    client.onEvent(onEventsCallback);

    client.setCACert(ca_cert);
    
    client.setCertificate(client_cert);
    client.setPrivateKey(client_private_key);
    
    // Connect to server
    client.connect(websockets_connection_string);

    // Send a message
    client.send("Hello Server");

    // Send a ping
    client.ping();

    Serial.print("Connected, sent.");
}

void loop() {
    client.poll();
}

Compilation status:

Using library ArduinoWebsockets at version 0.4.17 in folder: C:\Users\Adelin\Documents\Arduino\libraries\ArduinoWebsockets 
Sketch uses 881690 bytes (67%) of program storage space. Maximum is 1310720 bytes.
Global variables use 39880 bytes (12%) of dynamic memory, leaving 287800 bytes for local variables. Maximum is 327680 bytes.

@gilmaimon
Copy link
Owner

Thanks @adelin-mcbsoft , Merged!

@gilmaimon gilmaimon merged commit 8dcd30e into gilmaimon:master Jul 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants