UNIT 15 · LESSON 4 OF 6

Secure Boot and the Root of Trust

Where does the chain of “who checks whom” have to end for any of it to mean something?

INTERACTIVEA chain of trust is as strong as its anchor
Boot ROM, bootloader and application linked by verification stepsboot ROMimmutablebootloaderflashapplicationflashCRC onlysignatureROTPK hash: in OTP / ROMAttacker’s code runsThe ROM checks the first stage only with a CRC, as the RP2040’s ROM checks boot2.Modify the bootloader, fix the CRC, and every later check is yours to skip.
Boot ROM, bootloader and application linked by verification stepsboot ROMimmutablebootloaderflashapplicationflashCRC onlysignatureROTPK hash: in OTP / ROMAttacker’s code runsThe ROM checks the first stage only with a CRC, asthe RP2040’s ROM checks boot2. Modify thebootloader, fix the CRC, and every later check isyours to skip.

Try this

Weak link
Attacker can
Chain bypassed.

Secure boot builds a chain: immutable code verifies the next stage against a root-of-trust public key (ROTPK) that cannot be changed, and each stage verifies the next before running it. TF-M’s documentation puts it plainly: the first-stage bootloader and the ROTPK must be stored immutably, in ROM or write-protected flash and OTP, or the chain can be bypassed. Pick a weak link and an attacker.

What you will be able to do
  • Describe a chain of trust and identify the immutable components it rests on.
  • Explain why each weak link (unverified first stage, writable key, CRC-only ROM check, open debug port) lets an attacker with flash access bypass the chain.
  • Explain how a root-of-trust key is stored as a hash in OTP and verified against the key carried in an image, and how spare slots allow revocation.
  • State what secure boot guarantees and list threats it does not address.
  • Assess whether a given chip can anchor secure boot in hardware.
Before you start
  • Signatures and what they prove (lesson 2).
  • Boot ROMs and the RP2040 boot sequence (unit 5, lesson 2).
Steps in this lesson
  1. A chain of trust
  2. Making the anchor immutable
  3. Keys by their hash
  4. What secure boot does not do
  5. Worked example: a root of trust in OTP
  6. Common misconceptions

The puzzle

Lesson 2 put a signature check in the bootloader. But the bootloader lives in flash too, and so does the public key it checks against. Someone who can rewrite flash can install a bootloader that checks nothing, or keep your bootloader and swap in their own key. Where does the chain of “who checks whom” have to end for any of it to mean something?

STEP 1

A chain of trust

Secure boot makes every stage verify the next before running it: the boot ROM verifies the bootloader, the bootloader verifies the application. TF-M’s documentation defines the anchor: the root of trust is an immutable first-stage bootloader plus a root-of-trust public key (ROTPK), and it is “mandatory” that both are stored immutably, the code in ROM or write-protected flash, the key for example in one-time-programmable (OTP) memory. Written as an induction, stage k+1k+1 is trusted only if stage kk is and kk checked it:

trusted(s0),\text{trusted}(s_0), trusted(sk)∧Verify(pkk,sk+1)⇒trusted(sk+1)\text{trusted}(s_k) \wedge \mathrm{Verify}(pk_k, s_{k+1}) \Rightarrow \text{trusted}(s_{k+1})

The base case cannot be proved by software. It holds only because nobody can change s0s_0 or the key it uses.

↑ This step uses the figure at the top of the page.

Each weak link breaks the induction for someone who can write flash, with a programmer, through the debug port or through a bug in the running firmware. An update channel that only ever delivers images to the bootloader is a narrower door: those images are still checked. That is why a signature-checking bootloader on a chip without a hardware anchor still has value against remote attackers, and none against someone holding a flash programmer.

STEP 2

Making the anchor immutable

  • ROM. Mask ROM code cannot be changed after manufacture; neither can its bugs, so ROM verifiers are kept small.
  • OTP and fuses. Bits that can be programmed once and never cleared, used for key hashes and for the switch that turns enforcement on.
  • Write-protected flash. Acceptable only if the protection itself cannot be removed by software; a protection bit the application can clear is not immutable.

Check what your chip actually has. The pico-sdk says of the RP2040 that “all instances of RP2040 silicon are identical and have no persistent state”: there is no OTP to hold a key, and its ROM checks boot2 only with a CRC (unit 5, lesson 2). It cannot anchor secure boot in hardware. The RP2350 adds OTP with a SECURE_BOOT_ENABLE flag that makes its boot ROM enforce signatures.

STEP 3

Keys by their hash

OTP is small and expensive, so chips store a hash of each root key instead of the key. The image carries its full public key; the boot code hashes it, compares the result with the stored hash, and only then uses the key to check the signature:

SHA256(pkimage)=hOTPandVerify(pkimage,image,σ)\mathrm{SHA256}(pk_{\text{image}}) = h_{\text{OTP}} \quad\text{and}\quad \mathrm{Verify}(pk_{\text{image}}, \text{image}, \sigma)

MCUboot does the same with MCUBOOT_HW_KEY. The RP2350’s OTP has room for four 256-bit key hashes, each usable only when its KEY_VALID bit is set and its KEY_INVALID bit clear.

INTERACTIVETrusting a key by its hash
The hash of an image key compared with four OTP key slotsSHA-256 of the public key carried in the image2e910931e6d2e05aa604a1f281273977…slot 034b38b3773abb257611be5940dea6322…KEY_VALIDslot 12e910931e6d2e05aa604a1f281273977…KEY_VALIDslot 2—KEY_INVALIDslot 3—KEY_INVALIDbootsSHA-256 of the image’s public key matches slot 1; the signature then verifies withthat key, so the image boots.
The hash of an image key compared with four OTP key slotsSHA-256 of the public key carried in the image2e910931e6d2e05aa604…slot 034b38b3773abb257611b…KEY_VALIDslot 12e910931e6d2e05aa604…KEY_VALIDslot 2—KEY_INVALIDslot 3—KEY_INVALIDbootsSHA-256 of the image’s public key matches slot 1;the signature then verifies with that key, so theimage boots.
Image signed with
Slot 0
Slot 1
Image boots.

OTP is small, so chips store a hash of each root public key rather than the key itself. The image carries the full public key; the boot ROM hashes it, looks for a valid slot with the same hash, and only then checks the signature with it. The RP2350’s OTP holds four 256-bit SHA-256 boot-key hashes, each enabled by a KEY_VALID bit and permanently revoked by a KEY_INVALID bit. Key bytes here are illustrative.

Several slots make revocation possible. Provision two keys; sign releases with key 0; if key 0 leaks, set its KEY_INVALID bit, which cannot be undone, and sign with key 1 from then on. Mark unused slots invalid at manufacture, as the OTP documentation recommends, so nobody can add a key of their own later. And install a valid key before turning enforcement on: the same documentation warns that enabling secure boot without one renders the device unbootable.

STEP 4

What secure boot does not do

Secure boot guarantees that, at boot, only code signed with a trusted private key runs, provided the anchor is immutable, the private keys are secret and the verification code is correct. It does not:

  • fix bugs in signed code: an exploitable bug in the application is exploitable after a secure boot;
  • stop an old, validly signed release from being installed (anti-rollback, lessons 3 and 6);
  • keep the firmware secret (encryption, lesson 2);
  • prevent denial of service: someone who can erase flash can stop the device booting;
  • defeat physical attacks on the check itself, such as glitching the supply or clock to skip an instruction. Mitigations exist (MCUboot tests its fault-injection hardening by skipping instructions under a debugger; the RP2350 has glitch detectors), but they raise the cost rather than make it impossible.

Shortcuts weaken it too. MCUboot’s option to validate the primary slot only once and cache the result, for slow processors, is documented as “reducing the security level”: flash modified after the first check is not checked again.

A related idea, measured boot, records a hash of each image the bootloader starts (MCUboot can pass these records to the application) so a server can later ask the device, through an attestation service, what it booted.

STEP 5

Worked example: a root of trust in OTP

The RP2350’s boot-key hashes occupy OTP rows 0x80 to 0xBF: four keys × 16 rows × 16 bits = 1024 bits, 256 per key. The keys are elliptic-curve public keys on the secp256k1 curve; uncompressed, one is two 256-bit coordinates, 512 bits. Storing hashes halves the space:

4×5124×256=2\frac{4 \times 512}{4 \times 256} = 2

For an RSA key with a 3072-bit modulus the saving would be about 3072 / 256 = 12 times. The cost is one extra hash at boot and a copy of the public key in every signed image.

A provisioning plan: program the hashes of key 0 and key 1, verify them by reading back (an uncorrectable ECC error in a valid key slot would make the device unbootable), set KEY_VALID for slots 0 and 1 and KEY_INVALID for slots 2 and 3, and only then set SECURE_BOOT_ENABLE. Every step is permanent, so it is scripted and tested on sacrificial parts first.

MYTHS AND FACTS

Common misconceptions

Our bootloader checks signatures, so we have secure boot

Only if nothing can change the bootloader or its key; otherwise the check can be removed.

Secure boot makes the firmware secure

It controls what starts; bugs in what starts are untouched.

Storing the key hash is weaker than storing the key

Finding a different key with the same SHA-256 hash is not practically possible; the hash identifies the key.

Any microcontroller can do secure boot in software

Without immutable code and key storage, software can raise the bar against remote attackers, not anchor trust.

Check yourself

Answer in your head, then open the card.

An RP2040 product uses a bootloader that verifies ECDSA signatures on the application. What can an attacker with physical access to the flash chip do, and what can a remote attacker who can only send update images do?

With the flash chip they can replace the bootloader (fixing the boot2 CRC if they touch boot2), so the signature check is gone. A remote attacker’s images still pass through the bootloader’s check and are rejected unless validly signed.

Why does the ROTPK have to be immutable, not merely secret?

It is a public key, so it needs no secrecy; but whoever can replace it can install their own key and sign their own images with the matching private key.

A vendor’s signing key 0 is stolen. Their devices have key 1’s hash provisioned as valid too. What should they do?

Release firmware signed with key 1, and have that firmware program the KEY_INVALID bit for slot 0 so images signed with the stolen key are refused from then on. The revocation is permanent. It works only if the BOOT_FLAGS1 OTP page was left unlocked at production, so plan the page locks accordingly.

Name two threats a correctly implemented secure boot does not, by itself, protect against.

Any two of: exploitable bugs in signed firmware, installing an older signed release without anti-rollback, reading the firmware, erasing flash to stop the device, physical fault injection during the check.

Sources (6)
  1. Trusted Firmware-M v2.1.0, docs/design_docs/booting/tfm_secure_boot.rst — “a trust chain where each step in the execution chain authenticates the next step before execution … The Root of Trust is a combination of an immutable bootloader and a public key (ROTPK)”; “the bootloader code must be stored and executed from ROM or such part of flash memory which supports write protection. ROTPK can be stored in a one-time-programmable (OTP) memory … If immutability of root of trust … is not ensured then there is a risk that the secure boot process could be bypassed”; default keys “exclusively for testing”
  2. Trusted Firmware-M v2.1.0, docs/design_docs/booting/secure_boot_hw_key_integration.rst — “HW key(s) might stored in OTP memory which is an expensive resource … only the hash of the ROTPK will be stored in the HW”; the image carries the full key; the bootloader hashes it and compares with the hash retrieved from the platform before using it
  3. Raspberry Pi Ltd, pico-sdk 2.0.0, src/rp2350/hardware_regs/include/hardware/regs/otp_data.h — CRIT1.SECURE_BOOT_ENABLE: “Enable boot signature enforcement, and permanently disable the RISC-V cores”; BOOTKEY0_0 … BOOTKEY3_15 (rows 0x80–0xBF): SHA-256 hashes of four boot keys, 16 bits per row; BOOT_FLAGS1.KEY_VALID: “The bootrom will check signatures against all valid boot keys”, valid “only when KEY_VALID is set and KEY_INVALID is clear”, “Do not enable secure boot without first installing a valid key. This will render your device unbootable”; KEY_INVALID: mark unused slots “so that spurious keys can not be installed at a later time”
  4. MCUboot v2.1.0, docs/design.md (“Using hardware keys for verification”, “Integrity check”, “Measured boot”, “Testing Fault Injection Hardening”) — MCUBOOT_HW_KEY: the image carries the full public key and “MCUboot calculates the hash of the public key from the TLV area and compares it with the key-hash that was retrieved from the device”; MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE “is reducing the security level”; measured boot records the image hash for attestation; CI tests fault-injection hardening by skipping instructions
  5. Raspberry Pi Ltd, pico-sdk 1.5.1, pico_unique_id/include/pico/unique_id.h — “RP2040 does not have an on-board unique identifier (all instances of RP2040 silicon are identical and have no persistent state)”
  6. Raspberry Pi Ltd, pico-bootrom-rp2040, bootrom/bootrom_main.c — _flash_boot(): flash_read_data(BOOT2_FLASH_OFFS, boot2_load, BOOT2_SIZE_BYTES) with BOOT2_SIZE_BYTES 256, then crc32_small(boot2_load, BOOT2_SIZE_BYTES - 4, 0xffffffff) compared with the last word before entering boot2; otherwise the ROM falls through to _usb_boot(): the only check is a CRC