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

Add support for CA bundles #885

Merged
merged 8 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ a WebSocket Server and Client for Arduino based on RFC6455.
by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a
sample Nginx server configuration file to enable this.

### Root CA Cert Bundles for SSL/TLS connections ###

Secure connections require the certificate of the server to be verified. One option is to provide a single certificate in the chain of trust. However, for flexibility and robustness, a certificate bundle is recommended. If a server changes the root CA from which it derives its certificates, this will not be a problem. With a single CA cert it will not connect.

- For [technical details](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_crt_bundle.html)
- For a [PlatformIO setup](https://github.com/Duckle29/esp32-certBundle/)
- For an [example](examples/esp32/WebSocketClientSSLBundle/)

Including a bundle with all CA certs will use 77.2 kB but this list can be reduced to 16.5 kB for the 41 most common. This results in 90% absolute usage coverage and 99% market share coverage according to [W3Techs](https://w3techs.com/technologies/overview/ssl_certificate). The bundle is inserted into the compiled firmware. The bundle is not loaded into RAM, only its index.

### ESP Async TCP ###

This libary can run in Async TCP mode on the ESP.
Expand Down
8 changes: 8 additions & 0 deletions examples/esp32/WebSocketClientSSLBundle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
*secret*
!*secrets.hpp.template
*x509_crt_bundle
3,581 changes: 3,581 additions & 0 deletions examples/esp32/WebSocketClientSSLBundle/cacrt_all.pem

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions examples/esp32/WebSocketClientSSLBundle/cmn_crt_authorities.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Owner,Common Name or Certificate Name
Amazon Trust Services,Amazon Root CA 1
Amazon Trust Services,Amazon Root CA 2
Amazon Trust Services,Amazon Root CA 3
Amazon Trust Services,Amazon Root CA 4
Amazon Trust Services,Starfield Services Root Certificate Authority - G2
DigiCert,Baltimore CyberTrust Root
DigiCert,Cybertrust Global Root
DigiCert,DigiCert Assured ID Root CA
DigiCert,DigiCert Assured ID Root G2
DigiCert,DigiCert Assured ID Root G3
DigiCert,DigiCert Global Root CA
DigiCert,DigiCert Global Root G2
DigiCert,DigiCert Global Root G3
DigiCert,DigiCert High Assurance EV Root CA
DigiCert,DigiCert Trusted Root G4
GlobalSign,GlobalSign ECC Root CA - R5
GlobalSign,GlobalSign Root CA - R3
GlobalSign,GlobalSign Root CA - R6
GlobalSign,GlobalSign Root CA
GoDaddy,Go Daddy Class 2 CA
GoDaddy,Go Daddy Root Certificate Authority - G2
GoDaddy,Starfield Class 2 CA
GoDaddy,Starfield Root Certificate Authority - G2
Google Trust Services LLC (GTS),GlobalSign ECC Root CA - R4
Google Trust Services LLC (GTS),GlobalSign Root CA - R2
Google Trust Services LLC (GTS),GTS Root R1
Google Trust Services LLC (GTS),GTS Root R2
Google Trust Services LLC (GTS),GTS Root R3
Google Trust Services LLC (GTS),GTS Root R4
"IdenTrust Services, LLC",DST Root CA X3
"IdenTrust Services, LLC",IdenTrust Commercial Root CA 1
"IdenTrust Services, LLC",IdenTrust Public Sector Root CA 1
Sectigo,Comodo AAA Services root
Sectigo,COMODO Certification Authority
Sectigo,COMODO ECC Certification Authority
Sectigo,COMODO RSA Certification Authority
Sectigo,USERTrust ECC Certification Authority
Sectigo,USERTrust RSA Certification Authority
108 changes: 108 additions & 0 deletions examples/esp32/WebSocketClientSSLBundle/example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* WebSocketClient.ino
*
* Created on: 15.06.2024
*
*/

#include <Arduino.h>

#include <WiFi.h>
#include <WiFiMulti.h>
#include <WiFiClientSecure.h>

#include <WebSocketsClient.h>

extern const uint8_t rootca_crt_bundle_start[] asm(
"_binary_data_cert_x509_crt_bundle_bin_start");

WiFiMulti WiFiMulti;
WebSocketsClient webSocket;

#define USE_SERIAL Serial1

void hexdump(const void * mem, uint32_t len, uint8_t cols = 16) {
const uint8_t * src = (const uint8_t *)mem;
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
for(uint32_t i = 0; i < len; i++) {
if(i % cols == 0) {
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
}
USE_SERIAL.printf("%02X ", *src);
src++;
}
USE_SERIAL.printf("\n");
}

void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
USE_SERIAL.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED:
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);

// send message to server when Connected
webSocket.sendTXT("Connected");
break;
case WStype_TEXT:
USE_SERIAL.printf("[WSc] get text: %s\n", payload);

// send message to server
// webSocket.sendTXT("message here");
break;
case WStype_BIN:
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
hexdump(payload, length);

// send data to server
// webSocket.sendBIN(payload, length);
break;
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
break;
}
}

void setup() {
USE_SERIAL.begin(115200);

USE_SERIAL.setDebugOutput(true);

USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();

for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}

WiFiMulti.addAP("SSID", "passpasspass");

// WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}

// server address, port and URL (https://piehost.com/websocket-tester)
webSocket.beginSslWithBundle(
"demo.piesocket.com", 443, "/v3/channel_123?api_key=XYZ", rootca_crt_bundle_start);

// event handler
webSocket.onEvent(webSocketEvent);

// use HTTP Basic Authorization this is optional remove if not needed
webSocket.setAuthorization("user", "Password");

// try ever 5000 again if connection has failed
webSocket.setReconnectInterval(5000);
}

void loop() {
webSocket.loop();
}
Loading
Loading