Skip to content

Commit cc284bb

Browse files
earlephilhowerdevyte
authored andcommitted
Allow cipher specification for BearSSL (#5151)
* Allow cipher specification for BearSSL BearSSL has many more ciphers than axTLS, but they are more compute intensive and slower. Add an option to use only the same, limited security, axTLS ciphers as well as allow users to specify any suite of ciphers they want using standard BearSSL formats. Fixes #5110 * Rename methods to avoid axtls references. * Allow std::vector to set a list of allowed ciphers For C++ afficionados, allow std::vectors to be passed in to the setCipher() routine. The BearSSL object will now keep a copy of any set ciphers and free on object destruction. These custom lists should normally only be 1-4 entries long, so it is not expected to be a memory hog having this extra copy.
1 parent 1a44f79 commit cc284bb

File tree

3 files changed

+78
-5
lines changed

3 files changed

+78
-5
lines changed

Diff for: libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino

+27
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,32 @@ BearSSL does verify the notValidBefore/After fields.
193193
fetchURL(&client, host, port, path);
194194
}
195195

196+
void fetchFaster() {
197+
Serial.printf(R"EOF(
198+
The ciphers used to set up the SSL connection can be configured to
199+
only support faster but less secure ciphers. If you care about security
200+
you won't want to do this. If you need to maximize battery life, these
201+
may make sense
202+
)EOF");
203+
BearSSL::WiFiClientSecure client;
204+
client.setInsecure();
205+
uint32_t now = millis();
206+
fetchURL(&client, host, port, path);
207+
uint32_t delta = millis() - now;
208+
client.setInsecure();
209+
client.setCiphersLessSecure();
210+
now = millis();
211+
fetchURL(&client, host, port, path);
212+
uint32_t delta2 = millis() - now;
213+
std::vector<uint16_t> myCustomList = { BR_TLS_RSA_WITH_AES_256_CBC_SHA256, BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA };
214+
client.setInsecure();
215+
client.setCiphers(myCustomList);
216+
now = millis();
217+
fetchURL(&client, host, port, path);
218+
uint32_t delta3 = millis() - now;
219+
Serial.printf("Using more secure: %dms\nUsing less secure ciphers: %dms\nUsing custom cipher list: %dms\n", delta, delta2, delta3);
220+
}
221+
196222
void setup() {
197223
Serial.begin(115200);
198224
Serial.println();
@@ -220,6 +246,7 @@ void setup() {
220246
fetchSelfSigned();
221247
fetchKnownKey();
222248
fetchCertAuthority();
249+
fetchFaster();
223250
}
224251

225252

Diff for: libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp

+39-4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ void WiFiClientSecure::_clearAuthenticationSettings() {
8585

8686

8787
WiFiClientSecure::WiFiClientSecure() : WiFiClient() {
88+
_cipher_list = NULL;
89+
_cipher_cnt = 0;
8890
_clear();
8991
_clearAuthenticationSettings();
9092
_certStore = nullptr; // Don't want to remove cert store on a clear, should be long lived
@@ -101,6 +103,7 @@ WiFiClientSecure::~WiFiClientSecure() {
101103
_client->unref();
102104
_client = nullptr;
103105
}
106+
free(_cipher_list);
104107
_freeSSL();
105108
_local_bearssl_stack = nullptr; // Potentially delete it if we're the last SSL object
106109
if (_deleteChainKeyTA) {
@@ -685,6 +688,13 @@ extern "C" {
685688
BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
686689
};
687690

691+
// For apps which want to use less secure but faster ciphers, only
692+
static const uint16_t faster_suites_P[] PROGMEM = {
693+
BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
694+
BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
695+
BR_TLS_RSA_WITH_AES_256_CBC_SHA,
696+
BR_TLS_RSA_WITH_AES_128_CBC_SHA };
697+
688698
// Install hashes into the SSL engine
689699
static void br_ssl_client_install_hashes(br_ssl_engine_context *eng) {
690700
br_ssl_engine_set_hash(eng, br_md5_ID, &br_md5_vtable);
@@ -705,9 +715,9 @@ extern "C" {
705715
}
706716

707717
// Default initializion for our SSL clients
708-
static void br_ssl_client_base_init(br_ssl_client_context *cc) {
709-
uint16_t suites[sizeof(suites_P) / sizeof(uint16_t)];
710-
memcpy_P(suites, suites_P, sizeof(suites_P));
718+
static void br_ssl_client_base_init(br_ssl_client_context *cc, const uint16_t *cipher_list, int cipher_cnt) {
719+
uint16_t suites[cipher_cnt];
720+
memcpy_P(suites, cipher_list, cipher_cnt * sizeof(cipher_list[0]));
711721
br_ssl_client_zero(cc);
712722
br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
713723
br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0]));
@@ -726,6 +736,26 @@ extern "C" {
726736

727737
}
728738

739+
// Set custom list of ciphers
740+
bool WiFiClientSecure::setCiphers(const uint16_t *cipherAry, int cipherCount) {
741+
free(_cipher_list);
742+
_cipher_list = (uint16_t *)malloc(cipherCount * sizeof(uint16_t));
743+
if (!_cipher_list) {
744+
return false;
745+
}
746+
memcpy_P(_cipher_list, cipherAry, cipherCount * sizeof(uint16_t));
747+
_cipher_cnt = cipherCount;
748+
return true;
749+
}
750+
751+
bool WiFiClientSecure::setCiphersLessSecure() {
752+
return setCiphers(faster_suites_P, sizeof(faster_suites_P)/sizeof(faster_suites_P[0]));
753+
}
754+
755+
bool WiFiClientSecure::setCiphers(std::vector<uint16_t> list) {
756+
return setCiphers(&list[0], list.size());
757+
}
758+
729759
// Installs the appropriate X509 cert validation method for a client connection
730760
bool WiFiClientSecure::_installClientX509Validator() {
731761
if (_use_insecure || _use_fingerprint || _use_self_signed) {
@@ -787,7 +817,12 @@ bool WiFiClientSecure::_connectSSL(const char* hostName) {
787817
return false;
788818
}
789819

790-
br_ssl_client_base_init(_sc.get());
820+
// If no cipher list yet set, use defaults
821+
if (_cipher_list == NULL) {
822+
br_ssl_client_base_init(_sc.get(), suites_P, sizeof(suites_P) / sizeof(uint16_t));
823+
} else {
824+
br_ssl_client_base_init(_sc.get(), _cipher_list, _cipher_cnt);
825+
}
791826
// Only failure possible in the installation is OOM
792827
if (!_installClientX509Validator()) {
793828
_freeSSL();

Diff for: libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#ifndef wificlientbearssl_h
2525
#define wificlientbearssl_h
26+
#include <vector>
2627
#include "WiFiClient.h"
2728
#include <bearssl/bearssl.h>
2829
#include "BearSSLHelpers.h"
@@ -104,12 +105,18 @@ class WiFiClientSecure : public WiFiClient {
104105
_certStore = certStore;
105106
}
106107

108+
// Select specific ciphers (i.e. optimize for speed over security)
109+
// These may be in PROGMEM or RAM, either will run properly
110+
bool setCiphers(const uint16_t *cipherAry, int cipherCount);
111+
bool setCiphers(std::vector<uint16_t> list);
112+
bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
113+
107114
// Check for Maximum Fragment Length support for given len
108115
static bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len);
109116
static bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len);
110117
static bool probeMaxFragmentLength(const String host, uint16_t port, uint16_t len);
111118

112-
// AXTLS compatbile wrappers
119+
// AXTLS compatible wrappers
113120
bool verify(const char* fingerprint, const char* domain_name) { (void) fingerprint; (void) domain_name; return false; } // Can't handle this case, need app code changes
114121
bool verifyCertChain(const char* domain_name) { (void)domain_name; return connected(); } // If we're connected, the cert passed validation during handshake
115122

@@ -170,6 +177,10 @@ class WiFiClientSecure : public WiFiClient {
170177
const BearSSLPublicKey *_knownkey;
171178
unsigned _knownkey_usages;
172179

180+
// Custom cipher list pointer or NULL if default
181+
uint16_t *_cipher_list;
182+
uint8_t _cipher_cnt;
183+
173184
unsigned char *_recvapp_buf;
174185
size_t _recvapp_len;
175186

0 commit comments

Comments
 (0)