arendst / Tasmota

Alternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at
https://tasmota.github.io/docs
GNU General Public License v3.0
22.09k stars 4.79k forks source link

Self-signed mosquitto + Tasmota + MQTT TLS no longer working #20714

Closed fildourado closed 8 months ago

fildourado commented 8 months ago

PROBLEM DESCRIPTION

After following the instructions curently outlined in the Self-signed Mosquitto docs I am unable to provision a device to connect to my private broker. The error returned on the web console is as follows:

23:53:54.758 MQT: Attempting connection...
23:53:54.821 MQT: TLS connection error: 296
23:53:54.823 MQT: Connect failed to mqtt.<my server>.io:8883, rc -2. Retry in 100 sec

Error 296 is a SSL3_ALERT_HANDSHAKE_FAILURE. The server logs state the following:

1707778768: OpenSSL Error[0]: error:0A0000C1:SSL routines::no shared cipher
1707778768: Client <unknown> disconnected: Protocol error.

This implies, to me, that either the server or the device do not have the right cipher suite. The likely culprit is the tasmota device as it is configured to use a singular cipher suite here

When I manually use the ca.crt, device.crt and device.pem to try to connect to the server ./BearSSL/build/brssl client mqtt.<my server>.io:8883 \ -CA easy-rsa/easyrsa3/pki/ca.crt \ -cert easy-rsa/easyrsa3/pki/issued/device.crt \ -key easy-rsa/easyrsa3/pki/private/device.pem We succeed! But the cipher used is ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, here is the output.

Algorithms:
   RNG:           rdrand
   AES/CBC (enc): x86ni
   AES/CBC (dec): x86ni
   AES/CTR:       x86ni
   AES/CCM:       x86ni
   DES/CBC (enc): ct
   DES/CBC (dec): ct
   GHASH (GCM):   pclmul
   ChaCha20:      sse2
   Poly1305:      ctmulq
   EC:            all_m31
   ECDSA:         i31_asn1
   RSA (vrfy):    i62
Server requests a client certificate.
--- anchor DN list start ---
--- anchor DN list end ---
supported: RSA signatures: SHA-224 SHA-256 SHA-384 SHA-512
supported: ECDSA signatures: SHA-224 SHA-256 SHA-384 SHA-512
server key curve: secp256r1 (23)
using ECDSA, hash = 4 (SHA-256)
Handshake completed
   version:               TLS 1.2
   cipher suite:          ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
   ECDHE curve:           Curve25519
   secure renegotiation:  yes
SSL closed normally

According to the tasmota source code, the only supported cipher is BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. This implies that the device should be using an RSA cert/private key BUT the documentation only talks about EC. Based on my reading of previous issues, my suspicion is that the source was adapted to support AWS IOT which uses an RSA based cert and the self-signed support was not updated?

A few other things I've tried:

The documentation here https://tasmota.github.io/docs/TLS/#implementation-notes says the following:

EC private key: 
AWS IoT requires the client to authenticate with its own Private Key and Certificate. By default AWS IoT will generate an RSA 2048 bit private key. In Tasmota, we moved to an EC (Elliptic Curve) Private Key of 256 bits. EC keys are much smaller, and handshake is significantly faster. Note: the key being 256 bits does not mean it's less secure than RSA 2048, it's actually the opposite.

Single Cipher: to reduce code size, we only support a single TLS cipher and embed only the code strictly necessary. When using TLS (e.g. LetsEncrypt on Mosquitto) the supported cipher is ECDHE_RSA_WITH_AES_128_GCM_SHA256. Additionally, ECDHE offers Perfect Forward Secrecy which means extra security.

It's very unclear to my how we can force EasyRSA generate a 2048 bit RSA cert but use an EC private key.

So I'm at a bit of a loss, it seems like something switched to RSA at some point but the "Self-signed Mosquitto" documentation still refers to EC? I don't know enough about TLS to find where things are going wrong in the source.

Here is my user_config_override.h

/*
  user_config_override.h - user configuration overrides my_user_config.h for Tasmota
*/

#ifndef _USER_CONFIG_OVERRIDE_H_
#define _USER_CONFIG_OVERRIDE_H_

// disable
//#ifdef USE_DOMOTICZ
//#undef USE_DOMOTICZ                              
//#endif 

// TODO: REMOVE - just for local testing
#undef  STA_SSID1
#define STA_SSID1         "<removed>"             // [Ssid1] Wifi SSID

#undef  STA_PASS1
#define STA_PASS1         "<removed>"     // [Password1] Wifi password

#undef  MQTT_HOST
#define MQTT_HOST "mqtt.metermaid.io"   // [MqttHost]

#undef  MQTT_PORT
#define MQTT_PORT 8883 // [MqttPort] MQTT port (10123 on CloudMQTT)

#ifndef USE_MQTT_TLS
#define USE_MQTT_TLS
#endif

#ifdef MQTT_TLS_ENABLED
#undef MQTT_TLS_ENABLED
#endif
#define MQTT_TLS_ENABLED true

/*  
    Force full CA validation instead of fingerprints, slower, 
    but simpler to use. 
    (+2.2k code, +1.9k mem during connection handshake)
*/
#define USE_MQTT_TLS_CA_CERT   

/*
    This will include LetsEncrypt CA, as well as our CA, in tasmota_ca.ino 
    for verifying server certificates
*/
#define USE_MQTT_AWS_IOT

// We want to use our own certs
#define OMIT_AWS_CERT
#define OMIT_LETS_ENCRYPT_CERT

// This is deprecated, no longer used in the code
// #define USE_MQTT_TLS_FORCE_EC_CIPHER           // Force Elliptic Curve cipher (higher security) required by some servers (automatically enabled with USE_MQTT_AWS_IOT) (+11.4k code, +0.4k mem)

#define INCLUDE_LOCAL_CERT

#endif  // _USER_CONFIG_OVERRIDE_H_

REQUESTED INFORMATION

Make sure your have performed every step and checked the applicable boxes before submitting your issue. Thank you!

- [x] Set `weblog` to 4 and then, when you experience your issue, provide the output of the Console log:
```lua
  Console output here:
00:32:36.464 CMD: weblog 4
00:32:36.468 RSL: RESULT = {"WebLog":4}
00:32:36.601 CFG: Saved to flash at F4, Count 8, Bytes 4096
00:32:39.788 WIF: Checking connection...
00:32:57.409 WIF: Sending Gratuitous ARP
00:32:59.763 WIF: Checking connection...
00:33:19.774 WIF: Checking connection...
00:33:39.771 WIF: Checking connection...
00:33:40.025 MQT: Attempting connection...
00:33:40.028 WIF: DNS resolved 'mqtt.<my server>.io' (my server ip) in 0 ms
00:33:40.088 MQT: TLS connection error: 296
00:33:40.090 MQT: Connect failed to mqtt.<my server>.io:8883, rc -2. Retry in 100 sec

TO REPRODUCE

  1. Follow the procedure as outlined here: https://tasmota.github.io/docs/Self-signed-Mosquitto/
  2. See problem description for details about why this is going wrong

EXPECTED BEHAVIOUR

A successful MQTT TLS session with a mosquitto broker using a tasmota device

Additional Context

Here is an issue that is similar and recent BUT does not work for me in this case as they are using Let's Encrypt and Home Assistant https://github.com/arendst/Tasmota/discussions/20192

(Please, remember to close the issue when the problem has been addressed)

s-hadinger commented 8 months ago

According to the tasmota source code, the only supported cipher is BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. This implies that the device should be using an RSA cert/private key BUT the documentation only talks about EC. Based on my reading of previous issues, my suspicion is that the source was adapted to support AWS IOT which uses an RSA based cert and the self-signed support was not updated?

The documentation is still correct. Tasmota expects a RSA certificate for performance reasons (ECDHE is significantly slower, at least on BearSSL). That said, the cipher used is EC P256.

You can use EC ciphers based on RSA certificates. This combination is the best compromise between speed and security