From b04557928c539cd30eb8bdb39b252659a5c9038d Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:05:01 +0200 Subject: [PATCH] TLS enabled ECDSA by default for ESP8266 (#24009) --- CHANGELOG.md | 1 + lib/lib_ssl/tls_mini/src/StackThunk_light.cpp | 18 +++- lib/lib_ssl/tls_mini/src/StackThunk_light.h | 1 + .../src/WiFiClientSecureLightBearSSL.cpp | 26 ++--- tasmota/my_user_config.h | 1 + tasmota/tasmota_support/tasmota_ca.ino | 97 ++++++++++++++++++- .../tasmota_xdrv_driver/xdrv_02_9_mqtt.ino | 3 + 7 files changed, 127 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f88328ac..7635d2639 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [15.1.0.1] ### Added +- TLS enabled ECDSA by default for ESP8266 ### Breaking Changed diff --git a/lib/lib_ssl/tls_mini/src/StackThunk_light.cpp b/lib/lib_ssl/tls_mini/src/StackThunk_light.cpp index 00799d66c..ac4a3aa92 100644 --- a/lib/lib_ssl/tls_mini/src/StackThunk_light.cpp +++ b/lib/lib_ssl/tls_mini/src/StackThunk_light.cpp @@ -45,12 +45,16 @@ uint32_t stack_thunk_light_refcnt = 0; //#define _stackSize (5600/4) #if defined(USE_MQTT_CLIENT_CERT) || defined(USE_MQTT_AWS_IOT_LIGHT) || defined(USE_MQTT_AZURE_IOT) - #define _stackSize (5300/4) // using a light version of bearssl we can save 300 bytes + #define _stackSizeRSA (5300/4) // using a light version of bearssl we can save 500 bytes + #define _stackSizeECDSA (6300/4) // using a light version of bearssl we can save 300 bytes #else - #define _stackSize (4800/4) // no private key, we can reduce a little, max observed 4300 + #define _stackSizeRSA (4800/4) // no private key, we can reduce a little, max observed 4300 + #define _stackSizeECDSA (6800/4) // using a light version of bearssl we can save 300 bytes #endif #define _stackPaint 0xdeadbeef +size_t _stackSize = _stackSizeRSA; + void stack_thunk_yield() { if (can_yield()) { @@ -70,6 +74,16 @@ void stack_thunk_yield() } } +/* Set the size for stack depending on RSA or RSA/ECDSA */ +void stack_thunk_light_set_size(bool _rsa_only) +{ + if (_rsa_only) { + _stackSize = _stackSizeRSA; + } else { + _stackSize = _stackSizeECDSA; + } +} + /* Add a reference, and allocate the stack if necessary */ void stack_thunk_light_add_ref() { diff --git a/lib/lib_ssl/tls_mini/src/StackThunk_light.h b/lib/lib_ssl/tls_mini/src/StackThunk_light.h index ca6701422..98715fbb3 100644 --- a/lib/lib_ssl/tls_mini/src/StackThunk_light.h +++ b/lib/lib_ssl/tls_mini/src/StackThunk_light.h @@ -34,6 +34,7 @@ extern "C" { extern void stack_thunk_yield(); +extern void stack_thunk_light_set_size(bool _rsa_only); extern void stack_thunk_light_add_ref(); extern void stack_thunk_light_del_ref(); extern void stack_thunk_light_repaint(); diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp index 227e078d6..57568061b 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp @@ -884,14 +884,6 @@ extern "C" { ctx->fingerprint_all = fingerprint_all; } -#ifdef ESP8266 - // We limit to a single cipher to reduce footprint - // we reference it, don't put in PROGMEM - static const uint16_t suites[] = { - BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - }; -#else - // add more flexibility on ESP32 static const uint16_t suites[] = { BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, @@ -899,7 +891,6 @@ extern "C" { 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, bool _rsa_only) { @@ -908,14 +899,14 @@ extern "C" { 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 defined(ESP32) || (defined(ESP8266) && defined(USE_MQTT_TLS_ECDSA)) 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])); } +#else + br_ssl_engine_set_suites(&cc->eng, suites_RSA_ONLY, (sizeof suites_RSA_ONLY) / (sizeof suites_RSA_ONLY[0])); #endif br_ssl_client_set_default_rsapub(cc); br_ssl_engine_set_default_rsavrfy(&cc->eng); @@ -931,7 +922,7 @@ extern "C" { // 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); -#ifdef ESP32 +#if defined(ESP32) || (defined(ESP8266) && defined(USE_MQTT_TLS_ECDSA)) br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1); #endif } @@ -951,6 +942,7 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) { // ============================================================ // allocate Thunk stack, move to alternate stack and initialize #ifdef ESP8266 + stack_thunk_light_set_size(_rsa_only); stack_thunk_light_add_ref(); #endif // ESP8266 LOG_HEAP_SIZE("Thunk allocated"); @@ -986,9 +978,11 @@ 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 +#if defined(ESP32) || (defined(ESP8266) && defined(USE_MQTT_TLS_ECDSA)) + if (!_rsa_only) { + br_x509_minimal_set_ecdsa(x509_minimal, &br_ec_all_m15, &br_ecdsa_i15_vrfy_asn1); + } +#endif br_ssl_engine_set_x509(_eng, &x509_minimal->vtable); uint32_t now = UtcTime(); uint32_t cfg_time = CfgTime(); diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index bfd3828e4..a2847e178 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -462,6 +462,7 @@ // -- MQTT - TLS - AWS IoT ------------------------ // Using TLS starting with version v6.5.0.16 compilation will only work using Core 2.4.2 and 2.5.2. No longer supported: 2.3.0 //#define USE_MQTT_TLS // Use TLS for MQTT connection (+34.5k code, +7.0k mem and +4.8k additional during connection handshake) + #define USE_MQTT_TLS_ECDSA // (ESP8266 only, always on for ESP32) enable ECDSA in addition to RSA (+11.5k code) // #define USE_MQTT_TLS_CA_CERT // [DEPRECATED] Now TLS supports dual mode using SetOption132 - this flag is now ignored // #define USE_MQTT_AWS_IOT_LIGHT // Enable MQTT for AWS IoT in light mode, with user/password instead of private certificate // #define USE_MQTT_CLIENT_CERT // Enable MQTT with custom client certificate - requires a private key (+11.9k code, +0.4k mem) diff --git a/tasmota/tasmota_support/tasmota_ca.ino b/tasmota/tasmota_support/tasmota_ca.ino index c5056218c..2787dc4e4 100644 --- a/tasmota/tasmota_support/tasmota_ca.ino +++ b/tasmota/tasmota_support/tasmota_ca.ino @@ -115,12 +115,33 @@ static const unsigned char LetsEncrypt_ISRG_Root_X1_RSA_E[] = { #endif -#if ! defined(OMIT_AWS_CERT) +#if !defined(OMIT_AWS_CERT) /*********************************************************************************************\ - * Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117 + * Amazon Root CA1, RSA 2048 bits SHA 256, valid until 20380117 * * https://www.amazontrust.com/repository/ * Downloaded from https://www.amazontrust.com/repository/AmazonRootCA1.pem + * + * -----BEGIN CERTIFICATE----- + * MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF + * ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 + * b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL + * MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv + * b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj + * ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM + * 9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw + * IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 + * VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L + * 93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm + * jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC + * AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA + * A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI + * U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs + * N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv + * o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU + * 5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy + * rqXRfboQnoZsG4q5WTP468SQvvG5 + * -----END CERTIFICATE----- * * to convert do: "bearssl ta AmazonRootCA1.pem" * then copy and paste below, chain the generic names to the same as below @@ -165,6 +186,62 @@ static const unsigned char PROGMEM AmazonRootCA1_RSA_E[] = { 0x01, 0x00, 0x01 }; + +/*********************************************************************************************\ + * Amazon Root CA3, EC, NIST P-256 curve, valid until 20400526 + * + * https://www.amazontrust.com/repository/ + * Downloaded from https://www.amazontrust.com/repository/AmazonRootCA3.pem + * + * -----BEGIN CERTIFICATE----- + * MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 + * MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g + * Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG + * A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg + * Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl + * ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j + * QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr + * ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr + * BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM + * YyRIHN8wfdVoOw== + * -----END CERTIFICATE----- + * + * to convert do: "bearssl ta AmazonRootCA3.pem" + * then copy and paste below, chain the generic names to the same as below + * remove "static" and add "PROGMEM" +\*********************************************************************************************/ + +static const unsigned char AmazonRootCA3_DN[] = { + 0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A, + 0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6D, 0x61, 0x7A, 0x6F, + 0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33 +}; + +static const unsigned char AmazonRootCA3_EC_Q[] = { + 0x04, 0x29, 0x97, 0xA7, 0xC6, 0x41, 0x7F, 0xC0, 0x0D, 0x9B, 0xE8, 0x01, + 0x1B, 0x56, 0xC6, 0xF2, 0x52, 0xA5, 0xBA, 0x2D, 0xB2, 0x12, 0xE8, 0xD2, + 0x2E, 0xD7, 0xFA, 0xC9, 0xC5, 0xD8, 0xAA, 0x6D, 0x1F, 0x73, 0x81, 0x3B, + 0x3B, 0x98, 0x6B, 0x39, 0x7C, 0x33, 0xA5, 0xC5, 0x4E, 0x86, 0x8E, 0x80, + 0x17, 0x68, 0x62, 0x45, 0x57, 0x7D, 0x44, 0x58, 0x1D, 0xB3, 0x37, 0xE5, + 0x67, 0x08, 0xEB, 0x66, 0xDE +}; + +// static const br_x509_trust_anchor TAs[1] = { +// { +// { (unsigned char *)TA0_DN, sizeof TA0_DN }, +// BR_X509_TA_CA, +// { +// BR_KEYTYPE_EC, +// { .ec = { +// BR_EC_secp256r1, +// (unsigned char *)TA0_EC_Q, sizeof TA0_EC_Q, +// } } +// } +// } +// }; + #endif #if defined(INCLUDE_LOCAL_CERT) @@ -205,6 +282,22 @@ const br_x509_trust_anchor PROGMEM Tasmota_TA[] = { } } +#if defined(ESP32) || (defined(ESP8266) && defined(USE_MQTT_TLS_ECDSA)) + , + { + { (unsigned char *)AmazonRootCA3_DN, sizeof AmazonRootCA3_DN }, + BR_X509_TA_CA, + { + BR_KEYTYPE_EC, + { .ec = { + BR_EC_secp256r1, + (unsigned char *)AmazonRootCA3_EC_Q, sizeof AmazonRootCA3_EC_Q, + } } + } + } + +#endif // defined(ESP32) || (defined(ESP8266) && defined(USE_MQTT_TLS_ECDSA)) + #if defined(INCLUDE_LOCAL_CERT) , #endif diff --git a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino index 584751fcc..caf8863f9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino @@ -1392,6 +1392,8 @@ 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 defined(ESP32) || (defined(ESP8266) && defined(USE_MQTT_TLS_ECDSA)) 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 @@ -1400,6 +1402,7 @@ void MqttReconnect(void) { tlsClient->setECDSA(Settings->flag6.tls_use_ecdsa); AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS now enabling ECDSA 'SetOption165 1'"), tlsClient->getLastError()); } +#endif // defined(ESP32) || (defined(ESP8266) && defined(USE_MQTT_TLS_ECDSA)) } #endif /*