Signed SWUpdate updates¶
Sign SWUpdate's sw-description with a key held in the HSM, in whichever of
SWUpdate's signature modes your devices are built with, and check the result with
SWUpdate itself.
The Cyber Resilience Act's Annex I requires that security updates can be distributed
securely and that unauthorised changes to the software are detected. With SWUpdate
both rest on one file: sw-description lists every artifact of the update with its
SHA-256, and SWUpdate checks its signature before it installs anything.
How to read this
This is an example configuration, not a design guide. Choose what your devices trust, then take the commands for it. Delivering the archive to the device (hawkBit, a USB stick, a local web server) and the handlers that write the artifacts are your SWUpdate configuration and are not covered here. Building a device this way does not by itself make a product CRA compliant; the Annex I mapping sets out which requirements the platform supports and which remain yours.
Client version
The commands on this page need signing-tool 3.11.0 or later. The config file
test.ini is set up once, as described in
providing the token.
Who does what¶
-
LAAVAT
Signer
The HSM holds the signing key. It receives only the SHA-256 of
sw-description, never the update.Returns — a signature over
sw-description -
Your build host
Builder
Writes
sw-descriptionwith every artifact's hash, asks for the signature withsigning-tooland packs the.swu.Never holds — the private key
-
SWUpdate on the device
Verifier and installer
Checks the signature against the key or CA certificates in its image, then every artifact's hash, and only then installs.
Trusts — the key or CA certificates in its image
How SWUpdate checks an update¶
An update archive (.swu) is a cpio archive of three kinds of file:
sw-description, which lists every artifact of the update with its SHA-256;sw-description.sig, the signature oversw-description;- the artifacts themselves, for example
rootfs.ext4.
Only sw-description is signed; the hashes in it cover the artifacts. SWUpdate checks
the signature first, then every artifact's hash, and installs nothing if either check
fails. The build host sends LAAVAT only the SHA-256 of sw-description, never the
artifacts.
An example sw-description. It lists a single artifact, rootfs.ext4; a real update
has one entry per artifact, each with its own sha256.
software =
{
version = "1.4.0";
hardware-compatibility = [ "1.0" ];
images: (
{ filename = "rootfs.ext4"; device = "/dev/mmcblk0p3"; type = "raw";
sha256 = "<sha256 of rootfs.ext4>"; }
);
}
Choose what the device trusts¶
SWUpdate checks the signature against what its image gives it with -k. The signature
mode SWUpdate is built with decides which of two kinds of trust that is:
- A plain key (raw RSA or RSA-PSS): the device trusts one public key, the operation's.
- A certificate chain (CMS): the device trusts your CA hierarchy. The signature carries a certificate for the operation's key, and SWUpdate follows the chain from it up to the root. Built with OpenSSL, SWUpdate also takes the issuing CA from the signature, so the device needs only the root. Built with mbedTLS, it reads only one certificate from the signature, so the device holds the issuing CA as well.
| Build option | The device holds (-k) |
You also need | Replacing the signing key | Fits |
|---|---|---|---|---|
CONFIG_SIGALG_RAWRSA (RSA PKCS #1 v1.5) or CONFIG_SIGALG_RSAPSS (RSA-PSS) |
The operation's public key | Nothing besides LAAVAT | SWUpdate trusts one key, so the new key reaches devices in an update signed with the old one; from then on only the new key works | Short-lived or small fleets, no PKI |
CONFIG_SIGALG_CMS, OpenSSL |
Your root CA certificate | A CA hierarchy that issues a certificate for the signing key | A new key with a certificate under the same root needs no change on the device | Long-lived fleets, or a PKI you already run |
CONFIG_SIGALG_CMS, mbedTLS |
Your root CA and issuing CA certificates | As for OpenSSL | As for OpenSSL | As for OpenSSL |
The mbedTLS CMS mode needs SWUpdate 2026.05 or later, built with mbedTLS 3.4 or later; this page was checked with SWUpdate 2026.05.1 and mbedTLS 3.6.
The mode is built into SWUpdate on the device, so choose it while planning the product.
Which library SWUpdate uses is also a build option: OpenSSL is the default, mbedTLS
(CONFIG_SSL_IMPL_MBEDTLS) is the alternative this page covers. Your device's SWUpdate
configuration shows both settings, CONFIG_SIGALG_* and CONFIG_SSL_IMPL_*.
The LAAVAT product¶
The product has one DigestSigning operation. An RSA key serves every mode; an EC P-256
key also works in the CMS modes.
{
"name": "SWUpdate gateway",
"description": "SWUpdate: sw-description signed by digest signing",
"productType": "Production",
"enabled": true,
"caInfo": [], "rndKeys": [],
"productOperations": [
{ "name": "sw-description signing",
"description": "Signs the SHA-256 of sw-description",
"operationType": "DigestSigning",
"token": { "name": "SWUpdate signing key", "description": "RSA-3072", "keyType": "RSA3072" },
"approvalRule": { "name": "Release", "description": "Release group requests, approver group approves",
"allowedGroups": ["<release-group-uuid>"], "approvalGroups": ["<approver-group-uuid>"], "blanketGroups": [] } }
]
}
signing-tool -n test.ini product add -T swupdate-gateway.json
# the new product is approved in the LAAVAT console before use; then export the operation's public key
signing-tool -n test.ini product getpubkey -P <product-uuid> --operid <operation-uuid> -O public.pem
Approval rule. The rule decides who may sign. A member of allowedGroups submits
the signing request; it then waits until a member of approvalGroups approves it, in
the LAAVAT console or with signing-tool, and only then does the HSM sign. If the
requester is also a member of one of the blanketGroups, no approval is needed and the
request is signed straight away; that is how an unattended build pipeline, such as a
Jenkins job, signs. It skips the human check, so keep those groups narrow. The group ids
in the rule are the object ids of groups in your identity provider (Microsoft Entra ID
or Google Cloud Identity). See approval rules and
configuration groups.
public.pem is the operation's public key. Unlike in SWUpdate's own guide, you do not
generate a key pair with OpenSSL: the private key is created in the HSM and never leaves
it, and product getpubkey exports the public key. See
key custody.
Prepare what the device trusts¶
A plain key¶
Put public.pem into the device's root filesystem and start SWUpdate with
-k public.pem. If the boot chain verifies the root filesystem (for example with
dm-verity or a signed root filesystem image), the key cannot be swapped; see
Secure boot and CRA.
A certificate chain¶
SWUpdate does not trust the operation's key directly here: the key needs a certificate,
issued from your CA hierarchy, that names public.pem as its public key. For a test
setup, OpenSSL can issue one from the exported public key:
printf '%s\n' 'basicConstraints=CA:FALSE' 'keyUsage=critical,digitalSignature' \
'extendedKeyUsage=emailProtection' 'subjectKeyIdentifier=hash' 'authorityKeyIdentifier=keyid' > signer.ext
openssl x509 -new -subj "/CN=SWUpdate signing" -force_pubkey public.pem \
-CA issuing-ca.pem -CAkey issuing-ca.key -days 730 -extfile signer.ext -out signer.pem
cat signer.pem issuing-ca.pem > chain.pem
What the commands do:
signer.extlists what the certificate allows.basicConstraints=CA:FALSE: it is a signing certificate, not a CA.keyUsage=critical,digitalSignature: its key may make signatures.extendedKeyUsage=emailProtection: the purpose SWUpdate checks by default; if your CA issuescodeSigningcertificates instead, setcert-purpose = "codeSigning"inswupdate.cfg.subjectKeyIdentifierandauthorityKeyIdentifier: identifiers verifiers use to match the certificate to its key and to the CA that issued it.openssl x509 -newcreates the certificate.-force_pubkey public.pemputs the operation's public key into it (the private key stays in the HSM),-CAand-CAkeysign it with your issuing CA, and-days 730makes it valid for two years.catwriteschain.pem: the signing certificate followed by the issuing CA's. For the OpenSSL build, pass both tosigning-tool(--cms-cert chain.pem).
The files. The hierarchy in this example has two levels: a root CA (root.pem) and
an issuing CA under it (issuing-ca.pem, with its private key issuing-ca.key) that
issues the signing certificate. The device's -k file, in its root filesystem like a
plain key, is root.pem for the OpenSSL build. For the mbedTLS build it is the root and
the issuing CA in one file:
cat issuing-ca.pem root.pem > ca-chain.pem
Test setup or production
The commands above issue the certificate straight from the exported public key, so the issuing CA's private key has to be on the machine that runs them. That is fine for a test CA. A production CA normally issues certificates only from a CSR, which the key itself signs, and keeps its own private key in its protected environment. For that case, use a certificate the platform holds: the platform creates the key in the HSM together with a CSR for your CA. See Certificate-based signing.
Sign sw-description¶
Every mode sends the same thing: -p is the SHA-256 of sw-description, base64-encoded
on one line, and it is all that reaches LAAVAT. The modes differ only in the options
after it, and get --wait downloads the signature as sw-description.sig.
Raw RSA (CONFIG_SIGALG_RAWRSA)¶
signing-tool -n test.ini imagesigning add DigestSigning -P <product-uuid> --operid <operation-uuid> \
-p "$(openssl dgst -sha256 -binary sw-description | base64 -w0)" -H SHA256 \
-N "swu 1.4.0" -D "sw-description 1.4.0"
Image signing request sent. Request ID: <request-uuid> state: Created
signing-tool -n test.ini imagesigning get -I <request-uuid> --wait -O sw-description.sig
RSA-PSS (CONFIG_SIGALG_RSAPSS)¶
The raw RSA request with --padding PSS added.
signing-tool -n test.ini imagesigning add DigestSigning -P <product-uuid> --operid <operation-uuid> \
-p "$(openssl dgst -sha256 -binary sw-description | base64 -w0)" -H SHA256 --padding PSS \
-N "swu 1.4.0" -D "sw-description 1.4.0"
signing-tool -n test.ini imagesigning get -I <request-uuid> --wait -O sw-description.sig
CMS, OpenSSL build (CONFIG_SIGALG_CMS)¶
The signature carries the signing certificate and the issuing CA: --cms-cert chain.pem.
signing-tool -n test.ini imagesigning add DigestSigning -P <product-uuid> --operid <operation-uuid> \
-p "$(openssl dgst -sha256 -binary sw-description | base64 -w0)" -H SHA256 \
--format CMS --cms-preset swupdate --cms-cert chain.pem -N "swu 1.4.0" -D "sw-description 1.4.0"
signing-tool -n test.ini imagesigning get -I <request-uuid> --wait -O sw-description.sig
Optional: add --padding PSS to make the CMS signature RSA-PSS instead of PKCS #1 v1.5.
The OpenSSL build accepts both.
CMS, mbedTLS build (CONFIG_SIGALG_CMS)¶
The signature carries the signing certificate alone: --cms-cert signer.pem.
signing-tool -n test.ini imagesigning add DigestSigning -P <product-uuid> --operid <operation-uuid> \
-p "$(openssl dgst -sha256 -binary sw-description | base64 -w0)" -H SHA256 \
--format CMS --cms-preset swupdate-mbedtls --cms-cert signer.pem -N "swu 1.4.0" -D "sw-description 1.4.0"
signing-tool -n test.ini imagesigning get -I <request-uuid> --wait -O sw-description.sig
Two limits of the mbedTLS build:
- the signature must be RSA PKCS #1 v1.5 or ECDSA, so do not add
--padding PSS; - pass
signer.pem, notchain.pem, to--cms-cert: a signature that carries the issuing CA as well is refused.
Pack the update¶
The same for every mode. With sw-description.sig next to sw-description and the
artifacts:
printf 'sw-description\nsw-description.sig\nrootfs.ext4\n' | cpio -ov -H crc > update.swu
SWUpdate reads sw-description first and its signature second, so they lead the list;
the artifacts follow, one per line, the same ones sw-description lists. -H crc is one
of the two cpio formats SWUpdate accepts (newc is the other).
Verify the update¶
SWUpdate's check mode (-c) runs the same checks as the device: the signature, then every
artifact's hash. It installs nothing. Use a swupdate built with the same signature mode
as the device's; distribution packages are usually built for CMS.
swupdate -c -k public.pem -i update.swu # raw RSA or RSA-PSS
swupdate -c -k root.pem -i update.swu # CMS, OpenSSL build
swupdate -c -k ca-chain.pem -i update.swu # CMS, mbedTLS build
SWUPDATE successful !
Every refused update ends with Image invalid or corrupted. Not installing ..., and
swupdate exits with a non-zero status; the lines before it say why. In the CMS modes a
changed sw-description is reported as Signature verification failed, and the OpenSSL
build reports the same for another CA's root or a codeSigning certificate without
cert-purpose. Add -H <board>:<revision> when your build checks hardware compatibility.
Where off-hardware verification stops¶
| Claim | Off-hardware | What would close the gap |
|---|---|---|
| Each mode's signature is accepted by SWUpdate, with RSA-2048 and RSA-3072 keys, and EC P-256 keys in both CMS builds | Checked on the build host with swupdate -c built for each mode, plus a distribution-packaged SWUpdate for CMS |
Not needed |
| A changed description, a changed artifact, a foreign key or another CA's root is refused | Checked on the build host with swupdate -c |
Not needed |
| mbedTLS: RSA and ECDSA accepted, RSA-PSS and a full chain refused | Checked on the build host with SWUpdate 2026.05.1 and mbedTLS 3.6 | Not needed |
| The device holds the right key or CA certificates, protected by secure boot | Not testable off-device | The device's image build and secure boot chain |
| The handlers install the artifacts | Not tested | An update on the target |
Mapping to the CRA¶
| Annex I requirement | Covered by |
|---|---|
| Part I (2)(f): protect the integrity of programs, commands and configuration against manipulation or modification not authorised by the user | SWUpdate verifies the signature over sw-description and every artifact's hash before it installs |
| Part I (2)(c): vulnerabilities can be addressed through security updates. Part II (7): mechanisms to securely distribute updates | Signed .swu archives over any channel; a tampered or foreign archive is refused on the device |
| Supporting evidence, not an Annex I product requirement: custody of the signing key | The signing key stays in the HSM. Only members of the release group can request a signature, and each request is signed only after a member of the approver group approves it. Every request is in the platform's audit trail |
Related¶
- Digest signing — every option, preset and error message
- Signatures with digest signing — kernel modules, tokens, attestations and post-quantum keys
- Certificate-based signing — CMS signatures with a certificate your CA issues from a CSR and the platform holds
- Signed Mender OTA updates — the same idea with Mender
- Secure boot and CRA — the boot chain that protects the key on the device
References¶
- SWUpdate: signed images, including generating the private and public key, which the HSM replaces here
- SWUpdate: the sw-description syntax