OptiStick 5 (S905X5M) secure-boot test — signed bootloader on an unfused unit
Wilber Zheng · 2026-10-29 → 2026-10-30 · follow-up to the dbg1479 report
Result: a device-signed bootloader boots to the player on an unfused unit (dbg1491), once two things are true:
- bl30/bl33 are signed only, not AES-encrypted: drop
--infile-aes256-bl30/bl33-payloadfromgen-device-fip.sh. - vbmeta is signed with the same key as bl33 level-3. On S7D, a device-signed u-boot verifies vbmeta against the bl33 key in the FIP first (
CONFIG_AVB2_KPUB_FROM_FIP), and treats a mismatch as untrusted.
Identity
| Item | Value |
|---|---|
| Unit | One OptiStick 5 PVT (S905X5M / S7D rev B, 1 GB, eMMC BJTD4R). eFuse never burned. The same unit was used for every ROM below. |
| Burn | Aml_USB_Burn_Tool V1.0.3 (Mac), "Erase Bootloader" + "Erase Flash", image only, no eFuse / no .efuse file |
| SDK | Amlogic Yocto Kirkstone SDK, manifest yocto-kirkstone-sdk-lts.2.0 (u-boot v2023 @48669f6c, fip @76d3ff1e) |
| Source | prd36 source (yocto_os branch feature/wilber/secureboot-prd36-test and its children, below) |
| Signing keys | The device-keys SEI provided (s905x5m template, RSA-4096, trustchain 0) |
| Docs used | S905X5M Series Secure Boot User Guide (0.3); S905X5M Series eFuse Object Burning User Guide (0.3); Yocto SDK Enable Secureboot User Guide (0.1) |
| ROM | Bootloader | vbmeta key | Result | md5 |
|---|---|---|---|---|
| dbg1479 | device-signed, bl30/bl33 AES-encrypted (SDK default) | avb-dev-k1 | FAIL stops after boot bl33 ! and drops to USB mode (DFU:1) | 9c5b93f925245245ed5a01ffe9984e9c |
| dbg1489 | device-signed, not encrypted | avb-dev-k1 | PARTIAL U-Boot runs, then ab: both slots unbootable and the rescue ladder parks in USB mode | 329862b863d561ff4690fbf3f5d28f04 |
| dbg1476 | unsigned (control, same source) | avb-dev-k1 | PASS boots to the player; AVB2 cannot find fip key → OptiSigns kpub | 3deceafbd9a68c1c060805e915cae796 |
| dbg1491 | device-signed, not encrypted (as dbg1489) | SEI bl33-level-3 (sha1 f93861f0…) | PASS AVB2 verified with fip key success ×2, boots to the player | c90d0cf748f331d2d20bd3e41b236dd4 |
dbg1491 sha256 2458fdcb3b2293a436c5cd40b6ec2b01e71e4c874601b0195e427d6f702ec476. ROMs are on the bench host in ~/cand-out/.
Finding 1 — the SDK signing flow also encrypts bl30/bl33 (dbg1479)
fip/s7d/generate-binaries/bin/gen-device-fip.sh:71,74always passes--infile-aes256-bl30-payload/--infile-aes256-bl33-payload(genkey-prot-bl30/bl33.bin, derived from DVGK), so bl30/bl33 come out AES-encrypted.- The eFuse guide defines
FEAT_ENABLE_DEVICE_PROTas "Enable encryption of Device Vendor controlled BL30 and BL33 image". An unfused chip has neither that bit nor DVGK, so it jumps into encrypted bl33 and resets (log:decomp BL33 is Success→boot bl33 !→ BootROM, DFU:1). - Removing only those two arguments (every
--infile-signkey-*kept) gave dbg1489, which reaches U-Boot.
Finding 2 — a device-signed u-boot trusts only the FIP bl33 key for vbmeta (dbg1489 → dbg1491)
arch/arm/include/asm/amlogic/arch-s7d/cpu.h:80definesCONFIG_AVB2_KPUB_FROM_FIP.cmd/amlogic/cmd_avb.c:514-529compares the vbmeta key with__scs_bl33_devkeyfirst:- key not present (unsigned bl33) →
AVB2 cannot find fip key, and it falls through to our patch-166 OptiSigns kpub; - key present but different →
AVB2 verified with fip key failed, and it returns untrusted right away.
- key not present (unsigned bl33) →
fip/s7d/bin/add-device-keys-bl33.sh:187,208writes the bl33-level-3 public key into bl33 at offset 4. That is the FIP key.- dbg1489 signed vbmeta with avb-dev-k1, so slot A failed AVB, then slot B, and
get_valid_slotended inboth slots unbootable(our patches 113/122 rescue ladder). The dbg1476 control on the same unit and source boots, which isolates the cause to the signed bl33. - dbg1491 signs vbmeta and the recovery footer with the SEI bl33-level-3 key:
AVB2 verifying with fip key→AVB2 verified with fip key successbefore bothget_valid_slotandstoreboot. Then dm-verity on system_a, state/home unlocked, player up at about 15 s. - This logic does not look at eFuse, so it applies the same way on fused units. It is also why Amlogic's Yocto
scsroute signs vbmeta with the bl33 level-3 key. - The kernel itself is not checked by the chip path:
--avb2(AVB is in DISTRO_FEATURES viamesons7d-bm201-common.inc:83,u-boot_2023.01.bb:70) makes the Makefile defineCONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK(bl33/v2023/Makefile:2080).
Repo and SDK changes
Vendor SDK island (untracked; applied for each test bake, restored to pristine after each one)
| File | Change | ROMs |
|---|---|---|
bl33/v2023/configs/amlogic/s7d_bm201_defconfig | + CONFIG_AML_SIGNED_UBOOT=y (Secure Boot guide §2.6) | 1479, 1489, 1491 |
bl33/v2023/board/amlogic/s7d_bm201/fw_arb.cfg | device_scs/tee/ree_vers 0x6 → 0x0 | 1479, 1489, 1491 |
bl33/v2023/board/amlogic/s7d_bm201/device-keys/ | SEI device-keys copied in; device-fip-header.bin regenerated with gen_scs_root_hash.sh (the supplied one failed the BL30 size check; roothash unchanged) | 1479, 1489, 1491 |
fip/s7d/generate-binaries/bin/gen-device-fip.sh | − the two --infile-aes256-bl30/bl33-payload lines | 1489, 1491 |
| build host | python2 (needed by pem_extract_pubkey.py) | all |
yocto_os local branches (never pushed, never merged)
| Commit | Branch | What |
|---|---|---|
a0e6b588a | secureboot-prd36-test | amlogic/island.manifest: pin the signed-u-boot island (so island-manifest verify passes) |
387047605 | secureboot-prd36-test | amlogic/sdk-fixes/debug-image/assert-provenance.py: check 3 compares the bootloader with u-boot.bin.device.signed when the deploy aml_upgrade_package_ab.conf names it (it always compared with u-boot.bin.signed and refused the correct dbg1479 pack). Still a hard check. |
e341e47bc | secureboot-prd36-noenc | amlogic/island.manifest: pin the signed-only (no AES) island |
4583cd7fa | secureboot-prd36-avbfip | TEST-ONLY ota-trust:
optisigns-avb-kpub.h, avb-kpub.list, patch 166 and the prd channel are untouched. |
--- a/ota-trust/signers.json
+++ b/ota-trust/signers.json
"avb": {
- "dev": "avb-dev-k1",
+ "dev": "avb-dev-k2",
"prod": "avb-prod-k1"
}
Branches are named feature/wilber/secureboot-prd36-{test,noenc,avbfip}. Each one is stacked on the previous one.
Risks
- eFuse burning is irreversible. Nothing here has been tested on a fused unit.
- The SEI keyset is test-only: its private keys have been shared, and level-2 equals every level-3 key (same sha256). It must never be fused.
- Not every key path is aligned yet. dbg1491's image still lists avb-dev-k1 in
/etc/optisigns/avb-kpub.list, and the u-boot header still carries avb-dev-k1. So the on-device golden refresh would refuse SEI-signed goldens. Boot is unaffected; this is a test ROM only. - bl33 and AVB will share one key: if it leaks, both the bootloader and the OS fall. Rotating the AVB key means re-signing the bootloader.
- Anti-rollback is always on once fused (one-way OTP, at most 32 updates). After changing
fw_arb.cfg, re-sign the template withexport_signing_keys_and_sign_template.sh --arb-config. - Enabling secure boot may change RPMB key pairing (
FEAT_DISABLE_RPMB_SECRET_PAIRING_AFTER_DV_SCS). This can affect TEE/RPMB provisioning.
Plan (ranked)
- RECOMMENDED One key for bl33 level-3 and AVB, in KMS.
- Generate the production (and a separate dev) device keyset so that bl33-level-3 is the AVB key.
- Sign through
--cmd-signpipe-*, signed-only (no--infile-aes256-*). - Register the key everywhere one key is expected:
ota-trust,optisigns-avb-kpub.h(patch 166),avb-kpub.list. - Re-bake, then boot it on an unfused unit first.
- Wait for Amlogic's answers before fusing anything: the minimal signed-only set and order (expected: both root-cert hashes + lock,
DEVICE_SCS_SIG,DEVICE_VENDOR_SIG; no DVGK/DVUK,DEVICE_PROT,*_PUBRSA_PROT, USB_AUTH or DIF), the RPMB impact, and the signpipe format. - Fuse one sacrificial dev unit (DUT3) with the dev root and the confirmed minimal set. Verify boot, OTA, USB re-burn and recovery. Production fusing comes last.
- Alternative (not recommended): undefine
CONFIG_AVB2_KPUB_FROM_FIP. That needs a u-boot change, and the fused branch would also need patch 166 to trust our key (C6); a mistake there bricks fused units.
Logs (identifiers scrubbed)
- dbg1479-signed-fail.log: encrypted bl33, stops at
boot bl33 ! - dbg1476-unsigned-boot.log: unsigned control, burn + first boot
- dbg1491-avbfip-boot.log: signed + vbmeta on the bl33 key, second boot after the burn (the first-boot capture stalled; that boot came up normally on screen)
- dbg1489: two captures pasted in chat, not kept as files. Key lines:
active slot = 1→ab: both slots unbootable -- running the rescue ladder (no display), noMagic … incorrectline (the misc data was valid; earlier, uncaptured boots had used up both slots).
中文摘要
没烧 eFuse 的 Stick5 上,签了名的 bootloader 已经能开到播放器(dbg1491)。前提有两个:
- 只签名、不加密。dbg1479 起不来,是因为 SDK 默认把 bl30/bl33 加密了。
- vbmeta 要用 bl33 第三级密钥签。S7D 签了名的 u-boot 只认 FIP 里的这把密钥,dbg1489 卡在"两个槽都不可启动"就是这个原因。
u-boot 代码一行没改。仓库的改动都在本地分支,没有推送。下一步建议:用 KMS 生成正式密钥,让 bl33 第三级和 AVB 用同一把;Amlogic 确认最少要烧哪些 eFuse 位以后,先找一台测试机烧 eFuse 验证。