diff --git a/CHANGELOG.md b/CHANGELOG.md index de15733a2..304eed2b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ All notable changes to this project will be documented in this file. ### Fixed - Berry fixed 'be_top is non zero' warning when calling C mapped functions (#23989) - Berry fixed 'be_top is non zero' when `Br` command fails (#23990) +- TLS fix ECDSA and add `SetOption165 1` to enable ECDSA in addition to RSA ## [15.0.1.4] 20251002 ### Added diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp index c11acaec2..227e078d6 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp @@ -930,8 +930,8 @@ extern "C" { br_ssl_engine_set_ghash(&cc->eng, &br_ghash_ctmul32); // we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced - br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15); // TODO -#ifndef ESP8266 + br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15); +#ifdef ESP32 br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1); #endif } @@ -986,6 +986,9 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) { br_x509_minimal_init(x509_minimal, &br_sha256_vtable, _ta_P, _ta_size); br_x509_minimal_set_rsa(x509_minimal, br_ssl_engine_get_rsavrfy(_eng)); br_x509_minimal_set_hash(x509_minimal, br_sha256_ID, &br_sha256_vtable); +#ifdef ESP32 + br_x509_minimal_set_ecdsa(x509_minimal, &br_ec_all_m15, &br_ecdsa_i15_vrfy_asn1); +#endif // ESP32 br_ssl_engine_set_x509(_eng, &x509_minimal->vtable); uint32_t now = UtcTime(); uint32_t cfg_time = CfgTime(); diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h index 3cbbcc67e..dab8ca4f7 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h @@ -120,6 +120,9 @@ class WiFiClientSecure_light : public WiFiClient { return br_ssl_engine_last_error(_eng); } } + int32_t getLastCipherSuite(void) { + return _eng->session.cipher_suite; + } inline void setLastError(int32_t err) { _last_error = err; } @@ -131,6 +134,9 @@ class WiFiClientSecure_light : public WiFiClient { } void setInsecure(); + void setECDSA(bool ecdsa) { + _rsa_only = !ecdsa; + }; void setDomainName(const char * domain) { _domain = domain; diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index 2ebbfe618..b2ba441cb 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -199,7 +199,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t no_export_energy_today : 1; // bit 16 (v14.3.0.7) - SetOption162 - (Energy) Do not add export energy to energy today (1) uint32_t gui_device_name : 1; // bit 17 (v14.4.1.1) - SetOption163 - GUI_NOSHOW_DEVICENAME - (GUI) Disable display of GUI device name (1) uint32_t wizmote_enabled : 1; // bit 18 (v14.4.1.4) - SetOption164 - (WizMote) Enable WiZ Smart Remote support (1) - uint32_t spare19 : 1; // bit 19 + uint32_t tls_use_ecdsa : 1; // bit 19 (v15.0.1.0) - SetOption165 - (TLS) Enable ECDSA validation in addition to RSA uint32_t spare20 : 1; // bit 20 uint32_t spare21 : 1; // bit 21 uint32_t spare22 : 1; // bit 22 diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index b5a40701e..bfd3828e4 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -173,8 +173,9 @@ #define MQTT_INDEX_SEPARATOR false // [SetOption64] Enable "_" instead of "-" as sensor index separator #define MQTT_TUYA_RECEIVED false // [SetOption66] Enable TuyaMcuReceived messages over Mqtt #define MQTT_ONLY_JSON_OUTPUT false // [SetOption90] Disable non-json messages -#define MQTT_TLS_ENABLED false // [SetOption103] Enable TLS mode (requires TLS version) -#define MQTT_TLS_FINGERPRINT false // [SetOption132] Force TLS fingerprint validation instead of CA (requires TLS version) +#define MQTT_TLS_ENABLED false // [SetOption103] Enable TLS mode +#define MQTT_TLS_FINGERPRINT false // [SetOption132] Force TLS fingerprint validation instead of CA +#define MQTT_TLS_ECDSA false // [SetOption165] Enable TLS ECDSA validation in addition to RSA, false by default but automatically set to 'true' in case of a cipher error '296' // -- HTTP ---------------------------------------- #define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin) diff --git a/tasmota/tasmota_support/settings.ino b/tasmota/tasmota_support/settings.ino index f9a70e259..268e546a0 100644 --- a/tasmota/tasmota_support/settings.ino +++ b/tasmota/tasmota_support/settings.ino @@ -1448,6 +1448,7 @@ void SettingsDefaultSet2(void) { // Matter flag6.matter_enabled |= MATTER_ENABLED; + flag6.tls_use_ecdsa |= MQTT_TLS_ECDSA; Settings->flag = flag; Settings->flag2 = flag2; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino index 6c92168a6..584751fcc 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino @@ -262,6 +262,7 @@ void MqttInit(void) { if (!Settings->flag5.tls_use_fingerprint) { tlsClient->setTrustAnchor(Tasmota_TA, nitems(Tasmota_TA)); } + tlsClient->setECDSA(Settings->flag6.tls_use_ecdsa); MqttClient.setClient(*tlsClient); } else { @@ -1391,6 +1392,14 @@ void MqttReconnect(void) { 120 : 376 : BR_ALERT_NO_APPLICATION_PROTOCOL */ AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connection error: %d"), tlsClient->getLastError()); + if (tlsClient->getLastError() == 296) { + // in this special case of cipher mismatch, we force enable ECDSA + // this would be the case for newer letsencrypt certificates now defaulting + // to EC certificates requiring ECDSA instead of RSA + Settings->flag6.tls_use_ecdsa = true; + tlsClient->setECDSA(Settings->flag6.tls_use_ecdsa); + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS now enabling ECDSA 'SetOption165 1'"), tlsClient->getLastError()); + } } #endif /* @@ -1408,6 +1417,18 @@ void MqttReconnect(void) { */ MqttDisconnected(MqttClient.state()); } +#ifdef USE_MQTT_TLS + if (Mqtt.mqtt_tls) { + int32_t cipher_suite = tlsClient->getLastCipherSuite(); + if (BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 == cipher_suite) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "TLS cipher suite: %s"), PSTR("ECDHE_RSA_AES_128_GCM_SHA256")); + } else if (BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 == cipher_suite) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "TLS cipher suite: %s"), PSTR("ECDHE_ECDSA_AES_128_GCM_SHA256")); + } else if (0 != cipher_suite) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "TLS cipher suite: 0x%04X"), cipher_suite); + } + } +#endif // USE_MQTT_TLS } void MqttCheck(void) {