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:
parent
37563a92d5
commit
d2a397bcf8
5 changed files with 229 additions and 0 deletions
|
@ -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 */
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
161
subsys/net/lib/mqtt_sock/mqtt_transport_socket_tls.c
Normal file
161
subsys/net/lib/mqtt_sock/mqtt_transport_socket_tls.c
Normal 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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue