diff --git a/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino b/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino index 18f72f14da..6d016f702e 100644 --- a/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino +++ b/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino @@ -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 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(); } diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp index 45b7eec62c..44471d640c 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp @@ -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 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(); diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h index 365cb9bd01..aff2935c80 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h @@ -23,6 +23,7 @@ #ifndef wificlientbearssl_h #define wificlientbearssl_h +#include #include "WiFiClient.h" #include #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 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;