Need working example for openHAB MQTT over TLS

Tags: #<Tag:0x00007efebd7b6980> #<Tag:0x00007efebd7b68b8> #<Tag:0x00007efebd7b67f0>

Hello - I’ve been using openHAB for many years since the 1.x days and am currently runnign the latest 2.5.x. I’m trying to move all of my MQTT connections from plain text uname/passwd to encrypted connections with TLS. I have multiple machines running openHAB so not all of my openHAB MQTT connections are to localhost.

I have set up my broker to accept incoming TLS connections, created self-signed X509 certs and can successfully connect via the command line - like this:

mosquitto_pub -h 192.168.1.200 -p 8883 -i "blahblah" --cafile ./ca.crt --cert ./client.crt  --key ./client.key -d -t "foo/bar/motion" -m "OPEN"

I have set up all of my various devices (a few cameras that communicate via MQTT), scripts (Python, PERL, sh, etc) to use MQTT via TLS, but I cannot seem to get openHAB to successful connect.

I have googled and searched this forum and while there seems to be a lot of information out there, it all seems to be old and no longer relevant - typically from the OH 2.x beta/milestone release days. The most relevant thread I have found is this one:

This thread even has a new post from @DiViNe a few days also looking for help on this topic, but the examples in this tutorial don’t work and the thread seems to be abandoned.

So, does anyone in the community have a working example of how to create certs needed, get them into OH and connect to an MQTT broker over TLS? Once we have this defined, I’ll contact the binding’s author and see if we can get this added to the documentation.

How did you setup the bridge paperUI or things file?

Did you setup a basic auth username password?

did you set secure to true?

@denominator

I haven’t been able to get any tls certs into openHAB so trying to setup a client and connect doesn’t do much.

I configured a client on paperUI with secure connection turned on and the port set to 8883, the MQTT over TLS port.

The thing never goes online showing this error in paperUI

and I see this in the Broker log:

1609181961: OpenSSL Error: error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate
1609181961: Socket error on client <unknown>, disconnecting.
1609181968: Received PINGREQ from Net::MQTT::Simple[SGXAEKZXCB]

So it is not the simple configuration of the client in openhab that I cannot figure out, it is the step prior to this in getting certificate into OH to use in this connection.

What did you use for common name in cert your IP or Hostname. Are you connecting with openhab with the same name?

You shouldent need a cert to connect client to server the same as https. Well that is my understanding. I probably wrong.

Yeah, unfortunately that is incorrect. You need the ca-cert, the client cert and client key. In my original post I posted the command line connection from mosquitto_pub where you’ll see arguments with these credentials.

mosquitto_pub -h 192.168.1.200 -p 8883 -i "blahblah" --cafile ./ca.crt --cert ./client.crt  --key ./client.key -d -t "foo/bar/motion" -m "OPEN"

Also in my original post, I posted an old tutorial (that no longer works) where is shows you how to import your x509 certs into a java keystore and add that keystore to the commandline options that launch openhab.

So, this is what needs to be done, as there seems to be no other way to get the certs into OH, but I have no idea how to do this.

Ok good to know. Is the mqtt broker on the same computer as openHAB.

I don’t use tls but I did try and set it up. It has been on my todo list. I will let you know if I figure it out.

From my original post:

A connection to localhost won’t connect unless you used that as the common name while creating the cert.

I can see you are frustrated and you likely know more than me on the subject. Currenty we borh can’t get it to work. When I get time later today I will plod along and see if I can get it working.

Thanks @denominator - Yes - you are right on the common name for the cert.

I used the ip address of the machine the broker is running on when creating my certs. In this example it is 192.168.1.200. I can connect from both the broker’s machine as well as other machines on my LAN using:

mosquitto_pub -h 192.168.1.200 -p 8883 -i "blahblah" --cafile ./ca.crt --cert ./client.crt  --key ./client.key -d -t "foo/bar/motion" -m "OPEN"

So I know I have the broker configured correctly as well as the x509 certs configured correctly to accept connections to the IP address. The thing is that OH doesn’t know these certs exist, hence the broker’s error when trying to make OH connect:

1609181961: OpenSSL Error: error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate
1609181961: Socket error on client <unknown>, disconnecting.
1609181968: Received PINGREQ from Net::MQTT::Simple[SGXAEKZXCB]

The broker is saying that OH never sent a cert, which again, makes sense since OH doesn’t know anything about these certs.

@edolis Do you think you can help here?

1 Like

sure guys, just finished going through the process.
a) certificates: created using
openssl genrsa -des3 -out ca.key 2048 (generates ca key)
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt (generates cert auth certificate)
openssl genrsa -out server.key 2048 (server key pair)
openssl req -new -key server.key -out server.csr (server cert request)
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 18000 (server cert)
A couple of notes about this.
a) here a template of the data I filled in

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
Country Name (2 letter code) [AU]:IT
State or Province Name (full name) [Some-State]:ITALY
Locality Name (eg, city) []:Rome
Organization Name (eg, company) [Internet Widgits Pty Ltd]:EDcertAuthority
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:E. Dolis
Email Address []:exxxxxxxxx@gmail.com

the data filled in for the server should be different, in the end it makes sense as a CA authority should be different from the entity requesting the cert. I read that if data are exactly the same, things get broken because the two certs are nearly the same (?!)

b) watch the durations. I have so far tested the setup with the CA key issued for 1826 days and the server cert for 360. Since this cert is just for private use in my network, I wanted to push it further. I tried a high value for CA days and the resulting certificates seem to be invalid for mosquitto (the service wont start)’
as you see, I have pushed the server cert to kind of 50yearish and the server starts fine, need to test is in running env though

b) mosquitto.conf (add file in conf.d folder)

    log_type all
    log_type error
    log_type warning
    connection_messages true
    log_timestamp true
    allow_anonymous false
    password_file /etc/mosquitto/passwd
#SSL certificates
# note: if you want to restrict non-TSL connections to localhost, add localhost at the end of the following line
listener 1883
listener 8883
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
cafile  /etc/mosquitto/ca_certificates/ca.crt

other note. You create the username and passwords in mosquitto using the directions of steve

I had some issues as I used some command and discovered that the user entries were not concatenated. That is the password file was regenerated. Maybe I did something wrong, I didn’t track back the issue - just solved appending manually the contents.
This to say, if you created a new user, just check its entry is not replacing the previous ones.

Done this, well, everything should be set. I tested using a MQTT Explorer session (you need to add the ca.crt to the server certificates. + settings: validate->no TLS->yes) not from localhost and both the TSL and the plain username\pwd go through.

On OpenHAB 3 side here are the settings

UID: mqtt:broker:MOSQ_BROKER
label: Mosquitto broker
thingTypeUID: mqtt:broker
configuration:
lwtQos: 0
publickeypin: true
keepAlive: 60
clientid: f257ef8b-6490-4df8-9b03-64def5bf0f8b
certificate: CAB1697C204DE83771A3511E2137347899D4D3A4AB494C2725A151795CBB17F0
publickey: AE9E2E08D4C0E2EFC0FB7C6E69A07F0415DA6913B0EA4C9CC4B9F8AE4934DCDC
secure: true
certificatepin: true
password: **********
qos: 0
reconnectTime: 60000
host: localhost
lwtRetain: true
username: openHAB
enableDiscovery: true

The only settings I keyed in were host, username, password. I noticed that changing certificates I get an error related to pinning - I simply recreated the thing - I guess that when got more time I’ll try to understand more about this pinning thing.

Well, if this helped in any way and you wish to reciprocate, please solve this riddle of mine: How do I read the logs of mosquitto in Raspbian? very new to Linux and still not managed to do that :pleading_face:
EDIT:
I figured it out. Sheer luck sudo journalctl -u mosquitto.service -b

1 Like

@edolis,

Thanks for this write up. Unfortunately I don’t think you are actually connecting via TLS.

  • In your example, you create the CA certs, then you created server certs. (I think) This would allow the broker (mosquitto server) to send to the cert to the openHAB client and the openHAB client to remember that cert after the first connection. This allows the client to “verify” the host (this is what the cert pining stuff is in OH), but does not actually create a TLS connection.

  • You never created a client cert for openHAB

  • You never import any certs into openHAB

  • You have a username/password in your openHAB client configuration. TLS connections do not use username/passwords at all, they verify the login via the certs that you never created.

For example: using the command line clients and connecting to a broker I have set to accept both plain and TLS connections:

My /etc/mosquitto/conf.d/mosquitto.conf

listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd

listener 8883
#ssl settings
cafile /etc/mosquitto/ca_certificates/ca.crt
keyfile /etc/mosquitto/certs/server.key
certfile /etc/mosquitto/certs/server.crt
#client certifcate settings
require_certificate true
use_identity_as_username true

First, I show that if I specify no credentials, the broker rejects the connection (note, in your example config of mosquitto, you don’t specify allow_anonymous false so I suspect anyone can connect to your broker on port 1883 with no credentials at all!)

mosquitto_pub -h 192.168.1.200 -p 1883 -i "Test-Client" -t "testtopic/test" -m 'foobbar'
Connection Refused: not authorised.
Error: The connection was refused.

Next, I show an unencrypted connection to my broker on port 1883 using uname/passwd authentication

mosquitto_pub -h 192.168.1.200 -p 1883 -i “Test-Client” -u foo -P bar -d -t “testtopic/test” -m ‘foobbar’
Client Test-Client sending CONNECT
Client Test-Client received CONNACK
Client Test-Client sending PUBLISH (d0, q0, r0, m1, ‘testtopic/test’, … (7 bytes))
Client Test-Client sending DISCONNECT

In my mosquitto log I see:

1609602216: New connection from 192.168.1.50 on port 1883.
1609602216: New client connected from 192.168.1.50 as Test-Client (c1, k60, u'openhabian').
1609602216: No will message specified.
1609602216: Sending CONNACK to Test-Client (0, 0)
1609602216: Received PUBLISH from Test-Client (d0, q0, r0, m0, 'testtopic/test', ... (7 bytes))
1609602216: Received DISCONNECT from Test-Client

Lastly is a TLS connection to port 8883 which uses no uname/passed at all

mosquitto_pub -h 192.168.1.200 -p 8883 -i "Test-Client" --cafile /home/tom/ssl/ca.crt --cert /home/tom/ssl/client.crt  --key /home/tom/ssl/client.key -d -t "testtopic/test" -m 'foobbar'

In my mosquitto log I see:

1609601153: New connection from 192.168.1.50 on port 8883.
1609601153: New client connected from 192.168.1.50 as Test-Client (c1, k60, u'Heyu').
1609601153: No will message specified.
1609601153: Sending CONNACK to Test-Client (0, 0)
1609601153: Received PUBLISH from Test-Client (d0, q0, r0, m0, 'testtopic/test', ... (7 bytes))
1609601153: Received DISCONNECT from Test-Client

BTW, to answer your questions, mosquitto logs are configured by you in

/etc/mosquitto/mosquitto.conf 

with the line:

log_dest file /var/log/mosquitto/mosquitto.log

So for me, to watch the log in real time, I use

tail -f /var/log/mosquitto/mosquitto.log

you are correct - I misunderstood SSL for TSL.Now I understand your issue way better.
Let me work on it and I’ll get back to you, I am also interested in TSL (now :D) :slight_smile:
BTW just to understand, did you already try the instructions found here mosquitto-tls man page | Eclipse Mosquitto?

This link provides instructions on how to generate certs and set up a mosquitto broker for TLS. Mine is already configured and accepting TLS connections for many clients.

What I need is instructions for configuring the openHAB client to connect via TLS.

Thanks for your help!

1 Like

and working on the two parameters of the broker bridge
certificate: CAB1697C204DE83771A3511E2137347899D4D3A4AB494C2725A151795CBB17F0
publickey: AE9E2E08D4C0E2EFC0FB7C6E69A07F0415DA6913B0EA4C9CC4B9F8AE4934DCDC
did not help, right? Because those are the only places I see where you could work with certificates.

This cannot be configured via paperUI. You need to import the keys into a java keystore and then modify the openhab start up script to point to that keystore.

In my original post, I point to the tutorial that shows how to do this. Unfortunately is is out of date and no longer works, I cannot seem to figure out how to make it actually work:

I only set up certs (“real” ones, from Let’s Encrypt, for external facing services) however my understanding is that the certs only reside on the server?

In this scenario (I also use MQTT) isn’t OpenHAB the “client” and therefore should not need any certs?

Or maybe “real” PKI / TLS (i.e., httpS) work differently than “self-signed” certs. As I realize you are trying to do the latter here.

@TRS-80 [Love the uname BTW] - There are certs on the MQTT broker as well as client certs.

I have been under the belief that both client and server (broker) were needed for encrypted communication (TLS). What I think I may be coming to wonder is if the broker’s certs are actually used to encrypt the communication. Then, similar to ssh, you can log in via uname/passwd or use a cert on the client. I’m thinking that is what @edolis may have accomplished, encrypted communication but uname/passwd authentication allowed rather than using a cert for authentication, but to be honest I’m not sure.

If what I said above is true, I guess what I am trying to understand is how to import my certs into the openHAB MQTT client to use for authentication to the MQTT broker over TLS.

@ tommycw10, I think there must be a way to use no uname\pwd and have just client cert to take care of comm.
I have been trying to reproduce your environment for knowledge sake and at the moment I’m drained out of energies, everything is just too much at the moment and SSL things keep piling up the more I dig into that big pile. Most I accomplished is this for the time being

I tried to reproduce the set up and I still cannot make mosquitto TLS work (so I am at least a step behind you)

pi@raspi00:/etc/mosquitto/newSSL $ sudo mosquitto_pub -h 192.168.1.220 -p 8883 -i “Test-Client” --cafile /etc/mosquitto/newSSL/ca.crt --cert /etc/mosquitto/newSSL/client.crt --key /etc/mosquitto/newSSL/client.key -d -t “testtopic/test” -m ‘foobbar_TSL’
Enter PEM pass phrase:
Client Test-Client sending CONNECT
Error: host name verification failed.
OpenSSL Error[0]: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
Error: A TLS error occurred.

which would mean the password of the cert is ok but the validation fails (why? dunno)

this goes in pair with the OH broker

io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

and on mosquitto side I get

1609616770: New connection from 127.0.0.1 on port 8883.
1609616770: OpenSSL Error[0]: error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate
1609616770: Socket error on client , disconnecting.

which sounds like yours.
Now I was reading here c++ - OpenSSl Error: peer did not return a certificate - Stack Overflow and the part which sounds interesting is

Part of requesting that the client send its certificate, via the CertificateRequest message, is including, in that request, a list of the CAs that the server trusts (i.e. that it will use for verifying any client-provided certificates). Servers may trust multiple different CAs, and a given client may have multiple different certificates to choose from. The CertificateRequest message thus contains a list of the CAs, and the client will then choose which of its client certificates matches up with those CAs.
Thus to configure OpenSSL with that list of CAs used for verifying client certs, you would use the SSL_CTX_load_verify_locations() function, and point it at a PEM file of concatenated certificates, and/or a directory of trusted certificates (hashed using the OpenSSL c_rehash utility). Without this, your server may be sending the CertificateRequest message, but with an empty list of CAs, and thus the client does not/cannot choose which of its client certs to send.

This to say that I think, let’s say I’ve got a gut feeling the the error does not lies with the sw implementation of Mosquitto or openhab, but might be an error raised at lower level by the functions of OpenSSL (I should to check the source code, the impression is that the log just tallies the response of openSSL which cannot handle the communication.
Now, the question would be why? As I have been reading around could be either this CA not being tranferret to the client who does not know what to reply or a silly misalignment in the parameters used ny openssl or something different in java11 maybe?
I’m too steamed now, but I would go and chech the doc mentioned in the original mosquitto.conf (the one huge, all commented out, it’s the default for the Win installation - to see if it gives some clue I mean this one

#-----------------------------------------------------------------
#Certificate based SSL/TLS support
#-----------------------------------------------------------------
#The following options can be used to enable certificate based SSL/TLS support
#for this listener. Note that the recommended port for MQTT over TLS is 8883,
#but this must be set manually.
#See also the mosquitto-tls man page and the “Pre-shared-key based SSL/TLS
#support” section. Only one of certificate or PSK encryption support can be
#enabled for any listener.
#Both of certfile and keyfile must be defined to enable certificate based
#TLS encryption.
#Path to the PEM encoded server certificate.
#certfile
#Path to the PEM encoded keyfile.
#keyfile
#If you wish to control which encryption ciphers are used, use the ciphers
and so on.

I think the client is not returning a certificate because you’ve never imported a certificate into openHAB for it to return.