MQTT TLS and fingerprint learning

563 views
Skip to first unread message

Tam481

unread,
Sep 16, 2019, 2:06:13 PM9/16/19
to SonoffUsers
Hi all,
I'm a little confused by the behaviour of my MQTT server and Tasmota clients. I used OpenSSL to generate my own CA and server certs. I set my Mosquitto server to use the certificate and it is working fine (tested connectivity with MQTT-Spy)

I specified the CN (Common Name) of the certificate to match the hostname of the Mosquitto server. I then used openssl s_client -connect server.address:8883 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin  to obtain the fingerprint for the certificate. I ran the command locally and remotely against the server address and got the same fingerprint. However, I could not get Tasmota to connect. It kept returning error 1. I gave up and used the all 00 fingerprint for it to learn the fingerprint and upon restarting, it said that it learned a fingerprint that I cannot find anywhere.

For example, 

This is the fingerprint returned when I use openssl to get the fingerprint
51 E9 C7 7D 37 62 DF 8F 2D 5E CE 0F DD A8 A5 F2 B4 CA 79 7E

This is what Tasmota has learnt
2A 75 75 59 90 95 86 DD 6A EB B3 D0 D5 65 E8 11 95 6E E5 68

I checked the fingerprint of the CA and it was completely different.

Does anyone understand what is going on here?

Stephan Hadinger

unread,
Sep 16, 2019, 3:08:34 PM9/16/19
to SonoffUsers
Hi,

The fingerprint used in Tasmota is different from the fingerprint of the certificate shown by openssl. Tasmota uses a hash on the Public Key, not on the Certiicate.

There are two reasons for this:
1/ It would take too much memory to compute the certificate hash, it's much more lightweight to compute the fingerprint of the public key instead. This is due to the way BearSSL works.
2/ The fingerprint of the public key is much more stable than the certificate. For ex Letsencrypt requires to renew the certificate every 3 months, which would mean updating all devices every 3 months. On the contrary the public key does not change.

The problem is that the only way to know your fingerprint is to use Tasmota in auto-learn and write down the fingerprint.

Hope this helps
Stephan

Tam481

unread,
Sep 16, 2019, 3:55:40 PM9/16/19
to SonoffUsers
Thank you very much for that explanation @Stephan. I used the auto-learned key and hardcoded it in my code before building.

Do you know what fingerprint2 is for?

Stephan Hadinger

unread,
Sep 16, 2019, 5:05:21 PM9/16/19
to SonoffUsers
Tasmota will check against both fingerprint1 (aka fingerprint) and fingerprint2. This comes handy when you need to change the server certificate; just pre-configure the second fingerprint in advance. When you switch it goes smoothly, and you don't need to reconfigure all of them at once.

Otherwise just set the same value for both fingerprints.

Tam481

unread,
Sep 17, 2019, 12:50:25 PM9/17/19
to SonoffUsers
Thanks @Stephan.

I have a few more questions, if I may. As I understand it, both client and server have to exchange the encryption key in order to communicate securely. If the client i.e. my Sonoff Tasmota device sends a message to my MQTT server, the message is encrypted with the MQTT server's public key which only the MQTT server can decipher - so far so good. How does the MQTT server then update its subscribers securely? Don't the clients also have to have a public/private key set up just like the MQTT server?

How does this work for Tasmota devices and other devices communicating with MQTT for that matter?

Stephan Hadinger

unread,
Sep 17, 2019, 4:58:39 PM9/17/19
to SonoffUsers
Hi, sure. Encryption is one of my favorite topics.

This is a common misconception about TLS, actually a bit more complex.

Using Private/Public key for data encryption would be too inefficient and too slow. Instead TLS uses symmetric encryption for data flow.

The first phase is the TLS handshake where the client and server choose a cipher, the client authenticates the server, optionally the server authenticates the client, and they both negotiate a common symmetric key (here 128 bits). The symmetric key, also called session key is used for both encryption and decryption of data both ways. It is a secret shared between the client and the server for a limited period of time (typically 24h max).

In its simplest form, the client generates a random key (128 bits for Tasmota), encrypts the session key with the server's public key. The server decrypts the session key with its private key, and they can communicate. However, this scheme has a weakness. If you record all encrypted traffic, and if in the future the server gets compromised and the private key disclosed, you can then decrypt all past traffic.

To avoid this, the industry uses increasingly Diffie-Hellman: the session key is partly generated by both the client and the server, and they negociate a common key (interesting math behind this). This is also called Forward Perfect Secrecy.

Let's have a look of what Tasmota supports:

By default it uses TLS_RSA_WITH_AES_128_GCM_SHA256.
RSA: the private/public key of the server uses RSA, max 2048 bits
AES_128_GCM: AES symmetric encryption with Gallois Counter Mode using128 bits keys
SHA256: hashes use SHA-256 bits

If you set #define USE_MQTT_TLS_FORCE_EC_CIPHER, it uses more advanced cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
ECDHE: Ephemeral Elliptic Curve Diffie-Hellman, this provides Perfect Forward Secrecy when negotiating the symmetric key
RSA: server key is still of type RSA (max 2048 bits)
AES_128_GCM: same as above, symmetric encryption
SHA256: same as above

Hope this helps,
Stephan

Tam481

unread,
Sep 18, 2019, 1:07:20 PM9/18/19
to SonoffUsers
Thank you very much indeed @Stephan. That is a great explanation. I understand it much better now. 

Miroslav Mihok

unread,
Nov 5, 2021, 8:48:49 AM11/5/21
to TasmotaUsers
@Stephan: great explanation , thx ;-)

1.) Is there some list of supported cipher suites by Tasmota?
2.) What type of curve do you use ? secp521r1 ?

Miro

Dátum: streda 18. septembra 2019, čas: 19:07:20 UTC+2, odosielateľ: Tam481

Stephan Hadinger

unread,
Nov 6, 2021, 6:01:39 AM11/6/21
to TasmotaUsers
The default cipher supported is now `ECDHE_RSA_WITH_AES_128_GCM_SHA256` and the only EC curve is P256.

This is a trade-off to keep code as compact as possible, and it seems to be very widely supported.

Stephan

Weather Guy

unread,
Apr 17, 2022, 2:32:50 PM4/17/22
to TasmotaUsers
This is about hacking...if I'm talking nonsense, just say so and I'll go away...

So, let's say I want to use the 25519 elliptic curve for TLS. Would this work to add support (assuming the resulting image fits in memory) ?

It seems the curves to be supported are configured in the file lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp in the function br_ssl_client_base_init(). I'm guessing that changing the second argument in the call to br_ssl_engine_set_ec to either &br_ec_all_m15 or &br_ec_c25519_m15 will enable support for curve 25519.

I tried this, and the image builds okay, but I have not yet tried loading it into a Tasmota device. Thought I'd ask the question here first, in case I'm wasting my time.

AFAICT, mosquitto does support X25519 for key negotiation in TLS.

Footnote: generating a signed X509 certificate containing the X25519 public key is required so that can be stored in the Tasmota device with the TLSKey2 command. Doing this with the openssl command line is a bit tricky because X25519 doesn't support signing, but I think I've got that one figured out.

P.S. I'm not crystal clear on the difference between curve 25519 and X25519, but it sounds like the latter is not the curve, but a protocol for using the curve to exchange keys in TLS. While the former, is the actual definition of the elliptic curve parameters.

Stephan Hadinger

unread,
Apr 17, 2022, 4:30:29 PM4/17/22
to TasmotaUsers
This should work indeed. You also need to add the ciphers to the list of supported ciphers.

Weather Guy

unread,
Apr 17, 2022, 7:14:50 PM4/17/22
to TasmotaUsers
Ok, great. I'm learning a bit here. Tell me what I've got right or wrong. I'm pretty low on the learning curve w.r.t. cipher suites and protocols, etc.

There's a call to br_ssl_engine_seq_suites() which is what I think you're referring to, and it's passed an array of values (named suites[]) in the code.

The ciper suite constant for the existing setup (P-256 curve) specifies this value: BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
from the file t_bearssl_ssl.h which is describes a Diffie-Hellman Ephemeral protocol.

If I understand this, X25519 is a static Diffie-Hellman protocol. Or is the choice of static vs Ephemeral not part of the definition of X25519? If it is specifically a static DH protocol, then the change below seems to be indicated.

So if only the key exchange part is being replaced or enhanced, then I should edit the suites[] array in the above-mentioned .cpp file by either replacing or adding this entry: BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256

Weather Guy

unread,
Apr 18, 2022, 1:49:46 AM4/18/22
to TasmotaUsers
So, maybe never mind about the issue with suites. I read up on that topic a bit and I can probably leave the current list of a single suite unchanged, because it's only the curve that's different. Still ECDHE key exchange, and the remainder is the same. I'll try that later this week and post back the results.

Weather Guy

unread,
Apr 18, 2022, 7:36:36 PM4/18/22
to TasmotaUsers
Okay, the plot is thickening. I've manage to build a Tasmota device loaded with a X25519 public/private key pair. The public key entered (via TLSKey2 on console) has an RSA signature from the local CA certificate. I had to use openssl's -force_pubkey feature to do that, since openssl requires all CSRs to be self signed, and X25519 cannot be used for signing.

Wireshark shows what looks to me like a valid Client Hello -- advertising the desired cipher suite and EC curve. So far so good.

But then I get this error from mosquitto (truncated) ... process_cert_verify : signature for non signing certificate

Sounds like the Tasmota device passed a copy of it's X25519 certificate to mosquitto broker, and the broker didn't like the fact it was signed. Probably because of the allowed uses for that protocol.

I'm stumped...any ideas what to try next...?

Weather Guy

unread,
Apr 18, 2022, 10:20:10 PM4/18/22
to TasmotaUsers
The error above is coming from the openssl library that mosquitto uses.

Let me see if I understand the purpose of certificates in Tasmota:

1) Embeding the local CA certificate allows the device to verify the identity of the server, and this is independent of certificate (2), yes?
2) Embedding a RSA-signed cert in the device allows the device to prove its identity to the server, in addition to providing a public key to the server, yes?

So, if openssl won't accept a X25519 cert with RSA signature, the the device cannot establish its identity with the server.

Seems like a catch-22. If there's no signature on the X25519 cert, openssl will be happy, but the server cannot verify the device's identity...? Am I missing something?

Weather Guy

unread,
Apr 21, 2022, 2:07:48 PM4/21/22
to TasmotaUsers
This must be a really tough question, but I think I found an answer. Tried asking on mosquitto and openssl mailing lists/user groups with no answer either.

It appears this is related to mosquitto being configured to require a certificate from each Tasmota device. That's really handy because it allows the broker to validate the identity of each device w/o requiring a user name/password login.

The authentication process requires two things:
  1. The client (Tasmota) must send a copy it's certificate (e.g. with P-256 EC public key) to the broker. The broker can verify it's a valid cert because it is signed by the local root CA, and the broker has a copy of the root cert.
  2. The client needs to prove that it has the private key for the certificate. To do this, it must provide a hash (i.e. signature) for a pre-agreed amount of prior traffic using that private key.
The X25519 EC protocol does not allow the key pair to be used for signing, so the client has no way to provide a hash for the traffic using its private key.

Oh, Heller. Catch-a-twenty-two.

This probably means the only way that X25519 can be used if mosquitto doesn't require certificates from its clients. Then, user name/password logins would be required in mosquitto, and that's just another system management headache.

Rhetorically, why does this matter and why the interest in X25519? I suppose that to many or most folks it doesn't matter. To some security-conscious people however, it matters because X25519 is the only elliptic curve supported by Tasmota which is considered safe (see https://safecurves.cr.yp.to/). Again, there are plenty of arguments to say "don't worry about it", but at the very least, it's good to understand the risks involved.

Next question: Can Tasmota and mosquitto be configured to use a local root CA with P-256 EC signature (instead of  2048-bit RSA). This has the potential to save several hundred bytes of memory in each device, since EC public keys are about 32 bytes compared to 256 bytes for RSA.

iocir...@gmail.com

unread,
Sep 27, 2023, 11:22:10 AM9/27/23
to TasmotaUsers
Great conversation @Stephan.

Can i add the cert files in tasmota built, without entering the keys in the web console ?

Thanks in advance.
Reply all
Reply to author
Forward
0 new messages