This example demonstrates how the low level code signing and provisioning tools can be used to enable signed boot on Compute Module 4 or Compute Modulde 5. For simplicity, the example is based on the mass-storage-gadget which small buildroot image.
For production systems we recommend using the higher level Raspberry Pi Secure Boot Provisioner
See also: EEPROM and OTP provisioning guides for secure boot secure-boot-recovery CM4 secure boot secure-boot-recovery CM5
**WARNING: Enabling signed boot modifies the OTP memory and is irreversible. **
- A Raspberry Pi Compute Module 5 or Compute Module 4 / 4S and the relevant IO board.
- Micro USB cable for
rpiboot
connection - USB serial cable (for debug logs)
- Linux, WSL or Cygwin (Windows 11)
- OpenSSL
- Python3
- Python
cryptodomex
python3 -m pip install pycryptodomex
# or
pip install pycryptodomex
Before starting it's advisable to create a fresh clone of the usbboot
repo
to ensure that there are no stale configuration files.
git clone https://github.com/raspberrypi/usbboot secure-boot
cd secure-boot
git submodule update --init
make
See the top-level README for full build instructions.
Prepare the Compute Module for rpiboot
mode:
- Set the
nRPIBOOT
jumper which is labelled `Fit jumper to disable eMMC Boot' on the Compute Module 4 IO board. - Connect the micro USB cable to the
USB slave
port on the Compute Module IO board. - Power cycle the Compute Module IO board.
- Connect the USB serial adapter to GPIO 14/15 on the 40-pin header.
- Set the
nRPIBOOT
jumper which is labelled `Fit jumper to disable eMMC Boot' on the Compute Module 5 IO board. - Disconnect any USB peripherals from the IO board in order to reduce power consumption.
- Connect USB-A to USB-C cable from the rpiboot host to the IO board.
- Connect the USB serial adapter to GPIO 14/15 on the 40-pin header.
- If the Compute Module has the dedicate boot UART connector fitted then this will provide additional debug.
- Power cycle the Compute Module IO board.
Secure boot requires a 2048 bit RSA private key. You can either use a pre-existing
key or generate an specific key for this example. The KEY_FILE
environment variable
used in the following instructions must contain the absolute path to the RSA private key in
PEM format.
openssl genrsa 2048 > private.pem
export KEY_FILE=$(pwd)/private.pem
In a production environment it's essential that this key file is stored privately and securely.
Enable rpiboot
mode and flash the bootloader EEPROM with updated setting enables code signing.
Running update-pieeprom.sh
generates the signed pieeprom.bin
image.
cd secure-boot-recovery
# Generate the signed EEPROM image.
../tools/update-pieeprom.sh -k "${KEY_FILE}"
cd ..
# On Compute Modeule 4 or 4S
./rpiboot -d secure-boot-recovery
# On Compute Module 5
./rpiboot -d secure-boot-recovery5
Once secure-boot has been enable the OS boot.img
file must be signed with the customer private key.
On Compute Module 5 the Raspberry Pi 5 firmware must also be counter-signed with this key.
The sign.sh
script wraps the low level commands to do this:-
./sign.sh ${KEY_FILE}
Enable rpiboot
mode and run the example OS. If the boot.sig
signature does not match boot.img
,
the bootloader will refuse to load the OS.
./rpiboot -d secure-boot-example
Login as root
with the empty password.
Example script which uses a device-specific private key to create/mount an encrypted file-system.
Generating a 256-bit random key for test purposes.
export KEY_FILE=$(mktemp -d)/key.bin
openssl rand -hex 32 | xxd -rp > ${KEY_FILE}
Using rpi-otp-private-key to extract the device private key (if programmed).
export KEY_FILE=$(mktemp -d)/key.bin
rpi-otp-private-key -b > "${KEY_FILE}"
Creating an encrypted disk on a specified block device.
export BLK_DEV=/dev/mmcblk0p3
cryptsetup luksFormat --key-file="${KEY_FILE}" --key-size=256 --type=luks2 ${BLK_DEV}
cryptsetup luksOpen ${BLK_DEV} encrypted-disk --key-file="${KEY_FILE}"
mkfs /dev/mapper/encrypted-disk
mkdir -p /mnt/application-data
mount /dev/mapper/encrypted-disk /mnt/application-data
rm "${KEY_FILE}"
Once signed-boot is enabled the bootloader will only load images signed with private key generated earlier. To boot the Compute Module in mass storage mode a signed version of this code must be generated.
This signed image MUST NOT be distributed because it gives access to the EMMC.
Sign the mass storage drivers in the secure-boot-msd
directory. Please see the top level README for a description of the different usbboot
firmware drivers.
cd secure-boot-msd
../tools/rpi-eeprom-digest -i boot.img -o boot.sig -k "${KEY_FILE}"
cd ..
A new mass storage device should now be visible on the host OS. On Linux check dmesg
for something like '/dev/sda'.
./rpiboot -d secure-boot-msd
The bootloader can load a ramdisk boot.img
from any of the bootable modes defined by the BOOT_ORDER EEPROM config setting.
For example:
- Boot the Compute Module in MSD mode as explained in the previous step.
- Copy the
boot.img
andboot.sig
files from thesecure-boot-example
stage to the mass storage drive: No other files are required. - Remove the
nRPIBOOT
jumper. - Power cycle the Compute Module IO board.
- The system should now boot into the OS.
The secure-boot example image can be rebuilt and modified using buildroot. See raspberrypi-signed-boot buildroot configuration.