Skip to content

Commit c5e7a5e

Browse files
authored
Add support for CA bundles (#885)
Why: - Allow CA cert bundles to be used This change addresses the need by: - Adding a constructor that takes a pointer to the bundle - Setting the WiFiClientSecure to use the bundle - Adding an example
1 parent 93707d4 commit c5e7a5e

File tree

13 files changed

+4232
-0
lines changed

13 files changed

+4232
-0
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ a WebSocket Server and Client for Arduino based on RFC6455.
4848
by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a
4949
sample Nginx server configuration file to enable this.
5050

51+
### Root CA Cert Bundles for SSL/TLS connections ###
52+
53+
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.
54+
55+
- For [technical details](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_crt_bundle.html)
56+
- For a [PlatformIO setup](https://github.com/Duckle29/esp32-certBundle/)
57+
- For an [example](examples/esp32/WebSocketClientSSLBundle/)
58+
59+
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.
60+
5161
### ESP Async TCP ###
5262

5363
This libary can run in Async TCP mode on the ESP.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* main.cpp
3+
*
4+
* Created on: 15.06.2024
5+
*
6+
*/
7+
8+
#include <Arduino.h>
9+
#include <WiFi.h>
10+
#include <WiFiMulti.h>
11+
12+
#include <WebSocketsClient.h>
13+
14+
// Use the incbin library to embedd the cert binary
15+
// extern const uint8_t rootca_crt_bundle_start[] asm(
16+
// "_binary_data_cert_x509_crt_bundle_bin_start");
17+
18+
WiFiMulti wifiMulti;
19+
WebSocketsClient webSocket;
20+
21+
#define USE_SERIAL Serial
22+
23+
void setClock() {
24+
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
25+
26+
USE_SERIAL.print(F("Waiting for NTP time sync: "));
27+
time_t nowSecs = time(nullptr);
28+
while(nowSecs < 8 * 3600 * 2) {
29+
delay(500);
30+
USE_SERIAL.print(F("."));
31+
yield();
32+
nowSecs = time(nullptr);
33+
}
34+
35+
USE_SERIAL.println();
36+
struct tm timeinfo;
37+
gmtime_r(&nowSecs, &timeinfo);
38+
USE_SERIAL.print(F("Current time: "));
39+
USE_SERIAL.print(asctime(&timeinfo));
40+
}
41+
42+
void hexdump(const void * mem, uint32_t len, uint8_t cols = 16) {
43+
const uint8_t * src = (const uint8_t *)mem;
44+
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
45+
for(uint32_t i = 0; i < len; i++) {
46+
if(i % cols == 0) {
47+
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
48+
}
49+
USE_SERIAL.printf("%02X ", *src);
50+
src++;
51+
}
52+
USE_SERIAL.printf("\n");
53+
}
54+
55+
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
56+
switch(type) {
57+
case WStype_DISCONNECTED:
58+
USE_SERIAL.printf("[WSc] Disconnected!\n");
59+
break;
60+
case WStype_CONNECTED:
61+
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
62+
63+
// send message to server when Connected
64+
webSocket.sendTXT("Connected");
65+
break;
66+
case WStype_TEXT:
67+
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
68+
69+
// send message to server
70+
// webSocket.sendTXT("message here");
71+
break;
72+
case WStype_BIN:
73+
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
74+
hexdump(payload, length);
75+
76+
// send data to server
77+
// webSocket.sendBIN(payload, length);
78+
break;
79+
case WStype_ERROR:
80+
case WStype_FRAGMENT_TEXT_START:
81+
case WStype_FRAGMENT_BIN_START:
82+
case WStype_FRAGMENT:
83+
case WStype_FRAGMENT_FIN:
84+
break;
85+
}
86+
}
87+
88+
void setup() {
89+
USE_SERIAL.begin(115200);
90+
91+
USE_SERIAL.setDebugOutput(true);
92+
93+
USE_SERIAL.println();
94+
USE_SERIAL.println();
95+
USE_SERIAL.println();
96+
97+
for(uint8_t t = 4; t > 0; t--) {
98+
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
99+
USE_SERIAL.flush();
100+
delay(1000);
101+
}
102+
103+
wifiMulti.addAP("SSID", "WIFI_PASSPHRASE");
104+
105+
// WiFi.disconnect();
106+
while(wifiMulti.run() != WL_CONNECTED) {
107+
delay(100);
108+
}
109+
110+
setClock();
111+
112+
// server address, port and URL. This server can be flakey.
113+
// Expected response: Request served by 0123456789abcdef
114+
// webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", rootca_crt_bundle_start, "");
115+
webSocket.beginSslWithBundle("echo.websocket.org", 443, "/", NULL, "");
116+
117+
// event handler
118+
webSocket.onEvent(webSocketEvent);
119+
120+
// use HTTP Basic Authorization this is optional enable if needed
121+
// webSocket.setAuthorization("user", "Password");
122+
123+
// try ever 5000 again if connection has failed
124+
webSocket.setReconnectInterval(5000);
125+
}
126+
127+
void loop() {
128+
webSocket.loop();
129+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.pio
2+
.vscode/.browse.c_cpp.db*
3+
.vscode/c_cpp_properties.json
4+
.vscode/launch.json
5+
.vscode/ipch
6+
*secret*
7+
!*secrets.hpp.template
8+
*x509_crt_bundle.bin

0 commit comments

Comments
 (0)