TLS enabled ECDSA by default for ESP8266 (#24009)

This commit is contained in:
s-hadinger 2025-10-13 20:05:01 +02:00 committed by GitHub
parent 0e88a227fd
commit b04557928c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 127 additions and 20 deletions

View File

@ -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

View File

@ -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()
{

View File

@ -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();

View File

@ -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();

View File

@ -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)

View File

@ -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

View File

@ -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
/*