==================================== 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). 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 :doc:`/edl/firehose`. 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 :doc:`/edl/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 :doc:`/edl/firehose`. AVB / vbmeta_a.bin ================== The ``AVB0`` header, its descriptors, and the recomputed image hashes: .. list-table:: :header-rows: 1 :widths: 30 70 * - Field - Value * - Magic / libavb - ``AVB0``, required 1.0, ``avbtool 1.3.0`` * - Algorithm - 2 = SHA256_RSA4096 (signed) * - Signature - present, 512 bytes; embedded 4096-bit RSA public key * - Public key SHA256 - ``7728e30f50bfa5cea165f473175a08803f6a8346642b5aa10913e9d9e6defef6`` * - Flags - ``0x00000000`` * - → VERIFICATION_DISABLED (bit0) - False (verification NOT disabled) * - → HASHTREE_DISABLED (bit1) - False (dm-verity NOT disabled) * - Build fingerprint - ``Onyx/NoteAir5C/NoteAir5C:11/2026-08-03_16-13_4.2.1-rel_0803_eaa32b54f/3268:user/release-keys`` * - 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 ``95fcfc2751e6006381a6c9e4…`` same yes dtbo ``7a108e1f0ac3296cf72daa77…`` same yes recovery ``694d0092478bd48505081cea…`` 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. 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 :doc:`/abl/verified-boot`. A locked flag only matters if the code reading it is itself trusted, which it is not here (see `Why verification is not enforced`_). 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 ``CN=SecTools Test User, O=SecTools`` image signer Attestation CA ``CN=Generated Test Attestation CA, O=SecTools`` Root CA ``CN=Generated Test Root CA, OU=CDMA Technologies, OU=General Use Test Key (for testing only)`` 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. 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. 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. Not yet observed ================= - QFPROM ``SEC_BOOT_ENABLE`` blown to a non-test hash — a direct QFPROM ``peek`` at either register faults (XPU-protected, see :doc:`/edl/firehose`). ``OEM_PK_HASH`` has instead been read indirectly via Sahara ``CMD_EXEC`` (non-zero, origin unknown — :doc:`/edl/interface`); ``SEC_BOOT_ENABLE`` has no such indirect read and remains unobserved. - PBL enforcing the root-of-trust signature, not just the hash table (it enforces only the hash — :doc:`/edl/firehose`). - XBL/ABL signed under an Onyx/OEM production root instead of the test key. Provenance ========== :Source: static EDL dump in ``../_READONLY/`` (read-only); on-device EDL test sessions. :Method: AVB parsed with a hand-rolled ``AVB0`` reader (no ``avbtool`` on host); hashes recomputed with Python ``hashlib``. Certs carved on DER ``30 82`` boundaries from ``xbl_a`` / ``abl_a`` / ``tz_a``, decoded with ``openssl x509`` / ``asn1parse``. Lock state read from ``devinfo.bin`` offsets after the 13-byte ``ANDROID-BOOT!`` magic. Carved DER certs kept in ``/tmp/boox_certs/`` for re-inspection. :Cross-refs: :doc:`/edl/firehose` (on-device confirmation, hash gate), :doc:`/edl/interface` (Sahara OEM_ID, ``OEM_PK_HASH``), :doc:`/abl/verified-boot` (device_info accessors), :doc:`/partition-map`.