From 333060af29608906621b41d5fe7535463e47f837 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 15 Dec 2024 19:33:01 +0100 Subject: [PATCH] TLS disable ECDSA for MQTT to ensure we don't break fingerprints after #22649 --- CHANGELOG.md | 1 + .../src/WiFiClientSecureLightBearSSL.cpp | 21 ++++++++++++++++--- .../src/WiFiClientSecureLightBearSSL.h | 5 +++++ .../HttpClientLight/src/HttpClientLight.cpp | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 024175579fbc..1db752d6aeb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. ### Changed - ESP32 disable PSRAM check (and on restart some relay toggles) with `#define DISABLE_PSRAMCHECK` (#21266) +- TLS disable ECDSA for MQTT to ensure we don't break fingerprints after #22649 ### Fixed diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp index 4259023e5d9f..b4bbe6e6a32b 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp @@ -195,6 +195,7 @@ void WiFiClientSecure_light::_clear() { _recvapp_buf = nullptr; _recvapp_len = 0; _insecure = false; // set to true when calling setPubKeyFingerprint() + _rsa_only = true; // for now we disable ECDSA by default _fingerprint_any = true; // by default accept all fingerprints _fingerprint1 = nullptr; _fingerprint2 = nullptr; @@ -813,7 +814,10 @@ extern "C" { // The tag string doesn't really matter, but it should differ depending on // key type. For ECDSA it's a fixed string. - sha1_update_len(&shactx, "ecdsa-sha2-nistp256", 19); // tag + sha1_update_len(&shactx, "ecdsa", 5); // tag + int32_t curve = eckey.curve; + sha1_update_len(&shactx, &curve, 4); // curve id as int32 + sha1_update_len(&shactx, "curve", 5); // tag2 sha1_update_len(&shactx, eckey.q, eckey.qlen); // exponent } #endif @@ -888,16 +892,27 @@ extern "C" { BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, }; + static const uint16_t suites_RSA_ONLY[] = { + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }; #endif // Default initializion for our SSL clients - static void br_ssl_client_base_init(br_ssl_client_context *cc) { + static void br_ssl_client_base_init(br_ssl_client_context *cc, bool _rsa_only) { br_ssl_client_zero(cc); // forbid SSL renegotiation, as we free the Private Key after handshake br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION); br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12); +#ifdef ESP8266 br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); +#else + if (_rsa_only) { + br_ssl_engine_set_suites(&cc->eng, suites_RSA_ONLY, (sizeof suites_RSA_ONLY) / (sizeof suites_RSA_ONLY[0])); + } else { + br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); + } +#endif br_ssl_client_set_default_rsapub(cc); br_ssl_engine_set_default_rsavrfy(&cc->eng); @@ -945,7 +960,7 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) { _ctx_present = true; _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr - br_ssl_client_base_init(_sc.get()); + br_ssl_client_base_init(_sc.get(), _rsa_only); if (_alpn_names && _alpn_num > 0) { br_ssl_engine_set_protocol_names(_eng, _alpn_names, _alpn_num); } diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h index 792a6d48ec73..8ba7a33bad6d 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h @@ -85,6 +85,10 @@ class WiFiClientSecure_light : public WiFiClient { _fingerprint2 = f2; _fingerprint_any = f_any; _insecure = true; + _rsa_only = true; // if fingerprint, we limit to RSA only + } + void setRSAOnly(bool rsa_only) { + _rsa_only = rsa_only; } const uint8_t * getRecvPubKeyFingerprint(void) { return _recv_fingerprint; @@ -150,6 +154,7 @@ class WiFiClientSecure_light : public WiFiClient { bool _fingerprint_any; // accept all fingerprints bool _insecure; // force fingerprint + bool _rsa_only; // restrict to RSA only key exchange (no ECDSA - enabled to force RSA fingerprints) const uint8_t *_fingerprint1; // fingerprint1 to be checked against const uint8_t *_fingerprint2; // fingerprint2 to be checked against uint8_t _recv_fingerprint[20]; // fingerprint received diff --git a/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp b/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp index 6c35df2544d8..1430e6a6eeb8 100644 --- a/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp +++ b/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp @@ -89,6 +89,7 @@ class BearSSLTraits : public TransportTraitsLight { BearSSL::WiFiClientSecure_light& wcs = static_cast(client); wcs.setPubKeyFingerprint(_fingerprint_any, _fingerprint_any, true); // allow all fingerprints + wcs.setRSAOnly(false); // although we use fingerprint, we allow ECDSA return true; }