Commit Graph

3270 Commits (c4e853ea4b13cc3bcbf701f4f648afeb0fbe095f)

Author SHA1 Message Date
Daniele Lacamera c4e853ea4b F-6131: enforce full-transfer bounds check in spi_flash_read/spi_flash_write (QSPI)
spi_flash_read only rejected address > FLASH_DEVICE_SIZE (off-by-one,
admits address == FLASH_DEVICE_SIZE) and never validated address+len
against the device size, so an in-bounds start with an out-of-range
extent was not rejected. spi_flash_write had no bounds check at all.
Add an inclusive/full-extent check to both.
2026-07-02 16:17:51 +02:00
Daniele Lacamera dd16ccb590 F-6405: pin partition-fit accept boundary in wolfBoot_open_image_address/open_self_address
The fw_size > (WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE) guard was only
tested on the reject side (oversize + 1); no test asserted that a firmware
payload exactly filling the partition payload budget is accepted. A >/>=
mutation at image.c:1402 or image.c:1618 would silently reject a
maximally-sized valid image and survive the existing suite. Add positive
boundary assertions (via wolfBoot_open_image()/wolfBoot_open_image_address()
and wolfBoot_open_self_address()) paired with the existing reject-side
checks in test_open_image.
2026-07-02 16:05:38 +02:00
Daniele Lacamera 102ddc38fd F-5964: fix stale in-word offset in hal_flash_write byte-wise path (samr21/same51)
In the else branch of hal_flash_write, off was computed once per call from
the original (call-time) "address" instead of the current position
"address + i". The word index dst_idx advanced with i, but the fill loop
kept starting at the stale off, so once destination address and source
buffer had different alignment mod 4, every word after the first was
filled at the wrong byte offset, dropping and misplacing data. Derive off
and dst from address + i so each word's offset tracks the current
position, mirroring the fix already applied to mcxa.c for the same bug
class (F-5963).
2026-07-02 15:57:54 +02:00
Daniele Lacamera eb5574f19e F-6124: emit build-time warning for SIGN=NONE / WOLFBOOT_NO_SIGN
SIGN=NONE disables firmware signature authenticity verification
entirely (wolfBoot_verify_authenticity() becomes a stub that always
confirms), leaving only a hash check an attacker can satisfy. Every
other fail-safe-weakening option in this file (ALLOW_DOWNGRADE,
DISABLE_BACKUP, WOLFBOOT_UDS_UID_FALLBACK_FORTEST, FPGA_NONFATAL)
emits a $(warning ...) so the tradeoff is visible at build time;
SIGN=NONE was missing one despite being the most security-critical.
2026-07-02 15:47:17 +02:00
Daniele Lacamera 72186fa8d3 F-6126: add mutation-pinning test coverage for wolfBoot_check_flash_image_elf
The scattered-ELF flash integrity check's final image_CT_compare()
rejection branch had zero unit test coverage, so a weakened comparison
(e.g. != 0 -> == 0, or a dropped return -2) would silently pass. Add a
positive case (correctly-hashed scattered image verifies OK) and a
negative case (single corrupted byte in a scattered segment's
flash-resident payload is rejected via the digest-mismatch branch).
2026-07-02 15:46:24 +02:00
Daniele Lacamera 9a25fae89d F-6127: fix custom-TLV 8-byte value saturation in arg2num
arg2num() parsed --custom-tlv values with signed strtoll(), which
saturates to LLONG_MAX (0x7FFFFFFFFFFFFFFF) on positive overflow. For
LEN==8 no masking is applied afterwards (unlike LEN 1/2/4), so any
value >= 2^63 silently encoded as 0x7FFFFFFFFFFFFFFF instead of the
value the user supplied, breaking the TLV encode/decode roundtrip.

Switch to strtoull() and reject (exit 16) when it reports ERANGE for
an 8-byte value, mirroring the existing fw_version range check.
2026-07-02 15:28:09 +02:00
Daniele Lacamera dd0712ec52 F-6130: clear disk_encrypt_key/nonce before panic paths that skip the final cleanup
update_disk.c wolfBoot_start() already zeroizes disk_encrypt_key/nonce and
the decrypted header before most wolfBoot_panic() halts, but four paths
were missed: anti-rollback rejection, FIT FPGA load failure, FIT kernel
load failure, and flash-protect failure. Since wolfBoot_panic() halts
forever on real targets, these paths left the key live in BSS on a halted
device. Add the same disk_decrypted_header_clear()/disk_crypto_clear()
pair used on the other panic paths immediately before each.
2026-07-02 15:23:43 +02:00
Daniele Lacamera e38296c984 F-6398: fix OOB write in bmpatch when reconstructed image grows past source size
bmpatch mmaps `base` sized to the source file (len1) then memcpy's the
reconstructed output into base+len3, which runs past the mapping once the
destination image is larger than the source (a common case for delta
updates). This causes writes into the zero-fill slack of the last mapped
page to be silently dropped (never synced to the file even after the
trailing ftruncate) or, for larger overruns, a SIGBUS. Reproduced with the
existing `delta-test` fixtures: patching 1.txt back to the (larger) 0.txt
already corrupts the tail of the output today.

Write reconstructed blocks with pwrite(fd1, ...) instead of memcpy into the
undersized mapping; regular file writes grow the file naturally instead of
faulting/silently discarding data past the mapped region. The mmap of
`base` is only used for reads, so this is a minimal, in-place-preserving
fix. Verified `make -C tools/delta delta-test` now passes both directions
(shrinking 0->1 and growing 1->0).
2026-07-02 15:18:21 +02:00
Daniele Lacamera 32e41f0f40 F-6399: fix imx_rt DCACHE invalidation to include down-alignment offset
hal_flash_write() and hal_flash_erase() aligned the invalidation start
address down to a 32-byte cache line but rounded the length up from
"len" alone, omitting the (address - aligned_address) offset. Whenever
(address % 32) + (len % 32) > 32, the invalidated range fell short of
address + len, leaving the last cache line stale after a write/erase.

Extract the range computation into hal_flash_cache_align_range()
(hal/imx_rt.h, dependency-free so it's unit-testable without the
NXP SDK) and include the down-alignment offset before rounding the
length up, so the invalidated range always covers [address, address+len).
2026-07-02 15:13:28 +02:00
Daniele Lacamera e09074a0c6 F-6401: emit build-time warning for FPGA_NONFATAL=1
FPGA_NONFATAL downgrades a failed PL bitstream load from fatal (panic)
to a logged non-fatal warning, letting boot continue without the
programmable logic. Every other fail-safe-weakening option in this
file (ALLOW_DOWNGRADE, DISABLE_BACKUP,
WOLFBOOT_UDS_UID_FALLBACK_FORTEST) emits a $(warning ...) so the
tradeoff is visible at build time; FPGA_NONFATAL was missing one.
2026-07-02 15:07:05 +02:00
Daniele Lacamera f20a1e13a6 F-6403: add successful-boot test coverage for HW-swap wolfBoot_start
test_hwswap_highversion_rollback_denied was the only test for
update_flash_hwswap.c's wolfBoot_start and always ends in boot_panic,
so the entire successful-boot path (IMG_STATE_UPDATING->TESTING
transitions before and after the HW dualbank swap, and the same-version
boundary of the anti-rollback check) was never exercised and mutations
there would go undetected. Add three tests that reach do_boot() and pin
each of those code paths.
2026-07-02 15:06:17 +02:00
Daniele Lacamera 8df96895f6 F-6408: zeroize UDS from OTP keystore generator's heap and stack buffers
otp-keystore-gen.c reads the device root UDS into the stack buffer
`uds` and copies it into the heap buffer `otp_buf` at OTP_UDS_OFFSET,
then on every exit path calls free(otp_buf) without wiping it first,
and never clears `uds`. Both copies of the highest-value device secret
remain in the host process's freed heap chunk and stack frame.

Add a local secure_zero() helper (no wolfSSL dependency, matching this
standalone host tool's existing bare-gcc build) and call it on the
success path and on the write-failure/short-UDS-read error paths,
before free()/exit(), mirroring the zeroize-before-release pattern
already used elsewhere in this tree (src/x86/ata.c,
src/x86/ahci.c). Paths that exit before `uds` is populated are left
untouched since there is no secret to wipe yet.
2026-07-02 14:56:48 +02:00
Daniele Lacamera fea97c55f7 F-5963: fix over-advance of address/len in unaligned hal_flash_write (kinetis.c, mcxa.c, mcxw.c)
In the unaligned/partial-word path, address/len were advanced by the full
flash-word-relative loop index "i" (which starts at start_off), instead of
by the number of data bytes actually consumed (i - start_off). On a write
spanning more than one flash word this drops start_off bytes of input data
and misdirects the following word write. Mirrors the already-correct form
in hal/kinetis_kl26.c.
2026-07-02 14:47:38 +02:00
Daniele Lacamera 9ce750fdc6 F-5965: skip wb_diff match candidates whose offset MSB collides with ESC
A matched block's source offset is encoded as off[0..2] right after the
ESC (0x7f) header marker. When the match offset falls in
[0x7f0000, 0x7fffff], off[0] is 0x7f, so the header begins with ESC ESC
-- the same two bytes wb_patch uses to decode an escaped literal 0x7f.
The decoder then emits a single literal byte, consumes only 2 of the 6
header bytes, and desyncs the rest of the stream, breaking the
wb_patch(wb_diff(A,B)) == B roundtrip for base images >= ~8MB (a
supported MMU/Linux delta-update configuration).

Make wb_diff skip any candidate match whose offset's most-significant
byte equals ESC, in both the forward (base-image) and backward
(previously-patched-image) search paths, so the ambiguous header is
never produced; the position falls back to literal encoding instead.
2026-07-02 14:35:07 +02:00
Daniele Lacamera cd4e4be2f6 F-5968: zeroize disk-unlock passphrase from static ATA command buffer
security_command_passphrase() copies the plaintext disk-unlock secret
into the file-static DMA buffer `buffer` at ATA_SECURITY_PASSWORD_OFFSET
but never wipes it. On the slot<0 early return no ATA command is even
dispatched, and on failures of ata_security_set_password()/
ata_security_unlock_device() (which sata_unlock_disk() turns into a
panic()) no later IDENTIFY DMA ever overwrites it, so the secret is
left resident in BSS for as long as the device stays powered.

Zeroize the password field on the slot<0 path and after synchronous
command completion. The async path (used only by the currently
unreachable ata_security_erase_unit()) is left untouched because the
HBA may still be DMAing out of the buffer when exec_cmd_slot_ex()
returns ATA_ERR_BUSY; wiping it there would race the transfer.
2026-07-02 14:27:04 +02:00
Daniele Lacamera 20f11ae854 F-6129: zeroize disk-unlock secret before the state-mismatch panic in sata_unlock_disk
sata_unlock_disk() calls panic() directly when the post-unlock ATA
security state doesn't match the expected SEC5/SEC6, bypassing the
cleanup: label that zeroizes the plaintext secret[] stack buffer. On
x86, panic() is an infinite hlt() loop, so the plaintext disk-unlock
secret (TPM-unsealed key or password) remains readable in DRAM for as
long as the device stays halted. Zeroize secret[] before panic() on
this path, mirroring the existing cleanup zeroization.
2026-07-02 14:18:03 +02:00
Daniele Lacamera 60acdc231e F-6402: add negative tests pinning wolfBoot_check_rot digest comparison
Add tests asserting rejection on a mismatched pubkey hint and on a
short digestSz from wolfTPM2_NVReadAuth, so a weakened comparison
(e.g. == 0 -> >= 0, or a dropped clause) is caught.
2026-07-02 14:10:44 +02:00
Daniele Lacamera 228c9d6d80 F-6407: zeroize static cached_sector after each flash commit in psa_store
cache_commit() is the single choke point through which every psa_store
helper (create_object, delete_object, wolfPSA_Store_Write's sector loop,
update_store_size, erase_object_payload, check_vault) flushes the static
cached_sector staging buffer to flash. The buffer was never cleared, so
key-object plaintext staged there could remain resident in static SRAM
after the store operation returned. Wipe cached_sector with wc_ForceZero
right after the flash write completes, mirroring the existing pattern in
src/wolfhsm_flash_hal.c.
2026-07-02 14:03:24 +02:00
Marco Oliverio 466c481ba3 fdt: break loop compatibles when no NUL-terminator is found 2026-07-02 09:23:18 +02:00
Sameeh Jubran 2ef247a31e fix: capture real build config in sbom target and harden recipe
The sbom target fed `cc -dM -E` an empty /dev/null with only
WOLFSSL_USER_SETTINGS, so gen-sbom's build properties collapsed to host
compiler builtins (all filtered out as noise) and the SBOM did not reflect
the selected configuration. Harvest the actual -D config macros from CFLAGS
(filtered in the shell so defines whose values contain spaces, e.g.
BOOTLOADER_PARTITION_SIZE=$((...)), survive intact) so the SBOM captures the
real TARGET/SIGN/HASH/feature set.

Also:
- add preflight checks for empty WOLFBOOT_VERSION and missing GEN_SBOM
- pass sources via --srcs-file to avoid ARG_MAX on large configs
- include .S sources in the source set, not just .c
- make HOSTCC and GEN_SBOM overridable
- README: soften "CRA Compliance" wording, use wolfboot-<version>.* names,
  fix dangling wolfssl/doc/CRA.md link to point at the wolfSSL CRA Kit

Signed-off-by: Sameeh Jubran <sameeh.j@gmail.com>
2026-07-02 08:48:39 +02:00
Mark Atwood 5c75c51f46 docs: add SBOM/EU CRA Compliance section to README 2026-07-02 08:48:39 +02:00
Mark Atwood f0b28d2df5 feat: add sbom Makefile target
Adds sbom target that produces CycloneDX and SPDX
SBOM files for a specific TARGET+SIGN combination.
Sources extracted from OBJS variable via wildcard.
wolfcrypt sources compiled into wolfBoot are listed
as wolfBoot's own sources (not a separate component).
Requires GEN_SBOM or WOLFBOOT_LIB_WOLFSSL set.
2026-07-02 08:48:39 +02:00
Alex Lanzano 76b023008b Add DEBUG_UART build test for stm32wba. Fix stm32wba clock init 2026-07-02 08:44:45 +02:00
Alex Lanzano 337dabf2f2 Implement port for STM32WBA. Bump wolfHAL lib to latest 2026-07-02 08:44:45 +02:00
David Garske 221f2db787
Merge pull request #812 from danielinux/improve-armored-digest
armored: harden image integrity check against fault injections
2026-07-01 15:01:31 -07:00
Daniele Lacamera b0b36360ff test: bump SIGN=NONE footprint limit 2026-07-01 20:42:27 +02:00
Daniele Lacamera ed695bb0a2 armored: reset integrity state and extend sanity check 2026-07-01 20:28:58 +02:00
Daniele Lacamera 93f068b930 armored: harden image integrity check against fault injections 2026-07-01 19:48:02 +02:00
Aidan Garske 412face911
Merge pull request #811 from padelsbach/fix-wolfhsm-nightly
Add WOLFBOOT_TZ_TEST_BKPT=1 to fix wolfHSM nightly test
2026-06-30 16:34:12 -07:00
Paul Adelsbach 6558511ccb Add WOLFBOOT_TZ_TEST_BKPT=1 to fix wolfHSM nightly test 2026-06-30 13:37:37 -07:00
David Garske 1ad650b5be
Merge pull request #808 from rizlik/image_auth_int_fix
image: check integrity in wolfBoot_verify_authenticity()
2026-06-29 14:00:56 -07:00
Marco Oliverio ab80578d59 image: check integrity in wolfBoot_verify_authenticity() 2026-06-25 17:35:18 +02:00
David Garske 880c0a778e
Merge pull request #769 from aidangarske/h5-wolfhsm-port
Add WOLFCRYPT_TZ_WOLFHSM TrustZone engine for STM32H5
2026-06-24 19:15:55 -07:00
aidan garske b9bd6dae17 Add WOLFCRYPT_TZ_WOLFHSM TrustZone engine for STM32H5 2026-06-24 15:49:43 -07:00
David Garske b044c894fd
Merge pull request #806 from rizlik/oob_update_disk
update_disk.c: enforce bound over memcpy
2026-06-24 15:16:41 -07:00
Marco Oliverio 6e117a5b50 update_disk.c: enforce bound over memcpy 2026-06-23 17:28:25 +02:00
David Garske dd4fc26df8
Merge pull request #803 from rizlik/tpm_mfg_auth_value
IDevID: allow using pre-computed auth values
2026-06-22 08:49:25 -07:00
David Garske 7a76369acb
Merge pull request #798 from bigbrett/wolfhsm-no-keystore
Wolfhsm no keystore
2026-06-18 09:31:11 -07:00
David Garske 08c8bddc0d
Merge pull request #802 from rizlik/fix_oob_ramboot
fix: bound unauthenticated image size before RAM load
2026-06-18 08:01:55 -07:00
Marco Oliverio 4a1fc49aa6 test/ram-enc: add exact-max and one-block-over boundary tests 2026-06-18 11:26:15 +02:00
Marco Oliverio 6017dc5f2f ram_decrypt: assert RAM load region is block-aligned 2026-06-18 11:26:15 +02:00
Marco Oliverio e454c082fe ramboot: prefer RAMBOOT_MAX_SIZE bound over partition size 2026-06-18 11:26:15 +02:00
Marco Oliverio 0438c54c9b tpm: rename masterPassword param to authOverride 2026-06-18 11:06:18 +02:00
Marco Oliverio 723fffebc8 tpm: build MFG identity configs in CI 2026-06-18 11:06:18 +02:00
Marco Oliverio 68c797db72 tpm: dedupe precomputed authValue handle copy 2026-06-18 11:06:18 +02:00
Marco Oliverio f9cad20f5b tpm: zeroize EH master secret after derive 2026-06-18 10:45:40 +02:00
Marco Oliverio cb56e866b6 tpm: remove trailing whitespace in MFG identity docs 2026-06-18 10:45:13 +02:00
Marco Oliverio 8518eabc23 tpm: fix wolfBoot_tpm2_get_aik typo in header comment 2026-06-18 10:45:02 +02:00
Marco Oliverio 0649e5de99 ramboot: match #error text to the bounds-check guard 2026-06-18 10:22:55 +02:00
Marco Oliverio 4d1c961ae2 ram_decrypt: read header length endian-safe and aligned 2026-06-18 10:22:32 +02:00