1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

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.
This commit is contained in:
Earle F. Philhower, III 2018-09-21 07:47:20 -07:00 committed by Develo
parent 1a44f79a9e
commit cc284bb533
3 changed files with 78 additions and 5 deletions

View File

@ -193,6 +193,32 @@ BearSSL does verify the notValidBefore/After fields.
fetchURL(&client, host, port, path);
}
void fetchFaster() {
Serial.printf(R"EOF(
The ciphers used to set up the SSL connection can be configured to
only support faster but less secure ciphers. If you care about security
you won't want to do this. If you need to maximize battery life, these
may make sense
)EOF");
BearSSL::WiFiClientSecure client;
client.setInsecure();
uint32_t now = millis();
fetchURL(&client, host, port, path);
uint32_t delta = millis() - now;
client.setInsecure();
client.setCiphersLessSecure();
now = millis();
fetchURL(&client, host, port, path);
uint32_t delta2 = millis() - now;
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 };
client.setInsecure();
client.setCiphers(myCustomList);
now = millis();
fetchURL(&client, host, port, path);
uint32_t delta3 = millis() - now;
Serial.printf("Using more secure: %dms\nUsing less secure ciphers: %dms\nUsing custom cipher list: %dms\n", delta, delta2, delta3);
}
void setup() {
Serial.begin(115200);
Serial.println();
@ -220,6 +246,7 @@ void setup() {
fetchSelfSigned();
fetchKnownKey();
fetchCertAuthority();
fetchFaster();
}

View File

@ -85,6 +85,8 @@ void WiFiClientSecure::_clearAuthenticationSettings() {
WiFiClientSecure::WiFiClientSecure() : WiFiClient() {
_cipher_list = NULL;
_cipher_cnt = 0;
_clear();
_clearAuthenticationSettings();
_certStore = nullptr; // Don't want to remove cert store on a clear, should be long lived
@ -101,6 +103,7 @@ WiFiClientSecure::~WiFiClientSecure() {
_client->unref();
_client = nullptr;
}
free(_cipher_list);
_freeSSL();
_local_bearssl_stack = nullptr; // Potentially delete it if we're the last SSL object
if (_deleteChainKeyTA) {
@ -685,6 +688,13 @@ extern "C" {
BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
};
// For apps which want to use less secure but faster ciphers, only
static const uint16_t faster_suites_P[] PROGMEM = {
BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
BR_TLS_RSA_WITH_AES_256_CBC_SHA,
BR_TLS_RSA_WITH_AES_128_CBC_SHA };
// Install hashes into the SSL engine
static void br_ssl_client_install_hashes(br_ssl_engine_context *eng) {
br_ssl_engine_set_hash(eng, br_md5_ID, &br_md5_vtable);
@ -705,9 +715,9 @@ extern "C" {
}
// Default initializion for our SSL clients
static void br_ssl_client_base_init(br_ssl_client_context *cc) {
uint16_t suites[sizeof(suites_P) / sizeof(uint16_t)];
memcpy_P(suites, suites_P, sizeof(suites_P));
static void br_ssl_client_base_init(br_ssl_client_context *cc, const uint16_t *cipher_list, int cipher_cnt) {
uint16_t suites[cipher_cnt];
memcpy_P(suites, cipher_list, cipher_cnt * sizeof(cipher_list[0]));
br_ssl_client_zero(cc);
br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0]));
@ -726,6 +736,26 @@ extern "C" {
}
// Set custom list of ciphers
bool WiFiClientSecure::setCiphers(const uint16_t *cipherAry, int cipherCount) {
free(_cipher_list);
_cipher_list = (uint16_t *)malloc(cipherCount * sizeof(uint16_t));
if (!_cipher_list) {
return false;
}
memcpy_P(_cipher_list, cipherAry, cipherCount * sizeof(uint16_t));
_cipher_cnt = cipherCount;
return true;
}
bool WiFiClientSecure::setCiphersLessSecure() {
return setCiphers(faster_suites_P, sizeof(faster_suites_P)/sizeof(faster_suites_P[0]));
}
bool WiFiClientSecure::setCiphers(std::vector<uint16_t> list) {
return setCiphers(&list[0], list.size());
}
// Installs the appropriate X509 cert validation method for a client connection
bool WiFiClientSecure::_installClientX509Validator() {
if (_use_insecure || _use_fingerprint || _use_self_signed) {
@ -787,7 +817,12 @@ bool WiFiClientSecure::_connectSSL(const char* hostName) {
return false;
}
br_ssl_client_base_init(_sc.get());
// If no cipher list yet set, use defaults
if (_cipher_list == NULL) {
br_ssl_client_base_init(_sc.get(), suites_P, sizeof(suites_P) / sizeof(uint16_t));
} else {
br_ssl_client_base_init(_sc.get(), _cipher_list, _cipher_cnt);
}
// Only failure possible in the installation is OOM
if (!_installClientX509Validator()) {
_freeSSL();

View File

@ -23,6 +23,7 @@
#ifndef wificlientbearssl_h
#define wificlientbearssl_h
#include <vector>
#include "WiFiClient.h"
#include <bearssl/bearssl.h>
#include "BearSSLHelpers.h"
@ -104,12 +105,18 @@ class WiFiClientSecure : public WiFiClient {
_certStore = certStore;
}
// Select specific ciphers (i.e. optimize for speed over security)
// These may be in PROGMEM or RAM, either will run properly
bool setCiphers(const uint16_t *cipherAry, int cipherCount);
bool setCiphers(std::vector<uint16_t> list);
bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
// Check for Maximum Fragment Length support for given len
static bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len);
static bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len);
static bool probeMaxFragmentLength(const String host, uint16_t port, uint16_t len);
// AXTLS compatbile wrappers
// AXTLS compatible wrappers
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
bool verifyCertChain(const char* domain_name) { (void)domain_name; return connected(); } // If we're connected, the cert passed validation during handshake
@ -170,6 +177,10 @@ class WiFiClientSecure : public WiFiClient {
const BearSSLPublicKey *_knownkey;
unsigned _knownkey_usages;
// Custom cipher list pointer or NULL if default
uint16_t *_cipher_list;
uint8_t _cipher_cnt;
unsigned char *_recvapp_buf;
size_t _recvapp_len;