lawik
So this is something I am working on for a client I will reference as REDACTED, because they are ![]()
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?
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #blog-post
- #ai
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
fhunleth
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.imgfile 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:
boot.imgand then boots the Linux kernel in itboot.imgneeds 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.imgbinary manually and download/copy it to theimagesdirectory 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_rpi4fork and update it to know about theboot.imgfile and theboot.sigfile that goes with it. Modify thefwup.confscript to delete all of the normal non-root filesystem blobs thatfwupwrites and then add theboot.imgandboot.sig. The finalfwup.confwill writeboot.img,boot.sig, androotfs.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
fwupis called to create the.fwfile. The hook would turn the SquashFS filesystem into an image that can be authenticated bydm-verityor whatever you choose to use. After that,fwupwould include the result in the.fwand 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 theboot.img. Maybe you have twoboot.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.
lawik
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.
lawik
This is the usbboot of a non-locked secure-boot with a Nerves BOOT_A partition as a boot.img with a boot.sig.
I assume the things get more interesting and that initramfs comes into the picture when I want an image with a partition scheme I can actually flash to the device. I know we spoke about this during NervesConf. I will try to follow the steps you outlined above and get it going. I expect plenty of confusion
lawik
This was a bit odd:
And it does not boot:
I have some other stuff to try with the flashing. But not sure what fwup is angry about..
lawik
Ah, their secure-boot-msd is not the way to flash it, probably.
lawik
Misread the fwup error. I’m doing fat_write on something that probably is not fat..
lawik
Because I misread Frank’s post. Lets compile a new one..
lawik
Sometimes, success is a kernel panic:
lawik
The boot.img for this one worked to boot via the rpiboot tool but that sidesteps all the initramfs stuff I reckon. It is the BOOT_A partition of a pretty stock rpi4 system.
Next, we init some ram in the fs.
lawik
Oh, this is the commit which made the above work: Working packaging of boot.img and boot.sig · underjord/secure_outer_rpi4@0693da1 · GitHub