2024-10-30 02:06 AM
I’ve successfully implemented data transmission between my STM32 NUCLEO F429ZI and an MQTT broker. Now, I want to enhance the security of this communication by configuring TLS. Initially, I would like to set up TLS without requiring CA certificates for testing purposes. After confirming that data transmission works correctly, I plan to update the configuration to include CA certificates later.
Could anyone provide guidance or examples on how to set up TLS in my STM32 MQTT code without CA certificates? Any help would be greatly appreciated!
#include "mqtt_app.h"
#include "mbedtls.h"
#include "mbedtls/ssl.h"
#include "mbedtls/x509.h"
#include "mbedtls/net.h"
#include "mbedtls/error.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
#define MQTT_SELECT_TIMEOUT 1
extern mbedtls_ssl_context ssl;
extern mbedtls_ssl_config conf;
extern mbedtls_x509_crt cert;
extern mbedtls_ctr_drbg_context ctr_drbg;
extern mbedtls_entropy_context entropy;
static char strSubscribeTopic[MQTT_MAXIMUM_TOPIC_LENGTH] = "/from/app/to/device";
static char strPublishTopic[MQTT_MAXIMUM_TOPIC_LENGTH] = "/from/device/to/app";
static char strAllertTopic[MQTT_MAXIMUM_TOPIC_LENGTH] = "/from/device/to/be";
static char strRxMessage[MQTT_MAXIMUM_MESSAGE_LENGTH] = {0};
static char strRxTopic[MQTT_MAXIMUM_TOPIC_LENGTH];
//static char strSubscribeTopic_Endpoint_Link[MQTT_MAXIMUM_TOPIC_LENGTH] = {0};
//static char strPublishTopic_Endpoint_Link[MQTT_MAXIMUM_TOPIC_LENGTH] = {0};
TaskHandle_t xMqttHandle = NULL;
TaskHandle_t xMqttRx = NULL;
#define BROKER_TEST
#ifdef BROKER_TEST
char* strUrlDefault = "mqtts://broker-dev.vconnex.vn:1884";
char* strUsernameDefault = "VKX-SmartHome";
char* strPassWordDefault = "Sm@rtH0me!2020";
char* strCmdTopicDefault = "CmTopicTest"; //CmTopicTest
char* strContentTopicDefault = "ContentTopicTest";
#endif
static char strBrokerUrl[100] = {0};
static char strBrokerUser[100] = {0};
static char strBrokerPass[100] = {0};
bool mqtt_bMqttStatus = false;
bool g_bMqttPause = false;
bool mqtt_bMqttRefresh = false;
uint64_t g_LastestMessageTimestamp = 0;
static xQueueHandle mqttRxQueue = NULL;
static void task_mqtt_rx();
char mqtt_cLwipHostName[15] = {'V','C','N'};
static MQTTClient client;
static Network network;
static bool bMqttQueueCreated = false;
bool bFirstConnect = true;
static char strAddress[MQTT_MAXIMUM_URL_LENGTH] = {0};
static MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
static int iPort = 1884;
static unsigned char iUseTls = 1;
static unsigned char sendbuf[MQTT_SENDBUF_LEN] = {0};
static unsigned char readbuf[MQTT_READBUF_LEN] = {0};
static bool bResub = false;
static bool app_mqtt_handle_url(const char *src, char *url, int *port, uint8_t *useTls)
{
int len = strlen(src);
int index = 0;
char header[6] = {0};
memcpy(header,src,5);
if (strncmp(src, "mqtts://", 8) == 0) {
*useTls = 1;
src += 8;
printf("Protocol: mqtts, Length: %d\n", len);
} else if (strncmp(src, "mqtt://", 7) == 0) {
*useTls = 0;
src += 7;
printf("Protocol: mqtt, Length: %d\n", len);
}
else{
printf("lenstr %d \n", len);
printf("NG pro: %s\n", src);
return false;
}
int indexTemp = 0;
char *output = url;
char porttemp[10] = {0};
while (index<len){
if (src[index] == ':'){
output[index] = 0;
output = porttemp;
indexTemp = 0;
index++;
continue;
}
output[indexTemp++] = src[index];
index++;
}
*port = atoi(porttemp);
return true;
}
static void app_mqtt_message_cmd(MessageData* data)
{
if(data->message->payloadlen > (MQTT_MAXIMUM_MESSAGE_LENGTH-1) || data->topicName->lenstring.len > (MQTT_MAXIMUM_TOPIC_LENGTH-1)){
return;
}
// char *msg = (char *)data->message->payload;
memcpy(strRxTopic,data->topicName->lenstring.data,data->topicName->lenstring.len);
memcpy(strRxMessage,data->message->payload,data->message->payloadlen);
uint16_t datalen = data->message->payloadlen;
printf("RxMessage %s Topic %s datalen %d \n",strRxMessage, strRxTopic, datalen);
memset(strRxMessage, 0, MQTT_MAXIMUM_MESSAGE_LENGTH);
}
static bool app_mqtt_publish(char *topic, char *data)
{
int rc = 0;
MQTTMessage message;
message.qos = QOS1;
message.retained = 0;
message.payload = data;
if(client.mqttstatus == MQTT_RUNNING)
{
message.payloadlen = strlen(data);
HAL_GPIO_WritePin(GPIOB, Green_LED_Pin, GPIO_PIN_SET);
if ((rc = MQTTPublish(&client, topic, &message)) != 0)
{
mqtt_printf(MQTT_INFO, "Return code from MQTT publish is %d\n", rc);
mqtt_bMqttStatus = false;
MQTTSetStatus(&client, MQTT_START);
client.ipstack->disconnect(client.ipstack);
return false;
}
else{
return true;
}
}
return false;
}
void app_mqtt_subscribe(char *topic, messageHandler messageHandler){
MQTTSubscribe(&client,strSubscribeTopic,QOS1,messageHandler);
int i;
int isSubscribed = 0;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (client.messageHandlers[i].topicFilter == topic)
{
isSubscribed = 1;
break;
}
}
if(!isSubscribed){
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (client.messageHandlers[i].topicFilter == 0)
{
client.messageHandlers[i].topicFilter = topic;
client.messageHandlers[i].fp = messageHandler;
break;
}
}
}
}
void app_mqtt_init_task(void){
#ifdef BROKER_TEST
memcpy(strBrokerUrl, strUrlDefault, strlen(strUrlDefault));
if (strUsernameDefault) memcpy(strBrokerUser, strUsernameDefault, strlen(strUsernameDefault));
if (strUsernameDefault) memcpy(strBrokerPass, strPassWordDefault, strlen(strPassWordDefault));
memset(strSubscribeTopic, 0, strlen(strSubscribeTopic));
memset(strPublishTopic, 0, strlen(strPublishTopic));
memset(strAllertTopic, 0, strlen(strAllertTopic));
memcpy(strSubscribeTopic, strCmdTopicDefault, strlen(strCmdTopicDefault));
memcpy(strPublishTopic, strContentTopicDefault, strlen(strContentTopicDefault));
#endif /*BROKER_TEST*/
char cliId[40] = {0};
int iMqtt_rc = 0;
app_mqtt_handle_url(strBrokerUrl, strAddress, &iPort, &iUseTls);
connectData.MQTTVersion = 3;
connectData.clientID.cstring = cliId;
connectData.clientID.lenstring.data = cliId;
connectData.clientID.lenstring.len = strlen(cliId);
connectData.username.cstring = strBrokerUser;
connectData.username.lenstring.data = strBrokerUser;
connectData.username.lenstring.len = strlen(strBrokerUser);
connectData.password.cstring = strBrokerPass;
connectData.password.lenstring.data = strBrokerPass;
connectData.password.lenstring.len = strlen(strBrokerPass);
LREP(__FUNCTION__, "Broker url: '%s' port: %d", strAddress, iPort);
LREP(__FUNCTION__, "Broker user name: '%s'", strBrokerUser);
LREP(__FUNCTION__, "Broker pass word: '%s'", strBrokerPass);
LREP(__FUNCTION__, "Broker sub topic: '%s'", strSubscribeTopic);
LREP(__FUNCTION__, "Broker pub topic: '%s'", strPublishTopic);
LREP(__FUNCTION__, "Broker alert topic: '%s'", strAllertTopic);
NetworkInit(&network);
network.use_ssl = iUseTls;
MQTTClientInit(&client, &network, 5000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));
// if (iUseTls) {
// int ret = app_mqtt_tls_setup(&network);
// if (ret != 0) {
// printf("TLS setup failed with error code -0x%x\n", -ret);
// return;
// }
// }
while (1) {
while (app_ethernet_dhcp_ready() == false) {
osDelay(100);
mqtt_printf(MQTT_INFO, "Wait Wi-Fi to be connected.");
}
fd_set read_fds;
fd_set except_fds;
struct timeval timeout;
FD_ZERO(&read_fds);
FD_ZERO(&except_fds);
timeout.tv_sec = MQTT_SELECT_TIMEOUT;
timeout.tv_usec = 0;
if (network.my_socket >= 0) {
FD_SET(network.my_socket, &read_fds);
FD_SET(network.my_socket, &except_fds);
FreeRTOS_Select(network.my_socket + 1, &read_fds, NULL, &except_fds, &timeout);
if (FD_ISSET(network.my_socket, &except_fds)) {
mqtt_printf(MQTT_INFO, "except_fds is set");
MQTTSetStatus(&client, MQTT_START);
}
}
iMqtt_rc = MQTTDataHandle_custom(&client, &read_fds, &connectData, app_mqtt_message_cmd, strAddress, iPort, strSubscribeTopic, &bResub);
if (bResub) {
bResub = false;
LREP_WARNING(__FUNCTION__, "MQTT is reconnect -> resub topic!");
}
////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//Pub
// if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
// {
// printf("status button on");
// app_mqtt_publish("ContentTopicTest", "hi button");
//
//
// if (app_mqtt_publish("ContentTopicTest", "hi button")) {
// printf("Send: hello\n");
//
// } else {
// printf("Failed to send message.\n");
// }
// osDelay(100);
// }
osDelay(10);
}
}
void task_mqtt_rx(){
for(;;){
osDelay(100);
}
}
void app_mqtt_init(void)
{
if(mqttRxQueue == NULL) {
if (bMqttQueueCreated) return;
bMqttQueueCreated = true;
mqttRxQueue = xQueueCreate(2, sizeof(uint16_t));
xTaskCreate(&task_mqtt_rx,"task_mqtt_rx", 3072, NULL, 3, &xMqttRx);
}
xTaskCreate(app_mqtt_init_task, /* The function that implements the task. */
"MQTTTask", /* Just a text name for the task to aid debugging. */
8192, /* The stack size is defined in FreeRTOSIPConfig.h. 4096 */
NULL, /* The task parameter, not used in this case. */
3, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
&xMqttHandle); /* The task handle is not used. */
LREP_WARNING(__FUNCTION__,"Mqtt init done!");
}
I’ve tried adding TLS to my STM32 MQTT project with this code, but when I run it, the log output is as follows:
[13:29:01.205]IN¡û¡ôe[0;33m49me[0;32m number generator…
_task: Broker alert e[0;39;49mSetting up the SSL/TLS structure…
Failed! mbedtls_ssl_setup returned -0x7f00
TLS setup failed with error code -0x7f00
static int app_mqtt_tls_setup(Network *network)
{
int ret = 0;
printf("Free heap at start: %d\n", xPortGetFreeHeapSize());
// Initialize mbedtls memory
mbedtls_memory_buffer_alloc_init(tls_buffer, TLS_BUFFER_SIZE);
// Clean up any previous contexts
mbedtls_ssl_free(&ssl);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
// Initialize the contexts
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
printf("Seeding the random number generator...\n");
// 1. Seed the RNG with minimal personalization
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
NULL, 0)) != 0) {
printf("Failed! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
goto cleanup;
}
printf("Setting up the SSL/TLS structure...\n");
// 2. Setup SSL/TLS configuration with minimal settings
if ((ret = mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
printf("Failed! mbedtls_ssl_config_defaults returned -0x%x\n", -ret);
goto cleanup;
}
// 3. Reduce memory usage in SSL config
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
// 4. Setup SSL context with static memory buffer
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
printf("Failed! mbedtls_ssl_setup returned -0x%x\n", -ret);
goto cleanup;
}
// 5. Set SSL context in network structure
network->ssl = &ssl;
printf("SSL/TLS setup completed successfully\n");
printf("Free heap at end: %d\n", xPortGetFreeHeapSize());
return 0;
cleanup:
mbedtls_ssl_free(&ssl);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return ret;
}