Skip to content

Commit 1d743fa

Browse files
rluboskartben
authored andcommitted
net: mqtt: Add support for MQTT 5.0 AUTH packet
Add support for a new AUTH message introduced in MQTT 5.0. This is a new mechanism specified by MQTT 5.0, which allows clients and brokers for enhanced authentication in between CONNECT and CONNACK exchange. An additional MQTT event (MQTT_EVT_AUTH) was specified which is triggered when the AUTH packet arrives from the broker. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
1 parent 55e1c10 commit 1d743fa

File tree

6 files changed

+317
-0
lines changed

6 files changed

+317
-0
lines changed

include/zephyr/net/mqtt.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ enum mqtt_evt_type {
7979

8080
/** Ping Response from server. */
8181
MQTT_EVT_PINGRESP,
82+
83+
/** Authentication packet received from server. MQTT 5.0 only. */
84+
MQTT_EVT_AUTH,
8285
};
8386

8487
/** @brief MQTT version protocol level. */
@@ -208,6 +211,13 @@ enum mqtt_disconnect_reason_code {
208211
MQTT_DISCONNECT_WILDCARD_SUB_NOT_SUPPORTED = 162,
209212
};
210213

214+
/** @brief MQTT Authenticate reason codes (MQTT 5.0, chapter 3.15.2.1). */
215+
enum mqtt_auth_reason_code {
216+
MQTT_AUTH_SUCCESS = 0,
217+
MQTT_AUTH_CONTINUE_AUTHENTICATION = 24,
218+
MQTT_AUTH_RE_AUTHENTICATE = 25,
219+
};
220+
211221
/** @brief Abstracts UTF-8 encoded strings. */
212222
struct mqtt_utf8 {
213223
const uint8_t *utf8; /**< Pointer to UTF-8 string. */
@@ -602,6 +612,39 @@ struct mqtt_disconnect_param {
602612
#endif /* CONFIG_MQTT_VERSION_5_0 */
603613
};
604614

615+
#if defined(CONFIG_MQTT_VERSION_5_0)
616+
struct mqtt_auth_param {
617+
/* MQTT 5.0, chapter 3.15.2.1 Authenticate Reason Code */
618+
enum mqtt_auth_reason_code reason_code;
619+
620+
struct {
621+
/** MQTT 5.0, chapter 3.15.2.2.5 User Property. */
622+
struct mqtt_utf8_pair user_prop[CONFIG_MQTT_USER_PROPERTIES_MAX];
623+
624+
/** MQTT 5.0, chapter 3.15.2.2.2 Authentication Method. */
625+
struct mqtt_utf8 auth_method;
626+
627+
/** MQTT 5.0, chapter 3.15.2.2.3 Authentication Data. */
628+
struct mqtt_binstr auth_data;
629+
630+
/** MQTT 5.0, chapter 3.15.2.2.4 Reason String. */
631+
struct mqtt_utf8 reason_string;
632+
633+
/** Flags indicating whether given property was present in received packet. */
634+
struct {
635+
/** Authentication Method property was present. */
636+
bool has_auth_method;
637+
/** Authentication Data property was present. */
638+
bool has_auth_data;
639+
/** Reason String property was present. */
640+
bool has_reason_string;
641+
/** User Property property was present. */
642+
bool has_user_prop;
643+
} rx;
644+
} prop;
645+
};
646+
#endif /* CONFIG_MQTT_VERSION_5_0 */
647+
605648
/**
606649
* @brief Defines event parameters notified along with asynchronous events
607650
* to the application.
@@ -639,6 +682,9 @@ union mqtt_evt_param {
639682
#if defined(CONFIG_MQTT_VERSION_5_0)
640683
/** Parameters accompanying MQTT_EVT_DISCONNECT event. */
641684
struct mqtt_disconnect_param disconnect;
685+
686+
/** Parameters accompanying MQTT_EVT_AUTH event. */
687+
struct mqtt_auth_param auth;
642688
#endif /* CONFIG_MQTT_VERSION_5_0 */
643689
};
644690

@@ -1117,6 +1163,20 @@ int mqtt_ping(struct mqtt_client *client);
11171163
int mqtt_disconnect(struct mqtt_client *client,
11181164
const struct mqtt_disconnect_param *param);
11191165

1166+
#if defined(CONFIG_MQTT_VERSION_5_0)
1167+
/**
1168+
* @brief API to send an authentication packet to the server.
1169+
*
1170+
* @param[in] client Client instance for which the procedure is requested.
1171+
* Shall not be NULL.
1172+
* @param[in] param Parameters to be used for the auth message.
1173+
* Shall not be NULL.
1174+
*
1175+
* @return 0 or a negative error code (errno.h) indicating reason of failure.
1176+
*/
1177+
int mqtt_auth(struct mqtt_client *client, const struct mqtt_auth_param *param);
1178+
#endif /* CONFIG_MQTT_VERSION_5_0 */
1179+
11201180
/**
11211181
* @brief API to abort MQTT connection. This will close the corresponding
11221182
* transport without closing the connection gracefully at the MQTT level

subsys/net/lib/mqtt/mqtt.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,58 @@ int mqtt_ping(struct mqtt_client *client)
577577
return err_code;
578578
}
579579

580+
#if defined(CONFIG_MQTT_VERSION_5_0)
581+
static int verify_auth_state(const struct mqtt_client *client)
582+
{
583+
/* Enhanced authentication is only allowed when connecting at MQTT
584+
* level (before CONNACK is received).
585+
*/
586+
if (MQTT_HAS_STATE(client, MQTT_STATE_TCP_CONNECTED) &&
587+
!MQTT_HAS_STATE(client, MQTT_STATE_CONNECTED)) {
588+
return 0;
589+
}
590+
591+
/* Return generic protocol error */
592+
return -EPROTO;
593+
}
594+
595+
int mqtt_auth(struct mqtt_client *client, const struct mqtt_auth_param *param)
596+
{
597+
int err_code;
598+
struct buf_ctx packet;
599+
600+
NULL_PARAM_CHECK(client);
601+
NULL_PARAM_CHECK(param);
602+
603+
mqtt_mutex_lock(client);
604+
605+
if (!mqtt_is_version_5_0(client)) {
606+
NET_ERR("Auth packet only supported in MQTT 5.0");
607+
err_code = -ENOTSUP;
608+
goto error;
609+
}
610+
611+
tx_buf_init(client, &packet);
612+
613+
err_code = verify_auth_state(client);
614+
if (err_code < 0) {
615+
goto error;
616+
}
617+
618+
err_code = auth_encode(param, &packet);
619+
if (err_code < 0) {
620+
goto error;
621+
}
622+
623+
err_code = client_write(client, packet.cur, packet.end - packet.cur);
624+
625+
error:
626+
mqtt_mutex_unlock(client);
627+
628+
return err_code;
629+
}
630+
#endif /* CONFIG_MQTT_VERSION_5_0 */
631+
580632
int mqtt_abort(struct mqtt_client *client)
581633
{
582634
NULL_PARAM_CHECK(client);

subsys/net/lib/mqtt/mqtt_decoder.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,4 +1078,65 @@ int disconnect_decode(const struct mqtt_client *client, struct buf_ctx *buf,
10781078

10791079
return 0;
10801080
}
1081+
1082+
static int auth_properties_decode(struct buf_ctx *buf,
1083+
struct mqtt_auth_param *param)
1084+
{
1085+
struct property_decoder prop[] = {
1086+
{
1087+
&param->prop.auth_method,
1088+
&param->prop.rx.has_auth_method,
1089+
MQTT_PROP_AUTHENTICATION_METHOD
1090+
},
1091+
{
1092+
&param->prop.auth_data,
1093+
&param->prop.rx.has_auth_data,
1094+
MQTT_PROP_AUTHENTICATION_DATA
1095+
},
1096+
{
1097+
&param->prop.reason_string,
1098+
&param->prop.rx.has_reason_string,
1099+
MQTT_PROP_REASON_STRING
1100+
},
1101+
{
1102+
&param->prop.user_prop,
1103+
&param->prop.rx.has_user_prop,
1104+
MQTT_PROP_USER_PROPERTY
1105+
}
1106+
};
1107+
1108+
return properties_decode(prop, ARRAY_SIZE(prop), buf);
1109+
}
1110+
1111+
int auth_decode(const struct mqtt_client *client, struct buf_ctx *buf,
1112+
struct mqtt_auth_param *param)
1113+
{
1114+
size_t remaining_len;
1115+
uint8_t reason_code;
1116+
int err;
1117+
1118+
if (!mqtt_is_version_5_0(client)) {
1119+
return -ENOTSUP;
1120+
}
1121+
1122+
remaining_len = buf->end - buf->cur;
1123+
1124+
if (remaining_len > 0) {
1125+
err = unpack_uint8(buf, &reason_code);
1126+
if (err < 0) {
1127+
return err;
1128+
}
1129+
1130+
param->reason_code = reason_code;
1131+
}
1132+
1133+
if (remaining_len > 1) {
1134+
err = auth_properties_decode(buf, param);
1135+
if (err < 0) {
1136+
return err;
1137+
}
1138+
}
1139+
1140+
return 0;
1141+
}
10811142
#endif /* CONFIG_MQTT_VERSION_5_0 */

subsys/net/lib/mqtt/mqtt_encoder.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,3 +1480,109 @@ int ping_request_encode(struct buf_ctx *buf)
14801480

14811481
return 0;
14821482
}
1483+
1484+
#if defined(CONFIG_MQTT_VERSION_5_0)
1485+
static uint32_t auth_properties_length(const struct mqtt_auth_param *param)
1486+
{
1487+
return string_property_length(&param->prop.auth_method) +
1488+
binary_property_length(&param->prop.auth_data) +
1489+
string_property_length(&param->prop.reason_string) +
1490+
user_properties_length(param->prop.user_prop);
1491+
}
1492+
1493+
static int auth_properties_encode(const struct mqtt_auth_param *param,
1494+
struct buf_ctx *buf)
1495+
{
1496+
uint32_t properties_len;
1497+
int err;
1498+
1499+
/* Precalculate total properties length */
1500+
properties_len = auth_properties_length(param);
1501+
if (properties_len == 0) {
1502+
return 0;
1503+
}
1504+
1505+
err = pack_variable_int(properties_len, buf);
1506+
if (err < 0) {
1507+
return err;
1508+
}
1509+
1510+
err = encode_string_property(MQTT_PROP_AUTHENTICATION_METHOD,
1511+
&param->prop.auth_method, buf);
1512+
if (err < 0) {
1513+
return err;
1514+
}
1515+
1516+
err = encode_binary_property(MQTT_PROP_AUTHENTICATION_DATA,
1517+
&param->prop.auth_data, buf);
1518+
if (err < 0) {
1519+
return err;
1520+
}
1521+
1522+
err = encode_string_property(MQTT_PROP_REASON_STRING,
1523+
&param->prop.reason_string, buf);
1524+
if (err < 0) {
1525+
return err;
1526+
}
1527+
1528+
err = encode_user_properties(param->prop.user_prop, buf);
1529+
if (err < 0) {
1530+
return err;
1531+
}
1532+
1533+
return 0;
1534+
}
1535+
1536+
static int empty_auth_encode(struct buf_ctx *buf)
1537+
{
1538+
const uint8_t empty_auth_packet[] = {
1539+
MQTT_PKT_TYPE_AUTH,
1540+
0x00
1541+
};
1542+
uint8_t *cur = buf->cur;
1543+
uint8_t *end = buf->end;
1544+
1545+
if ((end - cur) < sizeof(empty_auth_packet)) {
1546+
return -ENOMEM;
1547+
}
1548+
1549+
memcpy(cur, empty_auth_packet, sizeof(empty_auth_packet));
1550+
buf->end = (cur + sizeof(empty_auth_packet));
1551+
1552+
return 0;
1553+
}
1554+
1555+
int auth_encode(const struct mqtt_auth_param *param, struct buf_ctx *buf)
1556+
{
1557+
const uint8_t message_type =
1558+
MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_AUTH, 0, 0, 0);
1559+
uint8_t *start;
1560+
int err;
1561+
1562+
/* Reserve space for fixed header. */
1563+
buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
1564+
start = buf->cur;
1565+
1566+
if ((param->reason_code == MQTT_AUTH_SUCCESS) &&
1567+
(auth_properties_length(param) == 0U)) {
1568+
return empty_auth_encode(buf);
1569+
}
1570+
1571+
err = pack_uint8(param->reason_code, buf);
1572+
if (err < 0) {
1573+
return err;
1574+
}
1575+
1576+
err = auth_properties_encode(param, buf);
1577+
if (err != 0) {
1578+
return err;
1579+
}
1580+
1581+
err = mqtt_encode_fixed_header(message_type, start, buf);
1582+
if (err != 0) {
1583+
return err;
1584+
}
1585+
1586+
return 0;
1587+
}
1588+
#endif /* CONFIG_MQTT_VERSION_5_0 */

subsys/net/lib/mqtt/mqtt_internal.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extern "C" {
5454
#define MQTT_PKT_TYPE_PINGREQ 0xC0
5555
#define MQTT_PKT_TYPE_PINGRSP 0xD0
5656
#define MQTT_PKT_TYPE_DISCONNECT 0xE0
57+
#define MQTT_PKT_TYPE_AUTH 0xF0
5758

5859
/**@brief MQTT Property Types. */
5960
#define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01
@@ -346,6 +347,20 @@ int unsubscribe_encode(const struct mqtt_client *client,
346347
*/
347348
int ping_request_encode(struct buf_ctx *buf);
348349

350+
#if defined(CONFIG_MQTT_VERSION_5_0)
351+
/**@brief Constructs/encodes Authenticate packet.
352+
*
353+
* @param[in] param Authenticate message parameters.
354+
* @param[inout] buf_ctx Pointer to the buffer context structure,
355+
* containing buffer for the encoded message.
356+
* As output points to the beginning and end of
357+
* the frame.
358+
*
359+
* @return 0 if the procedure is successful, an error code otherwise.
360+
*/
361+
int auth_encode(const struct mqtt_auth_param *param, struct buf_ctx *buf);
362+
#endif /* CONFIG_MQTT_VERSION_5_0 */
363+
349364
/**@brief Decode MQTT Packet Type and Length in the MQTT fixed header.
350365
*
351366
* @param[inout] buf A pointer to the buf_ctx structure containing current
@@ -469,6 +484,18 @@ int unsubscribe_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf
469484
*/
470485
int disconnect_decode(const struct mqtt_client *client, struct buf_ctx *buf,
471486
struct mqtt_disconnect_param *param);
487+
488+
/**@brief Decode MQTT Auth packet.
489+
*
490+
* @param[in] MQTT client for which packet is decoded.
491+
* @param[inout] buf A pointer to the buf_ctx structure containing current
492+
* buffer position.
493+
* @param[out] param Pointer to buffer for decoded Auth parameters.
494+
*
495+
* @return 0 if the procedure is successful, an error code otherwise.
496+
*/
497+
int auth_decode(const struct mqtt_client *client, struct buf_ctx *buf,
498+
struct mqtt_auth_param *param);
472499
#endif /* CONFIG_MQTT_VERSION_5_0 */
473500

474501
/**

subsys/net/lib/mqtt/mqtt_rx.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ static int mqtt_handle_packet(struct mqtt_client *client,
154154
notify_event = false;
155155
}
156156

157+
break;
158+
159+
case MQTT_PKT_TYPE_AUTH:
160+
evt.type = MQTT_EVT_AUTH;
161+
err_code = auth_decode(client, buf, &evt.param.auth);
162+
if (err_code == 0) {
163+
evt.result = evt.param.auth.reason_code;
164+
} else {
165+
notify_event = false;
166+
}
167+
157168
break;
158169
#endif
159170

0 commit comments

Comments
 (0)