Signing Binaries

Binaries can be optionally signed as part of a build automatically using CMake code, there is also the ability to use west sign to sign binaries too, this page describes the former, the latter is documented on Signing Binaries.

MCUboot / imgtool

The Zephyr build system has special support for signing binaries for use with the MCUboot bootloader using the imgtool program provided by its developers. You can both build and sign this type of application binary in one step by setting some Kconfig options. If you do, west flash will use the signed binaries.

Here is an example workflow, which builds and flashes MCUboot, as well as the Hello World application for chain-loading by MCUboot. Run these commands from the zephyrproject workspace you created in the Getting Started Guide.

west build -b YOUR_BOARD zephyr/samples/hello_world --sysbuild -d build-hello-signed -- \
     -DSB_CONFIG_BOOTLOADER_MCUBOOT=y

west flash -d build-hello-signed

Notes on the above commands:

  • YOUR_BOARD should be changed to match your board

  • The signing key value is the insecure default provided and used by MCUboot for development and testing

  • You can change the hello_world application directory to any other application that can be loaded by MCUboot, such as the SMP server sample.

For more information on these and other related configuration options, see:

  • SB_CONFIG_BOOTLOADER_MCUBOOT: build the application for loading by MCUboot

  • SB_CONFIG_BOOT_SIGNATURE_KEY_FILE: the key file, or a comma-separated list of key files, to use when signing images. If you have your own key, change this appropriately; see Signing key files for using an absolute path or a CMake variable such as ${APP_DIR}. When a list is given, MCUboot embeds the public half of every key and accepts an image signed with any of them; the first entry also signs the application, and every entry past the first must be a public-only PEM of the same signature type for imgtool.

  • CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS: optional additional command line arguments for imgtool

  • CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE: also generate a confirmed image, which may be more useful for flashing in production environments than the OTA-able default image

  • On Windows, if you get “Access denied” issues, the recommended fix is to run pip3 install imgtool, then retry with a pristine build directory.

For a worked example of a multi-key bootloader exercised end-to-end under QEMU, see the tests/boot/mcuboot_multiple_keys test.

If your west flash runner uses an image format supported by imgtool, you should see something like this on your device’s serial console when you run west flash -d build-hello-signed:

*** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1  ***
[00:00:00.004,669] <inf> mcuboot: Starting bootloader
[00:00:00.011,169] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
[00:00:00.021,636] <inf> mcuboot: Boot source: none
[00:00:00.027,374] <inf> mcuboot: Swap type: none
[00:00:00.115,142] <inf> mcuboot: Bootloader chainload address offset: 0xc000
[00:00:00.123,168] <inf> mcuboot: Jumping to the first image slot
*** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1  ***
Hello World! nrf52840dk_nrf52840

Whether west flash supports this feature depends on your runner. The nrfjprog and pyocd runners work with the above flow. If your runner does not support this flow and you would like it to, please send a patch or file an issue for adding support.

Signing key files

When building with sysbuild, SB_CONFIG_BOOT_SIGNATURE_KEY_FILE selects the key used to sign images. Its value is propagated to two images:

  • the application image, as CONFIG_MCUBOOT_SIGNATURE_KEY_FILE, which imgtool uses to sign the application; and

  • the MCUboot image, as CONFIG_BOOT_SIGNATURE_KEY_FILE, whose public part is built into the bootloader so it can verify that signature.

Warning

The default value points at one of the insecure development keys bundled with MCUboot (for example root-ec-p256.pem). These keys are public — they ship with every Zephyr and MCUboot checkout — so they are only suitable for development and testing. For anything else, generate your own key and keep the private key out of any repository or build directory that you do not control.

How sysbuild resolves the key file path

The value of SB_CONFIG_BOOT_SIGNATURE_KEY_FILE is processed with CMake’s string(CONFIGURE) command, so any ${VARIABLE} reference it contains is expanded as a CMake variable before the path is used. After expansion, an absolute path is used as-is; a relative path is resolved by each image independently:

Image

Search order for a relative path

Application (CONFIG_MCUBOOT_SIGNATURE_KEY_FILE)

APPLICATION_CONFIG_DIR, then the west workspace topdir (WEST_TOPDIR)

MCUboot (CONFIG_BOOT_SIGNATURE_KEY_FILE)

APPLICATION_CONFIG_DIR, then the MCUboot module directory

Warning

Each image resolves a relative path against a different base, so a bare relative path points at a different file for each image and usually fails to build. Do not use one: give an absolute path, or anchor the path with a CMake variable.

${APP_DIR} (the main application’s source directory) is the recommended anchor: it keeps the key inside your own application, and both images resolve it to the same file. Any CMake variable available when the value is expanded may be used:

# sysbuild.conf
SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="${APP_DIR}/keys/my-signing-key.pem"

The same resolution rules apply to the optional encryption key file (CONFIG_MCUBOOT_ENCRYPTION_KEY_FILE).

Extending signing externally

The signing script used when running west flash can be extended or replaced to change features or introduce different signing mechanisms. By default with MCUboot enabled, signing is setup by the cmake/mcuboot.cmake file in Zephyr which adds extra post build commands for generating the signed images. The file used for signing can be replaced from a sysbuild scope (if being used) or from a zephyr/zephyr module scope, the priority of which is:

  • Sysbuild

  • Zephyr property

  • Default MCUboot script (if enabled)

From sysbuild, -D<target>_SIGNING_SCRIPT can be used to set a signing script for a specific image or -DSIGNING_SCRIPT can be used to set a signing script for all images, for example:

west build -b <board> <application> -DSIGNING_SCRIPT=<file>

The zephyr property method is achieved by adjusting the SIGNING_SCRIPT property on the zephyr_property_target, ideally from by a module by using:

if(CONFIG_BOOTLOADER_MCUBOOT)
  set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/custom_signing.cmake)
endif()

This will include the custom signing CMake file instead of the default Zephyr one when projects are built with MCUboot signing support enabled. The base Zephyr MCUboot signing file can be used as a reference for creating a new signing system or extending the default behaviour.