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

IBM WebSphere interserver authentication: LTPA and SSL

On some applications J2EE applications deployed on WebSphere, you may have a two layer deployment: one server for the web layer and another server for the business logic layer. But for this to work you may need to enable global security and then to allow the communication between servers you need to setup LTPA between servers. On version 5.x and 6.0 just by moving the LTPA key from the business server to the application server and setting up the authentication method does the deal, and it has no need of intermediate steps to allow communication between servers.

On 6.1 version is not quite that simple, because RMI communication between servers runs now over SSL, and guess what: if an SSL session can’t be established, the communication is not possible.

The error message might be something like:  CAUGHT_EXCEPTION_WHILE_CONFIGURING_SSL_CLIENT_SOCKET: JSSL0080E: javax.net.ssl.SSLHandshakeException – The client and server could not negotiate the desired level of security. Reason: com.ibm.jsse2.util.h: No trusted certificate found vmcid: IBM minor code: E07 completed: No]

The key lead here is the “No trusted certificate found”, which means that an SSL session could not be established because of a missing server certificate.

The solution: On the IBM Websphere server that needs to communicate (in this case the server running the the web layer), execute the following steps:

1) Logon into the WAS console.

2) Goto Security -> SSL and Key Management

3) Select the NodeDefaultTrustStore and then Signer Certificates

4) Define your parameters, where the main information to be given is that the host must be the server you which to connect  to and the port is 9043.

5) Just give an alias name and press the button “Retrieve Signer Certificate”

6) Press apply and OK, and you’re done.

Try connecting again. It should work now.