Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How does one control cipher suites over MQTTS? #10217

Open
kazetsukaimiko opened this issue Feb 16, 2024 · 4 comments
Open

How does one control cipher suites over MQTTS? #10217

kazetsukaimiko opened this issue Feb 16, 2024 · 4 comments
Assignees
Labels
in review question generic question

Comments

@kazetsukaimiko
Copy link

Component
MQTT over TLS

  • Generic

Description
How do I control the cipher suites (NOT the TLS version) used for MQTTS? In MqttSslHandlerProvider, I see:

// ...
        sslEngine.setEnabledProtocols(sslEngine.getSupportedProtocols());
        sslEngine.setEnabledCipherSuites(sslEngine.getSupportedCipherSuites());
// ...

Using JSSE JVM arguments like -Djdk.tls.server.cipherSuites does not seem to change anything.

Environment

  • OS: TB Cassandar Docker / Linux
  • ThingsBoard: 3.6.1
@WebDust21
Copy link

This issue is kinda the reverse of #1469, which was closed as completed without any indication provided as to what was actually changed.

Basically, the root of the issue is that in testing, a lot of MCU SSL libraries--and cell modem chips--cannot successfully connect to TBMQ via MQTTS (whether due to bugs or otherwise).
However, they can connect without any hesitation to the "test.mosquitto.org" server port 8884 with TLS and X.509 client cert/key. (Also worth noting that they can connect to TBMQ without any problems if haproxy is used as the TLS front end--although they are promptly rejected by TBMQ at the MQTT CONACK due to haproxy not providing the X.509 client cert to TBMQ for verification. The main difference being that haproxy provides non-EC ciphers.)

The main difference appears to be that--presumably as a result of #1469--TBMQ now only provides elliptic-curve ciphers. While this is "more secure", if it renders certain hardware completely unable to utilize MQTTS, the only remaining option is to drop all security and use an unsecured MQTT connection! Somewhat curiously, the "demo.thingsboard.io" server does not provide an MQTTS port--so I am unable to determine if this difficulty exists in Thingsboard PE.

Yes, I agree that the problem likely lies in the client TLS firmware--but that can unfortunately be a fatal problem only solvable on the server side (i.e. TBMQ). At least in my case, a SIM70x0 modem cannot connect to a TBMQ server via MQTTS--and thus far my requests to Simcom for delta firmware updates have been completely ignored.

In other tests, most of the SSL/TLS libraries for the ESP32 also fail connecting to TBMQ: only one specific wrapper library around mbedTLS can successfully connect to TBMQ. (All the rest fail at the CA cert verification, and do not even get to the client cert.) It is worth noting that PC tools (MQTTX appimage, mosquito_pub, and Paho MQTT via Python) all can successfully connect to TBMQ--but the goal of TBMQ isn't necessarily "networking computers" as much as "connecting IoT devices"!

Here is nmap on "test.mosquitto.org:8884":

> nmap --script ssl-enum-ciphers -p8884 test.mosquitto.org
Starting Nmap 7.80 ( https://nmap.org ) at 2024-02-19 12:02 EST
Nmap scan report for test.mosquitto.org (91.121.93.94)
Host is up (0.20s latency).
Other addresses for test.mosquitto.org (not scanned): 2001:41d0:1:925e::1
rDNS record for 91.121.93.94: ks.ral.me

PORT     STATE SERVICE
8884/tcp open  unknown
| ssl-enum-ciphers: 
|   TLSv1.2: 
|     ciphers: 
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_256_CCM_8 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_256_CCM (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_128_CCM_8 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_128_CCM (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
|       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CCM_8 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CCM (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CCM_8 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CCM (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|     compressors: 
|       NULL
|     cipher preference: server
|_  least strength: A

An nmap scan on TBMQ (self-hosted Thingsboard CE) meanwhile returns the following:

nmap --script ssl-enum-ciphers -p3883 server.net
Starting Nmap 7.80 ( https://nmap.org ) at 2024-02-19 12:04 EST
Nmap scan report for server.net (***.***.***.***)
Host is up (0.054s latency).

PORT     STATE SERVICE
3883/tcp open  vrpn
| ssl-enum-ciphers: 
|   TLSv1.2: 
|     ciphers: 
|       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
|       TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA (prime256v1) - A
|       TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 (prime256v1) - A
|       TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 (prime256v1) - A
|       TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA (prime256v1) - A
|       TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 (prime256v1) - A
|       TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 (prime256v1) - A
|       TLS_ECDH_RSA_WITH_AES_128_CBC_SHA (prime256v1) - A
|       TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 (prime256v1) - A
|       TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 (prime256v1) - A
|       TLS_ECDH_RSA_WITH_AES_256_CBC_SHA (prime256v1) - A
|       TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 (prime256v1) - A
|       TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 (prime256v1) - A
|     compressors: 
|       NULL
|     cipher preference: client
|   TLSv1.3: 
|     ciphers: 
|       TLS_AKE_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_AKE_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_AKE_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
|     cipher preference: client
|_  least strength: A

Only EC ciphers are present on TLSv1.2 (note that most "MCU-scale" TLS libraries do not yet support TLSv1.3. If I could get a firmware update for the SIM7080G modem, it'd support TLSv1.3--but that has not been possible to get.)

So yes...how do we control what cipher suites are offered via MQTTS on TBMQ?

@AndriichnekoDm
Copy link

Hi @kazetsukaimiko @WebDust21 !
Thank you for your question. After careful review, we believe your query points towards an innovative feature that could enhance ThingsBoard.
We have forwarded this to our development team for consideration as a potential feature in our future updates. While we can't guarantee immediate implementation, your suggestion is now part of our ongoing discussions for platform enhancements.
If you could provide further details or specific use cases for this feature, it would greatly aid in our assessment and planning process.
Thanks for helping us improve ThingsBoard.

@WebDust21
Copy link

WebDust21 commented Feb 21, 2024

The main goal of this feature would be to allowing control over the TBMQ TLS configuration during deployment of Thingsboard, without requiring in-the-field source code modification of Thingsboard and complete recompilation for deployment.
The end result being that platform users such as #1469 can easily configure TBMQ TLS to be as secure as possible, and at the same time other platform users such as us here on #10217 can easily utilize TBMQ with IoT devices that may be unable to handle the latest ciphers.

Ideally this would be a system environment variable (global scope in the deployment).

@kazetsukaimiko
Copy link
Author

As @WebDust21 mentions (we are collaborating on a project), some IoT devices with modems use hardware built-in MQTT(s) functionality, offloading the MQTT + TLS overhead to the modem. It is not easy to select a cipher set on some of these clients because the support is in the modem's firmware binaries, and sometimes (as we have found) these firmware implementations can be buggy with certain ciphers.

It would help us if we could define the cipher set TB side, so that we can choose the most compatible cipherset to our devices (and eliminate ones with bad client side implementations). Also as @WebDust21 mentioned, forward-thinkers can use this same functionality to choose only the most restrictive and secure cipher sets when they really want a locked down configuration.

In our case, our modems would connect to test.mosquitto.org just fine, but not to TB, using two-way SSL. TB advertises EC-based keys and ciphers only, mosquitto accepts RSA 2048 keys / ciphers. We were banging our heads against this wall for about two weeks trying to get TB to behave as desired using JSSE configuration without success. I went as far as to modify / upgrade the JDK to 17 in the tb-cassandra image to see if the java.security policy changes from 11 -> 17 had any impact (not really, required lots of module path security workarounds, unsupported, etc). Eventually I spelunked into source and found that basically you'd ignore anything we set anyway.

We eventually moved from hardware/modem MQTT / TLS client to adding software layers, abandoning the modem functionality and now we're able to connect, but at a large performance penalty as we don't have hardware accelerated cryptography anymore.

I think this would best be an MQTTS_ environment option, expecting a comma-delimited list of ciphers from the same JDK / JSSE documentation you refer others to. When not passed, it would fallback to all supported cipher suites as you currently do. I thought of opening a PR, but as you use field injection and not constructor injection it was difficult to write mock-based unit tests that could be used to verify my fixes prior to any kind of deployment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in review question generic question
Projects
None yet
Development

No branches or pull requests

4 participants