8000 Add basic ESP32 WiFiClientSecure support (#704) · ZZKK000/arduino-pico@cfc05da · GitHub
[go: up one dir, main page]

Skip to content

Commit cfc05da

Browse files
Add basic ESP32 WiFiClientSecure support (earlephilhower#704)
Simple sketches should work without modification, but some modes (listed in the docs) are not possible to support on the Pico W with BearSSL. Fixes earlephilhower#691
1 parent 4a17410 commit cfc05da

File tree

8 files changed

+250
-8
lines changed

8 files changed

+250
-8
lines changed

docs/bearssl-client-secure-class.rst

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
:orphan:
22

33
WiFiClientSecure Class
4-
----------------------
4+
======================
55

66
`BearSSL::WiFiClientSecure` is the object which actually handles TLS encrypted WiFi connections to a remote server or client. It extends `WiFiClient` and so can be used with minimal changes to code that does unsecured communications.
77

@@ -117,3 +117,30 @@ setSSLVersion(uint32_t min, uint32_t max)
117117
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
118118

119119
Valid values for min and max are `BR_TLS10`, `BR_TLS11`, `BR_TLS12`. Min and max may be set to the same value if only a single TLS version is desired.
120+
121+
122+
ESP32 Compatibility
123+
===================
124+
Simple ESP32 ``WiFiClientSecure`` compatibility is built-in, allow for some sketches to run without any modification.
125+
The following methods are implemented:
126+
127+
.. code :: cpp
128+
129+
void setCACert(const char *rootCA);
130+
void setCertificate(const char *client_ca);
131+
void setPrivateKey(const char *private_key);
132+
bool loadCACert(Stream& stream, size_t size);
133+
bool loadCertificate(Stream& stream, size_t size);
134+
bool loadPrivateKey(Stream& stream, size_t size);
135+
int connect(IPAddress ip, uint16_t port, int32_t timeout);
136+
int connect(const char *host, uint16_t port, int32_t timeout);
137+
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
138+
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
139+
140+
Note that the SSL backend is very different between Arduino-Pico and ESP32-Arduino (BearSSL vs. mbedTLS). This means
141+
that, for instance, the SSL connection will check valid dates of certificates (and hence require system time to be
142+
set on the Pico, which is automatically done in this case).
143+
144+
TLS-Pre Shared Keys (PSK) is not supported by BearSSL, and hence not implemented here. Neither is ALPN.
145+
146+
For more advanced control, it is recommended to port to the native Pico calls which allows much more flexibility and control.

docs/wifintp.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,20 @@ returns a sane value before continuing a sketch:
3939
Serial.print("Current time: ");
4040
Serial.print(asctime(&timeinfo));
4141
}
42+
43+
bool NTP.waitSet(uint32_t timeout)
44+
----------------------------------
45+
This call will wait up to timeout milliseconds for the time to be set, and returns
46+
success or failure. It will also begin NTP with a default "pool.ntp.org" server if
47+
it is not already running. Using this method, the above code becomes:
48+
49+
.. code :: cpp
50+
51+
void setClock() {
52+
NTP.begin("pool.ntp.org", "time.nist.gov");
53+
NTP.waitSet();
54+
struct tm timeinfo;
55+
gmtime_r(&now, &timeinfo);
56+
Serial.print("Current time: ");
57+
Serial.print(asctime(&timeinfo));
58+
}

libraries/WiFi/keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ noLowPowerMode KEYWORD2
5959
ping KEYWORD2
6060
beginMulticast KEYWORD2
6161
setTimeout KEYWORD2
62+
waitSet KEYWORD2
6263

6364

6465
#######################################

libraries/WiFi/src/WiFiClientSecure.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2020
2121
*/
22+
#include "WiFi.h"
2223
#include "WiFiClient.h"
2324
#include "WiFiClientSecureBearSSL.h"
2425

libraries/WiFi/src/WiFiClientSecureBearSSL.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,11 @@
2323
#include <list>
2424
#include <errno.h>
2525
#include <algorithm>
26-
//#include <Esp.h>
2726

28-
29-
30-
//#include "debug.h"
3127
#include "WiFi.h"
32-
//#include "PolledTimeout.h"
3328
#include "WiFiClient.h"
3429
#include "WiFiClientSecureBearSSL.h"
30+
#include "WiFiNTP.h"
3531
#include "StackThunk.h"
3632
#include "lwip/opt.h"
3733
#include "lwip/ip.h"
@@ -95,6 +91,10 @@ void WiFiClientSecureCtx::_clear() {
9591
_cipher_cnt = 0;
9692
_tls_min = BR_TLS10;
9793
_tls_max = BR_TLS12;
94+
if (_esp32_ta) {
95+
delete _esp32_ta;
96+
_esp32_ta = nullptr;
97+
}
9898
}
9999

100100
void WiFiClientSecureCtx::_clearAuthenticationSettings() {
@@ -103,6 +103,10 @@ void WiFiClientSecureCtx::_clearAuthenticationSettings() {
103103
_use_self_signed = false;
104104
_knownkey = nullptr;
105105
_ta = nullptr;
106+
if (_esp32_ta) {
107+
delete _esp32_ta;
108+
_esp32_ta = nullptr;
109+
}
106110
}
107111

108112

@@ -166,12 +170,28 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext *client,
166170
}
167171

168172
void WiFiClientSecureCtx::setClientRSACert(const X509List *chain, const PrivateKey *sk) {
173+
if (_esp32_chain) {
174+
delete _esp32_chain;
175+
_esp32_chain = nullptr;
176+
}
177+
if (_esp32_sk) {
178+
delete _esp32_sk;
179+
_esp32_sk = nullptr;
180+
}
169181
_chain = chain;
170182
_sk = sk;
171183
}
172184

173185
void WiFiClientSecureCtx::setClientECCert(const X509List *chain,
174186
const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) {
187+
if (_esp32_chain) {
188+
delete _esp32_chain;
189+
_esp32_chain = nullptr;
190+
}
191+
if (_esp32_sk) {
192+
delete _esp32_sk;
193+
_esp32_sk = nullptr;
194+
}
175195
_chain = chain;
176196
_sk = sk;
177197
_allowed_usages = allowed_usages;
@@ -1071,7 +1091,11 @@ bool WiFiClientSecureCtx::_installClientX509Validator() {
10711091
DEBUG_BSSL("_installClientX509Validator: OOM for _x509_minimal\n");
10721092
return false;
10731093
}
1074-
br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _ta ? _ta->getTrustAnchors() : nullptr, _ta ? _ta->getCount() : 0);
1094+
if (_esp32_ta) {
1095+
br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _esp32_ta->getTrustAnchors(), _esp32_ta->getCount());
1096+
} else {
1097+
br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _ta ? _ta->getTrustAnchors() : nullptr, _ta ? _ta->getCount() : 0);
1098+
}
10751099
br_x509_minimal_set_rsa(_x509_minimal.get(), br_ssl_engine_get_rsavrfy(_eng));
10761100
#ifndef BEARSSL_SSL_BASIC
10771101
br_x509_minimal_set_ecdsa(_x509_minimal.get(), br_ssl_engine_get_ec(_eng), br_ssl_engine_get_ecdsa(_eng));
@@ -1107,6 +1131,14 @@ bool WiFiClientSecureCtx::_connectSSL(const char* hostName) {
11071131
_freeSSL();
11081132
_oom_err = false;
11091133

1134+
// The ESP32 doesn't check cert time, but we do. So enable NTP silently
1135+
if (_esp32_ta || _esp32_chain || _esp32_sk) {
1136+
if (!NTP.running()) {
1137+
NTP.begin("pool.ntp.org");
1138+
NTP.waitSet();
1139+
}
1140+
}
1141+
11101142
#ifdef DEBUG_ESP_SSL
11111143
// BearSSL will reject all connections unless an authentication option is set, warn in DEBUG builds
11121144
if (!_use_insecure && !_use_fingerprint && !_use_self_signed && !_knownkey && !_certStore && !_ta) {
@@ -1160,6 +1192,9 @@ bool WiFiClientSecureCtx::_connectSSL(const char* hostName) {
11601192
DEBUG_BSSL("_connectSSL: Attempting to use EC cert in minimal cipher mode (no EC)\n");
11611193
return false;
11621194
#endif
1195+
} else if (_esp32_sk && _esp32_chain) {
1196+
br_ssl_client_set_single_rsa(_sc.get(), _esp32_chain->getX509Certs(), _esp32_chain->getCount(),
1197+
_esp32_sk->getRSA(), br_rsa_pkcs1_sign_get_default());
11631198
}
11641199

11651200
// Restore session from the storage spot, if present

libraries/WiFi/src/WiFiClientSecureBearSSL.h

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,101 @@ class WiFiClientSecureCtx : public WiFiClient {
159159
// consume bytes after use (see peekBuffer)
160160
virtual void peekConsume(size_t consume) override;
161161
#endif
162+
163+
// ESP32 compatibility
164+
void setCACert(const char *rootCA) {
165+
if (_esp32_ta) {
166+
delete _esp32_ta;
167+
}
168+
_esp32_ta = new X509List(rootCA);
169+
}
170+
void setCertificate(const char *client_ca) {
171+
if (_esp32_chain) {
172+
delete _esp32_chain;
173+
}
174+
_esp32_chain = new X509List(client_ca);
175+
}
176+
void setPrivateKey(const char *private_key) {
177+
if (_esp32_sk) {
178+
delete _esp32_sk;
179+
}
180+
_esp32_sk = new PrivateKey(private_key);
181+
}
182+
bool loadCACert(Stream& stream, size_t size) {
183+
bool ret = false;
184+
auto buff = new char[size];
185+
if (size == stream.readBytes(buff, size)) {
186+
setCACert(buff);
187+
ret = true;
188+
}
189+
delete[] buff;
190+
return ret;
191+
}
192+
bool loadCertificate(Stream& stream, size_t size) {
193+
bool ret = false;
194+
auto buff = new char[size];
195+
if (size == stream.readBytes(buff, size)) {
196+
setCertificate(buff);
197+
ret = true;
198+
}
199+
delete[] buff;
200+
return ret;
201+
}
202+
bool loadPrivateKey(Stream& stream, size_t size) {
203+
bool ret = false;
204+
auto buff = new char[size];
205+
if (size == stream.readBytes(buff, size)) {
206+
setPrivateKey(buff);
207+
ret = true;
208+
}
209+
delete[] buff;
210+
return ret;
211+
}
212+
int connect(IPAddress ip, uint16_t port, int32_t timeout) {
213+
auto save = _timeout;
214+
_timeout = timeout * 1000; // timeout is in secs, _timeout in milliseconds
215+
auto ret = connect(ip, port);
216+
_timeout = save;
217+
return ret;
218+
}
219+
int connect(const char *host, uint16_t port, int32_t timeout) {
220+
auto save = _timeout;
221+
_timeout = timeout * 1000; // timeout is in secs, _timeout in milliseconds
222+
auto ret = connect(host, port);
223+
_timeout = save;
224+
return ret;
225+
}
226+
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) {
227+
if (_esp32_ta) {
228+
delete _esp32_ta;
229+
_esp32_ta = nullptr;
230+
}
231+
if (_esp32_chain) {
232+
delete _esp32_chain;
233+
_esp32_chain = nullptr;
234+
}
235+
if (_esp32_sk) {
236+
delete _esp32_sk;
237+
_esp32_sk = nullptr;
238+
}
239+
if (rootCABuff) {
240+
setCertificate(rootCABuff);
241+
}
242+
if (cli_cert && cli_key) {
243+
setCertificate(cli_cert);
244+
setPrivateKey(cli_key);
245+
}
246+
return connect(ip, port);
247+
}
248+
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) {
249+
IPAddress ip;
250+
if (WiFi.hostByName(host, ip, _timeout)) {
251+
return connect(ip, port, rootCABuff, cli_cert, cli_key);
252+
} else {
253+
return 0;
254+
}
255+
}
256+
162257
protected:
163258
bool _connectSSL(const char *hostName); // Do initial SSL handshake
164259

@@ -241,6 +336,11 @@ class WiFiClientSecureCtx : public WiFiClient {
241336
bool _installServerX509Validator(const X509List *client_CA_ta); // Setup X509 client cert validation, if supplied
242337

243338
uint8_t *_streamLoad(Stream& stream, size_t size);
339+
340+
// ESP32 compatibility
341+
X509List *_esp32_ta = nullptr;
342+
X509List *_esp32_chain = nullptr;
343+
PrivateKey *_esp32_sk = nullptr;
244344
}; // class WiFiClientSecureCtx
245345

246346

@@ -443,6 +543,40 @@ class WiFiClientSecure : public WiFiClient {
443543
return _ctx->peekConsume(consume);
444544
}
445545
#endif
546+
547+
// ESP32 compatibility
548+
void setCACert(const char *rootCA) {
549+
return _ctx->setCACert(rootCA);
550+
}
551+
void setCertificate(const char *client_ca) {
552+
return _ctx->setCertificate(client_ca);
553+
}
554+
void setPrivateKey(const char *private_key) {
555+
return _ctx->setPrivateKey(private_key);
556+
}
557+
bool loadCACert(Stream& stream, size_t size) {
558+
return _ctx->loadCACert(stream, size);
559+
}
560+
bool loadCertificate(Stream& stream, size_t size) {
561+
return _ctx->loadCertificate(stream, size);
562+
}
563+
bool loadPrivateKey(Stream& stream, size_t size) {
564+
return _ctx->loadPrivateKey(stream, size);
565+
}
566+
567+
int connect(IPAddress ip, uint16_t port, int32_t timeout) {
568+
return _ctx->connect(ip, port, timeout);
569+
}
570+
int connect(const char *host, uint16_t port, int32_t timeout) {
571+
return _ctx->connect(host, port, timeout);
572+
}
573+
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) {
574+
return _ctx->connect(ip, port, rootCABuff, cli_cert, cli_key);
575+
}
576+
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) {
577+
return _ctx->connect(host, port, rootCABuff, cli_cert, cli_key);
578+
}
579+
446580
private:
447581
std::shared_ptr<WiFiClientSecureCtx> _ctx;
448582

libraries/WiFi/src/WiFiNTP.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#pragma once
2121

2222
#include <Arduino.h>
23+
#include <time.h>
2324
#include <lwip/apps/sntp.h>
2425

2526
class NTPClass {
@@ -37,6 +38,7 @@ class NTPClass {
3738
sntp_setserver(0, server);
3839
sntp_setoperatingmode(SNTP_OPMODE_POLL);
3940
sntp_init();
41+
_running = true;
4042
}
4143
}
4244

@@ -51,15 +53,17 @@ class NTPClass {
5153
}
5254
sntp_setoperatingmode(SNTP_OPMODE_POLL);
5355
sntp_init();
56+
_running = true;
5457
}
5558

56-
5759
void begin(const char *server, int timeout = 3600) {
5860
IPAddress addr;
5961
if (WiFi.hostByName(server, addr)) {
6062
begin(addr, timeout);
6163
}
64+
_running = true;
6265
}
66+
6367
void begin(const char *s1, const char *s2, int timeout = 3600) {
6468
IPAddress a1, a2;
6569
if (WiFi.hostByName(s1, a1)) {
@@ -69,7 +73,26 @@ class NTPClass {
6973
begin(a1, timeout);
7074
}
7175
}
76+
_running = true;
7277
}
78+
79+
bool waitSet(uint32_t timeout = 10000) {
80+
if (!running()) {
81+
begin("pool.ntp.org");
82+
}
83+
uint32_t start = millis();
84+
while ((time(nullptr) < 10000000) && (millis() - start < timeout)) {
85+
delay(10);
86+
}
87+
return time(nullptr) < 10000000;
88+
}
89+
90+
bool running() {
91+
return _running;
92+
}
93+
94+
private:
95+
bool _running = false;
7396
};
7497

7598
// ESP8266 compat

0 commit comments

Comments
 (0)
0