Creating and Using Client Certificates with MQTT and Mosquitto

Another popular way of authenticating clients is via client certificates and can be use as in addition or as an alternative to using user name and password authentication.



In cryptography, a client certificate is a type of digital certificate that is used by client systems to make authenticated requests to a remote server.

Client certificates play a key role in many mutual authentication designs, providing strong assurances of a requester’s identity. –Wiki

A client certificate identifies the client just like the server certificate identifies the server.

Normally certificates are created and distributed to each client that connects to the server/broker that requires them.

However you can share a client certificate between clients.

As with username and password authentication the broker dictates whether or not a clients need to supply a certificate.

You can use certificates in combination with username and password authentication.

Mosquitto Broker Configuration

The main two settings are:

  • require_certificates – Main setting tells client it needs to supply a certificate when set to true. Default false
  • use_identity_as_username– – When set to true it tells mosquitto not to use the password file but to take the username from the certificate (common name given to certificate when you create it). Default false
  • crlfile – You can create a certificate revocation file that is used to revoke a client certificate

Creating Self SIgned Client Certificates

The client and server must use the same CA (certificate Authority)  for the client and server certificates.

You create the client certificates using the same process as you used for creating a server certificate.

  1. Create a client key  don’t password protect.
  2. Create a client certificate request using the key.
  3. Use the CA key to sign the client certificate request from step 2.

Preparation –

You need an existing CA certificate and private key which you get when you follow the steps for creating your own self signed server certificate.

You need to use the same CA for the client certificates as the server certificate, and the broker needs to use SSL.

This is because  client certificates require an encrypted connection.

If you don’t have a CA certificate then you need create one using the following:

First create a key for the CA

Command is:  openssl genrsa -des3 -out ca.key 2048

create-ca-key

Note: it is OK to create a password protected key for the CA.

Next:  Create a certificate for the CA using the CA key that we created in step 1

Command is:  openssl req -new -x509 -days 1826 -key ca.key -out ca.crt

create-ca-certificate

If you have followed the tutorial on creating server certificates then your folder should look like the one below:

ssl-directory

Step 1

The first step is to create a client private key.

The command is:

openssl genrsa -out client.key 2048

create-client key

Step 2

Next create a certificate request and use the client private key to sign it.

The command is:

openssl req -new -out client.csr -key client.key

You will be presented with a form that you need to complete.

The most important entry is the common name. This name can be used by the broker to identify the client in place of a username.

client-certificate-request
Normally this certificate would be sent to a Certificate authority, but we are our own Certificate authority so we complete the request to create a client certificate

Step 3

Now we complete the request and create a client certificate. The command is:

openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360

create-client-certificate

This is now what our directory looks like

client-cetificates-final-folder

Using Client Certificates

To use client certificates the client requires three files:

  • ca.crt – The Certificate authority certificate
  • client.crt – The client certifcate file
  • client.key – The client private key

Publishing using Mosquitto_pub tool

The command is:

mosquitto_pub --cafile C:\ssl\ca.crt --cert C:\ssl\client.crt --key C:\ssl\client.key -d -h 192.168.1.157 -p 8883 -t test -m "hello there"

using-client-certificates.jpg

Note: You need to use the server name that is on the server certificate. If I use the IP address instead I get this error.

using-client-certificates-error

Publish Using Python

If you use Python you need to set the TLS settings  using:

client.tls_set('c:/ssl/ca.crt','c:/ssl/client.crt',\
'c:/ssl/client.key')

Publish Using Node-Red

On Node red you need to enable the SSL/TLS option in the broker settings.

tls-node-red

and then upload the client files as shown in the screen shot below:

client-certificates-node-red

Mosquitto Broker Connection

When the client connects to the broker and the use_identity_as_username is true then this is what you see:

mosquitto-broker-client-certs

Resources:

Example Mosquitto configuration file:

port 1883
log_type error
log_type notice
log_type information
log_type debug
#allow_anonymous false
#password_file /etc/mosquitto/pass.txt
#Extra Listeners
listener 8883
#ssl settings
cafile /home/steve/mos/certs/ca.crt
keyfile /home/steve/mos/certs/server.key
certfile /home/steve/mos/certs/server.crt
#client certifcate settings
require_certificate true
use_identity_as_username true

Terms Used

CA= Certificate Authority
Private Key = An encryption key that isn’t shared and needs to be stored securely
Public Key= An encryption key that is shared and doesn’t needs to be stored securely.
Certificate Request = An application for a certificate made to a certificate authority. Like a passport application

Shell Scripts

To save you typing I’ve created two Linux shell scripts that run the commands and create server and client certificates and keys as in this tutorial and the server certificate tutorial.

Related Tutorials

Please rate? And use Comments to let me know more

97 comments

  1. Hi Steve

    We have a dockerized microservice that is running on Ubuntu 18.04 which allows registration of devices. As part of registration, the microservice receives self-signed certificates from the device which are stored in local database along with thumbprints. For future HTTPS communication, this self-signed certificate and the corresponding thumbprint is used to verify the incoming requests. This works well with HTTPS channel. We need similar authentication/verification for the MQTT channel as well using Mosquitto broker.

    1. Given that each device generates its own self-signed certificates, what are the options we have in this scenario?

    2. Is it possible to store all the self-signed certificate in some trust store where Mosquitto can access and validate?

    3. Are there any plugins available that can do this?

    4. In the absence of any off-the-shelf plugins as mentioned in point number 3 above, is there an option where we can register our own custom written plugins that can be used to verify with our own code?

    Appreciate your suggestions on how we can secure the MQTT connection in this case.

    1. Hi
      If you want it to work like your http clients then you will need to wrtie your own plugin. Mosquitto is going down the plugin route so doing so will get much easier.
      Here is an example from a few years ago
      https://github.com/jpmens/mosquitto-auth-plug
      They have also created their own plugin but it doesn’t do certificates you can read about it here
      http://www.steves-internet-guide.com/understanding-mosquitto-dynamic-security-plugin/

      Sorry I can’t be more help
      Rgds
      Steve

  2. Hey steve, I have few Raspberry pi MQTT Mosquitto clients and would like to have unique certificate for all of them. What would be easy method to generate unique client certificate or any automated process you can recommend? Thanks

  3. I have a Mosquitto broker and apache2 web server running ssl using a proper certificate rather than self signed. I am considering using the client certificate side of the Mosquitto but the above article really discusses the self signed certificate route. I am not sure my certificate authority will issue multiple client certificates. Is this something that needs to be done via them or can be done using OpenSSL. Another route to this is to leave the website certificate in place and create self signed CA certificate and client certificates just for the Mosquitto Broker. Any thoughts on this approach ?

    1. Not sure either re CA and client certificates. You need the CA to generate them I’m pretty sure you can do it with lets encrypt but haven’t tried it.
      The only disadvantage of using your own CA is if it needs public access via websockets and then you get a browser warning.
      Rgds
      Steve

  4. Hi Steve,
    Great article! I followed every step using the Windows name for the computer as common name and everything works perfectly. However, when trying the IP as common name (I also used the IP as server in the Node-Red client) the client doesn’t connect and shows the following error:

    1622623498: Client disconnected: protocol error.
    1622623513: New connection from 192.168.0.67:59274 on port 8883.

    Meanwhile, using mosquitto_pub and mosquitto_sub with the same IP (common name) it does work. And it also works fine in Node-Red when I disable the “Verify server certificate”. I am really interested in being able to use the IP as the name of the server correctly. Could you help me please?

    Thanks

    1. Sorry a bit confused as what works and what doesn’t. If you need to disable verify server certificate then you have a cmmon name conflict. the name you use to connect tot he server in the mqtt connect must match the common name on the certificate that you created.
      Does that make sense?
      Rgds
      Steve

  5. Hi Steve and thanks a lot for this tutorial, it really helped me!!!
    I’m having problem with the “Verify server certificate”, when I enable it it doesn’t work and on the mosquitto server log I see:
    New connection from 172.20.0.10:36458 on port 8883.
    Client closed its connection.

    With that option unchecked, it works without any problem.
    What could that be?
    Thanks!!!

    1. This is usually a common name mismatch on the certificate usually because you have common name of testserver.com on the certificate but you access it from the client using its ip address 192.168.1.1 .
      the names must match.
      rgds
      steve

  6. Hi Steve

    I am trying to publish data from my client to local install mqtt broker through TLS/SSL Connection.

    I have a mqtt broker install in my first PC.

    I created CA, Server & Client Cert Key base on your steps above.

    My Conf.file is defined as below.
    # =================================================
    port 8882
    cafile C:\Users\Desktop\certs\ca.crt
    certfile C:\Users\Desktop\certs\server.crt
    keyfile C:\Users\Desktop\certs\server.key
    require_certificate true
    use_identity_as_username true
    tls_version tlsv1.2
    # ===================================================
    In the first PC I am able to publish and subscribe.. You can refer to the command below.

    mosquitto_pub –cafile C:\Users\Desktop\certs\ca.crt –cert C:\Users\Desktop\certs\client.crt –key C:\Users\Desktop\certs\client.key -d -h LAPTOP -p 8882 -t testing -m “hello there”
    Client mosq-tjqNowdNYBtFWZpLAu sending CONNECT
    Client mosq-tjqNowdNYBtFWZpLAu received CONNACK (0)
    Client mosq-tjqNowdNYBtFWZpLAu sending PUBLISH (d0, q0, r0, m1, ‘testing’, … (11 bytes))

    mosquitto_sub –cafile C:\Users\Desktop\certs\ca.crt –cert C:\Users\Desktop\certs\client.crt –key C:\Users\Desktop\certs\client.key -d -h LAPTOP-C4UNUP7O -p 8882 -t testing
    Client mosq-7ZkwwrrhAaxHwO6Zb7 sending CONNECT
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received CONNACK (0)
    Client mosq-7ZkwwrrhAaxHwO6Zb7 sending SUBSCRIBE (Mid: 1, Topic: testing, QoS: 0, Options: 0x00)
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received SUBACK
    Subscribed (mid: 1): 0
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received PUBLISH (d0, q0, r0, m0, ‘testing’, … (11 bytes))
    hello there
    Client mosq-7ZkwwrrhAaxHwO6Zb7 sending PINGREQ
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received PINGRESP
    Client mosq-7ZkwwrrhAaxHwO6Zb7 received PUBLISH (d0, q0, r0, m0, ‘testing’, … (11 bytes))
    hello there
    _______________________________________________________________________________________________

    I copy the CA & Client Cert & Client key over to second PC that is running in the same network as my mqtt broker ( installed in first PC ) and publish through the command below.

    mosquitto_pub –cafile C:\Users\OneDrive\Desktop\certs\ca.crt –cert C:\Users\Desktop\certs\client.crt –key C:\Users\certs\client.key -d -h LAPTOP -p 8882 -t testing -m “hello there”
    Error: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

    Please advise.
    Thanks
    Ng

  7. Hi Steve,

    I have been trying to do this process with LetsEncrypt. I have successfully generated the Client Certificate and Client Key, but unable to authenticate.

    It is giving me the following error:

    Client (null) sending CONNECT
    OpenSSL Error[0]: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
    Error: A TLS error occurred.

    Please guide me with the corrections.

    Thank you.

    1. Try setting the insecure option in the client as it could be a name error. What client are you using and what name/ip are you using to connect to the broker.

      1. Hello Steve,

        Thank you for replying.

        Insecure option It didn’t work.

        I have tried mosquitto_pub as well as Mqtt.fx.

        Thank you.

        1. Then it is probably your certificates. Have you got it working with just ssl and not client certificates?
          Rgds
          Steve

          1. Hi Steve,

            Yes, I got it working with SSL without client certificates. But, it’s not working with Client Certificates.

            I think you can get certificate details by this command:
            openssl s_client -connect mqtt.tattva.cloud:8883

            Please check.

            Regards,
            Punit

          2. I can only suggest you recreate the client certs. What resource are you using to create these certificates?

  8. Hi Steve,

    I am trying to use mqtt over websockets, so I would like to use CA certificates my browser will view as secure. I have been running into problems with this. I have a cloudflare account and it is possible to create client certificates with their service for free, but I have a quick question about this. I basically just create the a private key and a CSR and then use this cloudflare service to sign this CSR. I can do these steps for multiple devices & the broker which will allow me to use TLS? Sorry if this is an overly basic question

      1. Great! Thanks Steve. Also, a related side question. When using MQTT in a browser that already has an SSL certificate — do I need to have another set of private key & certificate credentials in the browser specifically for MQTT(which seems like a dangerous security risk).

        Here is the same original question but with added detail:

        I generate a private key and a client signing request with openssl. Then , under my domain in cloudflare >> SSL/TLS >> Client Certificates >> Create Client Certificate >> Use My Own Private Key & CSR>> I copy the openssl CSR to cloudflare which generates a certificate. I am now left with a cloudflare signed certificate and a private key. However, for the mqtt credentials to work I need the ca.crt – The Certificate authority certificate. This is what has alluded me so far.

        As a sidenote- when trying to publish to the mosquitto broker using my domain name WHILE my domain is “orange clouded” in the cloudflare dashboard–meaning traffic is proxied through cloudflares DDoS detection network.– I am unable to connect or publish to the broker. If I use my IP address it works fine and if I deselect the “orange cloud” then I can publish via domain name. This is because cloudflare doesnt allow requests from port 1883–and many other ports. They do allow web socket ports however. So maybe if I have a IoT device it can use an encrypted mqtt port and when I use MQTT in the browser I can use the WSS protocol.

        This cloudflare developer tutorials link outlines the process, and beneath it they have a tutorial to provision these certs to IoT devices and a mobile app(however, the IoT uses https) — https://developers.cloudflare.com/ssl/client-certificates/create-a-client-certificate

        1. Hi
          I looked at it and I think that you can generate client certs etc and use it over websockets with the broker set up as an origin server.
          Using mqtt and ssl isn’t possible as I see it.
          Is there a reason yo use cloudflare. Will you have many websocket connections?

          1. Hi Steve. Sorry for this. I reached out to cloudflare and asked the maintainers of mosquito- the problem boils down to the fact that I don’t have access to the root certificates/certificate chain for cloudflare which won’t make using these certificates possible. I tried to use cloudflare because they can generate free client certificates. I’ve changed my approach to my problem though. Sorry if I wasted any of your time. You’re tutorials are very helpful. Thanks again Steve.

          2. Yes I have used lets encrypt to secure a web server. I was told that I couldn’t use it to generate client certificates. I don’t know how I could adapt it to Mosquitto & groups of IoT devices. If know of any resources to learn how to do this that would be helpful.

          3. I will try to repeat the process in the tutorial using lets encrypt this week
            Rgds
            Steve

  9. Hey Steve,
    thx for the detailed guide!
    I have a problem with the require_certificate and use_identity_as_username parameter. When I set them up to true, I get the following message:

    Client x|y-commonname sending CONNECT
    Error: A TLS error occured.

    When I set them to false, the TLS connection works as expected (from my point of view).

    The mosquitto.conf looks in principle like:
    listener 8883
    tls_version tlsv1.2
    cafile /y/c/ca_certificates/ca.crt
    certfile /y/c/certs/server.crt
    keyfile /y/c/certs/server.key

    require_certificate true
    use_identity_as_username true

    Thank you very much!

    1. When you set them True the broker requires a certificate from the client. Have you configured those. The certificates need to use the same CA as the SSL connection
      Rgds
      Steve

  10. HI all,
    Thanks for such a great tutorial and explanation.
    After applying all this steps i am facing the issue with connection to mqtt broker.(on raspberry and Node RED)
    I also tried to change TLS version on broker side, but without help.

    Thanks in advance

    My mosquitto.conf
    per_listener_settings true
    pid_file /var/packages/mosquitto/target/var/mosquitto.pid
    port 1883
    cafile /volume1/@appstore/mosquitto/var/ca.crt
    certfile /volume1/@appstore/mosquitto/var/server.crt
    keyfile /volume1/@appstore/mosquitto/var/server.key
    listener 8883
    tls_version tlsv1.1
    require_certificate true
    use_identity_as_username true
    log_dest file /volume1/@appstore/mosquitto/var/mosquitto.log
    log_type error
    log_type warning
    log_type notice
    log_type information

    MQTT broker log from NAS synology
    Starting mosquitto command /volume1/@appstore/mosquitto/sbin/mosquitto -d -c /volume1/@appstore/mosquitto/var/mosquitto.conf
    1611316308: mosquitto version 1.6.12 starting
    1611316308: Config loaded from /volume1/@appstore/mosquitto/var/mosquitto.conf.
    1611316308: Opening websockets listen socket on port 8883.
    1611316308: Opening ipv4 listen socket on port 1883.
    1611316308: Opening ipv6 listen socket on port 1883.
    1611316308: mosquitto version 1.6.12 running
    1611317344: New connection from 192.168.1.161 on port 1883.
    1611317344: OpenSSL Error[0]: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol
    1611317344: Socket error on client , disconnecting.
    1611317357: New connection from 192.168.1.161 on port 1883.
    1611317357: OpenSSL Error[0]: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol
    1611317357: Socket error on client , disconnecting.

    The same problem also from Raspberry pi
    pi@raspberrypi:~/automatizacia/MQTT $ mosquitto_pub –tls-version tlsv1.1 –cafile ca.crt –cert client.crt –key client.key -d -h NAS.local -p 1883 -t test -m “hello there”
    Client mosqpub|4064-raspberryp sending CONNECT
    OpenSSL Error: error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
    Error: A TLS error occurred.
    pi@raspberrypi:~/automatizacia/MQTT $ mosquitto_pub –cafile ca.crt –cert client.crt –key client.key -d -h NAS.local -p 8883 -t test -m “hello there”
    Client mosqpub|4065-raspberryp sending CONNECT
    OpenSSL Error: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
    Error: A TLS error occurred.

    Node RED log running in docker on synology:
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36)
    22 Jan 13:09:54 – [info] [mqtt-broker:NAS] Connection failed to broker: mqtts://NAS.local:8883
    22 Jan 13:09:59 – [info] [server:Home Assistant] Connecting to http://supervisor/core
    22 Jan 13:09:59 – [info] [server:Home Assistant] Connected to http://supervisor/core
    22 Jan 13:10:09 – [info] [mqtt-broker:NAS] Connection failed to broker: mqtts://NAS.local:8883

    pi@raspberrypi:~/automatizacia/MQTT $ ping NAS.local
    PING NAS.local (192.168.1.153) 56(84) bytes of data.
    64 bytes from 192.168.1.153 (192.168.1.153): icmp_seq=1 ttl=64 time=1.61 ms
    64 bytes from 192.168.1.153 (192.168.1.153): icmp_seq=2 ttl=64 time=1.31 ms
    64 bytes from 192.168.1.153 (192.168.1.153): icmp_seq=3 ttl=64 time=2.20 ms

  11. Hi Steve,
    really need your help here. I am trying to make this work on Raspberry Pi 4, latest Raspbian image installed.
    I used your scripts to create the certs, but I cannot get things running.
    This is what I get
    ________________
    $ sudo mosquitto_pub –cafile ~/ssl/server-certs/ca.crt –cert ~/ssl/client-certs/client.crt –key ~/ssl/client-certs/client.key -d -h raspi00 -p 8883 -t test -m “hello there”
    Client mosq-eRqbfbeRA630w5Ho14 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.
    ________________
    and in the mosquitto log I read
    _______________________
    New connection from 127.0.0.1 on port 8883.
    1609676639: OpenSSL Error[0]: error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
    1609676639: Socket error on client , disconnecting.
    _______________________

    I have been banging my head for hours, with no luck.
    Have you got any hint/suggestuions on howto move forward to make this work?
    Thanks 🙂

    1. Hi
      It looks like the common name you used on the server certificate isn’t the same as the one you are using in the mosquitto_pub command which is raspi00.
      Use the –insecure switch if that works then it is a name mismatch
      rgds
      steve

      1. Thanks Steve,
        really appreciate your help. Yes, that’s right, I had to recreate the certificates so that the DN of the certificate for the server running Mosquitto is raspi00. That was the issue.
        Many thanks for your kind help again 🙂

  12. Hai,
    Thank you for the reply.
    And it is regardless of self signed certifcates or certificates signed by third party, right?

  13. Hi,
    I was doing few tests for secure MQTT using different certificates. Here is one of the test case which failed for me.
    * used client.crt which is signed by clientCa.crt in my Mqtt Client (mqttnet).
    * used server.crt which is signed by serverCa.crt in mosquitto broker.
    I imported clientCa.crt in trusted root certificate authorities in my server. But still it failed.
    It is given in this blog that “The client and server must use the same CA (certificate Authority) for the client and server certificates.”.
    Does it mean that if client and server does not use same CA, then the server can never authenicate the client certificate?

    Thank you
    Appu

  14. Hi, Steve thx for this post 🙂

    i have a problem here with my project, im using raspberry pi3b+ which has the broker and the publisher, my configuration for broker is:

    pid_file /var/run/mosquitto.pid
    listener 8883 192.168.1.106
    #allow_anonymous true
    connection_messages true
    include_dir /etc/mosquitto/conf.d
    cafile /etc/mosquitto/ca_certificates/mosquitto.org.crt
    keyfile /etc/mosquitto/certs/broker.key
    certfile /etc/mosquitto/certs/broker.crt
    tls_version tlsv1
    protocol mqtt
    #require_certificate true
    #use_identity_as_username true
    #password_file /etc/mosquitto/pwfile

    the publisher is in raspberry pi and the subscriber i want to run it in other machine with ubuntu, the code for the publisher that i use is this

    publish.single(‘BPM’,”%d” % BPM,hostname=’192.168.1.106′,port=8883,tls={‘ca_certs’:”/etc/mosquitto/ca_certificates/mosquitto.org.crt”})

    the subscriber has the next code:

    client.tls_set(ca_certs=”/etc/mosquitto/ca_certificates/mosquitto.org.crt”,certfile=”/home/pi/cliente_pi.crt”,keyfile=”/home/pi/cliente_pi.key”)

    client.connect(host=”192.168.1.106″,port=8883)

    i choose for CA certificate test.mosquitto.org and the same to sign client and server certificates, and its working good if all the scripts publisher and subscriber are in raspberry, good comunication with tls, but when i move the subscriber to other machine with ubuntu it produced this error:

    ssl.SSLCertVerificationError: [SSL: Certificate_verify_failed] IP address mismatch, certificate is not valid for ‘192.168.1.106’. (_ssl.c:1108)

    the curious thing is i tried mosquito_sub -h 192.168.1.106 -p 8883 –cafile /PATH -m “hello world” -t test
    and its working fine the message that i send from raspberry to other laptop with ubuntu it received properly, but when i tried to put the subcriber in script the error appear, i use python 2.7, i tried too with python 3.8 but the error continue appearing.

    i really apreciate some ideas to try 🙂

    Thx

    1. Hi
      Looks like a ca name mismatch try using in insecure option to verify this.
      You alos seem to be mixing publish with subscribe commands
      mosquito_sub -h 192.168.1.106 -p 8883 –cafile /PATH -m “hello world” -t test
      Assume was a typo.
      Also It looks line on the subscribe side you are using client certificates if so remove them and try juts using SSL
      Rgds
      Steve

  15. Hi Steve! nice post btw. I tried this and could not make it work.

    I created a CA key and cert, and also server key and cert and could enable a secure TLS connection, now using the same CA key and following this steps I’m getting the following errors:

    Client side: ssl3_read_bytes:tlsv1 alert unknown ca
    Server side: tls_process_client_certificate:certificate verify failed

    My .conf file has a listener defined as follows:

    # =================================================================
    # MQTT mutual-authentication
    # =================================================================
    listener 8884
    protocol mqtt
    capath /mosquitto/data/ca.crt
    keyfile /mosquitto/data/server.key
    certfile /mosquitto/data/server.crt
    require_certificate true

    —-
    I also tried using the use_identity_as_username flag

    any clues? thanks!

      1. Thanks for the quick reply.

        Indeed, I’ve used your scripts with the same result, I’m deploying everything to a docker container using the eclipse-mosquitto official image (latest version).

        I have also tried using the official documentation: https://mosquitto.org/man/mosquitto-tls-7.html and the problem remains.

        If you have any clues please let me know, I’ll keep on trying to make it work and if I’m successful with this I’ll post my results!

        Thanks again, and sorry for bothering you.

          1. tried in 2 different mac computers and having the same problem, where are you storing the broker certificates ? I’m using a fixed folder should I use some location inside /etc/ ? do you happen to have a full broker config with certificates to share?

            I’m using test.mosquitto.org to test it now, but would love to have something locally and not depend on any 3p.

            Thanks again,

          2. The best solution is to install a local mosquitto broker. If you don’t have one then I will configure one on my network and send you the can so you can test.
            Rgds
            Steve

  16. Hi, Thanks for the great article and tutorial.
    We’re using Mosquitto in an enterprise environment, and we are wanting to move to SSL encrypted traffic.
    We are using Active Directory and have our own domain-based CA.
    Is there a way to get Mosquitto broker to leverage somehow this infrastructure or integrate with it in some way ? All the tutorials are based on using OpenSSL to be ‘your own CA’ and self-sign, but we’ll be looking at managing up to 100 separate brokers and managing the certificates in this way will be an arduous task.
    Any pointers would be greatly appreciated !
    thanks

    1. David
      You can use any CA certificates on mosquitto so you can generate them in AD. However you can’t distribute them to mosquitto using Active directory.
      Take me back a bit as I used to train Active directory and windows 2000 but stopped in about 2003 so I guess it has moved on a lot since then.
      Rgds
      Steve

  17. Steve,

    This is a lot to take in and your guidance has helped, but there’s one tough challenge here: how to make a cert for a TLS connection when you’re just making clients and using someone else’s broker server. In my case that’s CloudMQTT, whose docs leave much to be desired:
    https://www.cloudmqtt.com/docs/faq.html#TLS_SSL

    Do I need their server cert (if I can get it) to make my client certs?

    Cordially,
    Dan

    1. Hi
      Interesting question and I will look into it. However Cloudmqtt don’t say that they support client certificates as far as I can see.
      Rgds
      Steve

  18. Hi Steve,

    Thanks for a great article.

    I am trying to figure out what happens in the following scenarios after a client (for example node-red) connects using client & server certificates and subscribes to a topic which they have read permission (controlled by acl_file).

    1. Client certificate is revoked or expires. Would the client be disconnected?
    2. Read permission on the topic removed for a user. Does a client for that user stop getting messages on that topic?

    Thanks.

    1. Hi
      There is no checking for revoked certificates so nothing would happen.
      For the ACL then the client would not longer receive messages on that topic.
      Rgds
      Steve

    1. I believe you can use a single client certificate for all clients but it isn’t recommended and so if you use client certificates then each client should have its own.

      1. I’m using “my-ca.crt” for connecting mqtt , and in mqtt.config file i gave “cafile /etc/mosquitto/certs/my-ca4.crt”. So for every certificate i generate should i also change the .config file?

        1. The config file on mosquitto stays the same. Each client needs to use it’s own client certificate there is no change needed on the broker other than to configure it to use SSL and client certificates.
          This is the relevant part of the file
          #ssl settings
          cafile /home/steve/mos/certs/ca.crt
          keyfile /home/steve/mos/certs/server.key
          certfile /home/steve/mos/certs/server.crt
          #client certifcate settings
          require_certificate true
          use_identity_as_username true

          Rgds
          Steve

  19. Hi Steve, Thanks for all this information. It has been most useful in the setup and configurations that I have used. There is one puzzle and I cannot get around it. The publishing client requires only Client certificate and key and doesn’t have a placeholder for the server certificate. Is there a way to have such a configuration. So if I use the command above as a template, instead of [[mosquitto_pub -h -p -t -m –cafile mqttproxy-ca.crt -u -P -d –cert mqttproxy-ca.crt –key mqttproxy-ca-pkcs8-withoutpass.key]], I have to use [[mosquitto_pub -h -p -t -m -u -P -d –cert mqttproxy-ca.crt –key mqttproxy-ca-pkcs8-withoutpass.key]]. I am using MQTT proxy for Confluent Kafka as the broker.

    1. Sorry
      Not sure what you mean as thee client doesn’t need to have a copy of the server certificate

  20. Hi Steve, you have been inspiritaion in many aspects, now I am securing all my devices . But I am facing an issue. mosquitto broker is working fine in user&pass , and TLS config on port 8883, tested from paho-eclipse websocket online app. So Iam 100% sure is working, also locally with this command : mosquitto_pub -h tatuiot.com -t test -m “hello again” -p 8883 –capath /etc/ssl/certs/ -u “” -P “” -d , but I am stuck with certificates. (I am using wildcard one for mosquitto broker) but which is the the one that mosquitto_pub is using from this path “/etc/ssl/certs/” I see 273 listed there. Thanks a lot in advance

    1. Hi
      It will use the one that corresponds to the CA on the broker as I understand it just the same way as when you access a website your don’t know the CA of the website so your browser has to search in the store for a matching one.
      Rgds
      Steve

    1. Yes I’m sure it is but I don’t have the time to do that at the moment if yoy develop one let me know
      rgds
      steve

  21. Hi Steve, I setup my mosquitto-tls following your tutorials.
    CA :
    openssl genrsa -des3 -out ca.key 2048
    openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
    Common Name (eg, fully qualified host name) []:test.domain.com

    Server :
    openssl genrsa -out server.key 2048
    openssl req -new -out server.csr -key server.key
    Common Name (eg, fully qualified host name) []:mosquitto.test.domain.com
    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360

    Client :
    openssl genrsa -out client.key 2048
    openssl req -new -out client.csr -key client.key
    Common Name (eg, fully qualified host name) []:device1
    openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360

    mosquitto.conf :
    port 1883
    listener 8883
    cafile /mosquitto/certs/ca.crt
    certfile /mosquitto/certs/server.crt
    keyfile /mosquitto/certs/server.key
    tls_version tlsv1.2
    use_identity_as_username true

    I use MQTT.fx to connect to my broker using ca.crt, client.crt, client.key. But getting following error

    2020-03-30 12:13:09,793 ERROR — MqttFX ClientModel : Error when connecting
    java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217) ~[?:1.8.0_181]
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:372) ~[?:1.8.0_181]

    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_181]
    Caused by: java.security.InvalidKeyException: invalid key format
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:331) ~[?:1.8.0_181]

    2020-03-30 12:13:09,796 ERROR — MqttFX ClientModel : Please verify your Settings (e.g. Broker Address, Broker Port & Client ID) and the user credentials!
    java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_181]
    Caused by: java.security.InvalidKeyException: invalid key format
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:331) ~[?:1.8.0_181]

    Any idea what is wrong with my setup ?

    1. No I have used MQTT.fx.
      I would go back a step and try it first just using SSL and no client certificates and get that working after that introduce the client certificates.
      If you get nowhere then use the ask steve page and get it touch and you can then send me your certs and keys and I will try them. I can also send you a python script to try.
      Rgds
      Steve

      1. I have two ports 1883 & 8883. I was able to connect to port 1883 with no SSL/TLS. Getting above error when I try to connect to port 8883 with SSL/TLS.

        1. Roy
          Have you tried just using SSL and note client certificates. Also have you tried the mosquitto_pub tool. It is also worth trying another machine in case there is a problem with the SSL version.
          Send me your certs and keys and I’ll try them.
          Rgds
          Steve

  22. Hi there,

    Anyone has configured successfully the client certificate for homeassistant mqtt?
    I am using a mosquitto broker and hass version 0.105.2.
    This is the message I get:
    Invalid config for [mqtt]: not a file for dictionary value @ data[‘mqtt’][‘client_key’]. Got ‘client.key’.

    with this configuration.yaml:
    mqtt:
    broker:
    port: 8883
    certificate: /etc/mosquitto/ca_certificates/ca.crt
    client_key: client.key
    client_cert: /etc/mosquitto/certs/client.crt
    tls_version: ‘auto’
    # tls_insecure: true
    # username: hass.client

    It is working perfectly when I am subscribing and publishing with mosquitto clients, from ubuntu.
    In the broker I have enabled the “require_certificate” option.
    But given the error, I guess the mqtt module from hass seems not to accept key file format or similar issue.
    I have already tried to change the permissions, and the issues remains…
    Any idea?

    Thanks a lot!
    jaeg89

    1. Already fixed. It was an issue with the read permissions of the key. I change them once, but I regenerate the key… Stupid me 🙂
      Thanks!

  23. Hi Steve,

    Thanks for the great article! Helped me immensely. The client I am using requests only the CA certificate (ca.crt) and the client certificate (client.crt) and doesn’t ask for the client key (client.key). Should this be possible? It is asking for the certificates in DER format so I have converted them using openSSL but the system still doesn’t work. Other clients I have set up using MQTT.fx have worked OK when using the PEM formatted certs and keys is all good, however when using the DER formatted keys etc Mosquitto reports the following when trying to connect (same message when using either client):

    1580938430: New connection from 192.168.0.59 on port 8883.
    1580938430: OpenSSL Error: error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate
    1580938430: Socket error on client , disconnecting.

    Can you shed any light on this? Do I need to create all keys (not just client) in the DER format?

    1. Hi
      As far a I understand it you need the client key the format shouldn’t matter. If you use the ask steve page to contact me then you can send me all of the files (sever and client) by email and I’ll try them on my broker.
      Rgds
      Steve

  24. Hi, Steve
    Good article!
    I have setup mutual authentication with following configurations and they works well for my client using MQTT.fx.

    port 1883
    allow_anonymous false
    require_certificate true
    use_identity_as_username true
    cafile ~/root.crt
    certfile ~/server.crt
    keyfile ~/server.key

    The question is I do not see mosquitto server have a configuration method can check whether the client’s CN is in a local database for allowing connection. As you can see I already set allow_anonymous to false, although the client is signed by the CA certificate, it is still a unknown client to me when it is not in the ‘database’.
    The acl_file can limit the Pub/Sub permission of a specific username, but it can’t deny a client not in list.

    1. Just to clarify.
      You are trying tp limit access using certificate common name?
      Can you send me the acl you are using and I’ll try it.

      1. I did not build a ACL file. After checked ACL file syntax, it looks like it only be used to limit read/write permission to topics. It should be easy to define a ACL to not allow a user to pub/sub to any topic. But I want that user to be refused during connection. By checking it’s username (CN, as I defined use_identity_as_username)

        1. Hi
          It looks to me that the client name can be used for ACL control but not authentication as the certificate is doing that job.
          It is something I haven’t checked but reading the config file data seems to indicate that.
          rgds
          steve

  25. Hi Steve,

    Thank you for this wonderful article. I’m trying to achieve the same flow using Nginx as a load balancer and HiveMQ enterprise MQTT broker. The point is to Terminate SSL at the load balancer and also use client certificates for authentication. But the problem I’m facing is that the client certificates, even when changing the name of the client, works. Nginx authenticates the client irrespective of what the client ID is. Am I correct in assuming that this shouldn’t be the case? Only a client whose ClientID matches the FQDN string passed during its certificate creation be authenticated?

    1. Sorry but I’ve never used nginx with MQTT. However I suspect that nginx doesn’t cat about the client certificates as the authentication should be done on the broker.
      rgds
      steve

  26. Hi Steve,
    Very well explained!!
    I have a question,
    ca.crt – The Certificate authority certificate
    client.crt – The client certifcate file
    client.key – The client private key
    While publishing a message, we are using below:
    client.tls_set(‘c:/ssl/ca.crt’,’c:/ssl/client.crt’,\
    ‘c:/ssl/client.key’)

    Why should we send private key (client.key) in the handshake? That is to be stored securely right?
    Can you pls explain me in detail.

    Also We have an assignment:
    We are creating self-signed certificates using “openssl rsa” in the middleware(in our project). We’ve generated a cafile, certfile and privatekey and assigned it to vernemq broker(hosted in a cloud platform).

    Later we created multiple clients, each client is assigned a certfile and private key. Anyways cafile would be the same. Now these clients need to publish messages to the broker.
    We have configured in the message broker config file as below:
    listener.ssl.require_certificate=on and listener.ssl.use_identity_as_username=on

    How can the clients publish messages to the broker using their client certificates and how would the broker validate if it is a valid client? How can we do asymmetric key encryption?
    Can u pls describe any approach for this?

    Thanks in advance.

      1. Hi Steve,
        I have a question.
        I’m using a vernemq message broker. I have a client in VM which is trying to connect to the message broker using certificates. (Self-signed).
        I used the same CA in generating certificates for both the message broker and the client.
        CN for Vernemq message broker is “message broker”
        CN for client in VM is “send-data”
        client is written in nestjs( nodejs framework)
        Now, when i try to make a connection from the client to the message broker.

        It says “Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate’s altnames: Host: vmq.services. is not cert’s CN: messagebroker”

        Any idea? Why am i getting this error and how to resolve it?

        Thanks,
        Sri Durga

        1. I can only assume that the certificate common name doesn’t match the name that is being used by the server it is being used on. Most clients have an insecure option which bypasses this check. If that works then it more or less proves the name/IP mismatch.
          rgds
          steve

  27. Hi Steve.
    First of all thank you for all of these information, but I want to know what is the purpose of these client step. What will happen if we use only ca.crt but not client.crt and client.key? Thank you in advance…

    1. Using the ca.crt only on the client is the way most clients will be configured. This mode is effectively the same mode as you use on a web browser when accessing a secure site.
      You only need client certificates if you want to use them to authenticate the client usually in place of a username/password authentication.
      DEoes that make sense?
      Rgds
      Steve

      1. Thank you for a quick response 🙂
        Now. I am trying to use client certificate but I am facing with the error:
        ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:661)
        when I try to connect. What can be the reason of this ? Btw
        my tls_set code is —-
        client.tls_set(‘/home/pi/Security/ca.crt’,’/home/pi/Security/client1.crt’,’/home/pi/Security/client1.key’)
        Is there any error here?
        Thx in advance again …

        1. Hi
          Looks ok. Did you try just using the ca.crt file. Can you show me the mosquitto.conf file for this.
          Rgds
          Steve

          1. My original conf file is like :
            port 1883
            listener 8883
            cafile /home/pi/Security/ca.crt
            keyfile /home/pi/Security/server.key
            certfile /home/pi/Security/server.crt

            I’m sorry for deleting by mistake.

          2. You also need these lines when using client certificates
            #client certifcate settings
            require_certificate true
            use_identity_as_username true
            rgds
            steve

        2. Hi Steve,
          Thanks for this awesome blog post!
          I am facing one challenge… I have a device certificate (device.pem) ,(devicekey.key) and secret key from the available device in cloud but I am confused which certificate do I need to use in tls_set().
          I have tried with eclipse paho tool and I have used cacerts (available in jre folder) with password “changeit” and devicekey.key as keystore and device secret as password.
          Please help and let me know if any other information is required.
          Thanks,
          Sunny

          1. Hi
            You need the Ca certificate the client certificate and the client key
            example

            client.tls_set(‘c:/ssl/ca.crt’,’c:/ssl/client.crt’,\
            ‘c:/ssl/client.key’)
            Rgds
            steve

          2. Hi Steve,
            Thanks for the help.
            I have provided all the certificates (ca.crt, client.crt, client.key) in tls_set but when I am trying to execute client.connect(broker,8883,timeout) I am getting [SSL:CERTIFICATE_VERIFY_FAILED] certificate verify failed : unable to get local issuer certificate (_ssl.c:1056)
            Trace back: selfobj.do_handshake()

            Please help !

            Thanks,
            Sunny

          3. This is usually caused by the common name on the server certificate being different to the name you use when you access the broker. If you use the insecure option in the client then it overrides the check and it should work. If it does then it is a clear sign that you have a name mismatch
            rgds
            steve

          4. Hi Steve,
            Thanks for the reply!
            Please help me in solving my confusion. What will be the use of the device certificate then if i will be using the certificated generated by me using openssl?
            I tried with the “MQTT.fx” and enabled “TLS/SSL” and “selected self sign certificates in keystore” option.
            my keystore file : cacerts -> got from jre folder where java is installed
            client keystore file : client.key
            client keystore is generated by “openssl pkcs12 -export -in certificate.pem -inkey certificate.pem -out client.ks”
            client keystore password : password from device certificate (generated automatically )
            client keypair password : same as client keystore password.

            so my confusion is what will be the values in tls_set parameter() ?

            Thanks for the help!

          5. Hi
            Client certificates are used instead of username/password authentication.
            Client certificates are considered more secure than username/password encryption but they are more difficult to set up and less well understood.
            However they need an encrypted connection to work and therefore the connection must use SSL.
            Does that make sense
            rgds
            steve

Leave a Reply to Umut Cancel reply

Your email address will not be published. Required fields are marked *