coreMQTT Demo (with TLS Server Authentication)
coreMQTT is an MIT licensed open source MQTT client C library for microcontroller and small microprocessor based IoT devices.
Notice: We recommend using mutual authentication (both the IoT MQTT client and server
authenticate each other) when building any Internet of Things (IoT) application. The demo on this page is only meant for
educational purposes as it demonstrates encrypted communication without client authentication. It is not intended for
production use.
Single Threaded Vs Multi Threaded
There are two coreMQTT usage models, single threaded and multithreaded (multitasking). Using the MQTT
library solely from one thread within an otherwise multi-threaded application, as the demo documented on this page does, is
equivalent to the single threaded use case. Single threaded use cases require the application writer to make repeated explicit
calls into the MQTT library. Multithreaded use cases can instead execute the MQTT protocol in the background within
an agent (or daemon) task. Executing the MQTT protocol in an agent task removes the
need for the application writer to explicitly manage any MQTT state or call the MQTT_ProcessLoop()
API function.
Using an agent task also enables multiple application tasks to share a single MQTT connection without the need for synchronization
primitives such as mutexes.
Demo Introduction
This example project is one of three that introduce the concepts described on the "TLS
Introduction" page one at a time. The first example demonstrates unencrypted
MQTT communication. The second example (on this page) builds on the first to introduce server authentication (where the IoT
client authenticates the MQTT server it connects to). The third example
builds on the second to introduce strong mutual authentication (where the MQTT server also authenticates the client connecting to it).
This demo does not use mutual authentication so it is intended to be used as a learning exercise only.
This MQTT demo uses an mbedTLS-based network transport interface implementation to first
establish a server-authenticated TLS connection with the MQTT broker, and then it demonstrates the subscribe-publish workflow of
MQTT at the QoS 2 level. The demo has the broker echo messages back by subscribing to
a single topic filter and then publishing to that same topic. After each publish, it waits to receive the message back from the
server at the QoS 2 level. This cycle of publishing to the broker and receiving the
same message back from the broker is repeated indefinitely. Messages in this demo are sent at QoS 2 which guarantees exactly
once message delivery.
This basic MQTT demo project uses the FreeRTOS
Windows port, enabling it to be built and evaluated with the free Community version of Visual Studio on Windows, without the need for any particular MCU hardware.
Source Code Organization
The demo project is called mqtt_basic_tls_demo.sln and can be found in the FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS
directory of the main FreeRTOS download (and in Github, linked from the download page).
Configuring the Demo Project
The demo uses the FreeRTOS-Plus-TCP TCP/IP stack. Follow the
instructions provided for the TCP/IP starter project
to ensure you:
- Have the pre-requisite
components installed (such as WinPCap).
- Optionally, set a static
or dynamic IP address, gateway address and netmask.
- Optionally, set a MAC
address.
- Select an Ethernet
network interface on your host machine.
- …and most important, test
your network connection before attempting to run the MQTT demo.
All these setting should be performed in the MQTT demo project, not the TCP/IP starter project referenced from the same page!
As delivered the TCP/IP stack is configured to use a dynamic IP address.
Configuring the MQTT Broker Connection
Option 1: Using the publicly hosted Mosquitto MQTT broker (web hosted):
To communicate with Mosquitto’s publicly hosted MQTT broker, follow these steps:
- Open your local copy of
FreeRTOS/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/demo_config.h
- Set the following two constants as shown here:
#define democonfigMQTT_BROKER_ENDPOINT "test.mosquitto.org"
#define democonfigMQTT_BROKER_PORT (8883)
- Set the constant
#democonfigROOT_CA_PEM
(the server’s root CA certificate) to the PEM certificate linked
to from the main https://test.mosquitto.org page. The certificate needs to
be pasted as a string, so it will look like this:
#define democonfigROOT_CA_PEM \
"-----BEGIN CERTIFICATE-----\n"\
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"\
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"\
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n"\
"... etc. .......................................................\n"\
"-----END CERTIFICATE-----"
This setup should work if the demo connects to a network that has a DHCP service and Internet access. Note that
the FreeRTOS Windows port only works with a wired Ethernet network adapter, which can be a virtual Ethernet adapter.
You should use a separate MQTT client, such as MQTT.fx,
to test the MQTT connection from your host machine to the public MQTT broker.
Note: Mosquitto is an open source MQTT message broker that supports MQTT versions 5.0, 3.1.1, and 3.1. It is part of
the Eclipse foundation and is an Eclipse IoT project. The test.mosquitto.org
MQTT broker is not affiliated with or
maintained by FreeRTOS and may be unavailable at any time. Further the server authentication used by this broker is based on
1024-bit RSA, a cipher
that is not recommended for production purposes. Do NOT send any confidential information from your device
to this MQTT broker.
Option 2: Using a locally hosted Mosquitto MQTT message broker (host machine)
The Mosquitto broker can also run locally, either on your host machine (the machine used to build the demo application), or
another machine on your local network. To do this:
-
- Follow the instructions on https://mosquitto.org/download/ to download and install Mosquitto locally.
- Open “mosquitto.conf”, which is located in the Mosquitto install directory, and set the following configurations:
- per_listener_settings: true
- port: 8883
- allow_anonymous: false
- cafile: ./mosquitto/config/ca.crt
- certfile: ./mosquitto/config/server.crt
- keyfile: ./mosquitto/config/server.key
- tls_version: tlsv1.2
Note: The configurations “cafile”, “certfile”, and “keyfile” above refer to the locally-generated CA certificate, server certificate,
and server key, respectively. These can be generated using OpenSSL. More information can be found on
mosquitto.org.
- Open your local copy of
FreeRTOS/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/demo_config.h
- Add the following lines to set democonfigMQTT_BROKER_ENDPOINT and democonfigMQTT_BROKER_PORT:
#define democonfigMQTT_BROKER_ENDPOINT "w.x.y.z"
#define democonfigMQTT_BROKER_PORT ( 8883 )
Note: Port number 8883 is the default port number for encrypted MQTT. If you cannot use that port (for
example, if it is blocked by your IT security policy) then change the port used by Mosquitto to a high port number (for
example, something in the 50000 to 55000 range), and set mqttexampleMQTT_BROKER_PORT
accordingly. The port
number used by Mosquitto is set by the “port” parameter in “mosquitto.conf”, which is located in the Mosquitto install directory.
Option 3: An MQTT broker of your choosing:
Any MQTT broker that supports encrypted TCP/IP communication can be used with this demo. To do this:
- Open your local copy of
/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/demo_config.h
- Add the following lines with settings specific to your chosen broker:
- #define democonfigMQTT_BROKER_ENDPOINT "your-desired-endpoint"
- #define democonfigMQTT_BROKER_PORT ( 8883 )
- Optionally, set the server’s root CA certificate (
#democonfigROOT_CA_PEM
) in demo_config.h
Building the Demo Project
The demo project is built in the same way as the basic MQTT demo (without TLS).
- Open the
FreeRTOS/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/mqtt_basic_tls_demo.sln
Visual Studio solution file from within the Visual Studio IDE.
- Select Build Solution from the IDE’s Build menu.
NOTE: If you are using Microsoft Visual Studio 2017 or earlier, then you must
select a Platform Toolset compatible with your version: Project -> RTOSDemos Properties -> Platform Toolset
Troubleshooting
Note: If you set the constant #democonfigROOT_CA_PEM, make sure its format is correct.
X509 - Format not recognized.
- Make sure the begin and end of the certificate (#democonfigROOT_CA_PEM) is as below.
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
PEM - PEM string is not as expected: BASE64 - Invalid character in input.
- Make sure there’s no invalid character in the certificate string, especially when you copy paste the content.
Functionality
The demo provides the same functionality and structure as the basic
MQTT demo (without TLS), but uses a transport interface that includes TLS in place
of the plaintext transport interface.
Connecting to the MQTT Broker (with TLS)
The function prvConnectToServerWithBackoffRetries()
attempts to make a TLS connection to the MQTT broker. If
the connection fails, it retries after a timeout. The timeout value will exponentially increase and include jitter until the
maximum number of attempts are reached or the maximum timeout value is reached. The function RetryUtils_BackoffAndSleep()
provides an exponentially increasing timeout value and returns RetryUtilsRetriesExhausted
when the maximum number
of attempts has been reached. The variance in the time between retries is used to ensure a fleet of IoT devices that happen
to all get disconnected at the same time don't all try to reconnect at exactly the same time.
static TlsTransportStatus_t prvConnectToServerWithBackoffRetries(
NetworkCredentials_t * pxNetworkCredentials,
NetworkContext_t * pxNetworkContext )
{
TlsTransportStatus_t xNetworkStatus;
RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess;
RetryUtilsParams_t xReconnectParams;
pxNetworkCredentials->pRootCa = ( const unsigned char * ) democonfigROOT_CA_PEM;
pxNetworkCredentials->rootCaSize = sizeof( democonfigROOT_CA_PEM );
pxNetworkCredentials->disableSni = democonfigDISABLE_SNI;
RetryUtils_ParamsReset( &xReconnectParams );
xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS;
do
{
xNetworkStatus = TLS_FreeRTOS_Connect( pxNetworkContext,
democonfigMQTT_BROKER_ENDPOINT,
democonfigMQTT_BROKER_PORT,
pxNetworkCredentials,
mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS,
mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS );
if( xNetworkStatus != TLS_TRANSPORT_SUCCESS )
{
xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams );
}
if( xRetryUtilsStatus == RetryUtilsRetriesExhausted )
{
xNetworkStatus = TLS_TRANSPORT_CONNECT_FAILURE;
}
} while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) &&
( xRetryUtilsStatus == RetryUtilsSuccess ) );
return xNetworkStatus;
}
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.