diff --git a/src/ConnectionContext.hpp b/src/ConnectionContext.hpp index da88964..f8db833 100644 --- a/src/ConnectionContext.hpp +++ b/src/ConnectionContext.hpp @@ -5,7 +5,7 @@ #include // Required for SSL -#include "openssl/ssl.h" +#include "mbedtls/ssl.h" #undef read namespace httpsserver { diff --git a/src/HTTPResponse.hpp b/src/HTTPResponse.hpp index 7bd1758..bcbc326 100644 --- a/src/HTTPResponse.hpp +++ b/src/HTTPResponse.hpp @@ -9,7 +9,7 @@ #undef write #include -#include +#include #include "util.hpp" diff --git a/src/HTTPSConnection.cpp b/src/HTTPSConnection.cpp index e0e3dd0..c114534 100644 --- a/src/HTTPSConnection.cpp +++ b/src/HTTPSConnection.cpp @@ -1,11 +1,13 @@ #include "HTTPSConnection.hpp" +#include "mbedtls/net_sockets.h" namespace httpsserver { HTTPSConnection::HTTPSConnection(ResourceResolver * resResolver): HTTPConnection(resResolver) { - _ssl = NULL; + _sslCreated = false; + _socket = 0; } HTTPSConnection::~HTTPSConnection() { @@ -17,12 +19,36 @@ bool HTTPSConnection::isSecure() { return true; } +bool HTTPSConnection::setup(mbedtls_ssl_config *sslConfig) { + mbedtls_ssl_init(&_ssl); + int res = mbedtls_ssl_setup(&_ssl, sslConfig); + if (res == 0) { + return true; + } else { + mbedtls_ssl_free(&_ssl); + return false; + } +} + +bool HTTPSConnection::handshake() { + int res; + while (true) { + res = mbedtls_ssl_handshake(&_ssl); + if (res == 0) { + return true; + } + if (res != MBEDTLS_ERR_SSL_WANT_READ && res != MBEDTLS_ERR_SSL_WANT_WRITE) { + return false; + } + } +} + /** * Initializes the connection from a server socket. * * 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, mbedtls_ssl_config *sslConfig, HTTPHeaders *defaultHeaders) { if (_connectionState == STATE_UNDEFINED) { // Let the base class connect the plain tcp socket int resSocket = HTTPConnection::initialize(serverSocketID, defaultHeaders); @@ -30,25 +56,21 @@ int HTTPSConnection::initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeader // Build up SSL Connection context if the socket has been created successfully if (resSocket >= 0) { - _ssl = SSL_new(sslCtx); + _socket = resSocket; + _sslCreated = setup(sslConfig); - if (_ssl) { + if (_sslCreated) { // Bind SSL to the socket - int success = SSL_set_fd(_ssl, resSocket); - if (success) { - - // Perform the handshake - success = SSL_accept(_ssl); - if (success) { - return resSocket; - } else { - HTTPS_LOGE("SSL_accept failed. Aborting handshake. FID=%d", resSocket); - } + mbedtls_ssl_set_bio(&_ssl, &_socket, mbedtls_net_send, mbedtls_net_recv, NULL); + + // Perform the handshake + if (handshake()) { + return resSocket; } else { - HTTPS_LOGE("SSL_set_fd failed. Aborting handshake. FID=%d", resSocket); + HTTPS_LOGE("SSL handshake failed. Aborting handshake. FID=%d", resSocket); } } else { - HTTPS_LOGE("SSL_new failed. Aborting handshake. FID=%d", resSocket); + HTTPS_LOGE("SSL setup failed. Aborting handshake. FID=%d", resSocket); } } else { @@ -66,6 +88,18 @@ int HTTPSConnection::initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeader return -1; } +int HTTPSConnection::shutdown() { + int res; + while (true) { + res = mbedtls_ssl_close_notify(&_ssl); + if (res == 0) { + return 1; + } + if (res != MBEDTLS_ERR_SSL_WANT_WRITE) { + return 0; + } + } +} void HTTPSConnection::closeConnection() { @@ -83,41 +117,53 @@ 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 + if (_sslCreated) { + if (_connectionState == STATE_ERROR || shutdown() == 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; + mbedtls_ssl_free(&_ssl); + _sslCreated = false; } 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"); + // The timeout has been hit, we force SSL shutdown now by resetting the session + mbedtls_ssl_free(&_ssl); + _sslCreated = false; + HTTPS_LOGW("SSL shutdown did not receive close notification from the client"); _connectionState = STATE_ERROR; } } // If SSL has been brought down, close the socket - if (!_ssl) { + if (!_sslCreated) { HTTPConnection::closeConnection(); } } size_t HTTPSConnection::writeBuffer(byte* buffer, size_t length) { - return SSL_write(_ssl, buffer, length); + while (true) { + int res = mbedtls_ssl_write(&_ssl, buffer, length); + if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) { + continue; + } + return res; + } } size_t HTTPSConnection::readBytesToBuffer(byte* buffer, size_t length) { - return SSL_read(_ssl, buffer, length); + while (true) { + int res = mbedtls_ssl_read(&_ssl, buffer, length); + if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) { + continue; + } + return res; + } } size_t HTTPSConnection::pendingByteCount() { - return SSL_pending(_ssl); + return mbedtls_ssl_get_bytes_avail(&_ssl); } bool HTTPSConnection::canReadData() { - return HTTPConnection::canReadData() || (SSL_pending(_ssl) > 0); + return HTTPConnection::canReadData() || (mbedtls_ssl_get_bytes_avail(&_ssl) > 0); } } /* namespace httpsserver */ diff --git a/src/HTTPSConnection.hpp b/src/HTTPSConnection.hpp index 8adbce5..0011ebe 100644 --- a/src/HTTPSConnection.hpp +++ b/src/HTTPSConnection.hpp @@ -6,7 +6,7 @@ #include // Required for SSL -#include "openssl/ssl.h" +#include "mbedtls/ssl.h" #undef read // Required for sockets @@ -34,9 +34,12 @@ class HTTPSConnection : public HTTPConnection { HTTPSConnection(ResourceResolver * resResolver); virtual ~HTTPSConnection(); - virtual int initialize(int serverSocketID, SSL_CTX * sslCtx, HTTPHeaders *defaultHeaders); + virtual int initialize(int serverSocketID, mbedtls_ssl_config *sslConfig, HTTPHeaders *defaultHeaders); virtual void closeConnection(); virtual bool isSecure(); + bool setup(mbedtls_ssl_config *sslConfig); + bool handshake(); + int shutdown(); protected: friend class HTTPRequest; @@ -49,7 +52,9 @@ class HTTPSConnection : public HTTPConnection { private: // SSL context for this connection - SSL * _ssl; + mbedtls_ssl_context _ssl; + bool _sslCreated; + int _socket; }; diff --git a/src/HTTPSServer.cpp b/src/HTTPSServer.cpp index 4d8352d..f930b2e 100644 --- a/src/HTTPSServer.cpp +++ b/src/HTTPSServer.cpp @@ -8,95 +8,87 @@ HTTPSServer::HTTPSServer(SSLCert * cert, const uint16_t port, const uint8_t maxC _cert(cert) { // Configure runtime data - _sslctx = NULL; + mbedtls_ssl_config_init(&_ssl_config); + mbedtls_x509_crt_init(&_ssl_cert); + mbedtls_pk_init(&_ssl_pk); + mbedtls_entropy_init(&_ssl_entropy); + mbedtls_ctr_drbg_init(&_ssl_ctr_drbg); + + mbedtls_ctr_drbg_seed(&_ssl_ctr_drbg, mbedtls_entropy_func, &_ssl_entropy, nullptr, 0); + mbedtls_ssl_conf_rng(&_ssl_config, mbedtls_ctr_drbg_random, &_ssl_ctr_drbg); } HTTPSServer::~HTTPSServer() { + mbedtls_ctr_drbg_init(&_ssl_ctr_drbg); + mbedtls_entropy_init(&_ssl_entropy); + mbedtls_pk_free(&_ssl_pk); + mbedtls_x509_crt_free(&_ssl_cert); + mbedtls_ssl_config_free(&_ssl_config); } /** * This method starts the server and begins to listen on the port */ 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; - } - - if (HTTPServer::setupSocket()) { - return 1; - } else { - Serial.println("setupSockets failed"); - SSL_CTX_free(_sslctx); - _sslctx = NULL; - return 0; - } - } else { + if (isRunning()) { return 1; } + + int res = mbedtls_ssl_config_defaults(&_ssl_config, + MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + if (res != 0) { + Serial.println("Setting SSL default config failed"); + return 0; + } + + if (setupCert() != 0) { + Serial.println("setupCert failed"); + return 0; + } + + if (!HTTPServer::setupSocket()) { + Serial.println("setupSockets failed"); + return 0; + } + + return 1; } 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, &_ssl_config, &_defaultHeaders); } /** * This method configures the certificate and private key for the given * ssl context */ -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() - ); +int HTTPSServer::setupCert() { + int res = 0; + + res = mbedtls_x509_crt_parse(&_ssl_cert, _cert->getCertData(), _cert->getCertLength()); + if (res != 0) { + return res; + } + +#if ESP_IDF_VERSION_MAJOR > 4 + res = mbedtls_pk_parse_key(&_ssl_pk, _cert->getPKData(), _cert->getPKLength(), nullptr, 0, + mbedtls_ctr_drbg_random, &_ssl_ctr_drbg); +#else + res = mbedtls_pk_parse_key(&_ssl_pk, _cert->getPKData(), _cert->getPKLength(), nullptr, 0); +#endif + if (res != 0) { + return res; } - return ret; + return mbedtls_ssl_conf_own_cert(&_ssl_config, &_ssl_cert, &_ssl_pk); } } /* namespace httpsserver */ diff --git a/src/HTTPSServer.hpp b/src/HTTPSServer.hpp index 68596bf..88ab3b5 100644 --- a/src/HTTPSServer.hpp +++ b/src/HTTPSServer.hpp @@ -8,7 +8,8 @@ #include // Required for SSL -#include "openssl/ssl.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_ciphersuites.h" #undef read // Internal includes @@ -38,14 +39,18 @@ class HTTPSServer : public HTTPServer { SSLCert * _cert; //// Runtime data ============================================ - SSL_CTX * _sslctx; + mbedtls_entropy_context _ssl_entropy; + mbedtls_ctr_drbg_context _ssl_ctr_drbg; + mbedtls_ssl_config _ssl_config; + mbedtls_x509_crt _ssl_cert; + mbedtls_pk_context _ssl_pk; + // Status of the server: Are we running, or not? // Setup functions virtual uint8_t setupSocket(); virtual void teardownSocket(); - uint8_t setupSSLCTX(); - uint8_t setupCert(); + int setupCert(); // Helper functions virtual int createConnection(int idx); diff --git a/src/SSLCert.cpp b/src/SSLCert.cpp index e8f3cd8..302cce9 100644 --- a/src/SSLCert.cpp +++ b/src/SSLCert.cpp @@ -181,7 +181,12 @@ static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom } mbedtls_pk_init( &key ); + +#if ESP_IDF_VERSION_MAJOR > 4 + stepRes = mbedtls_pk_parse_key( &key, certCtx.getPKData(), certCtx.getPKLength(), NULL, 0, mbedtls_entropy_func, &ctr_drbg ); +#else stepRes = mbedtls_pk_parse_key( &key, certCtx.getPKData(), certCtx.getPKLength(), NULL, 0 ); +#endif if (stepRes != 0) { funcRes = HTTPS_SERVER_ERROR_CERTGEN_READKEY; goto error_after_key; @@ -230,7 +235,17 @@ static int cert_write(SSLCert &certCtx, std::string dn, std::string validityFrom funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL; goto error_after_cert_serial; } +#if ESP_IDF_VERSION_MAJOR > 4 + unsigned char serial_bytes[10]; + stepRes = mbedtls_mpi_write_binary( &serial, serial_bytes, 10 ); + if (stepRes != 0) { + funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL; + goto error_after_cert_serial; + } + stepRes = mbedtls_x509write_crt_set_serial_raw( &crt, serial_bytes, 10 ); +#else stepRes = mbedtls_x509write_crt_set_serial( &crt, &serial ); +#endif if (stepRes != 0) { funcRes = HTTPS_SERVER_ERROR_CERTGEN_SERIAL; goto error_after_cert_serial;