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
7 changes: 7 additions & 0 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ on:
make-args:
required: false
type: string
prep-run:
required: false
type: string

jobs:

Expand Down Expand Up @@ -42,6 +45,10 @@ jobs:
run: |
make -C tools/keytools && make -C tools/bin-assemble

- name: Pre-build setup
if: inputs.prep-run != ''
run: ${{inputs.prep-run}}

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

tegra234_test:
uses: ./.github/workflows/test-build.yml
with:
arch: aarch64
# Tegra234 bare-metal skeleton: build the bootloader only (RAM boot,
# no factory.bin), mirroring raspi3.
config-file: ./config/examples/tegra234.config
make-args: wolfboot.bin CROSS_COMPILE=aarch64-linux-gnu-
Comment on lines +362 to +369

sim_tfm_smallstack_test:
uses: ./.github/workflows/test-build.yml
with:
Expand Down Expand Up @@ -738,6 +747,14 @@ jobs:
arch: host
config-file: ./config/examples/x86_64_efi.config

aarch64_efi_test:
uses: ./.github/workflows/test-build.yml
with:
arch: aarch64
config-file: ./config/examples/aarch64_efi.config
# Build gnu-efi for aarch64 (pinned in the script) before wolfboot.efi.
prep-run: ./tools/scripts/build-gnu-efi-aarch64.sh

zynqmp_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
Expand Down
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,12 @@ sdcard.img

# wolfHSM STM32H5 TZ demo build output
port/stmicro/stm32h5-tz-wolfhsm/out/

# gnu-efi built for the AArch64 UEFI target and its cloned source
tools/gnu-efi-aarch64/
tools/gnu-efi-src/
# aarch64_efi working/staging dirs (build artifacts, not tracked)
aarch64_efi-stage/
tools/qemu-esp/
# UEFI Secure Boot keys/certs generated by tools/scripts/sign-efi-secureboot.sh
tools/efi-secureboot-keys/
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ SIGN_ENV=IMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) \


MAIN_TARGET=factory.bin
# PE/COFF output format for the wolfboot.efi objcopy rule. Overridden per
# target in arch.mk (e.g. pei-aarch64-little for aarch64_efi).
EFI_OBJCOPY_TARGET?=pei-x86-64
TARGET_H_TEMPLATE:=include/target.h.in

ifeq ($(TZEN),1)
Expand Down Expand Up @@ -293,6 +296,10 @@ ifeq ($(TARGET),x86_64_efi)
MAIN_TARGET:=wolfboot.efi
endif

ifeq ($(TARGET),aarch64_efi)
MAIN_TARGET:=wolfboot.efi
endif

ifeq ($(FSP), 1)
MAIN_TARGET:=wolfboot_stage1.bin
endif
Expand All @@ -310,6 +317,12 @@ ifeq ($(TARGET),raspi3)
MAIN_TARGET:=wolfboot.bin
endif

# Tegra234 bare-metal skeleton boots from RAM (loaded by an earlier stage),
# like raspi3: build the bootloader binary, no contiguous flash factory.bin.
ifeq ($(TARGET),tegra234)
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
endif

ifeq ($(TARGET),sim)
CFLAGS+=-fno-pie
LDFLAGS+=-no-pie
Expand Down Expand Up @@ -379,7 +392,7 @@ wolfboot.efi: wolfboot.elf
$(Q)$(OBJCOPY) -j .rodata -j .text -j .sdata -j .data \
-j .dynamic -j .dynsym -j .rel \
-j .rela -j .reloc -j .eh_frame \
-O pei-x86-64 --subsystem=10 $^ $@
-O $(EFI_OBJCOPY_TARGET) --subsystem=10 $^ $@
@echo
@echo "\t[SIZE]"
$(Q)$(SIZE) wolfboot.efi
Expand Down
69 changes: 67 additions & 2 deletions arch.mk
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,20 @@ endif

## ARM Cortex-A
ifeq ($(ARCH),AARCH64)
CROSS_COMPILE?=aarch64-none-elf-
ifeq ($(TARGET),aarch64_efi)
# UEFI app: Linux GNU toolchain (freestanding EFI ABI), not aarch64-none-elf-
CROSS_COMPILE?=aarch64-linux-gnu-
else
CROSS_COMPILE?=aarch64-none-elf-
endif
CFLAGS+=-DARCH_AARCH64 -DFAST_MEMCPY
OBJS+=src/boot_aarch64.o src/boot_aarch64_start.o
ifeq ($(TARGET),aarch64_efi)
# UEFI app: gnu-efi CRT0 is the entry; do_boot is in boot_aarch64_efi.o.
# Skip the bare-metal reset (boot_aarch64_start.S) and EL2/GIC glue.
OBJS+=src/boot_aarch64_efi.o
else
OBJS+=src/boot_aarch64.o src/boot_aarch64_start.o
endif

ifeq ($(TARGET),zynq)
ARCH_FLAGS=-march=armv8-a+crypto
Expand Down Expand Up @@ -117,6 +128,15 @@ ifeq ($(ARCH),AARCH64)
SPI_TARGET=nxp
endif

ifeq ($(TARGET),tegra234)
# NVIDIA Jetson Orin (Tegra234, Cortex-A78AE) bare-metal skeleton.
# Groundwork for the Path B firmware-replacement direction; the validated
# Orin path is the aarch64_efi UEFI app. See hal/tegra234.c.
ARCH_FLAGS=-mcpu=cortex-a78+crypto -march=armv8.2-a+crypto
CFLAGS+=$(ARCH_FLAGS) -DCORTEX_A78
CFLAGS+=-DWOLFBOOT_DUALBOOT
endif

# Default ARM ASM setting for unrecognized AARCH64 targets
ifeq ($(filter zynq versal nxp_ls1028a,$(TARGET)),)
NO_ARM_ASM?=1
Expand Down Expand Up @@ -1664,6 +1684,37 @@ ifeq ($(TARGET),x86_64_efi)
UPDATE_OBJS:=src/update_ram.o
endif

ifeq ($(TARGET),aarch64_efi)
# Generic AArch64 UEFI application (validated on NVIDIA Jetson Orin Nano).
# Build gnu-efi for aarch64 first: ./tools/scripts/build-gnu-efi-aarch64.sh
# (override the install path with GNU_EFI_PATH=... if needed).
USE_GCC_HEADLESS=0
GNU_EFI_PATH?=tools/gnu-efi-aarch64
GNU_EFI_LIB_PATH?=$(GNU_EFI_PATH)/lib
GNU_EFI_INC_PATH?=$(GNU_EFI_PATH)/include
GNU_EFI_CRT0=$(GNU_EFI_LIB_PATH)/crt0-efi-aarch64.o
GNU_EFI_LSCRIPT=$(GNU_EFI_LIB_PATH)/elf_aarch64_efi.lds
CFLAGS += -fpic -ffreestanding -fno-stack-protector -fno-stack-check \
-fshort-wchar -mstrict-align
CFLAGS += -I$(GNU_EFI_INC_PATH) -I$(GNU_EFI_INC_PATH)/efi \
-I$(GNU_EFI_INC_PATH)/efi/aarch64 \
-DTARGET_aarch64_efi -DWOLFBOOT_DUALBOOT
# avoid using of fixed LOAD_ADDRESS, uefi target uses dynamic location
CFLAGS += -DWOLFBOOT_NO_LOAD_ADDRESS
# AArch64 PE/COFF output format for objcopy (see the wolfboot.efi rule).
# This binutils exposes it as pei-aarch64-little (not efi-app-aarch64).
EFI_OBJCOPY_TARGET=pei-aarch64-little
# --allow-multiple-definition: gnu-efi's libefi init.o (pulled in for
# InitializeLib) also defines memset/memcpy; wolfBoot's src/string.o comes
# first in link order and wins.
LDFLAGS = -shared -Bsymbolic --allow-multiple-definition \
-L$(GNU_EFI_LIB_PATH) -T$(GNU_EFI_LSCRIPT)
LD_START_GROUP = $(GNU_EFI_CRT0)
LD_END_GROUP = -lgnuefi -lefi
LD = $(CROSS_COMPILE)ld
UPDATE_OBJS:=src/update_ram.o
endif

ifeq ($(ARCH),sim)
USE_GCC_HEADLESS=0
LD = gcc
Expand Down Expand Up @@ -1914,6 +1965,19 @@ endif

## Update mechanism
ifeq ($(ARCH),AARCH64)
ifeq ($(TARGET),aarch64_efi)
# UEFI app: UEFI owns MMU/FDT, so skip the -DMMU/-DWOLFBOOT_FDT DTS path and
# fdt.o/gpt.o (like x86_64_efi). update_ram.o is set in the block above.
# DEBUG=1: route wolfBoot_printf to the UEFI console (gnu-efi Print).
ifeq ($(DEBUG),1)
CFLAGS += -DWOLFBOOT_DEBUG_EFI=1
endif
# Drop -Werror for this target: WOLFBOOT_DEBUG_EFI pulls gnu-efi headers into
# every TU and efidebug.h redefines the -DDEBUG object macro as a function
# macro. That cpp macro-redefinition warning has no -W name, so it can't be
# scoped with -Wno-error=<name>; our own sources are kept warning-clean.
CFLAGS := $(filter-out -Werror,$(CFLAGS))
else
CFLAGS+=-DMMU -DWOLFBOOT_FDT -DWOLFBOOT_DUALBOOT
OBJS+=src/fdt.o
# src/gpt.c provides the CRC32 helpers reused by update_ram.c's uImage
Expand All @@ -1934,6 +1998,7 @@ ifeq ($(ARCH),AARCH64)
# RAM-based boot from external flash (default)
UPDATE_OBJS:=src/update_ram.o
endif
endif
else
ifeq ($(DUALBANK_SWAP),1)
CFLAGS+=-DWOLFBOOT_DUALBOOT
Expand Down
36 changes: 36 additions & 0 deletions config/examples/aarch64_efi.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# AArch64 UEFI application - wolfBoot as a UEFI app (the AArch64 sibling of the
# x86_64_efi target). Validated on the NVIDIA Jetson Orin Nano (Tegra234).
#
# wolfBoot builds as an AArch64 UEFI application (wolfboot.efi) launched by the
# platform UEFI firmware. It reads kernel.img/update.img from the EFI Simple
# File System, verifies them, and boots via UEFI LoadImage/StartImage.
# Modeled on config/examples/x86_64_efi.config.
#
# Prerequisite: build gnu-efi for AArch64 first (one-time):
# ./tools/scripts/build-gnu-efi-aarch64.sh
# then: cp config/examples/aarch64_efi.config .config && make
#
# Crypto starts on ED25519/SHA256 (matches the proven x86 EFI target) to
# de-risk the first build. Switch to ECC384/SHA384 once the port builds and
# runs: set SIGN?=ECC384, HASH?=SHA384, SPMATH=1 (pulls in SP math objects).
#
# For a FIPS 140-3 deployment use FIPS-approved algorithms: SIGN?=ECC384,
# HASH?=SHA384, SPMATH=1 (ED25519 is NOT FIPS approved). See docs/FIPS.md for
# the approved-algorithm vs. validated-module distinction and build steps.
ARCH=AARCH64
TARGET=aarch64_efi
WOLFBOOT_SMALL_STACK=1
SIGN?=ED25519
HASH?=SHA256
DEBUG=1
SPMATH=0
# required for keytools
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_NO_PARTITIONS=1
# Measured boot: extend the verified kernel into the platform firmware TPM via
# EFI_TCG2_PROTOCOL (PCR MEASURED_PCR_A) before handoff, using the firmware's
# own TPM stack -- no wolfTPM transport. Best-effort: skips cleanly if the
# firmware exposes no TCG2/TPM. Validated on the NVIDIA Orin Nano fTPM
# (TPM present, SHA-256 + SHA-384 PCR banks).
MEASURED_BOOT_TCG2=1
MEASURED_PCR_A?=9
30 changes: 30 additions & 0 deletions config/examples/tegra234.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# NVIDIA Jetson Orin / Tegra234 - BARE-METAL skeleton target.
#
# WARNING: this is groundwork for the "Path B" firmware-replacement direction
# (wolfBoot as a raw DRAM payload with its own drivers), NOT a validated boot
# path. It builds and links the lowest-level Tegra234 drivers (UART console +
# ARMv8 generic timer) on top of the shared AArch64 bare-metal startup, so the
# driver set has a home to grow in. The memory map (hal/tegra234.ld) and the
# earlier-stage clock/pinmux assumptions are PROVISIONAL and must be validated
# on hardware and finalized with the Path B handoff recon.
#
# For a working, validated Orin boot use config/examples/aarch64_efi.config
# (wolfBoot as a UEFI application) instead.
#
# Toolchain: aarch64-none-elf- (bare-metal), not the UEFI aarch64-linux-gnu-.
ARCH=AARCH64
TARGET=tegra234
SIGN?=ECC384
HASH?=SHA384
DEBUG?=1
DEBUG_UART?=1
SPMATH?=1
# Boot media is external (SD/eMMC/NVMe via ext_flash); no internal flash.
NO_XIP?=1
# Skip GIC init in the shared bare-metal startup for the skeleton bring-up.
NO_QNX?=1
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_NO_PARTITIONS=1
# PROVISIONAL DRAM load addresses (mirror hal/tegra234.ld).
WOLFBOOT_LOAD_ADDRESS?=0x90000000
WOLFBOOT_LOAD_DTS_ADDRESS?=0x91000000
52 changes: 52 additions & 0 deletions docs/FIPS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# FIPS 140-3 and wolfBoot

This page explains what "FIPS-ready" means for wolfBoot, how to build a wolfBoot image that uses only FIPS 140-3 approved algorithms, and what a fully CMVP-validated configuration 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 compliance 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 cryptographic module** boundary, which includes the power-on self test (POST), the in-core integrity check, and the module status gating (`wolfCrypt_GetStatus_fips`).

wolfBoot addresses (1) with configuration. wolfBoot does **not**, by default, satisfy (2): the build compiles individual wolfCrypt source files (`lib/wolfssl/wolfcrypt/src/*.c`) selected by the chosen `SIGN`/`HASH` options, rather than linking the validated wolfCrypt FIPS module container. There is no POST or in-core integrity check in a stock wolfBoot build. This is why the accurate phrasing is "FIPS-ready through wolfCrypt" (approved algorithms, from a codebase with FIPS validations) rather than "FIPS validated".

## Approved algorithms for image authentication

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

Approved options already wired into `options.mk`:

- Signature (`SIGN=`): `ECC256` / `ECC384` / `ECC521` (ECDSA P-256/P-384/P-521), or `RSAPSS2048` / `RSAPSS3072` / `RSAPSS4096` (RSA-PSS).
- Hash (`HASH=`): `SHA256` or `SHA384` (SHA-2). Match or exceed the signature strength (e.g. P-384 with SHA-384).

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.)

## Building a FIPS-ready AArch64 UEFI image

Select ECDSA P-384 + SHA-384 in the `aarch64_efi` config (edit `config/examples/aarch64_efi.config`: set `SIGN=ECC384`, `HASH=SHA384`, `SPMATH=1`), then build:

```
./tools/scripts/build-gnu-efi-aarch64.sh # one-time: AArch64 gnu-efi
cp config/examples/aarch64_efi.config .config # edit: SIGN=ECC384 HASH=SHA384 SPMATH=1
make keysclean # if switching from another algorithm
make # -> wolfboot.efi (ECC384/SHA384)
```

The same algorithm selection applies to any other target: set `SIGN=ECC384 HASH=SHA384` (and `SPMATH=1` for the single-precision math backend the wolfCrypt FIPS module is typically validated with) in that target's config.

Sign a payload with the matching algorithm, for example:

```
./tools/keytools/sign --ecc384 --sha384 kernel.img wolfboot_signing_private_key.der 1
```

## What a fully validated build additionally requires (scope, not yet implemented)

To move from "approved algorithms" to an actual FIPS 140-3 validated configuration, the crypto must run inside the validated module boundary. That means, in addition to the algorithm selection above:

- Link the certified wolfCrypt FIPS module bundle (the validated `fips.c` plus the exact validated wolfCrypt sources at the validated revision) instead of cherry-picking `.c` files, so the module boundary and its integrity hash are preserved.
- Run the module POST and in-core integrity check before the first cryptographic operation, and gate verification on `wolfCrypt_GetStatus_fips() == 0`.
- Constrain the build to the validated algorithm set and validated module version.

This is a wolfCrypt-integration effort (it depends on a wolfSSL FIPS bundle, not a wolfBoot-only change) and is not part of the stock wolfBoot build today. Contact wolfSSL (facts@wolfssl.com) for the current wolfCrypt FIPS 140-3 certificate, validated module version, and integration guidance for a specific target.
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) - FIPS 140-3: approved algorithm selection vs. a validated module, and how to build a FIPS-ready image.
- [**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
Loading
Loading