Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mbed: update cmake script to sign and encrypt images post build #2195

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions boot/mbed/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ mcuboot_generate_signing_keys_file(${CMAKE_CURRENT_BINARY_DIR}/signing_keys.c)
target_sources(${LIB_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/signing_keys.c)

if("MCUBOOT_ENCRYPT_RSA=1" IN_LIST MBED_CONFIG_DEFINITIONS)
mcuboot_generate_encryption_key_file(${CMAKE_CURRENT_BINARY_DIR}/enc_keys.c)
target_sources(${LIB_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/enc_keys.c)
set(MCUBOOT_ENCRYPTION_PUBLIC_KEY_PATH ${CMAKE_CURRENT_BINARY_DIR}/enc_key_public.pem CACHE INTERNAL "Path to mcuboot encryption public key" FORCE)
mcuboot_generate_encryption_public_key_file(${MCUBOOT_ENCRYPTION_PUBLIC_KEY_PATH})
mcuboot_generate_encryption_private_key_file(${CMAKE_CURRENT_BINARY_DIR}/enc_key_private.c)
target_sources(${LIB_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/enc_key_private.c)
endif()

# The cross-dependency requires that bootutil have access to the mbed port's
Expand Down
52 changes: 40 additions & 12 deletions boot/mbed/mcuboot_imgtool.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -62,33 +62,33 @@ function(_mcuboot_generate_image TARGET IMAGE_TYPE IMAGE_BASE_PATH)
set(TARGET_HEX_FILE ${CMAKE_CURRENT_BINARY_DIR}/$<TARGET_FILE_BASE_NAME:${TARGET}>.hex)

# Grab header size
if(NOT "${MBED_CONFIG_DEFINITIONS}" MATCHES "MCUBOOT_HEADER_SIZE=(0x[0-9A-Fa-f]+)")
if(NOT "${MBED_CONFIG_DEFINITIONS}" MATCHES "MCUBOOT_HEADER_SIZE=((0x[0-9A-Fa-f]+)|([0-9]+))")
message(FATAL_ERROR "Couldn't find MCUBOOT_HEADER_SIZE in Mbed configuration!")
endif()
set(HEADER_SIZE_HEX ${CMAKE_MATCH_1})

# Grab slot size
if(NOT "${MBED_CONFIG_DEFINITIONS}" MATCHES "MCUBOOT_SLOT_SIZE=(0x[0-9A-Fa-f]+)")
if(NOT "${MBED_CONFIG_DEFINITIONS}" MATCHES "MCUBOOT_SLOT_SIZE=((0x[0-9A-Fa-f]+)|([0-9]+))")
message(FATAL_ERROR "Couldn't find MCUBOOT_SLOT_SIZE in Mbed configuration!")
endif()
set(SLOT_SIZE_HEX ${CMAKE_MATCH_1})

get_property(objcopy GLOBAL PROPERTY ELF2BIN)

if(${IMAGE_TYPE} STREQUAL "update" AND "MCUBOOT_ENCRYPT_RSA=1" IN_LIST MBED_CONFIG_DEFINITIONS)
set(IMGTOOL_EXTRA_ARGS --encrypt ${MCUBOOT_ENCRYPTION_KEY_ABSPATH})
# MCUBOOT_ENCRYPTION_PUBLIC_KEY_PATH is set in CMakeLists.txt
set(IMGTOOL_EXTRA_ARGS --encrypt ${MCUBOOT_ENCRYPTION_PUBLIC_KEY_PATH})
elseif(${IMAGE_TYPE} STREQUAL "initial" AND "MCUBOOT_ENCRYPT_RSA=1" IN_LIST MBED_CONFIG_DEFINITIONS)
# If encryption is enabled, generate unencrypted initial image which supports encryption.
# See https://github.com/mbed-ce/mbed-os/issues/401#issuecomment-2567099213
set(IMGTOOL_EXTRA_ARGS --clear)
set(IMGTOOL_EXTRA_ARGS --encrypt ${MCUBOOT_ENCRYPTION_PUBLIC_KEY_PATH} --clear)
else()
set(IMGTOOL_EXTRA_ARGS "")
endif()

add_custom_command(
TARGET ${TARGET}
POST_BUILD
DEPENDS ${MCUBOOT_SIGNING_KEY_ABSPATH}
COMMAND
${Python3_EXECUTABLE} -m imgtool.main
sign
Expand All @@ -115,6 +115,9 @@ function(_mcuboot_generate_image TARGET IMAGE_TYPE IMAGE_BASE_PATH)
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
VERBATIM
)
if("MCUBOOT_ENCRYPT_RSA=1" IN_LIST MBED_CONFIG_DEFINITIONS)
add_dependencies(${TARGET} mcuboot-gen-enc-public-key)
endif()
endfunction(_mcuboot_generate_image)

#
Expand All @@ -141,7 +144,7 @@ function(mcuboot_generate_initial_image TARGET) # optional 2nd arg: initial imag
# We need to be slightly creative here -- Mbed thinks that the application start address
# is <primary slot address> + <header size>, but we actually want to upload to <primary slot address>.
# So we need to temporarily override MBED_UPLOAD_BASE_ADDR with an offset value
if(NOT "${MBED_CONFIG_DEFINITIONS}" MATCHES "MCUBOOT_HEADER_SIZE=(0x[0-9A-Fa-f]+)")
if(NOT "${MBED_CONFIG_DEFINITIONS}" MATCHES "MCUBOOT_HEADER_SIZE=((0x[0-9A-Fa-f]+)|([0-9]+))")
message(FATAL_ERROR "Couldn't find MCUBOOT_HEADER_SIZE in Mbed configuration!")
endif()
set(HEADER_SIZE_HEX ${CMAKE_MATCH_1})
Expand Down Expand Up @@ -202,18 +205,43 @@ endfunction(mcuboot_generate_signing_keys_file)
# Generate a C source file with the encryption private key in it at the given location.
# The file should be added as a source file to a library built in the same directory.
#
function(mcuboot_generate_encryption_key_file ENC_KEY_C_PATH)
function(mcuboot_generate_encryption_private_key_file ENC_PRIVATE_KEY_C_PATH)
add_custom_command(
OUTPUT ${ENC_KEY_C_PATH}
OUTPUT ${ENC_PRIVATE_KEY_C_PATH}
COMMAND
${Python3_EXECUTABLE} -m imgtool.main
getpriv
--key ${MCUBOOT_SIGNING_KEY_ABSPATH}
> ${ENC_KEY_C_PATH}
--key ${MCUBOOT_ENCRYPTION_KEY_ABSPATH}
> ${ENC_PRIVATE_KEY_C_PATH}

DEPENDS ${MCUBOOT_SIGNING_KEY_ABSPATH}
DEPENDS ${MCUBOOT_ENCRYPTION_KEY_ABSPATH}
COMMENT "Converting encryption key to C source..."
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
)
endfunction(mcuboot_generate_encryption_key_file)
endfunction(mcuboot_generate_encryption_private_key_file)

#
# Generate a PEM file with the encryption public key in it
# This is a temporal file, should be stored in the build folder
#
function(mcuboot_generate_encryption_public_key_file ENC_PUBLIC_KEY_PATH)
add_custom_command(
OUTPUT ${ENC_PUBLIC_KEY_PATH}
COMMAND
${Python3_EXECUTABLE} -m imgtool.main
getpub
--key ${MCUBOOT_ENCRYPTION_KEY_ABSPATH}
--encoding pem
> ${ENC_PUBLIC_KEY_PATH}

DEPENDS ${MCUBOOT_ENCRYPTION_KEY_ABSPATH}
COMMENT "Extracting encryption public key to PEM format..."
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
VERBATIM
)
# Custom target to ensure that public key gets generated
add_custom_target(mcuboot-gen-enc-public-key
ALL
DEPENDS ${ENC_PUBLIC_KEY_PATH})
endfunction(mcuboot_generate_encryption_public_key_file)
26 changes: 18 additions & 8 deletions docs/encrypted_images.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,24 @@ Append it with the `--clear` flag to keep the image unencrypted and ready for us

## [Creating your keys with imgtool](#creating-your-keys-with-imgtool)

`imgtool` can generate keys by using `imgtool keygen -k <output.pem> -t <type>`,
where type can be one of `rsa-2048`, `rsa-3072`, `ecdsa-p256`
or `ed25519`. This will generate a keypair or private key.

To extract the public key in source file form, use
`imgtool getpub -k <input.pem> -e <encoding>`, where `encoding` can be one of
`lang-c` or `lang-rust` (defaults to `lang-c`). To extract a public key in PEM
format, use `imgtool getpub -k <input.pem> -e pem`.
`imgtool` can be used to generate keys used for image encryption, similar to
how to generate keys for imaging signing:
```
./scripts/imgtool.py keygen -k encryption-keys.pem -t rsa-2048
```
The type of keys to generate will depend on which type of encryption is supported.
For mbed-os and mbed-ce ports, only RSA is currently supported.

Once an encryption key is generated, the next step is to extract the private key into
c format, and incorporate into your source files:
```
./scripts/imgtool.py getpriv -k encryption-keys.pem -f openssl >> enc-key-priv.c
```
The final step is to extract public key and pass it to `imgtool` during image signing
and encryption process.
```
./scripts/imgtool.py getpub -k encryption-keys.pem -e pem -o enc-key-pub.pem
```

If using AES-KW, follow the steps in the next section to generate the
required keys.
Expand Down
10 changes: 10 additions & 0 deletions docs/imgtool.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,13 @@ public key is incorporated into the bootloader). When the `full` option is used
instead, the TLV area will contain the whole public key and thus the bootloader
can be independent from the key(s). For more information on the additional
requirements of this option, see the [design](design.md) document.

The encryption key passed to `--encrypt` argument shall be derived from a
different key (not the sign key) per NIST recommendation, please refer to discussion
[here](https://github.com/mcu-tools/mcuboot/pull/2152#issuecomment-2581420713). Also
an extra tag `--clear` shall be provided to generate initial download images
that are not encrypted but support encryption during firmware upgrade, otherwise when
upgrading to encrypted images for the first time, an unencrypted image will be saved into
secondary slot, please refer to discussion [here](https://github.com/mcu-tools/mcuboot/issues/1555).
Please also refer to now partially updated documentation on [encrypted images](encrypted_images.md)
on how to generate and manage keys used for image encryption.