After releasing the new version of my M2Mqtt library with support for SSL / TLS with server-side authentication, the time has come to show you an example of use.

Choose and install the broker: Mosquitto

First we have to choose an MQTT broker among those available but unfortunately no one is developed using the .Net Framework . Discarding more complex solutions , especially with regard to the installation and configuration , such as IBM Websphere , we can take into account to brokers like RabbitMQ , HiveMQ or Mosquitto. In this case , my choice was Mosquitto that we can download from the official web site for various operating systems based on Linux , as well as there is a convenient installer for the Windows environment . In fact, for Windows there are two installation modes: the first uses an installer in which the broker is compiled natively while in the second case is based on the Cygwin provides a Linux-like environment for Windows. It 'obvious that the first mode is the most simple and immediate . After installation, in addition to being installed the broker itself ( mosquitto.exe ) , will be provided to two console applications that represent a publisher ( mosquitto_pub.exe ) and a subscriber ( mosquitto_sub ), very useful to test the operation of the broker . The use of Mosquitto is very well documented on the official website but what we want to know is above the SSL/ TLS related configuration. To change the default settings of the broker, the latter can be launched by specifying a configuration file ( a sample file mosquitto.conf is present in the installation folder ) . Before addressing this issue , you must generate the certificates of the CA (Certification Authority) and server / broker we're going to use in this example.

Certificates generation : CA and brokers

In this post, I don’t want to address the complex subject relating to the SSL / TLS protocol but I want to at least point out the main aspects related most closely to the example we're going to accomplish. The server that hosts the broker requires an X.509 certificate that must be properly signed by a CA (Certification Authority) . In our case, to avoid " buying " a certificate and have it signed by a real CA, we will generate a " self-signed " certificate  root for the CA through which the server then we will sign . Generating and signing certificates can be done in two ways: through the OpenSSL package , whose Windows installer can be downloaded here , or through the tool Makecert find that part of the installation of our "dear" Visual Studio. Using OpenSSL at work , I preferred to focus on the latter , because it is much more complete. The installer download is related to the version 1.0.1e (Win32 or Win64 depends on your operating system ) that needs the Visual C + + 2008 Redistributables package . At the end of the installation ( typically in C: \ OpenSSL - WinXX with XX = 32 or 64) , it may happen ( as has occurred to me) that if you run the command openssl from the command prompt (inside the bin folder installation) , you will be presented with the following warning :

WARNING : can’t open config file: /usr/local/ssl/openssl.cfg

Unable to load config info from /usr/local/ssl/openssl.cfg

The immediate solution plans to add an environment variable in which you define the path where the configuration file is:

set OPENSS_CONF=C:\OpenSSL-Win64\bin\openssl.cfg

I know, you're right, it is not normal that an installation does not end in the best way ... and I totally agree! But overcome this hurdle, OpenSSL is definitely the best! All the following operations are to be carried from the command prompt in the folder C: \ OpenSSL-Win64 \ bin \ PEM, in which OpenSSL runs his store of certificates.

First, we generate the CA certificate with the following command:

openssl req -new -x509 -days 3650 -keyout m2mqtt_ca.key -out m2mqtt_ca.crt

through which we will obtain a private key for the CA (certificate m2mqtt_ca.key and the "self-signed" m2mqtt_ca.crt). You will be prompted for a "pass phrase" to also encrypt the private key in succession all the information about the certificate (Country Name, State, ...) among which I preferred to set as CN (Common Name) the name of my PC (this setting is strictly required at the time of generation of the server certificate).

cert_ca_thumb[1]

At this point we can move on to the generation of a private key for the server and related certificate request must be signed by the CA. Regarding the generation of the private key, we can perform:

openssl genrsa -des3 -out m2mqtt_srv.key 1024

through which we get the private key of the server m2mqtt_srv.key encrypted using a "pass phrase".

02_key_srv_thumb[1]

Once this is done, let's move to the generation of the certificate request from the server to be signed by the CA.

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

In this way we generate the request m2mqtt_srv.csr (be careful! Has not yet signed certificate) in which there are all the server information (requests from the execution of the command) including the CN must be set to the name of same server that will provide the certificate at the time of the requests from the client. In my case, since the broker will run on my PC, the Common Name is the same as the name of my PC "ppatierno-PC".

03_csr_srv_thumb[1]

The last step is to sign the server request through the CA and obtain the final certificate of the broker.

openssl x509 -req -in m2mqtt_srv.csr -CA m2mqtt_ca.crt -CAkey m2mqtt_ca.key -CAcreateserial -out m2mqtt_srv.crt -days 3650

Thus we have completed all the steps required to generate the certificates.

04_cert_srv_thumb[2]

In fact, I prefer to bring forward a step. The newly generated certificates are in PEM format but the. Net Framework, through the SslStream (used in M2Mqtt library), uses certificates in DER format. The certificate that is obviously what we have to convert is the CA must be installed on the client, which instead will receive one of the server to be verified during the SSL handshake. The conversion can be performed always through OpenSSL in the following way:

openssl x509 -outform der -in m2mqtt_ca.crt -out m2mqtt_ca.der

We finally have everything we need in order to configure the broker!

Configuring and starting the broker

For the broker configuration, I recommend making a copy of the sample file mosquitto.conf we're going to change. In my case, I created the file mosquitto_m2mqtt.conf in which the parameters to be changed are as follows in the section "Default Listener" and "Certificate based SSL / TLS support":

  • bind_address : server name (in my case bind_address ppatierno-PC);
  • port : MQTT port for SSL/TLS is 8883 (port 8883);
  • cafile : path for CA certificate (cafile C:\OpenSSL-Win64\bin\PEM\m2mqtt_ca.crt);
  • certfile : path for server certificate (certfile C:\OpenSSL-Win64\bin\PEM\m2mqtt_srv.crt);
  • keyfile : path server private key (keyfile C:\OpenSSL-Win64\bin\PEM\m2mqtt_srv.key);
  • tls_version : TLS version (tls_version tlsv1);

After finishing the settings, the broker Mosquitto can be launched from the command prompt (run as administrator) as follows :

mosquitto –c mosquitto_m2mqtt.conf –v

Through the parameter-c specify the configuration file to use while mode-v "verbose" to see the debug messages. Will be asked to "pass phrase" the server's private key required during the SSL / TLS handshake in the use RSA asymmetric encryption algorithm.

05_broker_start_thumb[1]

In my case, it was done bind to IPv6 on my PC at which the broker listens on port 8883. Thus we have the broker running ready to receive and distribute messages between the various MQTT client.

Starting a subscriber and testing of the broker

As in the example, the client will use the M2Mqtt library will be the publisher of the messages, we use the tool mosquitto_sub for the part of subscribers so you can also test immediately if the broker is working properly. Also from a command prompt (run as administrator) in the installation folder Mosquitto, launch the client as follows:

mosquitto_sub -h ppatierno-PC -p 8883 -q 1 -t sensor/temp --cafile C:\OpenSSL-Win64\bin\PEM\m2mqtt_ca.crt --tls-version tlsv1 –d

We specify the hostname and port to connect to, the file path of the CA certificate to verify the server certificate received during the SSL / TLS handshake, the version of TLS, which subscribe to the topic with the corresponding level of QoS and finally the flag that activates debugging to display the exchange of messages with the broker.

06_sub_connect_thumb[1]

The exchange of messages for the connection (CONNECT, CONNACK) and the ping to keep alive the connection between client and broker (PINREQ, PINGRESP) is also visible in the console where the broker is running.

07_sub_broker_connect_thumb[1]

Installing the CA certificate

The classes of the. Net Framework that allow you to manage SSL / TLS connections, such as the SslStream, make use of SSPI (Security Support Provider Interface) system to manage certificates. This means that, before using the CA certificate within our client application, you must install it in our operating system. One of the easiest ways to use the wizard to import the certificates is through the "Internet Options" to import the certificate in the "Trusted Root Certification Authorities" (excuse me for italian screenshot).

08_import_der_thumb[2]

Let us remember that you need to import the certificate in DER format.

In the case in which the client is developed with the. Net Micro Framework, if it was run in the emulator, such operation would still be required, since the emulator uses the same interface to the operating system. Of course, only in the case that the application is executed on a real board, the CA certificate should be simply copied to a support (eg Flash, SD card, ...) and then be read at runtime by the application itself. In our case, we'll run the application on a PC with the. Net Framework (the result would be the same by running the same application with. NET Micro Framework emulator).

Develop the client and ... publish encrypted messages!

The client application that uses the M2Mqtt library , does nothing more than connect to the broker and pretended to publish a given temperature on the topic "sensor / temp" (to which we have signed another client in the previous paragraph). The CA certificate was included in a resource file (Resources.resx) and, once read as a byte stream is provided to the X509Certificate constructor class, in order to obtain a valid X.509 certificate for the MqttClient.

   1: class Program
   2: {
   3:     static void Main(string args)
   4:     {
   5:         MqttClient client = new MqttClient("ppatierno-PC",
   6:             MqttClient.MQTT_BROKER_DEFAULT_SSL_PORT,
   7:             true,
   8:             new X509Certificate(Resources.m2mqtt_ca));
   9:  
  10:         
  11:         client.Connect(Guid.NewGuid().ToString());
  12:  
  13:         for (int i = 0; i < 1000; i++)
  14:             client.Publish("sensor/temp", Encoding.UTF8.GetBytes("27"), MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE);
  15:  
  16:         Thread.Sleep(Timeout.Infinite);
  17:     }
  18: }

In the console window of the broker can be seen the publication and exchange of messages related to the MQTT QoS 1 (Exactly Once).

09_pub_broker_thumb[1]

In the console window of the subscriber is possible to observe the message received from the publisher.

10_pub_sub_thumb[1]

Conclusions

The MQTT protocol does not provide intrinsic security features, for which it is necessary to rely on what provides the transport layer on which the MQTT  messages traveling , namely the TCP / IP . In this case , one of the most widely used protocols is SSL / TLS also provides server authentication as well as data encryption. It 'obvious that such a layer , reduces the performance of the entire system and the speed with which messages are exchanged. Another possibility would be to apply the encryption directly on the data contained in the MQTT message but this involves the use of a symmetric encryption algorithm and for which the clients have all knowledge of the key. This way, however , would eliminate the authentication of the server that should be carried out at the application level in other way. In many cases, however , the adoption of one technique over another , it depends very much on the potential of our system in the case of embedded systems may not support SSL / TLS as a matter of cost of processing and memory footprint for encryption libraries .