MQTT Mosquitto broker – Client Authentication and Client Certificates

After seeing how to set up transport layer security for the Mosquitto MQTT broker by using the Transport layer security on this post, we need to see how to setup client authentication (only authorized clients can connect to the broker) either by using the common user/password based authentication method or using client certificates.

Authentication by user and password:
First let’s enable authentication to the broker by setting up user and password authentication. For enabling this kind of authentication we need to modify the broker configuration (/etc/mosquitto/mosquitto.conf in my case) file and change the following entries:

allow_anonymous false
password_file /etc/mosquitto/passwd_mqtt

Before restarting the MQTT broker we need to add some users to the passwd_mqtt file with the command mosquitto_passwd:

mosquitto_passwd -c passwd_mqtt user1

The -c parameter is for creating the initial password file, if doesn’t exist, otherwise it will overwrite it!. For adding new users or update the passwords just run the command without the -c parameter.

After restarting the broker will should not be able to logon anonymously:

# mosquitto_pub --cafile /etc/mosquitto/certs/ca.crt -h localhost -t "test" -m "message" -p 8883 -d
Client mosqpub/25688-pcortex sending CONNECT
Client mosqpub/25688-pcortex received CONNACK
Connection Refused: not authorised.
Error: The connection was refused.

But providing the user name and password:

# mosquitto_pub --cafile /etc/mosquitto/certs/ca.crt -h localhost -t "test" -m "message" -p 8883 -d -u user1 -P secret
Client mosqpub/25709-pcortex sending CONNECT
Client mosqpub/25709-pcortex received CONNACK
Client mosqpub/25709-pcortex sending PUBLISH (d0, q0, r0, m1, 'test', ... (7 bytes))
Client mosqpub/25709-pcortex sending DISCONNECT 

For subscription, the same has to be done, again by providing an user and password:

# mosquitto_sub -t \$SYS/broker/bytes/\# -v --cafile /etc/mosquitto/certs/ca.crt -p 8883 -u user1 -P secret
$SYS/broker/bytes/received 217
$SYS/broker/bytes/sent 20

Authentication by using client certificates
Using client certificates, signed by a certificate authority, assures the client identity. The certificate authority used must be the same used by the server certificates and is only supported over TLS/SSL.
For using client certificates for authentication, we need to change the listener configuration for TLS/SSL by adding the following directives:

# MQTT over TLS/SSL
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/hostname.crt
keyfile /etc/mosquitto/certs/hostname.key
require_certificate true
use_identity_as_username true

The require_certificate directive with the value true means that clients must now provide a client certificate to connect.
The use_identity_as_username means that the user name of the connecting user is taken from the CN (Common Name) property of the certificate, otherwise we still need to provide an user and password.

With the above new configuration, we now can’t access the broker with user/password token:

mosquitto_pub --cafile /etc/mosquitto/certs/ca.crt -h localhost -t "test" -m "message" -p 8883 -d -u user1 -P secret
Client mosqpub/26549-pcortex sending CONNECT
Error: A TLS error occurred.

the result on the log file is:

1478537500: New connection from 127.0.0.1 on port 8883.
1478537500: OpenSSL Error: error:140890C7:SSL routines:ssl3_get_client_certificate:peer did not return a certificate
1478537500: Socket error on client , disconnecting.

For accessing now the broker we must provide a client certificate and a private key. The client certificate must be generated from the same CA (Certificate authority) that created the server certificate, otherwise, the client certificate can’t be validated, and the connection fails:

1478537629: New connection from 127.0.0.1 on port 8883.
1478537629: OpenSSL Error: error:14089086:SSL routines:ssl3_get_client_certificate:certificate verify failed
1478537629: Socket error on client , disconnecting.

So on the same directory where the ca.crt and ca.key are residing execute the script to create the client certificate. For example for creating a client certificate for user1, we need to execute the following command:

# ./gen_CA.sh client user1

And we should have three files, two of them the user1.crt, the user certificate, and the user1.key, the user1 private key.

We can now logon to the broker:

# mosquitto_pub --cafile /etc/mosquitto/certs/ca.crt -h localhost -t "test" -m "message" -p 8883 -d  --cert user1.crt --key user1.key 
Client mosqpub/30264-pcortex sending CONNECT
Client mosqpub/30264-pcortex received CONNACK
Client mosqpub/30264-pcortex sending PUBLISH (d0, q0, r0, m1, 'test', ... (7 bytes))
Client mosqpub/30264-pcortex sending DISCONNECT

If we check the log, we have the following:

1478539830: New client connected from 127.0.0.1 as mosqpub/27159-pcortex (c1, k60, u'user1').
1478539830: Client mosqpub/27159-pcortex disconnected.
1478601507: New connection from 127.0.0.1 on port 8883.

We can see that the broker extracted the username from the certificate property CN. If we don’t use the use_identity_as_username as true we need to provide the username and password and the client certificate. In this case, the certificate is validated, and the user used to logon might not be the same as the one defined on the CN certificate property. So without this directive we either need to allow anonymous logon again or define user and passwords.

Additional thoughts:
With user and password authentication we can revoke access to an user, by deleting it from the password file or changing the password.
But what about the authentication based on client certificates? As long the certificate is valid, the user can logon at will, since the broker will always accept it until the end of the certificate validation date.
The solution for this is to revocate the client certificate so when it is used, the broker rejects it. For this functionality, most Certificate Authorities provide the revocation list by providing either by CRL (Certificate Revocation list) file, or by OSCP (Online Status Certificate Protocol), and the server checks the client certificate on this list before allowing access. Mosquitto broker only works with CRL files.

We need to modify the listener configuration to verify the client certificates if it was revocated or not:

# MQTT over TLS/SSL
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/hostname.crt
keyfile /etc/mosquitto/certs/hostname.key
require_certificate true
use_identity_as_username true
crlfile /etc/mosquitto/certs/ca.crl

The issue now is that the script that we are using for generating certificates doesn’t generate CRLs, and so we can’t revocate certificates by using this script.

We can do it by hand, but that wouldn’t make our life much easier, since revocating certificates means that the CA server must now track all certificates and their status.
One possible solution is to use scripts that allow to create (a not very secure) CA: easy-ca. These scripts will replace the genCA.sh script and allow the revocation of certificates.

Getting the easy-CA scripts:

git clone https://github.com/fcgdam/easy-ca.git

I’m omitting a lot of output that these scripts do, namely asking for the Organization name, CA passwords and so on.

Somewhere where we find suitable we create our CA:

Generating the CA:

# cd ~ 
# ~/easy-ca/create-root-ca -d CA
# cd CA

Then at the CA directory we created, we can now create our broker certificate and user certificate. Make sure that the names make sense.

Generating the broker certificate:

# bin/create-ssl -s brokername
# bin/create-client -c user1

At the end we have the following files:

ca/ca.crt

We now have all the needed files for setting up our broker with support for CRL.

# sudo -s
# cp ~/CA/ca/ca.crt /etc/mosquitto/certs
# cp ~/CA/crl/ca.crl /etc/mosquitto/certs
# cp ~/CA/certs/brokername.server.crt /etc/mosquitto/certs/brokername.crt
# cp ~/CA/private/brokername.server.key /etc/mosquitto/certs/brokername.key

And restarting the broker we have the new certificates in place.
We can test now by using our CA user certificate:

# cd ~/CA
# mosquitto_pub --cafile /etc/mosquitto/certs/ca.crt -h localhost -t "test" -m "message" -p 8883 -d  --cert certs/user1.client.crt --key private/user1.client.key 
Client mosqpub/7424-pcortex sending CONNECT
Client mosqpub/7424-pcortex received CONNACK
Client mosqpub/7424-pcortex sending PUBLISH (d0, q0, r0, m1, 'test', ... (7 bytes))
Client mosqpub/7424-pcortex sending DISCONNECT

It works. Now let’s revoke the user certificate:

# bin/revoke-cert -c certs/user1.client.crt 

Revoking certificate 'certs/user1.client.crt'

Reason for revocation: 

1. unspecified
2. keyCompromise
3. CACompromise
4. affiliationChanged
5. superseded
6. cessationOfOperation
7. certificateHold

Enter 1-7 [1]: 2
You are about to revoke this certificate with reason 'keyCompromise'.
Are you SURE you wish to continue? [y/N]: y
Using configuration from conf/ca.conf
Revoking Certificate 02.
Data Base Updated
Using configuration from conf/ca.conf

Server certificate revoked.

We need to copy the new CRL to the directory where mosquitto expects the CRL:

# sudo cp crl/ca.crl /etc/mosquitto/certs

And after restarting the broker we have:

mosquitto_pub --cafile /etc/mosquitto/certs/ca.crt -h localhost -t "test" -m "message" -p 8883 -d  --cert certs/user1.client.crt --key private/user1.client.key  
Client mosqpub/7640-pcortex sending CONNECT
Error: A TLS error occurred.

And on the logs:

1478625909: OpenSSL Error: error:14089086:SSL routines:ssl3_get_client_certificate:certificate verify failed
1478625909: Socket error on client , disconnecting.
1478625910: New connection from 127.0.0.1 on port 8883.
Advertisements

14 thoughts on “MQTT Mosquitto broker – Client Authentication and Client Certificates

  1. Pingback: MQTT Mosquitto broker with SSL/TLS transport security | Primal Cortex's Weblog

  2. This article and your transport security article are by far the most clear and concise resources I’ve found on this topic. From a complete coding novice, thanks a lot for taking the time to make them.

    • Well, I had the same problem regarding MQTT security and at the end, since that I also found nothing on the web, I’ve had to write this 🙂

      • Question. When I’m implementing certificates on the client side, I ran the generate-CA.sh again as you suggested and ended up with my 3 additional files. I then moved these files to my /etc/mosquitto/certs directory. Lastly I wanted to add them to my local mosquitto.conf file but realized I didn’t know the proper syntax to add multiple certificates. I’ve tried the following, simply putting a space between the paths… obviously this didn’t work:

        #MQTT over TLS/SSL

        listener 8883
        cafile /etc/mosquitto/certs/ca.crt
        certfile /etc/mosquitto/certs/RP3-CSB.crt /etc/mosquitto/certs/user1.crt
        keyfile /etc/mosquitto/certs/RP3-CSB.key user1.key /etc/mosquitto/certs/user1.key
        require_certificate true
        use_identity_as_username true
        tls_version tlsv1.2

        #End of MQTT over TLS/SSL

        allow_anonymous false
        password_file /etc/mosquitto/conf.d/passwd

        log_type error
        log_type warning
        log_type notice
        log_type information

        connection_messages true
        log_timestamp true

        Any suggestions?

        Thanks
        -Chase

  3. So I actually did get this to work with the following config. As you’ll notice, I had to create a whole separate listener and that listener must be on a separate port.

    Am I going about this the wrong way? Is there a better way to do this?

    #MQTT over TLS/SSL

    listener 8883
    cafile /etc/mosquitto/certs/ca.crt
    certfile /etc/mosquitto/certs/RP3-CSB.crt
    keyfile /etc/mosquitto/certs/RP3-CSB.key
    require_certificate true
    use_identity_as_username true
    tls_version tlsv1.2

    #End of MQTT over TLS/SSL

    listener 8884
    cafile /etc/mosquitto/certs/ca.crt
    certfile /etc/mosquitto/certs/user1.crt
    keyfile /etc/mosquitto/certs/user1.key
    require_certificate true
    use_identity_as_username true
    tls_version tlsv1.2

    #End of MQTT over TLS/SSL

    allow_anonymous false
    password_file /etc/mosquitto/conf.d/passwd

    log_type error
    log_type warning
    log_type notice
    log_type information

    connection_messages true
    log_timestamp true

  4. Hi: I think there is some confusion regarding your configuration. From what you have sent, you are using the user certificate on the mosquitto configuration. This is not necessary and it is not right. The only configuration needed is the first one where the server certificate is used. User certificates are only used on the client side.

    Now both the server and the users certificate must belong to the same CA, so when the client which uses the user certificate with the public key to communicate to the broker, the broker can check the signature validity.

    The user private key is always kept with the user otherwise it won’t be private…

    By other words: The broker only needs to have configured the server certificate and private key.

    The user to connect must provide the user certificate that holds the public key and also the user private key.

    Both private keys never should be used for anything else.

    The user certificates and keys are used as the following example:

    mosquitto_pub –cafile /etc/mosquitto/certs/ca.crt -h localhost -t “test” -m “message” -p 8883 -d –cert certs/user1.client.crt –key private/user1.client.key

    I hope I was able to help.

    • That is very helpful. I absolutely did not understand correctly.

      So, in the above example, I’m simply running MQTT in different command windows for testing. Are you saying, in a more realistic example, the ca.crt is the only file that needs to be included in the /etc/mosquitto/certs directory? That the user1.crt and user1.key would be on the separate device that is trying to communicate with the broker?

      If yes, and I have multiple clients using multiple different private client certs and keys, what belongs in the certfile and keyfile positions in the mosquitto configuration file?

      If no, I obviously still don’t understand.

      Basically your explanation lead me to believe that ca.crt is required on the broker side and user1.crt and user1.key (the public and private key) are required only on the client side? Is this correct?

      Thanks again for your assistance in this, I’d be lost without it.

      -Chase

      • Hi, yes you are correct, on the broker side the only thing needed is the CA cert and the broker cert and private key, nothing else. The broker does not need to track users or clients. That’s the CA job.

        So each client then has its own user/client cert and user/client private key.

        Since all certificates the broker and the client are created using the same CA, this means that the broker only needs to check on connection if the user certificate is valid against the CA and it does this with its own CA cert.

        The process is a bit more complicated, but basically its just that.

        So no need to add users on the broker. Just create user/client certificates from the same broker CA and it will just work fine on any client. Off course the user creating the certs must be authorized and the CA must be protected.

  5. Hi,

    Is it also possible to use client authentication with a certificate for web socket connections?

    Kind regards,
    Patrick

    • Not sure, since I didn’t try it out. The web sockets certificate FQDN must match the URL used for web sockets connection that is for sure otherwise the browser would complain.
      Since client auth based on certs are supported by the browser it really depends if mosquitto does support it… I’ll have to check it.

  6. Really nice and clear explanation, Thank you!
    I am a newbie and learning mosquitto and SSL/TLS. I have a situation where I have to create clients dynamically. After reading your article, I am comfortable using client side SSL certificates. I am thinking of doing some rest calls that my clients will do, and get dynamically generated certificates for themselves(using openssl), as the rest service is already secured. My question to you is, am I thinking the right way and should I also make use_identity_as_username to false and create user and password for each client so that on connecting to my mosquitto server, each client must provide a certificate, user and password.
    Thank you.

    • Using certificates AND user and password means that you have two things to manage, the certificates and the passwords. using only the certificates for authentication and security merges the two functions. It really depends on your use case what is better.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s