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/types.h>
#include <net/tls_credentials.h>
#ifdef __cplusplus
extern "C" {
@ -312,13 +313,40 @@ struct mqtt_client;
typedef void (*mqtt_evt_cb_t)(struct mqtt_client *client,
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. */
enum mqtt_transport_type {
/** Use non secure TCP transport for MQTT connection. */
MQTT_TRANSPORT_NON_SECURE = 0x00,
#if defined(CONFIG_MQTT_LIB_TLS)
/** Use secure TCP transport (TLS) for MQTT connection. */
MQTT_TRANSPORT_SECURE = 0x01,
#endif /* CONFIG_MQTT_LIB_TLS */
/** Shall not be used as a transport type.
* Indicator of maximum transport types possible.
@ -340,6 +368,19 @@ struct mqtt_transport {
/** Socket descriptor. */
int sock;
} 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.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 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

View file

@ -19,6 +19,16 @@ extern int mqtt_client_tcp_read(struct mqtt_client *client, u8_t *data,
u32_t buflen);
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. */
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_read,
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)

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;
}