From ed19ffa124f23fbdfd961886f8dd80228d848795 Mon Sep 17 00:00:00 2001 From: Zhiyong Li Date: Fri, 31 Jan 2025 07:51:45 -0800 Subject: [PATCH 1/2] update mbed cmake script to automatically sign & encrypt images --- boot/mbed/CMakeLists.txt | 6 ++-- boot/mbed/mcuboot_imgtool.cmake | 52 +++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/boot/mbed/CMakeLists.txt b/boot/mbed/CMakeLists.txt index 05199c380..66be70b6a 100644 --- a/boot/mbed/CMakeLists.txt +++ b/boot/mbed/CMakeLists.txt @@ -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 diff --git a/boot/mbed/mcuboot_imgtool.cmake b/boot/mbed/mcuboot_imgtool.cmake index 9760196fe..2e7fa5b73 100644 --- a/boot/mbed/mcuboot_imgtool.cmake +++ b/boot/mbed/mcuboot_imgtool.cmake @@ -62,13 +62,13 @@ function(_mcuboot_generate_image TARGET IMAGE_TYPE IMAGE_BASE_PATH) set(TARGET_HEX_FILE ${CMAKE_CURRENT_BINARY_DIR}/$.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}) @@ -76,11 +76,12 @@ function(_mcuboot_generate_image TARGET IMAGE_TYPE IMAGE_BASE_PATH) 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() @@ -88,7 +89,6 @@ function(_mcuboot_generate_image TARGET IMAGE_TYPE IMAGE_BASE_PATH) add_custom_command( TARGET ${TARGET} POST_BUILD - DEPENDS ${MCUBOOT_SIGNING_KEY_ABSPATH} COMMAND ${Python3_EXECUTABLE} -m imgtool.main sign @@ -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) # @@ -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 +
, but we actually want to upload to . # 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}) @@ -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) \ No newline at end of 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) From 6723e39d45af70b6e75f7defc556a8587d509bf8 Mon Sep 17 00:00:00 2001 From: Zhiyong Li Date: Fri, 31 Jan 2025 07:55:04 -0800 Subject: [PATCH 2/2] updated documentation on imgtool and image encryption --- docs/encrypted_images.md | 26 ++++++++++++++++++-------- docs/imgtool.md | 14 ++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/docs/encrypted_images.md b/docs/encrypted_images.md index 85d26d8e1..9a3f35c77 100644 --- a/docs/encrypted_images.md +++ b/docs/encrypted_images.md @@ -149,14 +149,24 @@ occurs and the information is spread across multiple areas. ## [Creating your keys with imgtool](#creating-your-keys-with-imgtool) -`imgtool` can generate keys by using `imgtool keygen -k -t `, - 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 -e `, 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 -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. diff --git a/docs/imgtool.md b/docs/imgtool.md index b4dc3b554..a86d6860f 100644 --- a/docs/imgtool.md +++ b/docs/imgtool.md @@ -85,6 +85,10 @@ primary slot and adds a header and trailer that the bootloader is expecting: firmware). [max. 12 characters] --overwrite-only Use overwrite-only instead of swap upgrades -e, --endian [little|big] Select little or big endian + -c, --clear Output a non-encrypted image with encryption + capabilities,so it can be installed in the + primary slot, and encrypted when swapped to + the secondary. -E, --encrypt filename Encrypt image using the provided public key --save-enctlv When upgrading, save encrypted key TLVs instead of plain keys. Enable when @@ -133,3 +137,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.