build: auto-generate signed mcuboot binaries

Add new Kconfig options which depend on CONFIG_BOOTLOADER_MCUBOOT:

- CONFIG_MCUBOOT_SIGNATURE_KEY_FILE: the path to the key pair which
  should be used to sign the image, in PEM format. This is sent to
  imgtool via 'west sign' when set to produce zephyr.signed.bin and
  zephyr.signed.hex files as needed.

- CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS: additional arguments to pass to
  imgtool.

- CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE: also generate
  zephyr.signed.confirmed.{bin,hex}

Add build system support for these options.

This makes a separate 'west sign' step unnecessary when using MCUboot,
if the application image is properly configured with the location of
the key file.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Martí Bolívar 2020-08-18 11:28:04 -07:00 committed by Carles Cufí
parent 9b6736748d
commit f66a0c3772
3 changed files with 188 additions and 0 deletions

View file

@ -1284,6 +1284,11 @@ if(CONFIG_BUILD_OUTPUT_EXE)
)
endif()
# Generate and use MCUboot related artifacts as needed.
if(CONFIG_BOOTLOADER_MCUBOOT)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake)
endif()
get_property(extra_post_build_commands
GLOBAL PROPERTY
extra_post_build_commands

View file

@ -398,6 +398,55 @@ config BOOTLOADER_MCUBOOT
(or Armv8-M baseline) targets with no built-in vector relocation
mechanisms
if BOOTLOADER_MCUBOOT
config MCUBOOT_SIGNATURE_KEY_FILE
string "Path to the mcuboot signing key file"
default ""
help
The file contains a key pair whose public half is verified
by your target's MCUboot image. The file is in PEM format.
If set to a non-empty value, the build system tries to
sign the final binaries using a 'west sign -t imgtool' command.
The signed binaries are placed in the build directory
at zephyr/zephyr.signed.bin and zephyr/zephyr.signed.hex.
The file names can be customized with CONFIG_KERNEL_BIN_NAME.
The existence of bin and hex files depends on CONFIG_BUILD_OUTPUT_BIN
and CONFIG_BUILD_OUTPUT_HEX.
This option should contain an absolute path to the same file
as the BOOT_SIGNATURE_KEY_FILE option in your MCUboot
.config. (The MCUboot config option is used for the MCUboot
bootloader image; this option is for your application which
is to be loaded by MCUboot. The MCUboot config option can be
a relative path from the MCUboot repository root; this option's
behavior is undefined for relative paths.)
If left empty, you must sign the Zephyr binaries manually.
config MCUBOOT_EXTRA_IMGTOOL_ARGS
string "Extra arguments to pass to imgtool"
default ""
help
If CONFIG_MCUBOOT_SIGNATURE_KEY_FILE is a non-empty string,
you can use this option to pass extra options to imgtool.
For example, you could set this to "--version 1.2".
config MCUBOOT_GENERATE_CONFIRMED_IMAGE
bool "Also generate a confirmed image"
help
The signed and confirmed binaries are placed in the build directory
at zephyr/zephyr.signed.confirmed.bin and
zephyr/zephyr.signed.confirmed.hex.
The file names can be customized with CONFIG_KERNEL_BIN_NAME.
The existence of bin and hex files depends on CONFIG_BUILD_OUTPUT_BIN
and CONFIG_BUILD_OUTPUT_HEX.
endif # BOOTLOADER_MCUBOOT
config BOOTLOADER_ESP_IDF
bool "ESP-IDF bootloader support"
depends on SOC_ESP32

134
cmake/mcuboot.cmake Normal file
View file

@ -0,0 +1,134 @@
# Copyright (c) 2020 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
# This file includes extra build system logic that is enabled when
# CONFIG_BOOTLOADER_MCUBOOT=y.
#
# It builds signed binaries using imgtool as a post-processing step
# after zephyr/zephyr.elf is created in the build directory.
#
# Since this file is brought in via include(), we do the work in a
# function to avoid polluting the top-level scope.
function(zephyr_mcuboot_tasks)
set(keyfile "${CONFIG_MCUBOOT_SIGNATURE_KEY_FILE}")
# Check for misconfiguration.
if("${keyfile}" STREQUAL "")
# No signature key file, no signed binaries. No error, though:
# this is the documented behavior.
return()
endif()
if(NOT WEST)
# This feature requires west.
message(FATAL_ERROR "Can't sign images for MCUboot: west not found. To fix, install west and ensure it's on PATH.")
endif()
if(NOT IS_ABSOLUTE "${keyfile}")
# Relative paths are relative to 'west topdir'.
set(keyfile "${WEST_TOPDIR}/${keyfile}")
set(keyfile_relative TRUE)
else()
set(keyfile_relative FALSE)
endif()
if(NOT EXISTS "${keyfile}")
if(keyfile_relative)
set(relative_msg " Note: relative paths are relative to the west workspace topdir \"${WEST_TOPDIR}\".")
else()
set(relative_msg "")
endif()
message(FATAL_ERROR "Can't sign images for MCUboot: CONFIG_MCUBOOT_SIGNATURE_KEY_FILE=\"${CONFIG_MCUBOOT_SIGNATURE_KEY_FILE}\" not found.${relative_msg}")
elseif(NOT (CONFIG_BUILD_OUTPUT_BIN OR CONFIG_BUILD_OUTPUT_HEX))
message(FATAL_ERROR "Can't sign images for MCUboot: Neither CONFIG_BUILD_OUTPUT_BIN nor CONFIG_BUILD_OUTPUT_HEX is enabled, so there's nothing to sign.")
endif()
# Find imgtool. Even though west is installed, imgtool might not be.
# The user may also have a custom manifest which doesn't include
# MCUboot.
#
# Therefore, go with an explicitly installed imgtool first, falling
# back on mcuboot/scripts/imgtool.py.
if(IMGTOOL)
set(imgtool_path "${IMGTOOL}")
elseif(DEFINED ZEPHYR_MCUBOOT_MODULE_DIR)
set(IMGTOOL_PY "${ZEPHYR_MCUBOOT_MODULE_DIR}/scripts/imgtool.py")
if(EXISTS "${IMGTOOL_PY}")
set(imgtool_path "${IMGTOOL_PY}")
endif()
endif()
# No imgtool, no signed binaries.
if(NOT DEFINED imgtool_path)
message(FATAL_ERROR "Can't sign images for MCUboot: can't find imgtool. To fix, install imgtool with pip3, or add the mcuboot repository to the west manifest and ensure it has a scripts/imgtool.py file.")
return()
endif()
# Basic 'west sign' command and output format independent arguments.
set(west_sign ${WEST} sign --quiet --tool imgtool
--tool-path "${imgtool_path}"
--build-dir "${APPLICATION_BINARY_DIR}")
# Arguments to imgtool.
if(NOT CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS STREQUAL "")
# Separate extra arguments into the proper format for adding to
# extra_post_build_commands.
#
# Use UNIX_COMMAND syntax for uniform results across host
# platforms.
separate_arguments(imgtool_extra UNIX_COMMAND ${CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS})
else()
set(imgtool_extra)
endif()
set(imgtool_args -- --key "${keyfile}" ${imgtool_extra})
# Extensionless prefix of any output file.
set(output ${ZEPHYR_BINARY_DIR}/${KERNEL_NAME})
# List of additional build byproducts.
set(byproducts)
# 'west sign' arguments for confirmed and unconfirmed images.
set(unconfirmed_args)
set(confirmed_args)
# Set up .bin outputs.
if(CONFIG_BUILD_OUTPUT_BIN)
list(APPEND unconfirmed_args --bin --sbin ${output}.signed.bin)
list(APPEND byproducts ${output}.signed.bin)
if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
list(APPEND confirmed_args --bin --sbin ${output}.signed.confirmed.bin)
list(APPEND byproducts ${output}.signed.confirmed.bin)
endif()
endif()
# Set up .hex outputs.
if(CONFIG_BUILD_OUTPUT_HEX)
list(APPEND unconfirmed_args --hex --shex ${output}.signed.hex)
list(APPEND byproducts ${output}.signed.hex)
if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
list(APPEND confirmed_args --hex --shex ${output}.signed.confirmed.hex)
list(APPEND byproducts ${output}.signed.confirmed.hex)
endif()
endif()
# Add the west sign calls and their byproducts to the post-processing
# steps for zephyr.elf.
#
# CMake guarantees that multiple COMMANDs given to
# add_custom_command() are run in order, so adding the 'west sign'
# calls to the "extra_post_build_commands" property ensures they run
# after the commands which generate the unsigned versions.
set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
${west_sign} ${unconfirmed_args} ${imgtool_args})
if(confirmed_args)
set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
${west_sign} ${confirmed_args} ${imgtool_args} --confirm)
endif()
set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts ${byproducts})
endfunction()
zephyr_mcuboot_tasks()