mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-15 00:02:49 +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
@ -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