From ebdc82f794cedf22dc91e468786cd6dfd851fe1a Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Tue, 3 Mar 2026 12:34:49 -0700 Subject: [PATCH 1/8] add build option to skip verification of boot image --- options.mk | 4 ++++ src/update_disk.c | 5 +++++ src/update_flash.c | 6 ++++++ src/update_flash_hwswap.c | 10 ++++++---- src/update_ram.c | 2 ++ 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/options.mk b/options.mk index ff57622796..c994d6bca2 100644 --- a/options.mk +++ b/options.mk @@ -681,6 +681,10 @@ ifeq ($(ALLOW_DOWNGRADE),1) CFLAGS+= -D"ALLOW_DOWNGRADE" endif +ifeq ($(WOLFBOOT_SKIP_BOOT_VERIFY),1) + CFLAGS+=-D"WOLFBOOT_SKIP_BOOT_VERIFY" +endif + ifeq ($(NVM_FLASH_WRITEONCE),1) CFLAGS+= -D"NVM_FLASH_WRITEONCE" endif diff --git a/src/update_disk.c b/src/update_disk.c index cdf815cd91..3f5c0917cd 100644 --- a/src/update_disk.c +++ b/src/update_disk.c @@ -424,6 +424,7 @@ void RAMFUNCTION wolfBoot_start(void) } os_image.fw_base = (uint8_t*)load_address; +#ifndef WOLFBOOT_SKIP_BOOT_VERIFY wolfBoot_printf("Checking image integrity..."); BENCHMARK_START(); if (wolfBoot_verify_integrity(&os_image) != 0) { @@ -445,6 +446,10 @@ void RAMFUNCTION wolfBoot_start(void) failures = 0; break; /* Success case */ } +#else + failures = 0; + break; /* Skip verification, boot directly */ +#endif } while (failures < MAX_FAILURES); if (failures) { diff --git a/src/update_flash.c b/src/update_flash.c index 054837d898..0be09a8e3e 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -1345,6 +1345,7 @@ void RAMFUNCTION wolfBoot_start(void) wolfBoot_printf("Booting version: 0x%x\n", wolfBoot_get_blob_version(boot.hdr)); +#ifndef WOLFBOOT_SKIP_BOOT_VERIFY if (bootRet < 0 || (wolfBoot_verify_integrity(&boot) < 0) || (wolfBoot_verify_authenticity(&boot) < 0) @@ -1376,6 +1377,11 @@ void RAMFUNCTION wolfBoot_start(void) } } PART_SANITY_CHECK(&boot); +#else + if (bootRet < 0) { + wolfBoot_panic(); + } +#endif #ifdef WOLFBOOT_ELF_FLASH_SCATTER unsigned long entry; diff --git a/src/update_flash_hwswap.c b/src/update_flash_hwswap.c index ec3816e5da..7006208562 100644 --- a/src/update_flash_hwswap.c +++ b/src/update_flash_hwswap.c @@ -50,10 +50,12 @@ void RAMFUNCTION wolfBoot_start(void) boot_panic(); for (;;) { - if ((wolfBoot_open_image(&fw_image, active) < 0) || - (wolfBoot_verify_integrity(&fw_image) < 0) || - (wolfBoot_verify_authenticity(&fw_image) < 0)) { - + if ((wolfBoot_open_image(&fw_image, active) < 0) +#ifndef WOLFBOOT_SKIP_BOOT_VERIFY + || (wolfBoot_verify_integrity(&fw_image) < 0) + || (wolfBoot_verify_authenticity(&fw_image) < 0) +#endif + ) { /* panic if authentication fails and no backup */ if (!wolfBoot_fallback_is_possible()) boot_panic(); diff --git a/src/update_ram.c b/src/update_ram.c index d415fc7602..3aba3dfde0 100644 --- a/src/update_ram.c +++ b/src/update_ram.c @@ -191,6 +191,7 @@ void RAMFUNCTION wolfBoot_start(void) goto backup_on_failure; } +#ifndef WOLFBOOT_SKIP_BOOT_VERIFY /* Verify image integrity (hash check) */ wolfBoot_printf("Checking integrity..."); BENCHMARK_START(); @@ -210,6 +211,7 @@ void RAMFUNCTION wolfBoot_start(void) goto backup_on_failure; } BENCHMARK_END("done"); +#endif { /* Success - integrity and signature valid */ From f2095be8ce1bc8c65391dff9ae48c85df9c09c8a Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:47:05 -0700 Subject: [PATCH 2/8] add monoloithic self-update test case and docs --- .../sim-self-update-monolithic.config | 19 +++++ docs/firmware_update.md | 72 +++++++++++++++++++ tools/test.mk | 36 ++++++++++ 3 files changed, 127 insertions(+) create mode 100644 config/examples/sim-self-update-monolithic.config diff --git a/config/examples/sim-self-update-monolithic.config b/config/examples/sim-self-update-monolithic.config new file mode 100644 index 0000000000..adc2cce837 --- /dev/null +++ b/config/examples/sim-self-update-monolithic.config @@ -0,0 +1,19 @@ +ARCH=sim +TARGET=sim +SIGN?=ED25519 +HASH?=SHA256 +WOLFBOOT_SMALL_STACK?=0 +SPI_FLASH=0 +DEBUG=1 +RAM_CODE=1 +WOLFBOOT_VERSION=1 + +# sizes should be multiple of system page size +WOLFBOOT_PARTITION_SIZE=0x40000 +WOLFBOOT_SECTOR_SIZE=0x1000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x60000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0xA0000 + +# required for keytools +WOLFBOOT_FIXED_PARTITIONS=1 diff --git a/docs/firmware_update.md b/docs/firmware_update.md index 971edcc845..ba0e1fc23c 100644 --- a/docs/firmware_update.md +++ b/docs/firmware_update.md @@ -200,6 +200,78 @@ regular signed image at the bootloader origin. See [Signing.md](Signing.md#header-only-output-wolfboot-self-header) for more detail on the `--header-only` sign tool option. +#### Monolithic updates + +The self-update mechanism can be used to update both the bootloader +**and** the application firmware in a single atomic operation. Because +`wolfBoot_self_update()` copies `fw_size` bytes from the update image to +`ARCH_FLASH_OFFSET`, a payload that is larger than the bootloader region +will spill into the contiguous BOOT partition, overwriting whatever +application image was there previously. + +No wolfBoot code changes are required — only the update payload needs to +be assembled differently. The payload is constructed by concatenating the +new bootloader binary with the new signed application image and signing +the result as a wolfBoot self-update: + +``` +cat wolfboot.bin image_v1_signed.bin > monolithic_payload.bin +sign --wolfboot-update monolithic_payload.bin key.der 2 +``` + +After the self-update completes, flash looks like: + +``` +ARCH_FLASH_OFFSET BOOT_ADDRESS + | | + v v + [ new bootloader bytes | padding | new signed app image ] + <-------- fw_size -------------------------------------------> +``` + +##### Self-header interaction + +When `WOLFBOOT_SELF_HEADER` is enabled, the persisted header retains the +`fw_size`, hash and signature exactly as the signing tool produced them. +The hash covers the **entire** monolithic payload — both the bootloader +bytes and the nested application image. Later calls to +`wolfBoot_open_self()` / `wolfBoot_verify_integrity()` will re-hash +`fw_size` bytes starting at `ARCH_FLASH_OFFSET`, spanning into the BOOT +partition. + +##### Restrictions + +- **Not power-fail safe.** Like all self-updates, a monolithic update + erases the bootloader region and writes in-place. An interruption + during the write leaves the device unbootable. Additionally, the BOOT + partition is written without a prior erase — this relies on the + partition being in an erased (0xFF) state, which is only guaranteed + when the device has no prior application installed or the partition has + been explicitly erased beforehand. + +- **Not revertable.** There is no swap or rollback mechanism. The old + bootloader and application are destroyed during the update. + +- **Locks bootloader verification to a specific application version.** + Because the self-header hash covers the full monolithic image, any + independent application update will invalidate the persisted + self-header. To maintain a valid self-header, both components must + always be updated together as a single monolithic payload. + +- **Payload must fit in the UPDATE partition.** The signed monolithic + image (header + bootloader + signed application) plus the 5-byte + `pBOOT` trailer must not exceed `WOLFBOOT_PARTITION_SIZE`. + +##### Simulator test + +A simulator test is provided in `tools/test.mk` to exercise this use case: + +``` +cp config/examples/sim-self-update-monolithic.config .config +make clean && make +make test-sim-self-update-monolithic +``` + ### Incremental updates (aka: 'delta' updates) wolfBoot supports incremental updates, based on a specific older version. The sign tool diff --git a/tools/test.mk b/tools/test.mk index c177bdfb53..df0dd2b208 100644 --- a/tools/test.mk +++ b/tools/test.mk @@ -266,6 +266,42 @@ test-sim-self-update: wolfboot.bin FORCE @# Verify dummy payload was written to bootloader region, indicating the self update swapped images as expected $(Q)cmp -n $$(wc -c < dummy_update.bin | awk '{print $$1}') dummy_update.bin internal_flash.dd && echo "=== Self-update test PASSED ===" +# Test monolithic self-update mechanism using simulator. A monolithic self-update +# updates both the bootloader AND the boot partition application image in a single +# operation by crafting a payload that spans the bootloader region and spills into +# the contiguous boot partition. +test-sim-self-update-monolithic: wolfboot.bin test-app/image_v1_signed.bin FORCE + @echo "=== Simulator Monolithic Self-Update Test ===" + @# Create dummy bootloader (0xAA pattern, exactly BOOTLOADER_PARTITION_SIZE) + $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) count=1 2>/dev/null | tr '\000' '\252' > monolithic_dummy_bl.bin + @# Concatenate dummy bootloader + signed app image to form monolithic payload + $(Q)cat monolithic_dummy_bl.bin test-app/image_v1_signed.bin > monolithic_payload.bin + @# Sign monolithic payload as wolfBoot self-update v2 + $(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update monolithic_payload.bin $(PRIVATE_KEY) 2 + @# Create update partition with signed monolithic image and "pBOOT" trailer + $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > update_part.dd + $(Q)dd if=monolithic_payload_v2_signed.bin of=update_part.dd bs=1 conv=notrunc + $(Q)printf "pBOOT" | dd of=update_part.dd bs=1 seek=$$(($(WOLFBOOT_PARTITION_SIZE) - 5)) conv=notrunc + @# Create erased boot and swap partitions + $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > boot_part.dd + $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_SECTOR_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > erased_sec.dd + @# Assemble flash: wolfboot.bin at 0, empty boot partition, update partition, swap + $(Q)$(BINASSEMBLE) internal_flash.dd \ + 0 wolfboot.bin \ + $$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) boot_part.dd \ + $$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS) - $(ARCH_FLASH_OFFSET))) update_part.dd \ + $$(($(WOLFBOOT_PARTITION_SWAP_ADDRESS) - $(ARCH_FLASH_OFFSET))) erased_sec.dd + @# Run simulator - self-update fires, copies monolithic payload to offset 0 + $(Q)./wolfboot.elf get_version || true + @# Verify bootloader region contains 0xAA pattern (dummy bootloader was written) + $(Q)cmp -n $$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) monolithic_dummy_bl.bin internal_flash.dd + @echo " Bootloader region 0xAA pattern: PASSED" + @# Extract nested app from boot partition and verify it matches original signed app + $(Q)dd if=internal_flash.dd bs=1 skip=$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) count=$$(wc -c < test-app/image_v1_signed.bin | awk '{print $$1}') of=nested_app.dd 2>/dev/null + $(Q)cmp nested_app.dd test-app/image_v1_signed.bin + @echo " Nested app at boot partition: PASSED" + @echo "=== Monolithic Self-Update Test PASSED ===" + # Test self-header cryptographic verification (hash + signature validation) # # Verifies that an application can cryptographically verify the bootloader using From d16fe4f4f14e05a55ca7fb2d760ca67f6b801e6c Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 4 Mar 2026 10:48:45 -0700 Subject: [PATCH 3/8] Fix self-update erase before write in boot partition, add monolithic build option --- .../examples/sim-self-update-monolithic.config | 1 + options.mk | 6 ++++++ src/update_flash.c | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/config/examples/sim-self-update-monolithic.config b/config/examples/sim-self-update-monolithic.config index adc2cce837..a2d0597c46 100644 --- a/config/examples/sim-self-update-monolithic.config +++ b/config/examples/sim-self-update-monolithic.config @@ -6,6 +6,7 @@ WOLFBOOT_SMALL_STACK?=0 SPI_FLASH=0 DEBUG=1 RAM_CODE=1 +SELF_UPDATE_MONOLITHIC=1 WOLFBOOT_VERSION=1 # sizes should be multiple of system page size diff --git a/options.mk b/options.mk index c994d6bca2..c05bdb8bad 100644 --- a/options.mk +++ b/options.mk @@ -74,6 +74,12 @@ ifeq ($(WOLFBOOT_TPM_SEAL),1) endif endif +## Monolithic self-update: erase covers fw_size so the payload can span +## the bootloader region into the contiguous boot partition. +ifeq ($(SELF_UPDATE_MONOLITHIC),1) + CFLAGS+=-DWOLFBOOT_SELF_UPDATE_MONOLITHIC +endif + ## Persist wolfBoot self header at fixed address ## Invariants and defaults are enforced in wolfboot.h ifeq ($(WOLFBOOT_SELF_HEADER),1) diff --git a/src/update_flash.c b/src/update_flash.c index 0be09a8e3e..0b3f3a4824 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -67,11 +67,19 @@ static uint8_t buffer[FLASHBUFFER_SIZE] XALIGNED(4); #endif -static void RAMFUNCTION wolfBoot_erase_bootloader(void) +static void RAMFUNCTION wolfBoot_erase_bootloader(uint32_t len) { - uint32_t len = WOLFBOOT_PARTITION_BOOT_ADDRESS - ARCH_FLASH_OFFSET; +#ifdef WOLFBOOT_SELF_UPDATE_MONOLITHIC + /* Erase the full write range (rounded up to sector boundary) so that + * a monolithic payload that spills past the bootloader region into the + * contiguous boot partition lands on erased flash. */ + len = ((len + WOLFBOOT_SECTOR_SIZE - 1) / + WOLFBOOT_SECTOR_SIZE) * WOLFBOOT_SECTOR_SIZE; +#else + (void)len; + len = WOLFBOOT_PARTITION_BOOT_ADDRESS - ARCH_FLASH_OFFSET; +#endif hal_flash_erase(ARCH_FLASH_OFFSET, len); - } #include @@ -154,7 +162,7 @@ static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src) #endif hal_flash_unlock(); - wolfBoot_erase_bootloader(); + wolfBoot_erase_bootloader(src->fw_size); #ifdef EXT_FLASH if (PART_IS_EXT(src)) { while (pos < src->fw_size) { From f45546f8cd28ad9bacfd3888bf9b070fc5f9aa73 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:07:00 -0700 Subject: [PATCH 4/8] add new AURIX monolithic self update config --- ...lithic-update-wolfHSM-certs-rsa4096.config | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 config/examples/aurix-tc375-hsm-monolithic-update-wolfHSM-certs-rsa4096.config diff --git a/config/examples/aurix-tc375-hsm-monolithic-update-wolfHSM-certs-rsa4096.config b/config/examples/aurix-tc375-hsm-monolithic-update-wolfHSM-certs-rsa4096.config new file mode 100644 index 0000000000..eacdfd7252 --- /dev/null +++ b/config/examples/aurix-tc375-hsm-monolithic-update-wolfHSM-certs-rsa4096.config @@ -0,0 +1,47 @@ +ARCH?=AURIX_TC3 +TARGET?=aurix_tc3xx +AURIX_TC3_HSM=1 +SIGN?=RSA4096 +HASH?=SHA256 +DEBUG?=0 +WOLFBOOT_VERSION?=1 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +EXT_FLASH?=1 +EXT_BOOT=1 +EXT_UPDATE=1 +EXT_SWAP=1 +FLAGS_INVERT=1 +FLASH_MULTI_SECTOR_ERASE=1 +DEBUG_UART=1 +PRINTF_ENABLED=1 + +# wolfHSM options +WOLFHSM_SERVER=1 + +# Cert chain options +CERT_CHAIN_VERIFY=1 + +# RSA4096 cert chains need the larger header and stack +WOLFBOOT_HUGE_STACK=1 +IMAGE_HEADER_SIZE=4096 + +# self-header feature (persist header in external flash) +WOLFBOOT_SELF_HEADER=1 +SELF_HEADER_EXT=1 + +# Monolithic updates +SELF_UPDATE_MONOLITHIC=1 + +# Enable wolfBoot hooks +WOLFBOOT_HOOK_LOADER_POSTINIT=1 +WOLFBOOT_HOOKS_FILE=../wolfBoot-callbacks/wolfboot_hooks.c + +ARCH_FLASH_OFFSET=0x80028000 +WOLFBOOT_SECTOR_SIZE=0x4000 +WOLFBOOT_PARTITION_SIZE=0x30000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80038000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80068000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x80098000 +WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS=0x8009C000 From dd2d54bbc8d1bc16786c08bc3e716068f67f1439 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:36:43 -0700 Subject: [PATCH 5/8] add example to monolithic doc section --- docs/firmware_update.md | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/firmware_update.md b/docs/firmware_update.md index ba0e1fc23c..57b9d32dc3 100644 --- a/docs/firmware_update.md +++ b/docs/firmware_update.md @@ -212,17 +212,35 @@ application image was there previously. No wolfBoot code changes are required — only the update payload needs to be assembled differently. The payload is constructed by concatenating the new bootloader binary with the new signed application image and signing -the result as a wolfBoot self-update: +the result as a wolfBoot self-update. Note that the user must ensure that padding +is supplied such that the header of the new signed app image will be located +at an offset of `WOLFBOOT_PARTITION_BOOT_ADDRESS` from the base of the binary. -``` -cat wolfboot.bin image_v1_signed.bin > monolithic_payload.bin -sign --wolfboot-update monolithic_payload.bin key.der 2 + +The following pseudo-shell-script demonstrates how to use standard CLI tools to +build this padded image, where `$PRIVATE_KEY`, `$ARCH_FLASH_OFFSET` and +`$WOLFBOOT_PARTITION_BOOT_ADDRESS` are the wolfBoot config variables that +correspond to your platform + +```sh +# Sign your app image as v2 for inclusion in the monolithic payload. This generates test-app/image_v2_signed.bin +tools/keytools/sign test-app/image.bin $(PRIVATE_KEY) 2 + +# Create padded wolfboot v2 binary file (0xFF fill to exact bootloader region size) +# Bootloader region = $WOLFBOOT_PARTITION_BOOT_ADDRESS - $ARCH_FLASH_OFFSET +dd if=/dev/zero bs=$$(($WOLFBOOT_PARTITION_BOOT_ADDRESS - $ARCH_FLASH_OFFSET)) count=1 2>/dev/null | tr '\000' '\377' > wolfboot_v2_padded.bin +dd if=wolfboot.bin of=wolfboot_v2_padded.bin conv=notrunc 2>/dev/null + +# Concatenate padded bootloader v2 + signed app v2 to form the monolithic payload +cat wolfboot_v2_padded.bin test-app/image_v2_signed.bin > monolithic_payload.bin +# Sign the monolithic payload as a wolfBoot self-update v2 +tools/keytools/sign --wolfboot-update monolithic_payload.bin $PRIVATE_KEY 2 ``` After the self-update completes, flash looks like: ``` -ARCH_FLASH_OFFSET BOOT_ADDRESS +ARCH_FLASH_OFFSET WOLFBOOT_PARTITION_BOOT_ADDRESS | | v v [ new bootloader bytes | padding | new signed app image ] @@ -243,11 +261,7 @@ partition. - **Not power-fail safe.** Like all self-updates, a monolithic update erases the bootloader region and writes in-place. An interruption - during the write leaves the device unbootable. Additionally, the BOOT - partition is written without a prior erase — this relies on the - partition being in an erased (0xFF) state, which is only guaranteed - when the device has no prior application installed or the partition has - been explicitly erased beforehand. + during the write leaves the device unbootable. - **Not revertable.** There is no swap or rollback mechanism. The old bootloader and application are destroyed during the update. From caaba83cdcb9dda96785e50d63e5bcffe8ab0639 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:48:51 -0700 Subject: [PATCH 6/8] Document WOLFBOOT_SKIP_BOOT_VERIFY --- docs/firmware_update.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/firmware_update.md b/docs/firmware_update.md index 57b9d32dc3..029eae973d 100644 --- a/docs/firmware_update.md +++ b/docs/firmware_update.md @@ -286,6 +286,34 @@ make clean && make make test-sim-self-update-monolithic ``` +#### Skipping boot image verification + +When wolfBoot is used together with the [self-header](#self-header-persisting-the-bootloader-manifest) +and [monolithic updates](#monolithic-updates) features, an external verifier such as +[wolfHSM](wolfHSM.md) can verify the combined bootloader+application payload before wolfBoot runs. +In this scenario, wolfBoot's own boot-time verification is redundant and can be skipped as a +performance optimization. + +Setting `WOLFBOOT_SKIP_BOOT_VERIFY=1` in the build configuration disables both the integrity (hash) +and authenticity (signature) checks that wolfBoot normally performs on the boot image at startup. + +**WARNING: This option completely disables boot-time firmware verification. It is only safe to use +when ALL of the following conditions are met:** + +- The self-header feature is enabled, so the bootloader manifest is persisted alongside the + application image +- Monolithic updates are enabled, so the bootloader and application are always updated together as a + single payload +- An external entity (e.g. an HSM running wolfHSM) is guaranteed to verify the full monolithic + payload before wolfBoot boots + +**Using this option outside of this specific scenario removes all boot-time authenticity and integrity +guarantees and is not secure.** + +Note that this option only affects verification of the boot image at startup. Firmware updates +staged in the update partition are still fully verified (signature and integrity) before being +installed, regardless of this setting. + ### Incremental updates (aka: 'delta' updates) wolfBoot supports incremental updates, based on a specific older version. The sign tool From 754a9ba0ea6b7218b89ef48609993fcd10ef6832 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:23:53 -0700 Subject: [PATCH 7/8] code review fixes --- docs/firmware_update.md | 6 +++--- tools/test.mk | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/firmware_update.md b/docs/firmware_update.md index 029eae973d..4d4c1fbac1 100644 --- a/docs/firmware_update.md +++ b/docs/firmware_update.md @@ -203,14 +203,14 @@ more detail on the `--header-only` sign tool option. #### Monolithic updates The self-update mechanism can be used to update both the bootloader -**and** the application firmware in a single atomic operation. Because +**and** the application firmware in a single operation. Because `wolfBoot_self_update()` copies `fw_size` bytes from the update image to `ARCH_FLASH_OFFSET`, a payload that is larger than the bootloader region will spill into the contiguous BOOT partition, overwriting whatever application image was there previously. -No wolfBoot code changes are required — only the update payload needs to -be assembled differently. The payload is constructed by concatenating the +To enable this behavior, set `SELF_UPDATE_MONOLITHIC=1` in your build +configuration. The payload should be constructed by concatenating the new bootloader binary with the new signed application image and signing the result as a wolfBoot self-update. Note that the user must ensure that padding is supplied such that the header of the new signed app image will be located diff --git a/tools/test.mk b/tools/test.mk index df0dd2b208..7218dced6d 100644 --- a/tools/test.mk +++ b/tools/test.mk @@ -272,7 +272,7 @@ test-sim-self-update: wolfboot.bin FORCE # the contiguous boot partition. test-sim-self-update-monolithic: wolfboot.bin test-app/image_v1_signed.bin FORCE @echo "=== Simulator Monolithic Self-Update Test ===" - @# Create dummy bootloader (0xAA pattern, exactly BOOTLOADER_PARTITION_SIZE) + @# Create dummy bootloader (0xAA pattern, exactly bootloader region size: WOLFBOOT_PARTITION_BOOT_ADDRESS - ARCH_FLASH_OFFSET) $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) count=1 2>/dev/null | tr '\000' '\252' > monolithic_dummy_bl.bin @# Concatenate dummy bootloader + signed app image to form monolithic payload $(Q)cat monolithic_dummy_bl.bin test-app/image_v1_signed.bin > monolithic_payload.bin From 3d2c9c54daba2fb173651bd007ad9966b1bc7ae9 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Thu, 5 Mar 2026 08:54:54 -0700 Subject: [PATCH 8/8] fix typo in readme --- docs/firmware_update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/firmware_update.md b/docs/firmware_update.md index 4d4c1fbac1..b0cc6b0af9 100644 --- a/docs/firmware_update.md +++ b/docs/firmware_update.md @@ -263,7 +263,7 @@ partition. erases the bootloader region and writes in-place. An interruption during the write leaves the device unbootable. -- **Not revertable.** There is no swap or rollback mechanism. The old +- **Not revertible.** There is no swap or rollback mechanism. The old bootloader and application are destroyed during the update. - **Locks bootloader verification to a specific application version.**