Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
717e53e
F-6046 - Reset the SN shared object instead of the generic message ob…
aidangarske Jul 10, 2026
623b7af
F-6219 - Validate exact length in SN_Decode_PublishResp
aidangarske Jul 10, 2026
6bcdace
F-6483 - Bound the SN PINGREQ client id to prevent length narrowing
aidangarske Jul 10, 2026
8a18f2a
F-6482 - Echo the received PUBLISH TopicId in the MQTT-SN PUBACK
aidangarske Jul 10, 2026
5205fca
F-3389 - Skip v5 property-stack shutdown when MqttClient_DeInit gets …
aidangarske Jul 10, 2026
b8357ba
F-6653 - Zero-fill the encoded data field when the payload pointer is…
aidangarske Jul 10, 2026
31ff000
F-4774 - Bound assigned client id copy by decoded length in mqttclient
aidangarske Jul 10, 2026
6e76371
F-4930 - Bound assigned client id copy by decoded length in nbclient
aidangarske Jul 10, 2026
af8123c
F-4998 - Bound assigned client id copy by decoded length in mqtt-pub
aidangarske Jul 10, 2026
0b77268
F-4999 - Bound assigned client id copy by decoded length in mqtt-sub
aidangarske Jul 10, 2026
f5326a4
F-2025 - Force-zero broker client credentials on static-memory free
aidangarske Jul 10, 2026
ab5f47e
F-6049 - Wipe the persist AES key cache unconditionally on broker free
aidangarske Jul 10, 2026
392a99d
F-2024 - Force-zero broker will buffers on static-memory ClearWill
aidangarske Jul 10, 2026
ef1ddfd
F-2026 - Force-zero retained message on static-memory delete
aidangarske Jul 10, 2026
ff9c8e9
F-2027 - Force-zero retained messages on static-memory free-all
aidangarske Jul 10, 2026
0fef1f2
F-3830 - Force-zero pending wills on static-memory cleanup
aidangarske Jul 10, 2026
9519460
F-4524 - Scrub each subscriber tx_buf after forwarding an immediate will
aidangarske Jul 10, 2026
db2b3aa
F-6051 - Force-zero retained payloads before free on dynamic-memory p…
aidangarske Jul 10, 2026
a71f43b
F-6657 - Force-zero broker out-queue payloads before free
aidangarske Jul 10, 2026
bdc73ec
F-6226 - Force-zero decrypted persist payloads before free
aidangarske Jul 10, 2026
9cdcc1e
F-6490 - Force-zero persist serialization buffers before free
aidangarske Jul 10, 2026
80a00b2
F-3822 - Reject reserved QoS in MqttEncode_Publish
aidangarske Jul 10, 2026
1e81241
F-3828 - Reject per-topic QoS above 2 in MqttEncode_Subscribe
aidangarske Jul 10, 2026
ce373d8
F-2753 - Reject zero-topic SUBSCRIBE and UNSUBSCRIBE encode
aidangarske Jul 10, 2026
2ae0159
F-4055 - Require a non-zero packet id in MqttEncode_PublishResp
aidangarske Jul 10, 2026
9a753bb
F-4526 - Validate the Will Topic name in MqttEncode_Connect
aidangarske Jul 10, 2026
55e67e1
F-4522 - Reject reserved Will QoS in MqttEncode_Connect
aidangarske Jul 10, 2026
58860cd
F-4525 - Normalize protocol level 0 before encoding CONNECT
aidangarske Jul 10, 2026
0ade8fc
F-6489 - Reject reserved ConnectAck flag bits
aidangarske Jul 10, 2026
74c30c0
F-3629 - Require an Authentication Method property when encoding AUTH
aidangarske Jul 10, 2026
5c80dc0
F-2758 - Default v5 DISCONNECT reason code when remaining length is zero
aidangarske Jul 10, 2026
b2f3714
F-6048 - Validate v5 UNSUBACK reason codes
aidangarske Jul 10, 2026
4c2aad2
F-6228 - Validate v5 property values in MqttEncode_Props
aidangarske Jul 10, 2026
f001cf6
F-5507 - Validate topic filters in SUBSCRIBE and UNSUBSCRIBE encode
aidangarske Jul 10, 2026
bd1612d
F-5667 - Reject v5 request-info property values above 1
aidangarske Jul 10, 2026
df9001b
F-6652 - Reject an empty v5 Topic Name without a Topic Alias
aidangarske Jul 10, 2026
6f36226
F-6218 - Treat retain as truthy in the retain-availability guard
aidangarske Jul 10, 2026
75bb05f
F-3139 - Guard property length underflow in MqttDecode_Props
aidangarske Jul 10, 2026
b396b96
F-3824 - Reject an over-long remaining-length VBI without an extra so…
aidangarske Jul 10, 2026
1bcd0bb
F-2759 - Compare broker credentials with a bounded constant-time length
aidangarske Jul 10, 2026
455707f
F-4306 - Return Packet-Identifier-Not-Found for untracked QoS2 PUBREL
aidangarske Jul 10, 2026
ad5b0b3
F-4519 - Deliver retained messages using the full subscription filter
aidangarske Jul 10, 2026
fbfae69
F-5666 - Force-zero tx_buf after encoding v5 DISCONNECT
aidangarske Jul 10, 2026
0a65851
F-5504 - Scrub tx_buf in MqttClient_CancelMessage
aidangarske Jul 10, 2026
06be735
F-2361 - Decode fixed-header remaining length via a typed word32 temp…
aidangarske Jul 10, 2026
763e3ba
F-2364 - Decode packet-read remaining length via a typed word32 tempo…
aidangarske Jul 10, 2026
6e24875
F-2365 - Decode property identifier via a typed word32 temporary
aidangarske Jul 10, 2026
32b8a5e
F-4521 - Reject a negative cmd_timeout_ms in MqttClient_Init
aidangarske Jul 10, 2026
6f846d9
F-4520 - Emit the plaintext-credentials warning in production builds
aidangarske Jul 10, 2026
0c14280
F-6040 - Reject a SUBACK whose return-code count differs from topic c…
aidangarske Jul 10, 2026
539709a
F-6041 - Reject a publish with buffer set but zero total length
aidangarske Jul 10, 2026
cead46f
F-5772 - Stream signed firmware from memory to close fwpush reopen TO…
aidangarske Jul 10, 2026
7575b76
F-3396 - Encode AUTH with the Success reason code
aidangarske Jul 10, 2026
13699b2
F-5770 - Guard firmware message length against integer overflow
aidangarske Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 52 additions & 28 deletions examples/firmware/fwpush.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include <wolfssl/wolfcrypt/hash.h>
#endif

#include <limits.h>
#include "fwpush.h"
#include "firmware.h"
#include "examples/mqttexample.h"
Expand Down Expand Up @@ -84,51 +85,58 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
static int mqtt_publish_cb(MqttPublish *publish) {
int ret = -1;
#if !defined(NO_FILESYSTEM)
size_t bytes_read;
FwpushCBdata *cbData;
FirmwareHeader *header;
word32 headerSize;
int avail, chunk;

/* Structure was stored in ctx pointer */
if (publish != NULL) {
cbData = (FwpushCBdata*)publish->ctx;
if (cbData != NULL) {
if (cbData != NULL && cbData->fwBuf != NULL) {
header = (FirmwareHeader*)cbData->data;
/* Guard a corrupt offset so avail/chunk can never go negative and
* feed a negative length back into the publish state machine. */
if (cbData->fwOffset < 0 || cbData->fwOffset > cbData->fwLen) {
return -1;
}
avail = cbData->fwLen - cbData->fwOffset;

/* Check for first iteration of callback */
if (cbData->fp == NULL) {
/* Get FW size from FW header struct */
/* Stream from the in-memory signed firmware rather than reopening
Comment thread
aidangarske marked this conversation as resolved.
* the file, so the bytes sent are exactly the bytes that were
* signed (no file-swap TOCTOU between build and send). */
if (!cbData->headerSent) {
headerSize = sizeof(FirmwareHeader) + header->sigLen +
header->pubKeyLen;
if (headerSize > publish->buffer_len) {
PRINTF("Error: Firmware Header %d larger than max buffer %d",
headerSize, publish->buffer_len);
(int)headerSize, publish->buffer_len);
return -1;
}

/* Copy header to buffer */
XMEMCPY(publish->buffer, header, headerSize);

/* Open file */
cbData->fp = fopen(cbData->filename, "rb");
if (cbData->fp != NULL) {
/* read a buffer of data from the file */
bytes_read = fread(&publish->buffer[headerSize],
1, publish->buffer_len - headerSize, cbData->fp);
if (bytes_read != 0) {
ret = (int)bytes_read + headerSize;
}
chunk = publish->buffer_len - (int)headerSize;
if (chunk > avail) {
chunk = avail;
}
if (chunk > 0) {
XMEMCPY(&publish->buffer[headerSize],
&cbData->fwBuf[cbData->fwOffset], chunk);
cbData->fwOffset += chunk;
}
cbData->headerSent = 1;
ret = (int)headerSize + chunk;
}
else {
/* read a buffer of data from the file */
bytes_read = fread(publish->buffer, 1, publish->buffer_len,
cbData->fp);
ret = (int)bytes_read;
}
if (cbData->fp && feof(cbData->fp)) {
fclose(cbData->fp);
cbData->fp = NULL;
chunk = publish->buffer_len;
if (chunk > avail) {
chunk = avail;
}
if (chunk > 0) {
XMEMCPY(publish->buffer,
&cbData->fwBuf[cbData->fwOffset], chunk);
cbData->fwOffset += chunk;
}
ret = chunk;
}
}
}
Expand All @@ -139,7 +147,7 @@ static int mqtt_publish_cb(MqttPublish *publish) {
}

static int fw_message_build(MQTTCtx *mqttCtx, const char* fwFile,
byte **p_msgBuf, int *p_msgLen)
byte **p_msgBuf, int *p_msgLen, byte **p_fwBuf, int *p_fwLen)
{
int rc;
byte *msgBuf = NULL, *sigBuf = NULL, *keyBuf = NULL, *fwBuf = NULL;
Expand Down Expand Up @@ -232,6 +240,12 @@ static int fw_message_build(MQTTCtx *mqttCtx, const char* fwFile,
#endif

/* Assemble message */
/* guard the int msgLen sum against overflow on huge firmware */
if (fwLen > INT_MAX - (int)(sizeof(FirmwareHeader) + sigLen + keyLen)) {
PRINTF("Firmware file too large: %d bytes", fwLen);
rc = EXIT_FAILURE;
goto exit;
}
msgLen = sizeof(FirmwareHeader) + sigLen + keyLen + fwLen;

/* The firmware will be copied by the callback */
Expand Down Expand Up @@ -265,6 +279,14 @@ static int fw_message_build(MQTTCtx *mqttCtx, const char* fwFile,
}

if (p_msgLen) *p_msgLen = msgLen;

/* Transfer ownership of the signed firmware buffer so the callback
* streams the exact signed bytes instead of re-reading the file. */
if (p_fwBuf) {
*p_fwBuf = fwBuf;
fwBuf = NULL;
}
if (p_fwLen) *p_fwLen = fwLen;
}
else {
if (msgBuf) WOLFMQTT_FREE(msgBuf);
Expand Down Expand Up @@ -445,7 +467,8 @@ int fwpush_test(MQTTCtx *mqttCtx)
cbData->filename = mqttCtx->pub_file;

rc = fw_message_build(mqttCtx, cbData->filename, &cbData->data,
(int*)&mqttCtx->publish.total_len);
(int*)&mqttCtx->publish.total_len,
&cbData->fwBuf, &cbData->fwLen);

/* The publish->ctx is available for use by the application to pass
* data to the callback routine. */
Expand Down Expand Up @@ -539,6 +562,7 @@ int fwpush_test(MQTTCtx *mqttCtx)
if (cbData) {
if (cbData->fp) fclose(cbData->fp);
if (cbData->data) WOLFMQTT_FREE(cbData->data);
if (cbData->fwBuf) WOLFMQTT_FREE(cbData->fwBuf);
WOLFMQTT_FREE(cbData);
}
if (mqttCtx->publish.buffer) WOLFMQTT_FREE(mqttCtx->publish.buffer);
Expand Down
4 changes: 4 additions & 0 deletions examples/firmware/fwpush.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ typedef struct FwpushCBdata_s {
const char *filename;
byte *data;
FILE *fp;
byte *fwBuf; /* signed firmware held in memory, streamed by the callback */
int fwLen;
int fwOffset;
int headerSent;
} FwpushCBdata;

/* Exposed functions */
Expand Down
14 changes: 9 additions & 5 deletions examples/mqttclient/mqttclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,15 @@ static int mqtt_property_cb(MqttClient *client, MqttProp *head, void *ctx)
/* Store client ID in global */
mqttCtx->client_id = &gClientId[0];

/* Store assigned client ID from CONNACK*/
XSTRNCPY((char*)mqttCtx->client_id, prop->data_str.str,
MAX_CLIENT_ID_LEN - 1);
/* should use strlcpy() semantics, but non-portable */
((char*)mqttCtx->client_id)[MAX_CLIENT_ID_LEN - 1] = '\0';
/* copy bounded by decoded len; data_str.str is not NUL-terminated */
{
word16 idLen = prop->data_str.len;
if (idLen >= MAX_CLIENT_ID_LEN) {
idLen = MAX_CLIENT_ID_LEN - 1;
}
XMEMCPY((char*)mqttCtx->client_id, prop->data_str.str, idLen);
((char*)mqttCtx->client_id)[idLen] = '\0';
}
break;

case MQTT_PROP_SUBSCRIPTION_ID_AVAIL:
Expand Down
14 changes: 9 additions & 5 deletions examples/nbclient/nbclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,15 @@ static int mqtt_property_cb(MqttClient *client, MqttProp *head, void *ctx)
/* Store client ID in global */
mqttCtx->client_id = &gClientId[0];

/* Store assigned client ID from CONNACK*/
XSTRNCPY((char*)mqttCtx->client_id, prop->data_str.str,
MAX_CLIENT_ID_LEN - 1);
/* should use strlcpy() semantics, but non-portable */
((char*)mqttCtx->client_id)[MAX_CLIENT_ID_LEN - 1] = '\0';
/* copy bounded by decoded len; data_str.str is not NUL-terminated */
{
word16 idLen = prop->data_str.len;
if (idLen >= MAX_CLIENT_ID_LEN) {
idLen = MAX_CLIENT_ID_LEN - 1;
}
XMEMCPY((char*)mqttCtx->client_id, prop->data_str.str, idLen);
((char*)mqttCtx->client_id)[idLen] = '\0';
}
break;

case MQTT_PROP_SUBSCRIPTION_ID_AVAIL:
Expand Down
14 changes: 9 additions & 5 deletions examples/pub-sub/mqtt-pub.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,15 @@ static int mqtt_property_cb(MqttClient *client, MqttProp *head, void *ctx)
/* Store client ID in global */
mqttCtx->client_id = &gClientId[0];

/* Store assigned client ID from CONNACK*/
XSTRNCPY((char*)mqttCtx->client_id, prop->data_str.str,
MAX_CLIENT_ID_LEN - 1);
/* should use strlcpy() semantics, but non-portable */
((char*)mqttCtx->client_id)[MAX_CLIENT_ID_LEN - 1] = '\0';
/* copy bounded by decoded len; data_str.str is not NUL-terminated */
{
word16 idLen = prop->data_str.len;
if (idLen >= MAX_CLIENT_ID_LEN) {
idLen = MAX_CLIENT_ID_LEN - 1;
}
XMEMCPY((char*)mqttCtx->client_id, prop->data_str.str, idLen);
((char*)mqttCtx->client_id)[idLen] = '\0';
}
break;

case MQTT_PROP_SUBSCRIPTION_ID_AVAIL:
Expand Down
14 changes: 9 additions & 5 deletions examples/pub-sub/mqtt-sub.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,15 @@ static int mqtt_property_cb(MqttClient *client, MqttProp *head, void *ctx)
/* Store client ID in global */
mqttCtx->client_id = &gClientId[0];

/* Store assigned client ID from CONNACK*/
XSTRNCPY((char*)mqttCtx->client_id, prop->data_str.str,
MAX_CLIENT_ID_LEN - 1);
/* should use strlcpy() semantics, but non-portable */
((char*)mqttCtx->client_id)[MAX_CLIENT_ID_LEN - 1] = '\0';
/* copy bounded by decoded len; data_str.str is not NUL-terminated */
{
word16 idLen = prop->data_str.len;
if (idLen >= MAX_CLIENT_ID_LEN) {
idLen = MAX_CLIENT_ID_LEN - 1;
}
XMEMCPY((char*)mqttCtx->client_id, prop->data_str.str, idLen);
((char*)mqttCtx->client_id)[idLen] = '\0';
}
break;

case MQTT_PROP_SUBSCRIPTION_ID_AVAIL:
Expand Down
Loading
Loading