Exosite Secure MQTT demo with Cypress WICED Studio (6.2.1)

Download and install WICED studio from Cypress

https://community.cypress.com/community/wiced-wifi/wiced-wifi-documentation

For this walkthrough i've used WICED Studio 6.2.1 for Linux (https://community.cypress.com/docs/DOC-15209)

Once installed, remember to restart the system in order for drivers and udev security rules to be loaded.

By default the WICED studio is installed to $HOME/WICED-Studio-6.2 and SDK + Source code at $HOME/Documents/WICED-Studio-6.2/43xxx_Wi-Fi.

Table of Contents


Creating a new Murano MQTT product

First we'll Create a new Murano Product.

Add Product

Choose Product Solution and "Start from Scratch".

Create New Product Solution

Next we'll go to settings in our new product and change protocol to MQTT with the default port 8883. We'll also keep the default token authentication method.

Update Product Settings

After this we'll go to the "Resource" page and add a new string resource called wiced_resource.

Add wiced_resource

We'll add a new device to our product.

Add One Device

Device Configuration

After we've created the new device we can manually set the credentials. Save the generated token as we'll later need to use it for the #define PASSWORD field in our example code.

Set Credentials

Save Token

We'll also need to know the solution id for our product in order to know our mqtt broker domain. The domain has the following pattern: <solution_id>.m2.exosite.io, ex: i24zq5fqdcylc0000.m2.exosite.io.

Get Solution ID


Creating a new WICED application

Launch WICED Studio by executing the provided eclipse binary $HOME/WICED-Studio-6.2/eclipse. Once launched you'll be asked wich project to use, then select 43xxx_Wi-Fi.

Main Window

WICED Studio organizes board applications under the apps/ directory. apps/demo/ more complete demo applications and apps/snip/ contains smaller example code snippets. More details on the folder strucutre is provided in the included README.txt provided in the 43xxx_Wi-Fi SDK directory.

Apps directory

We will use the provided apps/snip/secure_mqtt example and modify it for connecting to murano.

Secure MQTT snip

Copy apps/snip/secure_mqtt to a new project at apps/demo/secure_mqtt_exosite. Rename secure_mqtt.c -> secure_mqtt_exosite.c and secure_mqtt.mk -> secure_mqtt_exosite.mk.

Setup WIFI

In order to get WIFI working on our device we'll also add a wifi configuration that's missing from the secure_mqtt snip. Copy include/default_wifi_config_dct.h to apps/demo/secure_mqtt_exosite/wifi_config_dct.h.

Default Wifi config

Modify wifi_config_dct.h to add your wifi configuration:

-#define CLIENT_AP_SSID       "YOUR_AP_SSID"
-#define CLIENT_AP_PASSPHRASE "YOUR_AP_PASSPHRASE"
+#define CLIENT_AP_SSID       "YOUR_REAL_AP_SSID"
+#define CLIENT_AP_PASSPHRASE "YOUR_REAL_AP_PASSPHRASE"

Final setup

Add Murano TLS Certificate

The secure_mqtt example uses TLS to connect to the MQTT broker. In order to connect to Murano we need to replace the provided root certificate with the one used by Murano. The root certificate need to be stored as a resource under the resources/apps/<project> directory.

Download the Murano Service Certificate and save it under resources/apps/secure_mqtt_exosite/murano_root.cer.

Note: You can choose between the public certificate issued by Digicert or the long-lived Exosite certificate which has a much longer expiration time.

Root cert

We can now update our demo application make file (apps/demo/secure_mqtt_exosite/secure_mqtt_exosite.mk) with the following changes:

-NAME := App_Secure_MQTT
+NAME := App_Secure_MQTT_Exosite

-$(NAME)_SOURCES := secure_mqtt.c \
+$(NAME)_SOURCES := secure_mqtt_exosite.c \

 $(NAME)_COMPONENTS := protocols/MQTT

-$(NAME)_RESOURCES  := apps/secure_mqtt/secure_mqtt_root_cacert.cer
+WIFI_CONFIG_DCT_H := wifi_config_dct.h
+
+$(NAME)_RESOURCES  := apps/secure_mqtt_exosite/murano_root.cer

Enable SNI

In order to successfully and reliably connect Murano with the provided MQTT library (libraries/protocosl/MQTT/) we will need to make two adjustments. First we need to add support for the SNI TLS extension which is required to connect to murano. We also need to fix a bug in how the MQTT library handles multiple MQTT messages in a single TCP frame.

/libraries/protocols/MQTT/mqtt_common.h

@@ -132,12 +132,13 @@ typedef struct wiced_mqtt_pkt_connect_s

 typedef struct wiced_mqtt_security_s
 {
-     char*      ca_cert;                                        /* CA certificate, common between client and MQTT Broker */
-     uint32_t   ca_cert_len;                                    /* CA certificate length */
-     char*      cert;                                           /* Client certificate in PEM format */
-     uint32_t   cert_len;                                       /* Client certificate length */
-     char*      key;                                            /* Client private key */
-     uint32_t   key_len;                                        /* Client private key length */
+     char*                  ca_cert;                                        /* CA certificate, common between client and MQTT Broker */
+     uint32_t               ca_cert_len;                                    /* CA certificate length */
+     char*                  cert;                                           /* Client certificate in PEM format */
+     uint32_t               cert_len;                                       /* Client certificate length */
+     char*                  key;                                            /* Client private key */
+     uint32_t               key_len;                                        /* Client private key length */
+     wiced_tls_extension_t* tls_extension;                                  /* Optional TLS extension for connecting to the MQTT Broker */
 } wiced_mqtt_security_t;

/libraries/protocols/MQTT/mqtt_network.c

@@ -148,6 +148,11 @@ wiced_result_t mqtt_network_init( const wiced_ip_address_t *server_ip_address, u
             wiced_tls_init_context( &socket->tls_context, NULL,  (const char*) conn->peer_cn );
         }

+        if ( security->tls_extension )
+        {
+            wiced_tls_set_extension(&socket->tls_context, security->tls_extension);
+        }
+
         wiced_tcp_enable_tls( &socket->socket, &socket->tls_context );
     }

@@ -298,11 +303,10 @@ static wiced_result_t mqtt_consume_tcp_packet( mqtt_connection_t* conn, mqtt_fra
         /* Decrease the 'remaining' counter of the packet */
         pkt->remaining_bytes = pkt->remaining_bytes - bytes_to_consume;

-        /* If Packet is not exhausted yet and we've consumed the fragment of the packet completely;
-           Move the data-pointer counter to next-fragment of the packet */
-        if( bytes_to_consume == pkt->frag_length && pkt->remaining_bytes > 0 )
+        /* If Packet is not exhausted, fetch more messages from the same packet */
+        if( pkt->remaining_bytes > 0 )
         {
-            wiced_packet_get_data(pkt->packet, (uint16_t)bytes_to_consume, &pkt->data_start, (uint16_t*)&pkt->frag_length, &available_packet );
+            wiced_packet_get_data(pkt->packet, (uint16_t)pkt->consumed_bytes, &pkt->data_start, (uint16_t*)&pkt->frag_length, &available_packet );
         }
         return ret;
     }

Configure for Murano

With these fixes in place now work on updating apps/demo/secure_mqtt_exosite/secure_mqtt_exosite.c.

First we'll change some of the constants to match our Murano product, replace i24zq5fqdcylc0000 with your product ID.

@@ -118,13 +118,17 @@
  *                    Constants
  ******************************************************/
 /* Change the Broker domain address to match the server address */
-#define MQTT_BROKER_ADDRESS                 "test.mosquitto.org"
+#define MQTT_BROKER_ADDRESS                 "i24zq5fqdcylc0000.m2.exosite.io"
 /* Name of topic name */
-#define WICED_TOPIC                         "MQTT/WICED/TOPIC"
+#define WICED_TOPIC                         "$resource/wiced_resource"
 /* MQTT message content */
 #define WICED_MESSAGE_STR                   "HELLO WICED"
 /* MQTT client ID */
-#define CLIENT_ID                           "wiced"
+#define CLIENT_ID                           "" // Leave empty for connecting to Murano
+
+#define USER_NAME                           "" // Token authentication: leave empty, Password authentication: set device id
+
+#define PASSWORD                            "" // Token authentication: set token, Password authentication: set password

 #define WICED_MQTT_TIMEOUT                  (5000)

Next we'll add the TLS extension object and change the resource path to our root certificate.

@@ -175,10 +179,11 @@ void application_start( void )
     static wiced_mqtt_object_t mqtt_object;
     wiced_result_t ret = WICED_SUCCESS;
     uint32_t size_out;
+    wiced_tls_extension_t extension;

     wiced_init( );
     /* Read root CA certificate (self certified) from resources*/
-    resource_get_readonly_buffer( &resources_apps_DIR_secure_mqtt_DIR_secure_mqtt_root_cacert_cer, 0, MQTT_MAX_RESOURCE_SIZE, &size_out, (const void **) &security.ca_cert );
+    resource_get_readonly_buffer( &resources_apps_DIR_secure_mqtt_exosite_DIR_digicert_global_root_cer, 0, MQTT_MAX_RESOURCE_SIZE, &size_out, (const void **) &security.ca_cert );
     security.ca_cert_len = size_out;

     /* Memory allocated for mqtt object*/
@@ -203,6 +208,13 @@ void application_start( void )
         return;
     }

+
+
+    // Enable SNI support to connect to Murano
+    extension.type = TLS_EXTENSION_TYPE_SERVER_NAME;
+    extension.extension_data.server_name = (uint8_t *)MQTT_BROKER_ADDRESS;
+    security.tls_extension = &extension;
+
     wiced_mqtt_init( mqtt_object );

In Murano MQTT subscriptions are managed centrally from the cloud. There is no need for a device to subscribe/unsibscribe from topics so we should remove them from our application code. We also need to update the resource_free_readonly_buffer call to point to our new resource.

     wiced_rtos_init_semaphore( &semaphore );
     while ( ret == WICED_SUCCESS )
@@ -211,18 +223,12 @@ void application_start( void )
         WPRINT_APP_INFO(("[MQTT] Opening connection..."));
         RUN_COMMAND_PRINT_STATUS_AND_BREAK_ON_ERROR( mqtt_conn_open( mqtt_object,&broker_address, WICED_STA_INTERFACE, callbacks, &security ), NULL, "Did you configure you broker IP address?\n" );

-        WPRINT_APP_INFO(("[MQTT] Subscribing..."));
-        RUN_COMMAND_PRINT_STATUS_AND_BREAK_ON_ERROR( mqtt_app_subscribe( mqtt_object, WICED_TOPIC , WICED_MQTT_QOS_DELIVER_EXACTLY_ONCE ), NULL, NULL );
-
         WPRINT_APP_INFO(("[MQTT] Publishing..."));
-        RUN_COMMAND_PRINT_STATUS_AND_BREAK_ON_ERROR( mqtt_app_publish( mqtt_object, WICED_MQTT_QOS_DELIVER_EXACTLY_ONCE, WICED_TOPIC, (uint8_t*)WICED_MESSAGE_STR ,sizeof(WICED_MESSAGE_STR) ), NULL, NULL );
+        RUN_COMMAND_PRINT_STATUS_AND_BREAK_ON_ERROR( mqtt_app_publish( mqtt_object, WICED_MQTT_QOS_DELIVER_AT_LEAST_ONCE, WICED_TOPIC, (uint8_t*)WICED_MESSAGE_STR ,sizeof(WICED_MESSAGE_STR) ), NULL, NULL );

         WPRINT_APP_INFO(("[MQTT] Waiting some time for ping exchange...\n\n"));
         wiced_rtos_delay_milliseconds( WICED_MQTT_DELAY_IN_MILLISECONDS * 10 );

-        WPRINT_APP_INFO(("[MQTT] Unsubscribing..."));
-        RUN_COMMAND_PRINT_STATUS_AND_BREAK_ON_ERROR( mqtt_app_unsubscribe( mqtt_object, WICED_TOPIC ), NULL, NULL );
-
         WPRINT_APP_INFO(("[MQTT] Closing connection..."));
         RUN_COMMAND_PRINT_STATUS_AND_BREAK_ON_ERROR( mqtt_conn_close( mqtt_object ), NULL, NULL );

@@ -236,7 +242,7 @@ void application_start( void )
     free( mqtt_object );
     mqtt_object = NULL;
     /* Free security resources, only needed at initialization */
-    resource_free_readonly_buffer( &resources_apps_DIR_secure_mqtt_DIR_secure_mqtt_root_cacert_cer, security.ca_cert );
+    resource_free_readonly_buffer( &resources_apps_DIR_secure_mqtt_exosite_DIR_digicert_global_root_cer, security.ca_cert );
 }

Finally we need to update the MQTT conninfo to reference our USER_NAME and PASSWORD constants.

@@ -353,8 +359,8 @@ static wiced_result_t mqtt_conn_open( wiced_mqtt_object_t mqtt_obj, wiced_ip_add
     conninfo.clean_session = 1;
     conninfo.client_id = (uint8_t*) CLIENT_ID;
     conninfo.keep_alive = 10;
-    conninfo.password = NULL;
-    conninfo.username = NULL;
+    conninfo.password = (uint8_t*) PASSWORD;
+    conninfo.username = (uint8_t*) USER_NAME;
     conninfo.peer_cn = NULL;

     ret = wiced_mqtt_connect( mqtt_obj, address, interface, callback, security, &conninfo );

Deploy to the board

Now we can compile and deploy our application to the board. From the 43xxx_Wi-Fi/ directory we can execute the following

./make demo.secure_mqtt_exosite-AP72438V01

The make target is the directory path under apps/ but with directory slashes replaced with .. apps/demo/secure_mqtt_exosite -> demo.secure_mqtt_exosite. -AP72438V01 refers our platform (board). All avaliable boards can be found under platforms/. If your board is not avaliable you might need to contact your board provider to see if they have an WICED SDK platform configuration avaliable.

./make demo.secure_mqtt_exosite-AP72438V01 download run 
MAKEFILE MAKECMDGOALS=demo.secure_mqtt_exosite-AP72438V01 download run OTA2_SUPPORT is disabled
Building Bootloader
Finished Building Bootloader

demo.secure_mqtt_exosite-AP72438V01
----------------------------------|---------|---------|
                                  |         |  Static |
              Module              |  Flash  |   RAM   |
----------------------------------+---------+---------|
App                               |    1066 |      85 |
crc                               |    1060 |       0 |
DHCP_Server                       |    1408 |     132 |
DNS                               |    1972 |      44 |
Host MCU-family library           |   15549 |    2692 |
Interrupt Vectors                 |     388 |       0 |
libc                              |   25865 |    3372 |
Linked_List                       |     434 |       0 |
mbedTLS                           |  113430 |      88 |
MQTT_Client                       |    7606 |     816 |
Networking                        |    4736 |   13912 |
NetX-Duo - Interfaces & Stacks    |       0 |      16 |
Other                             |   47207 |     677 |
Packet Buffers                    |       0 |   22470 |
platform                          |    1480 |     256 |
RAM Initialisation                |    2820 |       0 |
resources                         |  391721 |       0 |
Ring_Buffer                       |     112 |       0 |
SPI_Flash_Library_AP72438V01      |     510 |       0 |
Startup Stack & Link Script fill  |      65 |      12 |
Supplicant - BESL                 |    4244 |     812 |
ThreadX                           |    8748 |     400 |
WICED                             |    4305 |    1040 |
Wiced_RO_FS                       |     566 |       0 |
WWD                               |   16178 |    3196 |
----------------------------------+---------+---------|
TOTAL (bytes)                     |  648650 |   50020 |
----------------------------------|---------|---------|

Downloading Bootloader ...
No changes detected

Download complete

Downloading DCT ...
No changes detected

Download complete

Downloading Application ...
No changes detected

Download complete

Resetting target
Target running
Build complete
Making .gdbinit

You should now be able to connect to your boards serial port to see the log output (refer to the documentation for your board on how to do this for your device).

ls /dev/ttyUSB* (find uart console)

screen /dev/ttyUSB1 115200 (might need sudo if your user is not part of the dialout group)

Please refer to the WICED SDK documentation for more details on how to connect to your specific device.

Starting WICED vWiced_006.002.001.0002
Platform AP72438V01 initialised
Started ThreadX v5.8
Initialising NetX_Duo v5.10_sp3
Creating Packet pools
WLAN MAC Address : B0:F1:EC:55:8C:8A
WLAN Firmware    : wl0: Apr 30 2018 04:14:19 version 7.45.98.50 (r688715 CY) FWID 01-283fcdb9
WLAN CLM         : API: 12.2 Data: 9.10.39 Compiler: 1.29.4 ClmImport: 1.36.3 Creation: 2018-04-11 22:31:21
Joining : exosite_taipei_03
Successfully joined : exosite_taipei_03
Obtaining IPv4 address via DHCP
DHCP CLIENT hostname WICED IP
IPv4 network ready IP: 172.16.10.14
Setting IPv6 link-local address
IPv6 network ready IP: FE80:0000:0000:0000:B2F1:ECFF:FE55:8C8A
Resolving IP address of MQTT broker...
Resolved Broker IP: 52.9.165.84

[MQTT] Opening connection...OK.

[MQTT] Publishing...OK.

[MQTT] Waiting some time for ping exchange...

[MQTT] Closing connection...OK.

[MQTT] Opening connection...OK.

[MQTT] Publishing...OK.

[MQTT] Waiting some time for ping exchange...