TL;DR: Verified boot is a fundamental security technology and it is important to be able to experiment with it on easily accessible hardware. However, creating a Verified boot demo on a Raspberry Pi 3 is harder than it sounds. We set out to find resources on the internet. Unfortunately, some of these were outdated, others blatantly wrong. After our fair share of failed builds, corrupted images and kernel panics, we made it to the other side. This is our story.

Verified boot refresher

Verified boot is the answer to a very important security requirement: guaranteeing that each piece of software loaded on a device when it boots, such as the kernel and the operating system, is “authentic”. By authentic, we mean not modified by the “bad guys”, i.e. malware or attackers with physical access to device. To accomplish this, we need help from the bootloader, the low-level software taking care of loading all other software components.

But wait, things already start to get tricky: depending on the bootloader, the process described above has a different name! Verified boot is the name used by U-Boot. For devices using UEFI, the same mechanism is called Secure boot.

For now, let’s focus on U-Boot’s Verified boot and take a high-level look at how it works. Verifying the authenticity of the kernel and the OS is made possible by cryptographic tools, especially hashes and signatures. The image below summarizes the steps needed to configure Verified boot:

Verified boot preparation in a nutshell.



Let’s dive a little deeper. First, the people responsible for loading the kernel and the OS on a device create a pair of private and public keys. The public key is baked inside U-Boot. Then, the software components are hashed and the hashes are signed using the private key. Finally, the signature and all the components are packed into a special image, called a FIT image, and copied onto the device, alongside U-Boot.

When the device boots, U-Boot first verifies the signature of the hashes using the public key. If the signature is valid, it hashes each individual component and compares the fresh hash with the signed hash. If they match, then the component is authentic. If either the signature verification or the hash comparison fail, U-Boot aborts the booting process.

Raspberry Pi 3 implementation

Sounds a little abstract? We believe that the easiest way to understand security concepts is to play around with them. This is why we decided to make a demo implementation on a Raspberry Pi 3 B+ device. Our demo uses U-Boot’s Verified boot to boot into OP-TEE OS (which is an OS that lets you play around with Trusted Execution Environments, but this is a story for another time).

For a detailed guide, you can visit our Github page – you’ll find everything you need to experiment with Verified boot on your RPi 3. The process involves downloading and building a copy of OP-TEE and U-Boot, creating keys, signing the image and partitioning the RPi’s SD card to place everything tightly. Let’s take a look at the final result:

U-Boot output with Verified Boot activated.

The image above shows output from U-Boot during the RPi boot. Did you spot the line ending with “sha1,rsa2048:dev+ OK”? This means U-Boot verified the signature of the kernel, the device tree and the OS hashes. And the three lines ending with “sha1+ OK”? This shows U-Boot verified that the hashes of the different components are identical to those in the signature. Finally, satisfied that all components are authentic, it handed over execution to our kernel.

Testing our implementation

But, we can’t stop here can we? How do we know Verified Boot really works? We have to put it to the test of course! The image below shows what happens if we modify the hashes protected by the signature, rendering it invalid:

Verified Boot detects our tampering with the configuration and stops the loading process.

Perfect! U-boot detected the invalid signature and stopped the booting process.

And if we tamper with the kernel? Once more, Verified Boot kicks in, detects the freshly calculated kernel hash is not the same as the signed one and stops the booting process:

Verified Boot detects the modified kernel and refuses to load it.

Limitations of the implementation

You might have spotted a fatal flow in our approach. All the cryptographic material related to Verified boot is stored on the SD-card. The bootloader itself, which is configured to use Verified boot is stored on the SD-card. Anything stored on the SD-card can be modified… So, bypassing Verified boot in this case would just boil down to replacing the entire SD-card’s contents with what we want! How can this be prevented?

The truth is that on a Raspberry Pi 3, it cannot… To fully secure the boot process, we need to start verifying based on something immutable, a “root of trust”. This is were hardware comes to the rescue: some SoCs offer the possibility of burning cryptographic material, such as a public key, in special fuses that can only be written once. Then, using that public key, the CPU can verify the authenticity of the bootloader and the Verified boot settings stored in it, before handing over execution to it. Finally, the bootloader takes care of the verification of the kernel and the OS, exactly as in our demo. In other words, we need to create a full “chain of trust”, anchored in hardware.

Conclusion

The idea behind Verified Boot is relatively straightforward. However, finding an up-to-date target implementation for an easily accessible platform is quite a challenge. There are not many tutorials available online, and the ones we found always ended up against a wall. We won’t point any fingers, but some even concluded by “and Verified Boot is now enabled”, but it was not enabled at all (don’t worry, we will be notifying these authors). This highlights the importance of verifying whether your security requirements are actually being enforced by your implementation!

This is not the end of the line. As part of NVISO Labs R&D activities, we will keep experimenting with all types of secure boot and bring you the latest on this blog. Until next time, stay safe.

About the author

Théo Rigas is an IT Security Consultant at NVISO. He has researched the security of connected alarm systems and is currently working on more IoT and embedded device security projects . Outside of his Research work, he performs Web, Mobile and IoT security assessments for NVISO.

Additional ressources

If you want to dive deeper in the technologies discussed in this post, here are some useful ressources:

ARM software’s Verified boot explanation: https://github.com/ARM-software/u-boot/blob/master/doc/uImage.FIT/verified-boot.txt

ARM software’s description of the image signing process: https://github.com/ARM-software/u-boot/blob/master/doc/uImage.FIT/signature.txt

UEFI’s whitepaper on Roots of Trust:

https://uefi.org/sites/default/files/resources/UEFI%20RoT%20white%20paper_Final%208%208%2016%20(003).pdf

And don’t forget to take a loot at our detailed instructions for enabling Verified boot on RPi3 on Github: https://github.com/NVISO-BE/VerifiedBootRPi3 .

Share this: Twitter

Reddit

WhatsApp

Email

