Add sim-OTA and submodules
parent
57dd2b0846
commit
873aa83965
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||

|
||||
|
||||
## 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.
|
||||
|
|
@ -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 **/
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/* tpm_handler.h
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot-Examples.
|
||||
*/
|
||||
|
||||
int tpm_handler(void);
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b456d0eabb55f4069574ab62c5ef49fabd84b90a
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2750bcbb06c0ecdcd3c144024a4089b9a53a9519
|
||||
Loading…
Reference in New Issue