From a6922dc0ec72275f64c791142773f89f7e80d4ba Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 26 Dec 2017 07:53:31 +0800 Subject: [PATCH 1/2] WiFiClientSecure: don't decrypt when testing for 'connected' --- libraries/ESP8266WiFi/src/WiFiClientSecure.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp index e7bcb1a4e4..5dac12a3dc 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp @@ -193,6 +193,12 @@ class SSLContext return cb; } + // similar to availble, but doesn't return exact size + bool hasData() + { + return _available > 0 || (s_io_ctx && s_io_ctx->getSize() > 0); + } + bool loadObject(int type, Stream& stream, size_t size) { std::unique_ptr buf(new uint8_t[size]); @@ -458,7 +464,7 @@ err x N N uint8_t WiFiClientSecure::connected() { if (_ssl) { - if (_ssl->available()) { + if (_ssl->hasData()) { return true; } if (_client && _client->state() == ESTABLISHED && _ssl->connected()) { From 02bc5384fd95eab131e5088a1b16a1c3fbe06614 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 26 Dec 2017 11:46:55 +0800 Subject: [PATCH 2/2] WiFiClientSecure: don't trash unread decrypted data when writing When application requests to write data, check if there is any unread decrypted data left. If there is, don't write immediately, but save the data to be written. When all decrypted data has been consumed by the application, send out the saved outgoing data. Fixes https://github.com/esp8266/Arduino/issues/2256. --- .../ESP8266WiFi/src/WiFiClientSecure.cpp | 102 +++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp index 5dac12a3dc..55d16addaa 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp @@ -27,6 +27,7 @@ extern "C" #include "osapi.h" #include "ets_sys.h" } +#include #include #include "debug.h" #include "ESP8266WiFi.h" @@ -50,6 +51,26 @@ extern "C" #define SSL_DEBUG_OPTS 0 #endif + +typedef struct BufferItem +{ + BufferItem(const uint8_t* data_, size_t size_) + : size(size_), data(new uint8_t[size]) + { + if (data.get() != nullptr) { + memcpy(data.get(), data_, size); + } else { + DEBUGV(":wcs alloc %d failed\r\n", size_); + size = 0; + } + } + + size_t size; + std::unique_ptr data; +} BufferItem; + +typedef std::list BufferList; + class SSLContext { public: @@ -139,6 +160,10 @@ class SSLContext _available -= will_copy; if (_available == 0) { _read_ptr = nullptr; + /* Send pending outgoing data, if any */ + if (_hasWriteBuffers()) { + _writeBuffersSend(); + } } return will_copy; } @@ -155,10 +180,34 @@ class SSLContext --_available; if (_available == 0) { _read_ptr = nullptr; + /* Send pending outgoing data, if any */ + if (_hasWriteBuffers()) { + _writeBuffersSend(); + } } return result; } + int write(const uint8_t* src, size_t size) + { + if (!_available) { + if (_hasWriteBuffers()) { + int rc = _writeBuffersSend(); + if (rc < 0) { + return rc; + } + } + return _write(src, size); + } + /* Some received data is still present in the axtls fragment buffer. + We can't call ssl_write now, as that will overwrite the contents of + the fragment buffer, corrupting the received data. + Save a copy of the outgoing data, and call ssl_write when all + recevied data has been consumed by the application. + */ + return _writeBufferAdd(src, size); + } + int peek() { if (!_available) { @@ -288,12 +337,63 @@ class SSLContext return _available; } + int _write(const uint8_t* src, size_t size) + { + if (!_ssl) { + return 0; + } + + int rc = ssl_write(_ssl, src, size); + if (rc >= 0) { + return rc; + } + DEBUGV(":wcs write rc=%d\r\n", rc); + return rc; + } + + int _writeBufferAdd(const uint8_t* data, size_t size) + { + if (!_ssl) { + return 0; + } + + _writeBuffers.emplace_back(data, size); + if (_writeBuffers.back().data.get() == nullptr) { + _writeBuffers.pop_back(); + return 0; + } + return size; + } + + int _writeBuffersSend() + { + while (!_writeBuffers.empty()) { + auto& first = _writeBuffers.front(); + int rc = _write(first.data.get(), first.size); + _writeBuffers.pop_front(); + if (rc < 0) { + if (_hasWriteBuffers()) { + DEBUGV(":wcs _writeBuffersSend dropping unsent data\r\n"); + _writeBuffers.clear(); + } + return rc; + } + } + return 0; + } + + bool _hasWriteBuffers() + { + return !_writeBuffers.empty(); + } + static SSL_CTX* _ssl_ctx; static int _ssl_ctx_refcnt; SSL* _ssl = nullptr; int _refcnt = 0; const uint8_t* _read_ptr = nullptr; size_t _available = 0; + BufferList _writeBuffers; bool _allowSelfSignedCerts = false; static ClientContext* s_io_ctx; }; @@ -377,7 +477,7 @@ size_t WiFiClientSecure::write(const uint8_t *buf, size_t size) return 0; } - int rc = ssl_write(*_ssl, buf, size); + int rc = _ssl->write(buf, size); if (rc >= 0) { return rc; }