Skip to content

Commit 0ebf6e6

Browse files
Merge branch 'master' of https://github.com/esp8266/Arduino into thunks
2 parents 37be1db + 6314093 commit 0ebf6e6

File tree

4 files changed

+193
-8
lines changed

4 files changed

+193
-8
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Example of using SSL sessions to speed up SSL connection initiation
2+
//
3+
// September 2018 by Earle F. Philhower, III
4+
// Released to the public domain
5+
6+
#include <ESP8266WiFi.h>
7+
#include <time.h>
8+
9+
const char *ssid = "....";
10+
const char *pass = "....";
11+
12+
const char * host = "api.github.com";
13+
const uint16_t port = 443;
14+
const char * path = "/";
15+
16+
void setup() {
17+
Serial.begin(115200);
18+
Serial.println();
19+
Serial.println();
20+
21+
Serial.printf("Connecting to %s\n", ssid);
22+
WiFi.mode(WIFI_STA);
23+
WiFi.begin(ssid, pass);
24+
25+
while (WiFi.status() != WL_CONNECTED) {
26+
delay(500);
27+
Serial.print(".");
28+
}
29+
Serial.println("\nConnected");
30+
Serial.println("IP Address: ");
31+
Serial.println(WiFi.localIP());
32+
33+
// Set up time to allow for certificate validation
34+
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
35+
36+
Serial.print("Waiting for NTP time sync: ");
37+
time_t now = time(nullptr);
38+
while (now < 8 * 3600 * 2) {
39+
delay(500);
40+
Serial.print(".");
41+
now = time(nullptr);
42+
}
43+
Serial.println("");
44+
struct tm timeinfo;
45+
gmtime_r(&now, &timeinfo);
46+
Serial.print("Current time: ");
47+
Serial.print(asctime(&timeinfo));
48+
}
49+
50+
// Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response
51+
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
52+
if (!path) {
53+
path = "/";
54+
}
55+
56+
Serial.printf("Trying: %s:443...", host);
57+
client->connect(host, port);
58+
if (!client->connected()) {
59+
Serial.printf("*** Can't connect. ***\n-------\n");
60+
return;
61+
}
62+
Serial.printf("Connected!\n-------\n");
63+
client->write("GET ");
64+
client->write(path);
65+
client->write(" HTTP/1.0\r\nHost: ");
66+
client->write(host);
67+
client->write("\r\nUser-Agent: ESP8266\r\n");
68+
client->write("\r\n");
69+
uint32_t to = millis() + 5000;
70+
if (client->connected()) {
71+
do {
72+
char tmp[32];
73+
memset(tmp, 0, 32);
74+
int rlen = client->read((uint8_t*)tmp, sizeof(tmp) - 1);
75+
yield();
76+
if (rlen < 0) {
77+
break;
78+
}
79+
// Only print out first line up to \r, then abort connection
80+
char *nl = strchr(tmp, '\r');
81+
if (nl) {
82+
*nl = 0;
83+
Serial.print(tmp);
84+
break;
85+
}
86+
Serial.print(tmp);
87+
} while (millis() < to);
88+
}
89+
client->stop();
90+
Serial.printf("\n-------\n\n");
91+
}
92+
93+
94+
void loop() {
95+
static const char digicert[] PROGMEM = R"EOF(
96+
-----BEGIN CERTIFICATE-----
97+
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
98+
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
99+
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
100+
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
101+
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
102+
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
103+
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
104+
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
105+
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
106+
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
107+
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
108+
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
109+
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
110+
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
111+
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
112+
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
113+
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
114+
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
115+
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
116+
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
117+
+OkuE6N36B9K
118+
-----END CERTIFICATE-----
119+
)EOF";
120+
uint32_t start, finish;
121+
BearSSL::WiFiClientSecure client;
122+
BearSSLX509List cert(digicert);
123+
124+
Serial.printf("Connecting without sessions...");
125+
start = millis();
126+
client.setTrustAnchors(&cert);
127+
fetchURL(&client, host, port, path);
128+
finish = millis();
129+
Serial.printf("Total time: %dms\n", finish - start);
130+
131+
BearSSLSession session;
132+
client.setSession(&session);
133+
Serial.printf("Connecting with an unitialized session...");
134+
start = millis();
135+
client.setTrustAnchors(&cert);
136+
fetchURL(&client, host, port, path);
137+
finish = millis();
138+
Serial.printf("Total time: %dms\n", finish - start);
139+
140+
Serial.printf("Connecting with the just initialized session...");
141+
start = millis();
142+
client.setTrustAnchors(&cert);
143+
fetchURL(&client, host, port, path);
144+
finish = millis();
145+
Serial.printf("Total time: %dms\n", finish - start);
146+
147+
Serial.printf("Connecting again with the initialized session...");
148+
start = millis();
149+
client.setTrustAnchors(&cert);
150+
fetchURL(&client, host, port, path);
151+
finish = millis();
152+
Serial.printf("Total time: %dms\n", finish - start);
153+
154+
delay(10000); // Avoid DDOSing github
155+
}
156+

libraries/ESP8266WiFi/src/BearSSLHelpers.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,21 @@ class BearSSLX509List {
119119
br_x509_trust_anchor *_ta;
120120
};
121121

122+
// Opaque object which wraps the BearSSL SSL session to make repeated connections
123+
// significantly faster. Completely optional.
124+
namespace BearSSL {
125+
class WiFiClientSecure;
126+
};
127+
128+
class BearSSLSession {
129+
friend class BearSSL::WiFiClientSecure;
130+
131+
public:
132+
BearSSLSession() { memset(&_session, 0, sizeof(_session)); }
133+
private:
134+
br_ssl_session_parameters *getSession() { return &_session; }
135+
// The actual BearSSL ession information
136+
br_ssl_session_parameters _session;
137+
};
138+
122139
#endif

libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ void WiFiClientSecure::_clear() {
8383
_recvapp_len = 0;
8484
_oom_err = false;
8585
_deleteChainKeyTA = false;
86+
_session = nullptr;
87+
_cipher_list = NULL;
88+
_cipher_cnt = 0;
8689
}
8790

8891
void WiFiClientSecure::_clearAuthenticationSettings() {
@@ -96,8 +99,6 @@ void WiFiClientSecure::_clearAuthenticationSettings() {
9699

97100

98101
WiFiClientSecure::WiFiClientSecure() : WiFiClient() {
99-
_cipher_list = NULL;
100-
_cipher_cnt = 0;
101102
_clear();
102103
_clearAuthenticationSettings();
103104
_certStore = nullptr; // Don't want to remove cert store on a clear, should be long lived
@@ -129,8 +130,6 @@ WiFiClientSecure::~WiFiClientSecure() {
129130
WiFiClientSecure::WiFiClientSecure(ClientContext* client,
130131
const BearSSLX509List *chain, const BearSSLPrivateKey *sk,
131132
int iobuf_in_size, int iobuf_out_size, const BearSSLX509List *client_CA_ta) {
132-
_cipher_list = NULL;
133-
_cipher_cnt = 0;
134133
_clear();
135134
_clearAuthenticationSettings();
136135
_iobuf_in_size = iobuf_in_size;
@@ -148,8 +147,6 @@ WiFiClientSecure::WiFiClientSecure(ClientContext *client,
148147
const BearSSLX509List *chain,
149148
unsigned cert_issuer_key_type, const BearSSLPrivateKey *sk,
150149
int iobuf_in_size, int iobuf_out_size, const BearSSLX509List *client_CA_ta) {
151-
_cipher_list = NULL;
152-
_cipher_cnt = 0;
153150
_clear();
154151
_clearAuthenticationSettings();
155152
_iobuf_in_size = iobuf_in_size;
@@ -194,8 +191,11 @@ void WiFiClientSecure::setBufferSizes(int recv, int xmit) {
194191

195192
bool WiFiClientSecure::stop(unsigned int maxWaitMs) {
196193
bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
197-
// Only if we've already connected, clear the connection options
194+
// Only if we've already connected, store session params and clear the connection options
198195
if (_handshake_done) {
196+
if (_session) {
197+
br_ssl_engine_get_session_parameters(_eng, _session->getSession());
198+
}
199199
_clearAuthenticationSettings();
200200
}
201201
_freeSSL();
@@ -882,7 +882,12 @@ bool WiFiClientSecure::_connectSSL(const char* hostName) {
882882
_cert_issuer_key_type, br_ec_get_default(), br_ecdsa_sign_asn1_get_default());
883883
}
884884

885-
if (!br_ssl_client_reset(_sc.get(), hostName, 0)) {
885+
// Restore session from the storage spot, if present
886+
if (_session) {
887+
br_ssl_engine_set_session_parameters(_eng, _session->getSession());
888+
}
889+
890+
if (!br_ssl_client_reset(_sc.get(), hostName, _session?1:0)) {
886891
_freeSSL();
887892
return false;
888893
}

libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ class WiFiClientSecure : public WiFiClient {
5858
bool flush(unsigned int maxWaitMs = 0) override;
5959
bool stop(unsigned int maxWaitMs = 0) override;
6060

61+
// Allow sessions to be saved/restored automatically to a memory area
62+
void setSession(BearSSLSession *session) { _session = session; }
63+
6164
// Don't validate the chain, just accept whatever is given. VERY INSECURE!
6265
void setInsecure() {
6366
_clearAuthenticationSettings();
@@ -170,6 +173,10 @@ class WiFiClientSecure : public WiFiClient {
170173
bool _handshake_done;
171174
bool _oom_err;
172175

176+
// Optional storage space pointer for session parameters
177+
// Will be used on connect and updated on close
178+
BearSSLSession *_session;
179+
173180
bool _use_insecure;
174181
bool _use_fingerprint;
175182
uint8_t _fingerprint[20];

0 commit comments

Comments
 (0)