mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-27 18:02:17 +03:00
Add SSL enabled WiFiServer, Updater, WebServer
Adds SSL server mode for WiFiServerSecure, for plain SSL connections, ESP8266WebServerSecure, for HTTPS web serving, and SecureHTTPSUpdater for encrypted OTA updates. Example code is provided for all new options, as well as a BASH script for generating their own, self-signed certificates. Both ESP8266WebServerSecure and SecureHTTPSUpdater are important for secure password-based authentication. HTTP Basic Authentication, the only supported model presently, sends the username and password in *cleartext* and therefore should *never* be used in any un-SSL encrypted channel unless you don't mind sharing your login and password with anyone else on the internet. Even if the ESP8266 is not safety critical, this cleartext broadcast could expose you should you reuse this password elsewhere on your network or the internet.
This commit is contained in:
committed by
Ivan Grokhotkov
parent
8765da258b
commit
bd1c7ce1dc
@ -0,0 +1,204 @@
|
||||
/*
|
||||
WiFiHTTPSServer - Simple SSL server example
|
||||
|
||||
This sketch demonstrates how to set up a simple HTTP-like server usingcl
|
||||
HTTPS encryption. This is NOT the recommended way of writing a web server!
|
||||
Please see the ESP8266WebServer and ESP8266WebServerSecure for a much easier
|
||||
and more robust server for your own applications.
|
||||
|
||||
The server will set a GPIO pin depending on the request
|
||||
https://server_ip/gpio/0 will set the GPIO2 low,
|
||||
https://server_ip/gpio/1 will set the GPIO2 high
|
||||
server_ip is the IP address of the ESP8266 module, will be
|
||||
printed to Serial when the module is connected.
|
||||
|
||||
IMPORTANT NOTES ABOUT SSL CERTIFICATES
|
||||
|
||||
1. USE/GENERATE YOUR OWN CERTIFICATES
|
||||
While a sample, self-signed certificate is included in this example,
|
||||
it is ABSOLUTELY VITAL that you use your own SSL certificate in any
|
||||
real-world deployment. Anyone with the certificate and key may be
|
||||
able to decrypt your traffic, so your own keys should be kept in a
|
||||
safe manner, not accessible on any public network.
|
||||
|
||||
2. HOW TO GENERATE YOUR OWN CERTIFICATE/KEY PAIR
|
||||
A sample script, "make-self-signed-cert.sh" is provided in the
|
||||
ESP8266WiFi/examples/WiFiHTTPSServer directory. This script can be
|
||||
modified (replace "your-name-here" with your Organization name). Note
|
||||
that this will be a *self-signed certificate* and will *NOT* be accepted
|
||||
by default by most modern browsers. They'll display something like,
|
||||
"This certificate is from an untrusted source," or "Your connection is
|
||||
not secure," or "Your connection is not private," and the user will
|
||||
have to manully allow the browser to continue by using the
|
||||
"Advanced/Add Exception" (FireFox) or "Advanced/Proceed" (Chrome) link.
|
||||
|
||||
You may also, of course, use a commercial, trusted SSL provider to
|
||||
generate your certificate. When requesting the certificate, you'll
|
||||
need to specify that it use SHA256 and 1024 or 512 bits in order to
|
||||
function with the axTLS implementation in the ESP8266.
|
||||
|
||||
Adapted by Earle F. Philhower, III, from the WiFiWebServer.ino example.
|
||||
This example is released into the public domain.
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
const char* ssid = "your-ssid";
|
||||
const char* password = "your-password";
|
||||
|
||||
// The certificate is stored in PMEM
|
||||
static const uint8_t x509[] PROGMEM = {
|
||||
0x30, 0x82, 0x01, 0x3d, 0x30, 0x81, 0xe8, 0x02, 0x09, 0x00, 0xfe, 0x56,
|
||||
0x46, 0xf2, 0x78, 0xc6, 0x51, 0x17, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
|
||||
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x26, 0x31,
|
||||
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x45, 0x53,
|
||||
0x50, 0x38, 0x32, 0x36, 0x36, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
|
||||
0x04, 0x03, 0x0c, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e,
|
||||
0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x31, 0x38, 0x31,
|
||||
0x34, 0x34, 0x39, 0x31, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x31,
|
||||
0x32, 0x35, 0x31, 0x34, 0x34, 0x39, 0x31, 0x38, 0x5a, 0x30, 0x26, 0x31,
|
||||
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x45, 0x53,
|
||||
0x50, 0x38, 0x32, 0x36, 0x36, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
|
||||
0x04, 0x03, 0x0c, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e,
|
||||
0x31, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02,
|
||||
0x41, 0x00, 0xc6, 0x72, 0x6c, 0x12, 0xe1, 0x20, 0x4d, 0x10, 0x0c, 0xf7,
|
||||
0x3a, 0x2a, 0x5a, 0x49, 0xe2, 0x2d, 0xc9, 0x7a, 0x63, 0x1d, 0xef, 0xc6,
|
||||
0xbb, 0xa3, 0xd6, 0x6f, 0x59, 0xcb, 0xd5, 0xf6, 0xbe, 0x34, 0x83, 0x33,
|
||||
0x50, 0x80, 0xec, 0x49, 0x63, 0xbf, 0xee, 0x59, 0x94, 0x67, 0x8b, 0x8d,
|
||||
0x81, 0x85, 0x23, 0x24, 0x06, 0x52, 0x76, 0x55, 0x9d, 0x18, 0x09, 0xb3,
|
||||
0x3c, 0x10, 0x40, 0x05, 0x01, 0xf3, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30,
|
||||
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
||||
0x05, 0x00, 0x03, 0x41, 0x00, 0x69, 0xdc, 0x6c, 0x9b, 0xa7, 0x62, 0x57,
|
||||
0x7e, 0x03, 0x01, 0x45, 0xad, 0x9a, 0x83, 0x90, 0x3a, 0xe7, 0xdf, 0xe8,
|
||||
0x8f, 0x46, 0x00, 0xd3, 0x5f, 0x2b, 0x0a, 0xde, 0x92, 0x1b, 0xc5, 0x04,
|
||||
0xc5, 0xc0, 0x76, 0xf4, 0xf6, 0x08, 0x36, 0x97, 0x27, 0x82, 0xf1, 0x60,
|
||||
0x76, 0xc2, 0xcd, 0x67, 0x6c, 0x4b, 0x6c, 0xca, 0xfd, 0x97, 0xfd, 0x33,
|
||||
0x9e, 0x12, 0x67, 0x6b, 0x98, 0x7e, 0xd5, 0x80, 0x8f
|
||||
};
|
||||
|
||||
// And so is the key. These could also be in DRAM
|
||||
static const uint8_t rsakey[] PROGMEM = {
|
||||
0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xc6, 0x72,
|
||||
0x6c, 0x12, 0xe1, 0x20, 0x4d, 0x10, 0x0c, 0xf7, 0x3a, 0x2a, 0x5a, 0x49,
|
||||
0xe2, 0x2d, 0xc9, 0x7a, 0x63, 0x1d, 0xef, 0xc6, 0xbb, 0xa3, 0xd6, 0x6f,
|
||||
0x59, 0xcb, 0xd5, 0xf6, 0xbe, 0x34, 0x83, 0x33, 0x50, 0x80, 0xec, 0x49,
|
||||
0x63, 0xbf, 0xee, 0x59, 0x94, 0x67, 0x8b, 0x8d, 0x81, 0x85, 0x23, 0x24,
|
||||
0x06, 0x52, 0x76, 0x55, 0x9d, 0x18, 0x09, 0xb3, 0x3c, 0x10, 0x40, 0x05,
|
||||
0x01, 0xf3, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x35, 0x0b, 0x74,
|
||||
0xd3, 0xff, 0x15, 0x51, 0x44, 0x0f, 0x13, 0x2e, 0x9b, 0x0f, 0x93, 0x5c,
|
||||
0x3f, 0xfc, 0xf1, 0x17, 0xf9, 0x72, 0x94, 0x5e, 0xa7, 0xc6, 0xb3, 0xf0,
|
||||
0xfe, 0xc9, 0x6c, 0xb1, 0x1e, 0x83, 0xb3, 0xc6, 0x45, 0x3a, 0x25, 0x60,
|
||||
0x7c, 0x3d, 0x92, 0x7d, 0x53, 0xec, 0x49, 0x8d, 0xb5, 0x45, 0x10, 0x99,
|
||||
0x9b, 0xc6, 0x22, 0x3a, 0x68, 0xc7, 0x13, 0x4e, 0xb6, 0x04, 0x61, 0x21,
|
||||
0x01, 0x02, 0x21, 0x00, 0xea, 0x8c, 0x21, 0xd4, 0x7f, 0x3f, 0xb6, 0x91,
|
||||
0xfa, 0xf8, 0xb9, 0x2d, 0xcb, 0x36, 0x36, 0x02, 0x5f, 0xf0, 0x0c, 0x6e,
|
||||
0x87, 0xaa, 0x5c, 0x14, 0xf6, 0x56, 0x8e, 0x12, 0x92, 0x25, 0xde, 0xb3,
|
||||
0x02, 0x21, 0x00, 0xd8, 0x99, 0x01, 0xf1, 0x04, 0x0b, 0x98, 0xa3, 0x71,
|
||||
0x56, 0x1d, 0xea, 0x6f, 0x45, 0xd1, 0x36, 0x70, 0x76, 0x8b, 0xab, 0x69,
|
||||
0x30, 0x58, 0x9c, 0xe0, 0x45, 0x97, 0xe7, 0xb6, 0xb5, 0xef, 0xc1, 0x02,
|
||||
0x21, 0x00, 0xa2, 0x01, 0x06, 0xc0, 0xf2, 0xdf, 0xbc, 0x28, 0x1a, 0xb4,
|
||||
0xbf, 0x9b, 0x5c, 0xd8, 0x65, 0xf7, 0xbf, 0xf2, 0x5b, 0x73, 0xe0, 0xeb,
|
||||
0x0f, 0xcd, 0x3e, 0xd5, 0x4c, 0x2e, 0x91, 0x99, 0xec, 0xb7, 0x02, 0x20,
|
||||
0x4b, 0x9d, 0x46, 0xd7, 0x3c, 0x01, 0x4c, 0x5d, 0x2a, 0xb0, 0xd4, 0xaa,
|
||||
0xc6, 0x03, 0xca, 0xa0, 0xc5, 0xac, 0x2c, 0xe0, 0x3f, 0x4d, 0x98, 0x71,
|
||||
0xd3, 0xbd, 0x97, 0xe5, 0x55, 0x9c, 0xb8, 0x41, 0x02, 0x20, 0x02, 0x42,
|
||||
0x9f, 0xd1, 0x06, 0x35, 0x3b, 0x42, 0xf5, 0x64, 0xaf, 0x6d, 0xbf, 0xcd,
|
||||
0x2c, 0x3a, 0xcd, 0x0a, 0x9a, 0x4d, 0x7c, 0xad, 0x29, 0xd6, 0x36, 0x57,
|
||||
0xd5, 0xdf, 0x34, 0xeb, 0x26, 0x03
|
||||
};
|
||||
|
||||
// Create an instance of the server
|
||||
// specify the port to listen on as an argument
|
||||
WiFiServerSecure server(443);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(10);
|
||||
|
||||
// prepare GPIO2
|
||||
pinMode(2, OUTPUT);
|
||||
digitalWrite(2, 0);
|
||||
|
||||
// Connect to WiFi network
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
|
||||
// Set the certificates from PMEM (if using DRAM remove the _P from the call)
|
||||
server.setServerKeyAndCert_P(rsakey, sizeof(rsakey), x509, sizeof(x509));
|
||||
|
||||
// Start the server
|
||||
server.begin();
|
||||
Serial.println("Server started");
|
||||
|
||||
// Print the IP address
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Check if a client has connected
|
||||
WiFiClientSecure client = server.available();
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait until the client sends some data
|
||||
Serial.println("new client");
|
||||
unsigned long timeout = millis() + 3000;
|
||||
while(!client.available() && millis() < timeout){
|
||||
delay(1);
|
||||
}
|
||||
if (millis() > timeout) {
|
||||
Serial.println("timeout");
|
||||
client.flush();
|
||||
client.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the first line of the request
|
||||
String req = client.readStringUntil('\r');
|
||||
Serial.println(req);
|
||||
client.flush();
|
||||
|
||||
// Match the request
|
||||
int val;
|
||||
if (req.indexOf("/gpio/0") != -1)
|
||||
val = 0;
|
||||
else if (req.indexOf("/gpio/1") != -1)
|
||||
val = 1;
|
||||
else {
|
||||
Serial.println("invalid request");
|
||||
client.print("HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html><body>Not found</body></html>");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set GPIO2 according to the request
|
||||
digitalWrite(2, val);
|
||||
|
||||
client.flush();
|
||||
|
||||
// Prepare the response
|
||||
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
|
||||
s += (val)?"high":"low";
|
||||
s += "</html>\n";
|
||||
|
||||
// Send the response to the client
|
||||
client.print(s);
|
||||
delay(1);
|
||||
Serial.println("Client disconnected");
|
||||
|
||||
// The client will actually be disconnected
|
||||
// when the function returns and 'client' object is detroyed
|
||||
}
|
||||
|
49
libraries/ESP8266WiFi/examples/WiFiHTTPSServer/make-self-signed-cert.sh
Executable file
49
libraries/ESP8266WiFi/examples/WiFiHTTPSServer/make-self-signed-cert.sh
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script generates a self-signed certificate for use by the ESP8266
|
||||
# Replace your-name-here with somethine appropriate before running and use
|
||||
# the generated .H files in your code as follows:
|
||||
#
|
||||
# static const uint8_t rsakey[] ICACHE_RODATA_ATTR = {
|
||||
# #include "key.h"
|
||||
# };
|
||||
#
|
||||
# static const uint8_t x509[] ICACHE_RODATA_ATTR = {
|
||||
# #include "x509.h"
|
||||
# };
|
||||
#
|
||||
# ....
|
||||
# WiFiServerSecure server(443);
|
||||
# server.setServerKeyAndCert_P(rsakey, sizeof(rsakey), x509, sizeof(x509));
|
||||
# ....
|
||||
|
||||
# 1024 or 512. 512 saves memory...
|
||||
BITS=512
|
||||
C=$PWD
|
||||
pushd /tmp
|
||||
|
||||
openssl genrsa -out tls.ca_key.pem $BITS
|
||||
openssl genrsa -out tls.key_$BITS.pem $BITS
|
||||
openssl rsa -in tls.key_$BITS.pem -out tls.key_$BITS -outform DER
|
||||
cat > certs.conf <<EOF
|
||||
[ req ]
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
|
||||
[ req_distinguished_name ]
|
||||
O = your-name-here
|
||||
CN = 127.0.0.1
|
||||
EOF
|
||||
openssl req -out tls.ca_x509.req -key tls.ca_key.pem -new -config certs.conf
|
||||
openssl req -out tls.x509_$BITS.req -key tls.key_$BITS.pem -new -config certs.conf
|
||||
openssl x509 -req -in tls.ca_x509.req -out tls.ca_x509.pem -sha256 -days 5000 -signkey tls.ca_key.pem
|
||||
openssl x509 -req -in tls.x509_$BITS.req -out tls.x509_$BITS.pem -sha256 -CAcreateserial -days 5000 -CA tls.ca_x509.pem -CAkey tls.ca_key.pem
|
||||
openssl x509 -in tls.ca_x509.pem -outform DER -out tls.ca_x509.cer
|
||||
openssl x509 -in tls.x509_$BITS.pem -outform DER -out tls.x509_$BITS.cer
|
||||
|
||||
xxd -i tls.key_$BITS | sed 's/.*{//' | sed 's/\};//' | sed 's/unsigned.*//' > "$C/key.h"
|
||||
xxd -i tls.x509_$BITS.cer | sed 's/.*{//' | sed 's/\};//' | sed 's/unsigned.*//' > "$C/x509.h"
|
||||
|
||||
rm -f tls.ca_key.pem tls.key_$BITS.pem tls.key_$BITS certs.conf tls.ca_x509.req tls.x509_$BITS.req tls.ca_x509.pem tls.x509_$BITS.pem tls.srl tls.x509_$BITS.cer tls.ca_x509.cer
|
||||
|
||||
popd
|
@ -15,6 +15,7 @@ ESP8266WiFi KEYWORD3
|
||||
WiFi KEYWORD1
|
||||
WiFiClient KEYWORD1
|
||||
WiFiServer KEYWORD1
|
||||
WiFiServerSecure KEYWORD1
|
||||
WiFiUDP KEYWORD1
|
||||
WiFiClientSecure KEYWORD1
|
||||
ESP8266WiFiMulti KEYWORD1
|
||||
|
@ -38,6 +38,7 @@ extern "C" {
|
||||
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
#include "WiFiServerSecure.h"
|
||||
#include "WiFiClientSecure.h"
|
||||
|
||||
#ifdef DEBUG_ESP_WIFI
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
virtual int connect(const String host, uint16_t port);
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
size_t write_P(PGM_P buf, size_t size);
|
||||
virtual size_t write_P(PGM_P buf, size_t size);
|
||||
size_t write(Stream& stream);
|
||||
|
||||
// This one is deprecated, use write(Stream& instead)
|
||||
|
@ -93,8 +93,6 @@ public:
|
||||
if (_ssl_ctx_refcnt == 0) {
|
||||
ssl_ctx_free(_ssl_ctx);
|
||||
}
|
||||
|
||||
s_io_ctx = nullptr;
|
||||
}
|
||||
|
||||
void ref()
|
||||
@ -116,14 +114,14 @@ public:
|
||||
if (_ssl) {
|
||||
/* Creating a new TLS session on top of a new TCP connection.
|
||||
ssl_free will want to send a close notify alert, but the old TCP connection
|
||||
is already gone at this point, so reset s_io_ctx. */
|
||||
s_io_ctx = nullptr;
|
||||
is already gone at this point, so reset io_ctx. */
|
||||
io_ctx = nullptr;
|
||||
ssl_free(_ssl);
|
||||
_available = 0;
|
||||
_read_ptr = nullptr;
|
||||
}
|
||||
s_io_ctx = ctx;
|
||||
_ssl = ssl_client_new(_ssl_ctx, 0, nullptr, 0, ext);
|
||||
io_ctx = ctx;
|
||||
_ssl = ssl_client_new(_ssl_ctx, reinterpret_cast<int>(this), nullptr, 0, ext);
|
||||
uint32_t t = millis();
|
||||
|
||||
while (millis() - t < timeout_ms && ssl_handshake_status(_ssl) != SSL_OK) {
|
||||
@ -136,14 +134,32 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void connectServer(ClientContext *ctx) {
|
||||
io_ctx = ctx;
|
||||
_ssl = ssl_server_new(_ssl_ctx, reinterpret_cast<int>(this));
|
||||
_isServer = true;
|
||||
|
||||
uint32_t timeout_ms = 5000;
|
||||
uint32_t t = millis();
|
||||
|
||||
while (millis() - t < timeout_ms && ssl_handshake_status(_ssl) != SSL_OK) {
|
||||
uint8_t* data;
|
||||
int rc = ssl_read(_ssl, &data);
|
||||
if (rc < SSL_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
s_io_ctx = nullptr;
|
||||
io_ctx = nullptr;
|
||||
}
|
||||
|
||||
bool connected()
|
||||
{
|
||||
return _ssl != nullptr && ssl_handshake_status(_ssl) == SSL_OK;
|
||||
if (_isServer) return _ssl != nullptr;
|
||||
else return _ssl != nullptr && ssl_handshake_status(_ssl) == SSL_OK;
|
||||
}
|
||||
|
||||
int read(uint8_t* dst, size_t size)
|
||||
@ -189,7 +205,9 @@ public:
|
||||
|
||||
int write(const uint8_t* src, size_t size)
|
||||
{
|
||||
if (!_available) {
|
||||
if (_isServer) {
|
||||
return _write(src, size);
|
||||
} else if (!_available) {
|
||||
if (_hasWriteBuffers()) {
|
||||
int rc = _writeBuffersSend();
|
||||
if (rc < 0) {
|
||||
@ -241,10 +259,10 @@ public:
|
||||
return cb;
|
||||
}
|
||||
|
||||
// similar to availble, but doesn't return exact size
|
||||
// similar to available, but doesn't return exact size
|
||||
bool hasData()
|
||||
{
|
||||
return _available > 0 || (s_io_ctx && s_io_ctx->getSize() > 0);
|
||||
return _available > 0 || (io_ctx && io_ctx->getSize() > 0);
|
||||
}
|
||||
|
||||
bool loadObject(int type, Stream& stream, size_t size)
|
||||
@ -308,8 +326,15 @@ public:
|
||||
|
||||
static ClientContext* getIOContext(int fd)
|
||||
{
|
||||
(void) fd;
|
||||
return s_io_ctx;
|
||||
return reinterpret_cast<SSLContext*>(fd)->io_ctx;
|
||||
}
|
||||
|
||||
int loadServerX509Cert(const uint8_t *cert, int len) {
|
||||
return ssl_obj_memory_load(SSLContext::_ssl_ctx, SSL_OBJ_X509_CERT, cert, len, NULL);
|
||||
}
|
||||
|
||||
int loadServerRSAKey(const uint8_t *rsakey, int len) {
|
||||
return ssl_obj_memory_load(SSLContext::_ssl_ctx, SSL_OBJ_RSA_KEY, rsakey, len, NULL);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -386,6 +411,7 @@ protected:
|
||||
return !_writeBuffers.empty();
|
||||
}
|
||||
|
||||
bool _isServer = false;
|
||||
static SSL_CTX* _ssl_ctx;
|
||||
static int _ssl_ctx_refcnt;
|
||||
SSL* _ssl = nullptr;
|
||||
@ -394,12 +420,11 @@ protected:
|
||||
size_t _available = 0;
|
||||
BufferList _writeBuffers;
|
||||
bool _allowSelfSignedCerts = false;
|
||||
static ClientContext* s_io_ctx;
|
||||
ClientContext* io_ctx;
|
||||
};
|
||||
|
||||
SSL_CTX* SSLContext::_ssl_ctx = nullptr;
|
||||
int SSLContext::_ssl_ctx_refcnt = 0;
|
||||
ClientContext* SSLContext::s_io_ctx = nullptr;
|
||||
|
||||
WiFiClientSecure::WiFiClientSecure()
|
||||
{
|
||||
@ -433,6 +458,42 @@ WiFiClientSecure& WiFiClientSecure::operator=(const WiFiClientSecure& rhs)
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Only called by the WifiServerSecure, need to get the keys/certs loaded before beginning
|
||||
WiFiClientSecure::WiFiClientSecure(ClientContext* client, bool usePMEM, const uint8_t *rsakey, int rsakeyLen, const uint8_t *cert, int certLen)
|
||||
{
|
||||
_client = client;
|
||||
if (_ssl) {
|
||||
_ssl->unref();
|
||||
_ssl = nullptr;
|
||||
}
|
||||
|
||||
_ssl = new SSLContext;
|
||||
_ssl->ref();
|
||||
|
||||
if (usePMEM) {
|
||||
// When using PMEM based certs, allocate stack and copy from flash to DRAM, call SSL functions to avoid
|
||||
// heap fragmentation that would happen w/malloc()
|
||||
uint8_t *stackData = (uint8_t*)alloca(max(certLen, rsakeyLen));
|
||||
if (rsakey && rsakeyLen) {
|
||||
memcpy_P(stackData, rsakey, rsakeyLen);
|
||||
_ssl->loadServerRSAKey(stackData, rsakeyLen);
|
||||
}
|
||||
if (cert && certLen) {
|
||||
memcpy_P(stackData, cert, certLen);
|
||||
_ssl->loadServerX509Cert(stackData, certLen);
|
||||
}
|
||||
} else {
|
||||
if (rsakey && rsakeyLen) {
|
||||
_ssl->loadServerRSAKey(rsakey, rsakeyLen);
|
||||
}
|
||||
if (cert && certLen) {
|
||||
_ssl->loadServerX509Cert(cert, certLen);
|
||||
}
|
||||
}
|
||||
_client->ref();
|
||||
_ssl->connectServer(client);
|
||||
}
|
||||
|
||||
int WiFiClientSecure::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
if (!WiFiClient::connect(ip, port)) {
|
||||
@ -496,6 +557,14 @@ size_t WiFiClientSecure::write(const uint8_t *buf, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t WiFiClientSecure::write_P(PGM_P buf, size_t size)
|
||||
{
|
||||
// Copy to RAM and call normal send. alloca() auto-frees on return
|
||||
uint8_t *copy = (uint8_t*)alloca(size);
|
||||
memcpy_P(copy, buf, size);
|
||||
return write(copy, size);
|
||||
}
|
||||
|
||||
int WiFiClientSecure::read(uint8_t *buf, size_t size)
|
||||
{
|
||||
if (!_ssl) {
|
||||
@ -584,6 +653,8 @@ void WiFiClientSecure::stop()
|
||||
{
|
||||
if (_ssl) {
|
||||
_ssl->stop();
|
||||
_ssl->unref();
|
||||
_ssl = nullptr;
|
||||
}
|
||||
WiFiClient::stop();
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
|
||||
uint8_t connected() override;
|
||||
size_t write(const uint8_t *buf, size_t size) override;
|
||||
size_t write_P(PGM_P buf, size_t size) override;
|
||||
int read(uint8_t *buf, size_t size) override;
|
||||
int available() override;
|
||||
int read() override;
|
||||
@ -80,6 +81,10 @@ public:
|
||||
return loadCACert(file, file.size());
|
||||
}
|
||||
|
||||
friend class WiFiServerSecure; // Needs access to custom constructor below
|
||||
protected:
|
||||
// Only called by WiFiServerSecure
|
||||
WiFiClientSecure(ClientContext* client, bool usePMEM, const uint8_t *rsakey, int rsakeyLen, const uint8_t *cert, int certLen);
|
||||
|
||||
protected:
|
||||
void _initSSLContext();
|
||||
|
@ -35,7 +35,8 @@ class ClientContext;
|
||||
class WiFiClient;
|
||||
|
||||
class WiFiServer : public Server {
|
||||
private:
|
||||
// Secure server needs access to all the private entries here
|
||||
protected:
|
||||
uint16_t _port;
|
||||
IPAddress _addr;
|
||||
tcp_pcb* _pcb;
|
||||
|
79
libraries/ESP8266WiFi/src/WiFiServerSecure.cpp
Normal file
79
libraries/ESP8266WiFi/src/WiFiServerSecure.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
WiFiServerSecure.cpp - SSL server for esp8266, mostly compatible
|
||||
with Arduino WiFi shield library
|
||||
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define LWIP_INTERNAL
|
||||
|
||||
extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "include/ClientContext.h"
|
||||
#include "WiFiServerSecure.h"
|
||||
|
||||
WiFiServerSecure::WiFiServerSecure(IPAddress addr, uint16_t port) : WiFiServer(addr, port)
|
||||
{
|
||||
}
|
||||
|
||||
WiFiServerSecure::WiFiServerSecure(uint16_t port) : WiFiServer(port)
|
||||
{
|
||||
}
|
||||
|
||||
void WiFiServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen)
|
||||
{
|
||||
this->usePMEM = false;
|
||||
this->rsakey = key;
|
||||
this->rsakeyLen = keyLen;
|
||||
this->cert = cert;
|
||||
this->certLen = certLen;
|
||||
}
|
||||
|
||||
void WiFiServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen)
|
||||
{
|
||||
this->usePMEM = true;
|
||||
this->rsakey = key;
|
||||
this->rsakeyLen = keyLen;
|
||||
this->cert = cert;
|
||||
this->certLen = certLen;
|
||||
}
|
||||
|
||||
WiFiClientSecure WiFiServerSecure::available(uint8_t* status)
|
||||
{
|
||||
(void) status; // Unused
|
||||
if (_unclaimed) {
|
||||
WiFiClientSecure result(_unclaimed, usePMEM, rsakey, rsakeyLen, cert, certLen);
|
||||
_unclaimed = _unclaimed->next();
|
||||
result.setNoDelay(_noDelay);
|
||||
DEBUGV("WS:av\r\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
optimistic_yield(1000);
|
||||
return WiFiClientSecure();
|
||||
}
|
||||
|
43
libraries/ESP8266WiFi/src/WiFiServerSecure.h
Normal file
43
libraries/ESP8266WiFi/src/WiFiServerSecure.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
WiFiServerSecure.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef wifiserversecure_h
|
||||
#define wifiserversecure_h
|
||||
|
||||
#include "WiFiServer.h"
|
||||
class WiFiClientSecure;
|
||||
|
||||
class WiFiServerSecure : public WiFiServer {
|
||||
public:
|
||||
WiFiServerSecure(IPAddress addr, uint16_t port);
|
||||
WiFiServerSecure(uint16_t port);
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
virtual ~WiFiServerSecure() {}
|
||||
WiFiClientSecure available(uint8_t* status = NULL);
|
||||
private:
|
||||
bool usePMEM = false;
|
||||
const uint8_t *rsakey = nullptr;
|
||||
int rsakeyLen = 0;
|
||||
const uint8_t *cert = nullptr;
|
||||
int certLen = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user