A toolkit that brings Android Verified Boot (AVB) to embedded Linux systems, covering the full trust chain:
- Append hash tree, sign and attach vbmeta on the host with avb_sign.py
- Verify on the target with avb_verify
It verifies AVB-signed images using libavb, extracts dm-verity parameters ready for use
with dmsetup and embeds a PKCS#7 root hash signature for kernel-level
integrity enforcement via: CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG.
It implements two layers of verification:
AVB layervalidates the vbmeta AVB raw signature (RSA/ML-DSA) and checks the embedded public key against a trusted reference key (or its SHA-256 digest, e.g. burned into OTP fuses).Root hash layer(optional) if the vbmeta image contains aroothash_sigproperty (a PKCS#7 signature of the root hash), loads it into the user session keyring so dm-verity can independently verify the root hash viaCONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG.
- CMake >= 3.10
- GCC or Clang
- libavb (submodule)
- Python 3 + OpenSSL for signing images with
avbtool(development only)
Note:
avb_verifyis lightweight: no external crypto library is required on the target and all cryptographic operations are handled by libavb's own built-in implementation. On the host side,avb_sign.py(viaavbtool) handles dm-verity hash tree generation and vbmeta signing directly, so cryptsetup or any verity userspace tooling is not required.
cmake -B build
cmake --build buildSupported algorithms: SHA256_RSA2048, SHA256_RSA4096, SHA256_RSA8192,
SHA512_RSA2048, SHA512_RSA4096, SHA512_RSA8192, MLDSA65, MLDSA87.
# Generate signing key
openssl genrsa -out key.pem 4096
# Self-signed certificate from the same key (used for PKCS#7 roothash_sig)
openssl req -x509 -key key.pem -out sig_cert.pem -days 3650 -subj "/CN=avb-signer"python3 avb_sign.py \
--image rootfs.ext4 \
--key key.pem \
--cert sig_cert.pem \
--partition-name rootfs \
--algorithm SHA256_RSA4096Use --output to write the signed image to a separate file and leave the input untouched:
python3 avb_sign.py \
--image rootfs.ext4 \
--output rootfs.ext4.avbverity \
--key key.pem \
--cert sig_cert.pem \
--partition-name rootfs \
--algorithm SHA256_RSA4096avb_verify requires the public key in AVB's serialized format (not PEM):
python3 avb/avbtool.py extract_public_key --key key.pem --output pubkey.binDeploy pubkey.bin to the target (e.g. stored in the initramfs).
sig_cert.pem is compiled into the kernel at build time via CONFIG_SYSTEM_TRUSTED_KEYS.
avb_verify -d <device> -k <pubkey.bin> [-x <sha256>] [-t] [-h]
| Option | Description |
|---|---|
-d, --device <path> |
Image file or block device (required) |
-k, --pubkey <path> |
AVB public key in serialized format (required) |
-x, --pubkey-digest <hex> |
Also verify that the key's SHA-256 matches this digest |
-t, --dm-table |
Print only the raw dm-verity table line |
-h, --help |
Show help |
Prints a human-readable verification summary followed by the dm-verity table:
avb_verify -d /dev/mmcblk0p2 -k pubkey.binFooter scan: 39.261 ms
Roothash signature loaded into keyring: avb_roothash_sig.root (687 bytes)
Verification: OK
Algorithm: SHA256_RSA4096
Rollback: 0
Partition: root
Hash alg: sha256
Data blocks: 77046
Data block sz: 4096
Hash block sz: 4096
Hash offset: 315580416
Root digest: 4aec6b1c1675f1a1bc2dd8394185e2fba4a230e8f754028e868b46e2f6cfc7a2
Salt: 72807c3fa652f8e7f176b22b55cf8c711e720ab067d9f26f8dc72a831e291be6
Roothash sig: avb_roothash_sig.root
dm table:
0 616368 verity 1 /dev/mmcblk0p2 /dev/mmcblk0p2 4096 4096 77046 77046 sha256 \
4aec6b1c1675f1a1bc2dd8394185e2fba4a230e8f754028e868b46e2f6cfc7a2 72807c3fa652f8e7f176b22b55cf8c711e720ab067d9f26f8dc72a831e291be6 \
2 root_hash_sig_key_desc avb_roothash_sig.root
Roothash sig and root_hash_sig_key_desc only appear when a roothash_sig
property is present in the vbmeta image (see Root hash signature).
With -t, outputs only the raw dm-verity table line for direct use with
dmsetup:
avb_verify -t -d /dev/mmcblk0p2 -k pubkey.bin | dmsetup create verity-systemUse -x to additionally verify that the embedded public key matches a known
SHA-256 digest, typically a value burned into OTP fuses at manufacturing time
or retrieved from secure storage. This guards against TOCTOU attacks where a
compromised pubkey.bin is substituted between verification and use but unlike
the key file the OTP digest is immutable and cannot be altered at runtime:
avb_verify -d /dev/mmcblk0p2 -k pubkey.bin \
-x $(sha256sum pubkey.bin | cut -d' ' -f1)AVB's vbmeta signature is verified in userspace by avb_verify within the
initramfs (which is itself verified by the bootloader at an earlier boot stage).
However, once Linux is running, the following combined attack is possible:
Attack scenario
- Attacker prepares a modified rootfs data in flash.
- Attacker overwrites
pubkey.binin memory with their own key.avb_verifyreads the attacker's key, accepts a crafted vbmeta signed with it, and passes the attacker-controlled root hash todmsetup.- dm-verity validates the tampered rootfs against the attacker's root hash and secure boot is bypassed.
The roothash_sig feature closes this window by delegating root hash
verification to the kernel: a PKCS#7 signature of the root hash is embedded
as a vbmeta property and loaded into the session keyring so dm-verity verifies
it atomically at device creation time, against the system's trusted keyring
(CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG). Even if an attacker substitutes
pubkey.bin in memory, the kernel independently rejects any root hash that
does not match the kernel-anchored trusted keyring.
The verified partition is split into a data region and an appended AVB footer that points to the vbmeta struct and hashtree.
The vbmeta block holds the hashtree descriptor (root hash, salt, tree layout) and a property descriptor (roothash_sig) along with the public key and signature over the whole structure.
Integrity is anchored by a Merkle tree built over fixed-size data blocks. Only the root hash needs to be trusted and any tampered block causes a verification failure up the tree.
The full on-disk hashtree layout: leaf hashes covering data blocks, intermediate levels and the root hash stored in the vbmeta descriptor.
Locate the AVB footerchecks the last 64 bytes first (standard location). If not found, detects the filesystem size from its superblock (ext4, erofs, squashfs) and scans forward in 1 MiB chunks from the filesystem boundary. This allows images signed with--partition_size 0to work correctly when written to a larger block device.Verify vbmeta signaturecallsavb_vbmeta_image_verify()from libavb.Check public keycompares the key embedded in vbmeta against the trustedpubkey.bin, and optionally its SHA-256 digest.Extract dm-verity parametersparses the hashtree descriptor and builds the dm-verity table string.Load root hash signature(if present) reads theroothash_sigvbmeta property, loads the PKCS#7 blob into the session keyring viaadd_key(2), and appendsroot_hash_sig_key_descto the dm-verity table.
CONFIG_BLK_DEV_DM=y
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
CONFIG_KEYS=y
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y
CONFIG_PKCS7_MESSAGE_PARSER=y
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS="/path/to/sig_cert.pem"
CONFIG_CRYPTO_RSA=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_MLDSA=y
CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA=y
Add the option to your kernel cmdline to enforce root hash signature verification:
dm_verity.require_signatures=1
With --partition_size 0, avbtool appends metadata directly after the
filesystem data without padding to a fixed size:
Offset 0 | filesystem data (ext4, squashfs, erofs, ...)
Offset <original_image_size> | hashtree (dm-verity Merkle tree)
Offset <vbmeta_offset> | VBMeta struct (signature + descriptors)
...padding to 4 KiB block...
End of last 4 KiB block − 64 | AVB footer (64 bytes)
When the image is written to a block device larger than the signed image,
trailing zeroes push the footer away from the device end. avb_verify
handles this by detecting the filesystem type from its superblock and
scanning forward from the filesystem boundary.
AVB footer fields:
| Field | Size | Description |
|---|---|---|
Magic (AVBf) |
4 bytes | Identifies this as an AVB footer |
| Version major/minor | 8 bytes | Footer format version |
original_image_size |
8 bytes | Filesystem size before signing |
vbmeta_offset |
8 bytes | Byte offset of the VBMeta struct |
vbmeta_size |
8 bytes | Size of the VBMeta struct |
| Reserved | 28 bytes | Padding |
ctest --test-dir build -VThe test suite creates temporary ext4, erofs, and squashfs images, signs them, and exercises all code paths: signature verification, key mismatch, corruption detection, footer scanning on padded images, digest checking and root hash signature loading.
This project is licensed under the GNU General Public License v3.0.
Alternative licensing (commercial, proprietary) are available contact info@embetrix.com for your enquiries.
This project includes libavb
from the Android Open Source Project used as a git submodule under avb.
libavb is licensed under a permissive MIT-style license, the Apache License 2.0, and the BSD 3-Clause License depending on the source file: see the upstream LICENSE for the full terms.