Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/test-sim-self-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ jobs:
cp config/examples/sim-self-update-ext.config .config
make test-sim-self-update-ext

- name: Run monolithic self-update test
run: |
make clean
cp config/examples/sim-self-update-monolithic.config .config
make test-sim-self-update-monolithic

- name: Run self-header verification test (internal flash)
run: |
make clean
Expand All @@ -43,3 +49,10 @@ jobs:
make clean
cp config/examples/sim-self-header-ext.config .config
make test-sim-self-header-ext-verify

- name: Run combined monolithic self-update + self-header test
run: |
make clean
cp config/examples/sim-self-update-monolithic.config .config
make test-sim-self-update-monolithic-self-header WOLFBOOT_SELF_HEADER=1 WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS=0x1F000

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ assemble_internal_flash.dd: FORCE
0 wolfboot.bin \
$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) test-app/image_v1_signed.bin \
$$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS)-$(ARCH_FLASH_OFFSET))) /tmp/swap \
$$(($(WOLFBOOT_PARTITION_SWAP_ADDRESS)-$(ARCH_FLASH_OFFSET))) /tmp/swap
$(if $(filter 1,$(DISABLE_BACKUP)),,$$(($(WOLFBOOT_PARTITION_SWAP_ADDRESS)-$(ARCH_FLASH_OFFSET))) /tmp/swap) # omit swap partition if DISABLE_BACKUP=1

internal_flash.dd: $(BINASSEMBLE) wolfboot.bin $(BOOT_IMG) $(PRIVATE_KEY) test-app/image_v1_signed.bin
@echo "\t[MERGE] internal_flash.dd"
Expand Down
8 changes: 4 additions & 4 deletions config/examples/sim-self-update-monolithic.config
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ RAM_CODE=1
SELF_UPDATE_MONOLITHIC=1
WOLFBOOT_VERSION=1

# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x40000
# Partition size 512KB so the monolithic payload (bootloader region + app)
# fits in the UPDATE partition.
WOLFBOOT_PARTITION_SIZE=0x80000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20000
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x60000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0xA0000
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0xA0000

# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1
20 changes: 20 additions & 0 deletions include/wolfboot/wolfboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,26 @@ extern "C" {

#endif /* defined WOLFBOOT */

/* Monolithic self-update: imply DISABLE_BACKUP and enforce prerequisites */
#ifdef WOLFBOOT_SELF_UPDATE_MONOLITHIC
#ifndef DISABLE_BACKUP
#define DISABLE_BACKUP
#endif
#ifdef DELTA_UPDATES
#error "DELTA_UPDATES is not compatible with WOLFBOOT_SELF_UPDATE_MONOLITHIC"
#endif
#ifdef NVM_FLASH_WRITEONCE
#error "NVM_FLASH_WRITEONCE is not compatible with WOLFBOOT_SELF_UPDATE_MONOLITHIC"
#endif
#ifndef RAM_CODE
#error "WOLFBOOT_SELF_UPDATE_MONOLITHIC requires RAM_CODE"
#endif
#endif

#if defined(DISABLE_BACKUP) && defined(DELTA_UPDATES)
#error "DELTA_UPDATES requires swap partition (incompatible with DISABLE_BACKUP)"
#endif

#define PART_BOOT 0
#define PART_UPDATE 1
#define PART_SWAP 2
Expand Down
2 changes: 2 additions & 0 deletions options.mk
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ endif
## the bootloader region into the contiguous boot partition.
ifeq ($(SELF_UPDATE_MONOLITHIC),1)
CFLAGS+=-DWOLFBOOT_SELF_UPDATE_MONOLITHIC
DISABLE_BACKUP=1
endif

## Persist wolfBoot self header at fixed address
Expand Down Expand Up @@ -719,6 +720,7 @@ endif

ifeq ($(DISABLE_BACKUP),1)
CFLAGS+= -D"DISABLE_BACKUP"
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0
endif

DEBUG_SYMBOLS?=0
Expand Down
30 changes: 29 additions & 1 deletion src/update_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ void RAMFUNCTION wolfBoot_check_self_update(void)
}
#endif /* RAM_CODE for self_update */

#ifndef WOLFBOOT_SELF_UPDATE_MONOLITHIC
/* The swap-based update machinery (wolfBoot_copy_sector, wolfBoot_update, etc.)
* is not used in monolithic self-update mode. */

static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
struct wolfBoot_image *dst, uint32_t sector)
{
Expand Down Expand Up @@ -804,7 +808,10 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
* magic has not been set flag will have an un-determined value when we go
* to check it */
uint8_t flag = SECT_FLAG_NEW;
struct wolfBoot_image boot, update, swap;
struct wolfBoot_image boot, update;
#ifndef DISABLE_BACKUP
struct wolfBoot_image swap;
#endif
uint16_t update_type;
uint32_t fw_size;
uint32_t size;
Expand Down Expand Up @@ -856,7 +863,9 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
return -1;
#endif
wolfBoot_open_image(&boot, PART_BOOT);
#ifndef DISABLE_BACKUP
wolfBoot_open_image(&swap, PART_SWAP);
#endif

#if defined(EXT_ENCRYPTED) && defined(DELTA_UPDATES)
wolfBoot_printf("Update partition fallback image: %d\n", fallback_image);
Expand Down Expand Up @@ -1208,6 +1217,7 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
#ifdef __CCRX__
#pragma section
#endif
#endif /* !WOLFBOOT_SELF_UPDATE_MONOLITHIC */

#if defined(ARCH_SIM) && defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_SEAL)
int wolfBoot_unlock_disk(void)
Expand Down Expand Up @@ -1319,12 +1329,14 @@ int wolfBoot_unlock_disk(void)
void RAMFUNCTION wolfBoot_start(void)
{
int bootRet;
#ifndef WOLFBOOT_SELF_UPDATE_MONOLITHIC
int updateRet;
#ifndef DISABLE_BACKUP
int resumedFinalErase;
#endif
uint8_t bootState;
uint8_t updateState;
#endif /* !WOLFBOOT_SELF_UPDATE_MONOLITHIC */
struct wolfBoot_image boot;

#if defined(ARCH_SIM) && defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_SEAL)
Expand All @@ -1335,6 +1347,8 @@ void RAMFUNCTION wolfBoot_start(void)
wolfBoot_check_self_update();
#endif

#ifndef WOLFBOOT_SELF_UPDATE_MONOLITHIC

#ifdef NVM_FLASH_WRITEONCE
/* nvm_select_fresh_sector needs unlocked flash in cases where the unused
* sector needs to be erased */
Expand Down Expand Up @@ -1393,6 +1407,12 @@ void RAMFUNCTION wolfBoot_start(void)
}
}

#else /* WOLFBOOT_SELF_UPDATE_MONOLITHIC */
#ifdef SECURE_PKCS11
WP11_Library_Init();
#endif
#endif /* !WOLFBOOT_SELF_UPDATE_MONOLITHIC */

bootRet = wolfBoot_open_image(&boot, PART_BOOT);
wolfBoot_printf("Booting version: 0x%x\n",
wolfBoot_get_blob_version(boot.hdr));
Expand All @@ -1404,6 +1424,7 @@ void RAMFUNCTION wolfBoot_start(void)
) {
wolfBoot_printf("Boot failed: Hdr %d, Hash %d, Sig %d\n",
boot.hdr_ok, boot.sha_ok, boot.signature_ok);
#ifndef WOLFBOOT_SELF_UPDATE_MONOLITHIC
wolfBoot_printf("Trying emergency update\n");
if (likely(wolfBoot_update(1) < 0)) {
/* panic: no boot option available. */
Expand All @@ -1427,6 +1448,13 @@ void RAMFUNCTION wolfBoot_start(void)
wolfBoot_panic();
}
}
#else
/* Monolithic mode: no emergency update path available */
#ifdef WOLFBOOT_TPM
wolfBoot_tpm2_deinit();
#endif
wolfBoot_panic();
#endif /* !WOLFBOOT_SELF_UPDATE_MONOLITHIC */
}
PART_SANITY_CHECK(&boot);
#else
Expand Down
51 changes: 46 additions & 5 deletions tools/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -282,15 +282,13 @@ test-sim-self-update-monolithic: wolfboot.bin test-app/image_v1_signed.bin FORCE
$(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
@# Create erased boot partition
$(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
@# Assemble flash: wolfboot.bin at 0, empty boot partition, update partition
$(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
$$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS) - $(ARCH_FLASH_OFFSET))) update_part.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)
Expand All @@ -302,6 +300,49 @@ test-sim-self-update-monolithic: wolfboot.bin test-app/image_v1_signed.bin FORCE
@echo " Nested app at boot partition: PASSED"
@echo "=== Monolithic Self-Update Test PASSED ==="

# Test monolithic self-update with self-header persistence.
# Same as test-sim-self-update-monolithic, but also verifies that the
# self-header was persisted at WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS and
# matches the signing tool's --header-only output byte-for-byte.
#
test-sim-self-update-monolithic-self-header: wolfboot.bin test-app/image_v1_signed.bin FORCE
@echo "=== Simulator Monolithic Self-Update + Self-Header Test ==="
@# Create dummy bootloader (0xAA pattern, exactly bootloader region 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, and generate header-only
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update monolithic_payload.bin $(PRIVATE_KEY) 2
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update --header-only 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 partition and self-header sector
$(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' > self_hdr.dd
@# Assemble flash: wolfboot.bin at 0, erased self-header, empty boot partition, update partition
$(Q)$(BINASSEMBLE) internal_flash.dd \
0 wolfboot.bin \
$$(($(WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS) - $(ARCH_FLASH_OFFSET))) self_hdr.dd \
$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) boot_part.dd \
$$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS) - $(ARCH_FLASH_OFFSET))) update_part.dd
@# Run simulator - self-update fires, copies monolithic payload to offset 0 and persists header
$(Q)./wolfboot.elf get_version || true
@# Verify bootloader region up to self-header contains 0xAA pattern
@# (the self-header sector itself is overwritten by wolfBoot_update_self_header)
$(Q)cmp -n $$(($(WOLFBOOT_PARTITION_SELF_HEADER_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"
@# Extract persisted self-header and verify it matches --header-only output
$(Q)dd if=internal_flash.dd bs=1 skip=$$(($(WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS) - $(ARCH_FLASH_OFFSET))) count=$$(($(WOLFBOOT_SECTOR_SIZE))) of=persisted_hdr.dd 2>/dev/null
$(Q)cmp -n $$(($(IMAGE_HEADER_SIZE))) persisted_hdr.dd monolithic_payload_v2_header.bin
@echo " Self-header persisted correctly: PASSED"
@echo "=== Monolithic Self-Update + Self-Header Test PASSED ==="

# Test self-header cryptographic verification (hash + signature validation)
#
# Verifies that an application can cryptographically verify the bootloader using
Expand Down
Loading