Skip to content

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-description with every artifact's hash, asks for the signature with signing-tool and 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 over sw-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.ext lists 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 issues codeSigning certificates instead, set cert-purpose = "codeSigning" in swupdate.cfg. subjectKeyIdentifier and authorityKeyIdentifier: identifiers verifiers use to match the certificate to its key and to the CA that issued it.
  • openssl x509 -new creates the certificate. -force_pubkey public.pem puts the operation's public key into it (the private key stays in the HSM), -CA and -CAkey sign it with your issuing CA, and -days 730 makes it valid for two years.
  • cat writes chain.pem: the signing certificate followed by the issuing CA's. For the OpenSSL build, pass both to signing-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, not chain.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

References