Skip to content

Commit 2f83ca9

Browse files
Add br_thunk_* calls to do ref counting, painting
Add reference counting br_thunk_add/del_ref() to replace stack handling code in the class. Add in stack painting and max usage calculation.
1 parent 39b6d36 commit 2f83ca9

File tree

5 files changed

+129
-138
lines changed

5 files changed

+129
-138
lines changed

libraries/ESP8266WiFi/src/BearSSLThunks.S

-100
This file was deleted.
+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
BearSSLThunks.c - Allow use second stack for BearSSL calls
3+
4+
BearSSL uses a significant amount of stack space, much larger than
5+
the default Arduino core stack. These routines handle swapping
6+
between a secondary, user-allocated stack on the heap and the real
7+
stack.
8+
9+
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
10+
11+
This library is free software; you can redistribute it and/or
12+
modify it under the terms of the GNU Lesser General Public
13+
License as published by the Free Software Foundation; either
14+
version 2.1 of the License, or (at your option) any later version.
15+
16+
This library is distributed in the hope that it will be useful,
17+
but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19+
Lesser General Public License for more details.
20+
21+
You should have received a copy of the GNU Lesser General Public
22+
License along with this library; if not, write to the Free Software
23+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24+
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
25+
*/
26+
27+
#include <stdint.h>
28+
#include <stdlib.h>
29+
30+
static uint32_t *_stackPtr = NULL;
31+
static uint32_t *_stackTop = NULL;
32+
static uint32_t _refcnt = 0;
33+
34+
#define _stackSize (4500/4)
35+
#define _stackPaint 0xdeadbeef
36+
37+
/* Add a reference, and allocate the stack if necessary */
38+
void br_thunk_add_ref()
39+
{
40+
_refcnt++;
41+
if (_refcnt == 1) {
42+
_stackPtr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
43+
_stackTop = _stackPtr + _stackSize - 1;
44+
for (int i=0; i < _stackSize; i++) {
45+
_stackPtr[i] = _stackPaint;
46+
}
47+
}
48+
}
49+
50+
/* Drop a reference, and free stack if no more in use */
51+
void br_thunk_del_ref()
52+
{
53+
if (_refcnt == 0) {
54+
/* Error! */
55+
return;
56+
}
57+
_refcnt--;
58+
if (!_refcnt) {
59+
free(_stackPtr);
60+
_stackPtr = NULL;
61+
_stackTop = NULL;
62+
}
63+
}
64+
65+
/* Return the number of bytes ever used since the stack was created */
66+
uint32_t br_thunk_get_max_usage()
67+
{
68+
uint32_t cnt = 0;
69+
70+
/* No stack == no usage by definition! */
71+
if (!_stackPtr) {
72+
return 0;
73+
}
74+
75+
for (cnt=0; (cnt < _stackSize) && (_stackPtr[cnt] == _stackPaint); cnt++) {
76+
/* Noop, all work done in for() */
77+
}
78+
return 4 * (_stackSize - cnt);
79+
}
80+
81+
__asm("\n\
82+
.data\n\
83+
.align 4\n\
84+
_saveStack: .word 0x00000000\n\
85+
\n\
86+
.text\n\
87+
.literal_position\n\
88+
\n\
89+
.macro thunk fcnName\n\
90+
.text\n\
91+
.global thunk_\\fcnName\n\
92+
.type thunk_\\fcnName, @function\n\
93+
.align 4\n\
94+
thunk_\\fcnName:\n\
95+
addi a1, a1, -16 /* Allocate space for saved registers on stack */\n\
96+
s32i a0, a1, 12 /* Store A0, trounced by calls */\n\
97+
s32i a15, a1, 8 /* Store A15 (our temporary one) */\n\
98+
movi a15, _saveStack /* Store A1(SP) in temp space */\n\
99+
s32i a1, a15, 0\n\
100+
movi a15, _stackTop /* Load A1(SP) with thunk stack */\n\
101+
l32i.n a1, a15, 0\n\
102+
call0 \\fcnName /* Do the call */\n\
103+
movi a15, _saveStack /* Restore A1(SP) */\n\
104+
l32i.n a1, a15, 0\n\
105+
l32i.n a15, a1, 8 /* Restore the saved registers */\n\
106+
l32i.n a0, a1, 12\n\
107+
addi a1, a1, 16 /* Free up stack and return to caller */\n\
108+
ret\n\
109+
.size thunk_\\fcnName, . - thunk_\\fcnName\n\
110+
.endm\n\
111+
\n\
112+
thunk br_ssl_engine_recvapp_ack\n\
113+
thunk br_ssl_engine_recvapp_buf\n\
114+
thunk br_ssl_engine_recvrec_ack\n\
115+
thunk br_ssl_engine_recvrec_buf\n\
116+
thunk br_ssl_engine_sendapp_ack\n\
117+
thunk br_ssl_engine_sendapp_buf\n\
118+
thunk br_ssl_engine_sendrec_ack\n\
119+
thunk br_ssl_engine_sendrec_buf");

libraries/ESP8266WiFi/src/BearSSLThunks.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
esp8266_thunks.h - Allow use second stack for BearSSL calls
2+
BearSSLThunks.h - Allow use second stack for BearSSL calls
33
44
BearSSL uses a significant amount of stack space, much larger than
55
the default Arduino core stack. These routines handle swapping
@@ -31,7 +31,9 @@ extern "C" {
3131

3232
#include <bearssl/bearssl.h>
3333

34-
extern void SetThunkStackEnd(unsigned int *end);
34+
extern void br_thunk_add_ref();
35+
extern void br_thunk_del_ref();
36+
extern uint32_t br_thunk_get_max_usage();
3537

3638
extern unsigned char *thunk_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len);
3739
extern void thunk_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);

libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp

+6-29
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern "C" {
4444
#include "c_types.h"
4545
#include "coredecls.h"
4646

47+
// The BearSSL thunks in use for now
4748
#define br_ssl_engine_recvapp_ack thunk_br_ssl_engine_recvapp_ack
4849
#define br_ssl_engine_recvapp_buf thunk_br_ssl_engine_recvapp_buf
4950
#define br_ssl_engine_recvrec_ack thunk_br_ssl_engine_recvrec_ack
@@ -53,16 +54,8 @@ extern "C" {
5354
#define br_ssl_engine_sendrec_ack thunk_br_ssl_engine_sendrec_ack
5455
#define br_ssl_engine_sendrec_buf thunk_br_ssl_engine_sendrec_buf
5556

56-
5757
namespace BearSSL {
5858

59-
// BearSSL needs a very large stack, larger than the entire ESP8266 Arduino
60-
// default one. This shared_pointer is allocated on first use and cleared
61-
// on last cleanup, with only one stack no matter how many SSL objects.
62-
std::shared_ptr<uint8_t> WiFiClientSecure::_bearssl_stack = nullptr;
63-
64-
65-
6659
void WiFiClientSecure::_clear() {
6760
// TLS handshake may take more than the 5 second default timeout
6861
_timeout = 15000;
@@ -102,18 +95,7 @@ WiFiClientSecure::WiFiClientSecure() : WiFiClient() {
10295
_clear();
10396
_clearAuthenticationSettings();
10497
_certStore = nullptr; // Don't want to remove cert store on a clear, should be long lived
105-
_ensureStackAvailable();
106-
_local_bearssl_stack = _bearssl_stack;
107-
}
108-
109-
void WiFiClientSecure::_ensureStackAvailable() {
110-
if (!_bearssl_stack) {
111-
const int stacksize = 4500; // Empirically determined stack for EC and RSA connections
112-
_bearssl_stack = std::shared_ptr<uint8_t>(new uint8_t[stacksize], std::default_delete<uint8_t[]>());
113-
unsigned int *endOfStack = (unsigned int *)_bearssl_stack.get();
114-
endOfStack += (stacksize/4) - 1;
115-
SetThunkStackEnd(endOfStack);
116-
}
98+
br_thunk_add_ref();
11799
}
118100

119101
WiFiClientSecure::~WiFiClientSecure() {
@@ -123,11 +105,8 @@ WiFiClientSecure::~WiFiClientSecure() {
123105
}
124106
free(_cipher_list);
125107
_freeSSL();
126-
_local_bearssl_stack = nullptr;
127-
// If there are no other uses than the initial creation, free the stack
128-
if (_bearssl_stack.use_count() == 1) {
129-
_bearssl_stack = nullptr;
130-
}
108+
// Serial.printf("Max stack usage: %d bytes\n", br_thunk_get_max_usage());
109+
br_thunk_del_ref();
131110
if (_deleteChainKeyTA) {
132111
delete _ta;
133112
delete _chain;
@@ -140,8 +119,7 @@ WiFiClientSecure::WiFiClientSecure(ClientContext* client,
140119
int iobuf_in_size, int iobuf_out_size, const BearSSLX509List *client_CA_ta) {
141120
_clear();
142121
_clearAuthenticationSettings();
143-
_ensureStackAvailable();
144-
_local_bearssl_stack = _bearssl_stack;
122+
br_thunk_add_ref();
145123
_iobuf_in_size = iobuf_in_size;
146124
_iobuf_out_size = iobuf_out_size;
147125
_client = client;
@@ -159,8 +137,7 @@ WiFiClientSecure::WiFiClientSecure(ClientContext *client,
159137
int iobuf_in_size, int iobuf_out_size, const BearSSLX509List *client_CA_ta) {
160138
_clear();
161139
_clearAuthenticationSettings();
162-
_ensureStackAvailable();
163-
_local_bearssl_stack = _bearssl_stack;
140+
br_thunk_add_ref();
164141
_iobuf_in_size = iobuf_in_size;
165142
_iobuf_out_size = iobuf_out_size;
166143
_client = client;

libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h

-7
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,6 @@ class WiFiClientSecure : public WiFiClient {
225225

226226
// AXTLS compatible mode needs to delete the stored certs and keys on destruction
227227
bool _deleteChainKeyTA;
228-
229-
private:
230-
// Single memory buffer used for BearSSL auxilliary stack, insead of growing main Arduino stack for all apps
231-
static std::shared_ptr<uint8_t> _bearssl_stack;
232-
void _ensureStackAvailable(); // Allocate the stack if necessary
233-
// The local copy, only used to enable a reference count
234-
std::shared_ptr<uint8_t> _local_bearssl_stack;
235228
};
236229

237230
};

0 commit comments

Comments
 (0)