Update images from verified source

It is becoming very important that a device must not only be safely updated, but also that it can verify if the delivered image is coming from a known source and it was not corrupted introducing some malware.

To achieve this goal, SWUpdate must verify the incoming images. There are several ways to do this. Should the compound image be signed ? Or some parts of it ?

Advantages and disadvantages are described in the following chapter.

Signing the compound image

It looks quite straightforward if the whole compound image is signed. However, this has some heavy drawbacks. It is not possible to know if the image is verified until the whole image is loaded. This means that verification can be done after installing the single images instead of doing it before touching the device. This leads to have some uninstall procedure if part of a not verified image is already installed, procedures that cannot be safe in case of power off letting some unwanted piece of software on the device.

Signing the sub-images

If each sub-image is signed, the verification is done before calling the corresponding hardware. Only signed images can be installed. Anyway, this remains unbound with the description of the release in sw-description. Even if sw-description is signed, an attacker can mix signed images together generating a new compound image that can be installed as well, because all sub-images are verified.

Combining signing sw-description with hash verification

To avoid the described drawbacks, SWUpdate combines signed sw-description with the verification of hashes for each single image. This means that only sw-description generated by a verified source can be accepted by the installer. sw-description contains hashes for each sub-image to verify that each delivered sub-image really belongs to the release.

Choice of algorithm

The algorithm chosen to sign and verify the sw-descrription file can be selected via menuconfig. Currently, the following mechanisms are implemented:

  • RSA Public / private key. The private key belongs to the build system, while the public key must be installed on the target.

  • CMS using certificates

  • GPG key signing

For RSA and CMS algorithms, key or certificate is passed to SWUpdate with the -k parameter.

Tool to generate keys / certificates

For RSA and CMS signing, the openssl tool is used to generate the keys. This is part of the OpenSSL project. A complete documentation can be found at the openSSL Website.

For GPG, gpg can be used to generate the keys and to sign the images. A complete documentation can be found at the GnuPG Website.

Usage with RSA PKCS#1.5 or RSA PSS

Generating private and public key

First, the private key must be created:

openssl genrsa -aes256 -out priv.pem

This asks for a passphrase. It is possible to retrieve the passphrase from a file - of course, this must be protected against intrusion.

openssl genrsa -aes256 -passout file:passout -out priv.pem

The private key is used to export the public key with:

openssl rsa -in priv.pem -out public.pem -outform PEM -pubout

“public.pem” contains the key in a format suitable for swupdate. The file can be passed to swupdate at the command line with the -k parameter.

How to sign with RSA

Signing the image with rsa-pkcs#1.5 is very simple:

openssl dgst -sha256 -sign priv.pem sw-description > sw-description.sig

Signing the image with rsa-pss is also very simple:

openssl dgst -sha256 -sign priv.pem -sigopt rsa_padding_mode:pss \
    -sigopt rsa_pss_saltlen:-2 sw-description > sw-description.sig

Usage with certificates and CMS

Generating self-signed certificates

openssl req -x509 -newkey rsa:4096 -nodes -keyout mycert.key.pem \
    -out mycert.cert.pem -subj "/O=SWUpdate /CN=target"

Check the documentation for more information about parameters. The “mycert.key.pem” contains the private key and it is used for signing. It is not delivered on the target.

The target must have “mycert.cert.pem” installed - this is used by SWUpdate for verification.

Using PKI issued certificates

It is also possible to use PKI issued code signing certificates. However, SWUpdate uses OpenSSL library for handling CMS signatures and the library requires the following attributes to be set on the signing certificate:

keyUsage=digitalSignature
extendedKeyUsage=emailProtection

It is also possible to completely disable signing certificate key usage checking if this requirement cannot be satisfied. This is controlled by CONFIG_CMS_IGNORE_CERTIFICATE_PURPOSE configuration option.

How to sign with CMS

Signing the image is simple as in the previous case:

openssl cms -sign -in  sw-description -out sw-description.sig -signer mycert.cert.pem \
        -inkey mycert.key.pem -outform DER -nosmimecap -binary

Usage with GNU PG

Generating a new keypair

First, a primary keypair needs to be generated

::

gpg –gen-key

The generated keys can be listed as follows

::

gpg -k

Check the documentation for more information about parameters.

How to sign with gpg

Signing the image is very simple:

::
gpg –batch –output sw-description.sig

–detach-sig sw-description

For an alternative GnuPG home directory, and if there are multiple keypairs, the following can be used to specify. In this example, the GnuPG home directory is in GPG_HOMEDIR, while the signing key is found in GPG_KEY.

::
gpg –batch –homedir “${GPG_HOMEDIR}” –default-key “${GPG_KEY}” –output sw-description.sig

–detach-sig sw-description

Building a signed SWU image

There are two files, sw-description and its signature sw-description.sig. The signature file must always directly follow the description file.

Each image inside sw-description must have the attribute “sha256”, with the SHA256 sum of the image. If an image does not have the sha256 attribute, the whole compound image results as not verified and SWUpdate stops with an error before starting to install.

A simple script to create a signed image can be:

#!/bin/bash

MODE="RSA-PKCS-1.5"
PRODUCT_NAME="myproduct"
CONTAINER_VER="1.0"
IMAGES="rootfs kernel"
FILES="sw-description sw-description.sig $IMAGES"

#if you use RSA
if [ x"$MODE" == "xRSA-PKCS-1.5" ]; then
    openssl dgst -sha256 -sign priv.pem sw-description > sw-description.sig
elif if [ x"$MODE" == "xRSA-PSS" ]; then
    openssl dgst -sha256 -sign priv.pem -sigopt rsa_padding_mode:pss \
        -sigopt rsa_pss_saltlen:-2 sw-description > sw-description.sig
elif if [ x"$MODE" == "xGPG" ]; then
    gpg --batch --homedir "${GPG_HOME_DIR}" --default-key "${GPG_KEY}" \
        --output sw-description.sig --detach-sig sw-description
else
    openssl cms -sign -in  sw-description -out sw-description.sig -signer mycert.cert.pem \
        -inkey mycert.key.pem -outform DER -nosmimecap -binary
fi
for i in $FILES;do
        echo $i;done | cpio -ov -H crc >  ${PRODUCT_NAME}_${CONTAINER_VER}.swu

Example for sw-description with signed image

The example applies to a Beaglebone, installing Yocto images:

software =
{
        version = "0.1.0";

        hardware-compatibility: [ "revC"];

        images: (
                {
                    filename = "core-image-full-cmdline-beaglebone.ext3";
                    device = "/dev/mmcblk0p2";
                    type = "raw";
                    sha256 = "43cdedde429d1ee379a7d91e3e7c4b0b9ff952543a91a55bb2221e5c72cb342b";
                }
        );
        scripts: (
                {
                    filename = "test.lua";
                    type = "lua";
                    sha256 = "f53e0b271af4c2896f56a6adffa79a1ffa3e373c9ac96e00c4cfc577b9bea5f1";
                 }
        );
}

Running SWUpdate with signed images

Verification is activated by setting CONFIG_SIGNED_IMAGES in SWUpdate’s configuration. If activated, SWUpdate will always check the compound image. For security reasons, it is not possible to disable the check at runtime.

For RSA and CMS signing, the -k parameter (public key file) is mandatory and the program stops if the public key is not passed.

For GPG signing, CONFIG_SIGALG_GPG needs to be enabled. The GPG key will need to be imported to the device’s GnuPG home directory. To do this, the key will need to be exported:

::

gpg –export <keyid> –output <public key>

You can then copy it onto the device and import it into your public keyring:

::

gpg –import <public key>

To verify that the key has been imported successfully:

::

gpg –list-keys

SWUpdate will need need to be configured with the following parameters:

::

GnuPG Home directory: gpg-home-dir in swupdate.cfg GPGME Protocol: gpgme-protocol in swupdate.cfg: openpgp or cms