When signing your update isn't enough: encrypting firmware updates

Part of a series: the three practices the CRA quietly expects, secure boot is not one feature, it's a chain and what "signed update" really means came before this one.
Who can read your firmware update? The last post was about what a signature on an update decides: whether a device accepts it. It does not decide who can read it. A signed update is still a readable file, and it travels through many hands before it reaches a device: the update server, a CDN, a vendor portal, a service technician's laptop, a USB stick in a maintenance van.
What an unencrypted update gives away
An unencrypted update is your product's software, handed to anyone who can download the file. That exposes two things.
The first is your intellectual property. The image contains your control algorithms, your calibration data, your protocol implementations: the code that makes your product different from a competitor's.
The second is a map to your security bugs. Anyone can compare two releases and see exactly what changed. When a release fixes a security bug, the difference between the old image and the new one points straight at that bug, and many devices in the field still run the old version.
Encrypting the update is the obvious answer, and it helps. But encryption does not remove the problem. It moves it: the thing to protect is no longer the image but the key that decrypts it. From here on, the questions are: who can read the plaintext along the way, and what does one leaked key expose?
Two ways to encrypt an update
There are two common designs, and they differ in who holds the secret.
A shared product key
One key for the whole product line. Your build encrypts each image with a fresh data key, and that data key is wrapped under the product key, which is kept in an HSM. The wrapped data key travels in the update manifest. Your factory station receives the product key once, wrapped for that station only, and writes it into every unit's secure element, which unwraps the data key on the device. The product key can be a symmetric key, as in the Raspberry Pi reference design (AES-128 in an ATECC608), or a key pair whose private half every unit holds; some manufacturers write an EC private key into each unit at the factory. The scheme is the same either way.
A key per device
Each unit generates its own key pair inside its TEE or secure element at the end of your production line and gets a certificate for the public half. The private half never leaves the unit. When you build a release, RAUC encrypts the bundle with a random key of its own and delivers that key to each device on your list, encrypted to that device's public key. The release side holds only certificates. Encrypted RAUC updates with per-device keys walks through this design, with the device keys in OP-TEE.
In both designs the image is encrypted once. What grows with the number of devices with a key per device is the list of encrypted keys in the bundle, not the image.
Where the plaintext exists
Take one release and follow it from the build to the device. At each station, ask two things: is the image readable here, and is there a key here that opens releases?
Station | Image readable here? | Key that opens releases, with a shared product key | Key that opens releases, with a key per device |
|---|---|---|---|
Release side (build and signing) | Yes | Yes, the product key, in the HSM | No, only public keys |
Update server, CDN, USB stick | No | No | No |
Factory station | No | Yes, the product key it writes into units | No |
Device | Only while installing | Yes, the product key, in its secure element | Yes, its own private key, in its TEE or secure element |
In both designs the image is readable in two places: on the release side, where it is built and encrypted, and on the device while it installs. Everything in between carries ciphertext, so the network is not where the risk is. The designs differ in where a key exists. A shared product key exists in the HSM and in every device, and passes through the factory station on the way; a good station keeps it only while provisioning. A key per device exists in one place: the device that made it. Who may reach the release side is an access-control question, and we come back to it at the end. The device comes first: where does it keep its key?
Where the key lives on the device
Suppose an attacker gets root on one of your devices. What they walk away with depends on where that device keeps its key, whether that is the shared product key or its own private key.
Plain flash | TEE or secure element | |
|---|---|---|
Where the key is used | In the updater, in Linux | In the secure world or inside the chip: it unwraps the key for this release, then Linux decrypts the image |
What root on one unit gets | The key itself, copied in seconds | Use of the key, only while the unit stays compromised |
What extracting the key takes | Reading the flash | A flaw in the secure world or in the boot chain that loads it; for a secure element, a physical attack on the chip |
An attacker with root on a unit can always read whatever that unit can install. No design changes that. What the design decides is whether the attacker leaves with a copy of the key, or has to keep that compromised unit running every time they want to read a release.
That is the real effect of encryption. It does not make your releases unreadable to a determined attacker. It changes the price. With the key in plain flash, the price is one rooted unit, once. With the key in a TEE or a secure element, the attacker has to keep that rooted unit running and receiving your updates, and, as the next section shows, that can be a unit you cut off. One caveat: a key in a TEE is only as safe as the secure boot chain that loads the secure world.
What one leaked key exposes
With a shared product key the secret is the same in every unit. One copy, taken from one unit, reads every release you publish for the product line from then on, and every old release still on your update server. Replacing it means reprovisioning devices in the field, and usually waits for the next hardware revision. On a board with a proper secure element, where extracting the key needs a physical attack, this is still a reasonable trade-off, and it is the simpler design to run: one key, one encryption per release, no bookkeeping.
With a key per device, a key opens one device. Example: you ship 2,000 chargers to one operator. You build the next release for those 2,000 serial numbers, and it is unreadable to any other unit, including a lost, returned or retired one you left off the list. What it does not do: a unit an attacker has already rooted keeps reading releases until you notice and drop it.
What a key per device costs you, in practice:
At the factory: one more step at end of line. Each unit creates its encryption key and gets a certificate for it from your CA, the same way it gets its identity certificate.
In the build pipeline: a release is no longer one file for everyone. It is built for a list of devices, and the list comes from your device registry. If the registry is wrong, a device does not get its update.
In the updater: each recipient adds a little to the bundle, and the updater has a limit on how many recipients one bundle can carry. A large fleet is served in batches, or the limit is raised in the device's configuration.
There is a middle ground: one key pair per group of devices, for example per customer or per region, instead of per unit. One leak then exposes one group's releases, not the whole product line, and your factory provisions a handful of keys instead of certifying every unit. RAUC's encrypted bundle format is the same either way; only the recipient list changes. Whichever you choose, choose it before the first unit ships: a key in a secure element or in TEE storage is not something a field update replaces, and a shared key cannot be turned into a key per device later without touching every unit.
Where is the key, who may use it, is there a record
The series' three questions apply to the encryption key too. Where is it? A shared product key is in the HSM and in every unit's secure element; a per-device key is in that device's TEE or secure element, and the release side holds only certificates. Who is allowed to use it? On the device, only the updater; on the release side, two roles matter: who may add a device to the registry, and who may build a release for a list of devices. Is there a record of every use? Each certificate issued and each release built should leave a record of who asked and when.
What the CRA asks for
The CRA does not require encrypted firmware as such. Annex I asks for integrity and confidentiality protection on the basis of your own risk assessment, and names encryption as one way to protect confidentiality. If your assessment says your updates need it, the Annex I mapping shows which requirements the key design answers.
Three questions for your own product
Where does the plaintext of your latest release exist right now?
Which single key, taken from one unit, would read every update you have ever shipped?
How would you stop a lost device from reading your next release?
Further reading: Encrypted RAUC updates with per-device keys walks through a per-device setup, with the device keys in OP-TEE, and the Raspberry Pi reference design shows the shared-key alternative with a secure element.



Comments