-
Notifications
You must be signed in to change notification settings - Fork 13.3k
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 BearSSL client and server, support true bidir, lower memory, modern SSL #4273
Changes from all commits
9c519a0
fb44b74
8f6f5df
71b003f
c9c560e
c91995c
c34f564
2c31676
a6f0042
5ec2865
67afc48
d2412d9
65103cf
9987019
d317be2
35ccf94
50e780a
6261b79
bac5c9c
6c94e92
df612f6
fc2aad0
a064caa
569bdda
e8fbc98
16bcc45
af52cb4
3c5a97c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,10 +133,15 @@ class HTTPClient | |
HTTPClient(); | ||
~HTTPClient(); | ||
|
||
// Plain HTTP connection, unencrypted | ||
bool begin(String url); | ||
bool begin(String url, String httpsFingerprint); | ||
bool begin(String host, uint16_t port, String uri = "/"); | ||
// Use axTLS for secure HTTPS connection | ||
bool begin(String url, String httpsFingerprint); | ||
bool begin(String host, uint16_t port, String uri, String httpsFingerprint); | ||
// Use BearSSL for secure HTTPS connection | ||
bool begin(String url, const uint8_t httpsFingerprint[20]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why can't we pass the fingerprint as |
||
bool begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]); | ||
// deprecated, use the overload above instead | ||
bool begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) __attribute__ ((deprecated)); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
SecureBearSSLUpdater - SSL encrypted, password-protected firmware update | ||
|
||
This example starts a HTTPS server on the ESP8266 to allow firmware updates | ||
to be performed. All communication, including the username and password, | ||
is encrypted via SSL. Be sure to update the SSID and PASSWORD before running | ||
to allow connection to your WiFi network. | ||
|
||
To upload through terminal you can use: | ||
curl -u admin:admin -F "image=@firmware.bin" esp8266-webupdate.local/firmware | ||
|
||
Adapted by Earle F. Philhower, III, from the SecureWebUpdater.ino example. | ||
This example is released into the public domain. | ||
*/ | ||
|
||
#include <ESP8266WiFi.h> | ||
#include <WiFiClient.h> | ||
#include <ESP8266WebServerSecure.h> | ||
#include <ESP8266mDNS.h> | ||
#include <ESP8266HTTPUpdateServer.h> | ||
|
||
const char* host = "esp8266-webupdate"; | ||
const char* update_path = "/firmware"; | ||
const char* update_username = "admin"; | ||
const char* update_password = "admin"; | ||
const char* ssid = "........"; | ||
const char* password = "........"; | ||
|
||
BearSSL::ESP8266WebServerSecure httpServer(443); | ||
ESP8266HTTPUpdateServer httpUpdater; | ||
|
||
static const char serverCert[] PROGMEM = R"EOF( | ||
-----BEGIN CERTIFICATE----- | ||
MIIDSzCCAjMCCQD2ahcfZAwXxDANBgkqhkiG9w0BAQsFADCBiTELMAkGA1UEBhMC | ||
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU9yYW5nZSBDb3VudHkx | ||
EDAOBgNVBAoMB1ByaXZhZG8xGjAYBgNVBAMMEXNlcnZlci56bGFiZWwuY29tMR8w | ||
HQYJKoZIhvcNAQkBFhBlYXJsZUB6bGFiZWwuY29tMB4XDTE4MDMwNjA1NDg0NFoX | ||
DTE5MDMwNjA1NDg0NFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh | ||
dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZI | ||
hvcNAQEBBQADggEPADCCAQoCggEBAPVKBwbZ+KDSl40YCDkP6y8Sv4iNGvEOZg8Y | ||
X7sGvf/xZH7UiCBWPFIRpNmDSaZ3yjsmFqm6sLiYSGSdrBCFqdt9NTp2r7hga6Sj | ||
oASSZY4B9pf+GblDy5m10KDx90BFKXdPMCLT+o76Nx9PpCvw13A848wHNG3bpBgI | ||
t+w/vJCX3bkRn8yEYAU6GdMbYe7v446hX3kY5UmgeJFr9xz1kq6AzYrMt/UHhNzO | ||
S+QckJaY0OGWvmTNspY3xCbbFtIDkCdBS8CZAw+itnofvnWWKQEXlt6otPh5njwy | ||
+O1t/Q+Z7OMDYQaH02IQx3188/kW3FzOY32knER1uzjmRO+jhA8CAwEAATANBgkq | ||
hkiG9w0BAQsFAAOCAQEAnDrROGRETB0woIcI1+acY1yRq4yAcH2/hdq2MoM+DCyM | ||
E8CJaOznGR9ND0ImWpTZqomHOUkOBpvu7u315blQZcLbL1LfHJGRTCHVhvVrcyEb | ||
fWTnRtAQdlirUm/obwXIitoz64VSbIVzcqqfg9C6ZREB9JbEX98/9Wp2gVY+31oC | ||
JfUvYadSYxh3nblvA4OL+iEZiW8NE3hbW6WPXxvS7Euge0uWMPc4uEcnsE0ZVG3m | ||
+TGimzSdeWDvGBRWZHXczC2zD4aoE5vrl+GD2i++c6yjL/otHfYyUpzUfbI2hMAA | ||
5tAF1D5vAAwA8nfPysumlLsIjohJZo4lgnhB++AlOg== | ||
-----END CERTIFICATE----- | ||
)EOF"; | ||
|
||
static const char serverKey[] PROGMEM = R"EOF( | ||
-----BEGIN RSA PRIVATE KEY----- | ||
MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI | ||
IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z | ||
uUPLmbXQoPH3QEUpd08wItP6jvo3H0+kK/DXcDzjzAc0bdukGAi37D+8kJfduRGf | ||
zIRgBToZ0xth7u/jjqFfeRjlSaB4kWv3HPWSroDNisy39QeE3M5L5ByQlpjQ4Za+ | ||
ZM2yljfEJtsW0gOQJ0FLwJkDD6K2eh++dZYpAReW3qi0+HmePDL47W39D5ns4wNh | ||
BofTYhDHfXzz+RbcXM5jfaScRHW7OOZE76OEDwIDAQABAoIBAQDKov5NFbNFQNR8 | ||
djcM1O7Is6dRaqiwLeH4ZH1pZ3d9QnFwKanPdQ5eCj9yhfhJMrr5xEyCqT0nMn7T | ||
yEIGYDXjontfsf8WxWkH2TjvrfWBrHOIOx4LJEvFzyLsYxiMmtZXvy6YByD+Dw2M | ||
q2GH/24rRdI2klkozIOyazluTXU8yOsSGxHr/aOa9/sZISgLmaGOOuKI/3Zqjdhr | ||
eHeSqoQFt3xXa8jw01YubQUDw/4cv9rk2ytTdAoQUimiKtgtjsggpP1LTq4xcuqN | ||
d4jWhTcnorWpbD2cVLxrEbnSR3VuBCJEZv5axg5ZPxLEnlcId8vMtvTRb5nzzszn | ||
geYUWDPhAoGBAPyKVNqqwQl44oIeiuRM2FYenMt4voVaz3ExJX2JysrG0jtCPv+Y | ||
84R6Cv3nfITz3EZDWp5sW3OwoGr77lF7Tv9tD6BptEmgBeuca3SHIdhG2MR+tLyx | ||
/tkIAarxQcTGsZaSqra3gXOJCMz9h2P5dxpdU+0yeMmOEnAqgQ8qtNBfAoGBAPim | ||
RAtnrd0WSlCgqVGYFCvDh1kD5QTNbZc+1PcBHbVV45EmJ2fLXnlDeplIZJdYxmzu | ||
DMOxZBYgfeLY9exje00eZJNSj/csjJQqiRftrbvYY7m5njX1kM5K8x4HlynQTDkg | ||
rtKO0YZJxxmjRTbFGMegh1SLlFLRIMtehNhOgipRAoGBAPnEEpJGCS9GGLfaX0HW | ||
YqwiEK8Il12q57mqgsq7ag7NPwWOymHesxHV5mMh/Dw+NyBi4xAGWRh9mtrUmeqK | ||
iyICik773Gxo0RIqnPgd4jJWN3N3YWeynzulOIkJnSNx5BforOCTc3uCD2s2YB5X | ||
jx1LKoNQxLeLRN8cmpIWicf/AoGBANjRSsZTKwV9WWIDJoHyxav/vPb+8WYFp8lZ | ||
zaRxQbGM6nn4NiZI7OF62N3uhWB/1c7IqTK/bVHqFTuJCrCNcsgld3gLZ2QWYaMV | ||
kCPgaj1BjHw4AmB0+EcajfKilcqtSroJ6MfMJ6IclVOizkjbByeTsE4lxDmPCDSt | ||
/9MKanBxAoGAY9xo741Pn9WUxDyRplww606ccdNf/ksHWNc/Y2B5SPwxxSnIq8nO | ||
j01SmsCUYVFAgZVOTiiycakjYLzxlc6p8BxSVqy6LlJqn95N8OXoQ+bkwUux/ekg | ||
gz5JWYhbD6c38khSzJb0pNXCo3EuYAVa36kDM96k1BtWuhRS10Q1VXk= | ||
-----END RSA PRIVATE KEY----- | ||
)EOF"; | ||
|
||
|
||
void setup() | ||
{ | ||
|
||
Serial.begin(115200); | ||
Serial.println(); | ||
Serial.println("Booting Sketch..."); | ||
WiFi.mode(WIFI_AP_STA); | ||
WiFi.begin(ssid, password); | ||
|
||
while(WiFi.waitForConnectResult() != WL_CONNECTED){ | ||
WiFi.begin(ssid, password); | ||
Serial.println("WiFi failed, retrying."); | ||
} | ||
|
||
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov"); | ||
|
||
MDNS.begin(host); | ||
|
||
httpServer.setRSACert(new BearSSLX509List(serverCert), new BearSSLPrivateKey(serverKey)); | ||
httpUpdater.setup(&httpServer, update_path, update_username, update_password); | ||
httpServer.begin(); | ||
|
||
MDNS.addService("https", "tcp", 443); | ||
Serial.printf("BearSSLUpdateServer ready!\nOpen https://%s.local%s in "\ | ||
"your browser and login with username '%s' and password "\ | ||
"'%s'\n", host, update_path, update_username, update_password); | ||
} | ||
|
||
void loop() | ||
{ | ||
httpServer.handleClient(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
/* | ||
HelloServerBearSSL - Simple HTTPS server example | ||
|
||
This example demonstrates a basic ESP8266WebServerSecure HTTPS server | ||
that can serve "/" and "/inline" and generate detailed 404 (not found) | ||
HTTP respoinses. Be sure to update the SSID and PASSWORD before running | ||
to allow connection to your WiFi network. | ||
|
||
Adapted by Earle F. Philhower, III, from the HelloServer.ino example. | ||
This example is released into the public domain. | ||
*/ | ||
#include <ESP8266WiFi.h> | ||
#include <WiFiClient.h> | ||
#include <ESP8266WebServerSecure.h> | ||
#include <ESP8266mDNS.h> | ||
|
||
const char* ssid = "...."; | ||
const char* password = "...."; | ||
|
||
BearSSL::ESP8266WebServerSecure server(443); | ||
|
||
static const char serverCert[] PROGMEM = R"EOF( | ||
-----BEGIN CERTIFICATE----- | ||
MIIDSzCCAjMCCQD2ahcfZAwXxDANBgkqhkiG9w0BAQsFADCBiTELMAkGA1UEBhMC | ||
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU9yYW5nZSBDb3VudHkx | ||
EDAOBgNVBAoMB1ByaXZhZG8xGjAYBgNVBAMMEXNlcnZlci56bGFiZWwuY29tMR8w | ||
HQYJKoZIhvcNAQkBFhBlYXJsZUB6bGFiZWwuY29tMB4XDTE4MDMwNjA1NDg0NFoX | ||
DTE5MDMwNjA1NDg0NFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh | ||
dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZI | ||
hvcNAQEBBQADggEPADCCAQoCggEBAPVKBwbZ+KDSl40YCDkP6y8Sv4iNGvEOZg8Y | ||
X7sGvf/xZH7UiCBWPFIRpNmDSaZ3yjsmFqm6sLiYSGSdrBCFqdt9NTp2r7hga6Sj | ||
oASSZY4B9pf+GblDy5m10KDx90BFKXdPMCLT+o76Nx9PpCvw13A848wHNG3bpBgI | ||
t+w/vJCX3bkRn8yEYAU6GdMbYe7v446hX3kY5UmgeJFr9xz1kq6AzYrMt/UHhNzO | ||
S+QckJaY0OGWvmTNspY3xCbbFtIDkCdBS8CZAw+itnofvnWWKQEXlt6otPh5njwy | ||
+O1t/Q+Z7OMDYQaH02IQx3188/kW3FzOY32knER1uzjmRO+jhA8CAwEAATANBgkq | ||
hkiG9w0BAQsFAAOCAQEAnDrROGRETB0woIcI1+acY1yRq4yAcH2/hdq2MoM+DCyM | ||
E8CJaOznGR9ND0ImWpTZqomHOUkOBpvu7u315blQZcLbL1LfHJGRTCHVhvVrcyEb | ||
fWTnRtAQdlirUm/obwXIitoz64VSbIVzcqqfg9C6ZREB9JbEX98/9Wp2gVY+31oC | ||
JfUvYadSYxh3nblvA4OL+iEZiW8NE3hbW6WPXxvS7Euge0uWMPc4uEcnsE0ZVG3m | ||
+TGimzSdeWDvGBRWZHXczC2zD4aoE5vrl+GD2i++c6yjL/otHfYyUpzUfbI2hMAA | ||
5tAF1D5vAAwA8nfPysumlLsIjohJZo4lgnhB++AlOg== | ||
-----END CERTIFICATE----- | ||
)EOF"; | ||
|
||
static const char serverKey[] PROGMEM = R"EOF( | ||
-----BEGIN RSA PRIVATE KEY----- | ||
MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI | ||
IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z | ||
uUPLmbXQoPH3QEUpd08wItP6jvo3H0+kK/DXcDzjzAc0bdukGAi37D+8kJfduRGf | ||
zIRgBToZ0xth7u/jjqFfeRjlSaB4kWv3HPWSroDNisy39QeE3M5L5ByQlpjQ4Za+ | ||
ZM2yljfEJtsW0gOQJ0FLwJkDD6K2eh++dZYpAReW3qi0+HmePDL47W39D5ns4wNh | ||
BofTYhDHfXzz+RbcXM5jfaScRHW7OOZE76OEDwIDAQABAoIBAQDKov5NFbNFQNR8 | ||
djcM1O7Is6dRaqiwLeH4ZH1pZ3d9QnFwKanPdQ5eCj9yhfhJMrr5xEyCqT0nMn7T | ||
yEIGYDXjontfsf8WxWkH2TjvrfWBrHOIOx4LJEvFzyLsYxiMmtZXvy6YByD+Dw2M | ||
q2GH/24rRdI2klkozIOyazluTXU8yOsSGxHr/aOa9/sZISgLmaGOOuKI/3Zqjdhr | ||
eHeSqoQFt3xXa8jw01YubQUDw/4cv9rk2ytTdAoQUimiKtgtjsggpP1LTq4xcuqN | ||
d4jWhTcnorWpbD2cVLxrEbnSR3VuBCJEZv5axg5ZPxLEnlcId8vMtvTRb5nzzszn | ||
geYUWDPhAoGBAPyKVNqqwQl44oIeiuRM2FYenMt4voVaz3ExJX2JysrG0jtCPv+Y | ||
84R6Cv3nfITz3EZDWp5sW3OwoGr77lF7Tv9tD6BptEmgBeuca3SHIdhG2MR+tLyx | ||
/tkIAarxQcTGsZaSqra3gXOJCMz9h2P5dxpdU+0yeMmOEnAqgQ8qtNBfAoGBAPim | ||
RAtnrd0WSlCgqVGYFCvDh1kD5QTNbZc+1PcBHbVV45EmJ2fLXnlDeplIZJdYxmzu | ||
DMOxZBYgfeLY9exje00eZJNSj/csjJQqiRftrbvYY7m5njX1kM5K8x4HlynQTDkg | ||
rtKO0YZJxxmjRTbFGMegh1SLlFLRIMtehNhOgipRAoGBAPnEEpJGCS9GGLfaX0HW | ||
YqwiEK8Il12q57mqgsq7ag7NPwWOymHesxHV5mMh/Dw+NyBi4xAGWRh9mtrUmeqK | ||
iyICik773Gxo0RIqnPgd4jJWN3N3YWeynzulOIkJnSNx5BforOCTc3uCD2s2YB5X | ||
jx1LKoNQxLeLRN8cmpIWicf/AoGBANjRSsZTKwV9WWIDJoHyxav/vPb+8WYFp8lZ | ||
zaRxQbGM6nn4NiZI7OF62N3uhWB/1c7IqTK/bVHqFTuJCrCNcsgld3gLZ2QWYaMV | ||
kCPgaj1BjHw4AmB0+EcajfKilcqtSroJ6MfMJ6IclVOizkjbByeTsE4lxDmPCDSt | ||
/9MKanBxAoGAY9xo741Pn9WUxDyRplww606ccdNf/ksHWNc/Y2B5SPwxxSnIq8nO | ||
j01SmsCUYVFAgZVOTiiycakjYLzxlc6p8BxSVqy6LlJqn95N8OXoQ+bkwUux/ekg | ||
gz5JWYhbD6c38khSzJb0pNXCo3EuYAVa36kDM96k1BtWuhRS10Q1VXk= | ||
-----END RSA PRIVATE KEY----- | ||
)EOF"; | ||
|
||
|
||
const int led = 13; | ||
|
||
void handleRoot() { | ||
digitalWrite(led, 1); | ||
server.send(200, "text/plain", "Hello from esp8266 over HTTPS!"); | ||
digitalWrite(led, 0); | ||
} | ||
|
||
void handleNotFound(){ | ||
digitalWrite(led, 1); | ||
String message = "File Not Found\n\n"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Series of concats like this should be avoided (causes mem fragmentation). While this is an example, many users will base off of it, so let's set a good one. Can you calculate the string lenght beforehand and use ::reserve()? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say that if you need to calculate the length before using String that defeats String's purpose as a crutch for new users. If I (easily) knew how long the buffer would be, I'd just use a temp on the stack or malloc() it and sprintf(). In this sample I'd need to sum up the constant bits and then replicate the for(all args) { len += argname[i].len + arg[i].len } loop just to get that length. Also, I believe umm_allocator will attempt to extend the existing block if there's unused heap after it, not make a new one, so we're not necessarily making as big of a mess as we might be in this case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've seen at least one user project stop crashing when a String::reserve() call was added before the concat sequence. But let's leave it as it is for now, we can always revisit later. |
||
message += "URI: "; | ||
message += server.uri(); | ||
message += "\nMethod: "; | ||
message += (server.method() == HTTP_GET)?"GET":"POST"; | ||
message += "\nArguments: "; | ||
message += server.args(); | ||
message += "\n"; | ||
for (uint8_t i=0; i<server.args(); i++){ | ||
message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; | ||
} | ||
server.send(404, "text/plain", message); | ||
digitalWrite(led, 0); | ||
} | ||
|
||
void setup(void){ | ||
pinMode(led, OUTPUT); | ||
digitalWrite(led, 0); | ||
Serial.begin(115200); | ||
WiFi.begin(ssid, password); | ||
Serial.println(""); | ||
|
||
// Wait for connection | ||
while (WiFi.status() != WL_CONNECTED) { | ||
delay(500); | ||
Serial.print("."); | ||
} | ||
|
||
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov"); | ||
|
||
Serial.println(""); | ||
Serial.print("Connected to "); | ||
Serial.println(ssid); | ||
Serial.print("IP address: "); | ||
Serial.println(WiFi.localIP()); | ||
|
||
if (MDNS.begin("esp8266")) { | ||
Serial.println("MDNS responder started"); | ||
} | ||
|
||
server.setRSACert(new BearSSLX509List(serverCert), new BearSSLPrivateKey(serverKey)); | ||
|
||
server.on("/", handleRoot); | ||
|
||
server.on("/inline", [](){ | ||
server.send(200, "text/plain", "this works as well"); | ||
}); | ||
|
||
server.onNotFound(handleNotFound); | ||
|
||
server.begin(); | ||
Serial.println("HTTPS server started"); | ||
} | ||
|
||
void loop(void){ | ||
server.handleClient(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code duplication is increasing with all these begin() methods. But let's fix that later as a cleanup step.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One suggestion voiced elsewhere was to change the way HTTPClient works to be similar to PubSubClient. That is, HTTPClient receives a prepared Client object (which can be WiFiClient or WiFiClientSecure or any other client). This object already has fingerprint set if necessary. If you think this is a good idea, i can prepare a PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we would have
HTTPClient::begin(Client& client, String hostname)
and would do something likeThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@igrr That's a good idea. Maybe for this immediate round we can shelve it and then migrate to that way afterwards? I'm already at 71 updated files here, and I'd rather not boil any more of the ocean in this pot than necessary.
We'd need to change
axTLS::WiFiClientSecure
to allow thissetFingerprint()
call and, when used, do an immediate check onconnect()
. Then only one TLSClient class in HTTPClient would be needed and we can decorate the older ones as deprecated.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure sure, no need to do anything in this PR. Once this is merged, I will prepare a PR about HTTPClient.