Secure Boot vs. Firmware Signing vs. Code Signing: The Differences Explained
Three controls, three places in your system, three different questions. Code signing proves your pipeline, firmware signing proves your update, secure boot enforces on the device. What each contributes, and why you need all three.
The three terms get used interchangeably in roadmaps and vendor decks, and the confusion is expensive: teams buy signing infrastructure and call it secure boot, or enable secure boot and call their update mechanism safe. They are three different controls, at three different places in your system, answering three different questions. This note separates them, and shows what each one genuinely contributes to a product.
Code signing: proof about your pipeline
Code signing happens at build time, on your infrastructure. The build server or a dedicated signing service hashes an artifact, a binary, a container image, a package, and produces a signature with a private key that lives in an HSM or a signing service. The claim the signature makes: this artifact came from this pipeline, unmodified.
That claim is real and valuable. It is also entirely server-side. A signature in your release system says nothing about what any device in the field does when it receives the artifact. Code signing is a necessary input to product security, and on its own, it protects exactly nothing on the device.
Firmware signing: proof about your update
Firmware signing is code signing applied to the update path. The release process signs the OTA package: image, manifest, version metadata. When a device downloads an update, it can verify the package against a public key before writing it to flash. The claim: this update is authentic and complete.
Two properties separate firmware signing from a generic signing step. First, the verification runs on the device, in the updater, so the updater is now part of your trust boundary and needs the same scrutiny as the boot chain. Second, the package typically carries more than an image: version, target hardware, dependencies. Signing all of it prevents an attacker from mixing honest components into a dishonest whole, downgrading the version field while keeping the image, for example. And even that does not prevent rollback by itself, as we cover in Firmware Anti-Rollback: an old, fully valid, fully signed package is exactly as authentic as the new one.
Secure boot: enforcement on the device
Secure boot is the only one of the three that is enforced locally at every start. The boot ROM verifies each stage against a key anchored in silicon, on every boot, offline, whether or not an update ever arrived. The claim: this device refuses to execute software the manufacturer did not sign.
That is a much stronger property than signing alone, and a much narrower one than teams assume. Secure boot only knows about the artifacts in the verified chain. Configuration, device trees, writable root filesystems and co-processor firmware fall outside it unless the chain explicitly covers them (see Secure Boot: What Signature Verification Protects).
Who verifies what, and where the keys live
The three controls imply three key estates, and they age differently:
- Build signing keys protect pipeline integrity. Compromise means attackers can sign their own artifacts as yours. Rotation is a release-process event, painful but contained.
- Release/firmware signing keys protect updates. Compromise means attackers can push "updates" to the fleet. Rotation requires a story for devices that only trust the old key, this is where key rotation becomes product architecture.
- The device root of trust (the public key hash in OTP/eFuse) protects the boot chain. It is deliberately hard to change, which means the key it points to must be rotatable through a verified chain-of-custody design, or your root becomes a single point of permanent failure.
Why you need all three
Each control fails differently, and they cover each other's failure modes. A signed update (firmware signing) limits what an attacker can inject over the network, but a compromised updater could still write flash directly; secure boot catches the result at next boot. Secure boot refuses unsigned code, but if your build pipeline is uncontrolled, "unsigned attacker code" never happens: the attacker ships inside your signatures. Code signing disciplines the pipeline, firmware signing disciplines the channel, secure boot disciplines the device.
When we assess a product, we reconstruct which of the three actually exist, not which appear in the security concept. A surprisingly common result: two of three, with the gap exactly at the layer nobody demoed. The question is never "do you sign your firmware?" It is: what verifies it, where, and what happens when that verification fails?