This Rust crate can be used to generate the VBMeta block of the system image. VBMeta holds a key and descriptors needed during startup to verify the integrity of the image, which is part of the Verified Boot process.
It further defines the vbmeta
tool, which is a thin wrapper around the main functionality of the library. It serves as a means of creating one-off VBMeta images from ZBIs - and its source further serves as example usage of the crate.
Usage
use vbmeta::{Key, HashDescriptor, Salt, VBMeta}; let key = Key::try_new(PRIVATE_KEY_PEM, PUBLIC_KEY_METADATA).unwrap(); let salt = Salt::random().unwrap(); let descriptor = HashDescriptor::new("zircon", ZBI_BYTES, salt); let descriptors = vec![descriptor]; let mut vbmeta = VBMeta::sign(descriptors, key).unwrap(); let vbmeta_bytes = vbmeta.bytes;
The layout of the VBMeta struct consists of a header, authentication data, and auxiliary data. The header is required and is always 0x100 bytes in length. Both the authentication and auxiliary data are generally optional, but in this API must be explicitly specified in VBMeta::sign(descriptors, key)
, because a VBMeta block without a descriptor and key is not useful on Fuchsia.
The VBMeta header contains information about how the block was generated, and section offsets for the authentication and auxiliary data.
The authentication data is used to verify the integrity of the vbmeta header and auxiliary data by signing it with the private key. First, the hash is calculated by digesting the header concatenated with the auxiliary data. Second, the signature is found by signing the hash with the private key.
Descriptors
Currently, Fuchsia only uses hash descriptors. VBMeta hash descriptors are used to verify the integrity of a particular image (such as the ZBI). The salt is added to the image before generating the digest. During startup, the image is hashed, and if it does not match the digest in VBMeta, the image is found to be untrustworthy.
Public key header
The public key is used to verify the signature in the authentication data matches the hash in the authentication data. On startup, the public key header is verified by comparing with a known trustworthy public key (usually fused onto the device).
As RSA signing large images is quite slow, intermediate values (n0inv
and rr
) are pre-calculated and stored in VBMeta's public key header to speed up the process.
Public key metadata
The public key metadata is copied directly from the input of Key::try_new(PRIVATE_KEY_PEM, PUBLIC_KEY_METADATA)
, and placed after the public key header.
When a device starts up, before loading the ZBI, Zircon uses libavb
to verify the authenticity of the VBMeta struct and each image. This is completed with the ZirconVBootSlotVerify function in Zircon's boot process, and performs the following steps: