Search code examples
sslssl-certificatemqtttls1.2mosquitto

TLS (v1.2) client certificate only sometimes required. Why?


I have set up a mosquitto MQTT server and created everything to encrypt the communication. The certificates are created with this script here. Everything works fine. The certificates check out with openssl verify -CAfile ca.crt cool-server.crt as "ok".

But I do not understand why on different clients differently.

The broker runs on an Ubuntu 18 server. Config here:

root@cool-server:~# cat /etc/mosquitto/conf.d/default.conf 
allow_anonymous false
password_file /etc/mosquitto/passwd

listener 1883 localhost

listener 8883

cafile /etc/mosquitto/ca_certificates/ca.crt
certfile /etc/mosquitto/certs/cool-server.crt
keyfile /etc/mosquitto/certs/cool-server.key

require_certificate true
#require_certificate false # tried this too

tls_version tlsv1.2

root@cool-server:~# cat /etc/mosquitto/mosquitto.conf 
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example

pid_file /var/run/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_type all
log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

I can connect to it via

  • mosquitto_sub / _pub (needs the ca.cert file)
  • an Arduino based ESP8266 with AsyncMqttCliet (needs a fingerprint derived with openssl from the certificates)
  • an custom Android app (needs nothing???) (all code below).

The questions are:

1. Why is it, that some clients need a certificate of fingerprint and others not?

According to my knowledge, TLS/SSL can secure the connection with only a certificate on the server side, but I am not sure. The Android app connects to my broker without any certificate or fingerprint, while mosquitto_pub only works with a cacert. Even if I configure the broker with require_certificate false the client still needs to specify the cacert. --insecure does not solve this. On the other hand, my ESP8266 only need a short fingerprint.

2. Are all my connections (especially the Android one) secure/encrypted?

ESP8266 / Arduino

const uint8_t mqttCertFingerprint[] = {0xA6, 0x4D, 0x9F, 0x43B, 0x80, 0xB7, 0xB2, 0x9A, 0x9D, 0xCB, 0xC9, 0xF7, 0xAA, 0xCC, 0x30, 0xEF, 0xF4, 0xFC, 0xD3, 0x31};
mqttClient_.setSecure(true);
mqttClient_.addServerFingerprint(mqttCertFingerprint);

Bash

mosquitto_pub -h cool-server.com -p 8883 -u user -P Password -t "topic/name" -m "hello" --cafile path/to/ca.crt

Android

       if (serverUri.contains("ssl")) {
        class TrustEveryoneManager implements X509TrustManager {
            public void checkClientTrusted(X509Certificate[] arg0, String arg1){}
            public void checkServerTrusted(X509Certificate[] arg0, String arg1){}
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        }

        SSLContext sslContext = SSLContext.getInstance("tls");
        sslContext.init(null, new TrustManager[]{new TrustEveryoneManager()}, new SecureRandom());

        mqttConnectOptions.setSocketFactory(sslContext.getSocketFactory());
    }

Solution

  • Assuming you are not using self signed certs.

    Both mosquitto_pub/sub and the PubSubClient Library require a CA certificate because they do not have a baked in trust store that contains a list of trusted certificates from the Certificate Authorities.

    On Android there is a baked Trust Store.

    On Linux you can normally point the mosquitto tools at /etc/ssl/certs/ to use the Trust Store CA certs that ship with the OS.

    Update:

    1. The certificate fingerprint is enough to verify that brokers certificate as long as the broker presents the full certificate chain when the client connects. The client can check that the broker certificate is signed by the CA cert and that the CA cert fingerprint matches the supplied one.

    2. No, you Android client is not secure. You have explicitly told Android to trust any certificate presented by the broker, this means that anybody can run a man in the middle attack against your android application and you will never be able to tell.