Ромка Ромка
Ромка Ромка

Reputation: 31

How to use STM32 lwip/mqtt api with tls?

i made stm32 + rtos + lwip/mqtt solution and it works well. Now i want to use it with embed tls secure connection. I did not find any exemples.

lwip mqtt api supports tls comunication. But there are no such example, just simple mqtt client using code LWIP MQTT Client i used.

I tried to enable embedtls and some options in cubemx, LWIP_ALTCP & LWIP_ALTCP_TLS, add LWIP_ALTCP_TLS_MBEDTLS to Path. It compiled. How to init mbedtls and add tls cert. this link takes a little info altcp tls

Has anyebody some expirience or working example with stm32 lwip/mqtt + tls (mbedtls) for stm32 lwip stack?

UPD. Here is my code of mqtt client setup:

struct mqtt_connect_client_info_t ci;
memset(&ci, 0, sizeof(ci));
ci.client_id = "lwip_test";
ci.client_user = "";
ci.client_pass = "";
ci.keep_alive = 0;
ci.tls_config = altcp_tls_create_config_client((const u8_t*)test_cert, sizeof(test_cert));
// create client
client = mqtt_client_new();
// connect client   
mqtt_client_connect(client, &resolved, port, mqtt_on_connect, (void *)0, &ci);

I give mqtt client ca certificate and length. I have an error in altcp_tls_create_config_client_common function (altcp_tls_mbedtls.c) with code -4480 (Failed to allocate memory).

ret = mbedtls_x509_crt_parse(conf->ca, ca, ca_len);
if (ret != 0) {
  LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse ca failed: %d 0x%x", ret, -1*ret));
  altcp_mbedtls_free_config(conf);
  return NULL;
}

What i am doing wrong, whitch options else i should set up in mbedtls module? I use default was generated by CubeMX

Upvotes: 1

Views: 9227

Answers (3)

Bayrem Gharsellaoui
Bayrem Gharsellaoui

Reputation: 308

you seem to have a memory allocation problem, you can try to increase the heap memory size in lwipopts.h like the following:

#define MEM_SIZE (50 * 1024)

Upvotes: 0

Ondřej Lufinka
Ondřej Lufinka

Reputation: 51

This thread helped me together with other examples in https://www.nongnu.org/lwip/2_0_x/group__mqtt.html to make the MQTT client work with MbedTLS 2 way authentication. I can now subscribe/publish to the amazon AWS cloud.

So if anybody is interested, here is what I did.

  1. Generate code from CubeMX with LwIP and MbedTLS enabled. Important is to enable MBEDTLS_PLATFORM_MEMORY, MEMP_MEM_MALLOC and LWIP_ALTCP_TLS_MBEDTLS so the library uses alternative calloc/free functions from LwIP (they are set in the altcp_mbedtls_mem_init() function).

  2. I also use MBEDTLS_ENTROPY_HARDWARE_ALT, MBEDTLS_NO_PLATFORM_ENTROPY and MBEDTLS_CTR_DRBG_C enabled, so the MbedTLS library can use the ctr drbg random number generator (initialized in the altcp_tls_create_config() function).

  3. If you use FreeRTOS with your LwIP as I do, it is necessarry to enable MBEDTLS_THREADING_ALT and then in your code call the mbedtls_threading_set_alt() function to enable mutex handling in the MbedTLS library.

  4. Here is then what I do in my code:

mqtt_client_t *client;
struct mqtt_connect_client_info_t client_info;
ip_addr_t server_ip;

/* Somewhere in the code call this to get IP address of the host */
ip_addr_t ipaddr;
err = dns_gethostbyname("host_name", &ipaddr, mqtt_resolved_cb, NULL);

/* Wait until this callback gets the IP */
static void mqtt_resolved_cb(const char *host, const ip_addr_t *ipaddr,
                             void *callback_arg)
{
  /* If resolved IP is known -> set it */
  if (ipaddr->addr != 0)
  {
    server_ip.addr = ipaddr->addr;
  }
}

/* Then call this to start MQTT client */
void mqtt_test(const ip_addr_t *ipaddr, uint16_t port,
               const uint8_t *ca_cert_str, size_t ca_cert_len,
               const uint8_t *dev_cert_str, size_t dev_cert_len,
               const uint8_t *dev_key_str, size_t dev_key_len,
               const uint8_t *dev_key_pass_str, size_t dev_key_pass_len)
{
  /* Setup an empty client info structure */
  memset(&mqtt.client_info, 0, sizeof(mqtt.client_info));

  /* Set client information */
  mqtt.client_info.client_id = "lwip_test";
  mqtt.client_info.client_user = NULL;
  mqtt.client_info.client_pass = NULL;
  mqtt.client_info.keep_alive = 0;
  mqtt.client_info.will_topic = NULL;
  mqtt.client_info.will_msg = NULL;
  mqtt.client_info.will_retain = 0;
  mqtt.client_info.will_qos = 0;

  /* Set TLS configuration */
  mqtt.client_info.tls_config = altcp_tls_create_config_client_2wayauth(
    ca_cert_str, ca_cert_len,
    dev_key_str, dev_key_len, dev_key_pass_str, dev_key_pass_len,
    dev_cert_str, dev_cert_len);

  /* Allocate memory for MQTT client */
  mqtt.client = mqtt_client_new();

  /* Connect to the server */
  if (mqtt.client != NULL)
  {
    err = mqtt_client_connect(
      mqtt.client, ipaddr, port,
      mqtt_connection_cb, 0, &mqtt.client_info);
  }
}

Then the code continues in the standard mqtt callbacks from the example link above.

Thanks and I hope this can help someone else too.

Upvotes: 5

lcudst
lcudst

Reputation: 21

I have an identical configuration, so I can tell you that if you debug code you'll see that it will crash trying to call calloc, if your environment is equal to mine, you have not that system function.

What I did is using calloc implemented in lwip, in particular into altcp module. I defined via cubemx MBEDTLS_PLATFORM_MEMORY, in order to activate the define ALTCP_MBEDTLS_PLATFORM_ALLOC in altcp_tls_mbedtls_mem.c, then I was able to use altcp_mbedtls_mem_init() function that specify to mbedtls to use altcp calloc and free.

This function is called into altcp_tls_create_config_client, so if you are going to use it, you don't have to call altcp_mbedtls_mem_init() twice.

In this way you should be able to correctly allocate memory for mbedtls.

Upvotes: 2

Related Questions