Orin Nano R36.5 SBKPKC: bootrom RCM rejects HSM-encrypted mb1, no UART output — chain spec verified

Edited 2026-06-10: BSI fuse readback added + new test results sharpened the diagnosis — see Update reply below.

Setup

  • Module: Jetson Orin Nano Super (P3767, T234, A01)
  • L4T: R36.5.0
  • Host: Ubuntu 24.04 + Docker (BSP container)
  • Auth chain: SBKPKC (PKC + SBK both fused). Production Mode NOT yet enabled. ODM_K1/K2 unprovisioned. BOOT_SECURITY_INFO_0 bit [3] burned.
  • SBK source: YubiHSM 2 (FIPS) opaque object. AES-256, 32 raw bytes. Same 32 bytes (sha256-verified) were used both for --encrypt_key to flash.sh and for the SBK fuse burn (via odmfuse.sh -X <xml> with <fuse name="SecureBootKey" size="32" value="0x…" />).
  • PKC source: YubiHSM RSA-3072 private key (same root used for both the PKC fuse hash burn and for tegrasign PKC signing).

Symptom

flash.sh --no-flash --hsm -u <PKC.pubkey> -v <SBK.hex> -c bootloader/generic/cfg/flash_t234_qspi.xml jetson-orin-nano-devkit-super internal produces signed+encrypted artifacts cleanly, then fails at the RCM boot-rom communication step:

[   8.0816 ] tegrarcm_v2 --new_session --chip 0x23 0 --uid
              --download bct_br br_bct_BR.bct
              --download mb1 mb1_t234_prod_aligned_sigheader_encrypt.bin.signed
              --download psc_bl1 …
              --download bct_mb1 …
[   8.0822 ] BR_CID: 0x…
[   8.1053 ] Sending bct_br
[   8.1063 ] Sending mb1
[   8.1068 ] ERROR: might be timeout in USB write.
Error: Return value 3

Sending bct_br does not report an error; Sending mb1 does. The device then warm-resets (FC REC jumper is sampled only at cold power-on, so warm-reset path goes coldboot from QSPI). On UART we observe zero bootrom-side output during the entire RCM session — the only UART content captured is from the post-rejection QSPI coldboot fallback (MB1-and-onwards print; bootrom itself is silent).

The QSPI on this module has a working PKC-only-signed boot chain from a pre-SBK-fuse-burn flash (which coldboots fine), so the module is not bricked.

What we’ve verified before posting

Listing this so we don’t double-cover ground:

  1. HSM SBK bytes. sha256(HSM opaque) matches the ceremony-recorded anchor. Same 32 bytes are written to the file we hand to flash.sh’s --encrypt_key and were the literal bytes in the <fuse name="SecureBootKey" value="0x…" /> XML when we burned the fuse via odmfuse.sh -X.

  2. KDF chain spec. Walked bootloader/tegrasign_v3_oemkey_t234.yaml for 0x230. For MB1: SBK → KDF(label=“MB1B”, ctx=“”) → SBK_MB1_KDK, then SBK_MB1_KDK → KDF(label=DERSTR, ctx=VER) → SBK_MB1_DK, AES-GCM(SBK_MB1_DK, IV, AAD, payload).

  3. KDF message construction. Implemented per bootloader/tegrasign_v3_util.py:get_composed_msg: counter:4BE || label_b || 0x00 || (ctx_b if non-empty else 0x00) || L:4BE. Verified byte-for-byte against NVIDIA’s reference across 5 vectors.

  4. Hook invocation. Diagnostic prints from a recent attempt show our HSM hook called with the correct labels — e.g. for MB1:

    oem_hsm_kdf ENTRY: in_key='SBK' out_key='SBK_MB1_KDK_…' label='4d423142' ctx=''
    oem_hsm_kdf ENTRY: in_key='SBK_MB1_KDK_…' out_key='SBK_MB1_DK_…' label='a560ff402f4e6445b260091ed663f43e' ctx='01040100'
    oem_hsm_aes_gcm ENTRY: key_id='SBK_MB1_DK_…' plain_len=274928
    
  5. Self-consistency. Standalone Python that mirrors the chain end-to-end (using the captured kdf_args_*.yaml from the actual attempt) encrypts and then re-derives DK + AES-GCM-decrypts. Round-trip succeeds for both BR-BCT and MB1 → our crypto code is internally consistent.

  6. PKC path is healthy. Same HSM-backed PKC signing produced a PKC-only-signed boot chain that flashes and boots to userspace on the same module (pre-SBK fuse-burn). So PKC-RSA-PSS sig + oem-rsa updatesigheader flow is working.

  7. tegraopenssl BR-BCT note. tegraopenssl --oem_encrypt on BR-BCT appears to be a no-op stub in R36.5 (emits ERROR: 0 to stdout, exits 0, leaves the file unmodified). Confirmed via standalone repro on captured inputs. do_kdf_oem_enc post-processes via HSM hooks, so the artifact is still produced correctly via the HSM path — but flagging in case it’s relevant.

Similar problem:

This post: ERROR: might be timeout in USB write after Fuse burning

Same ERROR: might be timeout in USB write at Sending mb1, but the marked solution there is about using the correct --auth flag for the FIRST fuse burn on an unfused board (--auth NS, not --auth SBKPKC). That doesn’t apply to us — our SBK burn used --auth PKC correctly because PKC was already burned by then, per our incremental burn order.

Our setup also differs in three meaningful ways:

  • BSI: ours 0x1e9 (bit 9 clear, ODM keys not enforced); theirs 0x20b (bit 9 set, ODM Key Valid)
  • ODM K1/K2: unprovisioned for us (intentional, planned for a later phase); they burned OemK1
  • Production Mode: NOT yet enabled on our side; theirs was 0x1 (locked)
  • L4T: we’re on R36.5; they were on R35.4.1

So we may be hitting the same error message for a different root cause. Flagging in case the bit-9-clear / ODM-unprovisioned / file-key vs HSM-key path on R36.5 has its own quirks the linked thread didn’t surface.

Questions

  1. Byte-order during odmfuse.sh -X SBK burn. We pass the 32 SBK bytes as a 0x… hex string in <fuse name="SecureBootKey" value="…" />. Does burnfuses (via tegraflash.py --cmd burnfuses <xml>) burn those bytes in the same order the bootrom reads them for AES-key use, or is there a word-level / register-level swap? Since FUSE_KEYS_SBK_0_0..7 are PSC fuses (per Note 6 / page 8 of “Platform Security Controller Fuses”) and can’t be read back, we have no post-burn way to verify byte order.

  2. Bootrom-side rejection observability. Is there any way to get bootrom to emit a rejection reason on UART or some other channel on Orin Nano R36.5? (We have UART connected, FUSE_DEBUG_AUTHENTICATION_0 and FUSE_OPT_NVJTAG_PROTECTION_ENABLE_0 are NOT burned on this module — but bootrom still appears silent during the failed RCM session.) Even a single error code would localize this.

  3. Anything else worth checking? Given the chain spec + crypto are verified self-consistent, is there a structural field in BR-BCT or mb1 sigheader that bootrom enforces on SBKPKC-fused silicon that doesn’t get populated correctly by the default flash.sh --hsm flow when SBK is HSM-resident? (E.g., a PSC-specific field, or something in the BR-BCT customer info region.)

  4. R36.4.4/R36.5 HSM support — does it cover SBK encryption, or signing only? Two relevant pieces of official documentation:

    • R36.4.4 release notes, under Features: “Added support for using Hardware Security Module (HSM) to sign boot images.” R36.5 ships on top of 36.4.4, so this support should be present. But the wording “to sign” is precise — it suggests the PKC RSA signing path was the new HSM-validated capability, not the SBK AES-GCM encryption path.
    • R36.5 Package Manifest entry for bootloader/tegrasign_v3_hsm.py: “A TegraFlash component that can directly communicate with OEM’s HSM server.” — generic, doesn’t pin down scope.

    SBKPKC requires both: PKC signing (✓ working for us, validated PKC-only boot on the same module) AND SBK-driven KDF + AES-GCM encryption of boot blobs (✗ failing). Concrete asks:

    • Is the R36.4.4/R36.5 “HSM to sign boot images” capability strictly for the PKC signing step, or does it also cover the SBK-driven KDF chain + AES-GCM encryption of the boot blobs?
    • If it covers both: is there a NVIDIA-validated end-to-end SBKPKC boot test on Orin Nano R36.5 that exercises the HSM hook path (not just file keys)? Even a softhsm reference run we could diff against would help.
    • If it covers signing only: that’s our exact gap. The shipped tegrasign_v3_hsm.py is documented in its own header as a reference template inviting OEM replacement. Our YubiHSM PKCS#11 implementation matches NVIDIA’s get_composed_msg byte-for-byte (5 vectors) and encrypt→decrypt round-trips self-consistently for BR-BCT and MB1, but if there’s no NVIDIA-side end-to-end test of the SBK-encrypt-via-HSM path, our artifacts may be subtly incompatible in a way only the SBKPKC-fused bootrom catches.

Artifacts available privately

Happy to share via NVIDIA’s preferred private channel:

  • Full host flash log
  • Diag log showing the entire HSM-hook KDF chain walk (every label + context + derived-key-id for every artifact on the flash list)
  • Captured kdf_args_*.yaml outputs from tegraopenssl --oem_encrypt for BR-BCT, MB1, MB1-cold-boot-BCT, MB1-recovery-BCT, MB2, PSC_BL1
  • Module ECID + fuse map readback
  • Our tegrasign_v3_hsm.py (YubiHSM PKCS#11 implementation) for cross-checking against NVIDIA’s softhsm reference

Not posting publicly because it includes ECID and HSM-handle details.

Any pointers appreciated. We’re stuck after exhausting the on-our-side diagnostics and the bootrom silence makes further isolation hard.


Update (2026-06-10): authoritative fuse readback + sharpened diagnosis

Since posting, we ran three more tests on the same module. Two results materially change the framing of the original questions.

What we did

  1. Hybrid file-key test. Patched do_kdf_oem in the BSP to honor an env var that skips the HSM branch for SBK only (PKC signing still HSM-routed). This forced the SBK encryption side through NVIDIA’s stock file-key path (tegraopenssl --kdfoem) using the same 32-byte SBK that lives in our HSM. Result: same Sending mb1 → ERROR: might be timeout in USB write. Confirms our HSM hook is not the bug — both code paths produce equivalent rejected ciphertext.

  2. Per-4-byte-word swapped SBK test. Same flow, but we reversed every 4-byte word of the SBK before handing it to tegrasign. Result: same rejection, same 5ms timing. Rules out the most common byte-order transform.

  3. Literal zero-SBK test. Provided 32 bytes of zeros as the SBK file. Result: same rejection. Rules out “fuse SBK is still all zeros / burn never took.”

  4. PKC-only flash on the SBKPKC-fused module. No --encrypt_key, no SBK encryption applied to any artifact. Result: Sending bct_br → Sending mb1 → Sending psc_bl1 → Sending bct_mb1 → Boot Rom communication completed. The flow went all the way to MB2 Applet (BL: version 1.4.0.7-t234-…) and successfully read every fuse via readfuses.

What the fuse readback shows

BootSecurityInfo:    000001e9
PublicKeyHash:       de5adb342a828f4938a14fc271842bfda644c1713442696c00cdca7aa8d245493a48d145e2e16bf767c6c71f1abd588d5b6a700cc803a9f7d5e28858dbba45a4
PkcPubkeyHash1:      <all zeros>
PkcPubkeyHash2:      <all zeros>
SecurityMode:        00000000
ArmJtagDisable:      00000000
DebugAuthentication: 00000000
SwReserved:          00000000
OdmInfo:             00000000
ReservedOdm0..7:     <all zeros>
Sku:                 000000d5

BootSecurityInfo = 0x1e9 decodes per Orin Fuse Specification (DA-10877-001 v1.5), Table 1, page 7:

  • bit [0] = 1 → Secure Boot Authentication Scheme = 3072-bit RSA ✓
  • bit [3] = 1 → “secure boot encryption scheme (SBK) enable” ✓
  • bits [8:4] = 1 → “Reserved (may not be logic 0 by default)” — matches the spec note
  • bit [9] = 0 → ODM Key Valid — intentionally not provisioned

So BSI is correctly burned to the value we intended.

What this changes about the diagnosis

The key word in the spec is “enable”, not “enforce”. On our SBKPKC-fused unit, BSI[3]=1 means bootrom can decrypt SBK-encrypted artifacts, but it does not require them — plaintext PKC-signed artifacts boot just fine. The failure pathway is now precisely:

  • We hand bootrom an mb1 sigheader that flags the payload as SBK-encrypted.
  • Bootrom validates the PKC RSA-3072 signature → passes.
  • Bootrom derives the per-image AES-GCM key (SBK_MB1_DK) from the SBK in FUSE_KEYS_SBK_0_0..7 via the chain in tegrasign_v3_oemkey_t234.yaml.
  • Bootrom AES-GCM-decrypts the payload → tag verification fails → reject within ~5 ms.

The only way that tag-verification can fail with all of our other plumbing verified is: the SBK bytes the PSCROM is using do not match the SBK bytes we used at encrypt time. No byte order we’ve tried matches. The fuse SBK is non-zero (zero-SBK encrypt also rejects).

Two specific new questions (in addition to the original four)

Q5. Does PSCROM combine FUSE_KEYS_SBK with the per-chip HUK (or any other per-chip secret) before use as the AES-256 key for boot-image decryption?

This is the critical question for our OEM workflow. If FUSE_KEYS_SBK is used directly as a fleet-wide key (as we’ve assumed), then once we discover the byte transform that burnfuses applies, a single SBKPKC firmware works across every module that was burned the same way. If instead the effective key is KDF(SBK_fuse, HUK_chip, …), then every module has a unique effective SBK, and SBKPKC requires per-device firmware builds — fundamentally different operational model.

Q6. How does burnfuses choose between cleartext mode and encrypted-form mode for FUSE_KEYS_SBK?

The spec (Table 1, FUSE_KEYS_SBK_0_*, page 5) says:

“This key may be programmed in encrypted form, with decryption performed by PSCROM”

There are sibling fuses FUSE_KEYS_OEM_FUSE_IV_0 (“Initialization vector used as part of the OEM fused keys encryption”) and FUSE_KEYS_KDK0_0_0 (“Key Decryption Key, these keys can be programmed in encrypted form”). On 2026-05-14 we burned via odmfuse.sh -X <xml> with:

<genericfuse MagicId="0x45535546" version="1.0.0">
    <fuse name="SecureBootKey" size="32" value="0x<32 raw bytes hex>" />
</genericfuse>

— bare hex bytes, no IV / KDK fuse provisioning beforehand. If burnfuses interpreted that as encrypted-form input and PSCROM is now “decrypting” our plaintext bytes with a default/zero KDK to obtain the effective SBK, that would explain the consistent ~5 ms tag-verification failure across every byte permutation we’ve tried — because no permutation of the post-decryption garbage is what we encrypt with.

Concretely: is there an XML attribute (or separate odmfuse flag) that selects cleartext-mode SBK burn for the 3072-RSA + SBK-enable BSI configuration? Or is FUSE_KEYS_OEM_FUSE_IV_0 / FUSE_KEYS_KDK0_0_0 a required precursor we missed?

Updated verification matrix

Check Result
sha256(HSM SBK bytes) matches ceremony anchor
Chain spec walked against tegrasign_v3_oemkey_t234.yaml
_composed_kdf_msg byte-equals NVIDIA’s get_composed_msg
HSM hook invoked with correct labels per chain spec
BR-BCT encrypt → decrypt round-trip (offline)
MB1 encrypt → decrypt round-trip (offline)
BSI fuse readback = 0x1e9 (bit [0] + bit [3] set per intent)
PKC-only flash on the SBKPKC-fused module ✓ boots through MB2 Applet, full readfuses succeeds
File-key SBK encrypt (bypasses our HSM hook) ✗ rejected at Sending mb1
Per-4-byte-word swapped SBK encrypt ✗ rejected at Sending mb1, same 5 ms timing
Zero-SBK encrypt ✗ rejected at Sending mb1, same 5 ms timing
Real-HSM-SBK encrypt (original test) ✗ rejected at Sending mb1, same 5 ms timing
odmfuseread of FUSE_KEYS_SBK_0_* ✗ PSC fuse, unreadable by design

The four Sending mb1 → ERROR rejections all have ~5 ms host-side timing and bootrom is silent on UART throughout. Consistent with one specific check inside PSCROM (most likely the AES-GCM tag check on the first SBK-encrypted artifact).

Pragmatic question for OEM workflow

Given that the module boots cleanly under PKC-only, is it expected NVIDIA practice to ship pilot units in this “SBK fuse burned but not currently used for encryption” mode and add SBK-encrypted artifacts in a later firmware update, or is that an unsupported configuration? The behavior we’re observing (BSI[3] enables but does not enforce) suggests it’s a supported posture, but explicit confirmation would help us scope our deployment plan.

— 🤖 This is an automated AI response. I’m here to help, but please verify important details! —

Based on the provided context, I will attempt to address the questions and concerns raised.

The issue at hand is related to flashing a Jetson Orin Nano module with a Secure Boot Key (SBK) and Public Key Cryptography (PKC) enabled. The user is experiencing a timeout error during the RCM boot stage, specifically when sending the mb1 binary.

To address the questions:

  1. Byte-order during odmfuse.sh -X SBK burn: The context does not explicitly state the byte order used by odmfuse.sh for burning the SBK. However, it is mentioned that the SBK bytes are passed as a 0x hex string in the <fuse name="SecureBootKey" value="0x..."> XML element. Without further information, it is unclear whether the bytes are burned in the same order as they are read by the bootrom for AES-key use.

  2. Bootrom-side rejection observability: The context does not provide a clear answer on how to get the bootrom to emit a rejection reason on UART or another channel on Orin Nano R36.5. However, it is mentioned that the bootrom is silent during the failed RCM session, and the only output is from the post-rejection QSPI coldboot fallback.

  3. Anything else worth checking: The context suggests verifying the chain spec, crypto, and PKC path. Additionally, it is recommended to check the BSI fuse readback, which shows that the BootSecurityInfo is correctly burned to the value intended (0x1e9).

  4. R36.4.4/R36.5 HSM support: The context indicates that R36.4.4 and R36.5 support using a Hardware Security Module (HSM) to sign boot images. However, it is unclear whether this support also covers SBK-driven KDF + AES-GCM encryption of boot blobs.

  5. New questions:

    • Q5: The context does not provide a clear answer on whether PSCROM combines FUSE_KEYS_SBK with the per-chip HUK (or any other per-chip secret) before use as the AES-256 key for boot-image decryption.
    • Q6: The context does not provide information on how burnfuses chooses between cleartext mode and encrypted-form mode for FUSE_KEYS_SBK.

In summary, while some questions have been addressed, others remain unclear due to the lack of explicit information in the provided context. Further investigation and clarification from NVIDIA or additional documentation may be necessary to resolve the issues at hand.

I could not find clear support for some parts of the question in the provided Jetson Orin Nano documentation.

— We support team will also look into your issue to have further suggestions soon. please stay tuned. —

Thanks for the auto-response. The chain spec / crypto / PKC path verification was the premise of the post, not the question — the questions I most need a NVIDIA engineer’s input on are Q5 (does PSCROM combine FUSE_KEYS_SBK with HUK or any per-chip secret before use as the AES key?) and Q6 (cleartext-mode vs encrypted-form selection in burnfuses). Q5 in particular is critical for our OEM workflow — if FUSE_KEYS_SBK is fleet-wide, our SBKPKC firmware can be one build; if it’s per-chip, every device needs a unique build. Could a Jetson Linux engineer weigh in?

hello curious-turtle,

FYI, the boot image authentication by PKC and decryption by SBK (technically it’s keys derived from SBK) will only be performed when either OemKeyValid or SecurityMode is burned.

Thanks JerryChang — that’s exactly the gate I was missing. This explains all four symptoms cleanly:

  • ✓ PKC-only flash boots through MB2 Applet (PKC-only path is active by default).
  • ✗ SBK-encrypted flash rejects at Sending mb1 in ~5 ms (bootrom isn’t attempting SBK decryption at all, because neither OemKeyValid nor SecurityMode is burned — so the encrypted ciphertext is treated as if it should be plain code).
  • All byte permutations of the SBK fail identically (consistent — the fuse value is never consulted).

Before burning FUSE_BOOT_SECURITY_INFO_0 bit [9] on the canary unit, a couple of confirmations to make sure the burn is safe and sufficient on its own:

  1. OemKeyValid without provisioned OEM keys. Is it a valid intermediate state to set BSI[9] = 1 while leaving FUSE_KEYS_OEM_K1_0 and FUSE_KEYS_OEM_K2_0 at zero? In other words, does the MB1 / PSC-FW / SBK-derived-KDK boot chain consult those OEM key fuses at all, or are they purely a higher-layer feature (e.g., for OEM-defined Trusted Apps in OP-TEE) that I can provision later without disturbing the bootrom-level SBKPKC validation? Our tegrasign_v3_oemkey_t234.yaml-defined chain for MB1 derives SBK_MB1_KDK from SBK (label “MB1B”), then SBK_MB1_DK from there — no OEM K1/K2 reference at that level. Want to confirm bootrom agrees.

  2. OP-TEE / HUK interaction. Does setting OemKeyValid = 1 (with OEM K1/K2 still zero) change any OP-TEE behaviour at first boot — specifically the luks-srv TA / HUK-bound disk-encryption key derivation? Or is that path independent of the BSI[9] flag?

If the answers are “no impact on MB1 boot chain” and “no impact on OP-TEE LUKS path”, I can burn BSI[9] alone (single OR-burn, 0x1e9 | 0x200 = 0x3e9), retest, and report back. If either has a caveat, I’d want to understand it before committing the fuse.

Thanks again for the quick and decisive answer.

hello curious-turtle,

>> Q1
see-also Example Orin Fuse Configuration, you should add OEM_K1 keys instead of using all 0s.
there’re OEM_K1/K2 to derive a root key which is itself used to sign and encrypt the EKB.
– OEM_K1 is the root of trust of EKB, and it is used to derive the RPMB key too.
– OEM_K2 is to derive the PV encryption key. If you don’t need to encrypt CPUBL with a PV key, you don’t need to care about OEM_K2.
you may also have PscOdmStatic, we recommend burning it to 0x60, which sets the purpose of:
– OEM_K1 to encryption. (see-also OEM_K1_PURPOSE=0x0)
– OEM_K2 to KDK(key derive key) (see-also OEM_K2_PURPOSE=0x6)

>> Q2
following above, HUK depends on EKB_RK, which on Orin is rooted in OEM_K1/OEM_K2.

Thanks — the docs link plus the gen_ekb.py README (Linux_for_Tegra/source/nv-optee/optee/samples/hwkey-agent/host/tool/gen_ekb/README) closed the loop. The T234 EKB derivation chain is explicit:

OEM_K1 (fuse) ─AES-128-ECB(OEM_K1, FV)──▶ EKB_RK
                                            │ NIST-SP-800-108
                                            ▼
                                  EKB_EK + EKB_AK ─AES-CBC▶ encrypted EKB
                                                              ├─ kernel-enc key
                                                              ├─ disk-enc key  (sym2_t234.key)
                                                              ├─ UEFI var auth key
                                                              └─ ...
on device:
  OP-TEE decrypts EKB ▶ extracts disk_enc_key
  LUKS_key = NIST-SP-800-108(disk_enc_key, "luks-srv-ecid", ECID)   ─ per-device
  passphrase = NIST-SP-800-108(LUKS_key, disk_UUID)

The README’s “Deriving EBK_RK from fuse key (T234: OEM_K1)” makes it explicit that on T234, OEM_K1 alone is the documented input, which resolves my OEM_K2 question — I’ll leave OEM_K2 unburned (the jetson_user_key_pta SSK code paths that touch OEM_K2 appear to be defensive fallback, not the documented happy path).

One remaining confirmation on the migration story before I commit the burn:

A unit that has been flash-provisioned before OEM_K1 is burned has an EKB encrypted with EKB_RK = AES-ECB(zeros, FV) — i.e. a publicly-derivable EKB root, and therefore a publicly-derivable disk encryption key. After we burn OEM_K1 to a non-zero ODM-controlled value:

  • The new EKB_RK derives differently (AES-ECB(OEM_K1, FV)).
  • The pre-burn EKB on the QSPI is no longer the right input for the new chain (OP-TEE will try to derive EKB_RK from the new OEM_K1 and won’t get the same value, so the existing EKB ciphertext won’t decrypt correctly).
  • Existing LUKS partitions, which were keyed via the pre-burn EKB-disk-encryption-key, become inaccessible.

Therefore the only correct migration is to re-flash the unit with a freshly generated eks_t234.img (using the new OEM_K1 and a fresh sym2_t234.key, both from our HSM), letting OP-TEE provision fresh LUKS partitions at first boot. There is no in-place EKB-rewrap path that preserves existing user-data, correct?

Thanks again for the time on this thread — the bot triage layer notwithstanding, your two answers cleanly resolved a multi-week investigation.

hello curious-turtle,

your understanding is correct. see-also EKB: Encrypted Key Blob for more details.
besides.. you may see-also similar discussion thread, Topic 331866. we were verified with SBKPKC fused target of.. bootloader Secureboot + UEFI Secureboot (uefi-keys) + UEFI payload encryption (uefi-enc) + Disk Encryption (ROOTFS_ENC)

Thank you, JerryChang — this clarifies the chain completely. We’re provisioning OEM_K1 and burning BSI[9] now, then re-flashing with a fresh EKB. I’ll report back with the end-to-end result to confirm the fix and close the thread.

We hit a sequencing problem actually executing it, and want to confirm the correct recovery before burning irreversibly.

Our board’s current BootSecurityInfo = 0x1e9 (bit [0] PKC + bit [3] SBK-enable set; bit [9] OemKeyValid clear). PKC hash + SBK are burned; OEM_K1 is still zero. We now want to burn OemK1 + set BootSecurityInfo bit [9] (target 0x3e9) in one odmfuse.sh -X operation.

The problem: because bit [3] (SBK-enable) is already set, odmfuse.sh’s get_fuse_level classifies the board as SBKPKC and builds an SBK-encrypted mb1 for the fuse-burn applet (mb1_..._encrypt.bin.signed). The bootrom rejects it at Sending mb1 (tegrarcm_v2 ... Return value 3, USB write timeout) — consistent with your earlier point that SBK decryption is only performed once OemKeyValid or SecurityMode is burned. So we cannot boot the fuse-burn applet to set bit [9], because the applet is encrypted with a key the bootrom won’t use until bit [9] is set.

A PKC-only (unencrypted) applet still boots fine on this board — flash.sh --no-flash PKC-only readfuses works and the board boots its PKC-signed bootloader normally. So the silicon is healthy; the issue is purely that the fuse-burn applet is being SBK-encrypted.

Question: what’s the correct way to burn OemK1 + OemKeyValid from a board in this state (bit [3] set, bit [9] clear)? Specifically:

  1. Can odmfuse.sh be directed to send a PKC-only (unencrypted) applet for the fuse burn, given the bootrom still accepts PKC-only here?
  2. Or is FSKP (fskp_fuseburn.py) the right tool for this case?
  3. Or is there another supported recovery for a board that has SBK-enable set but OemKeyValid not yet burned?

We reached this state by burning bit [3] in a separate step before bit [9] (rather than all-at-once as in the SecureBoot.html example) — so guidance on the supported path out would be much appreciated.

firstly, is the SecurityMode burnt with a value of 0x1, if yes, all additional fuse write requests will be blocked.
secondly, you may refer to developer guide, Burn Fuses with the Fuse Configuration file as an example to have additional fuses burn.
please have fuse.xml file with additional fuses,
for instance, $ sudo ./odmfuse.sh -X <fuse_config> -i 0x23 -k PKC.key -S SBK.key <target_config>

<genericfuse MagicId="0x45535546" version="1.0.0">
    <fuse name="OemK1" size="32" value="0x1234....XXXX"/>
    <fuse name="BootSecurityInfo" size="4" value="0x3e9"/>
</genericfuse>

Hi JerryChang,

Thank you for the guidance throughout this thread — much appreciated.

Closing the loop in case it helps anyone hitting the same wall: we resolved it by not using SBK. For our use case the at-rest protection comes from the OEM_K1-rooted EKB → LUKS chain, so SBK boot-chain encryption wasn’t required. We reconfigured to:

  • PKC (BootSecurityInfo bit[0]) + OEM_K1 + OemKeyValid (bit[9]) → BootSecurityInfo = 0x3e1, with bit[3]/SBK never set, burned --auth PKC.

On a fresh module this burns cleanly, accepts a PKC-signed image, and boots through to a LUKS unlock rooted in OEM_K1 end-to-end — no SBKPKC step at all, which sidesteps the bit[3]-set / bit[9]=0 chicken-and-egg this thread was about. It lines up with the OEM_K1-only configuration you confirmed as supported in thread 314134.

Your reminder to verify FUSE_SECURITY_MODE_0 isn’t already set before further fuse writes was a useful checkpoint too — we’ve made that an explicit preflight and are leaving Production Mode for last.

Thanks again.