Verified U-Boot
More systems these days are using some type of verified boot mechanism to ensure that only the expected code can be used to boot the system. Chrome OS uses verified boot to ensure that only approved images can be used on the Chromebook (in normal, non-developer mode). That feature is an integral part of the overall security architecture. The widespread use of UEFI on PCs in recent years has resulted in a lot of attention to its Secure Boot feature. It provides a way to ensure that only software signed by a vendor can be used on that PC.
For embedded systems that don't use Chrome OS and where UEFI is not in widespread use, some form of verified boot is useful for similar reasons. It helps to prevent malware from inserting itself into the boot process, provides user confidence that software updates are safe, and can help manufacturers control the software running on devices in the field.
The downside (at least from a technical user's point of view) may be this manufacturer control. This can be addressed by allowing the user to install keys as UEFI does, or having an option to turn off the verified boot. As an example of the latter, some Chrome OS devices have a mechanical screw which controls the firmware write-protection, so it is possible to disable verified boot.
U-Boot verified boot
U-Boot 2013.07 introduces a feature allowing for the verification of a kernel and other images. This can be used to implement a form of secure boot which we will call "verified boot", to avoid confusion with the UEFI implementation. U-Boot's new verified boot feature provides a mechanism for verifying images while still allowing them to be field-upgraded. It fits in seamlessly with the existing image loading infrastructure in U-Boot.
U-Boot verified boot relies on two familiar technologies: cryptographic hashing (e.g. SHA-1) and public key cryptography (e.g. RSA). Using these technologies it is possible to distribute images and have them verified on a device. Specifically we can create a key, hash an image, sign that hash, and publish the public key. On the device we can obtain an image and verify it was signed by the private key.
Images can be chained one after the other and signed in reverse order either using the same keys or sub-keys (keys derived from other keys). For example, U-Boot may load an image containing a new U-Boot, then boot that. That U-Boot in turn may load an image containing a kernel. Doing that would allow U-Boot itself to be updated with the firmware without risking having an unbootable device due to a bad update.
In principle this chain can be any length, but there must be an initial trusted image ("root of trust") that can start the process. This can be stored in read-only media during manufacture or perhaps protected by on-chip crypto using its own signing scheme. The "root of trust" U-Boot must include the initial public key, held in U-Boot's device tree (often called the flattened device tree or FDT). A more sophisticated scheme would allow the public keys to be provided by the user, perhaps by inserting an SD card containing the key. This could be implemented using a U-Boot script or with a more sophisticated user interface.
Overview of the verified boot flow
How does an image get signed initially, and then later verified?
First, on a host machine, we create a key pair. We make sure that the public key is distributed on each device in a tamper-proof place such as read-only memory or a verified key store. The private key is hidden away (i.e. not on the device!) since an attacker could use it to sign malicious images which all devices would accept as valid.
Second, an image is created. This is the image we want the device to load. The image is hashed and the hash is signed with the private key. This signature is sent to the device along with the image. The image typically contains one or more kernels and perhaps (on ARM at least) some device tree files for devices supported by that kernel.
Third, the device receives the image. It also hashes the image, then verifies that the hash agrees with the signature provided with the image. If it matches then the image is known to be signed as in step two, and it is safe to be used.
Signing and verifying
The implementation in U-Boot follows the above process closely. We will illustrate this by describing the process and also following along with an example. You can try the example yourself, or you can use U-Boot's vboot_test.sh which is a ready-made example using U-Boot's sandbox environment. The creation of a key pair is completed using openssl (you may need to install libssl-dev or similar package on your machine). These commands create a key pair and certificate (containing the public key) using 2048-bit RSA.
$ openssl genrsa -F4 -out keys/dev.key 2048 $ openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt
Having created these, we want to sign an image. U-Boot's primary image format is FIT (Flat Image Tree), a very flexible, structured container format which supports multiple kernel images, device trees, ram disks, etc. It is easy to add signatures and other metadata to a FIT either during or after creation. The signing can also be performed at the same time as image creation, or later.
So first, to create the FIT:
$ mkimage -f image.its image.fit
Then to sign it (with U-Boot 2013.07 or later):
$ mkimage -F image.fit -k keys -K u-boot.dtb -c "sjg@kiwi_signer 5-Sep-2013" -r
Here, -k provides the directory containing keys, -K is the FDT where the public key information will be stored (this file needs to be available on the device). The -c option provides a comment and -r means that any keys used for signing in this pass will be marked as "required", meaning that U-Boot will fail the image if they do not all verify.
The signing command can be run multiple times with different key directories. Each time it is run, it tries to find the keys mentioned in the FIT and sign images using them. The -K argument is itself a device tree file. Verified boot uses this to hold the public key information as mentioned above, and mkimage stores the public key there ready for use.
When creating a FIT with mkimage, a source file is provided. This tells mkimage what images should be included in the FIT. The keys used to sign the image are also specified in this file. An example source file is available in the U-Boot source tree.
The above scheme has a weakness. An attacker can create a new configuration to mix and match images and device tree files and thereby perhaps cause an incorrect combination to be booted. To avoid this, it is possible to sign configurations. This is more secure since it allows U-Boot to check not only that images are correct, but also that the correct images are being used together (example).
The setup is very similar, except now the signature is attached to the configuration(s) and not the images. Each image instead has a simple hash to protect it. The signing process ensures that the configuration and the hash for each associated image is signed. When booting, the configuration is checked first before any images can be loaded. As before, it is possible to sign multiple configurations at different times with different keys, without affecting the validity of previous signatures.
In the general case, there is nothing special to be done in U-Boot for images to be verified when loaded. When the "bootm" command runs, it will run through the FIT as normal — including checking hashes as previously supported. When U-Boot sees a signature node it will verify it (using public keys in the U-Boot control FDT) and display a plus for success and minus for failure. In this case failures are informational and do not cause the image to be rejected. But if any key is marked "required" then U-Boot will fail the image if it does not verify. This marking is done using the -r parameter to mkimage, as described earlier. A bootm run will then include the line:
Verifying Hash Integrity ... sha1,rsa2048:dev+ OKin its output, which indicates that RSA signature checking was performed on the image.
Other options and features
Apart from the core function of signing and verifying images, there are a number of optional features and expansions that can be used. For example is possible to use SoC-accelerated crypto, automatically update U-Boot in the field, provide a recovery mode from external media or the network when image verification fails, or to allow user-installed keys.
A Trusted Platform Module (TPM) can be used to hold rollback counters, to protect against rolling back to an older, compromised firmware. U-Boot also provides TPM support for trusted boot and remote attestation.
Performance
Verified boot does not necessarily mean slow boot. Chrome OS starts up U-Boot, loads and verifies a second U-Boot, loads and verifies a kernel and jumps to it all in under 700ms on a modern SoC. Similarly, U-Boot's verified boot implementation is optimized for code size and performance. Keys are pre-processed by mkimage so that U-Boot has to do only minimal processing to use them. The crypto code is simple and does not deal with multiple indirections and data conversions. In fact, it typically takes longer to hash a kernel than it does to verify it using RSA. On a BeagleBone Black (OMAP4), it takes about 6ms to verify a configuration and only adds 6.2KB to U-Boot's code size.
Wrapping up
Verified boot came from Google's Chrome OS, which uses a similar scheme with its own key format and verified boot flow. Initial patches were posted in January 2013 and the upstreaming work was completed for the 2013.07 U-Boot release in July.
The verified boot feature provides an easy way to enable a more secure boot on a device with minimal code size and boot-time impact. It uses the existing U-Boot FIT format and mkimage tool and is compatible with existing boot scripts.
More detailed design information is provided in the U-Boot source tree in verified-boot.txt and signature.txt.
Index entries for this article | |
---|---|
Security | Secure boot |
GuestArticles | Glass, Simon |
Posted Oct 23, 2013 23:58 UTC (Wed)
by josh (subscriber, #17465)
[Link] (2 responses)
Argh! FIT is already an established term in firmware, for "Firmware Interface Table", the partition table in a flash part. Acronym collisions across the entire technology industry are unavoidable due to limited namespaces, but having FIT mean two different things within the much narrower realm of system firmware seems highly confusing.
Posted Oct 24, 2013 0:55 UTC (Thu)
by ncm (guest, #165)
[Link]
Posted Nov 5, 2013 14:02 UTC (Tue)
by jdisnard (subscriber, #90248)
[Link]
Does seem to be an abuse of the Device Tree Compiler (DTC) to make device trees of all the things. Actually U-boot FIT images are nice, and I like them alot, much better than actual flattened-device-tree blobs. Never heard of "Firmware Interface Table" before. Perhaps since they apply to different firmware universes, it doesn't matter much?
Verified U-Boot
Verified U-Boot
Verified U-Boot