This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Implementing TLS with MQTT in nrf9160

I'm trying  to connect to an AWS MQTT broker I have set up based on the code in https://github.com/joakimtoe/fw-nrfconnect-nrf/tree/36532a8ca60bf7139a988b5cbb4e6cb47948a9fa/samples/nrf9160/mqtt_simple , and this is the output I get:

SPM: NS image at 0x8000
SPM: NS MSP at 0x200240e0
SPM: NS reset vector at 0xb73d
SPM: prepare to jump to Non-Secure image.
***** Booting Zephyr OS v1.14.99-ncs1 *****
The MQTT simple sample started
Deleting certs sec_tag: 16842753
nrf_inbuilt_key_delete(16842753, 0) => result=2
Deleting certs sec_tag: 16842753
***** BUS FAULT *****
  Precise data bus error
  BFAR Address: 0x3b61bb53
***** Hardware exception *****
Current thread ID = 0x20020400
Faulting instruction address = 0x16934
Fatal fault in thread 0x20020400! Aborting.
nrf_inbuilt_key_delete(16842753, 1) => result=14
Deleting certs sec_tag: 16842753
nrf_inbuilt_key_delete(16842753, 2) => result=14
Deleting certs sec_tag: 16842753
nrf_inbuilt_key_delete(16842753, 3) => result=14
Deleting certs sec_tag: 16842753
nrf_inbuilt_key_delete(16842753, 4) => result=14
Write ca certs sec_tag: 16842753
CA_CERTIFICATE err: 14
LTE Link Connecting ...
LTE Link Connected!
ERROR: getaddrinfo failed 22
ERROR: mqtt_connect -47

main.c:

/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
 */

#include <zephyr.h>
#include <stdio.h>
#include <uart.h>
#include <string.h>

#include <net/mqtt.h>
#include <net/socket.h>
#include <lte_lc.h>

#include <bsd.h>

#if defined(CONFIG_PROVISION_CERTIFICATES)
#if defined(CONFIG_BSD_LIBRARY)
#include "nrf_inbuilt_key.h"
#endif
//#include CONFIG_CERTIFICATES_FILE
#endif

#include <net/tls_credentials.h>
#include "certificates.h"

#if defined(CONFIG_MQTT_LIB_TLS)
	static sec_tag_t sec_tag_list[] = { CONFIG_SEC_TAG };
#endif

/* Buffers for MQTT client. */
static u8_t rx_buffer[CONFIG_MQTT_MESSAGE_BUFFER_SIZE];
static u8_t tx_buffer[CONFIG_MQTT_MESSAGE_BUFFER_SIZE];
static u8_t payload_buf[CONFIG_MQTT_PAYLOAD_BUFFER_SIZE];

/* The mqtt client struct */
static struct mqtt_client client;

/* MQTT Broker details. */
static struct sockaddr_storage broker;

/* Connected flag */
static bool connected;

/* File descriptor */
struct pollfd fds;

/**@brief Function to print strings without null-termination
 */
static void data_print(u8_t *prefix, u8_t *data, size_t len)
{
	char buf[len + 1];

	memcpy(buf, data, len);
	buf[len] = 0;
	printk("%s%s\n", prefix, buf);
}

/**@brief Function to publish data on the configured topic
 */
static int data_publish(struct mqtt_client *c, enum mqtt_qos qos,
	u8_t *data, size_t len)
{
	struct mqtt_publish_param param;

	param.message.topic.qos = qos;
	param.message.topic.topic.utf8 = CONFIG_MQTT_PUB_TOPIC;
	param.message.topic.topic.size = strlen(CONFIG_MQTT_PUB_TOPIC);
	param.message.payload.data = data;
	param.message.payload.len = len;
	param.message_id = sys_rand32_get();
	param.dup_flag = 0;
	param.retain_flag = 0;

	data_print("Publish: ", data, len);
	printk("to topic: %s len: %u\n",
		CONFIG_MQTT_PUB_TOPIC,
		(unsigned int)strlen(CONFIG_MQTT_PUB_TOPIC));

	return mqtt_publish(c, &param);
}

/**@brief Function to subscribe to the configured topic
 */
static int subscribe(void)
{
	struct mqtt_topic subscribe_topic = {
		.topic = {
			.utf8 = CONFIG_MQTT_SUB_TOPIC,
			.size = strlen(CONFIG_MQTT_SUB_TOPIC)
		},
		.qos = MQTT_QOS_1_AT_LEAST_ONCE
	};

	const struct mqtt_subscription_list subscription_list = {
		.list = &subscribe_topic,
		.list_count = 1,
		.message_id = 1234
	};

	printk("Subscribing to: %s len %u\n", CONFIG_MQTT_SUB_TOPIC,
		(unsigned int)strlen(CONFIG_MQTT_SUB_TOPIC));

	return mqtt_subscribe(&client, &subscription_list);
}

/**@brief Function to read the published payload.
 */
static int publish_get_payload(struct mqtt_client *c, size_t length)
{
	u8_t *buf = payload_buf;
	u8_t *end = buf + length;

	if (length > sizeof(payload_buf)) {
		return -EMSGSIZE;
	}

	while (buf < end) {
		int ret = mqtt_read_publish_payload(c, buf, end - buf);

		if (ret < 0) {
			if (ret == -EAGAIN) {
				printk("mqtt_read_publish_payload: EAGAIN");
				poll(&fds, 1, K_FOREVER);
				continue;
			}

			return ret;
		}

		if (ret == 0) {
			return -EIO;
		}

		buf += ret;
	}

	return 0;
}

/**@brief MQTT client event handler
 */
void mqtt_evt_handler(struct mqtt_client *const c,
		      const struct mqtt_evt *evt)
{
	int err;

	switch (evt->type) {
	case MQTT_EVT_CONNACK:
		if (evt->result != 0) {
			printk("MQTT connect failed %d\n", evt->result);
			break;
		}

		connected = true;
		printk("[%s:%d] MQTT client connected!\n", __func__, __LINE__);
		subscribe();
		break;

	case MQTT_EVT_DISCONNECT:
		printk("[%s:%d] MQTT client disconnected %d\n", __func__,
		       __LINE__, evt->result);

		connected = false;
		break;

	case MQTT_EVT_PUBLISH: {
		const struct mqtt_publish_param *p = &evt->param.publish;

		printk("[%s:%d] MQTT PUBLISH result=%d len=%d\n", __func__,
		       __LINE__, evt->result, p->message.payload.len);
		err = publish_get_payload(c, p->message.payload.len);
		if (err >= 0) {
			data_print("Received: ", payload_buf,
				p->message.payload.len);
			/* Echo back received data */
			data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE,
				payload_buf, p->message.payload.len);
		} else {
			printk("mqtt_read_publish_payload: Failed! %d\n", err);
		}
	} break;

	case MQTT_EVT_PUBACK:
		if (evt->result != 0) {
			printk("MQTT PUBACK error %d\n", evt->result);
			break;
		}

		printk("[%s:%d] PUBACK packet id: %u\n", __func__, __LINE__,
				evt->param.puback.message_id);
		break;

	case MQTT_EVT_SUBACK:
		if (evt->result != 0) {
			printk("MQTT SUBACK error %d\n", evt->result);
			break;
		}

		printk("[%s:%d] SUBACK packet id: %u\n", __func__, __LINE__,
				evt->param.suback.message_id);
		break;

	default:
		printk("[%s:%d] default: %d\n", __func__, __LINE__,
				evt->type);
		break;
	}
}

/**@brief Resolves the configured hostname and
 * initializes the MQTT broker structure
 */
static void broker_init(void)
{
	int err;
	struct addrinfo *result;
	struct addrinfo *addr;
	struct addrinfo hints;

	hints.ai_flags = 0;
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;

	err = getaddrinfo(CONFIG_MQTT_BROKER_HOSTNAME, NULL, &hints, &result);
	if (err) {
		printk("ERROR: getaddrinfo failed %d\n", err);

		return;
	}

	addr = result;
	err = -ENOENT;

	/* Look for address of the broker. */
	while (addr != NULL) {
		/* IPv4 Address. */
		if (addr->ai_addrlen == sizeof(struct sockaddr_in)) {
			struct sockaddr_in *broker4 =
				((struct sockaddr_in *)&broker);

			broker4->sin_addr.s_addr =
				((struct sockaddr_in *)addr->ai_addr)
				->sin_addr.s_addr;
			broker4->sin_family = AF_INET;
			broker4->sin_port = htons(CONFIG_MQTT_BROKER_PORT);
			printk("IPv4 Address found 0x%08x\n",
				broker4->sin_addr.s_addr);
			break;
		} else {
			printk("ai_addrlen = %u should be %u or %u\n",
				(unsigned int)addr->ai_addrlen,
				(unsigned int)sizeof(struct sockaddr_in),
				(unsigned int)sizeof(struct sockaddr_in6));
		}

		addr = addr->ai_next;
		break;
	}

	/* Free the address. */
	freeaddrinfo(result);
}

/**@brief Initialize the MQTT client structure
 */
static void client_init(struct mqtt_client *client)
{
	mqtt_client_init(client);

	broker_init();

	/* MQTT client configuration */
	client->broker = &broker;
	client->evt_cb = mqtt_evt_handler;
	client->client_id.utf8 = (u8_t *)CONFIG_MQTT_CLIENT_ID;
	client->client_id.size = strlen(CONFIG_MQTT_CLIENT_ID);
	client->password = NULL;
	client->user_name = NULL;
	client->protocol_version = MQTT_VERSION_3_1_1;

	/* MQTT buffers configuration */
	client->rx_buf = rx_buffer;
	client->rx_buf_size = sizeof(rx_buffer);
	client->tx_buf = tx_buffer;
	client->tx_buf_size = sizeof(tx_buffer);

	/* MQTT transport configuration */
#if defined(CONFIG_MQTT_LIB_TLS)
	struct mqtt_sec_config *tls_config = &client->transport.tls.config;
	
	client->transport.type = MQTT_TRANSPORT_SECURE;

	tls_config->peer_verify = 2;
	tls_config->cipher_count = 0;
	tls_config->cipher_list = NULL;
	tls_config->sec_tag_count = ARRAY_SIZE(sec_tag_list);
	tls_config->sec_tag_list = sec_tag_list;
	tls_config->hostname = CONFIG_MQTT_BROKER_HOSTNAME;
#else
	client->transport.type = MQTT_TRANSPORT_NON_SECURE;
#endif
}

/**@brief Initialize the file descriptor structure used by poll.
 */
static int fds_init(struct mqtt_client *c)
{
	if (c->transport.type == MQTT_TRANSPORT_NON_SECURE) {
		fds.fd = c->transport.tcp.sock;
	} else {
#if defined(CONFIG_MQTT_LIB_TLS)
		fds.fd = c->transport.tls.sock;
#else
		return -ENOTSUP;
#endif
	}

	fds.events = POLLIN;

	return 0;
}

/**@brief Configures modem to provide LTE link. Blocks until link is
 * successfully established.
 */
static void modem_configure(void)
{
#if defined(CONFIG_LTE_LINK_CONTROL)
	if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) {
		/* Do nothing, modem is already turned on
		 * and connected.
		 */
	} else {
		int err;

		printk("LTE Link Connecting ...\n");
		err = lte_lc_init_and_connect();
		__ASSERT(err == 0, "LTE link could not be established.");
		printk("LTE Link Connected!\n");
	}
#endif
}

static int provision_certificate(void)
{
#if defined(CONFIG_PROVISION_CERTIFICATES)
#if defined(CONFIG_BSD_LIBRARY)
	{
		int err;

		/* Delete certificates */
		nrf_sec_tag_t sec_tag = (nrf_sec_tag_t) sec_tag_list[0];

		for (nrf_key_mgnt_cred_type_t type = 0; type < 5; type++) {
			printk("Deleting certs sec_tag: %d\n", sec_tag);
			err = nrf_inbuilt_key_delete(sec_tag, type);
			printk("nrf_inbuilt_key_delete(%u, %d) => result=%d\n",
				sec_tag, type, err);
		}

#if defined(CA_CERTIFICATE)
		/* Provision CA Certificate. */
		printk("Write ca certs sec_tag: %d\n", sec_tag);
		err = nrf_inbuilt_key_write(sec_tag,
			NRF_KEY_MGMT_CRED_TYPE_CA_CHAIN,
			CA_CERTIFICATE,
			strlen(CA_CERTIFICATE));
		if (err) {
			printk("CA_CERTIFICATE err: %d\n", err);
			return err;
		}
#endif
#if defined (CLIENT_PRIVATE_KEY)
		/* Provision Private Certificate. */
		printk("Write private cert sec_tag: %d\n", sec_tag);
		err = nrf_inbuilt_key_write(
			sec_tag,
			NRF_KEY_MGMT_CRED_TYPE_PRIVATE_CERT,
			CLIENT_PRIVATE_KEY,
			strlen(CLIENT_PRIVATE_KEY));
		if (err) {
			printk("CLIENT_PRIVATE_KEY err: %d\n", err);
			return err;
		}
#endif
#if defined(CLIENT_PUBLIC_CERTIFICATE)
		/* Provision Public Certificate. */
		printk("Write public cert sec_tag: %d\n", sec_tag);
		err = nrf_inbuilt_key_write(
			sec_tag,
			NRF_KEY_MGMT_CRED_TYPE_PUBLIC_CERT,
			CLIENT_PUBLIC_CERTIFICATE,
			strlen(CLIENT_PUBLIC_CERTIFICATE));
		if (err) {
			printk("CLIENT_PUBLIC_CERTIFICATE err: %d\n",
				err);
			return err;
		}
	}
#endif
#else
	{
		int err;

		err = tls_credential_add(CONFIG_SEC_TAG,
			TLS_CREDENTIAL_CA_CERTIFICATE,
			NRF_CLOUD_CA_CERTIFICATE,
			sizeof(NRF_CLOUD_CA_CERTIFICATE));
		if (err < 0) {
			printk("Failed to register ca certificate: %d\n",
				err);
			return err;
		}
		err = tls_credential_add(CONFIG_SEC_TAG,
			TLS_CREDENTIAL_PRIVATE_KEY,
			NRF_CLOUD_CLIENT_PRIVATE_KEY,
			sizeof(NRF_CLOUD_CLIENT_PRIVATE_KEY));
		if (err < 0) {
			printk("Failed to register private key: %d\n",
				err);
			return err;
		}
		err = tls_credential_add(CONFIG_SEC_TAG,
			TLS_CREDENTIAL_SERVER_CERTIFICATE,
			NRF_CLOUD_CLIENT_PUBLIC_CERTIFICATE,
			sizeof(NRF_CLOUD_CLIENT_PUBLIC_CERTIFICATE));
		if (err < 0) {
			printk("Failed to register public certificate: %d\n",
				err);
			return err;
		}

	}
#endif /* defined(CONFIG_BSD_LIBRARY) */
#endif /* defined(CONFIG_PROVISION_CERTIFICATES) */

	return 0;
}

void main(void)
{
	int err;

//	if (!IS_ENABLED(CONFIG_AT_HOST_LIBRARY)) {
//		/* Stop the UART RX for power consumption reasons */
//		NRF_UARTE0_NS->TASKS_STOPRX = 1;
//		NRF_UARTE1_NS->TASKS_STOPRX = 1;
//	}

	printk("The MQTT simple sample started\n");

	provision_certificate();

	modem_configure();

	client_init(&client);

	err = mqtt_connect(&client);
	if (err != 0) {
		printk("ERROR: mqtt_connect %d\n", err);
		return;
	}

	err = fds_init(&client);
	if (err != 0) {
		printk("ERROR: fds_init %d\n", err);
		return;
	}

	while (1) {
		err = mqtt_input(&client);
		if (err != 0) {
			printk("ERROR: mqtt_input %d\n", err);
		}

		err = mqtt_live(&client);
		if (err != 0) {
			printk("ERROR: mqtt_live %d\n", err);
		}

		if (poll(&fds, 1, K_SECONDS(CONFIG_MQTT_KEEPALIVE)) < 0) {
			printk("ERROR: poll %d\n", errno);
		}
	}

        return;
}

prj.conf:

# General config
CONFIG_TEST_RANDOM_GENERATOR=y

# Networking
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y

# LTE link control
CONFIG_LTE_LINK_CONTROL=y
CONFIG_LTE_AUTO_INIT_AND_CONNECT=n
CONFIG_NRF_CLOUD_PROVISION_CERTIFICATES=y

# BSD library
CONFIG_BSD_LIBRARY=y

# AT Host
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_AT_HOST_LIBRARY=y

# MQTT
CONFIG_MQTT_LIB=y
CONFIG_MQTT_LIB_TLS=y

# Appliaction
CONFIG_MQTT_PUB_TOPIC="test/date"
CONFIG_MQTT_SUB_TOPIC="test/date"
CONFIG_MQTT_CLIENT_ID="test-id"
CONFIG_MQTT_BROKER_HOSTNAME="xxxxxxxxxxxxxxx.amazonaws.com"
CONFIG_MQTT_BROKER_PORT=443

CONFIG_SEC_TAG=16842753

CONFIG_PROVISION_CERTIFICATES=y
CONFIG_CERTIFICATES_FILE="certificates.h"

# Main thread
CONFIG_MAIN_THREAD_PRIORITY=7
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_HEAP_MEM_POOL_SIZE=1024

CONFIG_NO_OPTIMIZATIONS=y

Kconfig:

#
# Copyright (c) 2018 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
#

menu "MQTT simple sample"

config PROVISION_CERTIFICATES
	bool "Provision of certificate"
	help
		Enable run-time provisioning of certificates from the
		certificates header file selected by using CERTIFICATES_FILE

config CERTIFICATES_FILE
	string "Certificates to use"
	depends on PROVISION_CERTIFICATES
	default "certificates.h"

config SEC_TAG
	int "Security tag to use for the connection"
	default 16842753

config MQTT_PUB_TOPIC
	string "MQTT publish topic"
	default "test/date"

config MQTT_SUB_TOPIC
	string "MQTT subscribe topic"
	default "test/date"

config MQTT_CLIENT_ID
	string "MQTT Client ID"
	default "test-id"

config MQTT_BROKER_HOSTNAME
	string "MQTT broker hostname"
	default "xxxxxxxxxxxxxxxx.amazonaws.com"

config MQTT_BROKER_PORT
	int "MQTT broker port"
	default 443

config MQTT_MESSAGE_BUFFER_SIZE
	int ""
	default 128

config MQTT_PAYLOAD_BUFFER_SIZE
	int ""
	default 128

endmenu

menu "Zephyr Kernel"
source "$ZEPHYR_BASE/Kconfig.zephyr"
endmenu

And I have CA_CERTIFICATE, CLIENT_PRIVATE_KEY, and CLIENT_PUBLIC_CERTIFICATE defined in certificates.h in the src folder with main.c.

I've tried everything described in this thread: https://devzone.nordicsemi.com/f/nordic-q-a/48407/how-to-use-mqtt-tls-in-nrf9160/193461#193461 .

Looking at errno.h, it seems the error 14 (#define EFAULT 14       /* Bad address */) would indicate the sec_tag is incorrect in some way.

How should I go about solving this issue?

Thanks

Parents Reply Children
Related