Add sim-OTA and submodules

pull/11/head
Yosuke Shimizu 2026-03-13 10:16:53 +09:00
parent 57dd2b0846
commit 873aa83965
32 changed files with 10338 additions and 0 deletions

8
.gitignore vendored
View File

@ -63,4 +63,12 @@ contiki-nrf52/ota-server/mac.txt
cscope.out
tags
# simuletion files
sim-OTA/*bin
sim-OTA/*dd
sim-OTA/app/*bin
sim-OTA/test_app
sim-OTA/fwserver/fwserver
# vscode
.vscode

6
.gitmodules vendored
View File

@ -25,3 +25,9 @@
[submodule "freeRTOS-Freescale-K64F-scp/picotcp"]
path = freeRTOS-Freescale-K64F-scp/picotcp
url = https://github.com/tass-belgium/picotcp
[submodule "sim-OTA/wolfMQTT"]
path = sim-OTA/wolfMQTT
url = https://github.com/wolfSSL/wolfMQTT.git
[submodule "sim-OTA/wolfBoot"]
path = sim-OTA/wolfBoot
url = https://github.com/wolfSSL/wolfBoot.git

View File

@ -0,0 +1,30 @@
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
build-essential \
git \
autoconf \
automake \
libtool \
libssl-dev \
libgmp-dev \
libjson-c-dev \
pkg-config \
cmake \
ccache
WORKDIR /opt
# Clone IBM TPM2 Simulator
WORKDIR /opt
RUN git clone https://github.com/kgoldman/ibmswtpm2.git
# Build the TPM simulator
WORKDIR /opt/ibmswtpm2/src
RUN make -j$(nproc)
# Expose TPM ports
# 2321 = command port
# 2322 = platform port
EXPOSE 2321 2322

View File

@ -0,0 +1,16 @@
{
"name": "Ubuntu Dev Container",
"build": {
"dockerfile": "./Dockerfile"
},
"customizations": {
"vscode": {
"extensions": [
"ms-azuretools.vscode-docker",
"ms-vscode.cpptools",
"ms-python.python"
]
}
},
"remoteUser": "root"
}

208
sim-OTA/Makefile 100644
View File

@ -0,0 +1,208 @@
# Inherit our settings for wolfBoot, TARGET, ARCH, etc.
-include sim.config
# Make sure environment variables do not corrupt the binary output for MacOS users
LANG=
LC_COLLATE="C"
LC_CTYPE="C"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=
APPSRC:=./app
SEVSRC:=./fwserver
WOLFBOOT_ROOT:=./wolfBoot
WOLFSSL_ROOT:=./wolfBoot/lib/wolfssl
WOLFTPM_ROOT:=/usr/local/include/wolftpm/
WOLFMQTT_ROOT:=./wolfMQTT
DEBUG:=0
include $(WOLFBOOT_ROOT)/tools/config.mk
export WOLFBOOT_ROOT
ifneq ("$(wildcard $(WOLFBOOT_ROOT)/tools/keytools/keygen)","")
KEYGEN_TOOL:=$(WOLFBOOT_ROOT)/tools/keytools/keygen
else
ifneq ("$(wildcard $(WOLFBOOT_ROOT)/tools/keytools/keygen.exe)","")
KEYGEN_TOOL:=$(WOLFBOOT_ROOT)/tools/keytools/keygen.exe
else
KEYGEN_TOOL:=python3 $(WOLFBOOT_ROOT)/tools/keytools/keygen.py
endif
endif
ifneq ("$(wildcard $(WOLFBOOT_ROOT)/tools/keytools/sign)","")
SIGN_TOOL:=$(WOLFBOOT_ROOT)/tools/keytools/sign
else
ifneq ("$(wildcard $(WOLFBOOT_ROOT)/tools/keytools/sign.exe)","")
SIGN_TOOL:=$(WOLFBOOT_ROOT)/tools/keytools/sign.exe
else
SIGN_TOOL:=python3 $(WOLFBOOT_ROOT)/tools/keytools/sign.py
endif
endif
# Signing and test variables (used by test-sim-internal-flash-with-update)
PRIVATE_KEY:=$(WOLFBOOT_ROOT)/wolfboot_signing_private_key.der
SIGN_ENV=IMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) \
WOLFBOOT_PARTITION_SIZE=$(WOLFBOOT_PARTITION_SIZE) \
WOLFBOOT_SECTOR_SIZE=$(WOLFBOOT_SECTOR_SIZE) \
NVM_FLASH_WRITEONCE=$(NVM_FLASH_WRITEONCE) \
ML_DSA_LEVEL=$(ML_DSA_LEVEL) \
IMAGE_SIGNATURE_SIZE=$(IMAGE_SIGNATURE_SIZE) \
LMS_LEVELS=$(LMS_LEVELS) \
LMS_HEIGHT=$(LMS_HEIGHT) \
LMS_WINTERNITZ=$(LMS_WINTERNITZ) \
XMSS_PARAMS=$(XMSS_PARAMS)
SIGN_OPTIONS?=--ecc256
TEST_UPDATE_VERSION?=2
OTA_UPDATE_VERSION?=10
BINASSEMBLE:=$(WOLFBOOT_ROOT)/tools/bin-assemble/bin-assemble
DELTA_UPDATE_OPTIONS?=
ifeq ($(NVM_FLASH_WRITEONCE),1)
INVERSION=| tr "\000" "\377"
else
INVERSION=
endif
CFLAGS:=-Wall -Wstack-usage=1024 -ffreestanding -Wno-unused -DPLATFORM_$(TARGET) \
-I$(WOLFBOOT_ROOT)/include -I$(WOLFBOOT_ROOT) -I$(WOLFSSL_ROOT) \
-I$(WOLFTPM_ROOT) -I$(APPSRC) -I$(WOLFMQTT_ROOT) -DWOLFBOOT_MEASURED_PCR_A \
-DSIM_OTA=1
CFLAGS+=-DWOLFBOOT_HASH_SHA256
# fwserver CFLAGS
CFLAGS_SEV:=-g -ggdb -Wall -Wstack-usage=1024 -ffreestanding -Wno-unused \
-I$(WOLFSSL_ROOT) -I$(SEVSRC) -I$(WOLFMQTT_ROOT)
APP_OBJS:= \
$(APPSRC)/app_$(TARGET).o \
$(APPSRC)/tpm_handler.o \
$(APPSRC)/fwclient.o \
$(APPSRC)/mqttexample.o \
$(APPSRC)/mqttnet.o \
$(WOLFBOOT_ROOT)/hal/$(TARGET).o \
$(WOLFBOOT_ROOT)/src/libwolfboot.o
# Add objects for wolfMQTT support
APP_OBJS+= \
$(WOLFMQTT_ROOT)/src/libwolfmqtt_la-mqtt_client.o \
$(WOLFMQTT_ROOT)/src/libwolfmqtt_la-mqtt_packet.o \
$(WOLFMQTT_ROOT)/src/libwolfmqtt_la-mqtt_socket.o
# Add objects for fwserver
SEV_OBJS+= \
$(SEVSRC)/fwpush.o \
$(SEVSRC)/mqttexample.o \
$(SEVSRC)/mqttnet.o \
$(WOLFMQTT_ROOT)/src/libwolfmqtt_la-mqtt_client.o \
$(WOLFMQTT_ROOT)/src/libwolfmqtt_la-mqtt_packet.o \
$(WOLFMQTT_ROOT)/src/libwolfmqtt_la-mqtt_socket.o
# Link libwolfssl (full SSL + wolfCrypt) and macOS frameworks when needed
WOLFSSL_LDFLAGS := -L$(WOLFSSL_ROOT)/src/.libs -lwolfssl
ifeq ($(shell uname -s),Darwin)
WOLFSSL_LDFLAGS += -Wl,-rpath,$(WOLFSSL_ROOT)/src/.libs
WOLFSSL_LDFLAGS += -framework CoreFoundation -framework Security
else
WOLFSSL_LDFLAGS += -lm
endif
# Link libwolfTPM (full TPM support) and macOS frameworks when needed
WOLFTPM_LDFLAGS := -L/usr/local/lib -lwolftpm
ifeq ($(shell uname -s),Darwin)
WOLFTPM_LDFLAGS += -Wl,-rpath,/usr/local/lib
WOLFTPM_LDFLAGS += -framework CoreFoundation -framework Security
else
WOLFTPM_LDFLAGS += -lm
endif
# Inherit cross-compiler and similar settings from wolfBoot
include $(WOLFBOOT_ROOT)/arch.mk
# arch.mk sets OBJCOPY only when USE_GCC=1 (from wolfBoot options.mk); sim-OTA does not include it
OBJCOPY ?= objcopy
ifeq ($(DEBUG),0)
CFLAGS+=-Os -DNDEBUG -flto
else
CFLAGS+=-g -ggdb3
endif
vpath %.c $(dir $(WOLFSSL_ROOT)/src)
vpath %.c $(dir $(WOLFSSL_ROOT)/wolfcrypt/src)
vpath %.c $(dir $(WOLFBOOT_ROOT))/lib/wolfTPM/wolftpm
LDFLAGS:=$(CFLAGS)
LDFLAGS_SEV:=$(CFLAGS_SEV)
all: $(WOLFBOOT_ROOT)/wolfboot.elf app/image.elf fwserver/fwserver
$(WOLFBOOT_ROOT)/wolfboot.elf: wolfboot_target
cd $(WOLFBOOT_ROOT) && $(MAKE) WOLFBOOT_ROOT=$$(pwd) wolfboot.elf
app/image.bin: wolfboot_target app/image.elf
$(OBJCOPY) -O binary app/image.elf $@
$(SIZE) app/image.elf
app/image.elf: wolfboot_target $(APP_OBJS)
@echo "\t[LD] $@"
$(Q)$(LD) $(LDFLAGS) $(APP_OBJS) $(WOLFSSL_LDFLAGS) $(WOLFTPM_LDFLAGS) -o $@
@echo
fwserver/fwserver: wolfboot_target $(SEV_OBJS)
@echo "\t[LD] $@"
$(Q)$(LD) $(LDFLAGS_SEV) $(SEV_OBJS) $(WOLFSSL_LDFLAGS) -o $@
@echo
wolfboot_target: FORCE
cp -f sim.config $(WOLFBOOT_ROOT)/.config
cp ./hal-sim/sim.c $(WOLFBOOT_ROOT)/hal/sim.c
make -C $(WOLFBOOT_ROOT) include/target.h
wolfboot.bin: wolfBoot/wolfboot.elf
@echo "\t[BIN] $@"
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@
@echo
%.o:%.c
@echo "\t[CC-$(ARCH)] $@"
$(Q)$(CC) $(CFLAGS) -c -o $@ $^
%.o:%.S
@echo "\t[AS-$(ARCH)] $@"
$(Q)$(CC) $(CFLAGS) -c -o $@ $^
test-sim-internal-flash-with-update: wolfboot.bin app/image.elf FORCE
$(Q)cp app/image.elf app/image.bak.elf
$(Q)dd if=/dev/urandom bs=1k count=16 >> app/image.elf
# Create version 1 of the application (base image)
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) app/image.elf $(PRIVATE_KEY) 1
$(Q)cp app/image.bak.elf app/image.elf
$(Q)dd if=/dev/urandom bs=1k count=16 >> app/image.elf
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_SECTOR_SIZE))) count=1 2>/dev/null $(INVERSION) > erased_sec.dd
# Sign the update image (version 2 by default)
# This command handles both standard and delta update modes based on DELTA_UPDATE_OPTIONS
# empty DELTA_UPDATE_OPTIONS (Without --delta): Produces image_v2_signed.bin
# DELTA_UPDATE_OPTIONS="--delta app/image_v1_signed.bin": Produces image_v2_signed_diff.bin
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(DELTA_UPDATE_OPTIONS) \
app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
# Sign the update image for OTA example
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(DELTA_UPDATE_OPTIONS) \
app/image.elf $(PRIVATE_KEY) $(OTA_UPDATE_VERSION)
$(Q)$(BINASSEMBLE) internal_flash.dd \
0 wolfboot.bin \
$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) app/image_v1_signed.bin \
$$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS)-$(ARCH_FLASH_OFFSET))) app/image_v$(TEST_UPDATE_VERSION)_signed.bin \
$$(($(WOLFBOOT_PARTITION_SWAP_ADDRESS)-$(ARCH_FLASH_OFFSET))) erased_sec.dd
clean:
make -C $(WOLFBOOT_ROOT) clean
@rm -f *.bin *.elf $(OBJS) wolfboot.map *.bin *.hex src/*.o tags *.map
@rm -f app/*.elf app/*.bin app/image.map app/*.o fwserver/*.o fwserver/fwserver
FORCE:
.PHONY: FORCE clean all

114
sim-OTA/ReadMe.md 100644
View File

@ -0,0 +1,114 @@
# OTA Demonstrator with wolfBoot, wolfTPM and wolfMQTT
## Overview
This demonstrator shows a general over-the-air firmware update workflow secured by wolfSSL products and TPM.\
It uses the following products:
- wolfBoot: Secure boot loader. ([Home page](https://www.wolfssl.com/products/wolfboot/))
- wolfTPM: TPM library. ([Home page](https://www.wolfssl.com/products/wolftpm/))
- wolfMQTT: MQTT library. ([Home page](https://www.wolfssl.com/products/wolfmqtt/))
- wolfSSL: Secure TLS/SSL library. ([Home page](https://www.wolfssl.com/products/wolfssl/))
- wolfCrypt: Cryptography engine. ([Home page](https://www.wolfssl.com/products/wolfcrypt-2/))
## Prerequisites
This demonstrator uses a software TPM to simulate TPM functionality.\
For details, see [SWTPM simulator setup](https://www.wolfssl.com/documentation/manuals/wolftpm/chapter02.html#swtpm-simulator-setup).\
Alternatively, you can use the [.devcontainer](https://code.visualstudio.com/docs/devcontainers/containers), which builds the software TPM from the official repository: [ibmswtpm2](https://github.com/kgoldman/ibmswtpm2.git).
## How to Build
First, initialize the git submodules.
```
git submodule update --init --recursive
```
**You need to run swtpm before initializing the TPM tools so the hash of the public key can be stored in the NV index.**
Then build each module as follows.
1. Build the TPM tools and initialize swtpm
```
cd ./wolfBoot
make tpmtools
./tools/tpm/rot -write
cd ./tools/bin-assemble
make
```
2. Build wolfSSL
```
cd ./wolfBoot/lib/wolfssl/
./autogen.sh
./configure --disable-shared --enable-wolftpm
make -j
make install
```
3. Build wolfTPM
```
cd ./wolfBoot/lib/wolfTPM/
./autogen.sh
./configure --disable-shared --enable-swtpm
make -j
make install
```
4. Build wolfMQTT
```
cd ./wolfMQTT
./autogen.sh
./configure --disable-shared
make -j
```
5. Build wolfBoot and the application
```
make test-sim-internal-flash-with-update V=1
```
6. Build the OTA server app
```
make fwserver/fwserver
```
## How to Run
### OTA
1. Run swtpm. If you are using a devcontainer, run:
```
/opt/ibmswtpm2/src/tpm_server
```
2. From another terminal, run:
```
./wolfBoot/wolfboot.elf get_version
```
This command lets wolfBoot start the application and prints the firmware version (default: 1).
3. Trigger the OTA flow with the `ota` command:
```
./wolfBoot/wolfboot.elf ota
```
The application booted by wolfBoot starts the OTA flow. Once OTA starts, the application connects to the MQTT broker and subscribes to the firmware data topic, then waits for messages.
4. Open another terminal and run:
```
./fwserver/fwserver -t
```
This tool emulates the OTA server and sends the new firmware to the MQTT broker.
5. The application receives the MQTT message and verifies it. Finally, the firmware is stored in internal flash and the update is triggered by wolfBoot.
6. Run:
```
./wolfBoot/wolfboot.elf get_version
```
The application shows the new firmware version (default: 10).
### Attestation
You can try part of the remote attestation functionality.\
wolfBoot calculates its own hash and extends it to PCR 16. (Measured Boot)
Then the application requests a quote from swtpm with this command:
```
./wolfBoot/wolfboot.elf attestation
```
### Others
This demo app supports additional test commands.\
You can find them in `./app/app_sim.c`.
## Sequence Diagram
![OTA sequence](./sim-OTA.svg)
## Limitations on Mac environment
We use `objcopy` to prepare the file that emulates internal flash.\
However, macOS does not include `objcopy` by default.\
Please install it and set `OBJCOPY=` when you build the app and wolfBoot.\
Also, if wolfBoot runs in a native macOS environment, a temporary file named `test_app` is generated on each run.\
Please delete it after each run.

View File

@ -0,0 +1,212 @@
/* app_sim.c
*
* Test bare-metal boot-led-on application
*
* Copyright (C) 2025 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "target.h"
#include "wolfboot/wolfboot.h"
#ifdef WOLFBOOT_SELF_HEADER
#include "image.h"
#endif
#include "tpm_handler.h"
#include "fwclient.h"
#ifdef DUALBANK_SWAP
uint32_t hal_sim_get_dualbank_state(void);
#endif
#ifdef TARGET_sim
/* Matches all keys:
* - chacha (32 + 12)
* - aes128 (16 + 16)
* - aes256 (32 + 16)
*/
/* Longest key possible: AES256 (32 key + 16 IV = 48) */
char enc_key[] = "0123456789abcdef0123456789abcdef"
"0123456789abcdef";
#ifdef TEST_DELTA_DATA
static volatile char __attribute__((used)) garbage[TEST_DELTA_DATA] = {0x01, 0x02, 0x03, 0x04 };
#endif
void hal_init(void);
int do_cmd(const char *cmd)
{
if (strcmp(cmd, "powerfail") == 0) {
return 1;
}
/* forces a bad write of the boot partition to trigger and test the
* emergency fallback feature */
if (strcmp(cmd, "emergency") == 0) {
return 1;
}
if (strcmp(cmd, "get_version") == 0) {
printf("%d\n", wolfBoot_current_firmware_version());
wolfBoot_success();
return 0;
}
if (strcmp(cmd, "get_state") == 0) {
uint8_t st = 0;
wolfBoot_get_partition_state(PART_UPDATE, &st);
printf("%02x\n", st);
return 0;
}
if (strcmp(cmd, "success") == 0) {
wolfBoot_success();
return 0;
}
#ifdef DUALBANK_SWAP
if (strcmp(cmd, "get_swap_state") == 0) {
printf("%u\n", hal_sim_get_dualbank_state());
return 0;
}
#endif
if (strcmp(cmd, "update_trigger") == 0) {
#if EXT_ENCRYPTED
wolfBoot_set_encrypt_key((uint8_t *)enc_key,(uint8_t *)(enc_key + 32));
#endif
wolfBoot_update_trigger();
return 0;
}
if (strcmp(cmd, "reset") == 0) {
exit(0);
}
if (strncmp(cmd, "get_tlv",7) == 0) {
/* boot partition and skip the image header offset (8 bytes) */
uint8_t* imageHdr = (uint8_t*)WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_OFFSET;
uint8_t* ptr = NULL;
uint16_t tlv = 0x34; /* default */
int size;
int i;
const char* tlvStr = strstr(cmd, "get_tlv=");
if (tlvStr) {
tlvStr += strlen("get_tlv=");
tlv = (uint16_t)atoi(tlvStr);
}
size = wolfBoot_find_header(imageHdr, tlv, &ptr);
if (size > 0 && ptr != NULL) {
/* From here, the value 0xAABBCCDD is at ptr */
printf("TLV 0x%x: found (size %d):\n", tlv, size);
for (i=0; i<size; i++) {
printf("%02X", ptr[i]);
}
printf("\n");
return 0;
} else {
printf("TLV 0x%x: not found!\r\n", tlv);
}
}
#ifdef WOLFBOOT_SELF_HEADER
if (strcmp(cmd, "verify_self") == 0) {
struct wolfBoot_image img;
int ret;
printf("=== Self-Header Verification Test ===\n");
/* Open bootloader image using persisted self-header */
ret = wolfBoot_open_self(&img);
if (ret != 0) {
printf("FAIL: wolfBoot_open_self returned %d\n", ret);
return -1;
}
printf("open_self: OK (fw_size=%u, part=%d)\n", (unsigned)img.fw_size,
img.part);
/* Verify integrity (hash check) */
ret = wolfBoot_verify_integrity(&img);
if (ret != 0) {
printf("FAIL: wolfBoot_verify_integrity returned %d\n", ret);
return -1;
}
printf("verify_integrity: OK\n");
/* Verify authenticity (signature check) */
ret = wolfBoot_verify_authenticity(&img);
if (ret != 0) {
printf("FAIL: wolfBoot_verify_authenticity returned %d\n", ret);
return -1;
}
printf("verify_authenticity: OK\n");
printf("=== Self-header verification PASSED ===\n");
return 0;
}
#endif
if (strcmp(cmd, "attestation") == 0) {
int ret=0;
/* Call tpm handler for attestation */
ret = tpm_handler();
if (ret != 0){
printf("attestation command is failed.\n");
return -1;
}
return 0;
}
if (strcmp(cmd, "ota") == 0) {
int ret = 0;
/* Call ota handoer */
ret = fwclient_main();
if (ret != 0) {
printf("ota command is failed. \n");
return -1;
} else {
printf("Firmware Download is finished. Trigger the Update.\n");
wolfBoot_update_trigger();
return 0;
}
}
/* wrong command */
printf("wrong command\n");
return -1;
}
int main(int argc, char *argv[]) {
int i;
int ret;
printf("Simulator app is running...\n");
hal_init();
for (i = 1; i < argc; ++i) {
ret = do_cmd(argv[i]);
if (ret < 0)
return -1;
i+= ret;
}
return 0;
}
#endif /** TARGET_sim **/

View File

@ -0,0 +1,49 @@
/* firmware.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_FIRMWARE_H
#define WOLFMQTT_FIRMWARE_H
#ifdef __cplusplus
extern "C" {
#endif
#define FIRMWARE_TOPIC_NAME "wolfMQTT/example/firmware"
#define FIRMWARE_MAX_BUFFER 2048
#define FIRMWARE_MAX_PACKET (int)(FIRMWARE_MAX_BUFFER + sizeof(MqttPacket) + XSTRLEN(FIRMWARE_TOPIC_NAME) + MQTT_DATA_LEN_SIZE)
#define FIRMWARE_MQTT_QOS MQTT_QOS_2
#define FIRMWARE_HASH_TYPE WC_HASH_TYPE_SHA256
#define FIRMWARE_SIG_TYPE WC_SIGNATURE_TYPE_ECC
/* Signature Len, Public Key Len, Firmware Len, Signature, Public Key, Data */
typedef struct _FirmwareHeader {
word16 sigLen;
word16 pubKeyLen;
word32 fwLen;
} WOLFMQTT_PACK FirmwareHeader;
#ifdef __cplusplus
}
#endif
#endif /* WOLFMQTT_FIRMWARE_H */

View File

@ -0,0 +1,594 @@
/* fwclient.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Include the autoconf generated config.h */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "wolfmqtt/mqtt_client.h"
#include "target.h"
/* This example only works with ENABLE_MQTT_TLS (wolfSSL library). */
#if defined(ENABLE_MQTT_TLS)
#if !defined(WOLFSSL_USER_SETTINGS) && !defined(USE_WINDOWS_API)
#include <wolfssl/options.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/version.h>
/* Signature wrapper required; added in wolfSSL after 3.7.1.
* app and libwolfssl use wolfssl-setting/user_settings.h (no NO_SIG_WRAPPER). */
#if defined(LIBWOLFSSL_VERSION_HEX) && LIBWOLFSSL_VERSION_HEX > 0x03007001 \
&& defined(HAVE_ECC)
#undef ENABLE_FIRMWARE_SIG
#define ENABLE_FIRMWARE_SIG
#endif
#endif
#if defined(ENABLE_FIRMWARE_SIG)
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/signature.h>
#include <wolfssl/wolfcrypt/hash.h>
#endif
#include "fwclient.h"
#include "firmware.h"
#include "mqttexample.h"
#include "mqttnet.h"
/* Configuration */
#ifndef MAX_BUFFER_SIZE
#define MAX_BUFFER_SIZE FIRMWARE_MAX_PACKET
#endif
/* Locals */
static int mStopRead = 0;
static int mTestDone = 0;
static byte* mFwBuf;
static int fwfile_save(const char* filePath, byte* fileBuf, int fileLen)
{
#if !defined(NO_FILESYSTEM)
int ret = 0;
FILE* file = NULL;
/* Check arguments */
if (filePath == NULL || XSTRLEN(filePath) == 0 || fileLen == 0 ||
fileBuf == NULL) {
return EXIT_FAILURE;
}
/* Open file */
file = fopen(filePath, "wb");
if (file == NULL) {
PRINTF("File %s write error!", filePath);
ret = EXIT_FAILURE;
goto exit;
}
/* Save file */
ret = (int)fwrite(fileBuf, 1, fileLen, file);
if (ret != fileLen) {
PRINTF("Error reading file! %d", ret);
ret = EXIT_FAILURE;
goto exit;
}
PRINTF("Saved %d bytes to %s", fileLen, filePath);
exit:
if (file) {
fclose(file);
}
return ret;
#else
(void)filePath;
(void)fileBuf;
PRINTF("Firmware File Save: Len=%d (No Filesystem)", fileLen);
return fileLen;
#endif
}
static int fw_message_process(MQTTCtx *mqttCtx, byte* buffer, word32 len)
{
int rc = 0;
FirmwareHeader* header = (FirmwareHeader*)buffer;
byte *sigBuf, *pubKeyBuf, *fwBuf;
#ifdef ENABLE_FIRMWARE_SIG
ecc_key eccKey;
char cmd[200];
#endif
word32 check_len = sizeof(FirmwareHeader) + header->sigLen +
header->pubKeyLen + header->fwLen;
printf("Enter fw_message_process\n");
PRINTF("header sizes: sigLen=%u, pubKeyLen=%u, fwLen=%u",
header->sigLen, header->pubKeyLen, header->fwLen);
/* Verify entire message was received */
if (len != check_len) {
PRINTF("Message header vs. actual size mismatch! %d != %d",
len, check_len);
return EXIT_FAILURE;
}
/* Get pointers to structure elements */
sigBuf = (buffer + sizeof(FirmwareHeader));
pubKeyBuf = (buffer + sizeof(FirmwareHeader) + header->sigLen);
fwBuf = (buffer + sizeof(FirmwareHeader) + header->sigLen +
header->pubKeyLen);
#ifdef ENABLE_FIRMWARE_SIG
/* Import the public key */
wc_ecc_init(&eccKey);
rc = wc_ecc_import_x963(pubKeyBuf, header->pubKeyLen, &eccKey);
if (rc == 0) {
/* Perform signature verification using public key */
rc = wc_SignatureVerify(
FIRMWARE_HASH_TYPE, FIRMWARE_SIG_TYPE,
fwBuf, header->fwLen,
sigBuf, header->sigLen,
&eccKey, sizeof(eccKey));
PRINTF("Firmware Signature Verification: %s (%d)",
(rc == 0) ? "Pass" : "Fail", rc);
#else
(void)pubKeyBuf;
(void)sigBuf;
#endif
if (rc == 0) {
/* TODO: Process firmware image */
/* For example, save to disk using topic name */
fwfile_save(mqttCtx->pub_file, fwBuf, header->fwLen);
/* Call bin-assemble to create new internal flash with downloaded image */
rc = sprintf(cmd, "./wolfBoot/tools/bin-assemble/bin-assemble internal_flash.dd \
0 wolfboot.bin \
%lu app/image_v1_signed.bin \
%lu app/image_updated.bin \
%lu erased_sec.dd",
(WOLFBOOT_PARTITION_BOOT_ADDRESS - ARCH_FLASH_OFFSET),
(WOLFBOOT_PARTITION_UPDATE_ADDRESS - ARCH_FLASH_OFFSET),
(WOLFBOOT_PARTITION_SWAP_ADDRESS - ARCH_FLASH_OFFSET));
if (rc > 0) {
rc = system(cmd);
}
if (rc == 0) {
/* Exit the loop */
mStopRead = 1;
}
}
#ifdef ENABLE_FIRMWARE_SIG
}
else {
PRINTF("ECC public key import failed! %d", rc);
}
wc_ecc_free(&eccKey);
#endif
return rc;
}
static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
byte msg_new, byte msg_done)
{
MQTTCtx* mqttCtx = (MQTTCtx*)client->ctx;
/* Verify this message is for the firmware topic */
if (msg_new &&
XSTRNCMP(msg->topic_name, mqttCtx->topic_name,
msg->topic_name_len) == 0 &&
!mFwBuf)
{
/* Allocate buffer for entire message */
/* Note: On an embedded system this could just be a write to flash.
If writing to flash change FIRMWARE_MAX_BUFFER to match
block size */
mFwBuf = (byte*)WOLFMQTT_MALLOC(msg->total_len);
if (mFwBuf == NULL) {
return MQTT_CODE_ERROR_OUT_OF_BUFFER;
}
/* Print incoming message */
PRINTF("MQTT Firmware Message: Qos %d, Len %u",
msg->qos, msg->total_len);
}
if (mFwBuf) {
XMEMCPY(&mFwBuf[msg->buffer_pos], msg->buffer, msg->buffer_len);
/* Process message if done */
if (msg_done) {
fw_message_process(mqttCtx, mFwBuf, msg->total_len);
/* Free */
WOLFMQTT_FREE(mFwBuf);
mFwBuf = NULL;
/* for test mode stop client */
if (mqttCtx->test_mode) {
mTestDone = 1;
}
}
}
/* Return negative to terminate publish processing */
return MQTT_CODE_SUCCESS;
}
int fwclient_test(MQTTCtx *mqttCtx)
{
int rc = MQTT_CODE_SUCCESS, i;
switch(mqttCtx->stat) {
case WMQ_BEGIN:
{
PRINTF("MQTT Firmware Client: QoS %d, Use TLS %d", mqttCtx->qos, mqttCtx->use_tls);
}
FALL_THROUGH;
case WMQ_NET_INIT:
{
mqttCtx->stat = WMQ_NET_INIT;
/* Initialize Network */
rc = MqttClientNet_Init(&mqttCtx->net, mqttCtx);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Net Init: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto exit;
}
/* setup tx/rx buffers */
mqttCtx->tx_buf = (byte*)WOLFMQTT_MALLOC(MAX_BUFFER_SIZE);
mqttCtx->rx_buf = (byte*)WOLFMQTT_MALLOC(MAX_BUFFER_SIZE);
}
FALL_THROUGH;
case WMQ_INIT:
{
mqttCtx->stat = WMQ_INIT;
/* Initialize MqttClient structure */
rc = MqttClient_Init(&mqttCtx->client, &mqttCtx->net,
mqtt_message_cb,
mqttCtx->tx_buf, MAX_BUFFER_SIZE,
mqttCtx->rx_buf, MAX_BUFFER_SIZE,
mqttCtx->cmd_timeout_ms);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Init: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto exit;
}
mqttCtx->client.ctx = mqttCtx;
}
FALL_THROUGH;
case WMQ_TCP_CONN:
{
mqttCtx->stat = WMQ_TCP_CONN;
/* Connect to broker */
rc = MqttClient_NetConnect(&mqttCtx->client, mqttCtx->host,
mqttCtx->port, DEFAULT_CON_TIMEOUT_MS,
mqttCtx->use_tls, mqtt_tls_cb);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Socket Connect: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto exit;
}
/* Build connect packet */
XMEMSET(&mqttCtx->connect, 0, sizeof(MqttConnect));
mqttCtx->connect.keep_alive_sec = mqttCtx->keep_alive_sec;
mqttCtx->connect.clean_session = mqttCtx->clean_session;
mqttCtx->connect.client_id = mqttCtx->client_id;
if (mqttCtx->enable_lwt) {
/* Send client id in LWT payload */
mqttCtx->lwt_msg.qos = mqttCtx->qos;
mqttCtx->lwt_msg.retain = 0;
mqttCtx->lwt_msg.topic_name = FIRMWARE_TOPIC_NAME"lwttopic";
mqttCtx->lwt_msg.buffer = (byte*)mqttCtx->client_id;
mqttCtx->lwt_msg.total_len = (word16)XSTRLEN(mqttCtx->client_id);
}
/* Optional authentication */
mqttCtx->connect.username = mqttCtx->username;
mqttCtx->connect.password = mqttCtx->password;
}
FALL_THROUGH;
case WMQ_MQTT_CONN:
{
mqttCtx->stat = WMQ_MQTT_CONN;
/* Send Connect and wait for Connect Ack */
rc = MqttClient_Connect(&mqttCtx->client, &mqttCtx->connect);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Connect: Proto (%s), %s (%d)",
MqttClient_GetProtocolVersionString(&mqttCtx->client),
MqttClient_ReturnCodeToString(rc), rc);
/* Validate Connect Ack info */
PRINTF("MQTT Connect Ack: Return Code %u, Session Present %d",
mqttCtx->connect.ack.return_code,
(mqttCtx->connect.ack.flags & MQTT_CONNECT_ACK_FLAG_SESSION_PRESENT) ?
1 : 0
);
if (rc != MQTT_CODE_SUCCESS) {
goto disconn;
}
/* Build list of topics */
mqttCtx->topics[0].topic_filter = mqttCtx->topic_name;
mqttCtx->topics[0].qos = mqttCtx->qos;
/* Subscribe Topic */
XMEMSET(&mqttCtx->subscribe, 0, sizeof(MqttSubscribe));
mqttCtx->subscribe.packet_id = mqtt_get_packetid();
mqttCtx->subscribe.topic_count = 1;
mqttCtx->subscribe.topics = mqttCtx->topics;
}
FALL_THROUGH;
case WMQ_SUB:
{
mqttCtx->stat = WMQ_SUB;
rc = MqttClient_Subscribe(&mqttCtx->client, &mqttCtx->subscribe);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Subscribe: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto disconn;
}
for (i = 0; i < mqttCtx->subscribe.topic_count; i++) {
MqttTopic *topic = &mqttCtx->subscribe.topics[i];
PRINTF(" Topic %s, Qos %u, Return Code %u",
topic->topic_filter,
topic->qos,
topic->return_code);
}
/* Read Loop */
PRINTF("MQTT Waiting for message...");
}
FALL_THROUGH;
case WMQ_WAIT_MSG:
{
mqttCtx->stat = WMQ_WAIT_MSG;
do {
/* Try and read packet */
rc = MqttClient_WaitMessage(&mqttCtx->client,
mqttCtx->cmd_timeout_ms);
#ifdef WOLFMQTT_NONBLOCK
/* Track elapsed time with no activity and trigger timeout */
rc = mqtt_check_timeout(rc, &mqttCtx->start_sec,
mqttCtx->cmd_timeout_ms/1000);
#endif
/* check return code */
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
/* check for test mode */
if (mStopRead || mTestDone) {
rc = MQTT_CODE_SUCCESS;
mqttCtx->stat = WMQ_DISCONNECT;
PRINTF("MQTT Exiting...");
break;
}
if (rc == MQTT_CODE_ERROR_TIMEOUT) {
if (mqttCtx->test_mode) {
PRINTF("Timeout in test mode, exit early!");
mTestDone = 1;
}
/* Keep Alive */
PRINTF("Keep-alive timeout, sending ping");
rc = MqttClient_Ping_ex(&mqttCtx->client, &mqttCtx->ping);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
else if (rc != MQTT_CODE_SUCCESS) {
PRINTF("MQTT Ping Keep Alive Error: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
break;
}
}
else if (rc != MQTT_CODE_SUCCESS) {
/* There was an error */
PRINTF("MQTT Message Wait: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
break;
}
/* Exit if test mode */
if (mqttCtx->test_mode) {
break;
}
} while (1);
/* Check for error */
if (rc != MQTT_CODE_SUCCESS) {
goto disconn;
}
}
FALL_THROUGH;
case WMQ_DISCONNECT:
{
/* Disconnect */
rc = MqttClient_Disconnect(&mqttCtx->client);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Disconnect: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto disconn;
}
}
FALL_THROUGH;
case WMQ_NET_DISCONNECT:
{
mqttCtx->stat = WMQ_NET_DISCONNECT;
rc = MqttClient_NetDisconnect(&mqttCtx->client);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Socket Disconnect: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
}
FALL_THROUGH;
case WMQ_DONE:
{
mqttCtx->stat = WMQ_DONE;
rc = mqttCtx->return_code;
goto exit;
}
case WMQ_PUB:
case WMQ_UNSUB:
case WMQ_PING:
default:
rc = MQTT_CODE_ERROR_STAT;
goto exit;
} /* switch */
disconn:
mqttCtx->stat = WMQ_NET_DISCONNECT;
mqttCtx->return_code = rc;
rc = MQTT_CODE_CONTINUE;
exit:
if (rc != MQTT_CODE_CONTINUE) {
/* Free resources */
if (mqttCtx->tx_buf) WOLFMQTT_FREE(mqttCtx->tx_buf);
if (mqttCtx->rx_buf) WOLFMQTT_FREE(mqttCtx->rx_buf);
/* Cleanup network */
MqttClientNet_DeInit(&mqttCtx->net);
MqttClient_DeInit(&mqttCtx->client);
}
return rc;
}
/* so overall tests can pull in test function */
#ifdef USE_WINDOWS_API
#include <windows.h> /* for ctrl handler */
static BOOL CtrlHandler(DWORD fdwCtrlType)
{
if (fdwCtrlType == CTRL_C_EVENT) {
#if defined(ENABLE_FIRMWARE_SIG)
mStopRead = 1;
#endif
PRINTF("Received Ctrl+c");
return TRUE;
}
return FALSE;
}
#elif HAVE_SIGNAL
#include <signal.h>
static void sig_handler(int signo)
{
if (signo == SIGINT) {
#if defined(ENABLE_FIRMWARE_SIG)
mStopRead = 1;
#endif
PRINTF("Received SIGINT");
}
}
#endif
int fwclient_main(void)
{
int rc;
MQTTCtx mqttCtx;
printf("Start fwclient\n");
#if defined(DEBUG_WOLFSSL)
printf("Debug enabled\n");
wolfSSL_Debugging_ON();
#endif
/* init defaults */
mqtt_init_ctx(&mqttCtx);
mqttCtx.app_name = "fwclient";
mqttCtx.client_id = mqtt_append_random(FIRMWARE_CLIENT_ID,
(word32)XSTRLEN(FIRMWARE_CLIENT_ID));
mqttCtx.dynamicClientId = 1;
mqttCtx.topic_name = FIRMWARE_TOPIC_NAME;
mqttCtx.qos = FIRMWARE_MQTT_QOS;
mqttCtx.pub_file = FIRMWARE_DEF_SAVE_AS;
mqttCtx.use_tls = 1;
mqttCtx.username = "fwclient";
mqttCtx.password = "fwclient_pw";
#ifdef USE_WINDOWS_API
if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE) == FALSE) {
PRINTF("Error setting Ctrl Handler! Error %d", (int)GetLastError());
}
#elif HAVE_SIGNAL
if (signal(SIGINT, sig_handler) == SIG_ERR) {
PRINTF("Can't catch SIGINT");
}
#endif
do {
rc = fwclient_test(&mqttCtx);
} while (!mStopRead && rc == MQTT_CODE_CONTINUE);
mqtt_free_ctx(&mqttCtx);
return (rc == 0) ? 0 : EXIT_FAILURE;
}

View File

@ -0,0 +1,37 @@
/* fwclient.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_FWCLIENT_H
#define WOLFMQTT_FWCLIENT_H
#include "examples/mqttexample.h"
#define FIRMWARE_CLIENT_ID "WolfMQTTFWClient"
#define FIRMWARE_DEF_SAVE_AS "./app/image_updated.bin"
/* Exposed functions */
int fwclient_test(MQTTCtx *mqttCtx);
int fwclient_main(void);
#endif /* WOLFMQTT_FWCLIENT_H */

View File

@ -0,0 +1,934 @@
/* mqttexample.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Include the autoconf generated config.h */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "wolfmqtt/mqtt_client.h"
#include "mqttexample.h"
#include "mqttnet.h"
#include "mqttport.h"
/* locals */
static volatile word16 mPacketIdLast;
static const char* kDefTopicName = DEFAULT_TOPIC_NAME;
static const char* kDefClientId = DEFAULT_CLIENT_ID;
/* argument parsing */
static int myoptind = 0;
static char* myoptarg = NULL;
#ifdef ENABLE_MQTT_TLS
#ifdef HAVE_SNI
static int useSNI;
static const char* mTlsSniHostName = NULL;
#endif
#ifdef HAVE_PQC
static const char* mTlsPQAlg = NULL;
#endif
#endif /* ENABLE_MQTT_TLS */
static int mygetopt(int argc, char** argv, const char* optstring)
{
static char* next = NULL;
char c;
char* cp;
if (myoptind == 0)
next = NULL; /* we're starting new/over */
if (next == NULL || *next == '\0') {
if (myoptind == 0)
myoptind++;
if (myoptind >= argc || argv[myoptind][0] != '-' ||
argv[myoptind][1] == '\0') {
myoptarg = NULL;
if (myoptind < argc)
myoptarg = argv[myoptind];
return -1;
}
if (XSTRNCMP(argv[myoptind], "--", 2) == 0) {
myoptind++;
myoptarg = NULL;
if (myoptind < argc)
myoptarg = argv[myoptind];
return -1;
}
next = argv[myoptind];
next++; /* skip - */
myoptind++;
}
c = *next++;
/* The C++ strchr can return a different value */
cp = (char*)XSTRCHR(optstring, c);
if (cp == NULL || c == ':')
return '?';
cp++;
if (*cp == ':') {
if (*next != '\0') {
myoptarg = next;
next = NULL;
}
else if (myoptind < argc) {
myoptarg = argv[myoptind];
myoptind++;
}
else
return '?';
}
else if (*cp == ';') {
myoptarg = (char*)"";
if (*next != '\0') {
myoptarg = next;
next = NULL;
}
else if (myoptind < argc) {
/* Check if next argument is not a parameter argument */
if (argv[myoptind] && argv[myoptind][0] != '-') {
myoptarg = argv[myoptind];
myoptind++;
}
}
}
return c;
}
/* used for testing only, requires wolfSSL RNG */
#ifdef ENABLE_MQTT_TLS
#include <wolfssl/wolfcrypt/random.h>
#endif
static int mqtt_get_rand(byte* data, word32 len)
{
int ret = -1;
#ifdef ENABLE_MQTT_TLS
WC_RNG rng;
ret = wc_InitRng(&rng);
if (ret == 0) {
ret = wc_RNG_GenerateBlock(&rng, data, len);
wc_FreeRng(&rng);
}
#elif defined(HAVE_RAND)
word32 i;
for (i = 0; i<len; i++) {
data[i] = (byte)rand();
}
ret = 0; /* success */
#endif
return ret;
}
int mqtt_fill_random_hexstr(char* buf, word32 bufLen)
{
int rc = 0;
word32 pos = 0, sz, i;
const char kHexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
byte rndBytes[32]; /* fill up to x bytes at a time */
while (rc == 0 && pos < bufLen) {
sz = bufLen - pos;
if (sz > (int)sizeof(rndBytes))
sz = (int)sizeof(rndBytes);
sz /= 2; /* 1 byte expands to 2 bytes */
rc = mqtt_get_rand(rndBytes, sz);
if (rc == 0) {
/* Convert random to hex string */
for (i=0; i<sz; i++) {
byte in = rndBytes[i];
buf[pos + (i*2)] = kHexChar[in >> 4];
buf[pos + (i*2)+1] = kHexChar[in & 0xf];
}
pos += sz*2;
}
else {
PRINTF("MQTT Fill Random Failed! %d", rc);
}
}
return rc;
}
#ifndef TEST_RAND_SZ
#define TEST_RAND_SZ 4
#endif
char* mqtt_append_random(const char* inStr, word32 inLen)
{
int rc = 0;
char *tmp;
tmp = (char*)WOLFMQTT_MALLOC(inLen + 1 + (TEST_RAND_SZ*2) + 1);
if (tmp == NULL) {
rc = MQTT_CODE_ERROR_MEMORY;
}
if (rc == 0) {
/* Format: inStr + `_` randhex + null term */
XMEMCPY(tmp, inStr, inLen);
tmp[inLen] = '_';
rc = mqtt_fill_random_hexstr(tmp + inLen + 1, (TEST_RAND_SZ*2));
tmp[inLen + 1 + (TEST_RAND_SZ*2)] = '\0'; /* null term */
}
if (rc != 0) {
WOLFMQTT_FREE(tmp);
tmp = NULL;
}
return tmp;
}
void mqtt_show_usage(MQTTCtx* mqttCtx)
{
PRINTF("%s:", mqttCtx->app_name);
PRINTF("-? Help, print this usage");
PRINTF("-h <host> Host to connect to, default: %s",
mqttCtx->host);
#ifdef ENABLE_MQTT_TLS
PRINTF("-p <num> Port to connect on, default: Normal %d, TLS %d",
MQTT_DEFAULT_PORT, MQTT_SECURE_PORT);
PRINTF("-t Enable TLS"); /* Note: this string is used in test
* scripts to detect TLS feature */
PRINTF("-A <file> Load CA (validate peer)");
PRINTF("-K <key> Use private key (for TLS mutual auth)");
PRINTF("-c <cert> Use certificate (for TLS mutual auth)");
#ifndef ENABLE_MQTT_CURL
#ifdef HAVE_SNI
/* Remove SNI args for sn-client */
if(XSTRNCMP(mqttCtx->app_name, "sn-client", 10)){
PRINTF("-S <str> Use Host Name Indication, blank defaults to host");
}
#endif /* HAVE_SNI */
#ifdef HAVE_PQC
PRINTF("-Q <str> Use Key Share with post-quantum algorithm");
#endif /* HAVE_PQC */
#endif /* !ENABLE_MQTT_CURL */
PRINTF("-p <num> Port to connect on, default: %d",
MQTT_DEFAULT_PORT);
#endif
PRINTF("-q <num> Qos Level 0-2, default: %d",
mqttCtx->qos);
PRINTF("-s Disable clean session connect flag");
PRINTF("-k <num> Keep alive seconds, default: %d",
mqttCtx->keep_alive_sec);
PRINTF("-i <id> Client Id, default: %s",
mqttCtx->client_id);
PRINTF("-l Enable LWT (Last Will and Testament)");
PRINTF("-u <str> Username");
PRINTF("-w <str> Password");
if (mqttCtx->message) {
/* Only mqttclient example can set message from CLI */
PRINTF("-m <str> Message, default: %s", mqttCtx->message);
}
PRINTF("-n <str> Topic name, default: %s", mqttCtx->topic_name);
PRINTF("-r Set Retain flag on publish message");
PRINTF("-C <num> Command Timeout, default: %dms",
mqttCtx->cmd_timeout_ms);
#ifdef WOLFMQTT_V5
PRINTF("-P <num> Max packet size the client will accept, default: %d",
DEFAULT_MAX_PKT_SZ);
#endif
PRINTF("-T Test mode");
PRINTF("-x Skip subscribe (for testing session persistence)");
PRINTF("-R <file> Ready file (touched when subscribed, for test sync)");
PRINTF("-f <file> Use file contents for publish");
if (!mqttCtx->debug_on) {
PRINTF("-d Enable example debug messages");
}
}
void mqtt_init_ctx(MQTTCtx* mqttCtx)
{
XMEMSET(mqttCtx, 0, sizeof(MQTTCtx));
mqttCtx->host = DEFAULT_MQTT_HOST;
mqttCtx->qos = DEFAULT_MQTT_QOS;
mqttCtx->clean_session = 1;
mqttCtx->keep_alive_sec = DEFAULT_KEEP_ALIVE_SEC;
mqttCtx->client_id = kDefClientId;
mqttCtx->topic_name = kDefTopicName;
mqttCtx->cmd_timeout_ms = DEFAULT_CMD_TIMEOUT_MS;
mqttCtx->debug_on = 1;
#ifdef WOLFMQTT_V5
mqttCtx->max_packet_size = DEFAULT_MAX_PKT_SZ;
mqttCtx->topic_alias = 1;
mqttCtx->topic_alias_max = 1;
#endif
#ifdef WOLFMQTT_DEFAULT_TLS
mqttCtx->use_tls = WOLFMQTT_DEFAULT_TLS;
#endif
#ifdef ENABLE_MQTT_TLS
mqttCtx->ca_file = NULL;
mqttCtx->mtls_keyfile = NULL;
mqttCtx->mtls_certfile = NULL;
#endif
mqttCtx->app_name = "mqttclient";
mqttCtx->message = DEFAULT_MESSAGE;
}
int mqtt_parse_args(MQTTCtx* mqttCtx, int argc, char** argv)
{
int rc;
#ifdef ENABLE_MQTT_TLS
#ifdef ENABLE_MQTT_CURL
#define MQTT_TLS_ARGS "c:A:K:"
#else
#define MQTT_TLS_ARGS "c:A:K:S;Q:"
#endif
#else
#define MQTT_TLS_ARGS ""
#endif
#ifdef WOLFMQTT_V5
#define MQTT_V5_ARGS "P:"
#else
#define MQTT_V5_ARGS ""
#endif
while ((rc = mygetopt(argc, argv, "?h:p:q:sk:i:lu:w:m:n:C:Tf:rtdxR:" \
MQTT_TLS_ARGS MQTT_V5_ARGS)) != -1) {
switch ((char)rc) {
case '?' :
mqtt_show_usage(mqttCtx);
return MY_EX_USAGE;
case 'h' :
mqttCtx->host = myoptarg;
break;
case 'p' :
mqttCtx->port = (word16)XATOI(myoptarg);
if (mqttCtx->port == 0) {
return err_sys("Invalid Port Number!");
}
break;
case 'q' :
mqttCtx->qos = (MqttQoS)((byte)XATOI(myoptarg));
if (mqttCtx->qos > MQTT_QOS_2) {
return err_sys("Invalid QoS value!");
}
break;
case 's':
mqttCtx->clean_session = 0;
break;
case 'k':
mqttCtx->keep_alive_sec = XATOI(myoptarg);
break;
case 'i':
mqttCtx->client_id = myoptarg;
break;
case 'l':
mqttCtx->enable_lwt = 1;
break;
case 'u':
mqttCtx->username = myoptarg;
break;
case 'w':
mqttCtx->password = myoptarg;
break;
case 'm':
mqttCtx->message = myoptarg;
break;
case 'n':
mqttCtx->topic_name = myoptarg;
break;
case 'C':
mqttCtx->cmd_timeout_ms = XATOI(myoptarg);
break;
case 'T':
mqttCtx->test_mode = 1;
break;
case 'f':
mqttCtx->pub_file = myoptarg;
break;
case 'r':
mqttCtx->retain = 1;
break;
case 't':
mqttCtx->use_tls = 1;
break;
case 'd':
mqttCtx->debug_on = 1;
break;
case 'x':
mqttCtx->skip_subscribe = 1;
break;
case 'R':
mqttCtx->ready_file = myoptarg;
break;
#ifdef ENABLE_MQTT_TLS
case 'A':
mqttCtx->ca_file = myoptarg;
break;
case 'c':
mqttCtx->mtls_certfile = myoptarg;
break;
case 'K':
mqttCtx->mtls_keyfile = myoptarg;
break;
#ifndef ENABLE_MQTT_CURL
case 'S':
#ifdef HAVE_SNI
useSNI = 1;
mTlsSniHostName = myoptarg;
#else
PRINTF("To use '-S', enable SNI in wolfSSL");
#endif
break;
case 'Q':
#ifdef HAVE_PQC
mTlsPQAlg = myoptarg;
#else
PRINTF("To use '-Q', build wolfSSL with --enable-mlkem --enable-dilithium");
#endif
break;
#endif /* !ENABLE_MQTT_CURL */
#endif /* ENABLE_MQTT_TLS */
#ifdef WOLFMQTT_V5
case 'P':
mqttCtx->max_packet_size = XATOI(myoptarg);
break;
#endif
default:
mqtt_show_usage(mqttCtx);
return MY_EX_USAGE;
}
/* Remove SNI functionality for sn-client */
if(!XSTRNCMP(mqttCtx->app_name, "sn-client", 10)){
#ifdef HAVE_SNI
useSNI=0;
#endif
}
}
rc = 0;
myoptind = 0; /* reset for test cases */
/* if TLS not enable, check args */
#ifndef ENABLE_MQTT_TLS
if (mqttCtx->use_tls) {
PRINTF("Use TLS option not allowed (TLS not compiled in)");
mqttCtx->use_tls = 0;
if (mqttCtx->test_mode) {
return MY_EX_USAGE;
}
}
#endif
#ifdef HAVE_SNI
if ((useSNI == 1) && (XSTRLEN(mTlsSniHostName) == 0)) {
/* Set SNI host name to host if -S was blank */
mTlsSniHostName = mqttCtx->host;
}
#endif
/* for test mode only */
/* add random data to end of client_id and topic_name */
if (mqttCtx->test_mode && mqttCtx->topic_name == kDefTopicName) {
char* topic_name = mqtt_append_random(kDefTopicName,
(word32)XSTRLEN(kDefTopicName));
if (topic_name) {
mqttCtx->topic_name = (const char*)topic_name;
mqttCtx->dynamicTopic = 1;
}
}
if (mqttCtx->test_mode && mqttCtx->client_id == kDefClientId) {
char* client_id = mqtt_append_random(kDefClientId,
(word32)XSTRLEN(kDefClientId));
if (client_id) {
mqttCtx->client_id = (const char*)client_id;
mqttCtx->dynamicClientId = 1;
}
}
return rc;
}
void mqtt_free_ctx(MQTTCtx* mqttCtx)
{
if (mqttCtx == NULL) {
return;
}
if (mqttCtx->dynamicTopic && mqttCtx->topic_name) {
WOLFMQTT_FREE((char*)mqttCtx->topic_name);
mqttCtx->topic_name = NULL;
}
if (mqttCtx->dynamicClientId && mqttCtx->client_id) {
WOLFMQTT_FREE((char*)mqttCtx->client_id);
mqttCtx->client_id = NULL;
}
}
#if defined(__GNUC__) && !defined(NO_EXIT) && !defined(WOLFMQTT_ZEPHYR)
__attribute__ ((noreturn))
#endif
int err_sys(const char* msg)
{
if (msg) {
PRINTF("wolfMQTT error: %s", msg);
}
exit(EXIT_FAILURE);
#ifdef WOLFMQTT_ZEPHYR
/* Zephyr compiler produces below warning. Let's silence it.
* warning: 'noreturn' function does return
* 477 | }
* | ^
*/
return 0;
#endif
}
word16 mqtt_get_packetid(void)
{
/* Check rollover */
if (mPacketIdLast >= MAX_PACKET_ID) {
mPacketIdLast = 0;
}
return ++mPacketIdLast;
}
#ifdef WOLFMQTT_NONBLOCK
#if defined(MICROCHIP_MPLAB_HARMONY)
#include <system/tmr/sys_tmr.h>
#else
#include <time.h>
#endif
static word32 mqtt_get_timer_seconds(void)
{
word32 timer_sec = 0;
#if defined(MICROCHIP_MPLAB_HARMONY)
timer_sec = (word32)(SYS_TMR_TickCountGet() /
SYS_TMR_TickCounterFrequencyGet());
#else
/* Posix style time */
timer_sec = (word32)time(0);
#endif
return timer_sec;
}
int mqtt_check_timeout(int rc, word32* start_sec, word32 timeout_sec)
{
word32 elapsed_sec;
/* if start seconds not set or is not continue */
if (*start_sec == 0 || rc != MQTT_CODE_CONTINUE) {
*start_sec = mqtt_get_timer_seconds();
return rc;
}
/* Default to 2s timeout. This function sometimes incorrectly
* triggers if 1s is used because of rounding. */
if (timeout_sec == 0) {
timeout_sec = DEFAULT_CHK_TIMEOUT_S;
}
elapsed_sec = mqtt_get_timer_seconds();
if (*start_sec < elapsed_sec) {
elapsed_sec -= *start_sec;
if (elapsed_sec >= timeout_sec) {
*start_sec = mqtt_get_timer_seconds();
PRINTF("Timeout timer %d seconds", timeout_sec);
return MQTT_CODE_ERROR_TIMEOUT;
}
}
return rc;
}
#endif /* WOLFMQTT_NONBLOCK */
#if defined(ENABLE_MQTT_TLS) && !defined(EXTERNAL_MQTT_TLS_CALLBACK)
#ifdef WOLFSSL_ENCRYPTED_KEYS
int mqtt_password_cb(char* passwd, int sz, int rw, void* userdata)
{
(void)rw;
(void)userdata;
if (userdata != NULL) {
XSTRNCPY(passwd, (char*)userdata, sz);
return (int)XSTRLEN((char*)userdata);
}
else {
XSTRNCPY(passwd, "yassl123", sz);
return (int)XSTRLEN(passwd);
}
}
#endif
static int mqtt_tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
{
char buffer[WOLFSSL_MAX_ERROR_SZ];
MQTTCtx *mqttCtx = NULL;
char appName[PRINT_BUFFER_SIZE] = {0};
if (store->userCtx != NULL) {
/* The client.ctx was stored during MqttSocket_Connect. */
mqttCtx = (MQTTCtx *)store->userCtx;
XSTRNCPY(appName, " for ", PRINT_BUFFER_SIZE-1);
XSTRNCAT(appName, mqttCtx->app_name,
PRINT_BUFFER_SIZE-XSTRLEN(appName)-1);
}
PRINTF("MQTT TLS Verify Callback%s: PreVerify %d, Error %d (%s)",
appName, preverify,
store->error, store->error != 0 ?
wolfSSL_ERR_error_string(store->error, buffer) : "none");
PRINTF(" Subject's domain name is %s", store->domain);
if (store->error != 0) {
/* Allowing to continue */
/* Should check certificate and return 0 if not okay */
PRINTF(" Allowing cert anyways");
}
return 1;
}
/* Use this callback to setup TLS certificates and verify callbacks */
int mqtt_tls_cb(MqttClient* client)
{
int rc = WOLFSSL_FAILURE;
SocketContext * sock = (SocketContext *)client->net->context;
/* Use highest available and allow downgrade. If wolfSSL is built with
* old TLS support, it is possible for a server to force a downgrade to
* an insecure version. */
client->tls.ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
if (client->tls.ctx) {
wolfSSL_CTX_set_verify(client->tls.ctx, WOLFSSL_VERIFY_PEER,
mqtt_tls_verify_cb);
/* default to success */
rc = WOLFSSL_SUCCESS;
#if !defined(NO_CERT)
#if !defined(NO_FILESYSTEM)
if (sock->mqttCtx->ca_file) {
/* Load CA certificate file */
rc = wolfSSL_CTX_load_verify_locations(client->tls.ctx,
sock->mqttCtx->ca_file, NULL);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading CA %s: %d (%s)", sock->mqttCtx->ca_file,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
if (sock->mqttCtx->mtls_certfile && sock->mqttCtx->mtls_keyfile) {
/* Load If using a mutual authentication */
rc = wolfSSL_CTX_use_certificate_file(client->tls.ctx,
sock->mqttCtx->mtls_certfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading certificate %s: %d (%s)",
sock->mqttCtx->mtls_certfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
#ifdef WOLFSSL_ENCRYPTED_KEYS
/* Setup password callback for pkcs8 key */
wolfSSL_CTX_set_default_passwd_cb(client->tls.ctx,
mqtt_password_cb);
#endif
rc = wolfSSL_CTX_use_PrivateKey_file(client->tls.ctx,
sock->mqttCtx->mtls_keyfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading key %s: %d (%s)",
sock->mqttCtx->mtls_keyfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
#else
/* Note: Zephyr example uses NO_FILESYSTEM */
#ifdef WOLFSSL_ENCRYPTED_KEYS
/* Setup password callback for pkcs8 key */
wolfSSL_CTX_set_default_passwd_cb(client->tls.ctx,
mqtt_password_cb);
#endif
/* Examples for loading buffer directly */
/* Load CA certificate buffer */
rc = wolfSSL_CTX_load_verify_buffer_ex(client->tls.ctx,
(const byte*)root_ca, (long)sizeof(root_ca),
WOLFSSL_FILETYPE_ASN1, 0, WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY);
/* Load Client Cert */
if (rc == WOLFSSL_SUCCESS) {
rc = wolfSSL_CTX_use_certificate_buffer(client->tls.ctx,
(const byte*)device_cert, (long)sizeof(device_cert),
WOLFSSL_FILETYPE_ASN1);
}
/* Load Private Key */
if (rc == WOLFSSL_SUCCESS) {
rc = wolfSSL_CTX_use_PrivateKey_buffer(client->tls.ctx,
(const byte*)device_priv_key, (long)sizeof(device_priv_key),
WOLFSSL_FILETYPE_ASN1);
}
#endif /* !NO_FILESYSTEM */
#endif /* !NO_CERT */
#ifdef HAVE_SNI
if ((rc == WOLFSSL_SUCCESS) && (mTlsSniHostName != NULL)) {
rc = wolfSSL_CTX_UseSNI(client->tls.ctx, WOLFSSL_SNI_HOST_NAME,
mTlsSniHostName, (word16) XSTRLEN(mTlsSniHostName));
if (rc != WOLFSSL_SUCCESS) {
PRINTF("UseSNI failed");
}
}
#endif /* HAVE_SNI */
#ifdef HAVE_PQC
if ((rc == WOLFSSL_SUCCESS) && (mTlsPQAlg != NULL)) {
int group = 0;
if (XSTRCMP(mTlsPQAlg, "ML_KEM_768") == 0) {
group = WOLFSSL_ML_KEM_768;
} else if (XSTRCMP(mTlsPQAlg, "SecP384r1MLKEM768") == 0) {
group = WOLFSSL_SECP384R1MLKEM768;
} else {
PRINTF("Invalid post-quantum KEM specified");
}
if (group != 0) {
client->tls.ssl = wolfSSL_new(client->tls.ctx);
if (client->tls.ssl == NULL) {
rc = WOLFSSL_FAILURE;
}
if (rc == WOLFSSL_SUCCESS) {
rc = wolfSSL_UseKeyShare(client->tls.ssl, group);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Use key share failed");
}
}
}
}
#endif /* HAVE_PQC */
}
#if defined(NO_CERT) || defined(NO_FILESYSTEM)
(void)sock;
#endif
PRINTF("MQTT TLS Setup (%d)", rc);
return rc;
}
#ifdef WOLFMQTT_SN
int mqtt_dtls_cb(MqttClient* client) {
#ifdef WOLFSSL_DTLS
int rc = WOLFSSL_FAILURE;
SocketContext * sock = (SocketContext *)client->net->context;
client->tls.ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
if (client->tls.ctx) {
wolfSSL_CTX_set_verify(client->tls.ctx, WOLFSSL_VERIFY_PEER,
mqtt_tls_verify_cb);
/* default to success */
rc = WOLFSSL_SUCCESS;
#if !defined(NO_CERT) && !defined(NO_FILESYSTEM)
if (sock->mqttCtx->ca_file) {
/* Load CA certificate file */
rc = wolfSSL_CTX_load_verify_locations(client->tls.ctx,
sock->mqttCtx->ca_file, NULL);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading CA %s: %d (%s)", sock->mqttCtx->ca_file,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
if (sock->mqttCtx->mtls_certfile && sock->mqttCtx->mtls_keyfile) {
/* Load If using a mutual authentication */
rc = wolfSSL_CTX_use_certificate_file(client->tls.ctx,
sock->mqttCtx->mtls_certfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading certificate %s: %d (%s)",
sock->mqttCtx->mtls_certfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
rc = wolfSSL_CTX_use_PrivateKey_file(client->tls.ctx,
sock->mqttCtx->mtls_keyfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading key %s: %d (%s)",
sock->mqttCtx->mtls_keyfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
#else
(void)sock;
#endif
client->tls.ssl = wolfSSL_new(client->tls.ctx);
if (client->tls.ssl == NULL) {
rc = WOLFSSL_FAILURE;
return rc;
}
}
PRINTF("MQTT DTLS Setup (%d)", rc);
#else /* WOLFSSL_DTLS */
(void)client;
int rc = 0;
PRINTF("MQTT DTLS Setup - Must enable DTLS in wolfSSL!");
#endif
return rc;
}
#endif /* WOLFMQTT_SN */
#else
int mqtt_tls_cb(MqttClient* client)
{
(void)client;
return 0;
}
#ifdef WOLFMQTT_SN
int mqtt_dtls_cb(MqttClient* client)
{
(void)client;
return 0;
}
#endif
#endif /* ENABLE_MQTT_TLS */
int mqtt_file_load(const char* filePath, byte** fileBuf, int *fileLen)
{
#if !defined(NO_FILESYSTEM)
int rc = 0;
XFILE file = NULL;
long int pos = -1L;
/* Check arguments */
if (filePath == NULL || XSTRLEN(filePath) == 0 || fileLen == NULL ||
fileBuf == NULL) {
return MQTT_CODE_ERROR_BAD_ARG;
}
/* Open file */
file = XFOPEN(filePath, "rb");
if (file == NULL) {
PRINTF("File '%s' does not exist!", filePath);
rc = EXIT_FAILURE;
goto exit;
}
/* Determine length of file */
if (XFSEEK(file, 0, XSEEK_END) != 0) {
PRINTF("fseek() failed");
rc = EXIT_FAILURE;
goto exit;
}
pos = (int)XFTELL(file);
if (pos == -1L) {
PRINTF("ftell() failed");
rc = EXIT_FAILURE;
goto exit;
}
*fileLen = (int)pos;
if (XFSEEK(file, 0, XSEEK_SET) != 0) {
PRINTF("fseek() failed");
rc = EXIT_FAILURE;
goto exit;
}
#ifdef DEBUG_WOLFMQTT
PRINTF("File %s is %d bytes", filePath, *fileLen);
#endif
/* Allocate buffer for image */
*fileBuf = (byte*)WOLFMQTT_MALLOC(*fileLen);
if (*fileBuf == NULL) {
PRINTF("File buffer malloc failed!");
rc = MQTT_CODE_ERROR_MEMORY;
goto exit;
}
/* Load file into buffer */
rc = (int)XFREAD(*fileBuf, 1, *fileLen, file);
if (rc != *fileLen) {
PRINTF("Error reading file! %d", rc);
rc = EXIT_FAILURE;
goto exit;
}
rc = 0; /* Success */
exit:
if (file) {
XFCLOSE(file);
}
if (rc != 0) {
if (*fileBuf) {
WOLFMQTT_FREE(*fileBuf);
*fileBuf = NULL;
}
}
return rc;
#else
(void)filePath;
(void)fileBuf;
(void)fileLen;
PRINTF("File system support is not configured.");
return EXIT_FAILURE;
#endif
}

View File

@ -0,0 +1,240 @@
/* mqttexample.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_EXAMPLE_H
#define WOLFMQTT_EXAMPLE_H
#include "wolfmqtt/mqtt_client.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Compatibility Options */
#ifdef NO_EXIT
#undef exit
#define exit(rc) return rc
#endif
#ifndef MY_EX_USAGE
#define MY_EX_USAGE 2 /* Exit reason code */
#endif
/* STDIN / FGETS for examples */
#ifndef WOLFMQTT_NO_STDIO
/* For Linux/Mac */
#if !defined(FREERTOS) && !defined(USE_WINDOWS_API) && \
!defined(FREESCALE_MQX) && !defined(FREESCALE_KSDK_MQX) && \
!defined(MICROCHIP_MPLAB_HARMONY) && !defined(WOLFMQTT_ZEPHYR)
/* Make sure its not explicitly disabled and not already defined */
#if !defined(WOLFMQTT_NO_STDIN_CAP) && \
!defined(WOLFMQTT_ENABLE_STDIN_CAP)
/* Wake on stdin activity */
#define WOLFMQTT_ENABLE_STDIN_CAP
#endif
#endif
#ifdef WOLFMQTT_ENABLE_STDIN_CAP
#ifndef XFGETS
#define XFGETS fgets
#endif
#ifndef STDIN
#define STDIN 0
#endif
#endif
#endif /* !WOLFMQTT_NO_STDIO */
/* Default Configurations */
#ifndef DEFAULT_MQTT_HOST
/* Default MQTT host broker to use,
* when none is specified in the examples */
#define DEFAULT_MQTT_HOST "broker.hivemq.com"
/* "iot.eclipse.org" */
/* "broker.emqx.io" */
/* "broker.hivemq.com" */
#endif
#define DEFAULT_CMD_TIMEOUT_MS 30000
#define DEFAULT_CON_TIMEOUT_MS 5000
#define DEFAULT_CHK_TIMEOUT_S 2
#define DEFAULT_MQTT_QOS MQTT_QOS_0
#define DEFAULT_KEEP_ALIVE_SEC 60
#define DEFAULT_CLIENT_ID "WolfMQTTClient"
#ifndef WOLFMQTT_TOPIC_NAME
#define WOLFMQTT_TOPIC_NAME "wolfMQTT/example/"
#define DEFAULT_TOPIC_NAME WOLFMQTT_TOPIC_NAME"testTopic"
#else
#define DEFAULT_TOPIC_NAME WOLFMQTT_TOPIC_NAME
#endif
#define DEFAULT_AUTH_METHOD "EXTERNAL"
#define PRINT_BUFFER_SIZE 80
#define DEFAULT_MESSAGE "test"
#ifdef WOLFMQTT_V5
#define DEFAULT_MAX_PKT_SZ 1024*1024 /* The max MQTT control packet size
the client is willing to accept. */
#define DEFAULT_SUB_ID 1 /* Sub ID starts at 1 */
#define DEFAULT_SESS_EXP_INT 0xFFFFFFFF
#endif
/* certs are either static or extern, depending on the specific example */
#ifndef EXTERNAL_MQTT_TLS_CALLBACK
#ifdef WOLFMQTT_EXTERN_CERT
#undef WOLFMQTT_EXAMPLE_CERT
#define WOLFMQTT_EXAMPLE_CERT /* init extern from mqttexample.h */
extern const char* root_ca;
extern const char* device_cert;
extern const char* device_priv_key;
#else
#undef WOLFMQTT_EXAMPLE_CERT
#define WOLFMQTT_EXAMPLE_CERT static
#endif
#endif /* !EXTERNAL_MQTT_TLS_CALLBACK */
/* MQTT Client state */
typedef enum _MQTTCtxState {
WMQ_BEGIN = 0,
WMQ_NET_INIT,
WMQ_INIT,
WMQ_TCP_CONN,
WMQ_MQTT_CONN,
WMQ_SUB,
WMQ_PUB,
WMQ_WAIT_MSG,
WMQ_PING,
WMQ_UNSUB,
WMQ_DISCONNECT,
WMQ_NET_DISCONNECT,
WMQ_DONE
} MQTTCtxState;
/* MQTT Client context */
/* This is used for the examples as reference */
/* Use of this structure allow non-blocking context */
typedef struct _MQTTCtx {
MQTTCtxState stat;
void* app_ctx; /* For storing application specific data */
/* client and net containers */
MqttClient client;
MqttNet net;
/* temp mqtt containers */
MqttConnect connect;
MqttMessage lwt_msg;
MqttSubscribe subscribe;
MqttUnsubscribe unsubscribe;
MqttTopic topics[1];
MqttPublish publish;
MqttDisconnect disconnect;
MqttPing ping;
#ifdef WOLFMQTT_SN
SN_Publish publishSN;
#endif
/* configuration */
MqttQoS qos;
const char* app_name;
const char* host;
const char* username;
const char* password;
const char* topic_name;
const char* message;
const char* pub_file;
const char* client_id;
#if defined (ENABLE_MQTT_TLS)
const char* ca_file;
const char* mtls_keyfile;
const char* mtls_certfile;
#endif
byte *tx_buf, *rx_buf;
int return_code;
int use_tls;
int retain;
int enable_lwt;
#ifdef WOLFMQTT_V5
int max_packet_size;
#endif
word32 cmd_timeout_ms;
#ifdef WOLFMQTT_NONBLOCK
word32 start_sec; /* used for timeout and keep-alive */
#endif
word16 keep_alive_sec;
word16 port;
#ifdef WOLFMQTT_V5
word16 topic_alias;
word16 topic_alias_max; /* Server property */
#endif
byte clean_session;
byte test_mode;
byte debug_on:1; /* enable debug messages in example */
#ifdef WOLFMQTT_V5
byte subId_not_avail; /* Server property */
byte enable_eauth; /* Enhanced authentication */
#endif
unsigned int dynamicTopic:1;
unsigned int dynamicClientId:1;
unsigned int skip_subscribe:1;
const char* ready_file; /* touch file when ready (e.g., after SUBACK) */
#ifdef WOLFMQTT_NONBLOCK
unsigned int useNonBlockMode:1; /* set to use non-blocking mode.
network callbacks can return MQTT_CODE_CONTINUE to indicate "would block" */
#endif
#ifdef WOLFMQTT_WOLFIP
struct wolfIP *stack; /* wolfIP TCP/IP stack instance */
#endif
} MQTTCtx;
void mqtt_show_usage(MQTTCtx* mqttCtx);
void mqtt_init_ctx(MQTTCtx* mqttCtx);
void mqtt_free_ctx(MQTTCtx* mqttCtx);
int mqtt_parse_args(MQTTCtx* mqttCtx, int argc, char** argv);
int err_sys(const char* msg);
int mqtt_tls_cb(MqttClient* client);
#ifdef WOLFMQTT_SN
int mqtt_dtls_cb(MqttClient* client);
#endif
word16 mqtt_get_packetid(void);
#ifdef WOLFMQTT_NONBLOCK
int mqtt_check_timeout(int rc, word32* start_sec, word32 timeout_sec);
#endif
int mqtt_fill_random_hexstr(char* buf, word32 bufLen);
char* mqtt_append_random(const char* inStr, word32 inLen);
int mqtt_file_load(const char* filePath, byte** fileBuf, int *fileLen);
#ifdef WOLFSSL_ENCRYPTED_KEYS
int mqtt_password_cb(char* passwd, int sz, int rw, void* userdata);
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLFMQTT_EXAMPLE_H */

2028
sim-OTA/app/mqttnet.c 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/* mqttnet.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_NET_H
#define WOLFMQTT_NET_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ENABLE_MQTT_CURL
#include <curl/curl.h>
#endif
#include "examples/mqttexample.h"
#include "examples/mqttport.h"
#if defined(HAVE_NETX) && !defined(WOLFMQTT_NO_NETX_DNS)
/* include the NetX DNS addon header */
#include "nxd_dns.h"
#endif
/* Local context for Net callbacks */
typedef enum {
SOCK_BEGIN = 0,
SOCK_CONN
} NB_Stat;
typedef struct _SocketContext {
SOCKET_T fd;
NB_Stat stat;
SOCK_ADDR_IN addr;
#ifdef MICROCHIP_MPLAB_HARMONY
word32 bytes;
#endif
#if defined(WOLFMQTT_MULTITHREAD) && defined(WOLFMQTT_ENABLE_STDIN_CAP)
/* "self pipe" -> signal wake sleep() */
SOCKET_T pfd[2];
#endif
#ifdef ENABLE_MQTT_CURL
CURL * curl;
int bytes; /* track partial read/write */
#endif
#ifdef ENABLE_MQTT_WEBSOCKET
void* websocket_ctx;
#endif
#ifdef HAVE_NETX
#ifndef WOLFMQTT_NO_NETX_DNS
NX_DNS *dnsPtr;
#endif
NX_IP *ipPtr;
NX_PACKET *nxPacket;
ULONG nxOffset;
#endif
#ifdef WOLFMQTT_WOLFIP
struct wolfIP *stack;
#endif
MQTTCtx* mqttCtx;
} SocketContext;
/* Functions used to handle the MqttNet structure creation / destruction */
int MqttClientNet_Init(MqttNet* net, MQTTCtx* mqttCtx);
int MqttClientNet_DeInit(MqttNet* net);
#ifdef WOLFMQTT_SN
int SN_ClientNet_Init(MqttNet* net, MQTTCtx* mqttCtx);
#endif
int MqttClientNet_Wake(MqttNet* net);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLFMQTT_NET_H */

View File

@ -0,0 +1,105 @@
/* mqttport.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Include the autoconf generated config.h */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "wolfmqtt/mqtt_client.h"
#include "mqttnet.h"
#include "mqttexample.h"
#include "mqttport.h"
#ifdef WOLFMQTT_ZEPHYR
#ifndef NO_FILESYSTEM
#ifndef WOLFSSL_ZEPHYR
XFILE z_fs_open(const char* filename, const char* mode)
{
XFILE file;
fs_mode_t flags = 0;
if (mode == NULL)
return NULL;
/* Parse mode */
switch (*mode++) {
case 'r':
flags |= FS_O_READ;
break;
case 'w':
flags |= FS_O_WRITE|FS_O_CREATE;
break;
case 'a':
flags |= FS_O_APPEND|FS_O_CREATE;
break;
default:
return NULL;
}
/* Ignore binary flag */
if (*mode == 'b')
mode++;
if (*mode == '+') {
flags |= FS_O_READ;
/* Don't add write flag if already appending */
if (!(flags & FS_O_APPEND))
flags |= FS_O_RDWR;
}
/* Ignore binary flag */
if (*mode == 'b')
mode++;
/* Incorrect mode string */
if (*mode != '\0')
return NULL;
file = (XFILE)WOLFMQTT_MALLOC(sizeof(*file));
if (file != NULL) {
if (fs_open(file, filename, flags) != 0) {
WOLFMQTT_FREE(file);
file = NULL;
}
}
return file;
}
int z_fs_close(XFILE file)
{
int ret;
if (file == NULL)
return -1;
ret = (fs_close(file) == 0) ? 0 : -1;
WOLFMQTT_FREE(file);
return ret;
}
#endif /* !WOLFSSL_ZEPHYR */
#endif /* !NO_FILESYSTEM */
#else
/* Default implementations */
#endif

View File

@ -0,0 +1,320 @@
/*
* mqttport.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_PORT_H
#define WOLFMQTT_PORT_H
#ifdef __cplusplus
extern "C" {
#endif
/* FreeRTOS TCP */
#ifdef FREERTOS_TCP
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_DNS.h"
#include "FreeRTOS_Sockets.h"
#define SOCKET_T Socket_t
#define SOCK_ADDR_IN struct freertos_sockaddr
/* ToppersOS and LWIP */
#elif defined(TOPPERS) && defined(WOLFSSL_LWIP)
/* lwIP includes. */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
/* FreeRTOS and LWIP */
#elif defined(FREERTOS) && defined(WOLFSSL_LWIP)
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* lwIP includes. */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
/* LWIP only */
#elif defined(WOLFSSL_LWIP)
/* lwIP includes. */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
/* wolfIP TCP/IP stack */
#elif defined(WOLFMQTT_WOLFIP)
#include "wolfip.h"
#define SOCKET_T int
#define SOCKET_INVALID (-1)
#define SOCK_ADDR_IN struct wolfIP_sockaddr_in
/* For wolfIP targets without filesystem support, define NO_FILESYSTEM
* via build configuration (e.g., compiler flags or user_settings.h). */
#ifndef NO_FILESYSTEM
#define NO_FILESYSTEM
#endif
/* User defined IO */
#elif defined(WOLFMQTT_USER_IO)
#include "userio_template.h"
/* NetX */
#elif defined(HAVE_NETX)
#include "nx_api.h"
#define SOCKET_T NX_TCP_SOCKET
#define SOCK_ADDR_IN NXD_ADDRESS
/* Windows */
#elif defined(USE_WINDOWS_API)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#define SOCKET_T SOCKET
#ifdef _WIN32
#define SOERROR_T int
#else
#define SOERROR_T char
#endif
#define SELECT_FD(fd) (fd)
#ifndef SOCKET_INVALID /* Do not redefine from wolfssl */
#define SOCKET_INVALID ((SOCKET_T)INVALID_SOCKET)
#endif
#define SOCK_CLOSE closesocket
#define SOCK_SEND(s,b,l,f) send((s), (const char*)(b), (size_t)(l), (f))
#define SOCK_RECV(s,b,l,f) recv((s), (char*)(b), (size_t)(l), (f))
#define GET_SOCK_ERROR(f,s,o,e) (e) = WSAGetLastError()
#define SOCK_EQ_ERROR(e) (((e) == WSAEWOULDBLOCK) || ((e) == WSAEINPROGRESS))
/* Freescale MQX / RTCS */
#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
#if defined(FREESCALE_MQX)
#include <posix.h>
#endif
#include <rtcs.h>
/* Note: Use "RTCS_geterror(sock->fd);" to get error number */
#define SOCKET_INVALID RTCS_SOCKET_ERROR
#define SOCKET_T uint32_t
#define SOCK_CLOSE closesocket
#define SOCK_OPEN RTCS_socket
/* Microchip MPLABX Harmony, TCP/IP */
#elif defined(MICROCHIP_MPLAB_HARMONY)
#include "app.h"
#include "system_config.h"
#include "tcpip/tcpip.h"
#include <sys/errno.h>
#include <errno.h>
#define SOCKET_INVALID (-1)
#define SOCK_CLOSE closesocket
#ifndef WOLFMQTT_NONBLOCK
#error wolfMQTT must be built with WOLFMQTT_NONBLOCK defined for Harmony
#endif
/* Zephyr RTOS */
#elif defined(WOLFMQTT_ZEPHYR)
#include <zephyr/kernel.h>
#include <zephyr/fs/fs.h>
#ifndef CONFIG_POSIX_API
#include <zephyr/net/socket.h>
#endif
#ifdef CONFIG_ARCH_POSIX
#include <fcntl.h>
#else
#include <zephyr/posix/fcntl.h>
#endif
#define SOCKET_INVALID (-1)
typedef zsock_fd_set fd_set;
#define FD_ZERO ZSOCK_FD_ZERO
#define FD_SET ZSOCK_FD_SET
#define FD_ISSET ZSOCK_FD_ISSET
#define select zsock_select
#ifdef WOLFSSL_ZEPHYR
/* wolfSSL takes care of most defines */
#include <wolfssl/wolfcrypt/wc_port.h>
#else
#define addrinfo zsock_addrinfo
#define getaddrinfo zsock_getaddrinfo
#define freeaddrinfo zsock_freeaddrinfo
#define socket zsock_socket
#define close zsock_close
#define SOCK_CONNECT zsock_connect
#define getsockopt zsock_getsockopt
#define setsockopt zsock_setsockopt
#define send zsock_send
#define recv zsock_recv
#define MSG_PEEK ZSOCK_MSG_PEEK
#ifndef NO_FILESYSTEM
#define XFOPEN z_fs_open
#define XFCLOSE z_fs_close
#define XFILE struct fs_file_t*
/* These are our wrappers for opening and closing files to
* make the API more POSIX like. Copied from wolfSSL */
XFILE z_fs_open(const char* filename, const char* mode);
int z_fs_close(XFILE file);
#endif
#endif
#ifndef NO_FILESYSTEM
#ifndef XFILE
#define XFILE struct fs_file_t*
#endif
#ifndef XFFLUSH
#define XFFLUSH fs_sync
#endif
#ifndef XFSEEK
#define XFSEEK fs_seek
#endif
#ifndef XFTELL
#define XFTELL fs_tell
#endif
#ifndef XFREWIND
#define XFREWIND fs_rewind
#endif
#ifndef XFREAD
#define XFREAD(P,S,N,F) fs_read(F, P, S*N)
#endif
#ifndef XFWRITE
#define XFWRITE(P,S,N,F) fs_write(F, P, S*N)
#endif
#ifndef XSEEK_SET
#define XSEEK_SET FS_SEEK_SET
#endif
#ifndef XSEEK_END
#define XSEEK_END FS_SEEK_END
#endif
#endif
/* Linux */
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#endif
/* Setup defaults */
#ifndef NO_FILESYSTEM
#ifndef XFILE
#define XFILE FILE*
#endif
#ifndef XFOPEN
#define XFOPEN fopen
#endif
#ifndef XFCLOSE
#define XFCLOSE fclose
#endif
#ifndef XFSEEK
#define XFSEEK fseek
#endif
#ifndef XFTELL
#define XFTELL ftell
#endif
#ifndef XFREAD
#define XFREAD fread
#endif
#ifndef XFWRITE
#define XFWRITE fwrite
#endif
#ifndef XSEEK_SET
#define XSEEK_SET SEEK_SET
#endif
#ifndef XSEEK_END
#define XSEEK_END SEEK_END
#endif
#endif /* NO_FILESYSTEM */
#ifndef SOCK_OPEN
#define SOCK_OPEN socket
#endif
#ifndef SOCKET_T
#define SOCKET_T int
#endif
#ifndef SOERROR_T
#define SOERROR_T int
#endif
#ifndef SELECT_FD
#define SELECT_FD(fd) ((fd) + 1)
#endif
#ifndef SOCKET_INVALID
#define SOCKET_INVALID ((SOCKET_T)0)
#endif
#ifndef SOCK_CONNECT
#define SOCK_CONNECT connect
#endif
#ifndef SOCK_SEND
#define SOCK_SEND(s,b,l,f) send((s), (b), (size_t)(l), (f))
#endif
#ifndef SOCK_RECV
#define SOCK_RECV(s,b,l,f) recv((s), (b), (size_t)(l), (f))
#endif
#ifndef SOCK_CLOSE
#define SOCK_CLOSE close
#endif
#ifndef SOCK_ADDR_IN
#define SOCK_ADDR_IN struct sockaddr_in
#endif
#ifdef SOCK_ADDRINFO
#define SOCK_ADDRINFO struct addrinfo
#endif
#ifndef GET_SOCK_ERROR
#define GET_SOCK_ERROR(f,s,o,e) \
socklen_t len = sizeof(so_error); \
(void)getsockopt((f), (s), (o), &(e), &len)
#endif
#ifndef SOCK_EQ_ERROR
#define SOCK_EQ_ERROR(e) (((e) == EWOULDBLOCK) || ((e) == EAGAIN))
#endif
#ifdef __cplusplus
}
#endif
#endif /* WOLFMQTT_PORT_H */

View File

@ -0,0 +1,180 @@
/* tpm_handler.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfBoot-Examples.
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "wolftpm/tpm2.h"
#include "wolftpm/tpm2_wrap.h"
#include "tpm_handler.h"
#define TPM2_DEMO_STORAGE_KEY_HANDLE 0x81000200
static const char gStorageKeyAuth[] = "ThisIsMyStorageKeyAuth";
static const char gAiKeyAuth[] = "ThisIsMyAiKeyAuth";
int getPrimaryStorageKey(WOLFTPM2_DEV *pDev, WOLFTPM2_KEY *pStorageKey)
{
int rc;
TPM_HANDLE handle = TPM2_DEMO_STORAGE_KEY_HANDLE;
rc = wolfTPM2_ReadPublicKey(pDev, pStorageKey, handle);
if (rc != 0)
{
/* Create primary storage key */
rc = wolfTPM2_CreateSRK(pDev, pStorageKey, TPM_ALG_RSA,
(byte *)gStorageKeyAuth, sizeof(gStorageKeyAuth) - 1);
}
else
{
/* specify auth password for storage key */
pStorageKey->handle.auth.size = sizeof(gStorageKeyAuth) - 1;
XMEMCPY(pStorageKey->handle.auth.buffer, gStorageKeyAuth,
pStorageKey->handle.auth.size);
}
if (rc != 0)
{
printf("Loading SRK: Storage failed\n");
}
else
{
printf("Loading SRK: Storage 0x%x (%d bytes)\n",
(word32)pStorageKey->handle.hndl, pStorageKey->pub.size);
}
return rc;
}
int tpm_handler(void)
{
WOLFTPM2_DEV dev;
TPMS_ATTEST attestedData;
WOLFTPM2_CAPS caps;
WOLFTPM2_SESSION tpmSession;
TPMT_PUBLIC publicTemplate;
WOLFTPM2_KEY aikKey;
WOLFTPM2_KEY storage; /* SRK */
union
{
Quote_In quoteAsk;
byte maxInput[MAX_COMMAND_SIZE];
} cmdIn;
union
{
Quote_Out quoteResult;
byte maxOutput[MAX_RESPONSE_SIZE];
} cmdOut;
int rc;
printf("=== Attestation Test ===\n");
XMEMSET(&tpmSession, 0, sizeof(tpmSession));
XMEMSET(&storage, 0, sizeof(storage));
XMEMSET(&aikKey, 0, sizeof(aikKey));
rc = wolfTPM2_Init(&dev, NULL, NULL);
if (rc == 0)
{
/* Get device capabilities + options */
rc = wolfTPM2_GetCapabilities(&dev, &caps);
}
if (rc == 0)
{
printf("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x), "
"FIPS 140-2 %d, CC-EAL4 %d\n",
caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor,
caps.fwVerMinor, caps.fwVerVendor, caps.fips140_2, caps.cc_eal4);
}
else
{
printf("GetCapabilities failed\n");
return -1;
}
/* Generate or Read Storage Root Key */
rc = getPrimaryStorageKey(&dev, &storage);
if (rc == 0)
{
/* Generate AIK */
printf("Creating new key...\n");
rc = wolfTPM2_CreateAndLoadAIK(&dev, &aikKey, TPM_ALG_RSA,
&storage, (byte *)gAiKeyAuth, sizeof(gAiKeyAuth) - 1);
}
if (rc != TPM_RC_SUCCESS)
{
printf("wolfTPM2_CreateAndLoadAIK failed\n");
return -1;
}
else
{
printf("New key created and loaded (pub %d bytes)\n",
aikKey.pub.size);
}
/* Set the handle of AIK */
wolfTPM2_SetAuthHandle(&dev, 0, &aikKey.handle);
/* Prepare Quote request */
XMEMSET(&cmdIn.quoteAsk, 0, sizeof(cmdIn.quoteAsk));
XMEMSET(&cmdOut.quoteResult, 0, sizeof(cmdOut.quoteResult));
cmdIn.quoteAsk.signHandle = aikKey.handle.hndl;
cmdIn.quoteAsk.inScheme.scheme = TPM_ALG_RSASSA;
cmdIn.quoteAsk.inScheme.details.any.hashAlg = TPM_ALG_SHA256;
cmdIn.quoteAsk.qualifyingData.size = 0; /* optional */
/* Choose PCR for signing */
TPM2_SetupPCRSel(&cmdIn.quoteAsk.PCRselect, TPM_ALG_SHA256, 16);
rc = TPM2_Quote(&cmdIn.quoteAsk, &cmdOut.quoteResult);
if (rc != TPM_RC_SUCCESS)
{
printf("TPM2_Quote failed 0x%x: %s\n", rc, TPM2_GetRCString(rc));
return -1;
}
printf("Quote success\n");
rc = TPM2_ParseAttest(&cmdOut.quoteResult.quoted, &attestedData);
if (rc != TPM_RC_SUCCESS)
{
printf("TPM2_Packet_ParseAttest failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
return -1;
}
if (attestedData.magic != TPM_GENERATED_VALUE)
{
printf("\tError, attested data not generated by the TPM = 0x%X\n",
attestedData.magic);
return -1;
}
else
{
printf("TPM with signature attests (type 0x%x):\n", attestedData.type);
printf("\tTPM signed %lu count of PCRs\n",
(unsigned long)attestedData.attested.quote.pcrSelect.count);
#ifdef DEBUG_WOLFTPM
printf("\tPCR digest:\n");
TPM2_PrintBin(attestedData.attested.quote.pcrDigest.buffer,
attestedData.attested.quote.pcrDigest.size);
printf("\tTPM generated signature:\n");
TPM2_PrintBin(cmdOut.quoteResult.signature.signature.rsassa.sig.buffer,
cmdOut.quoteResult.signature.signature.rsassa.sig.size);
#endif
}
rc = wolfTPM2_Cleanup(&dev);
if (rc != TPM_RC_SUCCESS)
{
printf("Failed to clean up\n");
return -1;
}
return 0;
}

View File

@ -0,0 +1,8 @@
/* tpm_handler.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfBoot-Examples.
*/
int tpm_handler(void);

View File

@ -0,0 +1,49 @@
/* firmware.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_FIRMWARE_H
#define WOLFMQTT_FIRMWARE_H
#ifdef __cplusplus
extern "C" {
#endif
#define FIRMWARE_TOPIC_NAME "wolfMQTT/example/firmware"
#define FIRMWARE_MAX_BUFFER 2048
#define FIRMWARE_MAX_PACKET (int)(FIRMWARE_MAX_BUFFER + sizeof(MqttPacket) + XSTRLEN(FIRMWARE_TOPIC_NAME) + MQTT_DATA_LEN_SIZE)
#define FIRMWARE_MQTT_QOS MQTT_QOS_2
#define FIRMWARE_HASH_TYPE WC_HASH_TYPE_SHA256
#define FIRMWARE_SIG_TYPE WC_SIGNATURE_TYPE_ECC
/* Signature Len, Public Key Len, Firmware Len, Signature, Public Key, Data */
typedef struct _FirmwareHeader {
word16 sigLen;
word16 pubKeyLen;
word32 fwLen;
} WOLFMQTT_PACK FirmwareHeader;
#ifdef __cplusplus
}
#endif
#endif /* WOLFMQTT_FIRMWARE_H */

View File

@ -0,0 +1,616 @@
/* fwpush.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Include the autoconf generated config.h */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "wolfmqtt/mqtt_client.h"
#if defined(ENABLE_MQTT_TLS)
#if !defined(WOLFSSL_USER_SETTINGS) && !defined(USE_WINDOWS_API)
#include <wolfssl/options.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/version.h>
/* The signature wrapper for this example was added in wolfSSL after 3.7.1 */
#if defined(LIBWOLFSSL_VERSION_HEX) && LIBWOLFSSL_VERSION_HEX > 0x03007001 \
&& defined(HAVE_ECC) && !defined(NO_SIG_WRAPPER)
#undef ENABLE_FIRMWARE_SIG
#define ENABLE_FIRMWARE_SIG
#endif
#endif
#ifdef ENABLE_FIRMWARE_SIG
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/signature.h>
#include <wolfssl/wolfcrypt/hash.h>
#endif
#include "fwpush.h"
#include "firmware.h"
#include "mqttexample.h"
#include "mqttnet.h"
/* Configuration */
#ifndef MAX_BUFFER_SIZE
#define MAX_BUFFER_SIZE FIRMWARE_MAX_PACKET
#endif
/* Locals */
static int mStopRead = 0;
static int mqtt_message_cb(MqttClient *client, MqttMessage *msg,
byte msg_new, byte msg_done)
{
MQTTCtx* mqttCtx = (MQTTCtx*)client->ctx;
(void)mqttCtx;
(void)msg;
(void)msg_new;
(void)msg_done;
/* Return negative to terminate publish processing */
return MQTT_CODE_SUCCESS;
}
/* This callback is executed from within a call to MqttPublish. It is expected
to provide a buffer and it's size and return >=0 for success. In this example
a firmware header is stored in the publish->ctx. */
static int mqtt_publish_cb(MqttPublish *publish) {
int ret = -1;
#if !defined(NO_FILESYSTEM)
size_t bytes_read;
FwpushCBdata *cbData;
FirmwareHeader *header;
word32 headerSize;
/* Structure was stored in ctx pointer */
if (publish != NULL) {
cbData = (FwpushCBdata*)publish->ctx;
if (cbData != NULL) {
header = (FirmwareHeader*)cbData->data;
/* Check for first iteration of callback */
if (cbData->fp == NULL) {
/* Get FW size from FW header struct */
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);
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;
}
}
}
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;
}
}
}
#else
(void)publish;
#endif
return ret;
}
static int fw_message_build(MQTTCtx *mqttCtx, const char* fwFile,
byte **p_msgBuf, int *p_msgLen)
{
int rc;
byte *msgBuf = NULL, *sigBuf = NULL, *keyBuf = NULL, *fwBuf = NULL;
int msgLen = 0, fwLen = 0;
word32 keyLen = 0, sigLen = 0;
FirmwareHeader *header;
#ifdef ENABLE_FIRMWARE_SIG
ecc_key eccKey;
WC_RNG rng;
wc_InitRng(&rng);
#endif
/* Verify file can be loaded */
rc = mqtt_file_load(fwFile, &fwBuf, &fwLen);
if (rc < 0 || fwLen == 0 || fwBuf == NULL) {
PRINTF("Firmware File %s Load Error!", fwFile);
mqtt_show_usage(mqttCtx);
goto exit;
}
PRINTF("Firmware File %s is %d bytes", fwFile, fwLen);
#ifdef ENABLE_FIRMWARE_SIG
/* Generate Key */
/* Note: Real implementation would use previously exchanged/signed key */
wc_ecc_init(&eccKey);
rc = wc_ecc_make_key(&rng, 32, &eccKey);
if (rc != 0) {
PRINTF("Make ECC Key Failed! %d", rc);
goto exit;
}
keyLen = ECC_BUFSIZE;
keyBuf = (byte*)WOLFMQTT_MALLOC(keyLen);
if (!keyBuf) {
PRINTF("Key malloc failed! %d", keyLen);
rc = EXIT_FAILURE;
goto exit;
}
rc = wc_ecc_export_x963(&eccKey, keyBuf, &keyLen);
if (rc != 0) {
PRINTF("ECC public key x963 export failed! %d", rc);
goto exit;
}
/* Sign Firmware */
rc = wc_SignatureGetSize(FIRMWARE_SIG_TYPE, &eccKey, sizeof(eccKey));
if (rc <= 0) {
PRINTF("Signature type %d not supported!", FIRMWARE_SIG_TYPE);
rc = EXIT_FAILURE;
goto exit;
}
sigLen = rc;
sigBuf = (byte*)WOLFMQTT_MALLOC(sigLen);
if (!sigBuf) {
PRINTF("Signature malloc failed!");
rc = EXIT_FAILURE;
goto exit;
}
#endif
/* Display lengths */
PRINTF("Firmware Message: Sig %d bytes, Key %d bytes, File %d bytes",
sigLen, keyLen, fwLen);
#ifdef ENABLE_FIRMWARE_SIG
/* Generate Signature */
rc = wc_SignatureGenerate(
FIRMWARE_HASH_TYPE, FIRMWARE_SIG_TYPE,
fwBuf, fwLen,
sigBuf, &sigLen,
&eccKey, sizeof(eccKey),
&rng);
if (rc != 0) {
PRINTF("Signature Generate Failed! %d", rc);
rc = EXIT_FAILURE;
goto exit;
}
#endif
/* Assemble message */
msgLen = sizeof(FirmwareHeader) + sigLen + keyLen + fwLen;
/* The firmware will be copied by the callback */
msgBuf = (byte*)WOLFMQTT_MALLOC(msgLen - fwLen);
if (!msgBuf) {
PRINTF("Message malloc failed! %d", msgLen);
rc = EXIT_FAILURE;
goto exit;
}
header = (FirmwareHeader*)msgBuf;
header->sigLen = sigLen;
header->pubKeyLen = keyLen;
header->fwLen = fwLen;
if (sigLen > 0)
XMEMCPY(&msgBuf[sizeof(FirmwareHeader)], sigBuf, sigLen);
if (keyLen > 0)
XMEMCPY(&msgBuf[sizeof(FirmwareHeader) + sigLen], keyBuf, keyLen);
rc = 0;
exit:
if (rc == 0) {
/* Return values */
if (p_msgBuf) {
*p_msgBuf = msgBuf;
}
else {
if (msgBuf) WOLFMQTT_FREE(msgBuf);
}
if (p_msgLen) *p_msgLen = msgLen;
}
else {
if (msgBuf) WOLFMQTT_FREE(msgBuf);
}
/* Free resources */
if (keyBuf) WOLFMQTT_FREE(keyBuf);
if (sigBuf) WOLFMQTT_FREE(sigBuf);
if (fwBuf) WOLFMQTT_FREE(fwBuf);
#ifdef ENABLE_FIRMWARE_SIG
wc_ecc_free(&eccKey);
wc_FreeRng(&rng);
#endif
return rc;
}
int fwpush_test(MQTTCtx *mqttCtx)
{
int rc;
FwpushCBdata* cbData = NULL;
if (mqttCtx == NULL) {
return MQTT_CODE_ERROR_BAD_ARG;
}
/* restore callback data */
cbData = (FwpushCBdata*)mqttCtx->publish.ctx;
/* check for stop */
if (mStopRead) {
rc = MQTT_CODE_SUCCESS;
PRINTF("MQTT Exiting...");
mStopRead = 0;
goto disconn;
}
switch (mqttCtx->stat)
{
case WMQ_BEGIN:
{
PRINTF("MQTT Firmware Push Client: QoS %d, Use TLS %d",
mqttCtx->qos, mqttCtx->use_tls);
}
FALL_THROUGH;
case WMQ_NET_INIT:
{
mqttCtx->stat = WMQ_NET_INIT;
/* Initialize Network */
rc = MqttClientNet_Init(&mqttCtx->net, mqttCtx);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Net Init: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto exit;
}
/* setup tx/rx buffers */
mqttCtx->tx_buf = (byte*)WOLFMQTT_MALLOC(MAX_BUFFER_SIZE);
mqttCtx->rx_buf = (byte*)WOLFMQTT_MALLOC(MAX_BUFFER_SIZE);
}
FALL_THROUGH;
case WMQ_INIT:
{
mqttCtx->stat = WMQ_INIT;
/* Initialize MqttClient structure */
rc = MqttClient_Init(&mqttCtx->client, &mqttCtx->net,
mqtt_message_cb,
mqttCtx->tx_buf, MAX_BUFFER_SIZE,
mqttCtx->rx_buf, MAX_BUFFER_SIZE,
mqttCtx->cmd_timeout_ms);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Init: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto exit;
}
mqttCtx->client.ctx = mqttCtx;
}
FALL_THROUGH;
case WMQ_TCP_CONN:
{
mqttCtx->stat = WMQ_TCP_CONN;
/* Connect to broker */
rc = MqttClient_NetConnect(&mqttCtx->client, mqttCtx->host,
mqttCtx->port, DEFAULT_CON_TIMEOUT_MS, mqttCtx->use_tls,
mqtt_tls_cb);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Socket Connect: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto exit;
}
/* Build connect packet */
XMEMSET(&mqttCtx->connect, 0, sizeof(MqttConnect));
mqttCtx->connect.keep_alive_sec = mqttCtx->keep_alive_sec;
mqttCtx->connect.clean_session = mqttCtx->clean_session;
mqttCtx->connect.client_id = mqttCtx->client_id;
if (mqttCtx->enable_lwt) {
/* Send client id in LWT payload */
mqttCtx->lwt_msg.qos = mqttCtx->qos;
mqttCtx->lwt_msg.retain = 0;
mqttCtx->lwt_msg.topic_name = FIRMWARE_TOPIC_NAME"lwttopic";
mqttCtx->lwt_msg.buffer = (byte*)mqttCtx->client_id;
mqttCtx->lwt_msg.total_len =
(word16)XSTRLEN(mqttCtx->client_id);
}
/* Optional authentication */
mqttCtx->connect.username = mqttCtx->username;
mqttCtx->connect.password = mqttCtx->password;
}
FALL_THROUGH;
case WMQ_MQTT_CONN:
{
mqttCtx->stat = WMQ_MQTT_CONN;
/* Send Connect and wait for Connect Ack */
rc = MqttClient_Connect(&mqttCtx->client, &mqttCtx->connect);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Connect: Proto (%s), %s (%d)",
MqttClient_GetProtocolVersionString(&mqttCtx->client),
MqttClient_ReturnCodeToString(rc), rc);
/* Validate Connect Ack info */
PRINTF("MQTT Connect Ack: Return Code %u, Session Present %d",
mqttCtx->connect.ack.return_code,
(mqttCtx->connect.ack.flags &
MQTT_CONNECT_ACK_FLAG_SESSION_PRESENT) ?
1 : 0
);
if (rc != MQTT_CODE_SUCCESS) {
goto disconn;
}
/* setup publish message */
XMEMSET(&mqttCtx->publish, 0, sizeof(MqttPublish));
mqttCtx->publish.retain = mqttCtx->retain;
mqttCtx->publish.qos = mqttCtx->qos;
mqttCtx->publish.duplicate = 0;
mqttCtx->publish.topic_name = mqttCtx->topic_name;
mqttCtx->publish.packet_id = mqtt_get_packetid();
mqttCtx->publish.buffer_len = FIRMWARE_MAX_BUFFER;
mqttCtx->publish.buffer = (byte*)WOLFMQTT_MALLOC(FIRMWARE_MAX_BUFFER);
if (mqttCtx->publish.buffer == NULL) {
rc = MQTT_CODE_ERROR_OUT_OF_BUFFER;
goto disconn;
}
/* Calculate the total payload length and store the FirmwareHeader,
* signature, and key in FwpushCBdata structure to be used by the
* callback. */
cbData = (FwpushCBdata*)WOLFMQTT_MALLOC(sizeof(FwpushCBdata));
if (cbData == NULL) {
rc = MQTT_CODE_ERROR_OUT_OF_BUFFER;
goto disconn;
}
XMEMSET(cbData, 0, sizeof(FwpushCBdata));
cbData->filename = mqttCtx->pub_file;
rc = fw_message_build(mqttCtx, cbData->filename, &cbData->data,
(int*)&mqttCtx->publish.total_len);
/* The publish->ctx is available for use by the application to pass
* data to the callback routine. */
mqttCtx->publish.ctx = cbData;
if (rc != 0) {
PRINTF("Firmware message build failed! %d", rc);
exit(rc);
}
}
FALL_THROUGH;
case WMQ_PUB:
{
mqttCtx->stat = WMQ_PUB;
/* Publish using the callback version of the publish API. This
allows the callback to write the payload data, in this case the
FirmwareHeader stored in the publish->ctx and the firmware file.
The callback will be executed multiple times until the entire
payload in sent. */
rc = MqttClient_Publish_ex(&mqttCtx->client, &mqttCtx->publish,
mqtt_publish_cb);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Publish: Topic %s, ID %d, %s (%d)",
mqttCtx->publish.topic_name, mqttCtx->publish.packet_id,
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto disconn;
}
}
FALL_THROUGH;
case WMQ_DISCONNECT:
{
mqttCtx->stat = WMQ_DISCONNECT;
/* Disconnect */
rc = MqttClient_Disconnect(&mqttCtx->client);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Disconnect: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
if (rc != MQTT_CODE_SUCCESS) {
goto disconn;
}
}
FALL_THROUGH;
case WMQ_NET_DISCONNECT:
{
mqttCtx->stat = WMQ_NET_DISCONNECT;
rc = MqttClient_NetDisconnect(&mqttCtx->client);
if (rc == MQTT_CODE_CONTINUE) {
return rc;
}
PRINTF("MQTT Socket Disconnect: %s (%d)",
MqttClient_ReturnCodeToString(rc), rc);
}
FALL_THROUGH;
case WMQ_DONE:
{
mqttCtx->stat = WMQ_DONE;
rc = mqttCtx->return_code;
goto exit;
}
case WMQ_SUB:
case WMQ_WAIT_MSG:
case WMQ_UNSUB:
case WMQ_PING:
default:
rc = MQTT_CODE_ERROR_STAT;
goto exit;
} /* switch */
disconn:
mqttCtx->stat = WMQ_NET_DISCONNECT;
mqttCtx->return_code = rc;
rc = MQTT_CODE_CONTINUE;
exit:
if (rc != MQTT_CODE_CONTINUE) {
if (cbData) {
if (cbData->fp) fclose(cbData->fp);
if (cbData->data) WOLFMQTT_FREE(cbData->data);
WOLFMQTT_FREE(cbData);
}
if (mqttCtx->publish.buffer) WOLFMQTT_FREE(mqttCtx->publish.buffer);
if (mqttCtx->tx_buf) WOLFMQTT_FREE(mqttCtx->tx_buf);
if (mqttCtx->rx_buf) WOLFMQTT_FREE(mqttCtx->rx_buf);
/* Cleanup network */
MqttClientNet_DeInit(&mqttCtx->net);
MqttClient_DeInit(&mqttCtx->client);
}
return rc;
}
/* so overall tests can pull in test function */
#ifdef USE_WINDOWS_API
#include <windows.h> /* for ctrl handler */
static BOOL CtrlHandler(DWORD fdwCtrlType)
{
if (fdwCtrlType == CTRL_C_EVENT) {
#if defined(ENABLE_FIRMWARE_SIG)
mStopRead = 1;
#endif
PRINTF("Received Ctrl+c");
return TRUE;
}
return FALSE;
}
#elif HAVE_SIGNAL
#include <signal.h>
static void sig_handler(int signo)
{
if (signo == SIGINT) {
#if defined(ENABLE_FIRMWARE_SIG)
mStopRead = 1;
#endif
PRINTF("Received SIGINT");
}
}
#endif
#if defined(NO_MAIN_DRIVER)
int fwpush_main(int argc, char** argv)
#else
int main(int argc, char** argv)
#endif
{
int rc;
MQTTCtx mqttCtx;
/* init defaults */
mqtt_init_ctx(&mqttCtx);
mqttCtx.app_name = "fwpush";
mqttCtx.client_id = mqtt_append_random(FIRMWARE_PUSH_CLIENT_ID,
(word32)XSTRLEN(FIRMWARE_PUSH_CLIENT_ID));
mqttCtx.dynamicClientId = 1;
mqttCtx.topic_name = FIRMWARE_TOPIC_NAME;
mqttCtx.qos = FIRMWARE_MQTT_QOS;
mqttCtx.pub_file = FIRMWARE_PUSH_DEF_FILE;
/* parse arguments */
rc = mqtt_parse_args(&mqttCtx, argc, argv);
if (rc != 0) {
return rc;
}
#ifdef USE_WINDOWS_API
if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE) == FALSE) {
PRINTF("Error setting Ctrl Handler! Error %d", (int)GetLastError());
}
#elif HAVE_SIGNAL
if (signal(SIGINT, sig_handler) == SIG_ERR) {
PRINTF("Can't catch SIGINT");
}
#endif
do {
rc = fwpush_test(&mqttCtx);
} while (!mStopRead && rc == MQTT_CODE_CONTINUE);
mqtt_free_ctx(&mqttCtx);
return (rc == 0) ? 0 : EXIT_FAILURE;
}

View File

@ -0,0 +1,45 @@
/* fwpush.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_FWPUSH_H
#define WOLFMQTT_FWPUSH_H
#include "mqttexample.h"
#define FIRMWARE_PUSH_CLIENT_ID "WolfMQTTFwPush"
#define FIRMWARE_PUSH_DEF_FILE "./app/image_v10_signed.bin"
/* Structure to pass into the publish callback
* using the publish->ctx pointer */
typedef struct FwpushCBdata_s {
const char *filename;
byte *data;
FILE *fp;
} FwpushCBdata;
/* Exposed functions */
int fwpush_test(MQTTCtx *mqttCtx);
#if defined(NO_MAIN_DRIVER)
int fwpush_main(int argc, char** argv);
#endif
#endif /* WOLFMQTT_FWPUSH_H */

View File

@ -0,0 +1,934 @@
/* mqttexample.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Include the autoconf generated config.h */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "wolfmqtt/mqtt_client.h"
#include "mqttexample.h"
#include "mqttnet.h"
#include "mqttport.h"
/* locals */
static volatile word16 mPacketIdLast;
static const char* kDefTopicName = DEFAULT_TOPIC_NAME;
static const char* kDefClientId = DEFAULT_CLIENT_ID;
/* argument parsing */
static int myoptind = 0;
static char* myoptarg = NULL;
#ifdef ENABLE_MQTT_TLS
#ifdef HAVE_SNI
static int useSNI;
static const char* mTlsSniHostName = NULL;
#endif
#ifdef HAVE_PQC
static const char* mTlsPQAlg = NULL;
#endif
#endif /* ENABLE_MQTT_TLS */
static int mygetopt(int argc, char** argv, const char* optstring)
{
static char* next = NULL;
char c;
char* cp;
if (myoptind == 0)
next = NULL; /* we're starting new/over */
if (next == NULL || *next == '\0') {
if (myoptind == 0)
myoptind++;
if (myoptind >= argc || argv[myoptind][0] != '-' ||
argv[myoptind][1] == '\0') {
myoptarg = NULL;
if (myoptind < argc)
myoptarg = argv[myoptind];
return -1;
}
if (XSTRNCMP(argv[myoptind], "--", 2) == 0) {
myoptind++;
myoptarg = NULL;
if (myoptind < argc)
myoptarg = argv[myoptind];
return -1;
}
next = argv[myoptind];
next++; /* skip - */
myoptind++;
}
c = *next++;
/* The C++ strchr can return a different value */
cp = (char*)XSTRCHR(optstring, c);
if (cp == NULL || c == ':')
return '?';
cp++;
if (*cp == ':') {
if (*next != '\0') {
myoptarg = next;
next = NULL;
}
else if (myoptind < argc) {
myoptarg = argv[myoptind];
myoptind++;
}
else
return '?';
}
else if (*cp == ';') {
myoptarg = (char*)"";
if (*next != '\0') {
myoptarg = next;
next = NULL;
}
else if (myoptind < argc) {
/* Check if next argument is not a parameter argument */
if (argv[myoptind] && argv[myoptind][0] != '-') {
myoptarg = argv[myoptind];
myoptind++;
}
}
}
return c;
}
/* used for testing only, requires wolfSSL RNG */
#ifdef ENABLE_MQTT_TLS
#include <wolfssl/wolfcrypt/random.h>
#endif
static int mqtt_get_rand(byte* data, word32 len)
{
int ret = -1;
#ifdef ENABLE_MQTT_TLS
WC_RNG rng;
ret = wc_InitRng(&rng);
if (ret == 0) {
ret = wc_RNG_GenerateBlock(&rng, data, len);
wc_FreeRng(&rng);
}
#elif defined(HAVE_RAND)
word32 i;
for (i = 0; i<len; i++) {
data[i] = (byte)rand();
}
ret = 0; /* success */
#endif
return ret;
}
int mqtt_fill_random_hexstr(char* buf, word32 bufLen)
{
int rc = 0;
word32 pos = 0, sz, i;
const char kHexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
byte rndBytes[32]; /* fill up to x bytes at a time */
while (rc == 0 && pos < bufLen) {
sz = bufLen - pos;
if (sz > (int)sizeof(rndBytes))
sz = (int)sizeof(rndBytes);
sz /= 2; /* 1 byte expands to 2 bytes */
rc = mqtt_get_rand(rndBytes, sz);
if (rc == 0) {
/* Convert random to hex string */
for (i=0; i<sz; i++) {
byte in = rndBytes[i];
buf[pos + (i*2)] = kHexChar[in >> 4];
buf[pos + (i*2)+1] = kHexChar[in & 0xf];
}
pos += sz*2;
}
else {
PRINTF("MQTT Fill Random Failed! %d", rc);
}
}
return rc;
}
#ifndef TEST_RAND_SZ
#define TEST_RAND_SZ 4
#endif
char* mqtt_append_random(const char* inStr, word32 inLen)
{
int rc = 0;
char *tmp;
tmp = (char*)WOLFMQTT_MALLOC(inLen + 1 + (TEST_RAND_SZ*2) + 1);
if (tmp == NULL) {
rc = MQTT_CODE_ERROR_MEMORY;
}
if (rc == 0) {
/* Format: inStr + `_` randhex + null term */
XMEMCPY(tmp, inStr, inLen);
tmp[inLen] = '_';
rc = mqtt_fill_random_hexstr(tmp + inLen + 1, (TEST_RAND_SZ*2));
tmp[inLen + 1 + (TEST_RAND_SZ*2)] = '\0'; /* null term */
}
if (rc != 0) {
WOLFMQTT_FREE(tmp);
tmp = NULL;
}
return tmp;
}
void mqtt_show_usage(MQTTCtx* mqttCtx)
{
PRINTF("%s:", mqttCtx->app_name);
PRINTF("-? Help, print this usage");
PRINTF("-h <host> Host to connect to, default: %s",
mqttCtx->host);
#ifdef ENABLE_MQTT_TLS
PRINTF("-p <num> Port to connect on, default: Normal %d, TLS %d",
MQTT_DEFAULT_PORT, MQTT_SECURE_PORT);
PRINTF("-t Enable TLS"); /* Note: this string is used in test
* scripts to detect TLS feature */
PRINTF("-A <file> Load CA (validate peer)");
PRINTF("-K <key> Use private key (for TLS mutual auth)");
PRINTF("-c <cert> Use certificate (for TLS mutual auth)");
#ifndef ENABLE_MQTT_CURL
#ifdef HAVE_SNI
/* Remove SNI args for sn-client */
if(XSTRNCMP(mqttCtx->app_name, "sn-client", 10)){
PRINTF("-S <str> Use Host Name Indication, blank defaults to host");
}
#endif /* HAVE_SNI */
#ifdef HAVE_PQC
PRINTF("-Q <str> Use Key Share with post-quantum algorithm");
#endif /* HAVE_PQC */
#endif /* !ENABLE_MQTT_CURL */
PRINTF("-p <num> Port to connect on, default: %d",
MQTT_DEFAULT_PORT);
#endif
PRINTF("-q <num> Qos Level 0-2, default: %d",
mqttCtx->qos);
PRINTF("-s Disable clean session connect flag");
PRINTF("-k <num> Keep alive seconds, default: %d",
mqttCtx->keep_alive_sec);
PRINTF("-i <id> Client Id, default: %s",
mqttCtx->client_id);
PRINTF("-l Enable LWT (Last Will and Testament)");
PRINTF("-u <str> Username");
PRINTF("-w <str> Password");
if (mqttCtx->message) {
/* Only mqttclient example can set message from CLI */
PRINTF("-m <str> Message, default: %s", mqttCtx->message);
}
PRINTF("-n <str> Topic name, default: %s", mqttCtx->topic_name);
PRINTF("-r Set Retain flag on publish message");
PRINTF("-C <num> Command Timeout, default: %dms",
mqttCtx->cmd_timeout_ms);
#ifdef WOLFMQTT_V5
PRINTF("-P <num> Max packet size the client will accept, default: %d",
DEFAULT_MAX_PKT_SZ);
#endif
PRINTF("-T Test mode");
PRINTF("-x Skip subscribe (for testing session persistence)");
PRINTF("-R <file> Ready file (touched when subscribed, for test sync)");
PRINTF("-f <file> Use file contents for publish");
if (!mqttCtx->debug_on) {
PRINTF("-d Enable example debug messages");
}
}
void mqtt_init_ctx(MQTTCtx* mqttCtx)
{
XMEMSET(mqttCtx, 0, sizeof(MQTTCtx));
mqttCtx->host = DEFAULT_MQTT_HOST;
mqttCtx->qos = DEFAULT_MQTT_QOS;
mqttCtx->clean_session = 1;
mqttCtx->keep_alive_sec = DEFAULT_KEEP_ALIVE_SEC;
mqttCtx->client_id = kDefClientId;
mqttCtx->topic_name = kDefTopicName;
mqttCtx->cmd_timeout_ms = DEFAULT_CMD_TIMEOUT_MS;
mqttCtx->debug_on = 1;
#ifdef WOLFMQTT_V5
mqttCtx->max_packet_size = DEFAULT_MAX_PKT_SZ;
mqttCtx->topic_alias = 1;
mqttCtx->topic_alias_max = 1;
#endif
#ifdef WOLFMQTT_DEFAULT_TLS
mqttCtx->use_tls = WOLFMQTT_DEFAULT_TLS;
#endif
#ifdef ENABLE_MQTT_TLS
mqttCtx->ca_file = NULL;
mqttCtx->mtls_keyfile = NULL;
mqttCtx->mtls_certfile = NULL;
#endif
mqttCtx->app_name = "mqttclient";
mqttCtx->message = DEFAULT_MESSAGE;
}
int mqtt_parse_args(MQTTCtx* mqttCtx, int argc, char** argv)
{
int rc;
#ifdef ENABLE_MQTT_TLS
#ifdef ENABLE_MQTT_CURL
#define MQTT_TLS_ARGS "c:A:K:"
#else
#define MQTT_TLS_ARGS "c:A:K:S;Q:"
#endif
#else
#define MQTT_TLS_ARGS ""
#endif
#ifdef WOLFMQTT_V5
#define MQTT_V5_ARGS "P:"
#else
#define MQTT_V5_ARGS ""
#endif
while ((rc = mygetopt(argc, argv, "?h:p:q:sk:i:lu:w:m:n:C:Tf:rtdxR:" \
MQTT_TLS_ARGS MQTT_V5_ARGS)) != -1) {
switch ((char)rc) {
case '?' :
mqtt_show_usage(mqttCtx);
return MY_EX_USAGE;
case 'h' :
mqttCtx->host = myoptarg;
break;
case 'p' :
mqttCtx->port = (word16)XATOI(myoptarg);
if (mqttCtx->port == 0) {
return err_sys("Invalid Port Number!");
}
break;
case 'q' :
mqttCtx->qos = (MqttQoS)((byte)XATOI(myoptarg));
if (mqttCtx->qos > MQTT_QOS_2) {
return err_sys("Invalid QoS value!");
}
break;
case 's':
mqttCtx->clean_session = 0;
break;
case 'k':
mqttCtx->keep_alive_sec = XATOI(myoptarg);
break;
case 'i':
mqttCtx->client_id = myoptarg;
break;
case 'l':
mqttCtx->enable_lwt = 1;
break;
case 'u':
mqttCtx->username = myoptarg;
break;
case 'w':
mqttCtx->password = myoptarg;
break;
case 'm':
mqttCtx->message = myoptarg;
break;
case 'n':
mqttCtx->topic_name = myoptarg;
break;
case 'C':
mqttCtx->cmd_timeout_ms = XATOI(myoptarg);
break;
case 'T':
mqttCtx->test_mode = 1;
break;
case 'f':
mqttCtx->pub_file = myoptarg;
break;
case 'r':
mqttCtx->retain = 1;
break;
case 't':
mqttCtx->use_tls = 1;
break;
case 'd':
mqttCtx->debug_on = 1;
break;
case 'x':
mqttCtx->skip_subscribe = 1;
break;
case 'R':
mqttCtx->ready_file = myoptarg;
break;
#ifdef ENABLE_MQTT_TLS
case 'A':
mqttCtx->ca_file = myoptarg;
break;
case 'c':
mqttCtx->mtls_certfile = myoptarg;
break;
case 'K':
mqttCtx->mtls_keyfile = myoptarg;
break;
#ifndef ENABLE_MQTT_CURL
case 'S':
#ifdef HAVE_SNI
useSNI = 1;
mTlsSniHostName = myoptarg;
#else
PRINTF("To use '-S', enable SNI in wolfSSL");
#endif
break;
case 'Q':
#ifdef HAVE_PQC
mTlsPQAlg = myoptarg;
#else
PRINTF("To use '-Q', build wolfSSL with --enable-mlkem --enable-dilithium");
#endif
break;
#endif /* !ENABLE_MQTT_CURL */
#endif /* ENABLE_MQTT_TLS */
#ifdef WOLFMQTT_V5
case 'P':
mqttCtx->max_packet_size = XATOI(myoptarg);
break;
#endif
default:
mqtt_show_usage(mqttCtx);
return MY_EX_USAGE;
}
/* Remove SNI functionality for sn-client */
if(!XSTRNCMP(mqttCtx->app_name, "sn-client", 10)){
#ifdef HAVE_SNI
useSNI=0;
#endif
}
}
rc = 0;
myoptind = 0; /* reset for test cases */
/* if TLS not enable, check args */
#ifndef ENABLE_MQTT_TLS
if (mqttCtx->use_tls) {
PRINTF("Use TLS option not allowed (TLS not compiled in)");
mqttCtx->use_tls = 0;
if (mqttCtx->test_mode) {
return MY_EX_USAGE;
}
}
#endif
#ifdef HAVE_SNI
if ((useSNI == 1) && (XSTRLEN(mTlsSniHostName) == 0)) {
/* Set SNI host name to host if -S was blank */
mTlsSniHostName = mqttCtx->host;
}
#endif
/* for test mode only */
/* add random data to end of client_id and topic_name */
if (mqttCtx->test_mode && mqttCtx->topic_name == kDefTopicName) {
char* topic_name = mqtt_append_random(kDefTopicName,
(word32)XSTRLEN(kDefTopicName));
if (topic_name) {
mqttCtx->topic_name = (const char*)topic_name;
mqttCtx->dynamicTopic = 1;
}
}
if (mqttCtx->test_mode && mqttCtx->client_id == kDefClientId) {
char* client_id = mqtt_append_random(kDefClientId,
(word32)XSTRLEN(kDefClientId));
if (client_id) {
mqttCtx->client_id = (const char*)client_id;
mqttCtx->dynamicClientId = 1;
}
}
return rc;
}
void mqtt_free_ctx(MQTTCtx* mqttCtx)
{
if (mqttCtx == NULL) {
return;
}
if (mqttCtx->dynamicTopic && mqttCtx->topic_name) {
WOLFMQTT_FREE((char*)mqttCtx->topic_name);
mqttCtx->topic_name = NULL;
}
if (mqttCtx->dynamicClientId && mqttCtx->client_id) {
WOLFMQTT_FREE((char*)mqttCtx->client_id);
mqttCtx->client_id = NULL;
}
}
#if defined(__GNUC__) && !defined(NO_EXIT) && !defined(WOLFMQTT_ZEPHYR)
__attribute__ ((noreturn))
#endif
int err_sys(const char* msg)
{
if (msg) {
PRINTF("wolfMQTT error: %s", msg);
}
exit(EXIT_FAILURE);
#ifdef WOLFMQTT_ZEPHYR
/* Zephyr compiler produces below warning. Let's silence it.
* warning: 'noreturn' function does return
* 477 | }
* | ^
*/
return 0;
#endif
}
word16 mqtt_get_packetid(void)
{
/* Check rollover */
if (mPacketIdLast >= MAX_PACKET_ID) {
mPacketIdLast = 0;
}
return ++mPacketIdLast;
}
#ifdef WOLFMQTT_NONBLOCK
#if defined(MICROCHIP_MPLAB_HARMONY)
#include <system/tmr/sys_tmr.h>
#else
#include <time.h>
#endif
static word32 mqtt_get_timer_seconds(void)
{
word32 timer_sec = 0;
#if defined(MICROCHIP_MPLAB_HARMONY)
timer_sec = (word32)(SYS_TMR_TickCountGet() /
SYS_TMR_TickCounterFrequencyGet());
#else
/* Posix style time */
timer_sec = (word32)time(0);
#endif
return timer_sec;
}
int mqtt_check_timeout(int rc, word32* start_sec, word32 timeout_sec)
{
word32 elapsed_sec;
/* if start seconds not set or is not continue */
if (*start_sec == 0 || rc != MQTT_CODE_CONTINUE) {
*start_sec = mqtt_get_timer_seconds();
return rc;
}
/* Default to 2s timeout. This function sometimes incorrectly
* triggers if 1s is used because of rounding. */
if (timeout_sec == 0) {
timeout_sec = DEFAULT_CHK_TIMEOUT_S;
}
elapsed_sec = mqtt_get_timer_seconds();
if (*start_sec < elapsed_sec) {
elapsed_sec -= *start_sec;
if (elapsed_sec >= timeout_sec) {
*start_sec = mqtt_get_timer_seconds();
PRINTF("Timeout timer %d seconds", timeout_sec);
return MQTT_CODE_ERROR_TIMEOUT;
}
}
return rc;
}
#endif /* WOLFMQTT_NONBLOCK */
#if defined(ENABLE_MQTT_TLS) && !defined(EXTERNAL_MQTT_TLS_CALLBACK)
#ifdef WOLFSSL_ENCRYPTED_KEYS
int mqtt_password_cb(char* passwd, int sz, int rw, void* userdata)
{
(void)rw;
(void)userdata;
if (userdata != NULL) {
XSTRNCPY(passwd, (char*)userdata, sz);
return (int)XSTRLEN((char*)userdata);
}
else {
XSTRNCPY(passwd, "yassl123", sz);
return (int)XSTRLEN(passwd);
}
}
#endif
static int mqtt_tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
{
char buffer[WOLFSSL_MAX_ERROR_SZ];
MQTTCtx *mqttCtx = NULL;
char appName[PRINT_BUFFER_SIZE] = {0};
if (store->userCtx != NULL) {
/* The client.ctx was stored during MqttSocket_Connect. */
mqttCtx = (MQTTCtx *)store->userCtx;
XSTRNCPY(appName, " for ", PRINT_BUFFER_SIZE-1);
XSTRNCAT(appName, mqttCtx->app_name,
PRINT_BUFFER_SIZE-XSTRLEN(appName)-1);
}
PRINTF("MQTT TLS Verify Callback%s: PreVerify %d, Error %d (%s)",
appName, preverify,
store->error, store->error != 0 ?
wolfSSL_ERR_error_string(store->error, buffer) : "none");
PRINTF(" Subject's domain name is %s", store->domain);
if (store->error != 0) {
/* Allowing to continue */
/* Should check certificate and return 0 if not okay */
PRINTF(" Allowing cert anyways");
}
return 1;
}
/* Use this callback to setup TLS certificates and verify callbacks */
int mqtt_tls_cb(MqttClient* client)
{
int rc = WOLFSSL_FAILURE;
SocketContext * sock = (SocketContext *)client->net->context;
/* Use highest available and allow downgrade. If wolfSSL is built with
* old TLS support, it is possible for a server to force a downgrade to
* an insecure version. */
client->tls.ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
if (client->tls.ctx) {
wolfSSL_CTX_set_verify(client->tls.ctx, WOLFSSL_VERIFY_PEER,
mqtt_tls_verify_cb);
/* default to success */
rc = WOLFSSL_SUCCESS;
#if !defined(NO_CERT)
#if !defined(NO_FILESYSTEM)
if (sock->mqttCtx->ca_file) {
/* Load CA certificate file */
rc = wolfSSL_CTX_load_verify_locations(client->tls.ctx,
sock->mqttCtx->ca_file, NULL);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading CA %s: %d (%s)", sock->mqttCtx->ca_file,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
if (sock->mqttCtx->mtls_certfile && sock->mqttCtx->mtls_keyfile) {
/* Load If using a mutual authentication */
rc = wolfSSL_CTX_use_certificate_file(client->tls.ctx,
sock->mqttCtx->mtls_certfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading certificate %s: %d (%s)",
sock->mqttCtx->mtls_certfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
#ifdef WOLFSSL_ENCRYPTED_KEYS
/* Setup password callback for pkcs8 key */
wolfSSL_CTX_set_default_passwd_cb(client->tls.ctx,
mqtt_password_cb);
#endif
rc = wolfSSL_CTX_use_PrivateKey_file(client->tls.ctx,
sock->mqttCtx->mtls_keyfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading key %s: %d (%s)",
sock->mqttCtx->mtls_keyfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
#else
/* Note: Zephyr example uses NO_FILESYSTEM */
#ifdef WOLFSSL_ENCRYPTED_KEYS
/* Setup password callback for pkcs8 key */
wolfSSL_CTX_set_default_passwd_cb(client->tls.ctx,
mqtt_password_cb);
#endif
/* Examples for loading buffer directly */
/* Load CA certificate buffer */
rc = wolfSSL_CTX_load_verify_buffer_ex(client->tls.ctx,
(const byte*)root_ca, (long)sizeof(root_ca),
WOLFSSL_FILETYPE_ASN1, 0, WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY);
/* Load Client Cert */
if (rc == WOLFSSL_SUCCESS) {
rc = wolfSSL_CTX_use_certificate_buffer(client->tls.ctx,
(const byte*)device_cert, (long)sizeof(device_cert),
WOLFSSL_FILETYPE_ASN1);
}
/* Load Private Key */
if (rc == WOLFSSL_SUCCESS) {
rc = wolfSSL_CTX_use_PrivateKey_buffer(client->tls.ctx,
(const byte*)device_priv_key, (long)sizeof(device_priv_key),
WOLFSSL_FILETYPE_ASN1);
}
#endif /* !NO_FILESYSTEM */
#endif /* !NO_CERT */
#ifdef HAVE_SNI
if ((rc == WOLFSSL_SUCCESS) && (mTlsSniHostName != NULL)) {
rc = wolfSSL_CTX_UseSNI(client->tls.ctx, WOLFSSL_SNI_HOST_NAME,
mTlsSniHostName, (word16) XSTRLEN(mTlsSniHostName));
if (rc != WOLFSSL_SUCCESS) {
PRINTF("UseSNI failed");
}
}
#endif /* HAVE_SNI */
#ifdef HAVE_PQC
if ((rc == WOLFSSL_SUCCESS) && (mTlsPQAlg != NULL)) {
int group = 0;
if (XSTRCMP(mTlsPQAlg, "ML_KEM_768") == 0) {
group = WOLFSSL_ML_KEM_768;
} else if (XSTRCMP(mTlsPQAlg, "SecP384r1MLKEM768") == 0) {
group = WOLFSSL_SECP384R1MLKEM768;
} else {
PRINTF("Invalid post-quantum KEM specified");
}
if (group != 0) {
client->tls.ssl = wolfSSL_new(client->tls.ctx);
if (client->tls.ssl == NULL) {
rc = WOLFSSL_FAILURE;
}
if (rc == WOLFSSL_SUCCESS) {
rc = wolfSSL_UseKeyShare(client->tls.ssl, group);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Use key share failed");
}
}
}
}
#endif /* HAVE_PQC */
}
#if defined(NO_CERT) || defined(NO_FILESYSTEM)
(void)sock;
#endif
PRINTF("MQTT TLS Setup (%d)", rc);
return rc;
}
#ifdef WOLFMQTT_SN
int mqtt_dtls_cb(MqttClient* client) {
#ifdef WOLFSSL_DTLS
int rc = WOLFSSL_FAILURE;
SocketContext * sock = (SocketContext *)client->net->context;
client->tls.ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
if (client->tls.ctx) {
wolfSSL_CTX_set_verify(client->tls.ctx, WOLFSSL_VERIFY_PEER,
mqtt_tls_verify_cb);
/* default to success */
rc = WOLFSSL_SUCCESS;
#if !defined(NO_CERT) && !defined(NO_FILESYSTEM)
if (sock->mqttCtx->ca_file) {
/* Load CA certificate file */
rc = wolfSSL_CTX_load_verify_locations(client->tls.ctx,
sock->mqttCtx->ca_file, NULL);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading CA %s: %d (%s)", sock->mqttCtx->ca_file,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
if (sock->mqttCtx->mtls_certfile && sock->mqttCtx->mtls_keyfile) {
/* Load If using a mutual authentication */
rc = wolfSSL_CTX_use_certificate_file(client->tls.ctx,
sock->mqttCtx->mtls_certfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading certificate %s: %d (%s)",
sock->mqttCtx->mtls_certfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
rc = wolfSSL_CTX_use_PrivateKey_file(client->tls.ctx,
sock->mqttCtx->mtls_keyfile, WOLFSSL_FILETYPE_PEM);
if (rc != WOLFSSL_SUCCESS) {
PRINTF("Error loading key %s: %d (%s)",
sock->mqttCtx->mtls_keyfile,
rc, wolfSSL_ERR_reason_error_string(rc));
return rc;
}
}
#else
(void)sock;
#endif
client->tls.ssl = wolfSSL_new(client->tls.ctx);
if (client->tls.ssl == NULL) {
rc = WOLFSSL_FAILURE;
return rc;
}
}
PRINTF("MQTT DTLS Setup (%d)", rc);
#else /* WOLFSSL_DTLS */
(void)client;
int rc = 0;
PRINTF("MQTT DTLS Setup - Must enable DTLS in wolfSSL!");
#endif
return rc;
}
#endif /* WOLFMQTT_SN */
#else
int mqtt_tls_cb(MqttClient* client)
{
(void)client;
return 0;
}
#ifdef WOLFMQTT_SN
int mqtt_dtls_cb(MqttClient* client)
{
(void)client;
return 0;
}
#endif
#endif /* ENABLE_MQTT_TLS */
int mqtt_file_load(const char* filePath, byte** fileBuf, int *fileLen)
{
#if !defined(NO_FILESYSTEM)
int rc = 0;
XFILE file = NULL;
long int pos = -1L;
/* Check arguments */
if (filePath == NULL || XSTRLEN(filePath) == 0 || fileLen == NULL ||
fileBuf == NULL) {
return MQTT_CODE_ERROR_BAD_ARG;
}
/* Open file */
file = XFOPEN(filePath, "rb");
if (file == NULL) {
PRINTF("File '%s' does not exist!", filePath);
rc = EXIT_FAILURE;
goto exit;
}
/* Determine length of file */
if (XFSEEK(file, 0, XSEEK_END) != 0) {
PRINTF("fseek() failed");
rc = EXIT_FAILURE;
goto exit;
}
pos = (int)XFTELL(file);
if (pos == -1L) {
PRINTF("ftell() failed");
rc = EXIT_FAILURE;
goto exit;
}
*fileLen = (int)pos;
if (XFSEEK(file, 0, XSEEK_SET) != 0) {
PRINTF("fseek() failed");
rc = EXIT_FAILURE;
goto exit;
}
#ifdef DEBUG_WOLFMQTT
PRINTF("File %s is %d bytes", filePath, *fileLen);
#endif
/* Allocate buffer for image */
*fileBuf = (byte*)WOLFMQTT_MALLOC(*fileLen);
if (*fileBuf == NULL) {
PRINTF("File buffer malloc failed!");
rc = MQTT_CODE_ERROR_MEMORY;
goto exit;
}
/* Load file into buffer */
rc = (int)XFREAD(*fileBuf, 1, *fileLen, file);
if (rc != *fileLen) {
PRINTF("Error reading file! %d", rc);
rc = EXIT_FAILURE;
goto exit;
}
rc = 0; /* Success */
exit:
if (file) {
XFCLOSE(file);
}
if (rc != 0) {
if (*fileBuf) {
WOLFMQTT_FREE(*fileBuf);
*fileBuf = NULL;
}
}
return rc;
#else
(void)filePath;
(void)fileBuf;
(void)fileLen;
PRINTF("File system support is not configured.");
return EXIT_FAILURE;
#endif
}

View File

@ -0,0 +1,240 @@
/* mqttexample.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_EXAMPLE_H
#define WOLFMQTT_EXAMPLE_H
#include "wolfmqtt/mqtt_client.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Compatibility Options */
#ifdef NO_EXIT
#undef exit
#define exit(rc) return rc
#endif
#ifndef MY_EX_USAGE
#define MY_EX_USAGE 2 /* Exit reason code */
#endif
/* STDIN / FGETS for examples */
#ifndef WOLFMQTT_NO_STDIO
/* For Linux/Mac */
#if !defined(FREERTOS) && !defined(USE_WINDOWS_API) && \
!defined(FREESCALE_MQX) && !defined(FREESCALE_KSDK_MQX) && \
!defined(MICROCHIP_MPLAB_HARMONY) && !defined(WOLFMQTT_ZEPHYR)
/* Make sure its not explicitly disabled and not already defined */
#if !defined(WOLFMQTT_NO_STDIN_CAP) && \
!defined(WOLFMQTT_ENABLE_STDIN_CAP)
/* Wake on stdin activity */
#define WOLFMQTT_ENABLE_STDIN_CAP
#endif
#endif
#ifdef WOLFMQTT_ENABLE_STDIN_CAP
#ifndef XFGETS
#define XFGETS fgets
#endif
#ifndef STDIN
#define STDIN 0
#endif
#endif
#endif /* !WOLFMQTT_NO_STDIO */
/* Default Configurations */
#ifndef DEFAULT_MQTT_HOST
/* Default MQTT host broker to use,
* when none is specified in the examples */
#define DEFAULT_MQTT_HOST "broker.hivemq.com"
/* "iot.eclipse.org" */
/* "broker.emqx.io" */
/* "broker.hivemq.com" */
#endif
#define DEFAULT_CMD_TIMEOUT_MS 30000
#define DEFAULT_CON_TIMEOUT_MS 5000
#define DEFAULT_CHK_TIMEOUT_S 2
#define DEFAULT_MQTT_QOS MQTT_QOS_0
#define DEFAULT_KEEP_ALIVE_SEC 60
#define DEFAULT_CLIENT_ID "WolfMQTTClient"
#ifndef WOLFMQTT_TOPIC_NAME
#define WOLFMQTT_TOPIC_NAME "wolfMQTT/example/"
#define DEFAULT_TOPIC_NAME WOLFMQTT_TOPIC_NAME"testTopic"
#else
#define DEFAULT_TOPIC_NAME WOLFMQTT_TOPIC_NAME
#endif
#define DEFAULT_AUTH_METHOD "EXTERNAL"
#define PRINT_BUFFER_SIZE 80
#define DEFAULT_MESSAGE "test"
#ifdef WOLFMQTT_V5
#define DEFAULT_MAX_PKT_SZ 1024*1024 /* The max MQTT control packet size
the client is willing to accept. */
#define DEFAULT_SUB_ID 1 /* Sub ID starts at 1 */
#define DEFAULT_SESS_EXP_INT 0xFFFFFFFF
#endif
/* certs are either static or extern, depending on the specific example */
#ifndef EXTERNAL_MQTT_TLS_CALLBACK
#ifdef WOLFMQTT_EXTERN_CERT
#undef WOLFMQTT_EXAMPLE_CERT
#define WOLFMQTT_EXAMPLE_CERT /* init extern from mqttexample.h */
extern const char* root_ca;
extern const char* device_cert;
extern const char* device_priv_key;
#else
#undef WOLFMQTT_EXAMPLE_CERT
#define WOLFMQTT_EXAMPLE_CERT static
#endif
#endif /* !EXTERNAL_MQTT_TLS_CALLBACK */
/* MQTT Client state */
typedef enum _MQTTCtxState {
WMQ_BEGIN = 0,
WMQ_NET_INIT,
WMQ_INIT,
WMQ_TCP_CONN,
WMQ_MQTT_CONN,
WMQ_SUB,
WMQ_PUB,
WMQ_WAIT_MSG,
WMQ_PING,
WMQ_UNSUB,
WMQ_DISCONNECT,
WMQ_NET_DISCONNECT,
WMQ_DONE
} MQTTCtxState;
/* MQTT Client context */
/* This is used for the examples as reference */
/* Use of this structure allow non-blocking context */
typedef struct _MQTTCtx {
MQTTCtxState stat;
void* app_ctx; /* For storing application specific data */
/* client and net containers */
MqttClient client;
MqttNet net;
/* temp mqtt containers */
MqttConnect connect;
MqttMessage lwt_msg;
MqttSubscribe subscribe;
MqttUnsubscribe unsubscribe;
MqttTopic topics[1];
MqttPublish publish;
MqttDisconnect disconnect;
MqttPing ping;
#ifdef WOLFMQTT_SN
SN_Publish publishSN;
#endif
/* configuration */
MqttQoS qos;
const char* app_name;
const char* host;
const char* username;
const char* password;
const char* topic_name;
const char* message;
const char* pub_file;
const char* client_id;
#if defined (ENABLE_MQTT_TLS)
const char* ca_file;
const char* mtls_keyfile;
const char* mtls_certfile;
#endif
byte *tx_buf, *rx_buf;
int return_code;
int use_tls;
int retain;
int enable_lwt;
#ifdef WOLFMQTT_V5
int max_packet_size;
#endif
word32 cmd_timeout_ms;
#ifdef WOLFMQTT_NONBLOCK
word32 start_sec; /* used for timeout and keep-alive */
#endif
word16 keep_alive_sec;
word16 port;
#ifdef WOLFMQTT_V5
word16 topic_alias;
word16 topic_alias_max; /* Server property */
#endif
byte clean_session;
byte test_mode;
byte debug_on:1; /* enable debug messages in example */
#ifdef WOLFMQTT_V5
byte subId_not_avail; /* Server property */
byte enable_eauth; /* Enhanced authentication */
#endif
unsigned int dynamicTopic:1;
unsigned int dynamicClientId:1;
unsigned int skip_subscribe:1;
const char* ready_file; /* touch file when ready (e.g., after SUBACK) */
#ifdef WOLFMQTT_NONBLOCK
unsigned int useNonBlockMode:1; /* set to use non-blocking mode.
network callbacks can return MQTT_CODE_CONTINUE to indicate "would block" */
#endif
#ifdef WOLFMQTT_WOLFIP
struct wolfIP *stack; /* wolfIP TCP/IP stack instance */
#endif
} MQTTCtx;
void mqtt_show_usage(MQTTCtx* mqttCtx);
void mqtt_init_ctx(MQTTCtx* mqttCtx);
void mqtt_free_ctx(MQTTCtx* mqttCtx);
int mqtt_parse_args(MQTTCtx* mqttCtx, int argc, char** argv);
int err_sys(const char* msg);
int mqtt_tls_cb(MqttClient* client);
#ifdef WOLFMQTT_SN
int mqtt_dtls_cb(MqttClient* client);
#endif
word16 mqtt_get_packetid(void);
#ifdef WOLFMQTT_NONBLOCK
int mqtt_check_timeout(int rc, word32* start_sec, word32 timeout_sec);
#endif
int mqtt_fill_random_hexstr(char* buf, word32 bufLen);
char* mqtt_append_random(const char* inStr, word32 inLen);
int mqtt_file_load(const char* filePath, byte** fileBuf, int *fileLen);
#ifdef WOLFSSL_ENCRYPTED_KEYS
int mqtt_password_cb(char* passwd, int sz, int rw, void* userdata);
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLFMQTT_EXAMPLE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/* mqttnet.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_NET_H
#define WOLFMQTT_NET_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ENABLE_MQTT_CURL
#include <curl/curl.h>
#endif
#include "mqttexample.h"
#include "mqttport.h"
#if defined(HAVE_NETX) && !defined(WOLFMQTT_NO_NETX_DNS)
/* include the NetX DNS addon header */
#include "nxd_dns.h"
#endif
/* Local context for Net callbacks */
typedef enum {
SOCK_BEGIN = 0,
SOCK_CONN
} NB_Stat;
typedef struct _SocketContext {
SOCKET_T fd;
NB_Stat stat;
SOCK_ADDR_IN addr;
#ifdef MICROCHIP_MPLAB_HARMONY
word32 bytes;
#endif
#if defined(WOLFMQTT_MULTITHREAD) && defined(WOLFMQTT_ENABLE_STDIN_CAP)
/* "self pipe" -> signal wake sleep() */
SOCKET_T pfd[2];
#endif
#ifdef ENABLE_MQTT_CURL
CURL * curl;
int bytes; /* track partial read/write */
#endif
#ifdef ENABLE_MQTT_WEBSOCKET
void* websocket_ctx;
#endif
#ifdef HAVE_NETX
#ifndef WOLFMQTT_NO_NETX_DNS
NX_DNS *dnsPtr;
#endif
NX_IP *ipPtr;
NX_PACKET *nxPacket;
ULONG nxOffset;
#endif
#ifdef WOLFMQTT_WOLFIP
struct wolfIP *stack;
#endif
MQTTCtx* mqttCtx;
} SocketContext;
/* Functions used to handle the MqttNet structure creation / destruction */
int MqttClientNet_Init(MqttNet* net, MQTTCtx* mqttCtx);
int MqttClientNet_DeInit(MqttNet* net);
#ifdef WOLFMQTT_SN
int SN_ClientNet_Init(MqttNet* net, MQTTCtx* mqttCtx);
#endif
int MqttClientNet_Wake(MqttNet* net);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLFMQTT_NET_H */

View File

@ -0,0 +1,105 @@
/* mqttport.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Include the autoconf generated config.h */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "wolfmqtt/mqtt_client.h"
#include "mqttnet.h"
#include "mqttexample.h"
#include "mqttport.h"
#ifdef WOLFMQTT_ZEPHYR
#ifndef NO_FILESYSTEM
#ifndef WOLFSSL_ZEPHYR
XFILE z_fs_open(const char* filename, const char* mode)
{
XFILE file;
fs_mode_t flags = 0;
if (mode == NULL)
return NULL;
/* Parse mode */
switch (*mode++) {
case 'r':
flags |= FS_O_READ;
break;
case 'w':
flags |= FS_O_WRITE|FS_O_CREATE;
break;
case 'a':
flags |= FS_O_APPEND|FS_O_CREATE;
break;
default:
return NULL;
}
/* Ignore binary flag */
if (*mode == 'b')
mode++;
if (*mode == '+') {
flags |= FS_O_READ;
/* Don't add write flag if already appending */
if (!(flags & FS_O_APPEND))
flags |= FS_O_RDWR;
}
/* Ignore binary flag */
if (*mode == 'b')
mode++;
/* Incorrect mode string */
if (*mode != '\0')
return NULL;
file = (XFILE)WOLFMQTT_MALLOC(sizeof(*file));
if (file != NULL) {
if (fs_open(file, filename, flags) != 0) {
WOLFMQTT_FREE(file);
file = NULL;
}
}
return file;
}
int z_fs_close(XFILE file)
{
int ret;
if (file == NULL)
return -1;
ret = (fs_close(file) == 0) ? 0 : -1;
WOLFMQTT_FREE(file);
return ret;
}
#endif /* !WOLFSSL_ZEPHYR */
#endif /* !NO_FILESYSTEM */
#else
/* Default implementations */
#endif

View File

@ -0,0 +1,320 @@
/*
* mqttport.h
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfMQTT.
*
* wolfMQTT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfMQTT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFMQTT_PORT_H
#define WOLFMQTT_PORT_H
#ifdef __cplusplus
extern "C" {
#endif
/* FreeRTOS TCP */
#ifdef FREERTOS_TCP
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_DNS.h"
#include "FreeRTOS_Sockets.h"
#define SOCKET_T Socket_t
#define SOCK_ADDR_IN struct freertos_sockaddr
/* ToppersOS and LWIP */
#elif defined(TOPPERS) && defined(WOLFSSL_LWIP)
/* lwIP includes. */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
/* FreeRTOS and LWIP */
#elif defined(FREERTOS) && defined(WOLFSSL_LWIP)
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* lwIP includes. */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
/* LWIP only */
#elif defined(WOLFSSL_LWIP)
/* lwIP includes. */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
/* wolfIP TCP/IP stack */
#elif defined(WOLFMQTT_WOLFIP)
#include "wolfip.h"
#define SOCKET_T int
#define SOCKET_INVALID (-1)
#define SOCK_ADDR_IN struct wolfIP_sockaddr_in
/* For wolfIP targets without filesystem support, define NO_FILESYSTEM
* via build configuration (e.g., compiler flags or user_settings.h). */
#ifndef NO_FILESYSTEM
#define NO_FILESYSTEM
#endif
/* User defined IO */
#elif defined(WOLFMQTT_USER_IO)
#include "userio_template.h"
/* NetX */
#elif defined(HAVE_NETX)
#include "nx_api.h"
#define SOCKET_T NX_TCP_SOCKET
#define SOCK_ADDR_IN NXD_ADDRESS
/* Windows */
#elif defined(USE_WINDOWS_API)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#define SOCKET_T SOCKET
#ifdef _WIN32
#define SOERROR_T int
#else
#define SOERROR_T char
#endif
#define SELECT_FD(fd) (fd)
#ifndef SOCKET_INVALID /* Do not redefine from wolfssl */
#define SOCKET_INVALID ((SOCKET_T)INVALID_SOCKET)
#endif
#define SOCK_CLOSE closesocket
#define SOCK_SEND(s,b,l,f) send((s), (const char*)(b), (size_t)(l), (f))
#define SOCK_RECV(s,b,l,f) recv((s), (char*)(b), (size_t)(l), (f))
#define GET_SOCK_ERROR(f,s,o,e) (e) = WSAGetLastError()
#define SOCK_EQ_ERROR(e) (((e) == WSAEWOULDBLOCK) || ((e) == WSAEINPROGRESS))
/* Freescale MQX / RTCS */
#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
#if defined(FREESCALE_MQX)
#include <posix.h>
#endif
#include <rtcs.h>
/* Note: Use "RTCS_geterror(sock->fd);" to get error number */
#define SOCKET_INVALID RTCS_SOCKET_ERROR
#define SOCKET_T uint32_t
#define SOCK_CLOSE closesocket
#define SOCK_OPEN RTCS_socket
/* Microchip MPLABX Harmony, TCP/IP */
#elif defined(MICROCHIP_MPLAB_HARMONY)
#include "app.h"
#include "system_config.h"
#include "tcpip/tcpip.h"
#include <sys/errno.h>
#include <errno.h>
#define SOCKET_INVALID (-1)
#define SOCK_CLOSE closesocket
#ifndef WOLFMQTT_NONBLOCK
#error wolfMQTT must be built with WOLFMQTT_NONBLOCK defined for Harmony
#endif
/* Zephyr RTOS */
#elif defined(WOLFMQTT_ZEPHYR)
#include <zephyr/kernel.h>
#include <zephyr/fs/fs.h>
#ifndef CONFIG_POSIX_API
#include <zephyr/net/socket.h>
#endif
#ifdef CONFIG_ARCH_POSIX
#include <fcntl.h>
#else
#include <zephyr/posix/fcntl.h>
#endif
#define SOCKET_INVALID (-1)
typedef zsock_fd_set fd_set;
#define FD_ZERO ZSOCK_FD_ZERO
#define FD_SET ZSOCK_FD_SET
#define FD_ISSET ZSOCK_FD_ISSET
#define select zsock_select
#ifdef WOLFSSL_ZEPHYR
/* wolfSSL takes care of most defines */
#include <wolfssl/wolfcrypt/wc_port.h>
#else
#define addrinfo zsock_addrinfo
#define getaddrinfo zsock_getaddrinfo
#define freeaddrinfo zsock_freeaddrinfo
#define socket zsock_socket
#define close zsock_close
#define SOCK_CONNECT zsock_connect
#define getsockopt zsock_getsockopt
#define setsockopt zsock_setsockopt
#define send zsock_send
#define recv zsock_recv
#define MSG_PEEK ZSOCK_MSG_PEEK
#ifndef NO_FILESYSTEM
#define XFOPEN z_fs_open
#define XFCLOSE z_fs_close
#define XFILE struct fs_file_t*
/* These are our wrappers for opening and closing files to
* make the API more POSIX like. Copied from wolfSSL */
XFILE z_fs_open(const char* filename, const char* mode);
int z_fs_close(XFILE file);
#endif
#endif
#ifndef NO_FILESYSTEM
#ifndef XFILE
#define XFILE struct fs_file_t*
#endif
#ifndef XFFLUSH
#define XFFLUSH fs_sync
#endif
#ifndef XFSEEK
#define XFSEEK fs_seek
#endif
#ifndef XFTELL
#define XFTELL fs_tell
#endif
#ifndef XFREWIND
#define XFREWIND fs_rewind
#endif
#ifndef XFREAD
#define XFREAD(P,S,N,F) fs_read(F, P, S*N)
#endif
#ifndef XFWRITE
#define XFWRITE(P,S,N,F) fs_write(F, P, S*N)
#endif
#ifndef XSEEK_SET
#define XSEEK_SET FS_SEEK_SET
#endif
#ifndef XSEEK_END
#define XSEEK_END FS_SEEK_END
#endif
#endif
/* Linux */
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#endif
/* Setup defaults */
#ifndef NO_FILESYSTEM
#ifndef XFILE
#define XFILE FILE*
#endif
#ifndef XFOPEN
#define XFOPEN fopen
#endif
#ifndef XFCLOSE
#define XFCLOSE fclose
#endif
#ifndef XFSEEK
#define XFSEEK fseek
#endif
#ifndef XFTELL
#define XFTELL ftell
#endif
#ifndef XFREAD
#define XFREAD fread
#endif
#ifndef XFWRITE
#define XFWRITE fwrite
#endif
#ifndef XSEEK_SET
#define XSEEK_SET SEEK_SET
#endif
#ifndef XSEEK_END
#define XSEEK_END SEEK_END
#endif
#endif /* NO_FILESYSTEM */
#ifndef SOCK_OPEN
#define SOCK_OPEN socket
#endif
#ifndef SOCKET_T
#define SOCKET_T int
#endif
#ifndef SOERROR_T
#define SOERROR_T int
#endif
#ifndef SELECT_FD
#define SELECT_FD(fd) ((fd) + 1)
#endif
#ifndef SOCKET_INVALID
#define SOCKET_INVALID ((SOCKET_T)0)
#endif
#ifndef SOCK_CONNECT
#define SOCK_CONNECT connect
#endif
#ifndef SOCK_SEND
#define SOCK_SEND(s,b,l,f) send((s), (b), (size_t)(l), (f))
#endif
#ifndef SOCK_RECV
#define SOCK_RECV(s,b,l,f) recv((s), (b), (size_t)(l), (f))
#endif
#ifndef SOCK_CLOSE
#define SOCK_CLOSE close
#endif
#ifndef SOCK_ADDR_IN
#define SOCK_ADDR_IN struct sockaddr_in
#endif
#ifdef SOCK_ADDRINFO
#define SOCK_ADDRINFO struct addrinfo
#endif
#ifndef GET_SOCK_ERROR
#define GET_SOCK_ERROR(f,s,o,e) \
socklen_t len = sizeof(so_error); \
(void)getsockopt((f), (s), (o), &(e), &len)
#endif
#ifndef SOCK_EQ_ERROR
#define SOCK_EQ_ERROR(e) (((e) == EWOULDBLOCK) || ((e) == EAGAIN))
#endif
#ifdef __cplusplus
}
#endif
#endif /* WOLFMQTT_PORT_H */

View File

@ -0,0 +1,686 @@
/* sim.c
*
* Copyright (C) 2025 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Note: All logging must use stderr to avoid issue with scripts
* printing version information */
#define _GNU_SOURCE
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#ifdef __APPLE__
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/dyld.h>
#endif
#include "wolfboot/wolfboot.h"
#include "target.h"
#include "printf.h"
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
#include "elf.h"
#endif
#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT
#include "wolfhsm/wh_error.h"
#include "wolfhsm/wh_client.h"
#include "port/posix/posix_transport_tcp.h"
#elif defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) /*WOLFBOOT_ENABLE_WOLFHSM_CLIENT*/
#include "wolfhsm/wh_error.h"
#include "wolfhsm/wh_server.h"
#include "wolfhsm/wh_server_keystore.h"
#include "wolfhsm/wh_nvm.h"
#include "wolfhsm/wh_nvm_flash.h"
#include "wolfhsm/wh_transport_mem.h"
#include "port/posix/posix_flash_file.h"
#endif /* WOLFBOOT_ENABLE_WOLFHSM_SERVER */
/* Global pointer to the internal and external flash base */
uint8_t *sim_ram_base;
static uint8_t *flash_base;
int forceEmergency = 0;
uint32_t erasefail_address = 0xFFFFFFFF;
int flashLocked = 1;
int extFlashLocked = 1;
#define INTERNAL_FLASH_FILE "./internal_flash.dd"
#define EXTERNAL_FLASH_FILE "./external_flash.dd"
#ifdef DUALBANK_SWAP
#define SIM_REGISTER_FILE "./sim_registers.dd"
#define SIM_FLASH_OPTR_SWAP_BANK (1U << 20)
static uint32_t sim_flash_optr;
static void sim_dualbank_register_load(void);
static void sim_dualbank_register_store(void);
uint32_t hal_sim_get_dualbank_state(void);
#endif
/* global used to store command line arguments to forward to the test
* application */
char **main_argv;
int main_argc;
#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT
/* Client configuration/contexts */
static whTransportClientCb pttccb[1] = {PTT_CLIENT_CB};
static posixTransportTcpClientContext tcc[1] = {};
static posixTransportTcpConfig mytcpconfig[1] = {{
.server_ip_string = "127.0.0.1",
.server_port = 23456,
}};
static whCommClientConfig cc_conf[1] = {{
.transport_cb = pttccb,
.transport_context = (void*)tcc,
.transport_config = (void*)mytcpconfig,
.client_id = 12,
}};
static whClientConfig c_conf[1] = {{
.comm = cc_conf,
}};
/* Globally exported HAL symbols */
whClientContext hsmClientCtx = {0};
const int hsmDevIdHash = WH_DEV_ID;
const int hsmDevIdPubKey = WH_DEV_ID;
const int hsmKeyIdPubKey = 0xFF;
#ifdef EXT_ENCRYPT
#error "Simulator does not support firmware encryption with wolfHSM(yet)"
const int hsmDevIdCrypt = WH_DEV_ID;
const int hsmKeyIdCrypt = 0xFF;
#endif
#ifdef WOLFBOOT_CERT_CHAIN_VERIFY
const whNvmId hsmNvmIdCertRootCA = 1;
#endif
int hal_hsm_init_connect(void);
int hal_hsm_disconnect(void);
#elif defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) /*WOLFBOOT_ENABLE_WOLFHSM_CLIENT*/
/* HAL Flash state and configuration */
const whFlashCb fcb[1] = {POSIX_FLASH_FILE_CB};
posixFlashFileContext fc[1] = {0};
posixFlashFileConfig fc_conf[1] = {{
.filename = "wolfBoot_wolfHSM_NVM.bin",
.partition_size = 16384,
.erased_byte = (uint8_t)0,
}};
/* NVM Configuration using PosixSim HAL Flash */
whNvmFlashConfig nf_conf[1] = {{
.cb = fcb,
.context = fc,
.config = fc_conf,
}};
whNvmFlashContext nfc[1] = {0};
whNvmCb nfcb[1] = {WH_NVM_FLASH_CB};
whNvmConfig n_conf[1] = {{
.cb = nfcb,
.context = nfc,
.config = nf_conf,
}};
whNvmContext nvm[1] = {{0}};
static uint8_t req[] = {0};
static uint8_t resp[] = {0};
whTransportMemConfig tmcf[1] = {{
.req = (whTransportMemCsr*)req,
.req_size = sizeof(req),
.resp = (whTransportMemCsr*)resp,
.resp_size = sizeof(resp),
}};
whTransportServerCb tscb[1] = {WH_TRANSPORT_MEM_SERVER_CB};
whTransportMemServerContext tmsc[1] = {0};
/* Dummy comm server config */
whCommServerConfig cs_conf[1] = {{
.transport_cb = tscb,
.transport_context = &tmsc,
.transport_config = &tmcf,
.server_id = 0,
}};
/* Crypto context */
whServerCryptoContext crypto[1] = {{
.devId = INVALID_DEVID,
}};
#if defined(WOLFHSM_CFG_SHE_EXTENSION)
whServerSheContext she[1] = {{0}};
#endif
whServerConfig s_conf[1] = {{
.comm_config = cs_conf,
.nvm = nvm,
.crypto = crypto,
}};
whServerContext hsmServerCtx = {0};
const int hsmDevIdHash = INVALID_DEVID;
const int hsmDevIdPubKey = INVALID_DEVID;
const whNvmId hsmNvmIdCertRootCA = 1;
#ifdef EXT_ENCRYPT
#error "Simulator does not support firmware encryption with wolfHSM(yet)"
const int hsmDevIdCrypt = WH_DEV_ID;
const int hsmKeyIdCrypt = 0xFF;
#endif
int hal_hsm_server_init(void);
int hal_hsm_server_cleanup(void);
#endif /* WOLFBOOT_ENABLE_WOLFHSM_SERVER*/
static int mmap_file(const char *path, uint8_t *address, uint8_t** ret_address)
{
struct stat st = { 0 };
uint8_t *mmaped_addr;
int ret;
int fd;
if (path == NULL)
return -1;
ret = stat(path, &st);
if (ret == -1)
return -1;
fd = open(path, O_RDWR);
if (fd == -1) {
wolfBoot_printf( "can't open %s\n", path);
return -1;
}
mmaped_addr = mmap(address, st.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (mmaped_addr == MAP_FAILED)
return -1;
wolfBoot_printf( "Simulator assigned %s to base %p\n", path, mmaped_addr);
*ret_address = mmaped_addr;
close(fd);
return 0;
}
#ifdef DUALBANK_SWAP
static void sim_dualbank_register_store(void)
{
int fd = open(SIM_REGISTER_FILE, O_RDWR | O_CREAT, 0644);
if (fd == -1) {
wolfBoot_printf("Failed to open %s: %s\n", SIM_REGISTER_FILE, strerror(errno));
return;
}
if (pwrite(fd, &sim_flash_optr, sizeof(sim_flash_optr), 0) !=
(ssize_t)sizeof(sim_flash_optr)) {
wolfBoot_printf("Failed to store dualbank swap state: %s\n",
strerror(errno));
}
close(fd);
}
static void sim_dualbank_register_load(void)
{
int fd = open(SIM_REGISTER_FILE, O_RDWR | O_CREAT, 0644);
uint32_t value = 0;
int rd;
if (fd == -1) {
wolfBoot_printf("Failed to open %s: %s\n", SIM_REGISTER_FILE,
strerror(errno));
exit(-1);
}
rd = pread(fd, &value, sizeof(value), 0);
if (rd == (int)sizeof(value)) {
sim_flash_optr = value;
} else {
sim_flash_optr = 0;
if (pwrite(fd, &sim_flash_optr, sizeof(sim_flash_optr), 0) !=
sizeof(sim_flash_optr)) {
wolfBoot_printf("Failed to initialize dualbank swap state: %s\n",
strerror(errno));
}
}
close(fd);
}
uint32_t hal_sim_get_dualbank_state(void)
{
return (sim_flash_optr & SIM_FLASH_OPTR_SWAP_BANK) ? 1U : 0U;
}
#endif
void hal_flash_unlock(void)
{
flashLocked = 0;
}
void hal_flash_lock(void)
{
flashLocked = 1;
}
#ifdef DUALBANK_SWAP
void hal_flash_dualbank_swap(void)
{
uint8_t *boot = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS;
uint8_t *update = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
uint8_t *buffer;
int was_locked = flashLocked;
buffer = (uint8_t *)malloc(WOLFBOOT_PARTITION_SIZE);
if (buffer == NULL) {
wolfBoot_printf("Simulator dualbank swap failed: out of memory\n");
exit(-1);
}
if (was_locked)
hal_flash_unlock();
memcpy(buffer, boot, WOLFBOOT_PARTITION_SIZE);
memcpy(boot, update, WOLFBOOT_PARTITION_SIZE);
memcpy(update, buffer, WOLFBOOT_PARTITION_SIZE);
if (msync(boot, WOLFBOOT_PARTITION_SIZE, MS_SYNC) != 0) {
wolfBoot_printf("msync boot partition failed: %s\n", strerror(errno));
}
if (msync(update, WOLFBOOT_PARTITION_SIZE, MS_SYNC) != 0) {
wolfBoot_printf("msync update partition failed: %s\n", strerror(errno));
}
free(buffer);
sim_flash_optr ^= SIM_FLASH_OPTR_SWAP_BANK;
sim_dualbank_register_store();
wolfBoot_printf("Simulator dualbank swap complete, register=%u\n",
hal_sim_get_dualbank_state());
if (was_locked)
hal_flash_lock();
}
#endif
void hal_prepare_boot(void)
{
/* no op */
}
int hal_flash_write(uintptr_t address, const uint8_t *data, int len)
{
int i;
if (flashLocked == 1) {
wolfBoot_printf("FLASH IS BEING WRITTEN TO WHILE LOCKED\n");
return -1;
}
if (forceEmergency == 1 && address == WOLFBOOT_PARTITION_BOOT_ADDRESS) {
/* implicit cast abide compiler warning */
memset((void*)address, 0, len);
/* let the rest of the writes work properly for the emergency update */
forceEmergency = 0;
}
else {
for (i = 0; i < len; i++) {
#ifdef NVM_FLASH_WRITEONCE
uint8_t *addr = (uint8_t *)address;
if (addr[i] != FLASH_BYTE_ERASED) {
/* no writing to non-erased page in NVM_FLASH_WRITEONCE */
wolfBoot_printf("NVM_FLASH_WRITEONCE non-erased write detected at address %p!\n", addr);
wolfBoot_printf("Address[%d] = %02x\n", i, addr[i]);
return -1;
}
#endif
#ifdef WOLFBOOT_FLAGS_INVERT
((uint8_t*)address)[i] |= data[i];
#else
((uint8_t*)address)[i] &= data[i];
#endif
}
}
return 0;
}
int hal_flash_erase(uintptr_t address, int len)
{
if (flashLocked == 1) {
wolfBoot_printf("FLASH IS BEING ERASED WHILE LOCKED\n");
return -1;
}
/* implicit cast abide compiler warning */
wolfBoot_printf( "hal_flash_erase addr %p len %d\n", (void*)address, len);
if (address == erasefail_address + WOLFBOOT_PARTITION_BOOT_ADDRESS) {
wolfBoot_printf( "POWER FAILURE\n");
/* Corrupt page */
memset((void*)address, 0xEE, len);
exit(0);
}
memset((void*)address, FLASH_BYTE_ERASED, len);
return 0;
}
void hal_init(void)
{
int ret;
int i;
ret = mmap_file(INTERNAL_FLASH_FILE,
(uint8_t*)ARCH_FLASH_OFFSET, &sim_ram_base);
if (ret != 0) {
wolfBoot_printf( "failed to load internal flash file\n");
exit(-1);
}
#ifdef EXT_FLASH
ret = mmap_file(EXTERNAL_FLASH_FILE,
(uint8_t*)ARCH_FLASH_OFFSET + 0x10000000, &flash_base);
if (ret != 0) {
wolfBoot_printf( "failed to load external flash file\n");
exit(-1);
}
#endif /* EXT_FLASH */
#ifdef DUALBANK_SWAP
sim_dualbank_register_load();
#endif
for (i = 1; i < main_argc; i++) {
if (strcmp(main_argv[i], "powerfail") == 0) {
erasefail_address = strtol(main_argv[++i], NULL, 16);
wolfBoot_printf( "Set power fail to erase at address %x\n",
erasefail_address);
}
/* force a bad write of the boot partition to trigger and test the
* emergency fallback feature */
else if (strcmp(main_argv[i], "emergency") == 0)
forceEmergency = 1;
}
}
void ext_flash_lock(void)
{
extFlashLocked = 1;
}
void ext_flash_unlock(void)
{
extFlashLocked = 0;
}
int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
{
if (extFlashLocked == 1) {
wolfBoot_printf("EXT FLASH IS BEING WRITTEN TO WHILE LOCKED\n");
return -1;
}
memcpy(flash_base + address, data, len);
return 0;
}
int ext_flash_read(uintptr_t address, uint8_t *data, int len)
{
memcpy(data, flash_base + address, len);
return len;
}
int ext_flash_erase(uintptr_t address, int len)
{
if (extFlashLocked == 1) {
wolfBoot_printf("EXT FLASH IS BEING ERASED WHILE LOCKED\n");
return -1;
}
memset(flash_base + address, FLASH_BYTE_ERASED, len);
return 0;
}
#ifdef __APPLE__
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
/* Find the MachO entry point */
static int find_epc(void *base, struct entry_point_command **entry)
{
struct mach_header_64 *mh;
struct load_command *lc;
int i;
unsigned long text = 0;
*entry = NULL;
mh = (struct mach_header_64*)base;
lc = (struct load_command*)((uint8_t *)base + sizeof(struct mach_header_64));
for (i=0; i<(int)mh->ncmds; i++) {
if (lc->cmd == LC_MAIN) { /* 0x80000028 */
*entry = (struct entry_point_command *)lc;
return 1;
}
lc = (struct load_command*)((unsigned long)lc + lc->cmdsize);
}
return 0;
}
#endif
void do_boot(const uint32_t *app_offset)
{
int ret;
size_t app_size = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE;
wolfBoot_printf("Simulator do_boot app_offset = %p\n", app_offset);
if (flashLocked == 0) {
wolfBoot_printf("WARNING FLASH IS UNLOCKED AT BOOT");
}
if (extFlashLocked == 0) {
wolfBoot_printf("WARNING EXT FLASH IS UNLOCKED AT BOOT");
}
#ifdef __APPLE__
char template[] = "test_app";
int fd = mkstemp(template);
if (fd < 0) {
wolfBoot_printf( "mkstemp error\n");
exit(-1);
}
size_t wret = write(fd, app_offset, app_size);
if (wret != app_size) {
wolfBoot_printf( "write error\n");
exit(-1);
}
fchmod(fd, 0755);
close(fd);
wolfBoot_printf("Executing %s\n", template);
char *envp[] = { NULL };
execve(template, main_argv, envp);
wolfBoot_printf( "execve error\n");
#elif defined (WOLFBOOT_ELF_FLASH_SCATTER)
uint8_t *entry_point = (sim_ram_base + (unsigned long)app_offset);
printf("entry point: %p\n", entry_point);
printf("app offset: %p\n", app_offset);
typedef int (*main_entry)(int, char**);
main_entry main;
main = (main_entry)(entry_point);
/* TODO: call main ! */
/* main(main_argc, main_argv); */
wolfBoot_printf("Simulator for ELF_FLASH_SCATTER image not implemented yet. Exiting...\n");
exit(0);
#else
char *envp[1] = {NULL};
int fd = memfd_create("test_app", 0);
size_t wret;
if (fd == -1) {
wolfBoot_printf( "memfd error\n");
exit(-1);
}
wret = write(fd, app_offset, app_size);
if (wret != app_size) {
wolfBoot_printf( "can't write test-app to memfd, address %p\n", app_offset);
exit(-1);
}
wolfBoot_printf("Stored test-app to memfd, address %p (%zu bytes)\n", app_offset, wret);
ret = fexecve(fd, main_argv, envp);
wolfBoot_printf( "fexecve error\n");
#endif
exit(1);
}
#ifdef __APPLE__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
#if !defined(WOLFBOOT_DUALBOOT)
int wolfBoot_fallback_is_possible(void)
{
return 0;
}
int wolfBoot_dualboot_candidate(void)
{
return 0;
}
#endif
void arch_reboot(void)
{
exit(0);
}
#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT
int hal_hsm_init_connect(void)
{
int rc = 0;
rc = wh_Client_Init(&hsmClientCtx, c_conf);
if (rc != WH_ERROR_OK) {
fprintf(stderr, "Failed to initialize HSM client\n");
exit(-1);
}
rc = wh_Client_CommInit(&hsmClientCtx, NULL, NULL);
if (rc != WH_ERROR_OK) {
fprintf(stderr, "Failed to initialize HSM client communication\n");
exit(-1);
}
return rc;
}
int hal_hsm_disconnect(void)
{
int rc = 0;
rc = wh_Client_CommClose(&hsmClientCtx);
if (rc != WH_ERROR_OK) {
fprintf(stderr, "Failed to close HSM client connection\n");
exit(-1);
}
rc = wh_Client_Cleanup(&hsmClientCtx);
if (rc != WH_ERROR_OK) {
fprintf(stderr, "Failed to cleanup HSM client\n");
exit(-1);
}
return rc;
}
#elif defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) /*WOLFBOOT_ENABLE_WOLFHSM_CLIENT*/
int hal_hsm_server_init(void)
{
int rc = 0;
rc = wh_Nvm_Init(nvm, n_conf);
if (rc != 0) {
fprintf(stderr, "Failed to initialize NVM: %d\n", rc);
exit(-1);
}
wolfCrypt_Init();
rc = wc_InitRng_ex(crypto->rng, NULL, INVALID_DEVID);
if (rc != 0) {
fprintf(stderr, "Failed to initialize RNG: %d\n", rc);
exit(-1);
}
rc = wh_Server_Init(&hsmServerCtx, s_conf);
if (rc != 0) {
fprintf(stderr, "Failed to initialize HSM server: %d\n", rc);
exit(-1);
}
return rc;
}
int hal_hsm_server_cleanup(void)
{
int rc = 0;
rc = wh_Server_Cleanup(&hsmServerCtx);
if (rc != 0) {
fprintf(stderr, "Failed to cleanup HSM server: %d\n", rc);
exit(-1);
}
rc = wc_FreeRng(crypto->rng);
if (rc != 0) {
fprintf(stderr, "Failed to cleanup RNG: %d\n", rc);
exit(-1);
}
rc = wolfCrypt_Cleanup();
if (rc != 0) {
fprintf(stderr, "Failed to cleanup wolfCrypt: %d\n", rc);
exit(-1);
}
return rc;
}
#endif /* WOLFBOOT_ENABLE_WOLFHSM_SERVER */

File diff suppressed because one or more lines are too long

37
sim-OTA/sim.config 100644
View File

@ -0,0 +1,37 @@
ARCH=sim
TARGET=sim
# note TPM requires ASN.1 encoding for RSA, so use RSA2048ENC, RSA3072ENC, RSA4096ENC
SIGN?=ECC256
HASH?=SHA256
SPI_FLASH=0
WOLFTPM=1
# enable offloading of asymmetric verify to TPM
WOLFBOOT_TPM_VERIFY?=1
# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x180000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000
# if on external flash, it should be multiple of system page size
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x280000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x400000
# Measured boot at test PCR index 16
MEASURED_BOOT?=1
MEASURED_PCR_A?=16
# Use NV for TPM based Root of Trust
WOLFBOOT_TPM_KEYSTORE?=1
WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01400200
#WOLFBOOT_TPM_KEYSTORE_AUTH?=TestAuth
# Default image header size is larger to support room for policy
IMAGE_HEADER_SIZE?=512
# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1
# TPM Logging
CFLAGS_EXTRA+=-DDEBUG_WOLFTPM
#CFLAGS_EXTRA+=-DWOLFTPM_DEBUG_VERBOSE

1
sim-OTA/wolfBoot 160000

@ -0,0 +1 @@
Subproject commit b456d0eabb55f4069574ab62c5ef49fabd84b90a

1
sim-OTA/wolfMQTT 160000

@ -0,0 +1 @@
Subproject commit 2750bcbb06c0ecdcd3c144024a4089b9a53a9519