From fe8bce7ae4bbc51591d77ace3615cf2bf58b18f2 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 25 Sep 2024 14:55:11 +0000 Subject: [PATCH 01/10] Revert "[nrf noup] crypto: ecdsa: Fix shared crypto MCUBoot EXT_ABI" This reverts commit 895c76beb540d91cd9ddb53198bbfde0089c36d4. Signed-off-by: Dominik Ermel --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 450450dc3..eb3e33ee0 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -73,7 +73,7 @@ #if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) #include - #define NUM_ECC_BYTES (256 / 8) + #define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8) #endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ #ifdef __cplusplus @@ -81,8 +81,7 @@ extern "C" { #endif #if (defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || \ - defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)) \ - && !defined(MCUBOOT_USE_PSA_CRYPTO) + defined(MCUBOOT_USE_CC310)) && !defined(MCUBOOT_USE_PSA_CRYPTO) /* * Declaring these like this adds NULL termination. */ @@ -623,45 +622,43 @@ static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) -typedef uintptr_t bootutil_ecdsa_context; -static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) +typedef uintptr_t bootutil_ecdsa_p256_context; + +static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx) { (void)ctx; } -static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx) +static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx) { (void)ctx; } -static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, - uint8_t *pk, size_t pk_len, - uint8_t *hash, size_t hash_len, - uint8_t *sig, size_t sig_len) +static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, + uint8_t *pk, size_t pk_len, + uint8_t *hash, + uint8_t *sig, size_t sig_len) { (void)ctx; (void)pk_len; - (void)hash_len; uint8_t dsig[2 * NUM_ECC_BYTES]; if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { return -1; } - /* Only support uncompressed keys. */ - if (pk[0] != 0x04) { - return -1; - } - pk++; + /* As described on the compact representation in IETF protocols, + * the first byte of the key defines if the ECC points are + * compressed (0x2 or 0x3) or uncompressed (0x4). + * We only support uncompressed keys. + */ + if (pk[0] != 0x04) + return -1; - return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, pk, dsig); -} + pk++; -static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, - uint8_t **cp,uint8_t *end) -{ - (void)ctx; - return bootutil_import_key(cp, end); + return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, + pk, dsig); } #endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ From a69bd8330bf8eba1b432d42f8fee01e4a386f4de Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 25 Sep 2024 14:55:28 +0000 Subject: [PATCH 02/10] Revert "[nrf noup] crypto: ecdsa: Add required signature decoding" This reverts commit a42e9cc5fa46b614e60353d6a255984f72ab4d7e. Signed-off-by: Dominik Ermel --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index eb3e33ee0..5e79cd1bf 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -133,6 +133,8 @@ static int bootutil_import_key(uint8_t **cp, uint8_t *end) } #endif /* (MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310) && !MCUBOOT_USE_PSA_CRYPTO */ +#if defined(MCUBOOT_USE_TINYCRYPT) +#ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG /* * cp points to ASN1 string containing an integer. * Verify the tag, and that the length is 32 bytes. Helper function. @@ -182,8 +184,8 @@ static int bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp } return 0; } +#endif /* not MCUBOOT_ECDSA_NEED_ASN1_SIG */ -#if defined(MCUBOOT_USE_TINYCRYPT) typedef uintptr_t bootutil_ecdsa_context; static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) { @@ -252,12 +254,8 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, { (void)ctx; (void)pk_len; + (void)sig_len; (void)hash_len; - uint8_t dsig[2 * NUM_ECC_BYTES]; - - if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { - return -1; - } /* Only support uncompressed keys. */ if (pk[0] != 0x04) { @@ -265,7 +263,7 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, } pk++; - return cc310_ecdsa_verify_secp256r1(hash, pk, dsig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); + return cc310_ecdsa_verify_secp256r1(hash, pk, sig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); } static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, @@ -641,11 +639,7 @@ static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, { (void)ctx; (void)pk_len; - uint8_t dsig[2 * NUM_ECC_BYTES]; - - if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { - return -1; - } + (void)sig_len; /* As described on the compact representation in IETF protocols, * the first byte of the key defines if the ECC points are @@ -658,7 +652,7 @@ static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, pk++; return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, - pk, dsig); + pk, sig); } #endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ From 75871be85adf0f24b041e6cfc861b2b361423f7c Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 26 Sep 2024 10:57:11 +0000 Subject: [PATCH 03/10] Revert "[nrf noup] zephyr: disabled EXT_API_ATLEAST_OPTIONAL" This reverts commit cc42516352e797433e6e0413fc41e08d2b583739. Signed-off-by: Dominik Ermel --- boot/zephyr/external_crypto.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/external_crypto.conf b/boot/zephyr/external_crypto.conf index 8181ad51c..c362f000a 100644 --- a/boot/zephyr/external_crypto.conf +++ b/boot/zephyr/external_crypto.conf @@ -18,3 +18,4 @@ CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y CONFIG_SB_CRYPTO_CLIENT_SHA256=y CONFIG_BL_SHA256_EXT_API_REQUIRED=y CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y +CONFIG_EXT_API_PROVIDE_EXT_API_ATLEAST_OPTIONAL=y From b1b90f1da50d775ecd54546e83426806938ab566 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 26 Sep 2024 10:57:23 +0000 Subject: [PATCH 04/10] Revert "[nrf noup] zephyr: Set at least provide EXT_API" This reverts commit ff5338297c4be31e757f99d8cf5730b05a5cbed6. Signed-off-by: Dominik Ermel --- boot/zephyr/external_crypto.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/external_crypto.conf b/boot/zephyr/external_crypto.conf index c362f000a..8181ad51c 100644 --- a/boot/zephyr/external_crypto.conf +++ b/boot/zephyr/external_crypto.conf @@ -18,4 +18,3 @@ CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y CONFIG_SB_CRYPTO_CLIENT_SHA256=y CONFIG_BL_SHA256_EXT_API_REQUIRED=y CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y -CONFIG_EXT_API_PROVIDE_EXT_API_ATLEAST_OPTIONAL=y From 4995e750bcba8d05616ea0e34356e1ac9aef17a7 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 26 Sep 2024 10:57:50 +0000 Subject: [PATCH 05/10] Revert "[nrf noup] boot: Add shared crypto for ECDSA and SHA" This reverts commit 0faa8b2bb51bd58c9a1d3470f78f7b4136999652. Signed-off-by: Dominik Ermel --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 43 ------------------- boot/bootutil/include/bootutil/crypto/sha.h | 32 -------------- boot/zephyr/CMakeLists.txt | 2 - boot/zephyr/external_crypto.conf | 20 --------- .../include/mcuboot_config/mcuboot_config.h | 5 ++- 5 files changed, 3 insertions(+), 99 deletions(-) delete mode 100644 boot/zephyr/external_crypto.conf diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 5e79cd1bf..5a87f736b 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -34,7 +34,6 @@ #if (defined(MCUBOOT_USE_TINYCRYPT) + \ defined(MCUBOOT_USE_CC310) + \ - defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1 #error "One crypto backend must be defined: either CC310/TINYCRYPT/MBED_TLS/PSA_CRYPTO" #endif @@ -71,11 +70,6 @@ #include "bootutil/sign_key.h" #include "common.h" -#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) - #include - #define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8) -#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ - #ifdef __cplusplus extern "C" { #endif @@ -619,43 +613,6 @@ static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ -#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) -typedef uintptr_t bootutil_ecdsa_p256_context; - -static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx) -{ - (void)ctx; -} - -static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx) -{ - (void)ctx; -} - -static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, - uint8_t *pk, size_t pk_len, - uint8_t *hash, - uint8_t *sig, size_t sig_len) -{ - (void)ctx; - (void)pk_len; - (void)sig_len; - - /* As described on the compact representation in IETF protocols, - * the first byte of the key defines if the ECC points are - * compressed (0x2 or 0x3) or uncompressed (0x4). - * We only support uncompressed keys. - */ - if (pk[0] != 0x04) - return -1; - - pk++; - - return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, - pk, sig); -} -#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ - #ifdef __cplusplus } #endif diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index 28e827fea..9ce54bee5 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -30,7 +30,6 @@ #if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS) + \ defined(MCUBOOT_USE_TINYCRYPT) + \ - defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_CC310)) != 1 #error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO" #endif @@ -207,37 +206,6 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, } #endif /* MCUBOOT_USE_CC310 */ -#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) - -#include - -typedef bl_sha256_ctx_t bootutil_sha_context; - -static inline void bootutil_sha_init(bootutil_sha_context *ctx) -{ - bl_sha256_init(ctx); -} - -static inline void bootutil_sha_drop(bootutil_sha_context *ctx) -{ - (void)ctx; -} - -static inline int bootutil_sha_update(bootutil_sha_context *ctx, - const void *data, - uint32_t data_len) -{ - return bl_sha256_update(ctx, data, data_len); -} - -static inline int bootutil_sha_finish(bootutil_sha_context *ctx, - uint8_t *output) -{ - bl_sha256_finalize(ctx, output); - return 0; -} -#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ - #ifdef __cplusplus } #endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index c26633d11..382c98d9e 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -171,8 +171,6 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) zephyr_library_sources(${MCUBOOT_NRF_EXT_DIR}/cc310_glue.c) zephyr_library_include_directories(${MCUBOOT_NRF_EXT_DIR}) zephyr_link_libraries(nrfxlib_crypto) - elseif(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) - zephyr_include_directories(${BL_CRYPTO_DIR}/../include) endif() # Since here we are not using Zephyr's mbedTLS but rather our own, we need diff --git a/boot/zephyr/external_crypto.conf b/boot/zephyr/external_crypto.conf deleted file mode 100644 index 8181ad51c..000000000 --- a/boot/zephyr/external_crypto.conf +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2021 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause -# - -# These configurations should be used when using nrf/samples/bootloader -# as the immutable bootloader (B0), and MCUBoot as the second stage updateable -# bootloader. - -# Set ECDSA as signing mechanism -CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y - -# Use crypto backend from B0 -CONFIG_BOOT_NRF_EXTERNAL_CRYPTO=y -CONFIG_SECURE_BOOT_CRYPTO=y -CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y -CONFIG_SB_CRYPTO_CLIENT_SHA256=y -CONFIG_BL_SHA256_EXT_API_REQUIRED=y -CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 824e83b75..2f0cc243c 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -40,8 +40,9 @@ #define MCUBOOT_USE_TINYCRYPT #elif defined(CONFIG_BOOT_USE_CC310) #define MCUBOOT_USE_CC310 -#elif defined(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) -#define MCUBOOT_USE_NRF_EXTERNAL_CRYPTO +#ifdef CONFIG_BOOT_USE_NRF_CC310_BL +#define MCUBOOT_USE_NRF_CC310_BL +#endif #endif /* Zephyr, regardless of C library used, provides snprintf */ From e50adcb6e1524f05f16ab2136368c3946c5e286e Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Mon, 20 May 2024 08:47:02 +0200 Subject: [PATCH 06/10] [nrf fromtree] boot: SHA512 verification adds TLV and Kconfig to decouple verification from other options. Signed-off-by: Mateusz Michalek Signed-off-by: Dominik Ermel (cherry picked from commit 41df52e6906172ed3398b1478e4809abfc2bc3e2) --- boot/bootutil/include/bootutil/crypto/sha.h | 15 +++-- boot/bootutil/include/bootutil/image.h | 1 + boot/bootutil/src/image_validate.c | 1 + boot/zephyr/Kconfig | 56 +++++++++++++++++++ .../include/mcuboot_config/mcuboot_config.h | 10 ++++ 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index 9ce54bee5..28499ed6a 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -34,13 +34,16 @@ #error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO" #endif -#if defined(MCUBOOT_SIGN_EC384) +#if defined(MCUBOOT_SHA512) + #define IMAGE_HASH_SIZE (64) + #define EXPECTED_HASH_TLV IMAGE_TLV_SHA512 +#elif defined(MCUBOOT_SIGN_EC384) #define IMAGE_HASH_SIZE (48) #define EXPECTED_HASH_TLV IMAGE_TLV_SHA384 #else #define IMAGE_HASH_SIZE (32) #define EXPECTED_HASH_TLV IMAGE_TLV_SHA256 -#endif /* MCUBOOT_SIGN_EC384 */ +#endif /* MCUBOOT_SIGN */ /* Universal defines for SHA-256 */ #define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64) @@ -82,7 +85,9 @@ typedef psa_hash_operation_t bootutil_sha_context; static inline int bootutil_sha_init(bootutil_sha_context *ctx) { *ctx = psa_hash_operation_init(); -#if defined(MCUBOOT_SIGN_EC384) +#if defined(MCUBOOT_SHA512) + psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_512); +#elif defined(MCUBOOT_SIGN_EC384) psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_384); #else psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_256); @@ -107,7 +112,9 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, { size_t hash_length = 0; /* Assumes the output buffer is at least the expected size of the hash */ -#if defined(MCUBOOT_SIGN_EC384) +#if defined(MCUBOOT_SHA512) + return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_512), &hash_length); +#elif defined(MCUBOOT_SIGN_EC384) return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_384), &hash_length); #else return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &hash_length); diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 3e03f80dd..9ede800a2 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -96,6 +96,7 @@ struct flash_area; #define IMAGE_TLV_PUBKEY 0x02 /* public key */ #define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ #define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */ +#define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */ #define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */ #define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */ #define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 81782edf2..5043d385a 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -368,6 +368,7 @@ static const uint16_t allowed_unprot_tlvs[] = { IMAGE_TLV_PUBKEY, IMAGE_TLV_SHA256, IMAGE_TLV_SHA384, + IMAGE_TLV_SHA512, IMAGE_TLV_RSA2048_PSS, IMAGE_TLV_ECDSA224, IMAGE_TLV_ECDSA_SIG, diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 28f40bf52..8b35ab18c 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -27,6 +27,12 @@ config BOOT_USE_MBEDTLS help Use mbedTLS for crypto primitives. +config BOOT_USE_PSA_CRYPTO + bool + # Hidden option + help + Hidden option set if using PSA crypt for cryptography functionality + config BOOT_USE_TINYCRYPT bool # Hidden option @@ -70,6 +76,52 @@ config SINGLE_APPLICATION_SLOT uploading a new application overwrites the one that previously occupied the area. +config BOOT_IMG_HASH_ALG_SHA256_ALLOW + bool + help + Hidden option set by configurations that allow SHA256 + +config BOOT_IMG_HASH_ALG_SHA384_ALLOW + bool + help + Hidden option set by configurations that allow SHA384 + +config BOOT_IMG_HASH_ALG_SHA512_ALLOW + bool + depends on BOOT_USE_PSA_CRYPTO + help + Hidden option set by configurations that allow SHA512 + +choice BOOT_IMG_HASH_ALG + prompt "Selected image hash algorithm" + default BOOT_IMG_HASH_ALG_SHA256 if BOOT_IMG_HASH_ALG_SHA256_ALLOW + default BOOT_IMG_HASH_ALG_SHA384 if BOOT_IMG_HASH_ALG_SHA384_ALLOW + default BOOT_IMG_HASH_ALG_SHA512 if BOOT_IMG_HASH_ALG_SHA512_ALLOW + help + Hash algorithm used for image verification. Selection + here may be limited by other configurations, like for + example selected cryptographic signature. + +config BOOT_IMG_HASH_ALG_SHA256 + bool "SHA256" + depends on BOOT_IMG_HASH_ALG_SHA256_ALLOW + help + SHA256 algorithm + +config BOOT_IMG_HASH_ALG_SHA384 + bool "SHA384" + depends on BOOT_IMG_HASH_ALG_SHA384_ALLOW + help + SHA384 algorithm + +config BOOT_IMG_HASH_ALG_SHA512 + bool "SHA512" + depends on BOOT_IMG_HASH_ALG_SHA512_ALLOW + help + SHA512 algorithm + +endchoice # BOOT_IMG_HASH_ALG + choice BOOT_SIGNATURE_TYPE prompt "Signature type" default BOOT_SIGNATURE_TYPE_RSA @@ -77,12 +129,14 @@ choice BOOT_SIGNATURE_TYPE config BOOT_SIGNATURE_TYPE_NONE bool "No signature; use only hash check" select BOOT_USE_TINYCRYPT + select BOOT_IMG_HASH_ALG_SHA256_ALLOW config BOOT_SIGNATURE_TYPE_RSA bool "RSA signatures" select BOOT_USE_MBEDTLS select MBEDTLS select BOOT_ENCRYPTION_SUPPORT + select BOOT_IMG_HASH_ALG_SHA256_ALLOW if BOOT_SIGNATURE_TYPE_RSA config BOOT_SIGNATURE_TYPE_RSA_LEN @@ -94,6 +148,7 @@ endif config BOOT_SIGNATURE_TYPE_ECDSA_P256 bool "Elliptic curve digital signatures with curve P-256" select BOOT_ENCRYPTION_SUPPORT + select BOOT_IMG_HASH_ALG_SHA256_ALLOW if BOOT_SIGNATURE_TYPE_ECDSA_P256 choice BOOT_ECDSA_IMPLEMENTATION @@ -117,6 +172,7 @@ endif config BOOT_SIGNATURE_TYPE_ED25519 bool "Edwards curve digital signatures using ed25519" select BOOT_ENCRYPTION_SUPPORT + select BOOT_IMG_HASH_ALG_SHA256_ALLOW if BOOT_SIGNATURE_TYPE_ED25519 choice BOOT_ED25519_IMPLEMENTATION diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 2f0cc243c..49820ed7c 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -43,6 +43,16 @@ #ifdef CONFIG_BOOT_USE_NRF_CC310_BL #define MCUBOOT_USE_NRF_CC310_BL #endif +#elif defined(CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT) +#define MCUBOOT_USE_PSA_CRYPTO +#endif + +#ifdef CONFIG_BOOT_IMG_HASH_ALG_SHA512 +#define MCUBOOT_SHA512 +#endif + +#ifdef CONFIG_BOOT_IMG_HASH_ALG_SHA256 +#define MCUBOOT_SHA256 #endif /* Zephyr, regardless of C library used, provides snprintf */ From 8f4b9e031bffb4dcff0361e7d4ead9d048266e98 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 14 Feb 2019 13:20:34 +0100 Subject: [PATCH 07/10] [nrf noup] boot: Add shared crypto for ECDSA and SHA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add functions for ecdsa_verify_secp256r1 and sha256 to use the shared crypto API * Add Kconfig and CMake variables for selecting shared crypto when using ecdsa * Add custom section to project for placing the API section in the correct location in flash * Add kconfig fragment for using external crypto Signed-off-by: Sigvart Hovland Signed-off-by: Martí Bolívar Signed-off-by: Emil Obalski Signed-off-by: Andrzej Puzdrowski Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Trond Einar Snekvik Signed-off-by: Georgios Vasilakis Signed-off-by: Johann Fischer Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 55683e3133b6a801a7bb7feb55d24be81ecccdbb) (cherry picked from commit 0faa8b2bb51bd58c9a1d3470f78f7b4136999652) (cherry picked from commit a42e9cc5fa46b614e60353d6a255984f72ab4d7e) (cherry picked from commit 895c76beb540d91cd9ddb53198bbfde0089c36d4) (cherry picked from commit ff5338297c4be31e757f99d8cf5730b05a5cbed6) (cherry picked from commit cc42516352e797433e6e0413fc41e08d2b583739) --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 64 +++++++++++++++++-- boot/bootutil/include/bootutil/crypto/sha.h | 32 ++++++++++ boot/zephyr/CMakeLists.txt | 2 + boot/zephyr/external_crypto.conf | 20 ++++++ .../include/mcuboot_config/mcuboot_config.h | 5 +- 5 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 boot/zephyr/external_crypto.conf diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 5a87f736b..450450dc3 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -34,6 +34,7 @@ #if (defined(MCUBOOT_USE_TINYCRYPT) + \ defined(MCUBOOT_USE_CC310) + \ + defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1 #error "One crypto backend must be defined: either CC310/TINYCRYPT/MBED_TLS/PSA_CRYPTO" #endif @@ -70,12 +71,18 @@ #include "bootutil/sign_key.h" #include "common.h" +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + #include + #define NUM_ECC_BYTES (256 / 8) +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus extern "C" { #endif #if (defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || \ - defined(MCUBOOT_USE_CC310)) && !defined(MCUBOOT_USE_PSA_CRYPTO) + defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)) \ + && !defined(MCUBOOT_USE_PSA_CRYPTO) /* * Declaring these like this adds NULL termination. */ @@ -127,8 +134,6 @@ static int bootutil_import_key(uint8_t **cp, uint8_t *end) } #endif /* (MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310) && !MCUBOOT_USE_PSA_CRYPTO */ -#if defined(MCUBOOT_USE_TINYCRYPT) -#ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG /* * cp points to ASN1 string containing an integer. * Verify the tag, and that the length is 32 bytes. Helper function. @@ -178,8 +183,8 @@ static int bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp } return 0; } -#endif /* not MCUBOOT_ECDSA_NEED_ASN1_SIG */ +#if defined(MCUBOOT_USE_TINYCRYPT) typedef uintptr_t bootutil_ecdsa_context; static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) { @@ -248,8 +253,12 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, { (void)ctx; (void)pk_len; - (void)sig_len; (void)hash_len; + uint8_t dsig[2 * NUM_ECC_BYTES]; + + if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { + return -1; + } /* Only support uncompressed keys. */ if (pk[0] != 0x04) { @@ -257,7 +266,7 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, } pk++; - return cc310_ecdsa_verify_secp256r1(hash, pk, sig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); + return cc310_ecdsa_verify_secp256r1(hash, pk, dsig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); } static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, @@ -613,6 +622,49 @@ static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) +typedef uintptr_t bootutil_ecdsa_context; +static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) +{ + (void)ctx; +} + +static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx) +{ + (void)ctx; +} + +static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, + uint8_t *pk, size_t pk_len, + uint8_t *hash, size_t hash_len, + uint8_t *sig, size_t sig_len) +{ + (void)ctx; + (void)pk_len; + (void)hash_len; + uint8_t dsig[2 * NUM_ECC_BYTES]; + + if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { + return -1; + } + + /* Only support uncompressed keys. */ + if (pk[0] != 0x04) { + return -1; + } + pk++; + + return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, pk, dsig); +} + +static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, + uint8_t **cp,uint8_t *end) +{ + (void)ctx; + return bootutil_import_key(cp, end); +} +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index 28499ed6a..aeedff40e 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -30,6 +30,7 @@ #if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS) + \ defined(MCUBOOT_USE_TINYCRYPT) + \ + defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_CC310)) != 1 #error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO" #endif @@ -213,6 +214,37 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, } #endif /* MCUBOOT_USE_CC310 */ +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + +#include + +typedef bl_sha256_ctx_t bootutil_sha_context; + +static inline void bootutil_sha_init(bootutil_sha_context *ctx) +{ + bl_sha256_init(ctx); +} + +static inline void bootutil_sha_drop(bootutil_sha_context *ctx) +{ + (void)ctx; +} + +static inline int bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) +{ + return bl_sha256_update(ctx, data, data_len); +} + +static inline int bootutil_sha_finish(bootutil_sha_context *ctx, + uint8_t *output) +{ + bl_sha256_finalize(ctx, output); + return 0; +} +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus } #endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 382c98d9e..c26633d11 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -171,6 +171,8 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) zephyr_library_sources(${MCUBOOT_NRF_EXT_DIR}/cc310_glue.c) zephyr_library_include_directories(${MCUBOOT_NRF_EXT_DIR}) zephyr_link_libraries(nrfxlib_crypto) + elseif(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) + zephyr_include_directories(${BL_CRYPTO_DIR}/../include) endif() # Since here we are not using Zephyr's mbedTLS but rather our own, we need diff --git a/boot/zephyr/external_crypto.conf b/boot/zephyr/external_crypto.conf new file mode 100644 index 000000000..8181ad51c --- /dev/null +++ b/boot/zephyr/external_crypto.conf @@ -0,0 +1,20 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# These configurations should be used when using nrf/samples/bootloader +# as the immutable bootloader (B0), and MCUBoot as the second stage updateable +# bootloader. + +# Set ECDSA as signing mechanism +CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y + +# Use crypto backend from B0 +CONFIG_BOOT_NRF_EXTERNAL_CRYPTO=y +CONFIG_SECURE_BOOT_CRYPTO=y +CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y +CONFIG_SB_CRYPTO_CLIENT_SHA256=y +CONFIG_BL_SHA256_EXT_API_REQUIRED=y +CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 49820ed7c..9d58436d2 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -40,11 +40,10 @@ #define MCUBOOT_USE_TINYCRYPT #elif defined(CONFIG_BOOT_USE_CC310) #define MCUBOOT_USE_CC310 -#ifdef CONFIG_BOOT_USE_NRF_CC310_BL -#define MCUBOOT_USE_NRF_CC310_BL -#endif #elif defined(CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT) #define MCUBOOT_USE_PSA_CRYPTO +#elif defined(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) +#define MCUBOOT_USE_NRF_EXTERNAL_CRYPTO #endif #ifdef CONFIG_BOOT_IMG_HASH_ALG_SHA512 From 1d14eb5864e79f8afc8380c9faa8e4d931a2fcc5 Mon Sep 17 00:00:00 2001 From: Rustam Ismayilov Date: Mon, 27 Nov 2023 21:44:54 +0100 Subject: [PATCH 08/10] [nrf fromtree] imgtool: Fix verify command for edcsa-p384 signed images Fixed hash algorithm defaults to SHA256 in case no key provided. Verification improved by adding check for key - tlv mismatch, VerifyResult.KEY_MISMATCH added to indicate this case. Multiple styling fixes and import optimisation, exception handling. Signed-off-by: Rustam Ismayilov Change-Id: I61a588de5b39678707c0179f4edaa411ceb67c8e (cherry picked from commit 36f8bf3085cd013b0abdd29331d08c9bbe796ca9) Signed-off-by: Dominik Ermel --- scripts/imgtool/image.py | 101 ++++++++++++++++++++++----------------- scripts/imgtool/main.py | 2 + 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 3de8357a6..a30d53bf2 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -1,6 +1,6 @@ # Copyright 2018 Nordic Semiconductor ASA # Copyright 2017-2020 Linaro Limited -# Copyright 2019-2023 Arm Limited +# Copyright 2019-2024 Arm Limited # # SPDX-License-Identifier: Apache-2.0 # @@ -20,23 +20,25 @@ Image signing and management. """ -from . import version as versmod -from .boot_record import create_sw_component_data -import click -from enum import Enum -from intelhex import IntelHex import hashlib -import struct import os.path -from .keys import rsa, ecdsa, x25519 +import struct +from enum import Enum + +import click +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.asymmetric import ec, padding from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes, hmac -from cryptography.exceptions import InvalidSignature +from intelhex import IntelHex + +from . import version as versmod, keys +from .boot_record import create_sw_component_data +from .keys import rsa, ecdsa, x25519 IMAGE_MAGIC = 0x96f3b83d IMAGE_HEADER_SIZE = 32 @@ -90,10 +92,8 @@ } VerifyResult = Enum('VerifyResult', - """ - OK INVALID_MAGIC INVALID_TLV_INFO_MAGIC INVALID_HASH - INVALID_SIGNATURE - """) + ['OK', 'INVALID_MAGIC', 'INVALID_TLV_INFO_MAGIC', 'INVALID_HASH', 'INVALID_SIGNATURE', + 'KEY_MISMATCH']) def align_up(num, align): @@ -135,7 +135,24 @@ def get(self): return header + bytes(self.buf) -class Image(): +def get_digest(tlv_type, hash_region): + if tlv_type == TLV_VALUES["SHA384"]: + sha = hashlib.sha384() + elif tlv_type == TLV_VALUES["SHA256"]: + sha = hashlib.sha256() + + sha.update(hash_region) + return sha.digest() + + +def tlv_matches_key_type(tlv_type, key): + """Check if provided key matches to TLV record in the image""" + return (key is None or + type(key) == keys.ECDSA384P1 and tlv_type == TLV_VALUES["SHA384"] or + type(key) != keys.ECDSA384P1 and tlv_type == TLV_VALUES["SHA256"]) + + +class Image: def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, pad_header=False, pad=False, confirm=False, align=1, @@ -178,9 +195,9 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, msb = (self.max_align & 0xff00) >> 8 align = bytes([msb, lsb]) if self.endian == "big" else bytes([lsb, msb]) self.boot_magic = align + bytes([0x2d, 0xe1, - 0x5d, 0x29, 0x41, 0x0b, - 0x8d, 0x77, 0x67, 0x9c, - 0x11, 0x0f, 0x1f, 0x8a, ]) + 0x5d, 0x29, 0x41, 0x0b, + 0x8d, 0x77, 0x67, 0x9c, + 0x11, 0x0f, 0x1f, 0x8a, ]) if security_counter == 'auto': # Security counter has not been explicitly provided, @@ -321,9 +338,8 @@ def create(self, key, public_key_format, enckey, dependencies=None, self.enckey = enckey # Check what hashing algorithm should be used - if (key is not None and isinstance(key, ecdsa.ECDSA384P1) or - pub_key is not None and isinstance(pub_key, - ecdsa.ECDSA384P1Public)): + if (key and isinstance(key, ecdsa.ECDSA384P1) + or pub_key and isinstance(pub_key, ecdsa.ECDSA384P1Public)): hash_algorithm = hashlib.sha384 hash_tlv = "SHA384" else: @@ -430,13 +446,13 @@ def create(self, key, public_key_format, enckey, dependencies=None, if dependencies is not None: for i in range(dependencies_num): payload = struct.pack( - e + 'B3x'+'BBHI', - int(dependencies[DEP_IMAGES_KEY][i]), - dependencies[DEP_VERSIONS_KEY][i].major, - dependencies[DEP_VERSIONS_KEY][i].minor, - dependencies[DEP_VERSIONS_KEY][i].revision, - dependencies[DEP_VERSIONS_KEY][i].build - ) + e + 'B3x' + 'BBHI', + int(dependencies[DEP_IMAGES_KEY][i]), + dependencies[DEP_VERSIONS_KEY][i].major, + dependencies[DEP_VERSIONS_KEY][i].minor, + dependencies[DEP_VERSIONS_KEY][i].revision, + dependencies[DEP_VERSIONS_KEY][i].build + ) prot_tlv.add('DEPENDENCY', payload) if custom_tlvs is not None: @@ -640,42 +656,37 @@ def verify(imgfile, key): return VerifyResult.INVALID_MAGIC, None, None tlv_off = header_size + img_size - tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE] + tlv_info = b[tlv_off:tlv_off + TLV_INFO_SIZE] magic, tlv_tot = struct.unpack('HH', tlv_info) if magic == TLV_PROT_INFO_MAGIC: tlv_off += tlv_tot - tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE] + tlv_info = b[tlv_off:tlv_off + TLV_INFO_SIZE] magic, tlv_tot = struct.unpack('HH', tlv_info) if magic != TLV_INFO_MAGIC: return VerifyResult.INVALID_TLV_INFO_MAGIC, None, None - if isinstance(key, ecdsa.ECDSA384P1Public): - sha = hashlib.sha384() - hash_tlv = "SHA384" - else: - sha = hashlib.sha256() - hash_tlv = "SHA256" - prot_tlv_size = tlv_off - sha.update(b[:prot_tlv_size]) - digest = sha.digest() - + hash_region = b[:prot_tlv_size] + digest = None tlv_end = tlv_off + tlv_tot tlv_off += TLV_INFO_SIZE # skip tlv info while tlv_off < tlv_end: - tlv = b[tlv_off:tlv_off+TLV_SIZE] + tlv = b[tlv_off:tlv_off + TLV_SIZE] tlv_type, _, tlv_len = struct.unpack('BBH', tlv) - if tlv_type == TLV_VALUES[hash_tlv]: + if tlv_type == TLV_VALUES["SHA256"] or tlv_type == TLV_VALUES["SHA384"]: + if not tlv_matches_key_type(tlv_type, key): + return VerifyResult.KEY_MISMATCH, None, None off = tlv_off + TLV_SIZE - if digest == b[off:off+tlv_len]: + digest = get_digest(tlv_type, hash_region) + if digest == b[off:off + tlv_len]: if key is None: return VerifyResult.OK, version, digest else: return VerifyResult.INVALID_HASH, None, None elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]: off = tlv_off + TLV_SIZE - tlv_sig = b[off:off+tlv_len] + tlv_sig = b[off:off + tlv_len] payload = b[:prot_tlv_size] try: if hasattr(key, 'verify'): diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index e24c9a087..f70a8bf51 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -228,6 +228,8 @@ def verify(key, imgfile): print("Image has an invalid hash") elif ret == image.VerifyResult.INVALID_SIGNATURE: print("No signature found for the given key") + elif ret == image.VerifyResult.KEY_MISMATCH: + print("Key type does not match TLV record") else: print("Unknown return code: {}".format(ret)) sys.exit(1) From 9ae7287c1360527a948a883715904ce42646eb72 Mon Sep 17 00:00:00 2001 From: Mateusz Wielgos Date: Mon, 26 Feb 2024 15:02:45 -0600 Subject: [PATCH 09/10] [nrf fromtree] imgtool: Add --non-bootable flag Defaults to false. Signed-off-by: Mateusz Wielgos (cherry picked from commit dc03055537f2e835e3905e7853f0a1fc0b70a57e) Signed-off-by: Dominik Ermel --- scripts/imgtool/image.py | 6 +++++- scripts/imgtool/main.py | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index a30d53bf2..5c4732b53 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -159,7 +159,8 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, slot_size=0, max_sectors=DEFAULT_MAX_SECTORS, overwrite_only=False, endian="little", load_addr=0, rom_fixed=None, erased_val=None, save_enctlv=False, - security_counter=None, max_align=None): + security_counter=None, max_align=None, + non_bootable=False): if load_addr and rom_fixed: raise click.UsageError("Can not set rom_fixed and load_addr at the same time") @@ -183,6 +184,7 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, self.save_enctlv = save_enctlv self.enctlv_len = 0 self.max_align = max(DEFAULT_MAX_ALIGN, align) if max_align is None else int(max_align) + self.non_bootable = non_bootable if self.max_align == DEFAULT_MAX_ALIGN: self.boot_magic = bytes([ @@ -567,6 +569,8 @@ def add_header(self, enckey, protected_tlv_size, aes_length=128): flags |= IMAGE_F['RAM_LOAD'] if self.rom_fixed: flags |= IMAGE_F['ROM_FIXED'] + if self.non_bootable: + flags |= IMAGE_F['NON_BOOTABLE'] e = STRUCT_ENDIAN_DICT[self.endian] fmt = (e + diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index f70a8bf51..cc2cf9c58 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -314,6 +314,8 @@ def convert(self, value, param, ctx): @click.argument('outfile') @click.argument('infile') +@click.option('--non-bootable', default=False, is_flag=True, + help='Mark the image as non-bootable.') @click.option('--custom-tlv', required=False, nargs=2, default=[], multiple=True, metavar='[tag] [value]', help='Custom TLV that will be placed into protected area. ' @@ -411,7 +413,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, endian, encrypt_keylen, encrypt, infile, outfile, dependencies, load_addr, hex_addr, erased_val, save_enctlv, security_counter, boot_record, custom_tlv, rom_fixed, max_align, clear, fix_sig, - fix_sig_pubkey, sig_out, vector_to_sign): + fix_sig_pubkey, sig_out, vector_to_sign, non_bootable): if confirm: # Confirmed but non-padded images don't make much sense, because @@ -423,7 +425,8 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, max_sectors=max_sectors, overwrite_only=overwrite_only, endian=endian, load_addr=load_addr, rom_fixed=rom_fixed, erased_val=erased_val, save_enctlv=save_enctlv, - security_counter=security_counter, max_align=max_align) + security_counter=security_counter, max_align=max_align, + non_bootable=non_bootable) img.load(infile) key = load_key(key) if key else None enckey = load_key(encrypt) if encrypt else None From 6a31a91bde59b78bcb700cddf80e51d2ba92489c Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 22 Aug 2024 14:58:15 +0000 Subject: [PATCH 10/10] [nrf fromlist] imgtool: Add support for calculating SHA512 The adds support for hashing image with SHA512, to allow SHA512-ED25519-SHA512 signature. To support above --sha parameter has been added that can take value: auto, 256, 384, 512 to select sha, where auto brings the default behaviour, or current, behaviour. The sha provided here is tested against key so not all combinations are supported. Upstream PR: https://github.com/mcu-tools/mcuboot/pull/2048 Signed-off-by: Dominik Ermel --- scripts/imgtool/image.py | 111 ++++++++++++++++++++++++++++++++------- scripts/imgtool/main.py | 8 ++- 2 files changed, 97 insertions(+), 22 deletions(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 5c4732b53..53b19ef1d 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -40,6 +40,8 @@ from .boot_record import create_sw_component_data from .keys import rsa, ecdsa, x25519 +from collections import namedtuple + IMAGE_MAGIC = 0x96f3b83d IMAGE_HEADER_SIZE = 32 BIN_EXT = "bin" @@ -65,6 +67,7 @@ 'PUBKEY': 0x02, 'SHA256': 0x10, 'SHA384': 0x11, + 'SHA512': 0x12, 'RSA2048': 0x20, 'ECDSASIG': 0x22, 'RSA3072': 0x23, @@ -135,11 +138,73 @@ def get(self): return header + bytes(self.buf) +SHAAndAlgT = namedtuple('SHAAndAlgT', ['sha', 'alg']) + +TLV_SHA_TO_SHA_AND_ALG = { + TLV_VALUES['SHA256'] : SHAAndAlgT('256', hashlib.sha256), + TLV_VALUES['SHA384'] : SHAAndAlgT('384', hashlib.sha384), + TLV_VALUES['SHA512'] : SHAAndAlgT('512', hashlib.sha512), +} + + +USER_SHA_TO_ALG_AND_TLV = { + 'auto' : (hashlib.sha256, 'SHA256'), + '256' : (hashlib.sha256, 'SHA256'), + '384' : (hashlib.sha384, 'SHA384'), + '512' : (hashlib.sha512, 'SHA512') +} + + +def is_sha_tlv(tlv): + return tlv in TLV_SHA_TO_SHA_AND_ALG.keys() + + +def tlv_sha_to_sha(tlv): + return TLV_SHA_TO_SHA_AND_ALG[tlv].sha + + +# Auto selecting hash algorithm for type(key) +ALLOWED_KEY_SHA = { + keys.ECDSA384P1 : ['384'], + keys.ECDSA384P1Public : ['384'], + keys.ECDSA256P1 : ['256'], + keys.RSA : ['256'], + # This two are set to 256 for compatibility, the right would be 512 + keys.Ed25519 : ['256', '512'], + keys.X25519 : ['256', '512'] +} + +def key_and_user_sha_to_alg_and_tlv(key, user_sha): + """Matches key and user requested sha to sha alogrithm and TLV name. + + The returned tuple will contain hash functions and TVL name. + The function is designed to succeed or completely fail execution, + as providing incorrect pair here basically prevents doing + any more work. + """ + if key is None: + # If key is none, we allow whatever user has selected for sha + return USER_SHA_TO_ALG_AND_TLV[user_sha] + + # If key is not None, then we have to filter hash to only allowed + allowed = None + try: + allowed = ALLOWED_KEY_SHA[type(key)] + except KeyError: + raise click.UsageError("Colud not find allowed hash algorithms for {}" + .format(type(key))) + if user_sha == 'auto': + return USER_SHA_TO_ALG_AND_TLV[allowed[0]] + + if user_sha in allowed: + return USER_SHA_TO_ALG_AND_TLV[user_sha] + + raise click.UsageError("Key {} can not be used with --sha {}; allowed sha are one of {}" + .format(key.sig_type(), user_sha, allowed)) + + def get_digest(tlv_type, hash_region): - if tlv_type == TLV_VALUES["SHA384"]: - sha = hashlib.sha384() - elif tlv_type == TLV_VALUES["SHA256"]: - sha = hashlib.sha256() + sha = TLV_SHA_TO_SHA_AND_ALG[tlv_type].alg() sha.update(hash_region) return sha.digest() @@ -147,9 +212,16 @@ def get_digest(tlv_type, hash_region): def tlv_matches_key_type(tlv_type, key): """Check if provided key matches to TLV record in the image""" - return (key is None or - type(key) == keys.ECDSA384P1 and tlv_type == TLV_VALUES["SHA384"] or - type(key) != keys.ECDSA384P1 and tlv_type == TLV_VALUES["SHA256"]) + try: + # We do not need the result here, and the key_and_user_sha_to_alg_and_tlv + # will either succeed finding match or rise exception, so on success we + # return True, on exception we return False. + _, _ = key_and_user_sha_to_alg_and_tlv(key, tlv_sha_to_sha(tlv_type)) + return True + except: + pass + + return False class Image: @@ -336,17 +408,13 @@ def ecies_hkdf(self, enckey, plainkey): def create(self, key, public_key_format, enckey, dependencies=None, sw_type=None, custom_tlvs=None, encrypt_keylen=128, clear=False, - fixed_sig=None, pub_key=None, vector_to_sign=None): + fixed_sig=None, pub_key=None, vector_to_sign=None, user_sha='auto'): self.enckey = enckey - # Check what hashing algorithm should be used - if (key and isinstance(key, ecdsa.ECDSA384P1) - or pub_key and isinstance(pub_key, ecdsa.ECDSA384P1Public)): - hash_algorithm = hashlib.sha384 - hash_tlv = "SHA384" - else: - hash_algorithm = hashlib.sha256 - hash_tlv = "SHA256" + # key decides on sha, then pub_key; of both are none default is used + check_key = key if key is not None else pub_key + hash_algorithm, hash_tlv = key_and_user_sha_to_alg_and_tlv(check_key, user_sha) + # Calculate the hash of the public key if key is not None: pub = key.get_public_bytes() @@ -466,11 +534,14 @@ def create(self, key, public_key_format, enckey, dependencies=None, tlv = TLV(self.endian) - # Note that ecdsa wants to do the hashing itself, which means - # we get to hash it twice. + # These signature is done over sha of image. In case of + # EC signatures so called Pure algorithm, designated to be run + # over entire message is used with sha of image as message, + # so, for example, in case of ED25519 we have here SHAxxx-ED25519-SHA512. sha = hash_algorithm() sha.update(self.payload) digest = sha.digest() + message = digest; tlv.add(hash_tlv, digest) if vector_to_sign == 'payload': @@ -499,7 +570,7 @@ def create(self, key, public_key_format, enckey, dependencies=None, sig = key.sign(bytes(self.payload)) else: print(os.path.basename(__file__) + ": sign the digest") - sig = key.sign_digest(digest) + sig = key.sign_digest(message) tlv.add(key.sig_tlv(), sig) self.signature = sig elif fixed_sig is not None and key is None: @@ -678,7 +749,7 @@ def verify(imgfile, key): while tlv_off < tlv_end: tlv = b[tlv_off:tlv_off + TLV_SIZE] tlv_type, _, tlv_len = struct.unpack('BBH', tlv) - if tlv_type == TLV_VALUES["SHA256"] or tlv_type == TLV_VALUES["SHA384"]: + if is_sha_tlv(tlv_type): if not tlv_matches_key_type(tlv_type, key): return VerifyResult.KEY_MISMATCH, None, None off = tlv_off + TLV_SIZE diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index cc2cf9c58..848fd3110 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -72,6 +72,7 @@ def gen_x25519(keyfile, passwd): 'x25519': gen_x25519, } valid_formats = ['openssl', 'pkcs8'] +valid_sha = [ 'auto', '256', '384', '512' ] def load_signature(sigfile): @@ -401,6 +402,9 @@ def convert(self, value, param, ctx): @click.option('--sig-out', metavar='filename', help='Path to the file to which signature will be written. ' 'The image signature will be encoded as base64 formatted string') +@click.option('--sha', 'user_sha', type=click.Choice(valid_sha), default='auto', + help='selected sha algorithm to use; defaults to "auto" which is 256 if ' + 'no cryptographic signature is used, or default for signature type') @click.option('--vector-to-sign', type=click.Choice(['payload', 'digest']), help='send to OUTFILE the payload or payload''s digest instead ' 'of complied image. These data can be used for external image ' @@ -413,7 +417,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, endian, encrypt_keylen, encrypt, infile, outfile, dependencies, load_addr, hex_addr, erased_val, save_enctlv, security_counter, boot_record, custom_tlv, rom_fixed, max_align, clear, fix_sig, - fix_sig_pubkey, sig_out, vector_to_sign, non_bootable): + fix_sig_pubkey, sig_out, user_sha, vector_to_sign, non_bootable): if confirm: # Confirmed but non-padded images don't make much sense, because @@ -481,7 +485,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, img.create(key, public_key_format, enckey, dependencies, boot_record, custom_tlvs, int(encrypt_keylen), clear, baked_signature, - pub_key, vector_to_sign) + pub_key, vector_to_sign, user_sha) img.save(outfile, hex_addr) if sig_out is not None: