1. The boot chain, and where the counter comes in
At reset the core is secure and it fetches from a boot entry chosen by an option byte. BOOT_UBE lives in FLASH_OPTSR, bits 29:22, and takes the same 0xB4 / 0xC3 pair as everything else on this family: 0xC3 selects the ST immutable root of trust in system flash, 0xB4 selects an OEM root of trust at the address in SECBOOTADD.
Three options, and the choice is architectural rather than cosmetic:
ST-iRoT is ST's immutable root of trust, in system flash, which you cannot modify and therefore cannot get wrong. You configure it with a signed .obk file rather than writing code. The cost is that you inherit its constraints, and they are real: overwrite-only firmware update, no SWAP_BANK, and on SFSP 2.6.0 and earlier, an erratum stating that tampers are not usable with it, whose documented workaround is to switch to OEM-iRoT.
OEM-iRoT is your own root of trust in user flash, MCUboot-based in ST's reference projects. You own the code, the update policy, the flash layout and, if it matters to you, the certification of that code.
ST-iRoT plus OEM-uRoT puts an ST-immutable anchor in front of your own updatable second stage. It is the answer when you need a root of trust you can patch, which is increasingly what regulation expects.
RSS, the root secure services, sits underneath all of them: ST code in system flash, exposed through a function pointer table. Its RSSLIB_NSC_DataProvisioning entry is how you write option byte keys content that the stage doing the writing must not be able to read back afterwards. It is not the only path to the OBK area, which is also reachable through the FLASH SECOBKCFGR / NSOBKCFGR registers and the HAL_FLASHEx_OBK_* functions.
Whichever you choose, each stage verifies the next, then raises the hide protection level, then launches it.
2. HDPL, and why it is more than a permission bit
The level lives in SBS_HDPLSR.HDPL. You advance it by writing the key value 0x6A to SBS_HDPLCR.INCR_HDPL. There is no decrement, in the register set or in the HAL. It returns to its initial value at reset and at no other moment.
The values themselves are 0xB4, 0x51, 0x8A, 0x6F for levels 0 to 3. Non-sequential, high Hamming distance, same design instinct as TZEN. You do not compare them numerically.
In ST's reference flow the immutable root of trust runs at HDPL1, the secure application at HDPL2, and the final application at HDPL3, with the level raised by the stage that is about to hand over.
So far this is just a counter. What makes it a security mechanism is what it is wired to.
The DHUK, the derived hardware unique key, is a 256-bit key that the hardware derives from a root key and delivers to the SAES peripheral over a private bus. Software never sees it. And the current hide protection level is an input to that derivation.
The consequence is worth stating precisely, because it is the whole point of the design: a stage running at HDPL3 that asks SAES for "the DHUK" gets a different key than the HDPL1 stage got. Not a refused request. A different key. Data that the root of trust sealed at level 1 is not merely off-limits to the application, it is cryptographically meaningless to it.
No software gatekeeper is involved, so there is no gatekeeper to bypass.
A practical trap that follows from this and that costs people days: the derivation also depends on the security state, not only the level. Provisioning keys from code running with TrustZone disabled produces content that your secure boot stage cannot decrypt later. ST's support forum has this question repeatedly.
The same idea governs the HDP flash areas from Part 2. The boot stage reads its secrets from an area inside the HDP window, then raises the level, and that window becomes inaccessible until the next reset. The keys were in flash, they were read, and now nothing running can reach them.
3. OBK, the key store that is partitioned by level
The option byte keys area is a dedicated flash region outside the main array, aliased at 0x0FFD0000 secure and 0x0BFD0000 non-secure, implemented as two 8 KB sectors, current and alternate, so that a key update can be made robust. With TrustZone enabled, everything up to the first 3 KB of the HDPL3 partition is secure-only; the last 2032 bytes are the non-secure partition, reached through FLASH_NSOBKKEYR / NSOBKCFGR and the 0x0BFD0000 alias.
It is partitioned by hide protection level:
| Partition | Offsets | Typical owner |
|---|---|---|
OBK_HDPL0 |
0x000 to 0x0FF |
ST |
OBK_HDPL1 |
0x100 to 0x8FF |
immutable root of trust, debug authentication data |
OBK_HDPL2 |
0x900 to 0xBFF |
secure application |
OBK_HDPL3 |
0xC00 to 0x1FEF |
application, split 3 KB secure and 2032 bytes non-secure |
The mechanism that makes this useful is SBS_NEXTHDPLCR.NEXTHDPL, an offset of 0 to 3 applied when accessing OBK. A stage sets it and provisions secrets for a later stage without ever being able to read them back afterwards. That is how a factory provisioning step installs a key that only the application will ever use.
On the tooling: .obk files are produced by STM32 Trusted Package Creator from an XML description and programmed with STM32CubeProgrammer using -sdp. On parts with crypto, the debug-authentication OBK is stored encrypted with the DHUK; on H563 and H562, which have no crypto, it is stored in clear, which is why provisioning procedures for the two are not interchangeable.
4. Debug authentication
Debug authentication is how a closed device is opened again, and it implements Arm's PSA ADAC specification over DAP0 and the DBGMCU.
Two methods, and the choice is forced by your TZEN setting rather than by preference:
- Password, available only when TrustZone is disabled. The device compares a hash. It grants exactly one thing: full regression.
- Certificate, available only when TrustZone is enabled. ECDSA P-256 with SHA-256, a challenge and response proving the host holds the private key, and a certificate chain from a root you control.
The certificate method carries a 128-bit permission mask, so you can issue a certificate that reopens non-secure debug at HDPL3 for a field engineer without granting secure debug or regression. Certificates can also be bound to a SoC class or a specific SoC identifier.
That last point has an erratum attached that matters if your security model depends on it: on H562 and H563 running SFSP 2.6.0 or earlier, the SoC identifier is not available through DA discovery, and ST's workaround is to configure regression and debug opening without SoC ID filtering. If you planned per-device certificate binding, verify it on your exact part and firmware version before you design a process around it.
Regression comes in two forms. Full regression erases user flash, OBK, SRAM and backup RAM, and returns the device toward OPEN. Partial regression erases only the non-secure flash, the HDPL3 non-secure OBK and the backup RAM. There is an erratum on partial regression with TrustZone enabled, scoped to SFSP 2.4.0, where it can leave an incorrect device configuration, and ST's workaround is blunt: do not use partial regression, use full regression.
5. The product state, one more time, as a lifecycle
Part 2 listed the values. Here is what they mean as a process, because the transitions are what bite.
OPEN is the only forgiving state. Flash can be erased without a regression, debug is unrestricted, everything is reversible. Stay here for all of development.
PROVISIONING is where the OBK files are written. IROT_PROVISIONED marks a root of trust in place. TZ_CLOSED closes the secure world while leaving non-secure debug available at HDPL3, which is a genuinely useful production state for a device that still needs field diagnostics.
CLOSED refuses a debug connection outright. LOCKED removes debug authentication itself, so there is no reopening and no regression, ever.
The failure mode to internalise: CLOSED with no debug-authentication keys provisioned is functionally identical to LOCKED. ST's answer to engineers who have done this is that the device is unrecoverable and that this is the security feature working correctly. They are right, and it is still a bad afternoon.
Two errata belong in your checklist before any transition off OPEN:
- Product state change is not supported on early samples, which lock permanently if moved. The erratum identifies them by the secure native services identifier reading
0xA7CA2047or0xFFFFFFFF, not by date code. - Regression is impossible if the flash high-cycle data area is enabled. Disable it before leaving
OPEN, or you have silently removed your own recovery path.
6. Firmware update
ST's OEM-iRoT and OEM-uRoT are MCUboot, with the crypto offloaded to the PKA, SAES, HASH and RNG blocks. The default layout is two images, secure and non-secure, each with a primary and a secondary slot.
The install strategy is a compile-time switch, MCUBOOT_OVERWRITE_ONLY. Defined, the secondary slot is copied over the primary and there is no way back. Undefined, you get swap mode, which uses a 64 KB scratch area and can roll back a bad image.
ST-iRoT is overwrite-only. If you need rollback, that decides your root of trust for you.
On the question everyone asks, whether the update is atomic: no, and it does not need to be. MCUboot's swap is restartable, not instantaneous. The state lives in the image trailer, and a bootloader interrupted by a power cut replays the swap from where it stopped on the next boot. The distinction matters when you are writing a test plan, because "atomic" would let you skip the interrupted-update cases and "restartable" does not.
SWAP_BANK is a different thing entirely and the names invite confusion. It is the H5 option byte that exchanges the mapping of bank 1 and bank 2, a genuinely atomic flip. It is not supported by ST-iRoT, the OEM-iRoT and OEM-uRoT provisioning scripts explicitly force it to 0, and ST's own position is that dual-bank update is unusual in a secure boot context.
If you want none of this, STM32Trust TEE Secure Manager is ST's pre-built secure world: a signed binary implementing PSA Crypto, Internal Trusted Storage and Initial Attestation, PSA Certified Level 3 on the H573. You develop only the non-secure application. The trade is that you do not get the secure source and the flash layout is fixed until you regress the device and reinstall.
7. What to check before you close a device
Not a summary, a checklist, because every item below has cost somebody a batch of boards:
- Debug-authentication keys provisioned and tested by actually reopening a device, not just written.
- The certificate chain backed up somewhere that is not the laptop of the engineer who made it.
- SoC identifiers recorded, if your process needs them, and verified as readable on your part number.
- Flash high-cycle data disabled.
- Silicon date code checked against the early-sample erratum.
- A regression rehearsed end to end on a sacrificial board.
- Tampers verified with your chosen root of trust and firmware version, given the ST-iRoT erratum on SFSP 2.6.0 and earlier.
- Your binary checked for the byte sequence
0x00000000FFFFFFFF00000000FFFFFFFF, which ST-iRoT on SFSP 2.6.0 and earlier cannot install, and for which there is no fix beyond controlling the binary.
The last one is the flavour of this whole exercise. The architecture in Part 1 is elegant and the configuration in Part 2 is systematic, but shipping a secure STM32H5 is mostly about knowing which irreversible step you are one command away from.
Going further
Our one-day course ARM TrustZone for Cortex-M based devices (SEC7) covers this on a Cortex-M33 board: Armv8-M security extension, SAU and IDAU configuration, Cortex-M33 MPU and PMSA, exceptions across the boundary, security access faults, secure software design. STM32H5 (STR12), three days, takes it to the silicon: secure and non-secure images, NSC veneers, GTZC isolation patterns, TF-M and STM32Trust Secure Manager, provisioning and dual-bank update. Embedded Security for STM32-based devices (SEC5) covers the boot chain, key storage and debug authentication.
Sessions run online in both European and US time zones. See the course pages for the next dates, or request a session on your own dates, online or on-site.
SEC7 · STR12 · SEC5 · STR19 · STR13
References
- ST - AN6007, Getting started with STiRoT for STM32H5 MCUs
- ST - AN6008, Getting started with debug authentication for STM32 MCUs
- ST - ES0565, STM32H562xx/563xx/573xx device errata - read sections 2.2.8, 2.2.10, 2.2.19, 2.2.30, 2.2.37 to 2.2.40 before closing anything
- ST - UM3254, Secure Manager for STM32H573xx
- ST - UM2238, STM32 Trusted Package Creator
- ST - STM32CubeH5,
Projects/STM32H573I-DK/ROT_Provisioning - Trusted Firmware-M - secure boot design documentation