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 per 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
democonfigROOT_CA_PEM
,
democonfigMQTT_BROKER_ENDPOINT
and democonfigMQTT_BROKER_PORT
:
#define democonfigMQTT_BROKER_ENDPOINT "w.x.y.z"
#define democonfigMQTT_BROKER_PORT ( 8883 )
#define democonfigROOT_CA_PEM "......." /* Root Certificate */
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.