Understanding HAB keys: SRK, CSF and the fuses
In the last post I talked about the hardware. Before touching any actual tool, I wanted to properly understand the cryptography underneath it, because I've…
In the last post I talked about the hardware. Before touching any actual tool, I wanted to properly understand the cryptography underneath it, because I've learned the hard way in other projects that skipping this step and just "following the guide" leads to a point where something doesn't work and you have no idea why. So this post is only about the concepts. No commands yet — that's the next one.
NXP calls their mechanism HABv4, "High Assurance Boot." The name is a bit dry, but the idea is simple once you see the whole chain written out.
The chain, top to bottom
- The chip powers on. The very first code that runs lives in a boot ROM — it was burned into the silicon at the factory and cannot be changed by anyone, ever.
- That ROM code checks a small piece of one-time-programmable memory inside the chip. If a certain bit there is set, the device is "closed," and the ROM will refuse to run anything that isn't properly signed. If the bit is clear, the device is "open" and boots normally — but it still checks signatures and keeps a log of whether they were valid, it just doesn't refuse to boot on failure.
- If the device is closed, the ROM compares the signature on the first-stage bootloader against a key it trusts. Only if that matches does it hand off control. That first-stage code then does the same check on the next stage, and so on, all the way up.
Each stage only trusts the next stage if it's properly signed. That's the whole idea — a chain of custody from power-on switch to the moment your actual operating system takes over.
So where does the "open" device actually help?
This is the part I appreciated once I understood it properly. An "open" device still checks everything, and it still keeps a record of failures — you can ask it, at any point, "did anything fail a signature check just now?" But it boots anyway, even on failure. That makes it a genuinely safe place to learn: I can flash a completely wrong, unsigned, garbage image, and the board will still boot, and it will honestly tell me "yes, that failed the check" instead of pretending everything was fine. I get the real behavior of the security check, without any risk of bricking anything.
The one bit that actually closes the device is a separate, one-way action. Once that's set, unsigned code simply won't run, full stop, forever. I'm keeping that step for very last — after weeks of everything working cleanly — not because it's technically hard, but because there's no walking it back afterward.
Why there isn't just "one key"
My first assumption was: you generate one key pair, you sign things with the private half, done. That's not quite how it works here, and once I understood why, it made a lot of sense.
Picture a small family tree of keys:
CA
|
------------------------------
| | | |
SRK1 SRK2 SRK3 SRK4
| | | |
CSF+IMG CSF+IMG CSF+IMG CSF+IMG
- The CA is a "notary" key. Its only job, ever, is to certify the four SRK keys below it. It never signs an actual firmware image.
- The four SRK keys ("Super Root Keys") are the real masters. Only one of them is actually in active use at any time — I'm using the first one. The other three just sit there, unused, as a reserve. If the active key is ever compromised, there is exactly one way to recover: permanently burn a "revoke" bit for that key and switch to the next one. That's it, that's the entire key-rotation story for a device that's already been closed — which is exactly why you don't just generate one key.
- Underneath each SRK there are two more keys, with two different, very specific jobs. One key signs the instructions about what to check and how (which parts of the image, using which algorithm). The other key signs the actual bytes of the firmware image itself. Splitting these into two separate keys is a design choice from NXP, not something I invented — but it does mean the whole signing step later involves two distinct signatures over two distinct things, not just one blob getting one signature.
Only the fingerprint of the SRK table — a single 256-bit hash — is what eventually gets burned into the chip. Not the keys themselves. The actual public keys and certificates travel along inside every signed image; the chip just needs the hash to know it's looking at the right table.
What actually needs to stay secret
Out of this whole tree, only the private halves of these keys matter for secrecy. The public certificates are completely fine to hand out, embed in images, whatever — they're not the secret. The private keys are a different story though: if I ever lose them after the device is closed, I can never sign a new firmware for that device again, permanently. And if they ever leak, the entire point of secure boot on that device is gone, because anyone with the leaked key can sign whatever they want and the chip will trust it. So: keep them somewhere completely outside any source code repository, back them up properly, treat them like the actual crown jewels of the whole project. I'll go into exactly how I did that backup in a later post, because it deserves its own space.
Next post: the actual tool NXP provides for all of this, and what it was like using it for the very first time.