Skip to content

Commit 87b7d5e

Browse files
committed
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 #2256.
1 parent 9913e52 commit 87b7d5e

File tree

1 file changed

+112
-1
lines changed

1 file changed

+112
-1
lines changed

libraries/ESP8266WiFi/src/WiFiClientSecure.cpp

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern "C"
2626
{
2727
#include "osapi.h"
2828
#include "ets_sys.h"
29+
#include "queue.h"
2930
}
3031
#include <errno.h>
3132
#include "debug.h"
@@ -50,6 +51,28 @@ extern "C"
5051
#define SSL_DEBUG_OPTS 0
5152
#endif
5253

54+
55+
typedef struct BufferItem
56+
{
57+
size_t size;
58+
STAILQ_ENTRY(BufferItem) next;
59+
uint8_t data[0];
60+
61+
static BufferItem* Create(const uint8_t* data, size_t size)
62+
{
63+
BufferItem* newItem = (BufferItem*) calloc(1, sizeof(BufferItem) + size);
64+
if (newItem == nullptr) {
65+
return nullptr;
66+
}
67+
newItem->size = size;
68+
memcpy(newItem->data, data, size);
69+
return newItem;
70+
}
71+
72+
} BufferItem;
73+
74+
typedef STAILQ_HEAD(BufferList, BufferItem) BufferList;
75+
5376
class SSLContext
5477
{
5578
public:
@@ -59,6 +82,7 @@ class SSLContext
5982
_ssl_ctx = ssl_ctx_new(SSL_SERVER_VERIFY_LATER | SSL_DEBUG_OPTS | SSL_CONNECT_IN_PARTS | SSL_READ_BLOCKING | SSL_NO_DEFAULT_KEY, 0);
6083
}
6184
++_ssl_ctx_refcnt;
85+
STAILQ_INIT(&_writeBuffers);
6286
}
6387

6488
~SSLContext()
@@ -139,6 +163,10 @@ class SSLContext
139163
_available -= will_copy;
140164
if (_available == 0) {
141165
_read_ptr = nullptr;
166+
/* Send pending outgoing data, if any */
167+
if (_hasWriteBuffers()) {
168+
_writeBuffersSend();
169+
}
142170
}
143171
return will_copy;
144172
}
@@ -155,10 +183,34 @@ class SSLContext
155183
--_available;
156184
if (_available == 0) {
157185
_read_ptr = nullptr;
186+
/* Send pending outgoing data, if any */
187+
if (_hasWriteBuffers()) {
188+
_writeBuffersSend();
189+
}
158190
}
159191
return result;
160192
}
161193

194+
int write(const uint8_t* src, size_t size)
195+
{
196+
if (!_available) {
197+
if (_hasWriteBuffers()) {
198+
int rc = _writeBuffersSend();
199+
if (rc < 0) {
200+
return rc;
201+
}
202+
}
203+
return _write(src, size);
204+
}
205+
/* Some received data is still present in the axtls fragment buffer.
206+
We can't call ssl_write now, as that will overwrite the contents of
207+
the fragment buffer, corrupting the received data.
208+
Save a copy of the outgoing data, and call ssl_write when all
209+
recevied data has been consumed by the application.
210+
*/
211+
return _writeBufferAdd(src, size);
212+
}
213+
162214
int peek()
163215
{
164216
if (!_available) {
@@ -282,12 +334,71 @@ class SSLContext
282334
return _available;
283335
}
284336

337+
int _write(const uint8_t* src, size_t size)
338+
{
339+
if (!_ssl) {
340+
return 0;
341+
}
342+
343+
int rc = ssl_write(_ssl, src, size);
344+
if (rc >= 0) {
345+
return rc;
346+
}
347+
return rc;
348+
}
349+
350+
int _writeBufferAdd(const uint8_t* data, size_t size)
351+
{
352+
if (!_ssl) {
353+
return 0;
354+
}
355+
356+
BufferItem* newItem = BufferItem::Create(data, size);
357+
if (newItem == nullptr) {
358+
return SSL_NOT_OK;
359+
}
360+
STAILQ_INSERT_TAIL(&_writeBuffers, newItem, next);
361+
return size;
362+
}
363+
364+
int _writeBuffersSend()
365+
{
366+
BufferItem* it;
367+
BufferItem* tmp;
368+
STAILQ_FOREACH_SAFE(it, &_writeBuffers, next, tmp) {
369+
STAILQ_REMOVE_HEAD(&_writeBuffers, next);
370+
int rc = _write(it->data, it->size);
371+
free(it);
372+
if (rc < 0) {
373+
_writeBuffersDiscard();
374+
return rc;
375+
}
376+
}
377+
return 0;
378+
}
379+
380+
void _writeBuffersDiscard()
381+
{
382+
BufferItem* it;
383+
BufferItem* tmp;
384+
STAILQ_FOREACH_SAFE(it, &_writeBuffers, next, tmp) {
385+
STAILQ_REMOVE_HEAD(&_writeBuffers, next);
386+
free(it);
387+
}
388+
}
389+
390+
bool _hasWriteBuffers()
391+
{
392+
return !STAILQ_EMPTY(&_writeBuffers);
393+
}
394+
285395
static SSL_CTX* _ssl_ctx;
286396
static int _ssl_ctx_refcnt;
287397
SSL* _ssl = nullptr;
288398
int _refcnt = 0;
289399
const uint8_t* _read_ptr = nullptr;
290400
size_t _available = 0;
401+
BufferList _writeBuffers;
291402
bool _allowSelfSignedCerts = false;
292403
static ClientContext* s_io_ctx;
293404
};
@@ -371,7 +482,7 @@ size_t WiFiClientSecure::write(const uint8_t *buf, size_t size)
371482
return 0;
372483
}
373484

374-
int rc = ssl_write(*_ssl, buf, size);
485+
int rc = _ssl->write(buf, size);
375486
if (rc >= 0) {
376487
return rc;
377488
}

0 commit comments

Comments
 (0)