net: mqtt: Add TLS socket transport

Add TLS transport to socket MQTT implementation.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2018-09-06 10:28:55 +02:00 committed by Anas Nashif
commit d2a397bcf8
5 changed files with 229 additions and 0 deletions

View file

@ -26,6 +26,7 @@
#include <zephyr.h> #include <zephyr.h>
#include <zephyr/types.h> #include <zephyr/types.h>
#include <net/tls_credentials.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -312,13 +313,40 @@ struct mqtt_client;
typedef void (*mqtt_evt_cb_t)(struct mqtt_client *client, typedef void (*mqtt_evt_cb_t)(struct mqtt_client *client,
const struct mqtt_evt *evt); const struct mqtt_evt *evt);
/** @brief TLS configuration for secure MQTT transports. */
struct mqtt_sec_config {
/** Indicates the preference for peer verification. */
int peer_verify;
/** Indicates the number of entries in the cipher list. */
u32_t cipher_count;
/** Indicates the list of ciphers to be used for the session.
* May be NULL to use the default ciphers.
*/
int *cipher_list;
/** Indicates the number of entries in the sec tag list. */
u32_t sec_tag_count;
/** Indicates the list of security tags to be used for the session. */
sec_tag_t *seg_tag_list;
/** Peer hostname for ceritificate verification.
* May be NULL to skip hostname verification.
*/
char *hostname;
};
/** @brief MQTT transport type. */ /** @brief MQTT transport type. */
enum mqtt_transport_type { enum mqtt_transport_type {
/** Use non secure TCP transport for MQTT connection. */ /** Use non secure TCP transport for MQTT connection. */
MQTT_TRANSPORT_NON_SECURE = 0x00, MQTT_TRANSPORT_NON_SECURE = 0x00,
#if defined(CONFIG_MQTT_LIB_TLS)
/** Use secure TCP transport (TLS) for MQTT connection. */ /** Use secure TCP transport (TLS) for MQTT connection. */
MQTT_TRANSPORT_SECURE = 0x01, MQTT_TRANSPORT_SECURE = 0x01,
#endif /* CONFIG_MQTT_LIB_TLS */
/** Shall not be used as a transport type. /** Shall not be used as a transport type.
* Indicator of maximum transport types possible. * Indicator of maximum transport types possible.
@ -340,6 +368,19 @@ struct mqtt_transport {
/** Socket descriptor. */ /** Socket descriptor. */
int sock; int sock;
} tcp; } tcp;
#if defined(CONFIG_MQTT_LIB_TLS)
/* TLS socket transport for MQTT */
struct {
/** Socket descriptor. */
int sock;
/** TLS configuration. See @ref mqtt_sec_config for
* details.
*/
struct mqtt_sec_config config;
} tls;
#endif /* CONFIG_MQTT_LIB_TLS */
}; };
}; };

View file

@ -8,3 +8,7 @@ zephyr_library_sources(
mqtt_transport.c mqtt_transport.c
mqtt.c mqtt.c
) )
zephyr_library_sources_ifdef(CONFIG_MQTT_LIB_TLS
mqtt_transport_socket_tls.c
)

View file

@ -27,4 +27,9 @@ config MQTT_KEEPALIVE
Keep alive time for MQTT (in seconds). Sending of Ping Requests to Keep alive time for MQTT (in seconds). Sending of Ping Requests to
keep the connection alive are governed by this value. keep the connection alive are governed by this value.
config MQTT_LIB_TLS
bool "TLS support for socket MQTT Library"
help
Enable TLS support for socket MQTT Library
endif # MQTT_LIB endif # MQTT_LIB

View file

@ -19,6 +19,16 @@ extern int mqtt_client_tcp_read(struct mqtt_client *client, u8_t *data,
u32_t buflen); u32_t buflen);
extern int mqtt_client_tcp_disconnect(struct mqtt_client *client); extern int mqtt_client_tcp_disconnect(struct mqtt_client *client);
#if defined(CONFIG_MQTT_LIB_TLS)
/* Transport handler functions for TLS socket transport. */
extern int mqtt_client_tls_connect(struct mqtt_client *client);
extern int mqtt_client_tls_write(struct mqtt_client *client, const u8_t *data,
u32_t datalen);
extern int mqtt_client_tls_read(struct mqtt_client *client, u8_t *data,
u32_t buflen);
extern int mqtt_client_tls_disconnect(struct mqtt_client *client);
#endif /* CONFIG_MQTT_LIB_TLS */
/**@brief Function pointer array for TCP/TLS transport handlers. */ /**@brief Function pointer array for TCP/TLS transport handlers. */
const struct transport_procedure transport_fn[MQTT_TRANSPORT_NUM] = { const struct transport_procedure transport_fn[MQTT_TRANSPORT_NUM] = {
{ {
@ -26,7 +36,15 @@ const struct transport_procedure transport_fn[MQTT_TRANSPORT_NUM] = {
mqtt_client_tcp_write, mqtt_client_tcp_write,
mqtt_client_tcp_read, mqtt_client_tcp_read,
mqtt_client_tcp_disconnect, mqtt_client_tcp_disconnect,
},
#if defined(CONFIG_MQTT_LIB_TLS)
{
mqtt_client_tls_connect,
mqtt_client_tls_write,
mqtt_client_tls_read,
mqtt_client_tls_disconnect,
} }
#endif /* CONFIG_MQTT_LIB_TLS */
}; };
int mqtt_transport_connect(struct mqtt_client *client) int mqtt_transport_connect(struct mqtt_client *client)

View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file mqtt_transport_socket_tls.h
*
* @brief Internal functions to handle transport over TLS socket.
*/
#define LOG_MODULE_NAME net_mqtt_sock_tls
#define NET_LOG_LEVEL CONFIG_MQTT_LOG_LEVEL
#include <errno.h>
#include <net/socket.h>
#include <net/mqtt.h>
#include "mqtt_os.h"
/**@brief Handles connect request for TLS socket transport.
*
* @param[in] client Identifies the client on which the procedure is requested.
*
* @retval 0 or an error code indicating reason for failure.
*/
int mqtt_client_tls_connect(struct mqtt_client *client)
{
const struct sockaddr *broker = client->broker;
struct mqtt_sec_config *tls_config = &client->transport.tls.config;
int ret;
client->transport.tls.sock = socket(broker->sa_family,
SOCK_STREAM, IPPROTO_TLS_1_2);
if (client->transport.tls.sock < 0) {
return -errno;
}
MQTT_TRC("Created socket %d", client->transport.tls.sock);
/* Set secure socket options. */
ret = setsockopt(client->transport.tls.sock, SOL_TLS, TLS_PEER_VERIFY,
&tls_config->peer_verify,
sizeof(tls_config->peer_verify));
if (ret < 0) {
goto error;
}
if (tls_config->cipher_list != NULL && tls_config->cipher_count > 0) {
ret = setsockopt(client->transport.tls.sock, SOL_TLS,
TLS_CIPHERSUITE_LIST, tls_config->cipher_list,
sizeof(int) * tls_config->cipher_count);
if (ret < 0) {
goto error;
}
}
if (tls_config->seg_tag_list != NULL && tls_config->sec_tag_count > 0) {
ret = setsockopt(client->transport.tls.sock, SOL_TLS,
TLS_SEC_TAG_LIST, tls_config->seg_tag_list,
sizeof(sec_tag_t) * tls_config->sec_tag_count);
if (ret < 0) {
goto error;
}
}
if (tls_config->hostname) {
ret = setsockopt(client->transport.tls.sock, SOL_TLS,
TLS_HOSTNAME, tls_config->hostname,
strlen(tls_config->hostname));
if (ret < 0) {
goto error;
}
}
size_t peer_addr_size = sizeof(struct sockaddr_in6);
if (broker->sa_family == AF_INET) {
peer_addr_size = sizeof(struct sockaddr_in);
}
ret = connect(client->transport.tls.sock, client->broker,
peer_addr_size);
if (ret < 0) {
goto error;
}
MQTT_TRC("Connect completed");
return 0;
error:
(void)close(client->transport.tls.sock);
return -errno;
}
/**@brief Handles write requests on TLS socket transport.
*
* @param[in] client Identifies the client on which the procedure is requested.
* @param[in] data Data to be written on the transport.
* @param[in] datalen Length of data to be written on the transport.
*
* @retval 0 or an error code indicating reason for failure.
*/
int mqtt_client_tls_write(struct mqtt_client *client, const u8_t *data,
u32_t datalen)
{
u32_t offset = 0;
int ret;
while (offset < datalen) {
ret = send(client->transport.tls.sock, data + offset,
datalen - offset, 0);
if (ret < 0) {
return -errno;
}
offset += ret;
}
return 0;
}
/**@brief Handles read requests on TLS socket transport.
*
* @param[in] client Identifies the client on which the procedure is requested.
* @param[in] data Pointer where read data is to be fetched.
* @param[in] buflen Size of memory provided for the operation.
*
* @retval Number of bytes read or an error code indicating reason for failure.
* 0 if connection was closed.
*/
int mqtt_client_tls_read(struct mqtt_client *client, u8_t *data, u32_t buflen)
{
int ret;
ret = recv(client->transport.tls.sock, data, buflen, MSG_DONTWAIT);
if (ret < 0) {
return -errno;
}
return ret;
}
/**@brief Handles transport disconnection requests on TLS socket transport.
*
* @param[in] client Identifies the client on which the procedure is requested.
*
* @retval 0 or an error code indicating reason for failure.
*/
int mqtt_client_tls_disconnect(struct mqtt_client *client)
{
int ret;
MQTT_TRC("Closing socket %d", client->transport.tls.sock);
ret = close(client->transport.tls.sock);
if (ret < 0) {
return -errno;
}
return 0;
}