From 09cdacdc09ea4f69501d3600b74b8a0c6ccf025a Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Thu, 21 Jun 2018 11:19:31 +0200 Subject: [PATCH] BearSSL client: warn user on misconfiguration, allow flash string for fingerprint +update HTTPSRequest.ino example --- .../examples/HTTPSRequest/HTTPSRequest.ino | 46 ++++++++++++++++++- .../src/WiFiClientSecureBearSSL-fp.cpp | 36 +++++++++++++++ .../src/WiFiClientSecureBearSSL.cpp | 5 ++ .../ESP8266WiFi/src/WiFiClientSecureBearSSL.h | 12 ++++- 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL-fp.cpp diff --git a/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino b/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino index e6aaedee8e..926ee3e72d 100644 --- a/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino +++ b/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino @@ -19,6 +19,8 @@ #include #include +#define DEPRECATED_SSL_WITH_AXTLS 0 // use 1 for axTLS, 0 for BearSSL + const char* ssid = "........"; const char* password = "........"; @@ -27,8 +29,23 @@ const int httpsPort = 443; // Use web browser to view and copy // SHA1 fingerprint of the certificate + +#if DEPRECATED_SSL_WITH_AXTLS + +// no separator, or space, or ":", in iram: const char* fingerprint = "35 85 74 EF 67 35 A7 CE 40 69 50 F3 C0 F6 80 CF 80 3B 2E 19"; +#else // with BearSSL + +// compatible with axTLS: +//const char* fingerprint = "35 85 74 EF 67 35 A7 CE 40 69 50 F3 C0 F6 80 CF 80 3B 2E 19"; +// flash is allowed: +//#define fingerprint FPSTR("358574EF67:35:A7:CE:40:69:50:F3-C0-F6-80-CF-80-3B 2E 19") +// or an array in iram: +const uint8_t fingerprint [] = { 0x35, 0x85, 0x74, 0xEF, 0x67, 0x35, 0xA7, 0xCE, 0x40, 0x69, 0x50, 0xF3, 0xC0, 0xF6, 0x80, 0xCF, 0x80, 0x3B, 0x2E, 0x19 }; + +#endif + void setup() { Serial.begin(115200); Serial.println(); @@ -46,9 +63,13 @@ void setup() { Serial.println(WiFi.localIP()); // Use WiFiClientSecure class to create TLS connection - WiFiClientSecure client; Serial.print("connecting to "); Serial.println(host); + + ////////////////////////// axTLS (soon deprecated) + #if DEPRECATED_SSL_WITH_AXTLS + + axTLS::WiFiClientSecure client; if (!client.connect(host, httpsPort)) { Serial.println("connection failed"); return; @@ -60,6 +81,29 @@ void setup() { Serial.println("certificate doesn't match"); } + ////////////////////////// BearSSL + #else // new SSL api with BearSSL + + BearSSL::WiFiClientSecure client; + + // WARNING: + // - axTLS was insecure by default, + // and fingerprint could be checked after a successful connection + // - BearSSL is not: + // "If there are no CAs or insecure options specified, BearSSL will not connect." + // Check the BearSSL_Validation.ino example for more details + // Insecure connection is available with `client.setInsecure()` + // Semi-secure checking using fingerprint: + client.setFingerprint(fingerprint); + + if (!client.connect(host, httpsPort)) { + Serial.println("connection failed"); + return; + } + + #endif + ////////////////////////// + String url = "/repos/esp8266/Arduino/commits/master/status"; Serial.print("requesting URL: "); Serial.println(url); diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL-fp.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL-fp.cpp new file mode 100644 index 0000000000..848cf3e241 --- /dev/null +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL-fp.cpp @@ -0,0 +1,36 @@ + +#include + +namespace BearSSL { + +static uint8_t htoi (unsigned char c) +{ + return c >= '0' && c <= '9'? c - '0' + : c >= 'A' && c <= 'F'? c - 'A' + 10 + : c >= 'a' && c <= 'f'? c - 'a' + 10 + : 255; +} + +void WiFiClientSecure::setFingerprint(const String& fingerprint) { + + uint8_t fp [20]; + uint8_t c, d; + int idx = 0; + const char* _fingerprint = fingerprint.c_str(); + + while (idx < 20 && (c = *_fingerprint++) && (d = *_fingerprint++)) { + c = htoi(c); + d = htoi(d); + if (c > 15 || d > 15) { + // skip separator + _fingerprint--; + continue; + } + fp[idx++] = (c << 4) + d; + } + + if (idx == 20) + setFingerprint(fp); +} + +} // namespace diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp index 89fbffd3ed..3a60614941 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp @@ -768,6 +768,11 @@ bool WiFiClientSecure::_installClientX509Validator() { bool WiFiClientSecure::_connectSSL(const char* hostName) { _freeSSL(); _oom_err = false; +#ifdef DEBUG_ESP_SSL + if (!_use_insecure && !_use_fingerprint && !_use_self_signed && !_knownkey && !_sk) { + DEBUG_ESP_PORT.println(FPSTR("BearSSL: connection *will* fail, no authentication method is setup")); + } +#endif _sc = std::make_shared(); _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h index 23850fdba9..7179f9cc93 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h @@ -67,6 +67,7 @@ class WiFiClientSecure : public WiFiClient { _knownkey_usages = usages; } // Only check SHA1 fingerprint of certificate + void setFingerprint(const String& fingerprint); void setFingerprint(const uint8_t fingerprint[20]) { _use_fingerprint = true; memcpy_P(_fingerprint, fingerprint, 20); @@ -104,9 +105,14 @@ class WiFiClientSecure : public WiFiClient { 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 - 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 + // AXTLS compatible wrappers bool verifyCertChain(const char* domain_name) { (void)domain_name; return connected(); } // If we're connected, the cert passed validation during handshake + bool verify(const String& fingerprint, const String& domain_name) { + (void) fingerprint; + (void) domain_name; + WiFiClientSecure_verify__is_unavailable_with_BearSSL__use_setFingerprint_instead(); + return false; + } bool setCACert(const uint8_t* pk, size_t size); bool setCertificate(const uint8_t* pk, size_t size); @@ -208,6 +214,8 @@ class WiFiClientSecure : public WiFiClient { static std::shared_ptr _bearssl_stack; // The local copy, only used to enable a reference count std::shared_ptr _local_bearssl_stack; + + void WiFiClientSecure_verify__is_unavailable_with_BearSSL__use_setFingerprint_instead (void); }; };