3.2. Secure boot and image signing¶
The Onyx Boox Note Air5 C carries a fully populated, correctly signed Android
Verified Boot (AVB) layer and devinfo reports the bootloader locked — but
the Qualcomm bootloader chain underneath it (XBL, ABL, TZ) is signed with
Qualcomm’s publicly known generic test keys, not an OEM production key. A
device running test-key-signed XBL has its Secure Boot fuse (QFPROM
SEC_BOOT) effectively open — not blown, or blown to a non-exclusive/test
key (see On-device confirmation below). Either way the ROM pins the chain
to no secret, so the whole trust chain — including the AVB enforcement ABL
itself performs — is bypassable by re-signing images with the same, publicly
available test key: the re-signing acceptance itself has been confirmed
on-device, though flashing a patched ABL specifically to defeat its checks
has not (see Why verification is not enforced below).
3.2.1. On-device confirmation¶
A foreign Firehose programmer (lenovo_motorola
…[REDACTED]…_fhprg.bin, HWID 0x0) loaded and dumped the device.
On a secure-booted device, PBL/Sahara rejects a non-OEM-signed programmer
against the fused OEM_PK_HASH; it did not. SEC_BOOT is open — either
not blown, or set to a non-exclusive/test key. See Firehose fuse read and secure-boot confirmation.
QFPROM SEC_BOOT_ENABLE / OEM_PK_HASH are memory-mapped registers at
0x00780000, not in any partition. Sahara reports OEM_ID=0x0000 /
MODEL_ID=0x0000 (see EDL / Firehose interface); what has and hasn’t been
read from these two registers is under Not yet observed below.
PBL enforces the ELF per-segment SHA-384 hash table but not the
root-of-trust signature: a modified image is accepted iff its hash table is
recomputed to match (no OEM re-signing needed); a zeroed hash table is
rejected at Sahara. Integrity (SHA-384) is enforced; authenticity
(OEM_PK_HASH signature) is not. Details in Firehose fuse read and secure-boot confirmation.
3.2.2. AVB / vbmeta_a.bin¶
The AVB0 header, its descriptors, and the recomputed image hashes:
Field |
Value |
|---|---|
Magic / libavb |
|
Algorithm |
2 = SHA256_RSA4096 (signed) |
Signature |
present, 512 bytes; embedded 4096-bit RSA public key |
Public key SHA256 |
|
Flags |
|
→ VERIFICATION_DISABLED (bit0) |
False (verification NOT disabled) |
→ HASHTREE_DISABLED (bit1) |
False (dm-verity NOT disabled) |
Build fingerprint |
|
Security patch |
2025-10-01, Android 11 |
Descriptors:
Chain partition →
vbmeta_system(rollback_loc 2, its own 2048-bit key) — signature delegated.Hash descriptors (whole-image):
boot,dtbo,recovery.Hashtree descriptors (dm-verity): 2 (system/vendor/odm/product class partitions).
Integrity re-verification (digest = SHA256(salt ‖ image[:image_size])):
Partition |
AVB descriptor digest |
Recomputed |
Match |
|---|---|---|---|
boot |
|
same |
yes |
dtbo |
|
same |
yes |
recovery |
|
same |
yes |
The AVB layer is legitimately signed with release-keys, verification and hashtree are enabled, and the boot/dtbo/recovery images match their descriptors exactly. At the AVB level this is a properly verified production build. The ABL binary that enforces this layer is itself unprotected (see Why verification is not enforced), so a patched ABL can report success regardless of the actual image contents.
3.2.3. Device lock state — devinfo.bin¶
devinfo.bin’s is_unlocked field reads 0 → LOCKED (fastboot flashing
disabled in normal flow); full struct layout and byte offsets are in
AVB enforcement code path (LoadImageAndAuth / libavb). A locked flag only matters if the code
reading it is itself trusted, which it is not here (see Why verification is
not enforced).
3.2.4. Qualcomm bootloader signing chains¶
The embedded X.509 chains (Qualcomm MBN / SecTools format) are the actual root
of trust. xbl_a.bin, abl_a.bin and tz_a.bin are all signed with the
same generic Qualcomm TEST chain:
Tier |
Subject |
Note |
|---|---|---|
Leaf |
|
image signer |
Attestation CA |
|
|
Root CA |
|
public test key |
Signature algorithm: ECDSA P-384 (secp384r1) / SHA-384.
XBL and ABL chain to the identical test root: SHA256 fpr
95:9B:8D:05:49:EF:41:BE:FA:BC:24:F5:1E:FE:84:FE:E3:66:AC:16:9A:B0:4A:0D:B3:0C:79:9B:32:4F:D7:98.“General Use Test Key (for testing only)” is Qualcomm’s shipped-in-SecTools sample key; the private half is effectively public knowledge.
tz_a.bin also embeds a genuine Qualcomm chain
CN=CASS - SBL3 (QUALCOMM) → QSEE Attestation Root CA 4 SubCA 1 →
QSEE Attestation Root CA 4 (Qualcomm Technologies, Inc. / Qualcomm
Cryptographic Operations). These are the QSEE/Keymaster key-attestation
keybox certificates carried as reference data inside TrustZone. They are real
Qualcomm production certs but have nothing to do with verifying the boot
images, and are not the signing chain.
3.2.5. Multi-image OEM authentication table (multiimgoem_a)¶
multiimgoem_a.bin (LUN4, 32 KB) carries a second, independent signing
mechanism alongside the per-image MBN hash segments above: a multi-image
OEM authentication table. MBN/ELF32 envelope (test-key cert chain, same
2024-07-03 attestation cert as imagefv_a) wrapping a 1112-byte data
segment loaded to IMEM 0x148d7000. Layout: ASCII magic ``MULT`` at
+0, a reserved zero region, an entry count = 15 (0x0f at
+0x108), then 14 fixed 56-byte records starting at +0x118, each
[SHA-384 : 48 B][image-id : u64 LE] (the image-id is the last 8 bytes
of each record). The header’s entry count of 15 has no matching 15th
record: 0x118 + 15×56 = 1120 bytes, one past the segment’s 1112-byte
end, so only 14 complete records physically fit. The image-ids present are
0x02, 0x03, 0x04, 0x05, 0x07, 0x0e, 0x12, 0x15, 0x17, 0x21, 0x24, 0x25,
0x27, 0x28 (QTI multi-image image-IDs; the exact id→partition-name
mapping is a QTI enum not in this dump).
So this is a QTI “multi-image” descriptor: one signed table of 14 SHA-384
image hashes that lets ABL/XBL authenticate that group of images under a
single OEM signature rather than requiring each to carry its own MBN
signature — using the same hash algorithm (SHA-384) as the rest of the
chain. The companion multiimgqti slot is not present on this unit; only
multiimgoem is. A/B slots are byte-identical.
3.2.6. Why verification is not enforced¶
The immutable PBL verifies XBL against OEM_PK_HASH only when
SEC_BOOT is blown; since XBL/ABL here are signed by the generic public
test key (Qualcomm bootloader signing chains above), SEC_BOOT is
effectively open — not blown, or blown to a non-exclusive/test key. The
direct consequence for each enforcement point documented above:
ABL’s devinfo lock check (Device lock state — devinfo.bin) and its
AVB signature check (AVB / vbmeta_a.bin) both run inside an ABL binary
that anyone can re-sign with the same public test key, so both are
bypassable in practice — the same re-signing acceptance already confirmed
on-device via the Firehose programmer above (On-device confirmation),
though turning off the ABL-side checks specifically has not been directly
tested by flashing a patched ABL.
3.2.7. Not yet observed¶
QFPROM
SEC_BOOT_ENABLEblown to a non-test hash — a direct QFPROMpeekat either register faults (XPU-protected, see Firehose fuse read and secure-boot confirmation).OEM_PK_HASHhas instead been read indirectly via SaharaCMD_EXEC(non-zero, origin unknown — EDL / Firehose interface);SEC_BOOT_ENABLEhas no such indirect read and remains unobserved.PBL enforcing the root-of-trust signature, not just the hash table (it enforces only the hash — Firehose fuse read and secure-boot confirmation).
XBL/ABL signed under an Onyx/OEM production root instead of the test key.
3.2.8. Provenance¶
- Source:
static EDL dump in
../_READONLY/(read-only); on-device EDL test sessions.- Method:
AVB parsed with a hand-rolled
AVB0reader (noavbtoolon host); hashes recomputed with Pythonhashlib. Certs carved on DER30 82boundaries fromxbl_a/abl_a/tz_a, decoded withopenssl x509/asn1parse. Lock state read fromdevinfo.binoffsets after the 13-byteANDROID-BOOT!magic. Carved DER certs kept in/tmp/boox_certs/for re-inspection.- Cross-refs:
Firehose fuse read and secure-boot confirmation (on-device confirmation, hash gate), EDL / Firehose interface (Sahara OEM_ID,
OEM_PK_HASH), AVB enforcement code path (LoadImageAndAuth / libavb) (device_info accessors), Partition map and checksums.