Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ccce7eb
F-3825 F-4050 F-4051 F-4052 F-4059 - Harden v5 unsubscribe reject and…
aidangarske Jun 11, 2026
60d20f6
F-4244 F-4307 - Defer WebSocket close during publish fan-out and snap…
aidangarske Jun 11, 2026
57cfd36
F-4246 F-4247 - Reject v5 empty topic without alias and zero subscrip…
aidangarske Jun 11, 2026
1ef1d06
F-4245 F-4249 - Reject overlong static topics and clamp v5 will delay…
aidangarske Jun 11, 2026
2581a2c
F-4304 F-4654 F-4655 F-4722 F-4723 F-4727 F-4729 F-4776 F-4933 - Sani…
aidangarske Jun 11, 2026
d46da08
F-4305 F-4652 - Validate broker CONNECT credentials before any sessio…
aidangarske Jun 11, 2026
b455240
F-4308 F-4653 - Reject v5 zero topic alias and cap dynamic retained-m…
aidangarske Jun 11, 2026
5b97a8d
F-4529 - Add MqttClient_Subscribe broker-rejection regression test
aidangarske Jun 11, 2026
337f88d
F-4657 F-4658 - Validate v5 response topic and cap per-message proper…
aidangarske Jun 11, 2026
2c5ce32
F-4656 - Cap per-client broker subscriptions to prevent table exhaustion
aidangarske Jun 11, 2026
d9e79ce
F-4928 F-4929 F-4991 - Enforce TLS peer verification in example verif…
aidangarske Jun 11, 2026
087d9f0
F-5766 F-5767 F-5768 F-5769 F-5861 - Sanitize broker-controlled strin…
aidangarske Jun 11, 2026
c829dbc
F-4724 F-4772 - Fix firmware client length-overflow and topic-gate by…
aidangarske Jun 11, 2026
154bfae
F-5148 - Prevent broker client double-free on re-entrant takeover close
aidangarske Jun 11, 2026
be003af
F-4773 F-4992 F-5116 F-5143 F-5771 - Fix WebSocket fan-out UAF, TLS v…
aidangarske Jun 12, 2026
61870fb
F-4726 F-5115 - Enforce WebSocket origin allowlist and TLS-only liste…
aidangarske Jun 12, 2026
dc8ab1e
F-4994 F-4996 F-5149 - Clamp publish payload copy, reject duplicate v…
aidangarske Jun 12, 2026
356fd47
F-4997 F-5862 F-5863 F-5865 - Broker disconnect-with-will, pending-wi…
aidangarske Jun 12, 2026
0154f26
F-4777 F-4932 - Reject client PUBLISH subscription id and avoid false…
aidangarske Jun 12, 2026
dcbc2c0
F-4993 F-5512 - Add broker pre-CONNECT idle timeout and scrub WebSock…
aidangarske Jun 12, 2026
ab130c2
Address skoll review: bound UNSUBACK reason codes, reject oversized b…
aidangarske Jun 12, 2026
0fb17bc
Address skoll review: guard v5-only test registrations for non-v5 builds
aidangarske Jun 12, 2026
6bec2fb
Clarify MqttClient_Auth rx_buf scrub ordering (skoll FP: props consum…
aidangarske Jun 12, 2026
41dabde
Address skoll review: free v5 DISCONNECT props, floor per-client sub …
aidangarske Jun 12, 2026
bd8104d
Address skoll review: map UNSUBSCRIBE_REJECTED string and add client …
aidangarske Jun 12, 2026
7e14290
Address skoll review: cancel deferred retained delete on re-store and…
aidangarske Jun 12, 2026
abb3dcc
Add localhost SAN to broker test certs so WebSocket TLS hostname veri…
aidangarske Jun 12, 2026
bf581a1
Enforce example TLS peer verification only when a CA is configured
aidangarske Jun 12, 2026
9447505
Harden publish encode clamp, firmware length prints, and broker parti…
aidangarske Jun 12, 2026
3004ba9
F-4927 - Enforce curl TLS hostname verification instead of bypassing …
aidangarske Jun 12, 2026
c138692
Defer nested retained-delivery reap to outermost depth to avoid use-a…
aidangarske Jun 12, 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
53 changes: 42 additions & 11 deletions examples/aws/awsiot.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "awsiot.h"
#include "examples/mqttexample.h"
#include "examples/mqttnet.h"
#include "examples/mqtt_log.h"
#include <wolfmqtt/version.h>

/* Locals */
Expand Down Expand Up @@ -291,11 +292,18 @@ static int mqtt_aws_tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
PRINTF(" Rejecting cert: verification must succeed under"
" WOLFSSL_NO_ASN_STRICT");
return 0;
#elif defined(WOLFMQTT_ALLOW_INSECURE_TLS)
/* Development/testing override only: strict ASN parsing drops
* Starfield Services Root CA G2 (serialNumber=0), so the chain can
* legitimately fail here. Accept anyway to keep the demo running.
* MUST NOT be defined in production - it disables authentication. */
PRINTF(" Allowing cert anyways (WOLFMQTT_ALLOW_INSECURE_TLS)");
#else
/* Strict ASN parsing drops Starfield Services Root CA G2
* (serialNumber=0), so chain verification can legitimately
* fail here. Keep the demo running. */
PRINTF(" Allowing cert anyways");
/* Reject on any verification error by default. To run the AWS IoT
* demo against the live endpoint, build with WOLFSSL_NO_ASN_STRICT
* (loads the full trust bundle) or supply a trusted chain. */
PRINTF(" Rejecting cert: verification failed");
return 0;
#endif
}

Expand Down Expand Up @@ -352,6 +360,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
{
MQTTCtx* mqttCtx = (MQTTCtx*)client->ctx;
byte buf[PRINT_BUFFER_SIZE+1];
char safebuf[PRINT_BUFFER_SIZE+1];
word32 len;

(void)mqttCtx;
Expand All @@ -367,7 +376,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,

/* Print incoming message */
PRINTF("MQTT Message: Topic %s, Qos %d, Len %u",
buf, msg->qos, msg->total_len);
mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf), msg->qos, msg->total_len);
}

/* Print message payload */
Expand All @@ -378,7 +387,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
XMEMCPY(buf, msg->buffer, len);
buf[len] = '\0'; /* Make sure its null terminated */
PRINTF("Payload (%d - %d) printing %d bytes:" LINE_END "%s",
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, buf);
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf));

if (msg_done) {
PRINTF("MQTT Message: Done");
Expand All @@ -395,11 +404,30 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
/* The property callback is called after decoding a packet that contains at
least one property. The property list is deallocated after returning from
the callback. */
/* Copy a length-delimited, broker-controlled property string into dst and
* sanitize it for safe logging (CWE-117). */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove CWE reference

static const char* awsiot_log_prop(char* dst, word32 dstLen,
const char* src, word32 srcLen)
{
char tmp[PRINT_BUFFER_SIZE + 1];
word32 n = srcLen;
if (n > PRINT_BUFFER_SIZE) {
n = PRINT_BUFFER_SIZE;
}
if (src != NULL && n > 0) {
XMEMCPY(tmp, src, n);
}
tmp[n] = '\0';
return mqtt_log_sanitize(dst, dstLen, tmp);
}

static int mqtt_property_cb(MqttClient *client, MqttProp *head, void *ctx)
{
MqttProp *prop = head;
int rc = 0;
MQTTCtx* mqttCtx;
char safebuf[PRINT_BUFFER_SIZE + 1];
char safebuf2[PRINT_BUFFER_SIZE + 1];

if ((client == NULL) || (client->ctx == NULL)) {
return MQTT_CODE_ERROR_BAD_ARG;
Expand Down Expand Up @@ -447,14 +475,17 @@ static int mqtt_property_cb(MqttClient *client, MqttProp *head, void *ctx)
break;

case MQTT_PROP_REASON_STR:
PRINTF("Reason String: %.*s",
prop->data_str.len, prop->data_str.str);
PRINTF("Reason String: %s",
awsiot_log_prop(safebuf, (word32)sizeof(safebuf),
prop->data_str.str, prop->data_str.len));
break;

case MQTT_PROP_USER_PROP:
PRINTF("User property: key=\"%.*s\", value=\"%.*s\"",
prop->data_str.len, prop->data_str.str,
prop->data_str2.len, prop->data_str2.str);
PRINTF("User property: key=\"%s\", value=\"%s\"",
awsiot_log_prop(safebuf, (word32)sizeof(safebuf),
prop->data_str.str, prop->data_str.len),
awsiot_log_prop(safebuf2, (word32)sizeof(safebuf2),
prop->data_str2.str, prop->data_str2.len));
break;

case MQTT_PROP_ASSIGNED_CLIENT_ID:
Expand Down
6 changes: 4 additions & 2 deletions examples/azure/azureiothub.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#include "azureiothub.h"
#include "examples/mqttexample.h"
#include "examples/mqttnet.h"
#include "examples/mqtt_log.h"

/* Locals */
static int mStopRead = 0;
Expand Down Expand Up @@ -134,6 +135,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
{
MQTTCtx* mqttCtx = (MQTTCtx*)client->ctx;
byte buf[PRINT_BUFFER_SIZE+1];
char safebuf[PRINT_BUFFER_SIZE+1];
word32 len;

(void)mqttCtx;
Expand All @@ -149,7 +151,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,

/* Print incoming message */
PRINTF("MQTT Message: Topic %s, Qos %d, Len %u",
buf, msg->qos, msg->total_len);
mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf), msg->qos, msg->total_len);
}

/* Print message payload */
Expand All @@ -160,7 +162,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
XMEMCPY(buf, msg->buffer, len);
buf[len] = '\0'; /* Make sure its null terminated */
PRINTF("Payload (%d - %d) printing %d bytes:" LINE_END "%s",
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, buf);
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf));

if (msg_done) {
PRINTF("MQTT Message: Done");
Expand Down
36 changes: 28 additions & 8 deletions examples/firmware/fwclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,30 @@ static int fw_message_process(MQTTCtx *mqttCtx, byte* buffer, word32 len)
#ifdef ENABLE_FIRMWARE_SIG
ecc_key eccKey;
#endif
word32 check_len = sizeof(FirmwareHeader) + header->sigLen +
header->pubKeyLen + header->fwLen;
word32 remaining;

/* Verify entire message was received */
if (len != check_len) {
PRINTF("Message header vs. actual size mismatch! %d != %d",
len, check_len);
/* Validate sequentially; a summed length check overflows word32 for
* attacker-chosen fwLen (CWE-190 -> heap OOB on pubKeyBuf/fwBuf). */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove CWE reference

if (len < sizeof(FirmwareHeader)) {
PRINTF("Message smaller than firmware header! %u", (unsigned int)len);
return EXIT_FAILURE;
}
remaining = len - sizeof(FirmwareHeader);
if (header->sigLen > remaining) {
PRINTF("Firmware sigLen exceeds message! %u",
(unsigned int)header->sigLen);
return EXIT_FAILURE;
}
remaining -= header->sigLen;
if (header->pubKeyLen > remaining) {
PRINTF("Firmware pubKeyLen exceeds message! %u",
(unsigned int)header->pubKeyLen);
return EXIT_FAILURE;
}
remaining -= header->pubKeyLen;
if (header->fwLen != remaining) {
PRINTF("Message header vs. actual size mismatch! %u != %u",
(unsigned int)header->fwLen, (unsigned int)remaining);
return EXIT_FAILURE;
}

Expand Down Expand Up @@ -172,10 +189,13 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
{
MQTTCtx* mqttCtx = (MQTTCtx*)client->ctx;

/* Verify this message is for the firmware topic */
/* Verify this message is for the firmware topic. Compare against the full

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too wordy for the example. Revert this comment to the original.

* expected length (not the wire-supplied topic_name_len) so a zero-length
* (v5 Topic Alias) or byte-prefix topic cannot pass the gate. */
if (msg_new &&
msg->topic_name_len == (word16)XSTRLEN(mqttCtx->topic_name) &&
XSTRNCMP(msg->topic_name, mqttCtx->topic_name,
msg->topic_name_len) == 0 &&
XSTRLEN(mqttCtx->topic_name)) == 0 &&
!mFwBuf)
{
/* Allocate buffer for entire message */
Expand Down
19 changes: 15 additions & 4 deletions examples/mqttexample.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,13 +632,24 @@ static int mqtt_tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
wolfSSL_ERR_error_string(store->error, buffer) : "none");
PRINTF(" Subject's domain name is %s", store->domain);

#ifdef WOLFMQTT_ALLOW_INSECURE_TLS
/* Development/testing override only: accept any certificate. MUST NOT be
* defined in production builds - it disables server authentication. */
if (store->error != 0) {
/* Allowing to continue */
/* Should check certificate and return 0 if not okay */
PRINTF(" Allowing cert anyways");
PRINTF(" Allowing cert anyways (WOLFMQTT_ALLOW_INSECURE_TLS)");
}

return 1;
#else
/* With no CA configured there is no trust anchor to validate against
* (getting-started/demo mode), so accept and warn. When a CA is provided
* the chain-validation result is enforced so a bad certificate
* (self-signed, expired, wrong host, untrusted CA) fails the handshake. */
if (mqttCtx != NULL && mqttCtx->ca_file == NULL) {
PRINTF(" Warning: no CA configured, skipping server authentication");
return 1;
}
return preverify;
#endif
}

/* Use this callback to setup TLS certificates and verify callbacks */
Expand Down
15 changes: 7 additions & 8 deletions examples/mqttnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -856,14 +856,13 @@ mqttcurl_connect(SocketContext* sock, const char* host, word16 port,
return MQTT_CODE_ERROR_CURL;
}

/* Only do server host verification when not running against
* localhost broker. */
if (XSTRCMP(host, "localhost") == 0) {
res = curl_easy_setopt(sock->curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
else {
res = curl_easy_setopt(sock->curl, CURLOPT_SSL_VERIFYHOST, 2L);
}
/* Enforce server hostname verification. The cert's CN/SAN must match
* the connect host (broker_test certs carry a localhost SAN). */
#ifdef WOLFMQTT_ALLOW_INSECURE_TLS
res = curl_easy_setopt(sock->curl, CURLOPT_SSL_VERIFYHOST, 0L);
#else
res = curl_easy_setopt(sock->curl, CURLOPT_SSL_VERIFYHOST, 2L);
#endif

if (res != CURLE_OK) {
PRINTF("error: curl_easy_setopt(SSL_VERIFYHOST) returned: %d",
Expand Down
19 changes: 13 additions & 6 deletions examples/mqttsimple/mqttsimple.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "wolfmqtt/mqtt_client.h"
#include "examples/mqttport.h"
#include "examples/mqtt_log.h"
#include "mqttsimple.h"

/* Requires BSD Style Socket */
Expand Down Expand Up @@ -84,6 +85,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
byte msg_new, byte msg_done)
{
byte buf[PRINT_BUFFER_SIZE+1];
char safebuf[PRINT_BUFFER_SIZE+1];
word32 len;

(void)client;
Expand All @@ -99,7 +101,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,

/* Print incoming message */
PRINTF("MQTT Message: Topic %s, Qos %d, Len %u",
buf, msg->qos, msg->total_len);
mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf), msg->qos, msg->total_len);
}

/* Print message payload */
Expand All @@ -110,7 +112,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
XMEMCPY(buf, msg->buffer, len);
buf[len] = '\0'; /* Make sure its null terminated */
PRINTF("Payload (%d - %d) printing %d bytes:" LINE_END "%s",
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, buf);
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf));

if (msg_done) {
PRINTF("MQTT Message: Done");
Expand Down Expand Up @@ -295,13 +297,18 @@ static int mqtt_tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
wolfSSL_ERR_error_string(store->error, buffer) : "none");
PRINTF(" Subject's domain name is %s", store->domain);

#ifdef WOLFMQTT_ALLOW_INSECURE_TLS
/* Development/testing override only: accept any certificate. MUST NOT be
* defined in production builds - it disables server authentication. */
if (store->error != 0) {
/* Allowing to continue */
/* Should check certificate and return 0 if not okay */
PRINTF(" Allowing cert anyways");
PRINTF(" Allowing cert anyways (WOLFMQTT_ALLOW_INSECURE_TLS)");
}

return 1;
#else
/* Propagate wolfSSL's chain-validation result so a bad certificate
* (self-signed, expired, wrong host, untrusted CA) fails the handshake. */
return preverify;
#endif
}

/* Use this callback to setup TLS certificates and verify callbacks */
Expand Down
6 changes: 4 additions & 2 deletions examples/multithread/multithread.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "multithread.h"
#include "examples/mqttnet.h"
#include "examples/mqtt_log.h"
#include "examples/mqttexample.h"

#include <stdint.h>
Expand Down Expand Up @@ -165,6 +166,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
byte msg_new, byte msg_done)
{
byte buf[PRINT_BUFFER_SIZE+1];
char safebuf[PRINT_BUFFER_SIZE+1];
word32 len;
MQTTCtx* mqttCtx = (MQTTCtx*)client->ctx;
(void)mqttCtx;
Expand All @@ -181,7 +183,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,

/* Print incoming message */
PRINTF("MQTT Message: Topic %s, Qos %d, Id %d, Len %u, %u, %u",
buf, msg->qos, msg->packet_id, msg->total_len, msg->buffer_len,
mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf), msg->qos, msg->packet_id, msg->total_len, msg->buffer_len,
msg->buffer_pos);
}

Expand All @@ -193,7 +195,7 @@ static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
XMEMCPY(buf, msg->buffer, len);
buf[len] = '\0'; /* Make sure its null terminated */
PRINTF("Payload (%d - %d) printing %d bytes:" LINE_END "%s",
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, buf);
msg->buffer_pos, msg->buffer_pos + msg->buffer_len, len, mqtt_log_sanitize(safebuf, (word32)sizeof(safebuf), (char*)buf));

if (msg_done) {
/* for test mode: count the number of messages received */
Expand Down
16 changes: 13 additions & 3 deletions examples/websocket/net_libwebsockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,13 @@ static int callback_mqtt(struct lws *wsi, enum lws_callback_reasons reason,
else if (reason == LWS_CALLBACK_CLIENT_CONNECTION_ERROR) {
net->status = -1;
}
else if (reason == LWS_CALLBACK_CLOSED) {
else if (reason == LWS_CALLBACK_CLOSED ||
reason == LWS_CALLBACK_CLIENT_CLOSED) {
net->status = 0;
/* libwebsockets frees the wsi after this callback returns; clear the
* dangling pointer so NetWebsocket_Disconnect's `if (net->wsi)` guard
* skips lws_close_reason() on freed memory (CWE-416). */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove CWE reference

net->wsi = NULL;
}
else if (reason == LWS_CALLBACK_CLIENT_RECEIVE) {
if (in && len > 0) {
Expand Down Expand Up @@ -185,8 +190,13 @@ int NetWebsocket_Connect(void *ctx, const char* host, word16 port,
/* Set SSL options for the connection if TLS is enabled */
if (mqttCtx && mqttCtx->use_tls) {
conn_info.ssl_connection = LCCSCF_USE_SSL;
conn_info.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
conn_info.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
/* Only relax verification when no CA was supplied (dev/self-signed).
* When the operator provides a CA via -A, perform full chain and
* hostname verification rather than silently disabling it. */
if (mqttCtx->ca_file == NULL) {
conn_info.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
conn_info.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
}
}
#endif /* ENABLE_MQTT_TLS */

Expand Down
Loading
Loading