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
16 changes: 16 additions & 0 deletions .github/workflows/test-build-aarch64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ on:
required: false
type: boolean
default: false
fips:
# Download the FIPS-ready wolfSSL tree into ../ before building, for a
# build-only FIPS=1 verification (see WOLFBOOT_LIB_WOLFSSL in make-args).
required: false
type: boolean
default: false

jobs:

Expand Down Expand Up @@ -123,6 +129,16 @@ jobs:
unsigned long psu_ddr_qos_init_data(void) { return 1UL; }
STUB

- name: Download FIPS-ready wolfSSL
if: ${{ inputs.fips }}
run: |
set -euxo pipefail
sudo apt-get install -y unzip
curl -fsSL -o /tmp/wolfssl-fips-ready.zip \
https://www.wolfssl.com/wolfssl-5.9.2-gplv3-fips-ready.zip
unzip -q /tmp/wolfssl-fips-ready.zip -d ..
test -f ../wolfssl-5.9.2-gplv3-fips-ready/wolfcrypt/src/fips.c

- name: Build wolfboot
run: |
make ${{inputs.make-args}}
22 changes: 22 additions & 0 deletions .github/workflows/test-configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,28 @@ jobs:
config-file: ./config/examples/raspi3-encrypted.config
make-args: wolfboot.bin CROSS_COMPILE=aarch64-linux-gnu-

cm4_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
config-file: ./config/examples/cm4.config
make-args: wolfboot.bin

cm4_sdcard_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
config-file: ./config/examples/cm4_sdcard.config
make-args: wolfboot.bin

cm4_fips_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
config-file: ./config/examples/cm4.config
make-args: wolfboot.bin FIPS=1 WOLFBOOT_LIB_WOLFSSL=../wolfssl-5.9.2-gplv3-fips-ready NO_ARM_ASM=1
fips: true

sim_tfm_smallstack_test:
uses: ./.github/workflows/test-build.yml
with:
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ ifeq ($(TARGET),raspi3)
MAIN_TARGET:=wolfboot.bin
endif

ifeq ($(TARGET),cm4)
MAIN_TARGET:=wolfboot.bin
endif

ifeq ($(TARGET),sim)
CFLAGS+=-fno-pie
LDFLAGS+=-no-pie
Expand Down
12 changes: 11 additions & 1 deletion arch.mk
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,18 @@ ifeq ($(ARCH),AARCH64)
SPI_TARGET=nxp
endif

ifeq ($(TARGET),cm4)
# Raspberry Pi Compute Module 4 - Broadcom BCM2711, Cortex-A72
ARCH_FLAGS=-mcpu=cortex-a72+crypto -march=armv8-a+crypto -mtune=cortex-a72
# -mstrict-align: wolfBoot runs with the MMU off (simple startup), so data
# accesses are Device memory where unaligned access faults. Required for the
# FIPS in-core HMAC over the code region (NO_ARM_ASM drops the asm path that
# otherwise sets this).
CFLAGS+=$(ARCH_FLAGS) -DCORTEX_A72 -mstrict-align
endif

# Default ARM ASM setting for unrecognized AARCH64 targets
ifeq ($(filter zynq versal nxp_ls1028a,$(TARGET)),)
ifeq ($(filter zynq versal nxp_ls1028a cm4,$(TARGET)),)
NO_ARM_ASM?=1
endif

Expand Down
28 changes: 28 additions & 0 deletions config/examples/cm4.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Raspberry Pi CM4 (BCM2711) - RAM-boot authenticated boot.
#
# For wolfCrypt FIPS 140-3, build with FIPS=1 pointing at a FIPS / FIPS-ready
# wolfSSL tree. The FIPS module uses portable-C crypto, so NO_ARM_ASM is
# required. Entropy comes from the BCM2711 RNG200 hardware TRNG (hal/cm4.c).
# See docs/FIPS.md for the in-core hash-seal procedure (done on-target). e.g.:
# make FIPS=1 WOLFBOOT_LIB_WOLFSSL=../wolfssl-5.9.2-gplv3-fips-ready NO_ARM_ASM=1
#FIPS?=1
#WOLFBOOT_LIB_WOLFSSL?=../wolfssl-5.9.2-gplv3-fips-ready
#NO_ARM_ASM?=1
ARCH?=AARCH64
TARGET?=cm4
SIGN?=ECC384
HASH?=SHA384
DEBUG?=1
VTOR?=1
SPMATH?=1
IMAGE_HEADER_SIZE?=1024
PKA?=0
WOLFTPM?=0
DEBUG_UART?=0
NO_XIP?=1
NO_QNX?=1
WOLFBOOT_SECTOR_SIZE=0x400
WOLFBOOT_NO_PARTITIONS=1
WOLFBOOT_RAMBOOT_MAX_SIZE=0x20000000
WOLFBOOT_LOAD_ADDRESS?=0x3080000
WOLFBOOT_LOAD_DTS_ADDRESS?=0x400000
48 changes: 48 additions & 0 deletions config/examples/cm4_sdcard.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Raspberry Pi CM4 (BCM2711) - eMMC/SD A/B disk boot.
#
# Boots from the BCM2711 EMMC2 controller (Arasan SDHCI @ 0xFE340000), which
# drives the onboard eMMC (eMMC variants) or the microSD (CM4 Lite). wolfBoot
# reads GPT A/B image partitions via update_disk.c and boots the highest valid
# version with rollback.
#
# NOTE: the EMMC2 platform glue in hal/cm4.c is bring-up scaffolding pending
# on-hardware validation (controller clock/pinmux state left by the GPU
# firmware, card-detect wiring on the carrier). Use SDHCI_FORCE_CARD_DETECT
# for the embedded eMMC path.
#
# For wolfCrypt FIPS 140-3, build with FIPS=1 pointing at a FIPS / FIPS-ready
# wolfSSL tree. The FIPS module uses portable-C crypto, so NO_ARM_ASM is
# required. Entropy comes from the BCM2711 RNG200 hardware TRNG (hal/cm4.c).
# See docs/FIPS.md for the in-core hash-seal procedure (done on-target). e.g.:
# make FIPS=1 WOLFBOOT_LIB_WOLFSSL=../wolfssl-5.9.2-gplv3-fips-ready NO_ARM_ASM=1
#FIPS?=1
#WOLFBOOT_LIB_WOLFSSL?=../wolfssl-5.9.2-gplv3-fips-ready
#NO_ARM_ASM?=1
ARCH?=AARCH64
TARGET?=cm4
SIGN?=ECC384
HASH?=SHA384
IMAGE_HEADER_SIZE?=1024
DEBUG?=0
DEBUG_UART?=1
DISK_SDCARD?=1
DISK_EMMC?=0
CFLAGS_EXTRA+=-DSDHCI_FORCE_CARD_DETECT
EXT_FLASH?=0
NO_XIP=1
NO_QNX?=1
ELF?=1
VTOR?=1
SPMATH?=1
PKA?=0
WOLFTPM?=0
WOLFBOOT_NO_PARTITIONS=1
CFLAGS_EXTRA+=-DBOOT_PART_A=1
CFLAGS_EXTRA+=-DBOOT_PART_B=2
CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000
WOLFBOOT_LOAD_ADDRESS?=0x10000000
WOLFBOOT_RAMBOOT_MAX_SIZE=0x2BC00000
WOLFBOOT_LOAD_DTS_ADDRESS?=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80200000
WOLFBOOT_PARTITION_SIZE=0x4000000
WOLFBOOT_SECTOR_SIZE=0x1000
22 changes: 22 additions & 0 deletions config/examples/sim-fips.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# wolfBoot simulator build using the wolfCrypt FIPS 140-3 module.
# Point WOLFBOOT_LIB_WOLFSSL at an unpacked FIPS (or FIPS-ready) wolfSSL tree.
# Prototype target for the CM4 FIPS integration (see docs/FIPS.md).
ARCH=sim
TARGET=sim
SIGN?=ECC384
HASH?=SHA384
FIPS?=1
WOLFBOOT_LIB_WOLFSSL?=../wolfssl-5.9.2-gplv3-fips-ready
WOLFBOOT_SMALL_STACK?=0
SPI_FLASH=0
DEBUG=1

# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x40000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x100000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x180000

# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1
82 changes: 82 additions & 0 deletions docs/FIPS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# wolfBoot with wolfCrypt FIPS 140-3

This page explains how wolfBoot performs its firmware signature verification with the wolfCrypt FIPS 140-3 module, and what a fully CMVP-validated deployment additionally requires. Read it before making any FIPS claim about a wolfBoot deployment.

## Two distinct things: approved algorithms vs. a validated module

FIPS 140-3 has two separate requirements that are easy to conflate:

1. Using FIPS **approved algorithms** for the security-relevant operations (here: image signature verification and hashing).
2. Performing those operations inside the **CMVP-validated wolfCrypt module** boundary, with the power-on self-test (POST), the in-core integrity check, and status gating (`wolfCrypt_GetStatus_fips`).

A stock wolfBoot build only addresses (1): it compiles individual `wolfcrypt/src/*.c` files selected by `SIGN`/`HASH`, with no POST or in-core integrity check. Building with `FIPS=1` (this page) addresses (2): wolfBoot links the wolfCrypt FIPS module boundary, runs the POST + in-core check at boot, and refuses to boot unless the module is operational.

A production-validated deployment still requires the **licensed, validated** wolfCrypt FIPS bundle at the exact validated revision (not the evaluation "FIPS-ready" drop), the validated module version, and adherence to the module's Security Policy. Contact wolfSSL (facts@wolfssl.com) for the current certificate, validated module version, and integration guidance for a specific target.

## Approved algorithms for image authentication

wolfBoot authenticates images with a public-key signature over a hash of the image. The default wolfBoot signature algorithm, **ED25519, is NOT FIPS approved** and must not be used for a FIPS configuration.

Approved pairs (select in the target `.config`):

- Signature (`SIGN=`): `ECC256` / `ECC384` / `ECC521` (ECDSA P-256/P-384/P-521), or `RSAPSS2048` / `RSAPSS3072` / `RSAPSS4096` (RSA-PSS).
- Hash (`HASH=`): `SHA256`, `SHA384`. Match or exceed the signature strength (e.g. P-384 with SHA-384).
- Set `SPMATH=1` (the single-precision math backend the wolfCrypt FIPS module is validated with).

Not approved for signing: `ED25519`, `ED448`. The post-quantum options (`LMS`/`XMSS`/`ML-DSA`) are governed by separate NIST standards and are out of scope here.

## Getting the FIPS source

Obtain a FIPS wolfCrypt source tree. For evaluation, the FIPS-ready bundle can be downloaded from wolfSSL:

```
https://www.wolfssl.com/wolfssl-5.9.2-gplv3-fips-ready.zip
```

Production use requires the licensed, validated FIPS bundle. Unpack it and point wolfBoot at it with `WOLFBOOT_LIB_WOLFSSL`.

## Building wolfBoot with FIPS

The `FIPS=1` build option (`options.mk`) rebuilds the wolfcrypt object list as the validated module boundary in link order (`wolfcrypt_first.o` first, `wolfcrypt_last.o` last, with `fips.o`/`fips_test.o` and the boundary crypto between them - the in-core integrity hash on GCC/ELF is enforced by this link order). Point the build at the FIPS tree and select an approved algorithm pair:

```
cp config/examples/sim-fips.config .config # or config/examples/cm4.config
make FIPS=1 WOLFBOOT_LIB_WOLFSSL=/path/to/wolfssl-5.9.2-gplv3-fips-ready \
SIGN=ECC384 HASH=SHA384 SPMATH=1
```

`-DHAVE_FIPS` is added by the `FIPS=1` block; `settings.h` in the FIPS tree defines the exact version (the FIPS-ready 5.9.2 bundle reports `HAVE_FIPS_VERSION 7`). The `HAVE_FIPS` block in `include/user_settings.h` enables the module's algorithm set, keeps the RNG/DRBG enabled, and wires the entropy seed (below).

## Entropy source (required)

The FIPS DRBG needs a seed. wolfBoot's lean configuration compiles out the OS seed paths, so a seed is provided via `CUSTOM_RAND_GENERATE_SEED` (the `HAVE_FIPS` block in `include/user_settings.h` keeps the RNG enabled by undoing wolfBoot's `WC_NO_RNG`/`WC_NO_HASHDRBG`). The example wiring points it at `wolfBoot_fips_seed()`, implemented per target: `/dev/urandom` on the simulator (`hal/sim.c`) and the BCM2711 RNG200 hardware TRNG on the CM4 (`hal/cm4.c`). Without a working seed, the ECDSA power-on self-test (which performs a sign) fails with `ECDSA_KAT_FIPS_E` because `wc_GenerateSeed()` returns `NOT_COMPILED_IN`.

## Sealing the in-core integrity hash

The module verifies an in-core integrity hash (HMAC-SHA-256 over the module's code and read-only data) at startup. A fresh build ships with a placeholder, so the first run reports a mismatch; capture the runtime hash and seal it:

1. Build and run with a FIPS callback registered (wolfBoot does this in `src/loader.c`). On a mismatch the module reports the runtime hash; wolfBoot prints it (`FIPS in-core hash = ...`, from `wolfCrypt_GetCoreHash_fips()`), and on the CM4 the test app (`test-app/app_cm4.c`) prints it over UART.
2. Copy the reported 64-hex-character hash into `verifyCore[]` in `wolfcrypt/src/fips_test.c`.
3. Rebuild and re-run. `wolfCrypt_GetStatus_fips()` now returns 0 (operational).

The seal is **specific to the exact binary layout**: any code change that shifts the FIPS module's link addresses changes the in-core hash and requires a re-seal. Re-sealing `verifyCore[]` itself does not shift addresses (same-size rewrite), so once the rest of the build is fixed the seal converges in one pass.

## Bare-metal targets

The FIPS module targets a hosted environment; a few things must be provided on bare-metal (the CM4 does all of these):

- **POST entry.** The module registers its POST via a C constructor (`.init_array`), which a hosted runtime runs before `main()`. wolfBoot's bare-metal startup does not run `.init_array`, so build with `NO_ATTRIBUTE_CONSTRUCTOR` and call `fipsEntry()` explicitly (`src/loader.c`).
- **Normal (cacheable) memory.** wolfBoot's simple startup runs with the MMU off, where all memory is Device-nGnRnE and unaligned / 128-bit SIMD accesses fault (the FIPS module and newlib `printf`/`snprintf` do both). The CM4 HAL enables a minimal identity MMU with DDR mapped Normal cacheable before the POST (`cm4_mmu_enable`), and tears it down (clean D-cache, disable MMU/caches) before the boot handoff (`cm4_mmu_disable`) so the loaded image is coherent and the application starts MMU-off.
- **libc.** The module uses malloc/printf; stub the newlib syscalls (`--specs=nosys.specs`) and provide a bounded `_sbrk` so the heap cannot grow into the unverified image (the CM4 HAL allocates from a fixed static buffer in `hal/cm4.c`).

Bring the module up on the simulator (`config/examples/sim-fips.config`) first - it exercises the whole flow (module boundary, POST, in-core seal, verify, A/B update) with no hardware.

## Verifying operation

- POST/CASTs run at module initialization; `wc_RunAllCast_fips()` runs the conditional algorithm self-tests and `wolfCrypt_GetStatus_fips()` reports the module status (0 = operational).
- wolfBoot treats a non-zero FIPS status as a hard failure and refuses to boot (`src/loader.c`).
- A deliberately corrupted module boundary (flip a byte) makes the in-core check fail and blocks the boot - the negative test for the integration.

## See also

- [Targets.md](Targets.md) - Raspberry Pi Compute Module 4 (BCM2711) target. FIPS 140-3 authenticated boot (module operational -> SHA-384 integrity -> ECDSA-P384 verify seeded by the BCM2711 hardware TRNG -> handoff) is validated on CM4 hardware.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ See also: [wolfBoot Product Overview](https://www.wolfssl.com/products/wolfboot/
- [**encrypted_partitions.md**](./encrypted_partitions.md) - Creating and managing encrypted firmware/data partitions.
- [**firmware_image.md**](./firmware_image.md) - wolfBoot firmware image format, layout, and metadata.
- [**firmware_update.md**](./firmware_update.md) - Update flow: slots, verification, rollback, and recovery.
- [**FIPS.md**](./FIPS.md) - Building wolfBoot with the wolfCrypt FIPS 140-3 module: approved algorithms, DRBG entropy, and in-core integrity sealing.
- [**flash-OTP.md**](./flash-OTP.md) - Using One-Time Programmable (OTP) regions in flash for secure data.
- [**flash_partitions.md**](./flash_partitions.md) - Flash partitioning schemes and configuration guidance.
- [**HAL.md**](./HAL.md) - Hardware Abstraction Layer notes and porting considerations.
Expand Down
74 changes: 74 additions & 0 deletions docs/Targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This README describes configuration of supported targets.

* [Simulated](#simulated)
* [Cortex-A53 / Raspberry PI 3](#cortex-a53--raspberry-pi-3-experimental)
* [Cortex-A72 / Raspberry Pi Compute Module 4](#cortex-a72--raspberry-pi-compute-module-4-bcm2711)
* [Cypress PSoC-6](#cypress-psoc-6)
* [Infineon AURIX TC3xx](#infineon-aurix-tc3xx)
* [Intel x86-64 Intel FSP](#intel-x86_64-with-intel-fsp-support)
Expand Down Expand Up @@ -3695,6 +3696,79 @@ qemu-system-aarch64 -M raspi3b -m 1024 -serial stdio -kernel wolfboot_linux_rasp
```


## Cortex-A72 / Raspberry Pi Compute Module 4 (BCM2711)

wolfBoot runs on the Raspberry Pi Compute Module 4 (CM4), a Broadcom BCM2711 with a quad-core Cortex-A72 (AArch64). wolfBoot takes the place of the second-stage OS loader: the BCM2711 boot ROM loads the VideoCore firmware, the firmware loads `kernel8.img` from the boot partition, and that `kernel8.img` is wolfBoot. wolfBoot then verifies the signed application image and boots it, extending the platform root of trust into the OS.

```
BCM2711 boot ROM -> SPI EEPROM bootloader -> VideoCore firmware (start4.elf)
-> kernel8.img (wolfBoot) -> verify (ECDSA/SHA) -> application
```

On CM4 modules with onboard eMMC the boot files live on the eMMC FAT boot partition; on CM4 Lite they live on a microSD. Either way the medium hangs off the BCM2711 EMMC2 controller (a standard SDHCI v3.0 Arasan block at `0xFE340000`).

### Building

```
cp config/examples/cm4.config .config
make CROSS_COMPILE=aarch64-none-elf-
```

The example uses `SIGN=ECC384 HASH=SHA384` (both FIPS-approved). wolfBoot is entered by the firmware at `0x80000` at EL2, matching `hal/cm4.ld`. The image is loaded from RAM: wolfBoot reads the signed application at `kernel_addr` (`0x140000`), verifies it, copies it to `WOLFBOOT_LOAD_ADDRESS`, and boots.

### Signing and assembling the boot image

Sign the application, then concatenate wolfBoot and the signed image so the signed image lands at `kernel_addr` (`0x140000` = `0x80000` load + `0xC0000`):

```
make keytools tools/bin-assemble/bin-assemble
IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --ecc384 --sha384 \
app.bin wolfboot_signing_private_key.der 1
tools/bin-assemble/bin-assemble kernel8.img \
0x0 wolfboot.bin \
0xC0000 app_v1_signed.bin
```

### config.txt

The CM4 UART on GPIO14/15 defaults to the mini-UART because the PL011 is used by Bluetooth. wolfBoot drives the PL011, so route it to the header and fix a known UART clock:

```
arm_64bit=1
kernel=kernel8.img
enable_uart=1
uart_2ndstage=1
dtoverlay=disable-bt
init_uart_clock=48000000
init_uart_baud=115200
```

### Flashing

- CM4 Lite: write `kernel8.img` + the RPi firmware (`start4.elf`, `fixup4.dat`) + `config.txt` to the microSD FAT boot partition.
- CM4 with eMMC: put the module in USB boot mode (nRPIBOOT), run `rpiboot` to expose the eMMC as USB mass storage, and write the same files to its FAT boot partition. See https://github.com/raspberrypi/usbboot .

### Boot output

With `DEBUG_UART=1`, a successful authenticated boot prints (115200 8N1):

```
wolfBoot CM4 (BCM2711 Cortex-A72) hal_init, EL2
Trying partition 0 at 0x140000
Checking integrity...done
Verifying signature...done
Firmware Valid
Booting at 0x3080000
```

### Optional: eMMC/SD A/B updates

`config/examples/cm4_sdcard.config` enables the disk updater (`DISK_SDCARD`/`DISK_EMMC`), driving the BCM2711 EMMC2 controller through the generic SDHCI driver (`src/sdhci.c`) for A/B image partitions on the boot medium. This path is provided as bring-up scaffolding and is not yet hardware-validated.

### FIPS 140-3

The CM4 target uses `SIGN=ECC384 HASH=SHA384` (FIPS-approved) and can perform its signature verification with the wolfCrypt FIPS 140-3 module (build `config/examples/cm4.config` with `FIPS=1`, pointing `WOLFBOOT_LIB_WOLFSSL` at a FIPS wolfSSL tree). At boot the module runs its power-on self-test and in-core integrity check, and wolfBoot refuses to boot unless the module is operational. Entropy for the FIPS DRBG comes from the BCM2711 RNG200 hardware TRNG. The full flow has been brought up and exercised end to end on CM4 hardware using the FIPS-ready bundle: FIPS module operational -> SHA-384 integrity -> ECDSA-P384 signature verification -> boot handoff. A production, CMVP-validated deployment additionally requires the licensed validated wolfCrypt FIPS bundle at the validated revision (see [FIPS.md](FIPS.md)). The on-target harness in `test-app/app_cm4.c` prints the runtime in-core hash over the UART for the `verifyCore[]` seal. See [FIPS.md](FIPS.md) for the full build, entropy, and hash-sealing procedure.

## Xilinx Zynq UltraScale

AMD Zynq UltraScale+ MPSoC ZCU102 Evaluation Kit - Quad-core ARM Cortex-A53 (plus dual Cortex-R5).
Expand Down
Loading
Loading