Secure boot with Raspberry Pi CM4 and Nerves

So this is something I am working on for a client I will reference as REDACTED, because they are :slight_smile:

I’ve discussed it a fair bit with Frank and in the interest of sharing knowledge I will try my best to move all that I can in to the open and summarize what got us here. Hopefully we continue our exchanges unhindered and everyone benefits. Perfect world, I get great input. I have not put it in help, it is more of a project.

CM4 is not an ideal security device due to missing the ability to truly protect a secret in hardware (no, the ATECC for NervesKey has limitations here. no ARM TrustZone is on the SoC but has no secured peripherals or storage to use). More on this another time.

But one smart step is to enable secure boot, lock down the bootloader with the OTP (one-time programmable, not our usual OTP) storage part of eeprom shove a public key in there and then sign the boot.img with a boot.sig according to how raspberry pi wants it done.

This is not how fwup works.

fwup does not generate a full .img. It creates a ZIP archive with the .fw extension, signs it. The archive contains all necessary files and a compiled deterministic set of instructions for setting up partitions, copying files and all that. A .fw can be turned into a .img in a simple way.

Nerves generates a .fw. Secure boot according to CM4 methods would mean generating a Nerves firmware as a boot.img and then wrapping it up in a signature and a few additional files to make it boot.

I’ve done this manually and made it work. The question becomes, how do we tool this well in Nerves? It doesn’t really require changing the base build. I would not sign this way in dev, just prod devices.

mix firmware.sign perhaps? It could use fwup to generate a .fw with the boot.img and boot.sig inside it along with some extras. And that means deploying, updating and binary diffs should still be on the table.

I guess the “outer” .fw should own the data partition and so on and the inner .img just the firmware system. Should keep size down.

@fhunleth this a decent summary? Any further thoughts so far?

1 Like

I’ve never tried secure boot on a CM4, so my understanding is from skimming Secure boot chain of trust and the Buildroot configuration added by this commit. Please read with a grain of salt. This could be totally wrong.

This setup looks similar at a high level to secure booting with U-Boot. One difference is that the boot.img file that contains the Linux kernel, device tree, initramfs, etc. uses FAT32 as its container format. So, instead of a ZIP or a tarball or flattened image tree (FIT) file, they chose FAT32. Cool.

The auth flow is:

  1. BootROM validates bootsys and then executes it
  2. bootsys validates bootmain and then executes it
  3. bootmain validates your boot.img and then boots the Linux kernel in it
  4. Your initramfs in boot.img needs to verify the root filesystem and then mount it.

Almost everything in Nerves is for putting together the root filesystem. That’s totally separate from the initramfs so it means that you can create it totally separately if you want. I’d use Buildroot to create it since that’s the tool I know and there’s an example Buildroot config that I linked above. It also works to create a Buildroot package that recursively calls Buildroot so you could automate this in a Nerves system build, but maybe don’t do this first step. First step for me would be to create the boot.img binary manually and download/copy it to the images directory in the Nerves system build.

In your initramfs, you’ll need to mount the root filesystem and switch_root to it. If you google around, I think you should find examples on how to do that. I’d skip the root filesystem auth at this point.

Next step is to go back to Nerves, create a nerves_system_rpi4 fork and update it to know about the boot.img file and the boot.sig file that goes with it. Modify the fwup.conf script to delete all of the normal non-root filesystem blobs that fwup writes and then add the boot.img and boot.sig. The final fwup.conf will write boot.img, boot.sig, and rootfs.squashfs. I’m skipping details, but I think that at a high level this should work and you won’t need to modify any Nerves infrastructure.

After this works, I’d implement whatever mechanism that you want to use to authenticate the root filesystem. It can be anything you want since the code to do the authentication goes in the initramfs which is totally under your control. You may be interested in dm-verity.

The extension that Nerves needs is a hook that you can run after the Nerves tooling creates the read-only SquashFS filesystem and before fwup is called to create the .fw file. The hook would turn the SquashFS filesystem into an image that can be authenticated by dm-verity or whatever you choose to use. After that, fwup would include the result in the .fw and write it to eMMC or MicroSD just like normal. Your initramfs would know that the bytes were a dm-verity’d SquashFS.

I think that it’s important to reiterate that there are multiple keys involved. There are the keys used by CM4 to authenticate the boot.img. You have to do whatever the RPi docs say you have to do for those. Then there are the keys you use to authenticate the root filesystem. You can choose any algorithm for those. You just need to put the public keys that you trust in the boot.img. Maybe you have two boot.img’s that you use - one with the dev public key and one with the prod key so the flow is the same for dev and prod. Up to you.

I hope I understand this right. Interesting project.

I have made a boot.img from a Nerves BOOT_A and signed it. Then tried booting that using rpiboot from usboot (it doesn’t flash the emmc, just a kind of testboot). And that went fine. So for secure boot itself it is mostly about wrapping up the nerves boot image. Ideally I’d want to do the signing step via fwup so I could have the data partition outside of the boot.img or it will be massive.

The eeprom bootloader stuff I consider fairly separate for now and that is exclusively rpiboot.

I haven’t started on the full disk encryption part as much. Sounds like that will be initramfs and stuff and certainly change things further. Will dig in to what you’ve referenced.