Example project for using a FIPs Ready linux image on qemu and on RPI 5 with an initramfs kernel module loading, and ported projects to utilize wolfCrypt throughout the image example

pull/568/head
night1rider 2026-03-25 01:06:00 -06:00
parent bee7a18993
commit 28fcdbbc24
28 changed files with 1788 additions and 0 deletions

View File

@ -0,0 +1,38 @@
# Cloned repos (pulled by setup.sh, symlinked into layers/)
repos/
# Symlinks in layers/ pointing to repos/ (recreated by setup.sh)
layers/poky
layers/meta-raspberrypi
layers/meta-openembedded
layers/meta-wolfssl
# FIPS Ready config (contains bundle-specific details)
conf/wolfssl-fips-ready.conf
# Build artifacts
build/
downloads/
sstate-cache/
# Images copied by make move-image
*.wic
*.wic.bz2
*.wic.gz
*.wic.bmap
# FIPS Ready bundle (commercial, do not commit)
*.zip
# Generated network config (created by make ip-* / set-network.sh)
layers/meta-network-overrides/recipes-core/network-config/files/20-wired.network
# direnv (generated by setup.sh)
.envrc
# Project root is not a layer (old locations)
/conf/layer.conf
/recipes-core/
# Claude Code memory (local only)
memory/

View File

@ -0,0 +1,268 @@
# Makefile - Yocto Scarthgap RPi5 build targets
#
# Usage:
# ./setup.sh - clone layers and check host tools
# make configure - initialize build dir and write config
# make build - build the image
SHELL := /bin/bash
TOPDIR := $(shell pwd)
BUILD_DIR := $(TOPDIR)/build
POKY_DIR := $(TOPDIR)/layers/poky
FIPS_IMAGE := wolfssl-fips-ready-image
BASE_IMAGE := core-image-base
MACHINE := raspberrypi5
DEPLOY_DIR := $(BUILD_DIR)/tmp/deploy/images/$(MACHINE)
QEMU_MACHINE := qemuarm64
QEMU_IMAGE := wolfssl-fips-ready-image-qemu
QEMU_CONF := $(TOPDIR)/conf/qemu-override.conf
QEMU_DEPLOY_DIR := $(BUILD_DIR)/tmp/deploy/images/$(QEMU_MACHINE)
# Helper: source the OE environment and run a bitbake command
define bitbake-cmd
@if [ ! -d "$(POKY_DIR)" ]; then \
echo "Error: poky not found. Run ./setup.sh first."; \
exit 1; \
fi
@source $(POKY_DIR)/oe-init-build-env $(BUILD_DIR) > /dev/null 2>&1 && $(1)
endef
LAYERS_DIR := $(TOPDIR)/layers
OVERRIDES_LAYER := $(LAYERS_DIR)/meta-wolfssl-overrides
BBLAYERS_CONF := $(BUILD_DIR)/conf/bblayers.conf
LOCAL_CONF := $(BUILD_DIR)/conf/local.conf
FIPS_CONF := $(TOPDIR)/conf/wolfssl-fips-ready.conf
FIPS_MARKER := \# ==== wolfssl-fips-ready config ====
.PHONY: configure build build-minimal clean distclean clean-project image-info move-image ip-dhcp fips-on fips-off fips-status qemu run-qemu shell help
## configure: Initialize build dir, write bblayers.conf and local.conf
configure:
@$(TOPDIR)/configure.sh
## build: Build the image (FIPS image if enabled, base image otherwise)
build:
@if [ -f "$(BBLAYERS_CONF)" ] && grep -q "meta-wolfssl-overrides" "$(BBLAYERS_CONF)" 2>/dev/null; then \
echo "FIPS enabled - building $(FIPS_IMAGE)"; \
else \
echo "Building $(BASE_IMAGE)"; \
fi
$(call bitbake-cmd, \
if grep -q "meta-wolfssl-overrides" "$(BBLAYERS_CONF)" 2>/dev/null; then \
bitbake $(FIPS_IMAGE); \
else \
bitbake $(BASE_IMAGE); \
fi)
## build-minimal: Build core-image-minimal for RPi5
build-minimal:
$(call bitbake-cmd, bitbake core-image-minimal)
## clean: Clean the active image sstate (cleansstate)
clean:
$(call bitbake-cmd, \
if grep -q "meta-wolfssl-overrides" "$(BBLAYERS_CONF)" 2>/dev/null; then \
bitbake -c cleansstate $(FIPS_IMAGE); \
else \
bitbake -c cleansstate $(BASE_IMAGE); \
fi)
## distclean: Remove the entire build directory
distclean:
@echo "Removing build directory: $(BUILD_DIR)"
rm -rf $(BUILD_DIR)
## clean-project: Reset to clean state (keeps source files and FIPS bundle)
clean-project:
@echo "Removing all generated files and caches..."
rm -rf $(BUILD_DIR) $(TOPDIR)/repos $(TOPDIR)/downloads $(TOPDIR)/sstate-cache
rm -rf $(TOPDIR)/conf/wolfssl-fips-ready.conf $(TOPDIR)/.envrc
rm -f $(TOPDIR)/*.wic $(TOPDIR)/*.wic.bz2 $(TOPDIR)/*.wic.gz $(TOPDIR)/*.wic.bmap
rm -f $(TOPDIR)/layers/meta-network-overrides/recipes-core/network-config/files/20-wired.network
@echo "Done. Run './setup.sh' to start fresh."
## image-info: Show the output image location and file sizes
image-info:
@echo "Deploy directory: $(DEPLOY_DIR)"
@echo ""
@if [ -d "$(DEPLOY_DIR)" ]; then \
ls -lh $(DEPLOY_DIR)/*.wic.bz2 2>/dev/null || \
ls -lh $(DEPLOY_DIR)/*.wic.gz 2>/dev/null || \
ls -lh $(DEPLOY_DIR)/*.wic 2>/dev/null || \
echo "No .wic image found yet. Run 'make build' first."; \
else \
echo "Deploy directory does not exist. Run 'make build' first."; \
fi
## move-image: Copy the latest .wic image to the current directory
move-image:
@LATEST=$$(ls -t $(DEPLOY_DIR)/*.wic.bz2 2>/dev/null | head -1); \
if [ -z "$$LATEST" ]; then \
LATEST=$$(ls -t $(DEPLOY_DIR)/*.wic.gz 2>/dev/null | head -1); \
fi; \
if [ -z "$$LATEST" ]; then \
LATEST=$$(ls -t $(DEPLOY_DIR)/*.wic 2>/dev/null | head -1); \
fi; \
if [ -z "$$LATEST" ]; then \
echo "No .wic image found. Run 'make build' first."; \
exit 1; \
fi; \
echo "Copying $$LATEST to ."; \
cp "$$LATEST" . ; \
echo "Done: $$(basename $$LATEST)"
## generate-fips-conf: Generate wolfssl-fips-ready.conf from a bundle .zip
## Usage: make generate-fips-conf BUNDLE=/path/to/wolfssl-x.x.x-gplv3-fips-ready.zip
generate-fips-conf:
@if [ -z "$(BUNDLE)" ]; then \
echo "Usage: make generate-fips-conf BUNDLE=/path/to/wolfssl-x.x.x-gplv3-fips-ready.zip"; \
exit 1; \
fi
@$(TOPDIR)/generate-fips-conf.sh "$(BUNDLE)"
## fips-on: Enable FIPS Ready - add overrides layer and require conf
fips-on:
@if [ ! -f "$(BBLAYERS_CONF)" ]; then \
echo "Error: bblayers.conf not found. Run 'make configure' first."; \
exit 1; \
fi
@if [ ! -f "$(FIPS_CONF)" ]; then \
echo "Error: conf/wolfssl-fips-ready.conf not found."; \
echo ""; \
echo "Generate it from your bundle .zip:"; \
echo " make generate-fips-conf BUNDLE=/path/to/wolfssl-x.x.x-gplv3-fips-ready.zip"; \
echo ""; \
echo "The bundle can live anywhere on disk."; \
exit 1; \
fi
@# --- Add overrides layer to bblayers.conf ---
@if grep -q "meta-wolfssl-overrides" "$(BBLAYERS_CONF)"; then \
echo "[FIPS] Overrides layer already in bblayers.conf"; \
else \
sed -i 's|$(LAYERS_DIR)/meta-wolfssl \\|$(LAYERS_DIR)/meta-wolfssl \\\n $(OVERRIDES_LAYER) \\|' "$(BBLAYERS_CONF)"; \
echo "[FIPS] Added overrides layer to bblayers.conf"; \
fi
@# --- Add FIPS config to local.conf ---
@if grep -q "$(FIPS_MARKER)" "$(LOCAL_CONF)"; then \
echo "[FIPS] FIPS config block already in local.conf"; \
else \
echo '' >> "$(LOCAL_CONF)"; \
echo '$(FIPS_MARKER)' >> "$(LOCAL_CONF)"; \
echo 'require $(FIPS_CONF)' >> "$(LOCAL_CONF)"; \
echo '' >> "$(LOCAL_CONF)"; \
echo '# FIPS initramfs - kernel bundles wolfSSL kernel module for early boot' >> "$(LOCAL_CONF)"; \
echo 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"' >> "$(LOCAL_CONF)"; \
echo 'INITRAMFS_IMAGE_BUNDLE = "1"' >> "$(LOCAL_CONF)"; \
echo '$(FIPS_MARKER) END' >> "$(LOCAL_CONF)"; \
echo "[FIPS] Added FIPS config to local.conf"; \
fi
@echo ""
@echo "FIPS Ready ENABLED. Run 'make build' for the RPi5 image, or 'make qemu' for the QEMU image."
## fips-off: Disable FIPS Ready - remove overrides layer and FIPS config
fips-off:
@if [ ! -f "$(BBLAYERS_CONF)" ]; then \
echo "Error: bblayers.conf not found. Run 'make configure' first."; \
exit 1; \
fi
@# --- Remove overrides layer from bblayers.conf ---
@if grep -q "meta-wolfssl-overrides" "$(BBLAYERS_CONF)"; then \
sed -i '\|meta-wolfssl-overrides|d' "$(BBLAYERS_CONF)"; \
echo "[FIPS] Removed overrides layer from bblayers.conf"; \
else \
echo "[FIPS] Overrides layer already removed from bblayers.conf"; \
fi
@# --- Remove FIPS config block from local.conf ---
@if grep -q "$(FIPS_MARKER)" "$(LOCAL_CONF)"; then \
sed -i '/^$(FIPS_MARKER)/,/^$(FIPS_MARKER) END/d' "$(LOCAL_CONF)"; \
echo "[FIPS] Removed FIPS config block from local.conf"; \
else \
echo "[FIPS] FIPS config block already removed from local.conf"; \
fi
@echo ""
@echo "FIPS Ready DISABLED. Run 'make clean && make build' to rebuild."
## fips-status: Show whether FIPS Ready overrides are enabled
fips-status:
@if [ ! -f "$(BBLAYERS_CONF)" ]; then \
echo "FIPS: unknown (bblayers.conf not found)"; \
elif grep -q "meta-wolfssl-overrides" "$(BBLAYERS_CONF)"; then \
echo "FIPS: ENABLED"; \
if [ -f "$(FIPS_CONF)" ]; then \
echo "Config: conf/wolfssl-fips-ready.conf found"; \
else \
echo "Config: conf/wolfssl-fips-ready.conf MISSING"; \
fi; \
else \
echo "FIPS: DISABLED"; \
fi
## ip-dhcp: Set network to DHCP
ip-dhcp:
@$(TOPDIR)/set-network.sh dhcp
## ip-<address>: Set static IP (e.g. make ip-192.168.1.100)
## Optional: GW=192.168.1.1 PREFIX=24 DNS=8.8.8.8
ip-%:
@$(TOPDIR)/set-network.sh static $* $(GW) $(PREFIX) $(DNS)
## qemu: Build the FIPS Ready image for QEMU (aarch64)
qemu:
@if [ ! -f "$(BBLAYERS_CONF)" ]; then \
echo "Error: bblayers.conf not found. Run 'make configure' first."; \
exit 1; \
fi
@if ! grep -q "meta-wolfssl-overrides" "$(BBLAYERS_CONF)" 2>/dev/null; then \
echo "Error: FIPS not enabled. Run 'make fips-on' first."; \
exit 1; \
fi
@echo "Building $(QEMU_IMAGE) for $(QEMU_MACHINE)"
$(call bitbake-cmd, bitbake -R $(QEMU_CONF) $(QEMU_IMAGE))
## run-qemu: Launch the QEMU image (use QEMU_ARGS for extra options, e.g. QEMU_ARGS=nographic)
run-qemu:
@QBCONF=$$(ls -t $(QEMU_DEPLOY_DIR)/*.qemuboot.conf 2>/dev/null | head -1); \
if [ -z "$$QBCONF" ]; then \
echo "Error: No .qemuboot.conf found. Run 'make qemu' first."; \
exit 1; \
fi; \
echo "Using: $$QBCONF"
$(call bitbake-cmd, \
QBCONF=$$(ls -t $(QEMU_DEPLOY_DIR)/*.qemuboot.conf 2>/dev/null | head -1) && \
runqemu $$QBCONF nographic $(QEMU_ARGS))
## shell: Open an interactive shell with the bitbake environment sourced
shell:
@if [ ! -d "$(POKY_DIR)" ]; then \
echo "Error: poky not found. Run ./setup.sh first."; \
exit 1; \
fi
@echo "Entering bitbake environment shell. Type 'exit' to leave."
@bash --init-file <(echo "source $(POKY_DIR)/oe-init-build-env $(BUILD_DIR)")
## help: Show available targets
help:
@echo "Yocto Scarthgap RPi5 Build Targets"
@echo "==================================="
@echo ""
@echo " make configure - Initialize build dir and write config"
@echo " make build - Build image for $(MACHINE) (FIPS or base, auto-detected)"
@echo " make build-minimal - Build core-image-minimal for $(MACHINE)"
@echo " make clean - Clean active image sstate"
@echo " make distclean - Remove entire build directory"
@echo " make clean-project - Reset to clean state (keeps source + bundle)"
@echo " make image-info - Show output image location and sizes"
@echo " make move-image - Copy latest .wic image to current directory"
@echo " make generate-fips-conf BUNDLE=<path> - Generate FIPS config from .zip bundle"
@echo " make fips-on - Enable FIPS Ready overrides"
@echo " make fips-off - Disable FIPS overrides layer"
@echo " make fips-status - Show FIPS override status"
@echo " make qemu - Build FIPS Ready image for QEMU ($(QEMU_MACHINE))"
@echo " make run-qemu - Launch QEMU image (nographic/headless by default)"
@echo " make ip-dhcp - Set network to DHCP"
@echo " make ip-<address> - Set static IP (e.g. make ip-192.168.1.100)"
@echo " Optional: GW=x.x.x.x PREFIX=24 DNS=x.x.x.x"
@echo " make shell - Open a bitbake-ready shell"
@echo " make help - Show this help"
@echo ""
@echo "Run ./setup.sh first to clone layers and check host tools."

View File

@ -0,0 +1,635 @@
# meta-wolfssl-linux-fips
Yocto Scarthgap build environment for Raspberry Pi 5 and QEMU (aarch64) with
wolfSSL FIPS Ready cryptography.
## Overview
This project provides a turnkey setup for building a Linux image targeting the
Raspberry Pi 5 or QEMU (aarch64) using the Yocto Project's **Scarthgap** (5.0)
release. The RPi5 base image includes SSH, HDMI console output, Wi-Fi,
Bluetooth, and systemd. The QEMU target allows testing the full FIPS Ready
stack without physical hardware.
When FIPS is enabled, the image includes:
- **wolfSSL FIPS Ready** cryptographic library
- **libgcrypt** with wolfSSL backend
- **GnuTLS** with wolfSSL backend
- **wolfProvider** (OpenSSL 3.x provider, replace-default mode)
- **wolfSSL FIPS kernel module** loaded via initramfs at early boot
- Kernel FIPS mode (`CONFIG_CRYPTO_FIPS=y`) and LKCAPI registration
- wolfcrypttest, wolfcryptbenchmark, ptest suites for validation
## Prerequisites
### Host packages (Ubuntu/Debian)
```bash
sudo apt install gawk wget git diffstat unzip texinfo gcc build-essential \
chrpath socat cpio python3 python3-pip python3-pexpect xz-utils \
debianutils iputils-ping python3-git python3-jinja2 python3-subunit \
zstd liblz4-tool file locales libacl1
sudo locale-gen en_US.UTF-8
```
You can also run `./setup.sh` which will check for all required tools and
report any that are missing. On non-Debian distros where the tool names differ,
use `--ignore-missing-packages` to skip the check:
```bash
./setup.sh --ignore-missing-packages
```
### direnv (recommended)
direnv auto-sources the bitbake environment when you `cd` into the project
directory. `setup.sh` generates the `.envrc` file automatically.
**Step 1 - Install direnv and add the shell hook (one-time, before running
`setup.sh`):**
```bash
sudo apt install -y direnv
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
```
Open a new terminal (or `exec bash`) so the hook is active. `source ~/.bashrc`
is not sufficient in all shells.
**Step 2 - Run `./setup.sh`** (see Quick Start below). This generates the
`.envrc` file. direnv will report it as blocked on the first run — that's
expected.
**Step 3 - Allow direnv to load the generated `.envrc`:**
```bash
direnv allow
```
direnv will warn that `build/` isn't initialized yet — that's expected too.
It clears once `make configure` runs.
**Step 4 - Run `make configure`.** direnv auto-sources the bitbake
environment on the next prompt.
### System requirements
- **Disk space:** At least 65 GB free (downloads + sstate cache + build output)
- **RAM:** 8 GB minimum, 16 GB+ recommended
- **OS:** Linux (tested on Ubuntu 22.04+, Debian 13, WSL2)
## Quick Start
### 1. Common setup (required for all targets)
```bash
# Clone required Yocto layers and check host tools
./setup.sh
# Initialize build directory and write configuration
make configure
```
### 2a. RPi5 base image (no FIPS)
```bash
# (Optional) Set a static IP - default is DHCP
make ip-192.168.2.227 GW=192.168.2.1 PREFIX=24 DNS=8.8.8.8
# Build the base image
make build
# Copy the image to the current directory for flashing
make move-image
```
### 2b. RPi5 FIPS Ready image
```bash
# Generate FIPS config from your bundle (bundle can live anywhere on disk)
make generate-fips-conf BUNDLE=/path/to/wolfssl-x.x.x-gplv3-fips-ready.zip
# Enable FIPS (adds overrides layer, initramfs, and FIPS conf to local.conf)
make fips-on
# Build the FIPS image (auto-detected when FIPS is enabled)
make build
# Copy and flash
make move-image
```
To disable FIPS and go back to the base image:
```bash
make fips-off
make build
```
### 2c. QEMU FIPS Ready image (no RPi hardware needed)
This builds and runs the same FIPS Ready stack in QEMU, using `linux-yocto`
(6.6) instead of `linux-raspberrypi`. The wolfSSL FIPS kernel module loads
via initramfs at early boot, same as on RPi5.
```bash
# Generate FIPS config and enable FIPS (if not already done)
make generate-fips-conf BUNDLE=/path/to/wolfssl-x.x.x-gplv3-fips-ready.zip
make fips-on
# Build the QEMU FIPS image
make qemu
# Launch in QEMU (nographic/headless, serial on stdio)
make run-qemu
```
Exit QEMU with `Ctrl-A X`.
> **Note:** Both `make build` (RPi5) and `make qemu` (QEMU) can be used in
> the same build directory. FIPS must be enabled (`make fips-on`) for both.
> The `conf/qemu-override.conf` is applied via `bitbake -R` to swap the
> machine and kernel without modifying `local.conf`.
## Build Targets
| Command | Description |
|----------------------|----------------------------------------------|
| `make configure` | Initialize build dir and write config |
| `make build` | Build image (FIPS or base, auto-detected) |
| `make build-minimal` | Build `core-image-minimal` for RPi5 |
| `make clean` | Clean the active image (cleansstate) |
| `make distclean` | Remove the entire build directory |
| `make image-info` | Show output image location and size |
| `make move-image` | Copy latest `.wic` image to current directory|
| `make generate-fips-conf BUNDLE=<path>` | Generate FIPS config from .zip bundle |
| `make fips-on` | Enable FIPS Ready overrides and initramfs |
| `make fips-off` | Disable FIPS Ready overrides |
| `make fips-status` | Show FIPS Ready status |
| `make qemu` | Build FIPS Ready image for QEMU (qemuarm64) |
| `make run-qemu` | Launch QEMU image (nographic by default) |
| `make ip-dhcp` | Set network to DHCP |
| `make ip-<address>` | Set static IP (e.g. `make ip-192.168.1.100`) |
| `make shell` | Open a shell with the bitbake env sourced |
## FIPS Ready Architecture
When FIPS is enabled (`make fips-on`), the overrides layer
(`layers/meta-wolfssl-overrides/`) is added to the build. This layer:
- Provides the `wolfssl-fips-ready-image` recipe for RPi5 and
`wolfssl-fips-ready-image-qemu` for QEMU (both extend `core-image-base`)
- Configures wolfSSL, libgcrypt, GnuTLS, wolfProvider, OpenSSL, curl, and
OpenSSH via bbappends
- Enables kernel FIPS mode and the wolfSSL kernel randomness patch
- Bundles the wolfSSL FIPS kernel module into an initramfs for early boot
- Signs the kernel module with the kernel's build key
### Boot sequence (FIPS enabled)
**RPi5:**
```
1. RPi5 firmware loads kernel (with bundled initramfs)
2. Initramfs mounts, modprobe libwolfssl loads FIPS kernel module
3. Root filesystem mounts
4. Userspace applications use wolfSSL FIPS via:
- wolfProvider (OpenSSL 3.x replace-default)
- GnuTLS with wolfSSL backend
- libgcrypt with wolfSSL backend
```
**QEMU (qemuarm64):**
```
1. QEMU loads linux-yocto kernel (with bundled initramfs)
2. Initramfs mounts, modprobe libwolfssl loads FIPS kernel module
3. Root filesystem mounts (ext4 via virtio-blk)
4. Same userspace FIPS stack as RPi5
```
### FIPS bundle
The FIPS Ready bundle `.zip` can live anywhere on disk. Running
`make generate-fips-conf BUNDLE=/path/to/bundle.zip` computes checksums and
generates `conf/wolfssl-fips-ready.conf` pointing to the bundle's location.
The bundle is never copied into the source tree.
## Network Configuration
The image uses systemd-networkd for network management. Set the IP configuration
**before** building the image - it gets baked in.
### DHCP (default)
```bash
make ip-dhcp
make configure && make build
```
### Static IP
```bash
make ip-192.168.2.227 GW=192.168.2.1 PREFIX=24 DNS=8.8.8.8
make configure && make build
```
| Parameter | Default | Description |
|-----------|--------------------------|--------------------------|
| `GW` | Auto (IP with `.1`) | Gateway address |
| `PREFIX` | `24` | Subnet prefix length |
| `DNS` | `8.8.8.8` | DNS server |
## Flashing and Booting
### RPi5: Flash to SD card
```bash
make move-image
lsblk # find your SD card device
# Using bmaptool (recommended)
sudo bmaptool copy wolfssl-fips-ready-image-raspberrypi5.rootfs.wic.bz2 /dev/sdX
# Using dd
bzcat wolfssl-fips-ready-image-raspberrypi5.rootfs.wic.bz2 | sudo dd of=/dev/sdX bs=4M status=progress
```
### RPi5: Boot and connect
**Login:** `root` with no password (`debug-tweaks` is enabled).
**SSH:**
```bash
ssh root@192.168.2.227
```
### QEMU: Launch and connect
```bash
make run-qemu
```
Boots directly to a login prompt on stdio. Login as `root` (no password).
Exit with `Ctrl-A X`.
## Testing
These tests apply to both RPi5 and QEMU. Run them after booting the image.
### 1. Kernel Module Verification
Verify that the wolfSSL FIPS kernel module loaded via initramfs:
```bash
lsmod | grep libwolfssl
dmesg | grep -i wolfssl
```
Expected dmesg output includes:
```
FIPS 140-3 wolfCrypt-fips ... startup self-test succeeded.
wolfCrypt self-test passed.
wolfCrypt: changing fips_enabled from 0 to 1 for FIPS module.
```
Followed by LKCAPI algorithm registrations (AES-CBC, AES-GCM, HMAC-SHA*, SHA*, RSA, ECDSA, ECDH, DRBG).
Verify kernel crypto API registration:
```bash
cat /proc/crypto | grep -A 5 wolfcrypt
```
### 2. Kernel Randomness
If the kernel randomness patch is applied, verify the wolfSSL DRBG is integrated:
```bash
dmesg | grep "kernel global random_bytes handlers installed"
```
Test the DRBG under load:
```bash
# Basic test (2 GB)
dd if=/dev/urandom bs=1M count=2000 status=progress of=/dev/null
```
### 3. Cryptographic Benchmarking
Test kernel crypto via cryptsetup:
```bash
cryptsetup benchmark --cipher aes-cbc --key-size 256
cryptsetup benchmark
```
### 4. wolfCrypt Tests
```bash
wolfcrypttest
wolfcryptbenchmark
```
### 5. Testing libgcrypt
libgcrypt is configured to use wolfSSL as its crypto backend.
```bash
ptest-runner libgcrypt
```
Expected output: all tests PASS (basic, mpitests, curves, fips186-dsa, etc.).
Verify library linking:
```bash
ldd /usr/lib/libgcrypt.so.20 # should show libwolfssl
```
### 6. Testing GnuTLS
GnuTLS uses wolfSSL via the wolfssl-gnutls-wrapper.
```bash
cd /opt/wolfssl-gnutls-wrapper/tests/
make run_fips
```
All tests should pass with wrapper log messages showing crypto operations routed to wolfSSL.
Verify wrapper linking:
```bash
ldd /opt/wolfssl-gnutls-wrapper/lib/libgnutls-wolfssl-wrapper.so
# should show both libgnutls.so and libwolfssl.so
```
### 7. Testing wolfProvider
wolfProvider is an OpenSSL 3.x provider using wolfSSL as the crypto backend, configured in replace-default mode.
```bash
wolfprovidertest
```
Expected output:
```
Setting up environment...
Detected replace-default mode (from config file)
Detected wolfSSL FIPS build (from config file)
...
###### TESTSUITE SUCCESS
==========================================
Unit tests PASSED!
==========================================
```
### 8. Testing libssh (via libgcrypt)
```bash
ptest-runner libssh
```
Some tests may fail due to MD5 not being available in FIPS mode. Expected failures:
- `torture_keyfiles` - legacy key formats using MD5
- `torture_pki_rsa` - legacy RSA key formats using MD5
- `torture_threads_pki_rsa` - multi-threaded legacy RSA using MD5
## Project Structure
```
meta-wolfssl-linux-fips/
├── README.md
├── .gitignore
├── .envrc # (generated by setup.sh) direnv config
├── setup.sh # Clone repos, create symlinks, check host tools
├── configure.sh # Initialize build dir and write config
├── generate-fips-conf.sh # Generate FIPS config from bundle .zip
├── set-network.sh # Write network config (called by make ip-*)
├── Makefile # Build/clean/utility targets
├── conf/
│ ├── wolfssl-fips-ready.conf # (generated) FIPS bundle config
│ └── qemu-override.conf # QEMU machine overrides for bitbake -R
├── layers/
│ ├── poky -> ../repos/poky # (symlink)
│ ├── meta-raspberrypi -> ../repos/meta-raspberrypi # (symlink)
│ ├── meta-openembedded -> ../repos/meta-openembedded # (symlink)
│ ├── meta-wolfssl -> ../repos/meta-wolfssl # (symlink)
│ └── meta-wolfssl-overrides/ # FIPS overrides layer (tracked)
│ ├── conf/layer.conf
│ ├── recipes-core/images/
│ │ ├── wolfssl-fips-ready-image.bb # RPi5 FIPS image
│ │ ├── wolfssl-fips-ready-image-qemu.bb # QEMU FIPS image
│ │ └── core-image-minimal-initramfs.bbappend
│ ├── recipes-kernel/linux/
│ │ ├── linux-raspberrypi_%.bbappend # RPi kernel patches
│ │ ├── linux-yocto_%.bbappend # QEMU kernel patches
│ │ └── files/fips-crypto.cfg
│ ├── recipes-wolfssl/
│ │ ├── wolfssl/wolfssl-fips-ready.bbappend
│ │ ├── wolfssl/wolfssl-linuxkm-fips-ready.bbappend
│ │ └── wolfprovider/wolfprovider_%.bbappend
│ ├── recipes-support/
│ │ ├── curl/curl_%.bbappend
│ │ ├── gnupg/gnupg_%.bbappend
│ │ ├── gnutls/gnutls_%.bbappend
│ │ ├── libgcrypt/libgcrypt_%.bbappend
│ │ └── nettle/nettle_%.bbappend
│ ├── recipes-connectivity/
│ │ ├── openssh/openssh_%.bbappend
│ │ └── openssl/openssl_%.bbappend
│ └── recipes-core/network-config/ # Network config recipe
│ ├── network-config_1.0.bb
│ └── files/20-wired.network # (generated by make ip-*)
├── repos/ # Cloned git repos (git-ignored)
├── build/ # Build directory (git-ignored)
├── downloads/ # Shared download cache (git-ignored)
└── sstate-cache/ # Shared state cache (git-ignored)
```
## Image Configuration
### RPi5
| Setting | Value |
|-------------|--------------------------------------|
| Machine | `raspberrypi5` |
| Kernel | `linux-raspberrypi` (6.6) |
| Base image | `core-image-base` |
| FIPS image | `wolfssl-fips-ready-image` |
| SSH | OpenSSH server enabled |
| Display | vc4graphics / HDMI 1080p |
| Wi-Fi | Enabled (linux-firmware-rpidistro) |
| Bluetooth | Enabled (bluez5) |
| Init system | systemd |
| U-Boot | Disabled (direct kernel boot) |
| Login | `root` / no password (debug-tweaks) |
| Branch | Scarthgap (Yocto 5.0) |
### QEMU (aarch64)
| Setting | Value |
|-------------|--------------------------------------|
| Machine | `qemuarm64` |
| Kernel | `linux-yocto` (6.6) |
| FIPS image | `wolfssl-fips-ready-image-qemu` |
| CPU | `-cpu max` (supports A76 binaries) |
| Console | nographic (serial on stdio) |
| Networking | TAP via virtio-net-pci |
| Init system | systemd |
| Login | `root` / no password (debug-tweaks) |
| Branch | Scarthgap (Yocto 5.0) |
## What Each Step Does (Manual Equivalent)
If you want to integrate wolfSSL FIPS Ready into your own Yocto project, here
is what each make target does under the hood and the equivalent manual steps.
### `./setup.sh`
Clones the required Yocto layers into `repos/` and creates symlinks in
`layers/` so `bblayers.conf` has a single directory to reference:
```bash
git clone -b scarthgap git://git.yoctoproject.org/poky repos/poky
git clone -b scarthgap git://git.yoctoproject.org/meta-raspberrypi repos/meta-raspberrypi
git clone -b scarthgap git://git.openembedded.org/meta-openembedded repos/meta-openembedded
git clone -b master https://github.com/wolfSSL/meta-wolfssl.git repos/meta-wolfssl
ln -s ../repos/poky layers/poky
ln -s ../repos/meta-raspberrypi layers/meta-raspberrypi
ln -s ../repos/meta-openembedded layers/meta-openembedded
ln -s ../repos/meta-wolfssl layers/meta-wolfssl
```
Also checks that required host tools (gcc, python3, etc.) are installed and
generates a `.envrc` for direnv.
### `make configure`
Runs `configure.sh`, which:
1. Sources `oe-init-build-env` to create the `build/` directory
2. Writes `build/conf/bblayers.conf` with all layer paths (poky, meta-oe,
meta-raspberrypi, meta-wolfssl, meta-network-overrides)
3. Writes an RPi5-specific config block into `build/conf/local.conf`:
- `MACHINE = "raspberrypi5"`
- SSH, HDMI, Wi-Fi, Bluetooth, systemd
- Shared download/sstate cache directories
Manual equivalent: run `source layers/poky/oe-init-build-env build` and edit
`build/conf/bblayers.conf` and `build/conf/local.conf` by hand.
### `make generate-fips-conf BUNDLE=<path>`
Runs `generate-fips-conf.sh`, which inspects a wolfSSL FIPS Ready `.zip`
bundle and generates `conf/wolfssl-fips-ready.conf` containing:
- `PREFERRED_PROVIDER_virtual/wolfssl = "wolfssl-fips-ready"` (and linuxkm)
- `WOLFSSL_VERSION`, `WOLFSSL_SRC_SHA` (SHA256 of the zip)
- `WOLFSSL_LICENSE_MD5` (MD5 of the COPYING file inside the zip)
- `WOLFSSL_SRC_DIR` (absolute path to the directory containing the zip)
- `FIPS_HASH` placeholder (auto-extracted during build via QEMU)
Manual equivalent: compute the SHA256 and license MD5 yourself and write the
conf file with the correct variable assignments.
### `make fips-on`
Enables the FIPS overrides by modifying two files:
1. **`build/conf/bblayers.conf`** - adds `layers/meta-wolfssl-overrides` to
the `BBLAYERS` list (after `meta-wolfssl`)
2. **`build/conf/local.conf`** - appends a config block:
```
require conf/wolfssl-fips-ready.conf
INITRAMFS_IMAGE = "core-image-minimal-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"
```
The overrides layer (`meta-wolfssl-overrides`) provides:
- Image recipes (`wolfssl-fips-ready-image`, `wolfssl-fips-ready-image-qemu`)
- Kernel bbappends that apply the wolfSSL randomness patches and FIPS crypto
config (`CONFIG_CRYPTO_FIPS=y`, module signing)
- An initramfs bbappend that adds `wolfssl-linuxkm` to the initramfs and
injects `modprobe libwolfssl` into the init script
- bbappends for libgcrypt, GnuTLS, wolfProvider, OpenSSL, curl, and OpenSSH
to use wolfSSL as the crypto backend
### `make build` (RPi5)
Sources the bitbake environment and runs:
```bash
source layers/poky/oe-init-build-env build
bitbake wolfssl-fips-ready-image # if FIPS enabled
bitbake core-image-base # if FIPS disabled
```
This builds the full image for `MACHINE = "raspberrypi5"` using
`linux-raspberrypi` (6.6). The kernel is bundled with the initramfs
containing the wolfSSL FIPS kernel module. Output is a `.wic.bz2` image
in `build/tmp/deploy/images/raspberrypi5/`.
### `make qemu`
Sources the bitbake environment and runs:
```bash
source layers/poky/oe-init-build-env build
bitbake -R conf/qemu-override.conf wolfssl-fips-ready-image-qemu
```
The `-R conf/qemu-override.conf` flag layers additional config on top of
`local.conf` without modifying it. The override conf:
- Sets `MACHINE = "qemuarm64"`
- Switches kernel to `linux-yocto` (since `linux-raspberrypi` doesn't
support QEMU)
- Sets `INITRAMFS_IMAGE` and `INITRAMFS_IMAGE_BUNDLE` for the QEMU kernel
- Clears RPi device trees (`KERNEL_DEVICETREE = ""`)
- Adds `IMAGE_CLASSES += "qemuboot"` and `IMAGE_FSTYPES += "ext4"` (normally
provided by `qemuarm64.conf`, but `-R` is parsed too late for machine
config files to take effect)
- Provides all `QB_*` variables (`QB_MACHINE`, `QB_CPU`, `QB_SERIAL_OPT`,
etc.) that `runqemu` needs to launch the VM
- Sets `console=ttyAMA0` (QEMU's virtual PL011 UART, replacing RPi's
`ttyAMA10`)
- Removes RPi-specific packages (`linux-firmware-rpidistro-bcm43455`)
Output is an `.ext4` rootfs and `.qemuboot.conf` in
`build/tmp/deploy/images/qemuarm64/`.
### `make run-qemu`
Sources the bitbake environment and runs:
```bash
source layers/poky/oe-init-build-env build
runqemu /path/to/wolfssl-fips-ready-image-qemu-qemuarm64.qemuboot.conf nographic
```
The `.qemuboot.conf` file contains all the QEMU launch parameters (machine
type, CPU, memory, drives, network, serial). `runqemu` reads it and
constructs the full `qemu-system-aarch64` command line. The `nographic` flag
redirects the VM console to stdio.
### `make fips-off`
Reverses `make fips-on`:
1. Removes `meta-wolfssl-overrides` from `build/conf/bblayers.conf`
2. Removes the FIPS config block (including `INITRAMFS_IMAGE` settings) from
`build/conf/local.conf`
After this, `make build` produces a plain `core-image-base` without wolfSSL.
### `make ip-<address>` / `make ip-dhcp`
Runs `set-network.sh` to write a systemd-networkd config file at
`layers/meta-network-overrides/recipes-core/network-config/files/20-wired.network`.
This file is baked into the image at build time - it cannot be changed after
flashing without rebuilding.
## License
This layer configuration is provided under the MIT license. wolfSSL itself is
dual-licensed under GPLv2 and a commercial license. See
[wolfSSL licensing](https://www.wolfssl.com/license/) for details.

View File

@ -0,0 +1,45 @@
# QEMU override configuration
#
# Applied via 'bitbake -R' to override RPi5 settings for QEMU builds.
# This file is layered on top of local.conf - last assignment wins.
MACHINE = "qemuarm64"
# Use the standard QEMU kernel instead of linux-raspberrypi
PREFERRED_PROVIDER_virtual/kernel = "linux-yocto"
# Bundle initramfs into the kernel so wolfSSL FIPS module loads at early boot
# (same mechanism as RPi - these must be global so linux-yocto picks them up)
INITRAMFS_IMAGE = "core-image-minimal-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"
# Clear RPi device trees - linux-yocto doesn't have broadcom/ DTBs
KERNEL_DEVICETREE = ""
# Generate .qemuboot.conf so runqemu can launch the image
# (qemuarm64.conf / qemu.inc are not parsed because -R is too late for
# machine config resolution - we must replicate the essential settings here)
IMAGE_CLASSES += "qemuboot"
IMAGE_FSTYPES += "ext4"
# QEMU machine settings (from qemuarm64.conf - not parsed via -R)
QB_SYSTEM_NAME = "qemu-system-aarch64"
QB_MACHINE = "-machine virt"
QB_CPU = "-cpu max"
QB_SMP = "-smp 4"
QB_CPU_KVM = "-cpu host -machine gic-version=3"
QB_GRAPHICS = "-device virtio-gpu-pci"
QB_OPT_APPEND = "-device qemu-xhci -device usb-tablet -device usb-kbd"
QB_TAP_OPT = "-netdev tap,id=net0,ifname=@TAP@,script=no,downscript=no"
QB_NETWORK_DEVICE = "-device virtio-net-pci,netdev=net0,mac=@MAC@"
QB_ROOTFS_OPT = "-drive id=disk0,file=@ROOTFS@,if=none,format=raw -device virtio-blk-pci,drive=disk0"
QB_SERIAL_OPT = "-device virtio-serial-pci -chardev null,id=virtcon -device virtconsole,chardev=virtcon"
QB_TCPSERIAL_OPT = "-device virtio-serial-pci -chardev socket,id=virtcon,port=@PORT@,host=127.0.0.1,nodelay=on -device virtconsole,chardev=virtcon"
# Serial console - override RPi's ttyAMA10/tty1 with QEMU's ttyAMA0
SERIAL_CONSOLES = "115200;ttyAMA0 115200;hvc0"
CMDLINE_DEBUG = ""
QB_KERNEL_CMDLINE_APPEND = "console=ttyAMA0"
# Remove RPi-specific packages that don't exist for QEMU
IMAGE_INSTALL:remove = "linux-firmware-rpidistro-bcm43455"

View File

@ -0,0 +1,135 @@
#!/bin/bash
#
# configure.sh - Initialize Yocto build directory and write configuration
#
# Called by 'make configure'. Safe to re-run — managed config block is replaced.
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_DIR="${SCRIPT_DIR}/build"
LAYERS_DIR="${SCRIPT_DIR}/layers"
POKY_DIR="${LAYERS_DIR}/poky"
if [ ! -d "${POKY_DIR}" ]; then
echo "Error: poky not found. Run ./setup.sh first."
exit 1
fi
# --------------------------------------------------------------------------
# Initialize build directory if needed
# --------------------------------------------------------------------------
if [ ! -d "${BUILD_DIR}/conf" ]; then
echo "[INIT] Initializing build directory..."
source "${POKY_DIR}/oe-init-build-env" "${BUILD_DIR}" > /dev/null 2>&1
fi
# --------------------------------------------------------------------------
# Write bblayers.conf
# --------------------------------------------------------------------------
echo "[CONFIG] Writing bblayers.conf..."
cat > "${BUILD_DIR}/conf/bblayers.conf" <<BBLAYERS
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"
BBPATH = "\${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \\
${LAYERS_DIR}/poky/meta \\
${LAYERS_DIR}/poky/meta-poky \\
${LAYERS_DIR}/meta-openembedded/meta-oe \\
${LAYERS_DIR}/meta-openembedded/meta-python \\
${LAYERS_DIR}/meta-openembedded/meta-networking \\
${LAYERS_DIR}/meta-openembedded/meta-multimedia \\
${LAYERS_DIR}/meta-raspberrypi \\
${LAYERS_DIR}/meta-wolfssl \\
${LAYERS_DIR}/meta-network-overrides \\
"
BBLAYERS
# --------------------------------------------------------------------------
# Write RPi5 config block in local.conf
# --------------------------------------------------------------------------
echo "[CONFIG] Writing RPi5 configuration to local.conf..."
CONFIG_MARKER="# ==== meta-wolfssl-linux-fips managed config ===="
# Remove any existing managed config block
sed -i "/${CONFIG_MARKER}/,/${CONFIG_MARKER} END/d" "${BUILD_DIR}/conf/local.conf"
# Append fresh config block
cat >> "${BUILD_DIR}/conf/local.conf" <<'LOCALCONF'
# ==== meta-wolfssl-linux-fips managed config ====
# This block is managed by 'make configure'. To change, edit configure.sh
# and re-run 'make configure'.
MACHINE = "raspberrypi5"
# ---- Image features ----
IMAGE_FEATURES += "ssh-server-openssh"
# ---- Display / GPU ----
MACHINE_FEATURES:append = " vc4graphics"
VC4DTBO = "vc4-kms-v3d"
# ---- Early HDMI console ----
# Force HDMI output and route kernel console to framebuffer
RPI_EXTRA_CONFIG = "hdmi_force_hotplug=1\nhdmi_group=1\nhdmi_mode=16\ndisable_overscan=1"
CMDLINE_DEBUG = "console=tty1"
SERIAL_CONSOLES:append = " 115200;tty1"
# ---- Wi-Fi and Bluetooth ----
DISTRO_FEATURES:append = " wifi bluetooth"
IMAGE_INSTALL:append = " linux-firmware-rpidistro-bcm43455 bluez5 wpa-supplicant network-config"
LICENSE_FLAGS_ACCEPTED:append = " synaptics-killswitch"
# ---- systemd ----
DISTRO_FEATURES:append = " systemd usrmerge"
VIRTUAL-RUNTIME_init_manager = "systemd"
VIRTUAL-RUNTIME_initscripts = "systemd-compat-units"
# ---- Serial console (debug) ----
ENABLE_UART = "1"
# ---- U-Boot ----
# Disabled — U-Boot can cause HDMI issues on RPi5, boot kernel directly
RPI_USE_U_BOOT = "0"
# ---- Shared caches (keep outside build dir for reuse) ----
DL_DIR ?= "${TOPDIR}/../downloads"
SSTATE_DIR ?= "${TOPDIR}/../sstate-cache"
# ---- Host SDK architecture ----
SDKMACHINE ?= "x86_64"
# ---- Disable SPDX license metadata generation ----
INHERIT:remove = "create-spdx"
# ==== meta-wolfssl-linux-fips managed config ==== END
LOCALCONF
# --------------------------------------------------------------------------
# Ensure default network config exists (DHCP)
# --------------------------------------------------------------------------
NETCONF="${SCRIPT_DIR}/layers/meta-network-overrides/recipes-core/network-config/files/20-wired.network"
if [ ! -f "${NETCONF}" ]; then
echo "[CONFIG] Writing default network config (DHCP)..."
mkdir -p "$(dirname "${NETCONF}")"
cat > "${NETCONF}" <<'NETEOF'
[Match]
Name=end0 eth0
[Network]
DHCP=yes
NETEOF
fi
echo "[CONFIG] Done. Run 'make build' to build the image."

View File

@ -0,0 +1,145 @@
#!/bin/bash
#
# generate-fips-conf.sh - Generate wolfssl-fips-ready.conf from a FIPS Ready .zip bundle
#
# Usage: ./generate-fips-conf.sh /path/to/wolfssl-x.x.x-gplv3-fips-ready.zip
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONF_FILE="${SCRIPT_DIR}/conf/wolfssl-fips-ready.conf"
ZIP_PATH="$1"
if [ -z "${ZIP_PATH}" ]; then
echo "Usage: $0 /path/to/wolfssl-x.x.x-gplv3-fips-ready.zip"
exit 1
fi
if [ ! -f "${ZIP_PATH}" ]; then
echo "Error: File not found: ${ZIP_PATH}"
exit 1
fi
ZIP_NAME="$(basename "${ZIP_PATH}")"
# --------------------------------------------------------------------------
# Extract version from filename
# Expected format: wolfssl-X.X.X-gplv3-fips-ready.zip
# --------------------------------------------------------------------------
VERSION="$(echo "${ZIP_NAME}" | sed -n 's/wolfssl-\([0-9]*\.[0-9]*\.[0-9]*\).*/\1/p')"
if [ -z "${VERSION}" ]; then
echo "Error: Could not extract version from filename: ${ZIP_NAME}"
echo "Expected format: wolfssl-X.X.X-gplv3-fips-ready.zip"
exit 1
fi
echo "=== Generating FIPS Ready Configuration ==="
echo ""
echo "Bundle: ${ZIP_NAME}"
echo "Version: ${VERSION}"
# --------------------------------------------------------------------------
# Compute SHA256 of the bundle
# --------------------------------------------------------------------------
echo ""
echo "[HASH] Computing SHA256..."
BUNDLE_SHA="$(sha256sum "${ZIP_PATH}" | awk '{print $1}')"
echo " SHA256: ${BUNDLE_SHA}"
# --------------------------------------------------------------------------
# Extract COPYING file and compute MD5
# --------------------------------------------------------------------------
echo "[HASH] Extracting license MD5..."
TMPDIR="$(mktemp -d)"
trap "rm -rf ${TMPDIR}" EXIT
# Try to find COPYING in the zip — it may be at the root or in a subdirectory
COPYING_PATH="$(unzip -l "${ZIP_PATH}" | grep -m1 'COPYING$' | awk '{print $NF}')"
if [ -z "${COPYING_PATH}" ]; then
echo "Warning: COPYING file not found in zip. You'll need to set WOLFSSL_LICENSE_MD5 manually."
LICENSE_MD5=""
else
unzip -q -o "${ZIP_PATH}" "${COPYING_PATH}" -d "${TMPDIR}"
LICENSE_MD5="$(md5sum "${TMPDIR}/${COPYING_PATH}" | awk '{print $1}')"
echo " License MD5: ${LICENSE_MD5}"
fi
# --------------------------------------------------------------------------
# Derive bundle name
# --------------------------------------------------------------------------
SRC_NAME="${ZIP_NAME%.zip}"
# --------------------------------------------------------------------------
# Resolve bundle directory (absolute path)
# --------------------------------------------------------------------------
BUNDLE_DIR="$(cd "$(dirname "${ZIP_PATH}")" && pwd)"
# --------------------------------------------------------------------------
# Generate conf file
# --------------------------------------------------------------------------
echo "[CONFIG] Writing conf/wolfssl-fips-ready.conf..."
mkdir -p "$(dirname "${CONF_FILE}")"
cat > "${CONF_FILE}" <<EOF
# wolfSSL FIPS Ready Configuration
#
# Auto-generated by generate-fips-conf.sh from:
# ${ZIP_NAME}
#
# To regenerate: make generate-fips-conf BUNDLE=/path/to/bundle.zip
# Use wolfSSL FIPS Ready as the wolfSSL provider
PREFERRED_PROVIDER_virtual/wolfssl = "wolfssl-fips-ready"
PREFERRED_PROVIDER_wolfssl = "wolfssl-fips-ready"
# FIPS hash mode: "auto" (QEMU-based extraction) or "manual" (use static FIPS_HASH)
WOLFSSL_FIPS_HASH_MODE ?= "auto"
WOLFSSL_FIPS_HASH_MODE_LINUXKM ?= "auto"
# wolfSSL FIPS kernel module provider
PREFERRED_PROVIDER_virtual/wolfssl-linuxkm ?= "wolfssl-linuxkm-fips-ready"
PREFERRED_PROVIDER_wolfssl-linuxkm ?= "wolfssl-linuxkm-fips-ready"
# Bundle version
WOLFSSL_VERSION = "${VERSION}"
# SHA256 checksum of the bundle .zip
WOLFSSL_SRC_SHA = "${BUNDLE_SHA}"
# MD5 of the COPYING license file in the bundle
WOLFSSL_LICENSE_MD5 = "${LICENSE_MD5}"
# Bundle name (directory name inside the zip, without extension)
WOLFSSL_SRC = "${SRC_NAME}"
# Bundle archive filename
WOLFSSL_BUNDLE_FILE = "${ZIP_NAME}"
# Directory containing the .zip bundle (absolute path to where bundle lives)
WOLFSSL_SRC_DIR = "${BUNDLE_DIR}"
# FIPS hash (set after first build if using manual mode)
# Leave as-is for auto mode — it will be extracted automatically
FIPS_HASH = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
EOF
echo ""
echo "=== Done ==="
echo ""
echo "Generated: conf/wolfssl-fips-ready.conf"
echo "Bundle: ${BUNDLE_DIR}/${ZIP_NAME}"
echo ""
echo "Next steps:"
echo " make fips-on"
echo " make clean"
echo " make build"

View File

@ -0,0 +1,12 @@
# Layer configuration for meta-network-overrides
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "meta-network-overrides"
BBFILE_PATTERN_meta-network-overrides = "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-network-overrides = "6"
LAYERDEPENDS_meta-network-overrides = "core"
LAYERSERIES_COMPAT_meta-network-overrides = "scarthgap"

View File

@ -0,0 +1,16 @@
SUMMARY = "systemd-networkd configuration for wired ethernet"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://20-wired.network"
S = "${WORKDIR}"
do_install() {
install -d ${D}${sysconfdir}/systemd/network
install -m 0644 ${WORKDIR}/20-wired.network ${D}${sysconfdir}/systemd/network/20-wired.network
}
FILES:${PN} = "${sysconfdir}/systemd/network/20-wired.network"
RDEPENDS:${PN} = "systemd"

View File

@ -0,0 +1,18 @@
# Layer configuration for meta-wolfssl-overrides
#
# This layer provides bbappends and overrides for meta-wolfssl recipes,
# customizing wolfSSL for the RPi5 FIPS build.
# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"
# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "meta-wolfssl-overrides"
BBFILE_PATTERN_meta-wolfssl-overrides = "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-wolfssl-overrides = "7"
LAYERDEPENDS_meta-wolfssl-overrides = "core wolfssl"
LAYERSERIES_COMPAT_meta-wolfssl-overrides = "scarthgap"

View File

@ -0,0 +1,3 @@
# OpenSSH ptest modifications for wolfProvider FIPS testing
require ${WOLFSSL_LAYERDIR}/inc/wolfprovider/openssh/openssh-enable-wolfprovider.inc

View File

@ -0,0 +1,3 @@
# Configure OpenSSL to use wolfProvider in replace-default mode
require ${WOLFSSL_LAYERDIR}/inc/wolfprovider/openssl/openssl-enable-wolfprovider-replace-default.inc

View File

@ -0,0 +1,8 @@
# Add wolfSSL FIPS kernel module to initramfs for early boot loading
PACKAGE_INSTALL:append = " wolfssl-linuxkm"
inherit wolfssl-initramfs
ROOTFS_POSTPROCESS_COMMAND += "wolfssl_initramfs_run_depmod; "
ROOTFS_POSTPROCESS_COMMAND += "wolfssl_initramfs_inject_after_loadmodules; "

View File

@ -0,0 +1,44 @@
SUMMARY = "QEMU image with wolfSSL FIPS Ready cryptography"
DESCRIPTION = "QEMU (aarch64) image based on core-image-base with wolfSSL FIPS Ready \
crypto backend powering libgcrypt, gnutls, and wolfProvider (replace-default mode). \
Use this to test the wolfSSL FIPS Ready integration without physical hardware."
LICENSE = "MIT"
inherit wolfssl-compatibility
python __anonymous() {
virtual_provider = d.getVar('PREFERRED_PROVIDER_virtual/wolfssl') or ''
wolfssl_provider = d.getVar('PREFERRED_PROVIDER_wolfssl') or ''
valid_fips_providers = ('wolfssl-fips', 'wolfssl-fips-ready')
if virtual_provider not in valid_fips_providers:
bb.fatal("wolfssl-fips-ready-image-qemu requires PREFERRED_PROVIDER_virtual/wolfssl "
"to be one of %s. Current: '%s'. "
"Run 'make generate-fips-conf' and 'make fips-on' first."
% (valid_fips_providers, virtual_provider))
if wolfssl_provider not in valid_fips_providers:
bb.fatal("wolfssl-fips-ready-image-qemu requires PREFERRED_PROVIDER_wolfssl "
"to be one of %s. Current: '%s'. "
"Run 'make generate-fips-conf' and 'make fips-on' first."
% (valid_fips_providers, wolfssl_provider))
}
require recipes-core/images/core-image-base.bb
# NOTE: INITRAMFS_IMAGE and INITRAMFS_IMAGE_BUNDLE are set in conf/qemu-override.conf
# (they must be global so linux-yocto picks them up, not scoped to this image recipe)
# wolfSSL FIPS Ready core
IMAGE_INSTALL:append = " wolfssl wolfcrypttest wolfcryptbenchmark"
# FIPS Ready subsystems
IMAGE_INSTALL:append = " libgcrypt libgcrypt-ptest"
IMAGE_INSTALL:append = " gnutls gnutls-dev gnutls-bin gnutls-fips"
IMAGE_INSTALL:append = " wolfssl-gnutls-wrapper wolfssl-gnutls-wrapper-dev"
IMAGE_INSTALL:append = " wolfprovider openssl openssl-bin wolfprovidercmd wolfproviderenv"
# Test utilities
IMAGE_INSTALL:append = " ptest-runner bash make glibc-utils binutils ldd curl cryptsetup"

View File

@ -0,0 +1,44 @@
SUMMARY = "RPi5 image with wolfSSL FIPS Ready cryptography"
DESCRIPTION = "Raspberry Pi 5 image based on core-image-base with wolfSSL FIPS Ready \
crypto backend powering libgcrypt, gnutls, and wolfProvider (replace-default mode)."
LICENSE = "MIT"
inherit wolfssl-compatibility
python __anonymous() {
virtual_provider = d.getVar('PREFERRED_PROVIDER_virtual/wolfssl') or ''
wolfssl_provider = d.getVar('PREFERRED_PROVIDER_wolfssl') or ''
valid_fips_providers = ('wolfssl-fips', 'wolfssl-fips-ready')
if virtual_provider not in valid_fips_providers:
bb.fatal("wolfssl-fips-ready-image requires PREFERRED_PROVIDER_virtual/wolfssl "
"to be one of %s. Current: '%s'. "
"Run 'make generate-fips-conf' and 'make fips-on' first."
% (valid_fips_providers, virtual_provider))
if wolfssl_provider not in valid_fips_providers:
bb.fatal("wolfssl-fips-ready-image requires PREFERRED_PROVIDER_wolfssl "
"to be one of %s. Current: '%s'. "
"Run 'make generate-fips-conf' and 'make fips-on' first."
% (valid_fips_providers, wolfssl_provider))
}
require recipes-core/images/core-image-base.bb
# Use initramfs-bundled kernel so wolfSSL FIPS module loads before rootfs
IMAGE_BOOT_FILES:remove = "Image;kernel_2712.img"
IMAGE_BOOT_FILES:append = " Image-initramfs-${MACHINE}.bin;kernel_2712.img"
# wolfSSL FIPS Ready core
IMAGE_INSTALL:append = " wolfssl wolfcrypttest wolfcryptbenchmark"
# FIPS Ready subsystems
IMAGE_INSTALL:append = " libgcrypt libgcrypt-ptest"
IMAGE_INSTALL:append = " gnutls gnutls-dev gnutls-bin gnutls-fips"
IMAGE_INSTALL:append = " wolfssl-gnutls-wrapper wolfssl-gnutls-wrapper-dev"
IMAGE_INSTALL:append = " wolfprovider openssl openssl-bin wolfprovidercmd wolfproviderenv"
# Test utilities
IMAGE_INSTALL:append = " ptest-runner bash make glibc-utils binutils ldd curl cryptsetup"

View File

@ -0,0 +1,20 @@
CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_USER=m
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORMAT=y
CONFIG_MODULE_SIG_ALL=y
CONFIG_MODULE_SIG_SHA256=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_SKCIPHER=y
CONFIG_CRYPTO_SKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_AKCIPHER=y
CONFIG_CRYPTO_AKCIPHER2=y

View File

@ -0,0 +1,11 @@
# Apply wolfSSL kernel randomness patches for FIPS DRBG integration
# Adds callback hooks to drivers/char/random.c and include/linux/random.h
# allowing wolfSSL kernel module (libwolfssl.ko) to register its FIPS-certified
# DRBG implementation with the kernel.
inherit wolfssl-kernel-random
WOLFSSL_KERNEL_RANDOM_PATCH = "6.12"
# Enable kernel FIPS mode and crypto subsystem
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://fips-crypto.cfg"

View File

@ -0,0 +1,11 @@
# Apply wolfSSL kernel randomness patches for FIPS DRBG integration
# Adds callback hooks to drivers/char/random.c and include/linux/random.h
# allowing wolfSSL kernel module (libwolfssl.ko) to register its FIPS-certified
# DRBG implementation with the kernel.
inherit wolfssl-kernel-random
WOLFSSL_KERNEL_RANDOM_PATCH = "6.12"
# Enable kernel FIPS mode and crypto subsystem
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://fips-crypto.cfg"

View File

@ -0,0 +1,3 @@
# Configure curl with wolfProvider support
require ${WOLFSSL_LAYERDIR}/inc/curl/curl-enable-wolfprovider-fips.inc

View File

@ -0,0 +1,3 @@
# Configure gnupg for libgcrypt with wolfSSL backend
require ${WOLFSSL_LAYERDIR}/inc/gnupg/gnupg-enable-libgcrypt-wolfssl.inc

View File

@ -0,0 +1,3 @@
# Configure gnutls to use wolfSSL backend
require ${WOLFSSL_LAYERDIR}/inc/gnutls/gnutls-enable-wolfssl.inc

View File

@ -0,0 +1,3 @@
# Configure libgcrypt to use wolfSSL backend
require ${WOLFSSL_LAYERDIR}/inc/libgcrypt/libgcrypt-enable-wolfssl.inc

View File

@ -0,0 +1,3 @@
# nettle 3.10 required for gnutls 3.8.11
require ${WOLFSSL_LAYERDIR}/inc/nettle/nettle.inc

View File

@ -0,0 +1,39 @@
From: meta-wolfssl-overrides <noreply@wolfssl.com>
Subject: [PATCH] Fix KRB5KDF missing wc_AesInit causing segfault
The Aes struct in wp_kdf_krb5kdf_derive is never initialized with
wc_AesInit. In FIPS mode wc_AesCbcEncrypt dereferences uninitialized
internal pointers causing a segfault. Additionally wc_AesFree is called
unconditionally at the end, so early-exit error paths (wrong key size
etc.) also segfault on the uninitialized struct.
Fix by zeroing the struct at declaration and calling wc_AesInit
immediately, before any validation that could skip to wc_AesFree.
Signed-off-by: meta-wolfssl-overrides <noreply@wolfssl.com>
---
--- a/src/wp_krb5kdf.c
+++ b/src/wp_krb5kdf.c
@@ -446,7 +446,7 @@
size_t osize = 0;
size_t cipherLen = 0;
int rc;
- Aes aes;
+ Aes aes = {0};
byte block[AES_BLOCK_SIZE];
byte cipherBlock[AES_BLOCK_SIZE];
byte *plain = NULL;
@@ -457,6 +457,13 @@
if (!wolfssl_prov_is_running()) {
ok = 0;
}
+ if (ok) {
+ rc = wc_AesInit(&aes, NULL, INVALID_DEVID);
+ if (rc != 0) {
+ WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesInit", rc);
+ ok = 0;
+ }
+ }
if (ok && (!wp_kdf_krb5kdf_set_ctx_params(ctx, params))) {
ok = 0;
}

View File

@ -0,0 +1,10 @@
# Fix n_fold unsigned underflow segfault in KRB5KDF with small constants
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://0001-fix-krb5kdf-n_fold-unsigned-underflow.patch"
# Disable the feature check for manual image configuration
require ${WOLFSSL_LAYERDIR}/inc/wolfssl-manual-config.inc
# Enable unit tests for wolfprovider replace default mode
require ${WOLFSSL_LAYERDIR}/inc/wolfprovider/wolfprovider-enable-replace-default-unittest.inc
require ${WOLFSSL_LAYERDIR}/inc/wolfprovider/wolfprovider-enable-unittest.inc

View File

@ -0,0 +1,17 @@
# Configure wolfSSL FIPS Ready with libgcrypt, gnutls, and wolfProvider support
#
# These .inc files from meta-wolfssl enable the necessary wolfSSL configure
# options for each subsystem to use wolfSSL FIPS Ready as the crypto backend.
require ${WOLFSSL_LAYERDIR}/inc/wolfssl-fips-ready/wolfssl-enable-libgcrypt.inc
require ${WOLFSSL_LAYERDIR}/inc/wolfssl-fips-ready/wolfssl-enable-gnutls.inc
require ${WOLFSSL_LAYERDIR}/inc/wolfprovider/wolfssl-enable-wolfprovider-fips-ready.inc
# Fix for bundle missing stamp-h.in required by automake
do_configure_create_stamph() {
if [ ! -f ${S}/stamp-h.in ]; then
touch ${S}/stamp-h.in
fi
}
addtask do_configure_create_stamph after do_patch before do_configure

View File

@ -0,0 +1,8 @@
# RPi5 (Cortex-A76 aarch64) — enable ARM assembly and LKCAPI registration
EXTRA_OECONF:append:raspberrypi5 = " --enable-linuxkm-lkcapi-register=all-kconfig"
# QEMU (aarch64) — enable LKCAPI registration for virtual machine testing
EXTRA_OECONF:append:qemuarm64 = " --enable-linuxkm-lkcapi-register=all-kconfig"
# Sign the module with the kernel's own key to prevent "module verification failed" taint
require ${WOLFSSL_LAYERDIR}/inc/wolfssl-linuxkm/wolfssl-linuxkm-sign-module.inc

View File

@ -0,0 +1,63 @@
#!/bin/bash
#
# set-network.sh - Write systemd-networkd config for the RPi5 image
#
# Usage:
# ./set-network.sh dhcp
# ./set-network.sh static 192.168.1.100 [GATEWAY] [PREFIX] [DNS]
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NETCONF="${SCRIPT_DIR}/layers/meta-network-overrides/recipes-core/network-config/files/20-wired.network"
MODE="$1"
ADDR="$2"
GW="${3:-}"
PREFIX="${4:-24}"
DNS="${5:-8.8.8.8}"
if [ "${MODE}" = "dhcp" ]; then
echo "[CONFIG] Setting network to DHCP..."
cat > "${NETCONF}" <<'EOF'
[Match]
Name=end0 eth0
[Network]
DHCP=yes
EOF
elif [ "${MODE}" = "static" ] && [ -n "${ADDR}" ]; then
# Auto-detect gateway if not provided: use .1 of the same subnet
if [ -z "${GW}" ]; then
GW="$(echo "${ADDR}" | sed 's/\.[0-9]*$/.1/')"
fi
echo "[CONFIG] Setting static IP: ${ADDR}/${PREFIX} gw ${GW} dns ${DNS}"
cat > "${NETCONF}" <<EOF
[Match]
Name=end0 eth0
[Network]
Address=${ADDR}/${PREFIX}
Gateway=${GW}
DNS=${DNS}
EOF
else
echo "Usage:"
echo " $0 dhcp"
echo " $0 static <IP> [GATEWAY] [PREFIX] [DNS]"
echo ""
echo "Examples:"
echo " $0 dhcp"
echo " $0 static 192.168.1.100"
echo " $0 static 192.168.1.100 192.168.1.1 24 8.8.8.8"
exit 1
fi
echo ""
cat "${NETCONF}"
echo ""
echo "Rebuild the image with 'make build' to apply."

View File

@ -0,0 +1,180 @@
#!/bin/bash
#
# setup.sh - Clone Yocto layers and verify host tools for RPi5 Scarthgap build
#
# Usage: ./setup.sh [--ignore-missing-packages]
#
# This script is idempotent — safe to run multiple times.
#
# Repos are cloned into repos/ (git-ignored). Symlinks are created in layers/
# so that layers/ is the single directory referenced by bblayers.conf.
#
set -e
IGNORE_MISSING=false
for arg in "$@"; do
case "$arg" in
--ignore-missing-packages) IGNORE_MISSING=true ;;
esac
done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BRANCH="scarthgap"
REPOS_DIR="${SCRIPT_DIR}/repos"
LAYERS_DIR="${SCRIPT_DIR}/layers"
echo "=== Yocto Scarthgap RPi5 Setup ==="
echo "Working directory: ${SCRIPT_DIR}"
echo ""
cd "${SCRIPT_DIR}"
# --------------------------------------------------------------------------
# Check required host tools
# --------------------------------------------------------------------------
echo "--- Checking host tools ---"
MISSING=()
REQUIRED_TOOLS=(
git
gcc
g++
make
python3
wget
diffstat
unzip
makeinfo
chrpath
socat
cpio
xz
zstd
lz4
file
gawk
locale
)
for tool in "${REQUIRED_TOOLS[@]}"; do
if command -v "${tool}" &> /dev/null; then
echo " [OK] ${tool}"
else
echo " [MISS] ${tool}"
MISSING+=("${tool}")
fi
done
if [ ${#MISSING[@]} -gt 0 ]; then
echo ""
echo "WARNING: Missing required tools: ${MISSING[*]}"
echo ""
echo "On Debian/Ubuntu, install them with:"
echo " sudo apt install gawk wget git diffstat unzip texinfo gcc build-essential \\"
echo " chrpath socat cpio python3 python3-pip python3-pexpect xz-utils \\"
echo " debianutils iputils-ping python3-git python3-jinja2 python3-subunit \\"
echo " zstd liblz4-tool file locales libacl1"
echo ""
if [ "${IGNORE_MISSING}" = true ]; then
echo "Continuing anyway (--ignore-missing-packages)."
else
echo "Re-run with --ignore-missing-packages to skip this check."
exit 1
fi
fi
echo ""
# --------------------------------------------------------------------------
# Clone repos
# --------------------------------------------------------------------------
mkdir -p "${REPOS_DIR}"
echo "--- Cloning repos (branch: ${BRANCH}) ---"
clone_repo() {
local url="$1"
local dir="$2"
local branch="$3"
if [ -d "${REPOS_DIR}/${dir}" ]; then
echo " [SKIP] ${dir} already exists"
else
echo " [CLONE] ${dir}"
git clone -b "${branch}" "${url}" "${REPOS_DIR}/${dir}"
fi
}
clone_repo "git://git.yoctoproject.org/poky" "poky" "${BRANCH}"
clone_repo "git://git.yoctoproject.org/meta-raspberrypi" "meta-raspberrypi" "${BRANCH}"
clone_repo "git://git.openembedded.org/meta-openembedded" "meta-openembedded" "${BRANCH}"
clone_repo "https://github.com/wolfSSL/meta-wolfssl.git" "meta-wolfssl" "master"
echo ""
# --------------------------------------------------------------------------
# Create symlinks in layers/
# --------------------------------------------------------------------------
echo "--- Linking repos into layers/ ---"
link_layer() {
local name="$1"
if [ -L "${LAYERS_DIR}/${name}" ]; then
echo " [SKIP] layers/${name} symlink exists"
elif [ -d "${LAYERS_DIR}/${name}" ]; then
echo " [SKIP] layers/${name} is a directory (not a symlink)"
else
echo " [LINK] layers/${name} -> repos/${name}"
ln -s "../repos/${name}" "${LAYERS_DIR}/${name}"
fi
}
link_layer "poky"
link_layer "meta-raspberrypi"
link_layer "meta-openembedded"
link_layer "meta-wolfssl"
# --------------------------------------------------------------------------
# Generate .envrc for direnv
# --------------------------------------------------------------------------
echo "--- Generating .envrc ---"
if [ -f "${SCRIPT_DIR}/.envrc" ]; then
echo " [SKIP] .envrc already exists"
else
cat > "${SCRIPT_DIR}/.envrc" <<'ENVRC'
# Auto-source the Yocto/bitbake build environment when entering this directory.
# Managed by direnv — run 'direnv allow' after any changes to this file.
POKY_DIR="${PWD}/layers/poky"
BUILD_DIR="${PWD}/build"
if [ ! -d "${POKY_DIR}" ]; then
echo "direnv: layers/poky not found — run ./setup.sh first"
elif [ ! -d "${BUILD_DIR}/conf" ]; then
echo "direnv: build/ not initialized — run 'make configure' next"
else
# Suppress the oe-init-build-env banner output
source "${POKY_DIR}/oe-init-build-env" "${BUILD_DIR}" > /dev/null 2>&1
# Stay in the original directory (oe-init-build-env changes cwd)
cd "${ENVRC_DIR:-${PWD}}"
fi
ENVRC
echo " [OK] .envrc generated"
fi
echo ""
echo "=== Setup Complete ==="
echo ""
echo "Next steps:"
echo " make configure - Initialize build dir and write local.conf"
echo " make build - Build core-image-base"
echo ""