- Add NVM ECC mode, which introduces a new erase check HAL API to use
flash controller HW to blank check sectors instead of reading them
and comparing to an erased byte (which typically triggers an ECC
fault)
- Add NVM Journal mode as an alternative to NVM_FLASH_WRITE_ONCE that
does not require a sector-size RAM buffer and dramatically reduces
the number of erases and programs required to set individual flags,
while also being much more robust to power-cuts.
- ramboot_region_overlap in image.h: brace the single-statement ifs
(house C style) and wrap the 82-col comment line.
- .gitignore: unit-update-flash-db test binary.
The encrypted RAM load path only bounded the unauthenticated image
length; a bit-flipped header size could drive the decrypt loop over
wolfBoot's own code before the post-decryption signature check. Add
the same destination/wolfBoot overlap check the ramboot loader already
has, and move the ramboot_region_overlap helper to image.h so both
loaders share it.
The WOLFBOOT_DICE_HW exception assumed hardware DICE leaves the
secure world verify-only, but only the DICE attestation key runs on
the crypto engine: the secure PSA service still does software RSA/ECC
on keys created or imported through the IPC, so drop the exception and
let every WOLFCRYPT_SECURE_MODE fastmath build define
TFM_TIMING_RESISTANT.
sign.py and keygen.py are superseded by the C tools/keytools/sign and
keygen (built by the same Makefile, no python/wolfcrypt-py
dependency). Rewrite unit-sign-delta-tlv.py to sign a real delta
image with the C sign tool instead of the python bmdiff/sign.py
pipeline, and update README.md and include/delta.h references.
Three CI failures from the new bootloader-region overlap guards:
renesas_rx72n: the swap check measured the swap area as a full
WOLFBOOT_PARTITION_SIZE, but swap is one sector (the pre-existing
boot/update-vs-swap guards already use WOLFBOOT_SECTOR_SIZE). On rx72n
that inflated swap to 0xFFFE0000+0x1F0000 and falsely overlapped the
write-protect region at 0xFFFF0000. Use WOLFBOOT_SECTOR_SIZE.
- Add missing END_TEST after each START_TEST in unit-nrf5340-uart-crlf.c
- Fix partition overlap checks in target.h.in to use standard interval
intersection (catches partitions that start below WOLFBOOT_ORIGIN and
extend into the bootloader region)
nrf5340: the target references nrf5340_uart_crlf (src/update_flash.c)
but the Makefile does not compile hal/nrf5340_uart.c, so the linker
fails. Add the object to OBJS (Makefile) and APP_OBJS (test-app).
cypsoc6: the new boot/update/swap vs bootloader-region #error guards
in include/target.h.in fire on the cypsoc6 layout, where the boot
partition intentionally overlaps the bootloader region (the bootloader
and the boot image share the same flash region). Introduce
WOLFBOOT_ALLOW_PART_OVERLAP (defined in cypsoc6.config, gated in
target.h.in, added to CONFIG_VARS in tools/config.mk) to suppress the
guards for targets that legitimately overlap.
Verified: nrf5340 builds (make distclean + cp config + make, exit 0,
wolfboot.bin created). cypsoc6 cannot be built locally (the CI checks
out lib/psoc6pdl from Infineon, which is not available locally), but
the WOLFBOOT_ALLOW_PART_OVERLAP guard is verified to suppress the
#error for the cypsoc6 layout.
The boot, update and swap partitions were never checked against the
bootloader write-protect region [WOLFBOOT_ORIGIN, WOLFBOOT_ORIGIN +
BOOTLOADER_PARTITION_SIZE). An over-sized BOOTLOADER_PARTITION_SIZE
silently write-protects the head of a partition; the existing
boot/update/swap overlap guards did not cover this.
Add three #error guards (boot, update, swap vs bootloader region) to
include/target.h.in, gated on WOLFBOOT_ORIGIN < the partition address so
they only fire for real targets (the mock target has WOLFBOOT_ORIGIN ==
WOLFBOOT_PARTITION_BOOT_ADDRESS, a valid simplified geometry).
The undersized guard (BOOTLOADER_PARTITION_SIZE not covering the
self-update erase range) is deferred: it requires a compile-time
constant for ARCH_FLASH_OFFSET, which is a runtime value (sim_ram_base)
for the mock target.
The compile-only negative tests (part 2 of the finding) are deferred.
The wolfSSL bump to master 4aa1ad7a5 wraps all of coding.h in
"#ifndef NO_CODING". That block also holds the auto-enable that turns
WOLFSSL_KEY_GEN into WOLFSSL_BASE64_ENCODE, so wolfBoot configurations
that set both WOLFSSL_KEY_GEN (SECURE_PKCS11) and NO_CODING lost the
Base64_Encode() declaration -- and coding.c compiles to nothing under
NO_CODING, so the definition is gone too. settings.h still derives
WOLFSSL_DER_TO_PEM from WOLFSSL_KEY_GEN, so asn.c kept compiling
wc_DerToPemEx() and failed with an implicit declaration of
Base64_Encode(). This broke every TrustZone and PKCS11 target.
wolfBoot never emits PEM, so define WOLFSSL_NO_DER_TO_PEM whenever
NO_CODING is set rather than pulling base64 back in. The check sits
after the HAVE_FIPS block, which may undef NO_CODING. wolfTPM's
wc_DerToPem() callers are themselves guarded by WOLFSSL_DER_TO_PEM, so
they simply drop their optional PEM encoding path.
Separately, the update grows wolfboot by 8-136 bytes depending on the
configuration, so re-measure every test-size-all entry with the CI
container and record the new sizes.
c3f9717f guarded the success/trigger/sector-flag declarations behind
WOLFBOOT_FIXED_PARTITIONS, but wolfboot.h includes target.h only under
__WOLFBOOT, so test-apps (compiled without __WOLFBOOT) never saw the
macro and failed with implicit-declaration errors on imx95_m7, mcxa,
mcxw and mcxw-tz. Unguard the header declarations; keep the definitions
guarded and move wolfBoot_success out of the fixed-partition guard
since it only uses the partition-state API.
Called from the RAM-resident update path (update_ram.c) under
EXT_FLASH; place the body in RAM so it runs after flash remap
instead of faulting.
Verification: built unit-custom-trailer-nopart (EXT_FLASH) - compiles
clean; imx95_m7 (EXT_FLASH, CI repro) - compiles clean.
- libwolfboot.c: keep the partition state APIs (set/get_partition_state)
available to CUSTOM_PARTITION_TRAILER / WOLFBOOT_NO_PARTITIONS builds;
guard the fixed-partition APIs (sector flags, erase, trigger, success)
behind WOLFBOOT_FIXED_PARTITIONS. Add the unit-custom-trailer-nopart
compile target to lock in that configuration.
- unit-p1021-fcm-bytes.c: add program tests for status 0x81 (fail) and
0x00 (write-protected), asserting no later page is programmed.
- unit-p1021-erase-advance.c: add an erase test for status 0x00
(write-protected), asserting failure before advancing to the next block.
Add HAVE_PARTITION_TRAILERS macro (set when WOLFBOOT_FIXED_PARTITIONS or
CUSTOM_PARTITION_TRAILER is defined) and use it to gate the TESTING state
transition in update_ram.c. Previously the gate was WOLFBOOT_FIXED_PARTITIONS
only, so targets using custom partition trailers never transitioned from
UPDATING to TESTING, allowing rollback to older versions.
Add unit-update-ram-custom-trailer test covering the CUSTOM_PARTITION_TRAILER
path with mocked get/set_trailer_at callbacks.
Secure-mode worlds (TZ_PSA/PKCS11/FWTPM/WOLFHSM) process private keys
in software, so a USE_FAST_MATH build of one of them must keep the
timing-resistant TFM path instead of falling back to WC_NO_HARDEN.
The old condition only covered software DICE; FIPS=1 already forces
SPMATH (options.mk M10) and all CMake presets set SPMATH, so no
shipped config changes - this closes the integrator Makefile gap.
WOLFBOOT_DICE_HW stays verify-only (requires WOLFCRYPT_TZ_PSA).
wolfBoot_start() zeroed os_image once, before the retry loop, so the
fallback iteration kept the stale img->hdr of the failed partition and
wolfBoot_open_image_address() (which only adopts load_address when
hdr is NULL) re-verified the wrong image. The external header cache
had the same problem: it kept the first image opened.
memset the struct and invalidate the EXT_FLASH header cache at the
top of each loop iteration, per the documented precondition of
wolfBoot_open_image_address().
Add unit-update-ram-nofixed-noramboot: the non-fixed-partition,
non-RAMBOOT (XIP) layout where load_address varies per retry, with
fallback tests both directions plus candidate-selection checks.
The store commits sectors with hal_flash_erase()/hal_flash_write() and
then reads them back through the memory map - sector_ptr(),
cache_get_sector()'s refill, and the raw magic reads in check_vault().
On a part that caches flash reads (STM32 ICACHE) those reads can return
pre-erase bytes. check_vault() is the worst case: a stale magic there
does not merely read wrong, it triggers restore_backup() or a full vault
re-initialisation, losing the token.
Every wolfPKCS11 field write flushed the payload sector and the header
sector to flash (2 erases + 2 programs of a full sector each), and the
token store re-serializes all objects per C_CreateObject/C_DestroyObject,
so those calls cost hundreds of sector erases and tens of seconds on
flash with slow erase times.
Cache modified sectors in RAM and commit them together when the store
window closes:
- sector cache sized to the worst-case span of one object plus the
header sector (WOLFBOOT_PKCS11_STORE_CACHE_SECTORS), LRU eviction
when exceeded
- header sector commits last, so a committed header is the atomic
commit point of the batch: power failure during a flush leaves the
flash in either the pre-batch or the post-batch state
- per-commit backup sector write preserved, keeping recovery of the
sector in flight at failure time
- delete_object commits on return (durability contract, unit-tested)
- nodes table, bitmap, payload ids and the live object size
(handle->size) are read from the cache when the sector is dirty
Measured on an STM32H5 with 8KB sectors, wolfPKCS11 in the secure
world: C_CreateObject 1.5s -> 0.15s, C_DestroyObject 1.3s -> 0.12s,
456 -> 40 sector erases per create, and the count no longer scales
with the number of objects in the token.
PKCS11_STORE_STATS (off by default) adds flash-activity counters and a
test-app bench to quantify store traffic: make PKCS11_STORE_STATS=1.