Skip to content

Commit a98465f

Browse files
Add ESP8266WebServerSecure, a simple HTTPS server
Add support for simple, easy-to-use WebServer using the SecureServer. For the end user, operates the same as the existing class with the addition of a key/certificate setting stage (and using port 443, of course). Sample code included. Due to some ugly C++ object slicing issues, ended up duplicating a few functions that used the assignment operator to new local WiFiClients. Only the client communications bits needed this treatment and the actual unique secure server class is quite small and simple. Also found and fixed a memory leak in WiFiClientSecure in this use case: Unreference (and potentially delete) and clear the WiFiClientSecure's SSLContext on a ::stop(). The destructor for WiFiClientSecure sometimes isn't called when the WiFiClientSecure is cast to a WiFiClient (object slicing). This causes SSLContext* _ssl not to be freed, rapidly filling up memory and dying after 4-5 connections To avoid this, do the dereference and clear in the ::stop() which is safe since no more operations on the WiFiClientSecure can occur after the connection is ::stopped().
1 parent 2df885a commit a98465f

File tree

9 files changed

+407
-13
lines changed

9 files changed

+407
-13
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#include <ESP8266WiFi.h>
2+
#include <WiFiClient.h>
3+
#include <ESP8266WebServerSecure.h>
4+
#include <ESP8266mDNS.h>
5+
6+
const char* ssid = "........";
7+
const char* password = "........";
8+
9+
ESP8266WebServerSecure server(443);
10+
11+
// The certificate is stored in PMEM
12+
static const uint8_t x509[] ICACHE_RODATA_ATTR = {
13+
0x30, 0x82, 0x01, 0xc9, 0x30, 0x82, 0x01, 0x32, 0x02, 0x09, 0x00, 0xe6,
14+
0x60, 0x8d, 0xa3, 0x47, 0x8f, 0x57, 0x7a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
15+
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x29,
16+
0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x70,
17+
0x73, 0x79, 0x63, 0x68, 0x6f, 0x70, 0x6c, 0x75, 0x67, 0x31, 0x12, 0x30,
18+
0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x31, 0x32, 0x37, 0x2e,
19+
0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30,
20+
0x32, 0x32, 0x34, 0x30, 0x38, 0x30, 0x35, 0x33, 0x36, 0x5a, 0x17, 0x0d,
21+
0x33, 0x30, 0x31, 0x31, 0x30, 0x33, 0x30, 0x38, 0x30, 0x35, 0x33, 0x36,
22+
0x5a, 0x30, 0x29, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a,
23+
0x0c, 0x0a, 0x70, 0x73, 0x79, 0x63, 0x68, 0x6f, 0x70, 0x6c, 0x75, 0x67,
24+
0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x31,
25+
0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9f, 0x30,
26+
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
27+
0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
28+
0x00, 0xb6, 0x59, 0xd0, 0x57, 0xbc, 0x3e, 0xb9, 0xa0, 0x6c, 0xf5, 0xd5,
29+
0x46, 0x49, 0xaa, 0x9a, 0xb3, 0xbf, 0x09, 0xa9, 0xbb, 0x82, 0x3b, 0xdf,
30+
0xb7, 0xe3, 0x5a, 0x8e, 0x31, 0xf7, 0x27, 0xdf, 0xaa, 0xed, 0xa3, 0xd6,
31+
0xf6, 0x74, 0x35, 0xfc, 0x8d, 0x0b, 0xbc, 0xa2, 0x96, 0x10, 0x57, 0xe8,
32+
0xb2, 0xaa, 0x94, 0xf2, 0x47, 0x12, 0x4e, 0x3f, 0x7c, 0x5e, 0x90, 0xfe,
33+
0xad, 0x75, 0x88, 0xca, 0x7b, 0x9a, 0x18, 0x15, 0xbe, 0x3d, 0xe0, 0x31,
34+
0xb5, 0x45, 0x7f, 0xe7, 0x9d, 0x22, 0x99, 0x65, 0xba, 0x63, 0x70, 0x81,
35+
0x3b, 0x37, 0x22, 0x97, 0x64, 0xc5, 0x57, 0x8c, 0x98, 0x9c, 0x10, 0x36,
36+
0x98, 0xf0, 0x0b, 0x19, 0x28, 0x16, 0x9a, 0x40, 0x31, 0x5f, 0xbc, 0xd9,
37+
0x8e, 0x73, 0x68, 0xe1, 0x6a, 0x5d, 0x91, 0x0b, 0x4f, 0x73, 0xa4, 0x6b,
38+
0x8f, 0xa5, 0xad, 0x12, 0x09, 0x32, 0xa7, 0x66, 0x3b, 0x02, 0x03, 0x01,
39+
0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
40+
0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x1b, 0x46, 0x78,
41+
0xd1, 0xfa, 0x21, 0xc1, 0xd6, 0x75, 0xc0, 0x83, 0x59, 0x57, 0x05, 0xd5,
42+
0xae, 0xf8, 0x8c, 0x78, 0x03, 0x65, 0x3b, 0xbf, 0xef, 0x70, 0x3f, 0x78,
43+
0xc6, 0xe1, 0x5a, 0xac, 0xb1, 0x93, 0x5b, 0x41, 0x35, 0x45, 0x47, 0xf8,
44+
0x07, 0x86, 0x40, 0x34, 0xa2, 0x9e, 0x2a, 0x16, 0x8d, 0xea, 0xf9, 0x1e,
45+
0x1f, 0xd7, 0x70, 0xb4, 0x28, 0x6b, 0xd8, 0xf5, 0x3f, 0x33, 0x3f, 0xc2,
46+
0x2c, 0x69, 0xf2, 0xa3, 0x54, 0x4d, 0xbf, 0x7d, 0xf9, 0xde, 0x05, 0x0c,
47+
0x9c, 0xe3, 0x1b, 0x72, 0x07, 0x7b, 0x41, 0x76, 0x1a, 0x57, 0x03, 0x5d,
48+
0xb2, 0xff, 0x4c, 0x17, 0xbd, 0xd7, 0x73, 0x32, 0x98, 0x26, 0x6b, 0x2c,
49+
0xc4, 0xbf, 0x6e, 0x01, 0x36, 0x8b, 0xbf, 0x00, 0x48, 0x9c, 0xfb, 0x3d,
50+
0x7d, 0x76, 0x1f, 0x55, 0x96, 0x43, 0xc5, 0x4e, 0xc1, 0xa3, 0xa1, 0x6a,
51+
0x94, 0x5f, 0x84, 0x3a, 0xdd
52+
};
53+
54+
// And so is the key. These could also be in DRAM
55+
static const uint8_t rsakey[] ICACHE_RODATA_ATTR = {
56+
0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xb6,
57+
0x59, 0xd0, 0x57, 0xbc, 0x3e, 0xb9, 0xa0, 0x6c, 0xf5, 0xd5, 0x46, 0x49,
58+
0xaa, 0x9a, 0xb3, 0xbf, 0x09, 0xa9, 0xbb, 0x82, 0x3b, 0xdf, 0xb7, 0xe3,
59+
0x5a, 0x8e, 0x31, 0xf7, 0x27, 0xdf, 0xaa, 0xed, 0xa3, 0xd6, 0xf6, 0x74,
60+
0x35, 0xfc, 0x8d, 0x0b, 0xbc, 0xa2, 0x96, 0x10, 0x57, 0xe8, 0xb2, 0xaa,
61+
0x94, 0xf2, 0x47, 0x12, 0x4e, 0x3f, 0x7c, 0x5e, 0x90, 0xfe, 0xad, 0x75,
62+
0x88, 0xca, 0x7b, 0x9a, 0x18, 0x15, 0xbe, 0x3d, 0xe0, 0x31, 0xb5, 0x45,
63+
0x7f, 0xe7, 0x9d, 0x22, 0x99, 0x65, 0xba, 0x63, 0x70, 0x81, 0x3b, 0x37,
64+
0x22, 0x97, 0x64, 0xc5, 0x57, 0x8c, 0x98, 0x9c, 0x10, 0x36, 0x98, 0xf0,
65+
0x0b, 0x19, 0x28, 0x16, 0x9a, 0x40, 0x31, 0x5f, 0xbc, 0xd9, 0x8e, 0x73,
66+
0x68, 0xe1, 0x6a, 0x5d, 0x91, 0x0b, 0x4f, 0x73, 0xa4, 0x6b, 0x8f, 0xa5,
67+
0xad, 0x12, 0x09, 0x32, 0xa7, 0x66, 0x3b, 0x02, 0x03, 0x01, 0x00, 0x01,
68+
0x02, 0x81, 0x81, 0x00, 0xa8, 0x55, 0xf9, 0x33, 0x45, 0x20, 0x52, 0x94,
69+
0x7a, 0x81, 0xe6, 0xc4, 0xe0, 0x34, 0x92, 0x63, 0xe4, 0xb3, 0xb2, 0xf0,
70+
0xda, 0xa5, 0x13, 0x3d, 0xda, 0xb0, 0x3a, 0x1c, 0x7e, 0x21, 0x5d, 0x25,
71+
0x9a, 0x03, 0x69, 0xea, 0x52, 0x15, 0x94, 0x73, 0x50, 0xa6, 0x6f, 0x21,
72+
0x41, 0x2d, 0x26, 0x2f, 0xe9, 0xb1, 0x5e, 0x87, 0xa5, 0xaa, 0x7e, 0x88,
73+
0xfd, 0x73, 0xb4, 0xe7, 0xc4, 0x5c, 0xe7, 0x2d, 0xeb, 0x9e, 0x6b, 0xe1,
74+
0xf1, 0x38, 0x45, 0xf4, 0x10, 0x12, 0xac, 0x79, 0x40, 0x72, 0xf0, 0x45,
75+
0x89, 0x5c, 0x9d, 0x8b, 0x7b, 0x5d, 0x69, 0xd9, 0x11, 0xf9, 0x25, 0xff,
76+
0xe1, 0x2a, 0xb3, 0x6d, 0x49, 0x18, 0x8d, 0x38, 0x0a, 0x6f, 0x0f, 0xbd,
77+
0x48, 0xd0, 0xdd, 0xcb, 0x41, 0x5c, 0x2a, 0x75, 0xa0, 0x51, 0x43, 0x4a,
78+
0x0b, 0xf6, 0xa2, 0xd2, 0xe9, 0xda, 0x37, 0xca, 0x2d, 0xd7, 0x22, 0x01,
79+
0x02, 0x41, 0x00, 0xe7, 0x11, 0xea, 0x93, 0xf4, 0x0b, 0xe6, 0xa0, 0x1a,
80+
0x57, 0x2d, 0xee, 0x96, 0x05, 0x5c, 0xa1, 0x08, 0x8f, 0x9c, 0xac, 0x9a,
81+
0x72, 0x60, 0x5a, 0x41, 0x2a, 0x92, 0x38, 0x36, 0xa5, 0xfe, 0xb9, 0x35,
82+
0xb2, 0x06, 0xbb, 0x02, 0x58, 0xc8, 0x93, 0xd6, 0x09, 0x6f, 0x57, 0xd7,
83+
0xc1, 0x2e, 0x90, 0xb3, 0x09, 0xdd, 0x0c, 0x63, 0x99, 0x91, 0xb7, 0xe4,
84+
0xcc, 0x6f, 0x78, 0x24, 0xbc, 0x3b, 0x7b, 0x02, 0x41, 0x00, 0xca, 0x06,
85+
0x4a, 0x09, 0x36, 0x08, 0xaa, 0x27, 0x08, 0x91, 0x86, 0xc5, 0x17, 0x14,
86+
0x6e, 0x24, 0x9a, 0x86, 0xd1, 0xbc, 0x41, 0xb1, 0x42, 0x5e, 0xe8, 0x80,
87+
0x5a, 0x8f, 0x7c, 0x9b, 0xe8, 0xcc, 0x28, 0xe1, 0xa2, 0x8f, 0xe9, 0xdc,
88+
0x60, 0xd5, 0x00, 0x34, 0x76, 0x32, 0x36, 0x00, 0x93, 0x69, 0x6b, 0xab,
89+
0xc6, 0x8b, 0x70, 0x95, 0x4e, 0xc2, 0x27, 0x4a, 0x24, 0x73, 0xbf, 0xcd,
90+
0x24, 0x41, 0x02, 0x40, 0x40, 0x46, 0x75, 0x90, 0x0e, 0x54, 0xb9, 0x24,
91+
0x53, 0xef, 0x68, 0x31, 0x73, 0xbd, 0xae, 0x14, 0x85, 0x43, 0x1d, 0x7b,
92+
0xcd, 0xc2, 0x7f, 0x16, 0xdc, 0x05, 0xb1, 0x82, 0xbd, 0x80, 0xd3, 0x28,
93+
0x45, 0xcd, 0x6d, 0x9d, 0xdb, 0x7b, 0x42, 0xe0, 0x0c, 0xab, 0xb7, 0x33,
94+
0x22, 0x2a, 0xf4, 0x7e, 0xff, 0xae, 0x80, 0xb4, 0x8f, 0x88, 0x0a, 0x46,
95+
0xb2, 0xf8, 0x43, 0x11, 0x92, 0x76, 0x61, 0xbd, 0x02, 0x40, 0x5c, 0x86,
96+
0x3a, 0xdc, 0x33, 0x1a, 0x0e, 0xcb, 0xa7, 0xb9, 0xf6, 0xae, 0x47, 0x5e,
97+
0xbc, 0xff, 0x18, 0xa2, 0x8c, 0x66, 0x1a, 0xf4, 0x13, 0x00, 0xa2, 0x9d,
98+
0x3e, 0x5c, 0x9e, 0xe6, 0x4c, 0xdd, 0x4c, 0x0f, 0xe2, 0xc2, 0xe4, 0x89,
99+
0x60, 0xf3, 0xcc, 0x8f, 0x3a, 0x5e, 0xce, 0xaa, 0xbe, 0xd8, 0xb6, 0x4e,
100+
0x4a, 0xb5, 0x4c, 0x0f, 0xa5, 0xad, 0x78, 0x0f, 0x15, 0xd8, 0xc9, 0x4c,
101+
0x2b, 0xc1, 0x02, 0x40, 0x4e, 0xe9, 0x78, 0x48, 0x94, 0x11, 0x75, 0xc1,
102+
0xa2, 0xc7, 0xff, 0xf0, 0x73, 0xa2, 0x93, 0xd7, 0x67, 0xc7, 0xf8, 0x96,
103+
0xac, 0x15, 0xaa, 0xe5, 0x5d, 0x18, 0x18, 0x29, 0xa9, 0x9a, 0xfc, 0xac,
104+
0x48, 0x4d, 0xa0, 0xca, 0xa2, 0x34, 0x09, 0x7c, 0x13, 0x22, 0x4c, 0xfc,
105+
0x31, 0x75, 0xa0, 0x21, 0x1e, 0x7a, 0x91, 0xbc, 0xb1, 0x97, 0xde, 0x43,
106+
0xe1, 0x40, 0x2b, 0xe3, 0xbd, 0x98, 0x44, 0xad
107+
};
108+
109+
const int led = 13;
110+
111+
void handleRoot() {
112+
digitalWrite(led, 1);
113+
server.send(200, "text/plain", "Hello from esp8266 over HTTPS!");
114+
digitalWrite(led, 0);
115+
}
116+
117+
void handleNotFound(){
118+
digitalWrite(led, 1);
119+
String message = "File Not Found\n\n";
120+
message += "URI: ";
121+
message += server.uri();
122+
message += "\nMethod: ";
123+
message += (server.method() == HTTP_GET)?"GET":"POST";
124+
message += "\nArguments: ";
125+
message += server.args();
126+
message += "\n";
127+
for (uint8_t i=0; i<server.args(); i++){
128+
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
129+
}
130+
server.send(404, "text/plain", message);
131+
digitalWrite(led, 0);
132+
}
133+
134+
void setup(void){
135+
pinMode(led, OUTPUT);
136+
digitalWrite(led, 0);
137+
Serial.begin(115200);
138+
WiFi.begin(ssid, password);
139+
Serial.println("");
140+
141+
// Wait for connection
142+
while (WiFi.status() != WL_CONNECTED) {
143+
delay(500);
144+
Serial.print(".");
145+
}
146+
Serial.println("");
147+
Serial.print("Connected to ");
148+
Serial.println(ssid);
149+
Serial.print("IP address: ");
150+
Serial.println(WiFi.localIP());
151+
152+
if (MDNS.begin("esp8266")) {
153+
Serial.println("MDNS responder started");
154+
}
155+
156+
server.setServerKeyAndCert_P(rsakey, sizeof(rsakey), x509, sizeof(x509));
157+
158+
server.on("/", handleRoot);
159+
160+
server.on("/inline", [](){
161+
server.send(200, "text/plain", "this works as well");
162+
});
163+
164+
server.onNotFound(handleNotFound);
165+
166+
server.begin();
167+
Serial.println("HTTPS server started");
168+
}
169+
170+
void loop(void){
171+
server.handleClient();
172+
}

libraries/ESP8266WebServer/keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#######################################
88

99
ESP8266WebServer KEYWORD1
10+
ESP8266WebServerSecure KEYWORD1
1011
HTTPMethod KEYWORD1
1112

1213
#######################################

libraries/ESP8266WebServer/src/ESP8266WebServer.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ void ESP8266WebServer::send(int code, const char* content_type, const String& co
287287
//if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
288288
// _contentLength = CONTENT_LENGTH_UNKNOWN;
289289
_prepareHeader(header, code, content_type, content.length());
290-
_currentClient.write(header.c_str(), header.length());
290+
_currentClientWrite(header.c_str(), header.length());
291291
if(content.length())
292292
sendContent(content);
293293
}
@@ -303,7 +303,7 @@ void ESP8266WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
303303
char type[64];
304304
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
305305
_prepareHeader(header, code, (const char* )type, contentLength);
306-
_currentClient.write(header.c_str(), header.length());
306+
_currentClientWrite(header.c_str(), header.length());
307307
sendContent_P(content);
308308
}
309309

@@ -331,13 +331,13 @@ void ESP8266WebServer::sendContent(const String& content) {
331331
char * chunkSize = (char *)malloc(11);
332332
if(chunkSize){
333333
sprintf(chunkSize, "%x%s", len, footer);
334-
_currentClient.write(chunkSize, strlen(chunkSize));
334+
_currentClientWrite(chunkSize, strlen(chunkSize));
335335
free(chunkSize);
336336
}
337337
}
338-
_currentClient.write(content.c_str(), len);
338+
_currentClientWrite(content.c_str(), len);
339339
if(_chunked){
340-
_currentClient.write(footer, 2);
340+
_currentClientWrite(footer, 2);
341341
}
342342
}
343343

@@ -351,13 +351,13 @@ void ESP8266WebServer::sendContent_P(PGM_P content, size_t size) {
351351
char * chunkSize = (char *)malloc(11);
352352
if(chunkSize){
353353
sprintf(chunkSize, "%x%s", size, footer);
354-
_currentClient.write(chunkSize, strlen(chunkSize));
354+
_currentClientWrite(chunkSize, strlen(chunkSize));
355355
free(chunkSize);
356356
}
357357
}
358-
_currentClient.write_P(content, size);
358+
_currentClientWrite_P(content, size);
359359
if(_chunked){
360-
_currentClient.write(footer, 2);
360+
_currentClientWrite(footer, 2);
361361
}
362362
}
363363

libraries/ESP8266WebServer/src/ESP8266WebServer.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
4747
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
4848

4949
class ESP8266WebServer;
50+
class ESP8266WebServerSecure;
5051

5152
typedef struct {
5253
HTTPUploadStatus status;
@@ -66,15 +67,17 @@ class FS;
6667

6768
class ESP8266WebServer
6869
{
70+
friend class ESP8266WebServerSecure; // HTTPS server needs access to privates
71+
6972
public:
7073
ESP8266WebServer(IPAddress addr, int port = 80);
7174
ESP8266WebServer(int port = 80);
7275
~ESP8266WebServer();
7376

74-
void begin();
75-
void handleClient();
77+
virtual void begin();
78+
virtual void handleClient();
7679

77-
void close();
80+
virtual void close();
7881
void stop();
7982

8083
bool authenticate(const char * username, const char * password);
@@ -91,7 +94,7 @@ class ESP8266WebServer
9194

9295
String uri() { return _currentUri; }
9396
HTTPMethod method() { return _currentMethod; }
94-
WiFiClient client() { return _currentClient; }
97+
virtual WiFiClient client() { return _currentClient; }
9598
HTTPUpload& upload() { return _currentUpload; }
9699

97100
String arg(String name); // get request argument value by name
@@ -137,6 +140,10 @@ template<typename T> size_t streamFile(T &file, const String& contentType){
137140
return _currentClient.write(file);
138141
}
139142

143+
private:
144+
virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient.write( b, l ); }
145+
virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return _currentClient.write( b, l ); }
146+
140147
protected:
141148
void _addRequestHandler(RequestHandler* handler);
142149
void _handleRequest();

0 commit comments

Comments
 (0)