From fea072d4cc2622885e3e6921809446d0353a2394 Mon Sep 17 00:00:00 2001 From: bligeti <64783210+bligeti@users.noreply.github.com> Date: Tue, 12 May 2020 23:01:45 +0200 Subject: [PATCH 01/16] Trigger wsHander onClose from closeConnection() In case closeConnection() is called due to SSL reported error - like session disconnection due to unstable Wifi - onClose() should be called to free up the recorded websocket handlers. --- src/HTTPConnection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index 0ab739c..60c44bb 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -133,6 +133,7 @@ void HTTPConnection::closeConnection() { if (_httpHeaders != NULL) { HTTPS_LOGD("Free headers"); + _wsHandler->onClose(); delete _httpHeaders; _httpHeaders = NULL; } From 276ec451695a7506af36f1dd585fde6225b9f481 Mon Sep 17 00:00:00 2001 From: bligeti <64783210+bligeti@users.noreply.github.com> Date: Tue, 12 May 2020 23:13:23 +0200 Subject: [PATCH 02/16] Handle error triggered by closed sessions From updateBuffer() a session clean up is initiated via closeConnection() if error is detected when reading from SSL but the already removed session is not handled in other parts of the state machine. --- src/HTTPConnection.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index 60c44bb..c6069b0 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -207,7 +207,7 @@ int HTTPConnection::updateBuffer() { } else { // An error occured _connectionState = STATE_ERROR; - HTTPS_LOGE("An receive error occured, FID=%d", _socket); + HTTPS_LOGE("An receive error occured, FID=%d, SSL_error=%d", _socket, readReturnCode); closeConnection(); return -1; } @@ -255,7 +255,7 @@ size_t HTTPConnection::readBuffer(byte* buffer, size_t length) { size_t HTTPConnection::pendingBufferSize() { updateBuffer(); - + if (isClosed()) return 0; return _bufferUnusedIdx - _bufferProcessed + pendingByteCount(); } @@ -589,11 +589,15 @@ void HTTPConnection::loop() { } // If the handler has terminated the connection, clean up and close the socket too - if (_wsHandler->closed() || _clientState == CSTATE_CLOSED) { - HTTPS_LOGI("WS closed, freeing Handler, FID=%d", _socket); - delete _wsHandler; - _wsHandler = nullptr; - _connectionState = STATE_CLOSING; + if (_wsHandler != nullptr){ + if (_wsHandler->closed() || _clientState == CSTATE_CLOSED) { + HTTPS_LOGI("WS closed, freeing Handler, FID=%d", _socket); + delete _wsHandler; + _wsHandler = nullptr; + _connectionState = STATE_CLOSING; + } + } else { + HTTPS_LOGI("WS closed due to SSL level issue and cleanded up"); } break; default:; From 586cdec9ced705b83a3178b5b1cbea5834acd9bf Mon Sep 17 00:00:00 2001 From: bligeti <64783210+bligeti@users.noreply.github.com> Date: Tue, 12 May 2020 23:19:25 +0200 Subject: [PATCH 03/16] Get detailed SSL_read error --- src/HTTPSConnection.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/HTTPSConnection.cpp b/src/HTTPSConnection.cpp index e0e3dd0..5169ee6 100644 --- a/src/HTTPSConnection.cpp +++ b/src/HTTPSConnection.cpp @@ -109,7 +109,11 @@ size_t HTTPSConnection::writeBuffer(byte* buffer, size_t length) { } size_t HTTPSConnection::readBytesToBuffer(byte* buffer, size_t length) { - return SSL_read(_ssl, buffer, length); + int ret = SSL_read(_ssl, buffer, length); + if (ret < 0) { + HTTPS_LOGD("SSL_read error: %d", SSL_get_error(_ssl, ret)); + } + return ret; } size_t HTTPSConnection::pendingByteCount() { From 34b3beba7b5575058e26aa73afcd29e47d2f23b8 Mon Sep 17 00:00:00 2001 From: bligeti <64783210+bligeti@users.noreply.github.com> Date: Mon, 22 Jun 2020 01:02:42 +0200 Subject: [PATCH 04/16] Update src/HTTPSConnection.cpp Co-authored-by: Frank Hessel --- src/HTTPSConnection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HTTPSConnection.cpp b/src/HTTPSConnection.cpp index 5169ee6..e500ff9 100644 --- a/src/HTTPSConnection.cpp +++ b/src/HTTPSConnection.cpp @@ -111,7 +111,7 @@ size_t HTTPSConnection::writeBuffer(byte* buffer, size_t length) { size_t HTTPSConnection::readBytesToBuffer(byte* buffer, size_t length) { int ret = SSL_read(_ssl, buffer, length); if (ret < 0) { - HTTPS_LOGD("SSL_read error: %d", SSL_get_error(_ssl, ret)); + HTTPS_LOGD("SSL_read error: %d", SSL_get_error(_ssl, ret)); } return ret; } From 985b9020fe7e6d793a6588f6ce282779229d4af2 Mon Sep 17 00:00:00 2001 From: bligeti <64783210+bligeti@users.noreply.github.com> Date: Mon, 22 Jun 2020 01:22:56 +0200 Subject: [PATCH 05/16] Update src/HTTPConnection.cpp Co-authored-by: Frank Hessel --- src/HTTPConnection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index c6069b0..8e496d6 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -207,7 +207,7 @@ int HTTPConnection::updateBuffer() { } else { // An error occured _connectionState = STATE_ERROR; - HTTPS_LOGE("An receive error occured, FID=%d, SSL_error=%d", _socket, readReturnCode); + HTTPS_LOGE("An receive error occurred, FID=%d, code=%d", _socket, readReturnCode); closeConnection(); return -1; } From 2bf7522b0cdb10981b082cf92c607e11d176ba00 Mon Sep 17 00:00:00 2001 From: bligeti <64783210+bligeti@users.noreply.github.com> Date: Mon, 22 Jun 2020 01:25:20 +0200 Subject: [PATCH 06/16] correct the copy-paste error --- src/HTTPConnection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index 8e496d6..e26a846 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -133,13 +133,13 @@ void HTTPConnection::closeConnection() { if (_httpHeaders != NULL) { HTTPS_LOGD("Free headers"); - _wsHandler->onClose(); delete _httpHeaders; _httpHeaders = NULL; } if (_wsHandler != nullptr) { HTTPS_LOGD("Free WS Handler"); + _wsHandler->onClose(); delete _wsHandler; _wsHandler = NULL; } From c70d6fd215c1bd37ed1d87a4fbf17d8e03768ebe Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Sun, 29 Sep 2024 16:12:39 +0200 Subject: [PATCH 07/16] github repo link update --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 0456c47..b5b0777 100644 --- a/library.json +++ b/library.json @@ -5,7 +5,7 @@ "repository": { "type": "git", - "url": "https://github.com/fhessel/esp32_https_server.git" + "url": "https://github.com/bligeti/esp32_https_server.git" }, "license": "MIT", "version": "1.0.0", diff --git a/library.properties b/library.properties index 3ffb202..fdb20c3 100644 --- a/library.properties +++ b/library.properties @@ -5,6 +5,6 @@ maintainer=Frank Hessel sentence=Alternative ESP32 Webserver implementation for the ESP32, supporting HTTPS and HTTP. paragraph=The library provides TLS support and simultaneous connections. It can be used to run an HTTP or HTTPS server, or both in parallel. The server's resources are defined through handler and middleware functions, giving an easy start to everyone who has worked with frameworks like Express or Servlets before. category=Communication -url=https://github.com/fhessel/esp32_https_server +url=https://github.com/blgeti/esp32_https_server architectures=esp32 includes=HTTPSServer.hpp,HTTPRequest.hpp,HTTPResponse.hpp From 9990493e97081e59794abbc63ea823ff4f0d2d98 Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Sun, 29 Sep 2024 18:28:23 +0200 Subject: [PATCH 08/16] Extend websockethandler with initialized check --- src/WebsocketHandler.cpp | 3 +++ src/WebsocketHandler.hpp | 1 + 2 files changed, 4 insertions(+) diff --git a/src/WebsocketHandler.cpp b/src/WebsocketHandler.cpp index 5e4c1d1..2ab459b 100644 --- a/src/WebsocketHandler.cpp +++ b/src/WebsocketHandler.cpp @@ -250,5 +250,8 @@ void WebsocketHandler::send(uint8_t* data, uint16_t length, uint8_t sendType) { bool WebsocketHandler::closed() { return _receivedClose || _sentClose; } +bool WebsocketHandler::initialized() { + return (_con != nullptr); +} } diff --git a/src/WebsocketHandler.hpp b/src/WebsocketHandler.hpp index c8c710d..af902fd 100644 --- a/src/WebsocketHandler.hpp +++ b/src/WebsocketHandler.hpp @@ -70,6 +70,7 @@ class WebsocketHandler void send(std::string data, uint8_t sendType = SEND_TYPE_BINARY); void send(uint8_t *data, uint16_t length, uint8_t sendType = SEND_TYPE_BINARY); bool closed(); + bool initialized(); void loop(); void initialize(ConnectionContext * con); From ba452ec12be5825639f04ddd23778d6dd0ab2846 Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Sun, 29 Sep 2024 18:35:52 +0200 Subject: [PATCH 09/16] Make sure wshandler isclosed if close was inistate from ssl --- src/HTTPSConnection.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/HTTPSConnection.cpp b/src/HTTPSConnection.cpp index e500ff9..29aca4a 100644 --- a/src/HTTPSConnection.cpp +++ b/src/HTTPSConnection.cpp @@ -81,7 +81,9 @@ void HTTPSConnection::closeConnection() { // correctly _connectionState = STATE_CLOSING; } - + if (this->_wsHandler != nullptr) { + this->_wsHandler->onClose(); + } // Try to tear down SSL while we are in the _shutdownTS timeout period or if an error occurred if (_ssl) { if(_connectionState == STATE_ERROR || SSL_shutdown(_ssl) == 0) { From 25516f1fe0dc7ac334f3b4e456d2f816baff0f93 Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Wed, 2 Oct 2024 22:33:04 +0200 Subject: [PATCH 10/16] Fix infinite loop when the buffer ends with \r and crash on WebSocket request to non-WebSocket node. --- src/HTTPConnection.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index e26a846..deb9101 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -138,7 +138,7 @@ void HTTPConnection::closeConnection() { } if (_wsHandler != nullptr) { - HTTPS_LOGD("Free WS Handler"); + HTTPS_LOGD("Free WS Handler in closeConnection()"); _wsHandler->onClose(); delete _wsHandler; _wsHandler = NULL; @@ -207,7 +207,7 @@ int HTTPConnection::updateBuffer() { } else { // An error occured _connectionState = STATE_ERROR; - HTTPS_LOGE("An receive error occurred, FID=%d, code=%d", _socket, readReturnCode); + HTTPS_LOGE("An receive error occured, FID=%d, SSL_error=%d", _socket, readReturnCode); closeConnection(); return -1; } @@ -239,6 +239,7 @@ bool HTTPConnection::canReadData() { size_t HTTPConnection::readBuffer(byte* buffer, size_t length) { updateBuffer(); + if (isClosed()) return 0; size_t bufferSize = _bufferUnusedIdx - _bufferProcessed; if (length > bufferSize) { @@ -304,6 +305,10 @@ void HTTPConnection::readLine(int lengthLimit) { raiseError(400, "Bad Request"); return; } + } else if (_bufferProcessed+1 == _bufferUnusedIdx){ + //Look ahead was not possible so let it go for the next round + _parserLine.possiblenewlineoverflow = true; + return; } } else { _parserLine.text += newChar; @@ -390,7 +395,7 @@ void HTTPConnection::loop() { HTTPS_LOGI("Request: %s %s (FID=%d)", _httpMethod.c_str(), _httpResource.c_str(), _socket); _connectionState = STATE_REQUEST_FINISHED; } - + if (_parserLine.possiblenewlineoverflow) _parserLine.possiblenewlineoverflow = false; break; case STATE_REQUEST_FINISHED: // Read headers @@ -423,6 +428,10 @@ void HTTPConnection::loop() { _parserLine.parsingFinished = false; _parserLine.text = ""; + } + if (_parserLine.possiblenewlineoverflow) { + _parserLine.possiblenewlineoverflow = false; + break; } } @@ -483,7 +492,8 @@ void HTTPConnection::loop() { // Find the request handler callback HTTPSCallbackFunction * resourceCallback; - if (websocketRequested) { + if (websocketRequested && resolvedResource.getMatchingNode()->_nodeType == WEBSOCKET) { + //if (websocketRequested) { // For the websocket, we use the handshake callback defined below resourceCallback = &handleWebsocketHandshake; } else { @@ -519,7 +529,8 @@ void HTTPConnection::loop() { } // Finally, after the handshake is done, we create the WebsocketHandler and change the internal state. - if(websocketRequested) { + //if(websocketRequested) { + if(websocketRequested &&resolvedResource.getMatchingNode()->_nodeType == WEBSOCKET) { _wsHandler = ((WebsocketNode*)resolvedResource.getMatchingNode())->newHandler(); _wsHandler->initialize(this); // make websocket with this connection _connectionState = STATE_WEBSOCKET; @@ -610,7 +621,7 @@ void HTTPConnection::loop() { bool HTTPConnection::checkWebsocket() { if(_httpMethod == "GET" && !_httpHeaders->getValue("Host").empty() && - _httpHeaders->getValue("Upgrade") == "websocket" && + (_httpHeaders->getValue("Upgrade") == "websocket" || _httpHeaders->getValue("Upgrade") == "WebSocket") && _httpHeaders->getValue("Connection").find("Upgrade") != std::string::npos && !_httpHeaders->getValue("Sec-WebSocket-Key").empty() && _httpHeaders->getValue("Sec-WebSocket-Version") == "13") { From 168b13e8560347465d49e2903e2c3a5e5005d63f Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Wed, 2 Oct 2024 22:55:35 +0200 Subject: [PATCH 11/16] HTTPConnection header update --- src/HTTPConnection.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HTTPConnection.hpp b/src/HTTPConnection.hpp index fb15d7a..5113fd3 100644 --- a/src/HTTPConnection.hpp +++ b/src/HTTPConnection.hpp @@ -144,6 +144,7 @@ class HTTPConnection : private ConnectionContext { struct { std::string text = ""; bool parsingFinished = false; + bool possiblenewlineoverflow=false; } _parserLine; // HTTP properties: Method, Request, Headers From b796eb39dfff0ded902c550750be26545cc54c3d Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Wed, 2 Oct 2024 23:02:09 +0200 Subject: [PATCH 12/16] Make WebsocketHandler public --- src/HTTPConnection.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/HTTPConnection.hpp b/src/HTTPConnection.hpp index 5113fd3..efc57eb 100644 --- a/src/HTTPConnection.hpp +++ b/src/HTTPConnection.hpp @@ -107,6 +107,9 @@ class HTTPConnection : private ConnectionContext { CSTATE_ACTIVE, CSTATE_CLOSED } _clientState; + + //Websocket connection + WebsocketHandler * _wsHandler; private: void raiseError(uint16_t code, std::string reason); @@ -158,8 +161,6 @@ class HTTPConnection : private ConnectionContext { // Should we use keep alive bool _isKeepAlive; - //Websocket connection - WebsocketHandler * _wsHandler; }; From c7e05bf6fe623e18e4555e6868f921281f7fb881 Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Thu, 3 Oct 2024 00:17:53 +0200 Subject: [PATCH 13/16] Vulnerability!! WSHandler is created even at faile auth. Rogue clinets (like curl) who ignores http 401 will connect to websocket. This fix checks if the handshake was really done (HTTP 101 was replied). --- src/HTTPConnection.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index deb9101..ebfca48 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -529,8 +529,7 @@ void HTTPConnection::loop() { } // Finally, after the handshake is done, we create the WebsocketHandler and change the internal state. - //if(websocketRequested) { - if(websocketRequested &&resolvedResource.getMatchingNode()->_nodeType == WEBSOCKET) { + if(websocketRequested && res.getStatusCode() == 101 &&resolvedResource.getMatchingNode()->_nodeType == WEBSOCKET) { _wsHandler = ((WebsocketNode*)resolvedResource.getMatchingNode())->newHandler(); _wsHandler->initialize(this); // make websocket with this connection _connectionState = STATE_WEBSOCKET; From 1e518ace9b9b899d214f685021227936e9774a5d Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Mon, 7 Oct 2024 00:04:07 +0200 Subject: [PATCH 14/16] Merge branch pr/bligeti/2 into 'master' - IDF 5 support --- CHANGELOG.md | 15 +- example.conf | 9 + example.crt | 15 ++ src/ConnectionContext.hpp | 6 +- src/HTTPConnection.cpp | 5 +- src/HTTPConnection.hpp | 3 +- src/HTTPResponse.hpp | 3 +- src/HTTPSConnection.cpp | 57 ++--- src/HTTPSConnection.hpp | 11 +- src/HTTPSServer.cpp | 71 ++---- src/HTTPSServer.hpp | 10 +- src/SSLCert.cpp | 481 ++++++++++++++++++++------------------ src/WebsocketHandler.cpp | 4 + 13 files changed, 342 insertions(+), 348 deletions(-) create mode 100644 example.conf create mode 100644 example.crt diff --git a/CHANGELOG.md b/CHANGELOG.md index f9ba97b..4b48fbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,13 @@ # Changelog -## [pending (master)](https://github.com/fhessel/esp32_https_server/tree/master) +## [v1.1.1](https://github.com/jackjansen/esp32_idf5_https_server/tree/master) -New functionality: - -– - -Bug fixes: - -– +- Addressed issues with esp32-arduino-core v3 and esp-idf 5.0 -Breaking changes: +## [v1.1.0](https://github.com/jackjansen/esp32_idf5_https_server/tree/master) -– +- Compatible with ESP-IDF 5.0 +- Use esp-tls in stead of openssl ## [v1.0.0](https://github.com/fhessel/esp32_https_server/releases/tag/v1.0.0) diff --git a/example.conf b/example.conf new file mode 100644 index 0000000..01f46b1 --- /dev/null +++ b/example.conf @@ -0,0 +1,9 @@ +[ req ] +distinguished_name = req_distinguished_name +prompt = no +[ req_distinguished_name ] +C = DE +ST = BE +L = Berlin +O = MyCompany +CN = esp32.local diff --git a/example.crt b/example.crt new file mode 100644 index 0000000..a27ff33 --- /dev/null +++ b/example.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICYTCCAcqgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJERTEL +MAkGA1UECAwCQkUxDzANBgNVBAcMBkJlcmxpbjESMBAGA1UECgwJTXlDb21wYW55 +MRMwEQYDVQQDDApteWNhLmxvY2FsMB4XDTI0MDcwOTEwMTEwN1oXDTM0MDcwNzEw +MTEwN1owVTELMAkGA1UEBhMCREUxCzAJBgNVBAgMAkJFMQ8wDQYDVQQHDAZCZXJs +aW4xEjAQBgNVBAoMCU15Q29tcGFueTEUMBIGA1UEAwwLZXNwMzIubG9jYWwwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK/aY9jhRfEAgfu3KeTNQ1T2CshDP12e +benmLPnnVG830HQhMLIe1itN/f0tPTguUYtOBgUS9w2zeZEdm6aqeskkkV55Wnmz +IhGNg/cuwl/zp98NbOsZ4Rwcjp5dtL5w8UnlIsK8PsFntRWHQOthgaKH3YzyGg65 +ZtPKD13/ZGXbAgMBAAGjQjBAMB0GA1UdDgQWBBTBnWcv/0066SQSwr7nvZc0bg8B +fzAfBgNVHSMEGDAWgBTCqpgyA21IXR4Maq4makkkGgy66TANBgkqhkiG9w0BAQsF +AAOBgQAV0W4470+7/P5bRd94GYyF16/DR1W/H4NITptAJsMGjdyOaRVQnebCYP73 +idqMu9LUk0XGqG7StMys5n0VatMjhqOKrZF67wYEgGlaPYTRfpHEDMCPDLB/myYC +OpkxBG45CHzNz2tABRxsfPXN4+8bZpz0y6LUoeQD/ZMcMmZ2sA== +-----END CERTIFICATE----- diff --git a/src/ConnectionContext.hpp b/src/ConnectionContext.hpp index da88964..6778cd7 100644 --- a/src/ConnectionContext.hpp +++ b/src/ConnectionContext.hpp @@ -5,9 +5,9 @@ #include // Required for SSL -#include "openssl/ssl.h" -#undef read - +//#include "openssl/ssl.h" +//#undef read +#include namespace httpsserver { class WebsocketHandler; diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index ebfca48..4cd2188 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -1,5 +1,6 @@ #include "HTTPConnection.hpp" - +#include "mbedtls/base64.h" +#include "mbedtls/sha1.h" namespace httpsserver { HTTPConnection::HTTPConnection(ResourceResolver * resResolver): @@ -679,7 +680,7 @@ void handleWebsocketHandshake(HTTPRequest * req, HTTPResponse * res) { std::string websocketKeyResponseHash(std::string const &key) { std::string newKey = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; uint8_t shaData[HTTPS_SHA1_LENGTH]; - esp_sha(SHA1, (uint8_t*)newKey.data(), newKey.length(), shaData); + mbedtls_sha1((uint8_t*)newKey.data(), newKey.length(), shaData); // Get output size required for base64 representation size_t b64BufferSize = 0; diff --git a/src/HTTPConnection.hpp b/src/HTTPConnection.hpp index efc57eb..2430ea4 100644 --- a/src/HTTPConnection.hpp +++ b/src/HTTPConnection.hpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include // Required for sockets diff --git a/src/HTTPResponse.hpp b/src/HTTPResponse.hpp index 7bd1758..2ff5c88 100644 --- a/src/HTTPResponse.hpp +++ b/src/HTTPResponse.hpp @@ -9,7 +9,8 @@ #undef write #include -#include +//#include +#include #include "util.hpp" diff --git a/src/HTTPSConnection.cpp b/src/HTTPSConnection.cpp index 29aca4a..b769c93 100644 --- a/src/HTTPSConnection.cpp +++ b/src/HTTPSConnection.cpp @@ -5,7 +5,7 @@ namespace httpsserver { HTTPSConnection::HTTPSConnection(ResourceResolver * resResolver): HTTPConnection(resResolver) { - _ssl = NULL; + _ssl = esp_tls_init(); } HTTPSConnection::~HTTPSConnection() { @@ -22,42 +22,32 @@ bool HTTPSConnection::isSecure() { * * The call WILL BLOCK if accept(serverSocketID) blocks. So use select() to check for that in advance. */ -int HTTPSConnection::initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeaders *defaultHeaders) { +int HTTPSConnection::initialize(int serverSocketID, esp_tls_cfg_server_t * cfgSrv, HTTPHeaders *defaultHeaders) { if (_connectionState == STATE_UNDEFINED) { // Let the base class connect the plain tcp socket int resSocket = HTTPConnection::initialize(serverSocketID, defaultHeaders); - + HTTPS_LOGI("Cert len:%d, apn:%s\n",cfgSrv->servercert_bytes,cfgSrv->alpn_protos[0]); // Build up SSL Connection context if the socket has been created successfully if (resSocket >= 0) { - - _ssl = SSL_new(sslCtx); - - if (_ssl) { + int res=esp_tls_server_session_create(cfgSrv,resSocket,_ssl); + if (0==res) { + esp_tls_cfg_server_session_tickets_init(cfgSrv); + _cfg = cfgSrv; // Bind SSL to the socket - int success = SSL_set_fd(_ssl, resSocket); - if (success) { - - // Perform the handshake - success = SSL_accept(_ssl); - if (success) { + if (ESP_OK == esp_tls_get_conn_sockfd(_ssl,&resSocket)) { return resSocket; - } else { - HTTPS_LOGE("SSL_accept failed. Aborting handshake. FID=%d", resSocket); - } } else { - HTTPS_LOGE("SSL_set_fd failed. Aborting handshake. FID=%d", resSocket); + HTTPS_LOGE("SSL_accept failed. Aborting handshake. FID=%d", resSocket); } } else { - HTTPS_LOGE("SSL_new failed. Aborting handshake. FID=%d", resSocket); + HTTPS_LOGE("SSL_new failed. Aborting handshake. Error=%d", res); } } else { HTTPS_LOGE("Could not accept() new connection. FID=%d", resSocket); } - _connectionState = STATE_ERROR; _clientState = CSTATE_ACTIVE; - // This will only be called if the connection could not be established and cleanup // variables like _ssl etc. closeConnection(); @@ -86,18 +76,10 @@ void HTTPSConnection::closeConnection() { } // Try to tear down SSL while we are in the _shutdownTS timeout period or if an error occurred if (_ssl) { - if(_connectionState == STATE_ERROR || SSL_shutdown(_ssl) == 0) { - // SSL_shutdown will return 1 as soon as the client answered with close notify - // This means we are safe to close the socket - SSL_free(_ssl); - _ssl = NULL; - } else if (_shutdownTS + HTTPS_SHUTDOWN_TIMEOUT < millis()) { - // The timeout has been hit, we force SSL shutdown now by freeing the context - SSL_free(_ssl); - _ssl = NULL; - HTTPS_LOGW("SSL_shutdown did not receive close notification from the client"); - _connectionState = STATE_ERROR; - } + esp_tls_cfg_server_session_tickets_free(_cfg); + esp_tls_server_session_delete(_ssl); + _ssl = NULL; + _connectionState = STATE_ERROR; } // If SSL has been brought down, close the socket @@ -107,23 +89,24 @@ void HTTPSConnection::closeConnection() { } size_t HTTPSConnection::writeBuffer(byte* buffer, size_t length) { - return SSL_write(_ssl, buffer, length); + return esp_tls_conn_write(_ssl,buffer,length);// SSL_write(_ssl, buffer, length); } size_t HTTPSConnection::readBytesToBuffer(byte* buffer, size_t length) { - int ret = SSL_read(_ssl, buffer, length); + int ret = esp_tls_conn_read(_ssl, buffer, length); if (ret < 0) { - HTTPS_LOGD("SSL_read error: %d", SSL_get_error(_ssl, ret)); + //HTTPS_LOGD("SSL_read error: %d", SSL_get_error(_ssl, ret)); + HTTPS_LOGD("SSL_read error"); } return ret; } size_t HTTPSConnection::pendingByteCount() { - return SSL_pending(_ssl); + return esp_tls_get_bytes_avail(_ssl); } bool HTTPSConnection::canReadData() { - return HTTPConnection::canReadData() || (SSL_pending(_ssl) > 0); + return HTTPConnection::canReadData() || (esp_tls_get_bytes_avail(_ssl) > 0); } } /* namespace httpsserver */ diff --git a/src/HTTPSConnection.hpp b/src/HTTPSConnection.hpp index 8adbce5..6b0efa0 100644 --- a/src/HTTPSConnection.hpp +++ b/src/HTTPSConnection.hpp @@ -6,8 +6,9 @@ #include // Required for SSL -#include "openssl/ssl.h" -#undef read +//#include "openssl/ssl.h" +//#undef read +#include // Required for sockets #include "lwip/netdb.h" @@ -34,7 +35,7 @@ class HTTPSConnection : public HTTPConnection { HTTPSConnection(ResourceResolver * resResolver); virtual ~HTTPSConnection(); - virtual int initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeaders *defaultHeaders); + virtual int initialize(int serverSocketID,esp_tls_cfg_server_t * cfgSrv, HTTPHeaders *defaultHeaders); virtual void closeConnection(); virtual bool isSecure(); @@ -49,8 +50,8 @@ class HTTPSConnection : public HTTPConnection { private: // SSL context for this connection - SSL * _ssl; - + esp_tls_t * _ssl; + esp_tls_cfg_server_t * _cfg; }; } /* namespace httpsserver */ diff --git a/src/HTTPSServer.cpp b/src/HTTPSServer.cpp index 4d8352d..249e5ce 100644 --- a/src/HTTPSServer.cpp +++ b/src/HTTPSServer.cpp @@ -2,17 +2,24 @@ namespace httpsserver { +constexpr const char * alpn_protos[] = { "http/1.1", NULL } ; HTTPSServer::HTTPSServer(SSLCert * cert, const uint16_t port, const uint8_t maxConnections, const in_addr_t bindAddress): HTTPServer(port, maxConnections, bindAddress), _cert(cert) { - // Configure runtime data - _sslctx = NULL; + _cfg = new esp_tls_cfg_server(); + _cfg->alpn_protos = (const char **)alpn_protos; + _cfg->cacert_buf = NULL; + _cfg->cacert_bytes = 0; + _cfg->servercert_buf =cert->getCertData(); + _cfg->servercert_bytes = cert->getCertLength(); + _cfg->serverkey_buf= cert->getPKData(); + _cfg->serverkey_bytes= cert->getPKLength(); } HTTPSServer::~HTTPSServer() { - + free(_cfg); } /** @@ -20,24 +27,15 @@ HTTPSServer::~HTTPSServer() { */ uint8_t HTTPSServer::setupSocket() { if (!isRunning()) { - if (!setupSSLCTX()) { - Serial.println("setupSSLCTX failed"); - return 0; - } - - if (!setupCert()) { - Serial.println("setupCert failed"); - SSL_CTX_free(_sslctx); - _sslctx = NULL; - return 0; - } + _cfg->servercert_buf= _cert->getCertData(); + _cfg->servercert_bytes = _cert->getCertLength(); + _cfg->serverkey_buf= _cert->getPKData(); + _cfg->serverkey_bytes= _cert->getPKLength(); if (HTTPServer::setupSocket()) { return 1; } else { Serial.println("setupSockets failed"); - SSL_CTX_free(_sslctx); - _sslctx = NULL; return 0; } } else { @@ -49,30 +47,12 @@ void HTTPSServer::teardownSocket() { HTTPServer::teardownSocket(); - // Tear down the SSL context - SSL_CTX_free(_sslctx); - _sslctx = NULL; } int HTTPSServer::createConnection(int idx) { HTTPSConnection * newConnection = new HTTPSConnection(this); _connections[idx] = newConnection; - return newConnection->initialize(_socket, _sslctx, &_defaultHeaders); -} - -/** - * This method configures the ssl context that is used for the server - */ -uint8_t HTTPSServer::setupSSLCTX() { - _sslctx = SSL_CTX_new(TLSv1_2_server_method()); - if (_sslctx) { - // Set SSL Timeout to 5 minutes - SSL_CTX_set_timeout(_sslctx, 300); - return 1; - } else { - _sslctx = NULL; - return 0; - } + return newConnection->initialize(_socket, _cfg , &_defaultHeaders); } /** @@ -81,22 +61,11 @@ uint8_t HTTPSServer::setupSSLCTX() { */ uint8_t HTTPSServer::setupCert() { // Configure the certificate first - uint8_t ret = SSL_CTX_use_certificate_ASN1( - _sslctx, - _cert->getCertLength(), - _cert->getCertData() - ); - - // Then set the private key accordingly - if (ret) { - ret = SSL_CTX_use_RSAPrivateKey_ASN1( - _sslctx, - _cert->getPKData(), - _cert->getPKLength() - ); - } - - return ret; + _cfg->servercert_buf= _cert->getCertData(); + _cfg->servercert_bytes = _cert->getCertLength(); + _cfg->serverkey_buf= _cert->getPKData(); + _cfg->serverkey_bytes= _cert->getPKLength(); + return 1; } } /* namespace httpsserver */ diff --git a/src/HTTPSServer.hpp b/src/HTTPSServer.hpp index 68596bf..5e87430 100644 --- a/src/HTTPSServer.hpp +++ b/src/HTTPSServer.hpp @@ -8,8 +8,9 @@ #include // Required for SSL -#include "openssl/ssl.h" -#undef read +//#include "openssl/ssl.h" +#include +//#undef read // Internal includes #include "HTTPServer.hpp" @@ -31,20 +32,19 @@ class HTTPSServer : public HTTPServer { public: HTTPSServer(SSLCert * cert, const uint16_t portHTTPS = 443, const uint8_t maxConnections = 4, const in_addr_t bindAddress = 0); virtual ~HTTPSServer(); - + virtual esp_tls_cfg_server_t *getConfig() {return _cfg;} private: // Static configuration. Port, keys, etc. ==================== // Certificate that should be used (includes private key) SSLCert * _cert; //// Runtime data ============================================ - SSL_CTX * _sslctx; + esp_tls_cfg_server_t * _cfg; // Status of the server: Are we running, or not? // Setup functions virtual uint8_t setupSocket(); virtual void teardownSocket(); - uint8_t setupSSLCTX(); uint8_t setupCert(); // Helper functions diff --git a/src/SSLCert.cpp b/src/SSLCert.cpp index 3df7073..fe608fd 100644 --- a/src/SSLCert.cpp +++ b/src/SSLCert.cpp @@ -3,306 +3,321 @@ namespace httpsserver { SSLCert::SSLCert(unsigned char * certData, uint16_t certLength, unsigned char * pkData, uint16_t pkLength): - _certLength(certLength), - _certData(certData), - _pkLength(pkLength), - _pkData(pkData) { + _certLength(certLength), + _certData(certData), + _pkLength(pkLength), + _pkData(pkData) { } SSLCert::~SSLCert() { - // TODO Auto-generated destructor stub + // TODO Auto-generated destructor stub } uint16_t SSLCert::getCertLength() { - return _certLength; + return _certLength; } uint16_t SSLCert::getPKLength() { - return _pkLength; + return _pkLength; } unsigned char * SSLCert::getCertData() { - return _certData; + return _certData; } unsigned char * SSLCert::getPKData() { - return _pkData; + return _pkData; } void SSLCert::setPK(unsigned char * pkData, uint16_t length) { - _pkData = pkData; - _pkLength = length; + _pkData = pkData; + _pkLength = length; } void SSLCert::setCert(unsigned char * certData, uint16_t length) { - _certData = certData; - _certLength = length; + _certData = certData; + _certLength = length; } void SSLCert::clear() { - for(uint16_t i = 0; i < _certLength; i++) _certData[i]=0; - delete _certData; - _certLength = 0; + for(uint16_t i = 0; i < _certLength; i++) _certData[i]=0; + delete _certData; + _certLength = 0; - for(uint16_t i = 0; i < _pkLength; i++) _pkData[i] = 0; - delete _pkData; - _pkLength = 0; + for(uint16_t i = 0; i < _pkLength; i++) _pkData[i] = 0; + delete _pkData; + _pkLength = 0; } #ifndef HTTPS_DISABLE_SELFSIGNING /** * Function to create the key for a self-signed certificate. - * + * * Writes private key as DER in certCtx - * + * * Based on programs/pkey/gen_key.c */ static int gen_key(SSLCert &certCtx, SSLKeySize keySize) { - // Initialize the entropy source - mbedtls_entropy_context entropy; - mbedtls_entropy_init( &entropy ); - - // Initialize the RNG - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_ctr_drbg_init( &ctr_drbg ); - int rngRes = mbedtls_ctr_drbg_seed( - &ctr_drbg, mbedtls_entropy_func, &entropy, - NULL, 0 - ); - if (rngRes != 0) { - mbedtls_entropy_free( &entropy ); - return HTTPS_SERVER_ERROR_KEYGEN_RNG; - } - - // Initialize the private key - mbedtls_pk_context key; - mbedtls_pk_init( &key ); - int resPkSetup = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ); - if ( resPkSetup != 0) { - mbedtls_ctr_drbg_free( &ctr_drbg ); - mbedtls_entropy_free( &entropy ); - return HTTPS_SERVER_ERROR_KEYGEN_SETUP_PK; - } - - // Actual key generation - int resPkGen = mbedtls_rsa_gen_key( - mbedtls_pk_rsa( key ), - mbedtls_ctr_drbg_random, - &ctr_drbg, - keySize, - 65537 - ); - if ( resPkGen != 0) { - mbedtls_pk_free( &key ); + // Initialize the entropy source + mbedtls_entropy_context entropy; + mbedtls_entropy_init( &entropy ); + + // Initialize the RNG + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ctr_drbg_init( &ctr_drbg ); + int rngRes = mbedtls_ctr_drbg_seed( + &ctr_drbg, mbedtls_entropy_func, &entropy, + NULL, 0 + ); + if (rngRes != 0) { + mbedtls_entropy_free( &entropy ); + return HTTPS_SERVER_ERROR_KEYGEN_RNG; + } + + // Initialize the private key + mbedtls_pk_context key; + mbedtls_pk_init( &key ); + int resPkSetup = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ); + if ( resPkSetup != 0) { + mbedtls_ctr_drbg_free( &ctr_drbg ); + mbedtls_entropy_free( &entropy ); + return HTTPS_SERVER_ERROR_KEYGEN_SETUP_PK; + } + + // Actual key generation + int resPkGen = mbedtls_rsa_gen_key( + mbedtls_pk_rsa( key ), + mbedtls_ctr_drbg_random, + &ctr_drbg, + keySize, + 65537 + ); + if ( resPkGen != 0) { + mbedtls_pk_free( &key ); + mbedtls_ctr_drbg_free( &ctr_drbg ); + mbedtls_entropy_free( &entropy ); + return HTTPS_SERVER_ERROR_KEYGEN_GEN_PK; + } + + // Free the entropy source and the RNG as they are no longer needed mbedtls_ctr_drbg_free( &ctr_drbg ); mbedtls_entropy_free( &entropy ); - return HTTPS_SERVER_ERROR_KEYGEN_GEN_PK; - } - // Free the entropy source and the RNG as they are no longer needed - mbedtls_ctr_drbg_free( &ctr_drbg ); - mbedtls_entropy_free( &entropy ); - - // Allocate the space on the heap, as stack size is quite limited - unsigned char * output_buf = new unsigned char[4096]; - if (output_buf == NULL) { - mbedtls_pk_free( &key ); - return HTTPS_SERVER_ERROR_KEY_OUT_OF_MEM; - } - memset(output_buf, 0, 4096); - - // Write the key to the temporary buffer and determine its length - int resPkWrite = mbedtls_pk_write_key_der( &key, output_buf, 4096 ); - if (resPkWrite < 0) { - delete[] output_buf; - mbedtls_pk_free( &key ); - return HTTPS_SERVER_ERROR_KEY_WRITE_PK; - } - size_t pkLength = resPkWrite; - unsigned char *pkOffset = output_buf + sizeof(unsigned char) * 4096 - pkLength; - - // Copy the key into a new, fitting space on the heap - unsigned char * output_pk = new unsigned char[pkLength]; - if (output_pk == NULL) { + // Allocate the space on the heap, as stack size is quite limited + unsigned char * output_buf = new unsigned char[4096]; + if (output_buf == NULL) { + mbedtls_pk_free( &key ); + return HTTPS_SERVER_ERROR_KEY_OUT_OF_MEM; + } + memset(output_buf, 0, 4096); + + // Write the key to the temporary buffer and determine its length + int resPkWrite = mbedtls_pk_write_key_der( &key, output_buf, 4096 ); + if (resPkWrite < 0) { + delete[] output_buf; + mbedtls_pk_free( &key ); + return HTTPS_SERVER_ERROR_KEY_WRITE_PK; + } + size_t pkLength = resPkWrite; + unsigned char *pkOffset = output_buf + sizeof(unsigned char) * 4096 - pkLength; + + // Copy the key into a new, fitting space on the heap + unsigned char * output_pk = new unsigned char[pkLength]; + if (output_pk == NULL) { + delete[] output_buf; + mbedtls_pk_free( &key ); + return HTTPS_SERVER_ERROR_KEY_WRITE_PK; + } + memcpy(output_pk, pkOffset, pkLength); + + // Clean up the temporary buffer and clear the key context delete[] output_buf; mbedtls_pk_free( &key ); - return HTTPS_SERVER_ERROR_KEY_WRITE_PK; - } - memcpy(output_pk, pkOffset, pkLength); - - // Clean up the temporary buffer and clear the key context - delete[] output_buf; - mbedtls_pk_free( &key ); - // Set the private key in the context - certCtx.setPK(output_pk, pkLength); + // Set the private key in the context + certCtx.setPK(output_pk, pkLength); - return 0; + return 0; } /** * Function to generate the X509 certificate data for a private key - * + * * Writes certificate in certCtx * * Based on programs/x509/cert_write.c */ static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom, std::string validityTo) { - int funcRes = 0; - int stepRes = 0; - - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_pk_context key; - mbedtls_x509write_cert crt; - mbedtls_mpi serial; - unsigned char * primary_buffer; - unsigned char *certOffset; - unsigned char * output_buffer; - size_t certLength; - - // Make a C-friendly version of the distinguished name - char dn_cstr[dn.length()+1]; - strcpy(dn_cstr, dn.c_str()); - - // Initialize the entropy source - mbedtls_entropy_init( &entropy ); - - // Initialize the RNG - mbedtls_ctr_drbg_init( &ctr_drbg ); - stepRes = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 ); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_RNG; - goto error_after_entropy; - } - - mbedtls_pk_init( &key ); - stepRes = mbedtls_pk_parse_key( &key, certCtx.getPKData(), certCtx.getPKLength(), NULL, 0 ); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_READKEY; - goto error_after_key; - } - - // Start configuring the certificate - mbedtls_x509write_crt_init( &crt ); - // Set version and hash algorithm - mbedtls_x509write_crt_set_version( &crt, MBEDTLS_X509_CRT_VERSION_3 ); - mbedtls_x509write_crt_set_md_alg( &crt, MBEDTLS_MD_SHA256 ); - - // Set the keys (same key as we self-sign) - mbedtls_x509write_crt_set_subject_key( &crt, &key ); - mbedtls_x509write_crt_set_issuer_key( &crt, &key ); - - // Set issuer and subject (same, as we self-sign) - stepRes = mbedtls_x509write_crt_set_subject_name( &crt, dn_cstr ); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_NAME; - goto error_after_cert; - } - stepRes = mbedtls_x509write_crt_set_issuer_name( &crt, dn_cstr ); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_NAME; - goto error_after_cert; - } - - // Set the validity of the certificate. At the moment, it's fixed from 2019 to end of 2029. - stepRes = mbedtls_x509write_crt_set_validity( &crt, validityFrom.c_str(), validityTo.c_str()); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_VALIDITY; - goto error_after_cert; - } - - // Make this a CA certificate - stepRes = mbedtls_x509write_crt_set_basic_constraints( &crt, 1, 0 ); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_VALIDITY; - goto error_after_cert; - } - - // Initialize the serial number - mbedtls_mpi_init( &serial ); - stepRes = mbedtls_mpi_read_string( &serial, 10, "1" ); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL; - goto error_after_cert_serial; - } - stepRes = mbedtls_x509write_crt_set_serial( &crt, &serial ); - if (stepRes != 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL; - goto error_after_cert_serial; - } - - // Create buffer to write the certificate - primary_buffer = new unsigned char[4096]; - if (primary_buffer == NULL) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_OUT_OF_MEM; - goto error_after_cert_serial; - } - - // Write the actual certificate - stepRes = mbedtls_x509write_crt_der(&crt, primary_buffer, 4096, mbedtls_ctr_drbg_random, &ctr_drbg ); - if (stepRes < 0) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_WRITE; - goto error_after_primary_buffer; - } - - // Create a matching buffer - certLength = stepRes; - certOffset = primary_buffer + sizeof(unsigned char) * 4096 - certLength; - - // Copy the cert into a new, fitting space on the heap - output_buffer = new unsigned char[certLength]; - if (output_buffer == NULL) { - funcRes = HTTPS_SERVER_ERROR_CERTGEN_OUT_OF_MEM; - goto error_after_primary_buffer; - } - memcpy(output_buffer, certOffset, certLength); - - // Configure the cert in the context - certCtx.setCert(output_buffer, certLength); - - // Run through the cleanup process + int funcRes = 0; + int stepRes = 0; + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_pk_context key; + mbedtls_x509write_cert crt; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + const char *serial = "peer"; +#else + mbedtls_mpi serial; +#endif + + unsigned char * primary_buffer; + unsigned char *certOffset; + unsigned char * output_buffer; + size_t certLength; + + // Make a C-friendly version of the distinguished name + char dn_cstr[dn.length()+1]; + strcpy(dn_cstr, dn.c_str()); + + // Initialize the entropy source + mbedtls_entropy_init( &entropy ); + + // Initialize the RNG + mbedtls_ctr_drbg_init( &ctr_drbg ); + stepRes = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 ); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_RNG; + goto error_after_entropy; + } +#if MBEDTLS_VERSION_NUMBER < 0x03040000 + mbedtls_pk_init( &key ); + stepRes = mbedtls_pk_parse_key( &key, certCtx.getPKData(), certCtx.getPKLength(), NULL, 0 ); +#else + stepRes = mbedtls_pk_parse_key( &key, + certCtx.getPKData(), + certCtx.getPKLength(), + NULL, 0, NULL, NULL); +#endif + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_READKEY; + goto error_after_key; + } + // Start configuring the certificate + mbedtls_x509write_crt_init( &crt ); + // Set version and hash algorithm + mbedtls_x509write_crt_set_version( &crt, MBEDTLS_X509_CRT_VERSION_3 ); + mbedtls_x509write_crt_set_md_alg( &crt, MBEDTLS_MD_SHA256 ); + + // Set the keys (same key as we self-sign) + mbedtls_x509write_crt_set_subject_key( &crt, &key ); + mbedtls_x509write_crt_set_issuer_key( &crt, &key ); + + // Set issuer and subject (same, as we self-sign) + stepRes = mbedtls_x509write_crt_set_subject_name( &crt, dn_cstr ); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_NAME; + goto error_after_cert; + } + stepRes = mbedtls_x509write_crt_set_issuer_name( &crt, dn_cstr ); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_NAME; + goto error_after_cert; + } + + // Set the validity of the certificate. At the moment, it's fixed from 2019 to end of 2029. + stepRes = mbedtls_x509write_crt_set_validity( &crt, validityFrom.c_str(), validityTo.c_str()); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_VALIDITY; + goto error_after_cert; + } + + // Make this a CA certificate + stepRes = mbedtls_x509write_crt_set_basic_constraints( &crt, 1, 0 ); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_VALIDITY; + goto error_after_cert; + } + +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + mbedtls_x509write_crt_set_serial_raw(&crt, (unsigned char *) serial, strlen(serial)); +#else + // generate random serial number + mbedtls_mpi_init( &serial ); + stepRes = mbedtls_mpi_fill_random( &serial, 10, mbedtls_ctr_drbg_random, &ctr_drbg ); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL; + goto error_after_cert_serial; + } + stepRes = mbedtls_x509write_crt_set_serial( &crt, &serial ); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL; + goto error_after_cert_serial; + } +#endif + // Create buffer to write the certificate + primary_buffer = new unsigned char[4096]; + if (primary_buffer == NULL) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_OUT_OF_MEM; + goto error_after_cert_serial; + } + + // Write the actual certificate + stepRes = mbedtls_x509write_crt_der(&crt, primary_buffer, 4096, mbedtls_ctr_drbg_random, &ctr_drbg ); + if (stepRes < 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_WRITE; + goto error_after_primary_buffer; + } + + // Create a matching buffer + certLength = stepRes; + certOffset = primary_buffer + sizeof(unsigned char) * 4096 - certLength; + + // Copy the cert into a new, fitting space on the heap + output_buffer = new unsigned char[certLength]; + if (output_buffer == NULL) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_OUT_OF_MEM; + goto error_after_primary_buffer; + } + memcpy(output_buffer, certOffset, certLength); + + // Configure the cert in the context + certCtx.setCert(output_buffer, certLength); + + // Run through the cleanup process error_after_primary_buffer: - delete[] primary_buffer; + delete[] primary_buffer; error_after_cert_serial: - mbedtls_mpi_free( &serial ); +#if MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_mpi_free( &serial ); +#endif error_after_cert: - mbedtls_x509write_crt_free( &crt ); + mbedtls_x509write_crt_free( &crt ); error_after_key: - mbedtls_pk_free(&key); + mbedtls_pk_free(&key); error_after_entropy: - mbedtls_ctr_drbg_free( &ctr_drbg ); - mbedtls_entropy_free( &entropy ); - return funcRes; + mbedtls_ctr_drbg_free( &ctr_drbg ); + mbedtls_entropy_free( &entropy ); + return funcRes; } int createSelfSignedCert(SSLCert &certCtx, SSLKeySize keySize, std::string dn, std::string validFrom, std::string validUntil) { - // Add the private key - int keyRes = gen_key(certCtx, keySize); - if (keyRes != 0) { - // Key-generation failed, return the failure code - return keyRes; - } - - // Add the self-signed certificate - int certRes = cert_write(certCtx, dn, validFrom, validUntil); - if (certRes != 0) { - // Cert writing failed, reset the pk and return failure code - certCtx.setPK(NULL, 0); - return certRes; - } - - // If all went well, return 0 - return 0; + // Add the private key + int keyRes = gen_key(certCtx, keySize); + if (keyRes != 0) { + // Key-generation failed, return the failure code + return keyRes; + } + + // Add the self-signed certificate + int certRes = cert_write(certCtx, dn, validFrom, validUntil); + if (certRes != 0) { + // Cert writing failed, reset the pk and return failure code + certCtx.setPK(NULL, 0); + return certRes; + } + + // If all went well, return 0 + return 0; } #endif // !HTTPS_DISABLE_SELFSIGNING diff --git a/src/WebsocketHandler.cpp b/src/WebsocketHandler.cpp index 2ab459b..c7d7a25 100644 --- a/src/WebsocketHandler.cpp +++ b/src/WebsocketHandler.cpp @@ -1,5 +1,9 @@ #include "WebsocketHandler.hpp" +#ifndef TAG +static const char *TAG = "WebsocketHandler"; +#endif + namespace httpsserver { /** From b4e9f30adbdc94066dd7dfafa8a90c3c9b1586e7 Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Mon, 21 Oct 2024 00:23:36 +0200 Subject: [PATCH 15/16] fix idf 5 compile error --- src/WebsocketHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WebsocketHandler.cpp b/src/WebsocketHandler.cpp index c7d7a25..b444889 100644 --- a/src/WebsocketHandler.cpp +++ b/src/WebsocketHandler.cpp @@ -117,7 +117,7 @@ int WebsocketHandler::read() { if (payloadLen == 0) { HTTPS_LOGW("WS payload not present"); } else { - HTTPS_LOGI("WS payload: length=%d", payloadLen); + HTTPS_LOGI("WS payload: length=%d", (int)payloadLen); } switch(frame.opCode) { From dc21271135f39c8a6504e9e36294c629d10b75e2 Mon Sep 17 00:00:00 2001 From: Balnt Ligeti Date: Sun, 27 Oct 2024 16:04:11 +0100 Subject: [PATCH 16/16] Fixes for ESPIDF5 --- library.json | 2 +- library.properties | 6 ++--- src/ConnectionContext.hpp | 2 -- src/HTTPConnection.cpp | 7 +++--- src/HTTPSConnection.cpp | 27 +++++++++++---------- src/HTTPSConnection.hpp | 1 - src/HTTPSServer.cpp | 50 +++++++++++++++++++-------------------- src/HTTPSServer.hpp | 5 ++-- 8 files changed, 49 insertions(+), 51 deletions(-) diff --git a/library.json b/library.json index b5b0777..0542003 100644 --- a/library.json +++ b/library.json @@ -8,7 +8,7 @@ "url": "https://github.com/bligeti/esp32_https_server.git" }, "license": "MIT", - "version": "1.0.0", + "version": "1.1.0", "frameworks": "arduino", "platforms": ["espressif32"] } diff --git a/library.properties b/library.properties index fdb20c3..5ccdfb9 100644 --- a/library.properties +++ b/library.properties @@ -1,7 +1,7 @@ name=ESP32_HTTPS_Server -version=1.0.0 -author=Frank Hessel -maintainer=Frank Hessel +version=1.1.0 +author=bligeti +maintainer=bligeti sentence=Alternative ESP32 Webserver implementation for the ESP32, supporting HTTPS and HTTP. paragraph=The library provides TLS support and simultaneous connections. It can be used to run an HTTP or HTTPS server, or both in parallel. The server's resources are defined through handler and middleware functions, giving an easy start to everyone who has worked with frameworks like Express or Servlets before. category=Communication diff --git a/src/ConnectionContext.hpp b/src/ConnectionContext.hpp index 6778cd7..e6a2a46 100644 --- a/src/ConnectionContext.hpp +++ b/src/ConnectionContext.hpp @@ -5,8 +5,6 @@ #include // Required for SSL -//#include "openssl/ssl.h" -//#undef read #include namespace httpsserver { diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index 4cd2188..809852c 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -588,19 +588,20 @@ void HTTPConnection::loop() { break; case STATE_WEBSOCKET: // Do handling of the websocket refreshTimeout(); // don't timeout websocket connection - if(pendingBufferSize() > 0) { + //re-checking the _connectionState since it can change at pendingBufferSize() + if(pendingBufferSize() > 0 && !isClosed() ) { HTTPS_LOGD("Calling WS handler, FID=%d", _socket); _wsHandler->loop(); } // If the client closed the connection unexpectedly - if (_clientState == CSTATE_CLOSED) { + if (_clientState == CSTATE_CLOSED && !isClosed()) { HTTPS_LOGI("WS lost client, calling onClose, FID=%d", _socket); _wsHandler->onClose(); } // If the handler has terminated the connection, clean up and close the socket too - if (_wsHandler != nullptr){ + if (!isClosed()){ if (_wsHandler->closed() || _clientState == CSTATE_CLOSED) { HTTPS_LOGI("WS closed, freeing Handler, FID=%d", _socket); delete _wsHandler; diff --git a/src/HTTPSConnection.cpp b/src/HTTPSConnection.cpp index b769c93..c978d80 100644 --- a/src/HTTPSConnection.cpp +++ b/src/HTTPSConnection.cpp @@ -5,7 +5,7 @@ namespace httpsserver { HTTPSConnection::HTTPSConnection(ResourceResolver * resResolver): HTTPConnection(resResolver) { - _ssl = esp_tls_init(); + _ssl = NULL; } HTTPSConnection::~HTTPSConnection() { @@ -26,21 +26,22 @@ int HTTPSConnection::initialize(int serverSocketID, esp_tls_cfg_server_t * cfgSr if (_connectionState == STATE_UNDEFINED) { // Let the base class connect the plain tcp socket int resSocket = HTTPConnection::initialize(serverSocketID, defaultHeaders); - HTTPS_LOGI("Cert len:%d, apn:%s\n",cfgSrv->servercert_bytes,cfgSrv->alpn_protos[0]); + HTTPS_LOGI("Cert len:%d, apn:%s",cfgSrv->servercert_bytes,cfgSrv->alpn_protos[0]); // Build up SSL Connection context if the socket has been created successfully if (resSocket >= 0) { + + _ssl = esp_tls_init(); + + if (!_ssl) { + HTTPS_LOGE("esp_tls_init failed. FID=%d", resSocket); + return -1; + } + int res=esp_tls_server_session_create(cfgSrv,resSocket,_ssl); - if (0==res) { - esp_tls_cfg_server_session_tickets_init(cfgSrv); - _cfg = cfgSrv; - // Bind SSL to the socket - if (ESP_OK == esp_tls_get_conn_sockfd(_ssl,&resSocket)) { - return resSocket; - } else { - HTTPS_LOGE("SSL_accept failed. Aborting handshake. FID=%d", resSocket); - } + if (res != 0) { + HTTPS_LOGE("esp_tls_server_session_create failed. FID=%d, Error=%d", resSocket, res); } else { - HTTPS_LOGE("SSL_new failed. Aborting handshake. Error=%d", res); + return resSocket; } } else { @@ -76,7 +77,7 @@ void HTTPSConnection::closeConnection() { } // Try to tear down SSL while we are in the _shutdownTS timeout period or if an error occurred if (_ssl) { - esp_tls_cfg_server_session_tickets_free(_cfg); + esp_tls_server_session_delete(_ssl); _ssl = NULL; _connectionState = STATE_ERROR; diff --git a/src/HTTPSConnection.hpp b/src/HTTPSConnection.hpp index 6b0efa0..c4b1500 100644 --- a/src/HTTPSConnection.hpp +++ b/src/HTTPSConnection.hpp @@ -51,7 +51,6 @@ class HTTPSConnection : public HTTPConnection { private: // SSL context for this connection esp_tls_t * _ssl; - esp_tls_cfg_server_t * _cfg; }; } /* namespace httpsserver */ diff --git a/src/HTTPSServer.cpp b/src/HTTPSServer.cpp index 249e5ce..098e669 100644 --- a/src/HTTPSServer.cpp +++ b/src/HTTPSServer.cpp @@ -8,18 +8,12 @@ HTTPSServer::HTTPSServer(SSLCert * cert, const uint16_t port, const uint8_t maxC HTTPServer(port, maxConnections, bindAddress), _cert(cert) { // Configure runtime data - _cfg = new esp_tls_cfg_server(); - _cfg->alpn_protos = (const char **)alpn_protos; - _cfg->cacert_buf = NULL; - _cfg->cacert_bytes = 0; - _cfg->servercert_buf =cert->getCertData(); - _cfg->servercert_bytes = cert->getCertLength(); - _cfg->serverkey_buf= cert->getPKData(); - _cfg->serverkey_bytes= cert->getPKLength(); + _cfg = NULL; + } HTTPSServer::~HTTPSServer() { - free(_cfg); + } /** @@ -27,15 +21,24 @@ HTTPSServer::~HTTPSServer() { */ uint8_t HTTPSServer::setupSocket() { if (!isRunning()) { - _cfg->servercert_buf= _cert->getCertData(); + _cfg = new esp_tls_cfg_server(); + _cfg->alpn_protos = (const char **)alpn_protos; + _cfg->cacert_buf = NULL; + _cfg->cacert_bytes = 0; + _cfg->servercert_buf = _cert->getCertData(); _cfg->servercert_bytes = _cert->getCertLength(); - _cfg->serverkey_buf= _cert->getPKData(); - _cfg->serverkey_bytes= _cert->getPKLength(); + _cfg->serverkey_buf = _cert->getPKData(); + _cfg->serverkey_bytes = _cert->getPKLength(); + + esp_err_t ret = esp_tls_cfg_server_session_tickets_init(_cfg); + if ( ret != ESP_OK ) { + HTTPS_LOGE("Failed to init session ticket support. error: %s", esp_err_to_name(ret)); + } if (HTTPServer::setupSocket()) { return 1; } else { - Serial.println("setupSockets failed"); + HTTPS_LOGE("HTTPServer::setupSocket failed"); return 0; } } else { @@ -47,6 +50,15 @@ void HTTPSServer::teardownSocket() { HTTPServer::teardownSocket(); + if (_cfg) { + //esp_tls_cfg_server_session_tickets_free(_cfg); + free((void *)_cfg->servercert_buf); + free((void *)_cfg->serverkey_buf); + } + delete _cfg; + _cfg = NULL; + + } int HTTPSServer::createConnection(int idx) { @@ -55,17 +67,5 @@ int HTTPSServer::createConnection(int idx) { return newConnection->initialize(_socket, _cfg , &_defaultHeaders); } -/** - * This method configures the certificate and private key for the given - * ssl context - */ -uint8_t HTTPSServer::setupCert() { - // Configure the certificate first - _cfg->servercert_buf= _cert->getCertData(); - _cfg->servercert_bytes = _cert->getCertLength(); - _cfg->serverkey_buf= _cert->getPKData(); - _cfg->serverkey_bytes= _cert->getPKLength(); - return 1; -} } /* namespace httpsserver */ diff --git a/src/HTTPSServer.hpp b/src/HTTPSServer.hpp index 5e87430..563e9ae 100644 --- a/src/HTTPSServer.hpp +++ b/src/HTTPSServer.hpp @@ -32,7 +32,6 @@ class HTTPSServer : public HTTPServer { public: HTTPSServer(SSLCert * cert, const uint16_t portHTTPS = 443, const uint8_t maxConnections = 4, const in_addr_t bindAddress = 0); virtual ~HTTPSServer(); - virtual esp_tls_cfg_server_t *getConfig() {return _cfg;} private: // Static configuration. Port, keys, etc. ==================== // Certificate that should be used (includes private key) @@ -45,7 +44,7 @@ class HTTPSServer : public HTTPServer { // Setup functions virtual uint8_t setupSocket(); virtual void teardownSocket(); - uint8_t setupCert(); + // Helper functions virtual int createConnection(int idx); @@ -53,4 +52,4 @@ class HTTPSServer : public HTTPServer { } /* namespace httpsserver */ -#endif /* SRC_HTTPSSERVER_HPP_ */ +#endif /* SRC_HTTPSSERVER_HPP_ */ \ No newline at end of file