# Verified Boot

meta-tq provides some support for building a chain of trust consisting
of signed bootloader images, signed FIT images and rootfs partition with
dm-verity. This readme contains useful information on how to activate each
part of the chain and provides also some background information.

[[_TOC_]]

## Signed Bootloader Image (IMX HAB)

Currently only the High Assurance Boot (HAB) feature of i.MX platforms is
supported. HAB allows to verify the booted image against a public key hash
programmed into the fuses of the i.MX SoC to prevent manipulation of the
software on the boot medium.

i.MX HAB exists in two variants: HAB4 (HAB Version 4) and AHAB (Advanced HAB).
Please refer to the HAB documentation, in particular the [i.MX Code Signing Tool
documentation](https://gitlab.apertis.org/pkg/imx-code-signing-tool/-/tree/apertis/v2024dev2/docs)
and documentation provided with U-Boot, [HAB4](https://source.denx.de/u-boot/u-boot/-/tree/master/doc/imx/habv4)
or [AHAB](https://source.denx.de/u-boot/u-boot/-/tree/master/doc/imx/ahab)
respectively, for further information on signing key generation, signature
creation and general concepts of HAB.

### Supported platforms

meta-tq supports HAB4 signature generation on all i.MX8M-based platforms:

- TQMa8MPxL
- TQMa8Mx
- TQMa8MxML
- TQMa8MxNL

meta-tq supports AHAB signature generation on the following platforms:

- TQMa8x
- TQMa8Xx
- TQMa93xx

### Abbreviations

|     | Definition            |
| --- | --------------------- |
| CSF | Command Sequence File |
| CST | Code Signing Tool     |
| HAB | High Assurance Boot   |

### Configuration

Signature generation can either be handled as part of the Yocto build (for
convenience during development) or separately (strongly recommended for
production images, so signing keys can be stored on a protected host separate
from the build system). Also the process of signing images should be executed in
a trusted environment).

In both cases, the "secure" distro feature must be enabled, either in a
custom distro config or in `local.conf`:

    DISTRO_FEATURES:append = " secure"

Enabling the distro feature has two effects:

- HAB support is enabled in U-Boot. The SPL will validate the BL3 boot stage,
  and various commands like `hab_status`/`ahab_status` are made available
  from the U-Boot command line.
- Optionally, [automated signing](#automated-signing) can be enabled using the
  `IMX_HAB_KEY_NAME` variable. If this variable is unset, signing will be
  skipped and a log message is printed.

#### Separate signing step

If signatures are not generated as a part of the Yocto build, the
`IMX_HAB_KEY_NAME` variable should be left unset.

On supported platforms, the build will place the following files in the artifact
directory at `${DEPLOY_DIR_IMAGE}` to facilitate the creation of signatures (for
each U-Boot configuration `config` and boot source `target`):

- `habinfo-${config}.env-${target}`

  A shell environment file which contains information about HAB blocks and CSF
  offsets. The HAB block list must be copied into a CSF input file, which is
  then used by the Code Signing Tool.

  On HAB4 platforms, the autogenerated file might look like the following:

      SPL_CSF_OFF="0x29000"
      SPL_HAB_BLOCK="0x911fc0 0x0 0x29000"
      SLD_CSF_OFF="0x59020"
      SLD_HAB_BLOCK="0x401fcdc0 0x58000 0x1020"
      FIT_HAB_BLOCK="0x40200000 0x5B000 0xB3268
      0x402B3268 0x10E268 0x74E8
      0x960000 0x115750 0xB1B0
      "

  Two separate signatures need to be generated on these platforms: one for the
  SPL/BL2 (signing `SPL_HAB_BLOCK`) and one for the BL3 boot stage
  containing U-Boot, ATF and optionally OP-TEE (signing both `SLD_HAB_BLOCK`
  and `FIT_HAB_BLOCK`). `SPL_CSF_OFF` and `SLD_CSF_OFF` specify the offsets
  where the signatures need to be patched into the bootstream
  (`imx-boot-${MACHINE}-${config}.bin-${target}`).

  On AHAB platforms, the autogenerated file might look like the following:

      CONTAINER_HEADER_OFF="0x0"
      SIGNATURE_BLOCK_OFF="0x110"

  As for HAB4, two signatures are needed. But for AHAB they are generated in
  two separate signing steps. In the first step, a container with U-Boot, ATF
  and optionally OP-TEE is signed. In the next step, the whole bootstream with
  the signed container from step one, SPL and various firmware files is built
  using imx-mkimage and then signed again. Therefore two different `habinfo`
  files for each `config` are in `${DEPLOY_DIR_IMAGE}`.

- `csf_*-${config}.txt-${target}`

  Example CSF input files generated based on the data in the habinfo
  file. The templates that these files are based on are located under
  `meta-tq/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files`.
  A bbappend for the `imx-boot-tq` recipe can be used to customize these
  templates.

#### Automated signing

For convenience during development, the entire signature generation can be
handled as a part of the Yocto build process. This requires the signing keys
to be provided by the `imx-cst-keys` package
(`meta-tq/dynamic-layers/freescale-layer/recipes-security/imx-cst-keys`).
A set of example keys is already included in meta-tq; other keys can be added
using a bbappend file.

To enable automated signing, the `IMX_HAB_KEY_NAME` variable must be set in a
distro config or in `local.conf`, for example:

    # This selects the example key for SoCs with HAB4 support
    IMX_HAB_KEY_NAME = "hab4"

With this configuration, signatures will be created based on the generated
CSF files and patched into the corresponding bootstream files
(`imx-boot-${MACHINE}-${config}.bin-${target}`).

## Signed FIT Image

**Attention:** Verifying and booting signed FIT images is currently not
supported for all HAB4/i.MX8M based platforms.

With signed FIT images the chain of trust can be extended to Linux kernel
and devicetree. The FIT image bundles the kernel image and one or multiple
devicetree images into a single binary. This image can then be signed using
methods of asymmetric cryptography. The private key used for signing the
image must be kept secret by the issuer of the FIT image and the public key
is included into the U-Boot devicetree. This allows the bootloader to verify
the signature of the FIT image and therefore prove its integrity.

Signed FIT images can be used for all TQ modules. A FIT image is assembled
by default if a TQ image is used.

### Signing using example keys

Example key and certificate needed for signing and verification are provided in
meta-dumpling. To enable signing this FIT image, the option `UBOOT_SIGN_ENABLE`
must be set to `1` in `local.conf`:

    UBOOT_SIGN_ENABLE = "1"

### Signing using custom keys

A custom key and certificate can be used instead of the provided example key.
Key and certificate must have the same file name and the file endings `key` and
 `crt` respectively. The following `openssl` command can be used for
generation:

    openssl req -batch -new -x509 -key custom.key -out custom.crt
    openssl genpkey -algorithm RSA -out custom.key -pkeyopt rsa_keygen_bits:2048

To use custom key and certificate, one has to override `UBOOT_SIGN_KEYDIR`,
`UBOOT_SIGN_KEYNAME` and `UBOOT_MKIMAGE_DTCOPTS` as needed in `local.conf`.

    UBOOT_SIGN_KEYDIR = "/keys/directory"
    UBOOT_SIGN_KEYNAME = "custom" # keys name in keydir (eg. "custom.crt", "custom.key")

### Booting a signed FIT image

#### TQMa8 series

On older U-Boot versions, used by TQMa8 module series, some modification is
needed in U-Boot environment to boot a FIT image:

    setenv image fitImage
    setenv boot_os 'bootm ${loadaddr}'
    setenv sec_boot no

`sec_boot` is set to `yes` if HAB4/AHAB boot is enabled in U-Boot config. This
setting requires a signed os container to be loaded, which is beyond the scope
of this README. Set to `no` to skip this check.

#### TQMa9 series

TQMa9x can boot signed FIT image with distroboot:

    run distro_bootcmd

## DM-Verity for Root-Partition

The verity devicemapper is a way to guarantee integrity of some data. It is used
here to create a protected rootfs partition. To do so, we need meta-security,
which provides `dm-verity-img.bbclass`, as dependency:

URI: https://git.yoctoproject.org/meta-security  
branch: scarthgap  
revision: HEAD  
layers: meta-security

The layer must be added to `bblayers.conf`:

    BBLAYERS += "${BSPDIR}/sources/meta-security"

A block of settings must be set in `local.conf` to enable the build of a
verity protected root partition. The first one is to add `dm-verity-img` from
meta-security to `IMAGE_CLASSES`:

    IMAGE_CLASSES += "dm-verity-img"

The next step is to choose a FIT image for creating the devicemapper and
mounting the verity protected root filesystem. meta-security also provides such
an initramfs image:

    INITRAMFS_IMAGE = "dm-verity-image-initramfs"

The FIT image with the initramfs must be deployed to the boot partition:

    IMAGE_BOOT_FILES:append = " fitImage-${INITRAMFS_IMAGE}-${MACHINE}-${MACHINE};fitImage"

To apply dm-verity to a root filesystem image, set `DM_VERITY_IMAGE` and
`DM_VERITY_IMAGE_TYPE` accordingly. For example, building
`tq-image-generic-debug` with dm-verity:

    DM_VERITY_IMAGE = "tq-image-generic-debug"
    DM_VERITY_IMAGE_TYPE = "ext4"

Bitbake will automatically create the hash data for the root partition and store
the root hash inside the initramfs when the image set in `DM_VERITY_IMAGE`
is build.

### Booting a signed FIT image for dm-verity

The FIT image with initramfs for dm-verity usage is located in the boot
partition, because the root hash that is saved inside the initramfs must be kept
separate from the root partition.

#### TQMa8 series

For TQMa8 module series with U-Boot 2020.04, the environment settings for TQMa8
from [Booting a signed FIT image](#booting-a-signed-fit-image) can be used.
Additionally, `loadaddr` must be set to an address with enough free memory space
to fit a FIT image with initramfs:

Module    | `loadaddr`
--------- | ------------
TQMa8x    | `0xA0000000`
TQMa8Xx   | `0xA0000000`
TQMa8XxS  | `0xA0000000`
TQMa8Mx   | `0x60000000`
TQMa8MxML | `0x60000000`
TQMa8MxNL | `0x60000000`
TQMa8MPxL | `0x60000000`

#### TQMa9 series

The bootloader for TQMa9 module series loads images from root fs by default. To
load the FIT image from the boot partition, some environment adjustments are
needed:

    setenv mmcpart 1
    setenv mmcpath /
    setenv image fitImage
    setenv boot_os 'bootm ${kernel_addr_r}'
    setenv sec_boot no

`sec_boot` is set to `yes` if HAB4/AHAB boot is enabled in U-Boot config. This
setting requires a signed os container to be loaded, which is beyond the scope
of this README. Set to `no` to skip this check.

## Limitations

### Protection measures for root filesystem

For now, only DMVerity is applied in the example implementation. Other
mesasures for protecting the root filesystem exist in the Linux kernel,
each with different capabilities and guarantees:
  - DMIntegrity
  - DMCrypt
  - Integrity Measurement Architecture (IMA)

Discussion of the specific advantages and disadvantages of the different
approaches is out of scope for this document.

### Compatibility

The signed images for i.MX8M generated by `imx-mkimage` version `lf-6.1.55_2.2.0`
and newer are not compatible to images generated by older versions of this tool.
Care must be taken when updating image generation and bootloader.

Currently, Verified Boot with `secure` in `DISTRO_FEATURES` is mutually
exclusive to RAUC with distro feature `rauc`.
