wolfBoot: add Yocto/OE secure bootloader recipes#164
wolfBoot: add Yocto/OE secure bootloader recipes#164dgarske wants to merge 1 commit intowolfSSL:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces initial Yocto/OpenEmbedded support for wolfBoot inside meta-wolfssl, including recipes to build the bootloader, host-side key/sign tools, and a helper recipe/bbappend to produce and consume signed FIT images (notably for ZynqMP boot flows).
Changes:
- Add
wolfboot.incand recipes to buildwolfboot.elf, build native key/sign tooling, and sign the kernel FIT image. - Add a
xilinx-bootbinbbappend to swap the SSBL inBOOT.BINto wolfBoot when explicitly opted in viaEXTRA_IMAGEDEPENDS. - Register the new recipe globs and
PREFERRED_PROVIDER_wolfbootinconf/layer.conf.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| recipes-wolfssl/wolfboot/wolfboot_git.bb | Cross-compiles wolfboot.elf, generates keys, and deploys artifacts. |
| recipes-wolfssl/wolfboot/wolfboot.inc | Shared source/Licensing include with git fetch of wolfBoot + wolfSSL side-by-side. |
| recipes-wolfssl/wolfboot/wolfboot-signed-image.bb | Signs the kernel FIT image and deploys a versioned signed binary. |
| recipes-wolfssl/wolfboot/wolfboot-keytools-native_git.bb | Builds and installs wolfboot-keygen / wolfboot-sign as native tools. |
| recipes-wolfssl/wolfboot/README.md | Documents layer usage, workflow, and ZynqMP caveats. |
| recipes-bsp/bootbin/xilinx-bootbin_%.bbappend | Conditionally rewrites the BIF to use wolfboot.elf as SSBL on ZynqMP. |
| conf/layer.conf | Adds new BBFILES globs and sets PREFERRED_PROVIDER_wolfboot. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if [ -z "${WOLFBOOT_PUBLIC_KEY}" ] || [ ! -f "${WOLFBOOT_PUBLIC_KEY}" ]; then | ||
| openssl rsa -in ${WOLFBOOT_SIGNING_KEY} -inform DER -pubout -outform DER \ | ||
| -out ${S}/wolfboot_signing_public_key.der | ||
| PUBKEY_FOR_MAKE=${S}/wolfboot_signing_public_key.der | ||
| else | ||
| PUBKEY_FOR_MAKE=${WOLFBOOT_PUBLIC_KEY} | ||
| fi |
There was a problem hiding this comment.
do_compile() derives a public key using the openssl CLI, but the recipe doesn’t declare a dependency on openssl-native. This can fail on build hosts without an openssl binary in PATH. Add an explicit native dependency (or switch to using the already-built wolfboot-keygen tool for public-key derivation) to make the build reproducible.
| # KEYGEN_TOOL override: wolfBoot's Makefile otherwise tries to build | ||
| # tools/keytools/keygen using the target cross-compiler and then run | ||
| # the resulting AArch64 binary on the x86_64 build host. Point it at | ||
| # the native keygen from wolfboot-keytools-native instead. | ||
| NATIVE_KEYGEN="$(command -v wolfboot-keygen)" | ||
| make wolfboot.elf \ | ||
| CROSS_COMPILE=${TARGET_PREFIX} \ | ||
| CC="${TARGET_PREFIX}gcc $SYSROOT_FLAG" \ | ||
| LD="${TARGET_PREFIX}gcc $SYSROOT_FLAG" \ | ||
| USER_PRIVATE_KEY="${WOLFBOOT_SIGNING_KEY}" \ | ||
| USER_PUBLIC_KEY="$PUBKEY_FOR_MAKE" \ | ||
| KEYGEN_TOOL="$NATIVE_KEYGEN" \ | ||
| V=1 |
There was a problem hiding this comment.
KEYGEN_TOOL is set via command -v wolfboot-keygen, which depends on PATH and could accidentally pick up a host-installed binary (or resolve to empty and make will fall back to building/running the target keygen). Prefer pointing directly at the staged native tool path (and fail early if it’s missing) so the build is deterministic.
| # (DER format). If unset, wolfBoot's keygen derives the public key from the | ||
| # private key in-memory to populate src/keystore.c. Only set this if you | ||
| # want to pin a public key independent of the private key file (e.g. HSM). |
There was a problem hiding this comment.
The comment for WOLFBOOT_PUBLIC_KEY says wolfBoot’s keygen derives the public key from the private key when unset, but the recipe currently derives it using openssl rsa -pubout. Either adjust the comment to match the actual implementation or update the implementation to use wolfBoot’s keygen as described.
| # (DER format). If unset, wolfBoot's keygen derives the public key from the | |
| # private key in-memory to populate src/keystore.c. Only set this if you | |
| # want to pin a public key independent of the private key file (e.g. HSM). | |
| # (DER format). If unset, the recipe derives the public key from | |
| # WOLFBOOT_SIGNING_KEY before populating src/keystore.c. Only set this if | |
| # you want to pin a public key independent of the private key file | |
| # (e.g. HSM). |
| of this README. The recipe: | ||
|
|
||
| - Stages the private key at `${S}/wolfboot_signing_private_key.der` so the | ||
| wolfBoot Makefile can derive the public half and compile it into | ||
| `wolfboot.elf` via `src/keystore.c`. | ||
| - Does **not** deploy the private key to `DEPLOY_DIR_IMAGE`. Only |
There was a problem hiding this comment.
This README section says the recipe “stages the private key at ${S}/wolfboot_signing_private_key.der”, but the current implementation passes WOLFBOOT_SIGNING_KEY directly to the build/signing tools and does not copy it into ${S}. Update the documentation (or the recipe) so users don’t look for a non-existent staged file.
| of this README. The recipe: | |
| - Stages the private key at `${S}/wolfboot_signing_private_key.der` so the | |
| wolfBoot Makefile can derive the public half and compile it into | |
| `wolfboot.elf` via `src/keystore.c`. | |
| - Does **not** deploy the private key to `DEPLOY_DIR_IMAGE`. Only | |
| of this README. The recipes: | |
| - Pass `WOLFBOOT_SIGNING_KEY` directly to the wolfBoot build/signing tools | |
| so the public half can be derived and compiled into `wolfboot.elf` via | |
| `src/keystore.c`. | |
| - Do **not** stage or copy the private key into `${S}` as | |
| `wolfboot_signing_private_key.der`, so users should not expect that file | |
| to exist in the source tree. | |
| - Do **not** deploy the private key to `DEPLOY_DIR_IMAGE`. Only |
| # Only activates when WOLFBOOT_ENABLE = "1" is set in configuration (e.g. | ||
| # local.conf or a machine .conf). Without that flag this bbappend is a | ||
| # no-op and xilinx-bootbin keeps using U-Boot. | ||
| # | ||
| # A dedicated variable is used here instead of inspecting EXTRA_IMAGEDEPENDS: | ||
| # EXTRA_IMAGEDEPENDS is frequently set inside image recipes, which are | ||
| # parsed in a different context than xilinx-bootbin, so the anonymous | ||
| # python() below would see an empty value and silently stay inert. |
There was a problem hiding this comment.
PR description says the xilinx-bootbin bbappend “only activates when wolfboot-signed-image is in EXTRA_IMAGEDEPENDS”, but the implementation actually gates activation on WOLFBOOT_ENABLE = "1". Please update either the PR description/README or the bbappend logic so the activation condition is consistent and unambiguous for users.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # NOTE: SRCREVs below are pinned to wolfSSL/wolfBoot master and | ||
| # wolfSSL/wolfssl master tips at the time of writing. Bump these as | ||
| # upstream evolves. Downstream users can override via local.conf: | ||
| # SRCREV_wolfboot:pn-wolfboot = "<sha>" | ||
| # SRCREV_wolfboot:pn-wolfboot-keytools-native = "<sha>" | ||
| # to pick up un-merged fixes (e.g. wolfSSL/wolfBoot#750 adds the ZynqMP | ||
| # hal_dts_fixup / MMU-cleanup-before-Linux / SDHCI cold-boot retry path | ||
| # needed for PetaLinux 2025.2 on ZCU102). | ||
| SRC_URI = " \ | ||
| git://github.com/wolfssl/wolfBoot.git;protocol=https;branch=master;name=wolfboot;destsuffix=git \ | ||
| git://github.com/wolfssl/wolfssl.git;protocol=https;branch=master;name=wolfssl;destsuffix=git/lib/wolfssl \ | ||
| " | ||
| SRCREV_wolfboot ?= "58c2e044a606c1e077483aa09822bb0fa9127967" | ||
| SRCREV_wolfssl ?= "48a0347581ce83958ae965bf2f150e6b6de7e978" | ||
| SRCREV_FORMAT = "wolfboot_wolfssl" |
There was a problem hiding this comment.
This layer generally pins Git fetches directly in SRC_URI using nobranch=1;rev=<sha> (e.g. recipes-wolfssl/wolfssl/wolfssl_5.9.1.bb:13, recipes-wolfssl/wolftpm/wolftpm_3.10.0.bb:15). Here SRC_URI specifies branch=master and uses weak SRCREV_* ?= ..., which can make fetches more brittle if the branch name changes and makes it easier to accidentally build against a different revision. Consider switching these URIs to nobranch=1;rev=${SRCREV_wolfboot} / rev=${SRCREV_wolfssl} (or hardcode rev= like the other recipes) and pin SRCREV_* with =.
| # NOTE: SRCREVs below are pinned to wolfSSL/wolfBoot master and | |
| # wolfSSL/wolfssl master tips at the time of writing. Bump these as | |
| # upstream evolves. Downstream users can override via local.conf: | |
| # SRCREV_wolfboot:pn-wolfboot = "<sha>" | |
| # SRCREV_wolfboot:pn-wolfboot-keytools-native = "<sha>" | |
| # to pick up un-merged fixes (e.g. wolfSSL/wolfBoot#750 adds the ZynqMP | |
| # hal_dts_fixup / MMU-cleanup-before-Linux / SDHCI cold-boot retry path | |
| # needed for PetaLinux 2025.2 on ZCU102). | |
| SRC_URI = " \ | |
| git://github.com/wolfssl/wolfBoot.git;protocol=https;branch=master;name=wolfboot;destsuffix=git \ | |
| git://github.com/wolfssl/wolfssl.git;protocol=https;branch=master;name=wolfssl;destsuffix=git/lib/wolfssl \ | |
| " | |
| SRCREV_wolfboot ?= "58c2e044a606c1e077483aa09822bb0fa9127967" | |
| SRCREV_wolfssl ?= "48a0347581ce83958ae965bf2f150e6b6de7e978" | |
| SRCREV_FORMAT = "wolfboot_wolfssl" | |
| # NOTE: SRCREVs below are pinned to specific wolfBoot and wolfSSL commits | |
| # at the time of writing. Bump these as upstream evolves. Downstream users | |
| # can override via local.conf: | |
| # SRCREV_wolfboot:pn-wolfboot = "<sha>" | |
| # SRCREV_wolfboot:pn-wolfboot-keytools-native = "<sha>" | |
| # to pick up un-merged fixes (e.g. wolfSSL/wolfBoot#750 adds the ZynqMP | |
| # hal_dts_fixup / MMU-cleanup-before-Linux / SDHCI cold-boot retry path | |
| # needed for PetaLinux 2025.2 on ZCU102). | |
| SRC_URI = " \ | |
| git://github.com/wolfssl/wolfBoot.git;protocol=https;nobranch=1;rev=${SRCREV_wolfboot};name=wolfboot;destsuffix=git \ | |
| git://github.com/wolfssl/wolfssl.git;protocol=https;nobranch=1;rev=${SRCREV_wolfssl};name=wolfssl;destsuffix=git/lib/wolfssl \ | |
| " | |
| SRCREV_wolfboot = "58c2e044a606c1e077483aa09822bb0fa9127967" | |
| SRCREV_wolfssl = "48a0347581ce83958ae965bf2f150e6b6de7e978" |
| wolfboot-sign --rsa4096 --sha3 \ | ||
| ${WOLFBOOT_FIT_IMAGE} \ | ||
| ${WOLFBOOT_SIGNING_KEY} \ | ||
| ${WOLFBOOT_IMAGE_VERSION} |
There was a problem hiding this comment.
wolfboot-sign is invoked with ${WOLFBOOT_SIGNING_KEY} unquoted. Since this is a user-supplied absolute path, quoting it (and other args) avoids failures when the path contains spaces or special characters.
| # keytools-native provides wolfboot-keygen (used only when deriving the | ||
| # public half from a supplied private key) and wolfboot-sign (used by | ||
| # wolfboot-signed-image.bb for FIT image signing). | ||
| DEPENDS = "wolfboot-keytools-native" |
There was a problem hiding this comment.
do_compile() invokes the host openssl binary to derive a public key, but the recipe doesn't depend on openssl-native. This can make builds non-reproducible or fail on hosts without openssl installed. Add openssl-native to DEPENDS (or otherwise ensure the openssl tool is provided by the build).
| DEPENDS = "wolfboot-keytools-native" | |
| DEPENDS = "wolfboot-keytools-native openssl-native" |
|
Would it make sense for wolfBoot to use That's BitBake's standard mechanism for swapping bootloaders - vanilla Yocto and PetaLinux default to U-Boot via Instead of I'm not sure exactly what artifacts/tasks BitBake expects from a virtual/bootloader provider (deploy outputs, |
Add wolfBoot secure boot support to meta-wolfssl. Four new recipes
cross-compile wolfboot.elf, build host-side signing/keygen tools,
and sign kernel FIT images with RSA4096+SHA3-384 for verified boot.
New recipes:
wolfboot.inc - shared SRC_URI, LICENSE, SRCREVs
wolfboot_git.bb - cross-compiles wolfboot.elf from a
user-selected config/examples/ template;
embeds a user-supplied RSA4096 public key
wolfboot-keytools-native_git.bb - native wolfboot-keygen / wolfboot-sign
wolfboot-signed-image.bb - signs kernel FIT with RSA4096+SHA3-384
Supporting files:
xilinx-bootbin_%.bbappend - replaces U-Boot with wolfBoot in BOOT.BIN
on ZynqMP (gated by WOLFBOOT_ENABLE="1");
uses BBFILES_DYNAMIC for meta-xilinx-tools
conf/layer.conf - registers wolfboot BBFILES globs and
PREFERRED_PROVIDER
README.md - usage guide, key provisioning, ZynqMP notes
Design decisions:
- Signing key is user-supplied out-of-band (WOLFBOOT_SIGNING_KEY) to
avoid leaking private key material through sstate or DEPLOY_DIR_IMAGE.
- wolfboot_git.bb uses raw make (not oe_runmake) because wolfBoot is a
bare-metal bootloader with its own -nostdlib/-ffreestanding toolchain
flags that conflict with Yocto's CC/CFLAGS/LDFLAGS injection.
- SRCREVs use weak assignment (?=) so downstream users can override via
local.conf to track unreleased upstream fixes.
Tested on AMD/Xilinx ZCU102 hardware with PetaLinux 2025.2:
FSBL -> PMU FW -> ATF -> wolfBoot (EL2) -> signed FIT -> Linux
WOLFBOOT_CONFIG="zynqmp_sdcard.config"
WOLFBOOT_LINUX_BOOTARGS_ROOT="/dev/mmcblk0p4"
Summary
wolfboot.elf, native signing/keygen tools, and RSA4096+SHA3-384 FIT imagesigning
xilinx-bootbinbbappend to replace U-Boot with wolfBoot inBOOT.BINon AMD/Xilinx ZynqMP (opt-in via
WOLFBOOT_ENABLE="1")WOLFBOOT_SIGNING_KEY) keeps private keymaterial out of sstate and deploy artifacts
New files
recipes-wolfssl/wolfboot/wolfboot.increcipes-wolfssl/wolfboot/wolfboot_git.bbwolfboot.elf; seeds.configfromconfig/examples/${WOLFBOOT_CONFIG}recipes-wolfssl/wolfboot/wolfboot-keytools-native_git.bbwolfboot-keygenandwolfboot-signutilitiesrecipes-wolfssl/wolfboot/wolfboot-signed-image.bbimage_v<N>_signed.binrecipes-wolfssl/wolfboot/README.mdrecipes-bsp/bootbin/xilinx-bootbin_%.bbappendBOOT.BIN(ZynqMP only, gated)conf/layer.conf(modified)BBFILES_DYNAMICfor bootbin,PREFERRED_PROVIDERKey design points
Signing key isolation --
WOLFBOOT_SIGNING_KEYis a user-suppliedabsolute path to a pre-generated RSA4096 DER private key. Recipes never
auto-generate or deploy private key material. Public key is derived at build
time and compiled into
wolfboot.elfviasrc/keystore.c.Bare-metal cross-compilation --
wolfboot_git.bbuses rawmake(not
oe_runmake) and unsetsCFLAGS/LDFLAGSto avoid Yocto hostflags leaking into the freestanding bootloader build.
KEYGEN_TOOLisoverridden to point at the native keygen, preventing the Makefile from
trying to cross-compile and execute an AArch64 keygen binary on x86_64.
Conditional bootbin override -- The bbappend only activates when
WOLFBOOT_ENABLE="1"is set in configuration. UsesBBFILES_DYNAMICso the layer doesn't hard-depend on
meta-xilinx-tools.Overridable SRCREVs --
wolfboot.incuses weak assignment (?=) forSRCREVs so downstream users can pin to specific commits via
local.confwithout patching the layer.