From 75e570986ced2f627c2f982a7c9a6f00cf57d38a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 01/44] Revert "[nrf noup] zephyr: Add support for encrypted compressed updates" This reverts commit 148712e7b4618aadbedd04e8d3ce5c3847d3be4f. Signed-off-by: Dominik Ermel --- boot/bootutil/src/loader.c | 2 +- boot/zephyr/Kconfig | 3 +- boot/zephyr/decompression.c | 134 ++---------------------------------- 3 files changed, 8 insertions(+), 131 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index f9a9de71d..a561d5cb7 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1612,7 +1612,7 @@ boot_copy_region(struct boot_loader_state *state, #else (void)state; #endif -#if defined(MCUBOOT_DECOMPRESS_IMAGES) && !defined(MCUBOOT_ENC_IMAGES) +#ifdef MCUBOOT_DECOMPRESS_IMAGES struct image_header *hdr; #endif diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 1632e6a34..0ee9e20c7 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -975,7 +975,8 @@ config BOOT_BANNER_STRING config BOOT_DECOMPRESSION_SUPPORT bool depends on NRF_COMPRESS && NRF_COMPRESS_DECOMPRESSION && (NRF_COMPRESS_LZMA_VERSION_LZMA1 || NRF_COMPRESS_LZMA_VERSION_LZMA2) - depends on !SINGLE_APPLICATION_SLOT && BOOT_UPGRADE_ONLY + depends on !SINGLE_APPLICATION_SLOT && !BOOT_ENCRYPT_IMAGE && BOOT_UPGRADE_ONLY + depends on UPDATEABLE_IMAGE_NUMBER = 1 default y help Hidden symbol which should be selected if a system provided decompression support. diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c index 7a9507de6..35a1950b2 100644 --- a/boot/zephyr/decompression.c +++ b/boot/zephyr/decompression.c @@ -58,17 +58,11 @@ bool boot_is_compressed_header_valid(const struct image_header *hdr, const struc uint32_t protected_tlvs_size; uint32_t decompressed_size; - primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); - - if (primary_fa_id == fap->fa_id) { - BOOT_LOG_ERR("Primary slots cannot be compressed, image: %d", BOOT_CURR_IMG(state)); - return false; - } - if (BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT) == NULL) { opened_flash_area = true; } + primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); assert(rc == 0); @@ -117,55 +111,6 @@ static bool is_compression_object_valid(struct nrf_compress_implementation *comp return true; } -#ifdef MCUBOOT_ENC_IMAGES -int bootutil_get_img_decrypted_comp_size(const struct image_header *hdr, - const struct flash_area *fap, uint32_t *img_comp_size) -{ - if (hdr == NULL || fap == NULL || img_comp_size == NULL) { - return BOOT_EBADARGS; - } else if (hdr->ih_protect_tlv_size == 0) { - return BOOT_EBADIMAGE; - } - - if (!IS_ENCRYPTED(hdr)) { - /* Update is not encrypted so use size from header */ - *img_comp_size = hdr->ih_img_size; - } else { - struct image_tlv_iter it; - uint32_t off; - uint16_t len; - int32_t rc; - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_COMP_DEC_SIZE, true); - - if (rc) { - return rc; - } - - rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); - - if (rc != 0) { - return -1; - } - - if (len != sizeof(*img_comp_size)) { - BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); - return BOOT_EBADIMAGE; - } - - rc = LOAD_IMAGE_DATA(hdr, fap, off, img_comp_size, len); - - if (rc) { - BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - off, len, fap->fa_id, rc); - return BOOT_EFLASH; - } - } - - return 0; -} -#endif - int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index, struct image_header *hdr, const struct flash_area *fap, uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, @@ -183,28 +128,8 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index bootutil_sha_context sha_ctx; uint8_t flash_erased_value; -#ifdef MCUBOOT_ENC_IMAGES - uint32_t comp_size = 0; - - rc = bootutil_get_img_decrypted_comp_size(hdr, fap, &comp_size); - - if (rc) { - BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); - rc = BOOT_EBADIMAGE; - goto finish_end; - } -#endif - bootutil_sha_init(&sha_ctx); -#ifdef MCUBOOT_ENC_IMAGES - /* Encrypted images only exist in the secondary slot */ - if (MUST_DECRYPT(fap, image_index, hdr) && - !boot_enc_valid(enc_state, 1)) { - return -1; - } -#endif - /* Setup decompression system */ #if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { @@ -287,13 +212,8 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index /* Read in compressed data, decompress and add to hash calculation */ read_pos = 0; -#ifdef MCUBOOT_ENC_IMAGES - while (read_pos < comp_size) { - uint32_t copy_size = comp_size - read_pos; -#else while (read_pos < hdr->ih_img_size) { uint32_t copy_size = hdr->ih_img_size - read_pos; -#endif uint32_t tmp_off = 0; uint8_t offset_zero_check = 0; @@ -310,14 +230,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index goto finish; } -#ifdef MCUBOOT_ENC_IMAGES - if (MUST_DECRYPT(fap, image_index, hdr)) { - boot_enc_decrypt(enc_state, 1, read_pos, - copy_size, (read_pos & 0xf), - tmp_buf); - } -#endif - /* Decompress data in chunks, writing it back with a larger write offset of the primary * slot than read size of the secondary slot */ @@ -334,11 +246,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index chunk_size = (copy_size - tmp_off); } -#ifdef MCUBOOT_ENC_IMAGES - if ((read_pos + tmp_off + chunk_size) >= comp_size) { -#else if ((read_pos + tmp_off + chunk_size) >= hdr->ih_img_size) { -#endif last_packet = true; } @@ -458,9 +366,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index finish_without_clean: bootutil_sha_drop(&sha_ctx); -#ifdef MCUBOOT_ENC_IMAGES -finish_end: -#endif return rc; } @@ -532,7 +437,7 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, } if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { + type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Skip these TLVs as they are not needed */ continue; } else { @@ -641,7 +546,7 @@ static int boot_sha_protected_tlvs(const struct image_header *hdr, } if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { + type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Skip these TLVs as they are not needed */ continue; } @@ -706,7 +611,7 @@ int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_ } if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { + type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Exclude these TLVs as they will be copied to the unprotected area */ tlv_size -= len + sizeof(struct image_tlv); } @@ -758,7 +663,7 @@ int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flas * original ones */ continue; - } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV || type == IMAGE_TLV_COMP_DEC_SIZE) { + } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { /* Exclude the original unprotected TLVs for signature and hash, the length of the * signature of the compressed data might not be the same size as the signaute of the * decompressed data, as is the case when using ECDSA-P256 @@ -980,22 +885,8 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl bool excess_data_buffer_full = false; #endif -#ifdef MCUBOOT_ENC_IMAGES - uint32_t comp_size = 0; -#endif - hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); -#ifdef MCUBOOT_ENC_IMAGES - rc = bootutil_get_img_decrypted_comp_size(hdr, fap_src, &comp_size); - - if (rc) { - BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); - rc = BOOT_EBADIMAGE; - goto finish; - } -#endif - /* Setup decompression system */ #if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { @@ -1075,13 +966,8 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl } /* Read in, decompress and write out data */ -#ifdef MCUBOOT_ENC_IMAGES - while (pos < comp_size) { - uint32_t copy_size = comp_size - pos; -#else while (pos < hdr->ih_img_size) { uint32_t copy_size = hdr->ih_img_size - pos; -#endif uint32_t tmp_off = 0; if (copy_size > buf_size) { @@ -1097,12 +983,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl goto finish; } -#ifdef MCUBOOT_ENC_IMAGES - if (IS_ENCRYPTED(hdr)) { - boot_enc_decrypt(BOOT_CURR_ENC(state), 1, pos, copy_size, (pos & 0xf), buf); - } -#endif - /* Decompress data in chunks, writing it back with a larger write offset of the primary * slot than read size of the secondary slot */ @@ -1120,11 +1000,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl chunk_size = (copy_size - tmp_off); } -#ifdef MCUBOOT_ENC_IMAGES - if ((pos + tmp_off + chunk_size) >= comp_size) { -#else if ((pos + tmp_off + chunk_size) >= hdr->ih_img_size) { -#endif last_packet = true; } From f2840ffe5bca21b90a3c54262880b843db609cb9 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 02/44] Revert "[nrf fromtree] boot: bootutil: Add TLV for size of compressed but decrypted image" This reverts commit bc8d277df74908cd52f24fd9a3744f225f21169e. Signed-off-by: Dominik Ermel --- boot/bootutil/include/bootutil/image.h | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 92adc605b..05e04438b 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -124,7 +124,6 @@ struct flash_area; * the format and size of the raw slot (compressed) * signature */ -#define IMAGE_TLV_COMP_DEC_SIZE 0x73 /* Compressed decrypted image size */ /* * vendor reserved TLVs at xxA0-xxFF, * where xx denotes the upper byte From 410377ec55331f34bcd93df354e6e837065fb2c6 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 03/44] Revert "[nrf noup] boot: bootutil: image_validate: Add KMU support to compression" This reverts commit 97e8acfb8db54b23de41130732ab6f95c3053d15. Signed-off-by: Dominik Ermel --- boot/bootutil/src/image_validate.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 64983b318..f71d1d9a6 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -815,7 +815,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } #ifdef EXPECTED_SIG_TLV -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && defined(EXPECTED_KEY_TLV) +#ifdef EXPECTED_KEY_TLV rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); if (rc) { goto out; @@ -861,7 +861,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, */ } } -#endif /* !CONFIG_BOOT_SIGNATURE_USING_KMU && EXPECTED_KEY_TLV */ +#endif /* EXPECTED_KEY_TLV */ rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); if (rc) { @@ -884,12 +884,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Ignore this signature if it is out of bounds. */ -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } -#endif if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; From 1a835fc7ad506d9244e4d126ae5d5373fe3f0f3a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 04/44] Revert "[nrf noup] boot: bootutil: Allow configuring number of KMU keys" This reverts commit 2ca0efedf8d331028455f05d77f1c3c5064b773b. Signed-off-by: Dominik Ermel --- boot/bootutil/src/ed25519_psa.c | 9 +++------ boot/zephyr/Kconfig | 12 ------------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 3042eeabf..83fc692a1 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2024 Nordic Semiconductor ASA + * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ @@ -12,7 +12,6 @@ #include #include -#include #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #include #endif @@ -31,9 +30,7 @@ static psa_key_id_t kmu_key_ids[3] = { MAKE_PSA_KMU_KEY_ID(228), MAKE_PSA_KMU_KEY_ID(230) }; - -BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), - "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); +#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) #endif #if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) @@ -106,7 +103,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len, status = PSA_ERROR_BAD_STATE; - for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { + for (int i = 0; i < KMU_KEY_COUNT; ++i) { psa_key_id_t kid = kmu_key_ids[i]; status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 0ee9e20c7..f39daaa18 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -317,18 +317,6 @@ config BOOT_SIGNATURE_USING_KMU MCUboot will use keys provisioned to the device key management unit for signature verification instead of compiling in key data from a file. -if BOOT_SIGNATURE_USING_KMU - -config BOOT_SIGNATURE_KMU_SLOTS - int "KMU key slots" - range 1 3 - default 1 - help - Selects the number of KMU key slots (also known as generations) to use when verifying - an image. - -endif - if !BOOT_SIGNATURE_USING_KMU config BOOT_SIGNATURE_KEY_FILE From ff3a91595665c5c048f42229c6bd76358afe7e0a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 05/44] Revert "[nrf noup] boot: zephyr: Add experimental selection to compression" This reverts commit 4ceb4773b31dd8d56dfcb6e0461a70bb161ca95f. Signed-off-by: Dominik Ermel --- boot/zephyr/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index f39daaa18..ba3888e74 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -972,10 +972,9 @@ config BOOT_DECOMPRESSION_SUPPORT if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION - bool "Decompression [EXPERIMENTAL]" + bool "Decompression" select NRF_COMPRESS_CLEANUP select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP - select EXPERIMENTAL help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to From e2addc398ac657be69b6d1a74a2b7d7415232bdc Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 06/44] Revert "[nrf noup] bootutil: Add support for KMU stored ED25519 signature key" This reverts commit b647a94a24b1a20b3cbbde41ff9a4a92be67a232. Signed-off-by: Dominik Ermel --- boot/bootutil/src/ed25519_psa.c | 51 ------------------------------ boot/bootutil/src/image_ed25519.c | 19 +++-------- boot/bootutil/src/image_validate.c | 6 ---- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/Kconfig | 29 +---------------- 5 files changed, 6 insertions(+), 101 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 83fc692a1..e84b71d2a 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -12,9 +12,6 @@ #include #include -#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) -#include -#endif BOOT_LOG_MODULE_REGISTER(ed25519_psa); @@ -22,18 +19,6 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #define EDDSA_KEY_LENGTH 32 #define EDDSA_SIGNAGURE_LENGTH 64 -#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) -/* List of KMU stored key ids available for MCUboot */ -#define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) -static psa_key_id_t kmu_key_ids[3] = { - MAKE_PSA_KMU_KEY_ID(226), - MAKE_PSA_KMU_KEY_ID(228), - MAKE_PSA_KMU_KEY_ID(230) -}; -#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) -#endif - -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], const uint8_t public_key[EDDSA_KEY_LENGTH]) @@ -84,39 +69,3 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return ret; } -#else -int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], - const uint8_t public_key[EDDSA_KEY_LENGTH]) -{ - ARG_UNUSED(public_key); - /* Set to any error */ - psa_status_t status = PSA_ERROR_BAD_STATE; - int ret = 0; /* Fail by default */ - - /* Initialize PSA Crypto */ - status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - BOOT_LOG_ERR("PSA crypto init failed %d", status); - return 0; - } - - status = PSA_ERROR_BAD_STATE; - - for (int i = 0; i < KMU_KEY_COUNT; ++i) { - psa_key_id_t kid = kmu_key_ids[i]; - - status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, - message_len, signature, - EDDSA_SIGNAGURE_LENGTH); - if (status == PSA_SUCCESS) { - ret = 1; - break; - } - - BOOT_LOG_ERR("ED25519 signature verification failed %d", status); - } - - return ret; -} -#endif diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 07131d1ae..8e74f48f0 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -27,16 +27,14 @@ #include "bootutil/crypto/sha.h" #define EDDSA_SIGNATURE_LENGTH 64 + +static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; #define NUM_ED25519_BYTES 32 extern int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNATURE_LENGTH], const uint8_t public_key[NUM_ED25519_BYTES]); -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) - -static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; - /* * Parse the public key used for signing. */ @@ -75,7 +73,6 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } -#endif fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, @@ -83,17 +80,14 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, { int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); - uint8_t *pubkey = NULL; -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) + uint8_t *pubkey; uint8_t *end; -#endif if (hlen != IMAGE_HASH_SIZE || slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; @@ -102,7 +96,6 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, FIH_SET(fih_rc, FIH_FAILURE); goto out; } -#endif rc = ED25519_verify(hash, IMAGE_HASH_SIZE, sig, pubkey); @@ -124,17 +117,14 @@ bootutil_verify_img(const uint8_t *img, uint32_t size, { int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); - uint8_t *pubkey = NULL; -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) + uint8_t *pubkey; uint8_t *end; -#endif if (slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; @@ -143,7 +133,6 @@ bootutil_verify_img(const uint8_t *img, uint32_t size, FIH_SET(fih_rc, FIH_FAILURE); goto out; } -#endif rc = ED25519_verify(img, size, sig, pubkey); diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index f71d1d9a6..c419b9497 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -245,7 +245,6 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, # define KEY_BUF_SIZE (SIG_BUF_SIZE + 24) #endif /* !MCUBOOT_HW_KEY */ -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #if !defined(MCUBOOT_HW_KEY) static int bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) @@ -311,7 +310,6 @@ bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) } #endif /* !MCUBOOT_HW_KEY */ #endif /* !MCUBOOT_BUILTIN_KEY */ -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #endif /* EXPECTED_SIG_TLV */ /** @@ -628,7 +626,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, break; } #endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */ -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #ifdef EXPECTED_KEY_TLV case EXPECTED_KEY_TLV: { @@ -659,17 +656,14 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, break; } #endif /* EXPECTED_KEY_TLV */ -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #ifdef EXPECTED_SIG_TLV case EXPECTED_SIG_TLV: { -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; goto out; diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 596e698b3..c5d712e74 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -305,7 +305,7 @@ if(CONFIG_MCUBOOT_SERIAL) endif() endif() -if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") +if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") # CONF_FILE points to the KConfig configuration files of the bootloader. foreach (filepath ${CONF_FILE}) file(READ ${filepath} temp_text) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index ba3888e74..2eb1bac7d 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -293,7 +293,6 @@ config BOOT_ED25519_MBEDTLS config BOOT_ED25519_PSA bool "Use PSA crypto" - depends on NRF_SECURITY select BOOT_USE_PSA_CRYPTO select BOOT_ED25519_PSA_DEPENDENCIES select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE @@ -303,22 +302,6 @@ endif endchoice -config BOOT_SIGNATURE_USING_KMU - bool "Use KMU stored keys for signature verification" - depends on NRF_SECURITY - depends on CRACEN_LIB_KMU - select PSA_WANT_ALG_GCM - select PSA_WANT_KEY_TYPE_AES - select PSA_WANT_AES_KEY_SIZE_256 - select PSA_WANT_ALG_SP800_108_COUNTER_CMAC - select PSA_WANT_ALG_CMAC - select PSA_WANT_ALG_ECB_NO_PADDING - help - MCUboot will use keys provisioned to the device key management unit for signature - verification instead of compiling in key data from a file. - -if !BOOT_SIGNATURE_USING_KMU - config BOOT_SIGNATURE_KEY_FILE string "PEM key file" default "root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 @@ -336,8 +319,6 @@ config BOOT_SIGNATURE_KEY_FILE with the public key information will be written in a format expected by MCUboot. -endif - config MCUBOOT_CLEANUP_ARM_CORE bool "Perform core cleanup before chain-load the application" depends on CPU_CORTEX_M @@ -360,18 +341,10 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. -# Disable MBEDTLS from being selected if NRF_SECURITY is enabled, and use default NRF_SECURITY -# configuration file for MBEDTLS -config MBEDTLS - depends on !NRF_SECURITY - -config NRF_SECURITY - select MBEDTLS_PROMPTLESS - if MBEDTLS config MBEDTLS_CFG_FILE - default "mcuboot-mbedtls-cfg.h" if !NRF_SECURITY + default "mcuboot-mbedtls-cfg.h" endif From f3602907d9b266a783c1b43abfc324463dd5f358 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 07/44] Revert "[nrf noup] bootutil: PureEdDSA using ED25519" This reverts commit a43e5f460b230ae696454eb4b189d1c1139c73a6. Signed-off-by: Dominik Ermel --- boot/bootutil/src/bootutil_priv.h | 3 - boot/bootutil/src/image_ed25519.c | 37 -------- boot/bootutil/src/image_validate.c | 95 ++----------------- boot/zephyr/Kconfig | 29 +----- .../include/mcuboot_config/mcuboot_config.h | 4 - 5 files changed, 8 insertions(+), 160 deletions(-) diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 5592f1a87..345933a5f 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -270,9 +270,6 @@ struct boot_loader_state { fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t key_id); -fih_ret bootutil_verify_img(const uint8_t *img, uint32_t size, - uint8_t *sig, size_t slen, uint8_t key_id); - fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n); int boot_find_status(int image_index, const struct flash_area **fap); diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 8e74f48f0..897edcad1 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -111,41 +111,4 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, FIH_RET(fih_rc); } -fih_ret -bootutil_verify_img(const uint8_t *img, uint32_t size, - uint8_t *sig, size_t slen, uint8_t key_id) -{ - int rc; - FIH_DECLARE(fih_rc, FIH_FAILURE); - uint8_t *pubkey; - uint8_t *end; - - if (slen != EDDSA_SIGNATURE_LENGTH) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; - } - - pubkey = (uint8_t *)bootutil_keys[key_id].key; - end = pubkey + *bootutil_keys[key_id].len; - - rc = bootutil_import_key(&pubkey, end); - if (rc) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; - } - - rc = ED25519_verify(img, size, sig, pubkey); - - if (rc == 0) { - /* if verify returns 0, there was an error. */ - FIH_SET(fih_rc, FIH_FAILURE); - goto out; - } - - FIH_SET(fih_rc, FIH_SUCCESS); -out: - - FIH_RET(fih_rc); -} - #endif /* MCUBOOT_SIGN_ED25519 */ diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index c419b9497..fa1d373d7 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -65,7 +65,6 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); #include "bootutil_priv.h" -#ifndef MCUBOOT_SIGN_PURE /* * Compute SHA hash over the image. * (SHA384 if ECDSA-P384 is being used, @@ -185,7 +184,6 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, return 0; } -#endif /* * Currently, we only support being able to verify one type of @@ -372,43 +370,6 @@ bootutil_get_img_security_cnt(struct image_header *hdr, return 0; } -#if defined(MCUBOOT_SIGN_PURE) -/* Returns: - * 0 -- found - * 1 -- not found or found but not true - * -1 -- failed for some reason - * - * Value of TLV does not matter, presence decides. - */ -static int bootutil_check_for_pure(const struct image_header *hdr, - const struct flash_area *fap) -{ - struct image_tlv_iter it; - uint32_t off; - uint16_t len; - int32_t rc; - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false); - if (rc) { - return rc; - } - - /* Search for the TLV */ - rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); - if (rc == 0 && len == 1) { - bool val; - - rc = LOAD_IMAGE_DATA(hdr, fap, off, &val, 1); - if (rc == 0) { - rc = !val; - } - } - - return rc; -} -#endif - - #ifndef ALLOW_ROGUE_TLVS /* * The following list of TLVs are the only entries allowed in the unprotected @@ -425,9 +386,6 @@ static const uint16_t allowed_unprot_tlvs[] = { IMAGE_TLV_ECDSA_SIG, IMAGE_TLV_RSA3072_PSS, IMAGE_TLV_ED25519, -#if defined(MCUBOOT_SIGN_PURE) - IMAGE_TLV_SIG_PURE, -#endif IMAGE_TLV_ENC_RSA2048, IMAGE_TLV_ENC_KW, IMAGE_TLV_ENC_EC256, @@ -450,6 +408,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, uint32_t off; uint16_t len; uint16_t type; + int image_hash_valid = 0; #ifdef EXPECTED_SIG_TLV FIH_DECLARE(valid_signature, FIH_FAILURE); #ifndef MCUBOOT_BUILTIN_KEY @@ -466,10 +425,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, #endif /* EXPECTED_SIG_TLV */ struct image_tlv_iter it; uint8_t buf[SIG_BUF_SIZE]; -#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) - int image_hash_valid = 0; uint8_t hash[IMAGE_HASH_SIZE]; -#endif int rc = 0; FIH_DECLARE(fih_rc, FIH_FAILURE); #ifdef MCUBOOT_HW_ROLLBACK_PROT @@ -540,7 +496,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } #endif -#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); if (rc) { @@ -550,15 +505,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (out_hash) { memcpy(out_hash, hash, IMAGE_HASH_SIZE); } -#endif - -#if defined(MCUBOOT_SIGN_PURE) - /* If Pure type signature is expected then it has to be there */ - rc = bootutil_check_for_pure(hdr, fap); - if (rc != 0) { - goto out; - } -#endif rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); if (rc) { @@ -602,10 +548,8 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } } #endif - switch(type) { -#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) - case EXPECTED_HASH_TLV: - { + + if (type == EXPECTED_HASH_TLV) { /* Verify the image hash. This must always be present. */ if (len != sizeof(hash)) { rc = -1; @@ -623,12 +567,8 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } image_hash_valid = 1; - break; - } -#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */ #ifdef EXPECTED_KEY_TLV - case EXPECTED_KEY_TLV: - { + } else if (type == EXPECTED_KEY_TLV) { /* * Determine which key we should be checking. */ @@ -653,12 +593,9 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, * The key may not be found, which is acceptable. There * can be multiple signatures, each preceded by a key. */ - break; - } #endif /* EXPECTED_KEY_TLV */ #ifdef EXPECTED_SIG_TLV - case EXPECTED_SIG_TLV: - { + } else if (type == EXPECTED_SIG_TLV) { /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; @@ -672,25 +609,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (rc) { goto out; } -#ifndef MCUBOOT_SIGN_PURE FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), buf, len, key_id); -#else - /* Directly check signature on the image, by using the mapping of - * a device to memory. The pointer is beginning of image in flash, - * so offset of area, the range is header + image + protected tlvs. - */ - FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap), - hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size, - buf, len, key_id); -#endif key_id = -1; - break; - } #endif /* EXPECTED_SIG_TLV */ #ifdef MCUBOOT_HW_ROLLBACK_PROT - case IMAGE_TLV_SEC_CNT: - { + } else if (type == IMAGE_TLV_SEC_CNT) { /* * Verify the image's security counter. * This must always be present. @@ -725,21 +649,14 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, /* The image's security counter has been successfully verified. */ security_counter_valid = fih_rc; - break; - } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ } } -#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = !image_hash_valid; if (rc) { goto out; } -#elif defined(MCUBOOT_SIGN_PURE) - /* This returns true on EQ, rc is err on non-0 */ - rc = FIH_NOT_EQ(valid_signature, FIH_SUCCESS); -#endif #ifdef EXPECTED_SIG_TLV FIH_SET(fih_rc, valid_signature); #endif diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2eb1bac7d..a8aef35d9 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -192,14 +192,6 @@ config BOOT_IMG_HASH_ALG_SHA512 endchoice # BOOT_IMG_HASH_ALG -config BOOT_SIGNATURE_TYPE_PURE_ALLOW - bool - help - Hidden option set by configurations that allow Pure variant, - for example ed25519. The pure variant means that image - signature is calculated over entire image instead of hash - of an image. - choice BOOT_SIGNATURE_TYPE prompt "Signature type" default BOOT_SIGNATURE_TYPE_ED25519 if SOC_NRF54L15_CPUAPP @@ -250,32 +242,15 @@ endif config BOOT_SIGNATURE_TYPE_ED25519 bool "Edwards curve digital signatures using ed25519" - select BOOT_ENCRYPTION_SUPPORT if !BOOT_SIGNATURE_TYPE_PURE - select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !BOOT_SIGNATURE_TYPE_PURE - # The SHA is used only for key hashing, not for images. + select BOOT_ENCRYPTION_SUPPORT + select BOOT_IMG_HASH_ALG_SHA256_ALLOW select BOOT_IMG_HASH_ALG_SHA512_ALLOW if BOOT_USE_PSA_CRYPTO - select BOOT_SIGNATURE_TYPE_PURE_ALLOW help This is ed25519 signature calculated over SHA512 of SHA256 of application image; that is not completely correct approach as the SHA512 should be rather directly calculated over an image. - Select BOOT_SIGNATURE_TYPE_PURE to have a PureEdDSA calculating image - signature directly on image, rather than hash of the image. if BOOT_SIGNATURE_TYPE_ED25519 - -config BOOT_SIGNATURE_TYPE_PURE - bool "Use Pure signature of image" - depends on BOOT_SIGNATURE_TYPE_PURE_ALLOW - help - The Pure signature is calculated directly over image rather than - hash of an image. - This is more secure signature, specifically if hardware can do the - verification without need to share key. - Note that this requires that all slots for which signature is to be - verified need to be accessible through memory address space that - cryptography can access. - choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" default BOOT_ED25519_TINYCRYPT diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 36b5faa42..40f771911 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -155,10 +155,6 @@ #define MCUBOOT_HASH_STORAGE_DIRECTLY #endif -#ifdef CONFIG_BOOT_SIGNATURE_TYPE_PURE -#define MCUBOOT_SIGN_PURE -#endif - #ifdef CONFIG_BOOT_BOOTSTRAP #define MCUBOOT_BOOTSTRAP 1 #endif From 767e1455e65f72b144340360a3f9f073b64af57f Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 08/44] Revert "[nrf noup] bootutil: Enable hash calculation directly on storage" This reverts commit 32a7c77d13f25c2832b4b3ebaf774c2299be5818. Signed-off-by: Dominik Ermel --- boot/bootutil/src/image_validate.c | 15 +++------------ boot/zephyr/Kconfig | 16 ---------------- .../include/mcuboot_config/mcuboot_config.h | 7 ------- 3 files changed, 3 insertions(+), 35 deletions(-) diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index fa1d373d7..b1a50f126 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -77,15 +77,13 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, uint8_t *seed, int seed_len) { bootutil_sha_context sha_ctx; + uint32_t blk_sz; uint32_t size; uint16_t hdr_size; + uint32_t off; + int rc; uint32_t blk_off; uint32_t tlv_off; -#if !defined(MCUBOOT_HASH_STORAGE_DIRECTLY) - int rc; - uint32_t off; - uint32_t blk_sz; -#endif #if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \ defined(MCUBOOT_RAM_LOAD) @@ -128,12 +126,6 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, /* If protected TLVs are present they are also hashed. */ size += hdr->ih_protect_tlv_size; -#ifdef MCUBOOT_HASH_STORAGE_DIRECTLY - /* No chunk loading, storage is mapped to address space and can - * be directly given to hashing function. - */ - bootutil_sha_update(&sha_ctx, (void *)flash_area_get_off(fap), size); -#else /* MCUBOOT_HASH_STORAGE_DIRECTLY */ #ifdef MCUBOOT_RAM_LOAD bootutil_sha_update(&sha_ctx, (void*)(IMAGE_RAM_BASE + hdr->ih_load_addr), @@ -178,7 +170,6 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, bootutil_sha_update(&sha_ctx, tmp_buf, blk_sz); } #endif /* MCUBOOT_RAM_LOAD */ -#endif /* MCUBOOT_HASH_STORAGE_DIRECTLY */ bootutil_sha_finish(&sha_ctx, hash_result); bootutil_sha_drop(&sha_ctx); diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a8aef35d9..7942bbd19 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -146,22 +146,6 @@ config BOOT_IMG_HASH_ALG_SHA512_ALLOW help Hidden option set by configurations that allow SHA512 -config BOOT_IMG_HASH_DIRECTLY_ON_STORAGE - bool "Hash calculation functions access storage through address space" - depends on !BOOT_ENCRYPT_IMAGE - help - When possible to map storage device, at least for read operations, - to address space or RAM area, enabling this option allows hash - calculation functions to directly access the storage through that address - space or using its own DMA. This reduces flash read overhead done - by the MCUboot. - Notes: - - not supported when encrypted images are in use, because calculating - SHA requires image to be decrypted first, which is done to RAM. - - currently only supported on internal storage of devices; this - option will not work with devices that use external storage for - either of image slots. - choice BOOT_IMG_HASH_ALG prompt "Selected image hash algorithm" default BOOT_IMG_HASH_ALG_SHA256 if BOOT_IMG_HASH_ALG_SHA256_ALLOW diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 40f771911..4743539f1 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -148,13 +148,6 @@ #define MCUBOOT_DECOMPRESS_IMAGES #endif -/* Invoke hashing functions directly on storage. This requires for device - * to be able to map storage to address space or RAM. - */ -#ifdef CONFIG_BOOT_IMG_HASH_DIRECTLY_ON_STORAGE -#define MCUBOOT_HASH_STORAGE_DIRECTLY -#endif - #ifdef CONFIG_BOOT_BOOTSTRAP #define MCUBOOT_BOOTSTRAP 1 #endif From 078353fafee693254f35fca02763872c6d684965 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 09/44] Revert "[nrf noup] bootutil: Provide support for SHA512 with ED25519" This reverts commit 4e2273f992401997fc9a08868a0f4c4e3fac682e. Signed-off-by: Dominik Ermel --- boot/zephyr/Kconfig | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 7942bbd19..778ffca52 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -80,7 +80,7 @@ config BOOT_PSA_IMG_HASH_ALG_SHA256_DEPENDENCIES config BOOT_ED25519_PSA_DEPENDENCIES bool - select PSA_WANT_ALG_SHA_256 if BOOT_IMG_HASH_ALG_SHA256 + select PSA_WANT_ALG_SHA_256 select PSA_WANT_ALG_SHA_512 select PSA_WANT_ALG_PURE_EDDSA select PSA_WANT_ECC_TWISTED_EDWARDS_255 @@ -228,11 +228,6 @@ config BOOT_SIGNATURE_TYPE_ED25519 bool "Edwards curve digital signatures using ed25519" select BOOT_ENCRYPTION_SUPPORT select BOOT_IMG_HASH_ALG_SHA256_ALLOW - select BOOT_IMG_HASH_ALG_SHA512_ALLOW if BOOT_USE_PSA_CRYPTO - help - This is ed25519 signature calculated over SHA512 of SHA256 of application - image; that is not completely correct approach as the SHA512 should be - rather directly calculated over an image. if BOOT_SIGNATURE_TYPE_ED25519 choice BOOT_ED25519_IMPLEMENTATION From 38a0a0975a6609901311ec89998a00f7bd72f9d7 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 10/44] Revert "[nrf noup] PSA configuration required changes" This reverts commit 9644dc258228d71e7eff85025e9d67dbc56df789. Signed-off-by: Dominik Ermel --- boot/bootutil/zephyr/CMakeLists.txt | 14 ++--- boot/zephyr/CMakeLists.txt | 39 ++++-------- boot/zephyr/Kconfig | 73 +---------------------- boot/zephyr/include/mcuboot-mbedtls-cfg.h | 2 +- 4 files changed, 16 insertions(+), 112 deletions(-) diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index d5364d025..72a6a8638 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -29,18 +29,12 @@ zephyr_library_link_libraries(MCUBOOT_BOOTUTIL) target_link_libraries(MCUBOOT_BOOTUTIL INTERFACE zephyr_interface) if(CONFIG_BOOT_USE_TINYCRYPT) - target_include_directories(MCUBOOT_BOOTUTIL INTERFACE - ../../../ext/tinycrypt/lib/include - ) -endif() - -if(CONFIG_BOOT_USE_PSA_CRYPTO) - target_include_directories(MCUBOOT_BOOTUTIL INTERFACE - ${ZEPHYR_MBEDTLS_MODULE_DIR}/include - ) +target_include_directories(MCUBOOT_BOOTUTIL INTERFACE + ../../../ext/tinycrypt/lib/include +) endif() -if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO AND NOT CONFIG_PSA_CORE_OBERON) +if(CONFIG_BOOT_USE_MBEDTLS) zephyr_link_libraries(mbedTLS) endif() endif() diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index c5d712e74..fa9f4c68c 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -47,12 +47,6 @@ zephyr_library_include_directories( include ) -if(DEFINED CONFIG_MBEDTLS) - zephyr_library_include_directories( - ${ZEPHYR_MBEDTLS_MODULE_DIR}/include - ) -endif() - # Zephyr port-specific sources. zephyr_library_sources( main.c @@ -104,10 +98,6 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c ) -if(DEFINED CONFIG_BOOT_ENCRYPT_X25519 AND DEFINED CONFIG_BOOT_ED25519_PSA) - zephyr_library_sources(${BOOT_DIR}/bootutil/src/encrypted_psa.c) -endif() - if(DEFINED CONFIG_MEASURED_BOOT OR DEFINED CONFIG_BOOT_SHARE_DATA) zephyr_library_sources( ${BOOT_DIR}/bootutil/src/boot_record.c @@ -248,28 +238,19 @@ elseif(CONFIG_BOOT_SIGNATURE_TYPE_ED25519 OR CONFIG_BOOT_ENCRYPT_X25519) ${FIAT_DIR}/include/ ) - if(NOT CONFIG_BOOT_ED25519_PSA) - zephyr_library_sources( - ${FIAT_DIR}/src/curve25519.c - ) - else() - zephyr_library_sources( - ${MBEDTLS_ASN1_DIR}/src/asn1parse.c - ${BOOT_DIR}/bootutil/src/ed25519_psa.c - ) - endif() + zephyr_library_sources( + ${FIAT_DIR}/src/curve25519.c + ) endif() -if(NOT CONFIG_BOOT_ED25519_PSA) - if(CONFIG_BOOT_ENCRYPT_EC256 OR CONFIG_BOOT_ENCRYPT_X25519) - zephyr_library_sources( - ${TINYCRYPT_DIR}/source/aes_encrypt.c - ${TINYCRYPT_DIR}/source/aes_decrypt.c - ${TINYCRYPT_DIR}/source/ctr_mode.c - ${TINYCRYPT_DIR}/source/hmac.c - ${TINYCRYPT_DIR}/source/ecc_dh.c +if(CONFIG_BOOT_ENCRYPT_EC256 OR CONFIG_BOOT_ENCRYPT_X25519) + zephyr_library_sources( + ${TINYCRYPT_DIR}/source/aes_encrypt.c + ${TINYCRYPT_DIR}/source/aes_decrypt.c + ${TINYCRYPT_DIR}/source/ctr_mode.c + ${TINYCRYPT_DIR}/source/hmac.c + ${TINYCRYPT_DIR}/source/ecc_dh.c ) - endif() endif() if(CONFIG_BOOT_ENCRYPT_EC256) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 778ffca52..8f84e9275 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -29,10 +29,7 @@ config BOOT_USE_MBEDTLS config BOOT_USE_PSA_CRYPTO bool - default y if NRF_SECURITY - # This is counter intuitive but that is how PSA heap is enabled. - select MBEDTLS_ENABLE_HEAP - select MBEDTLS_PSA_CRYPTO_C + # Hidden option help Hidden option set if using PSA crypt for cryptography functionality @@ -69,58 +66,6 @@ config NRF_CC310_BL bool default n -if BOOT_USE_PSA_CRYPTO - -config BOOT_PSA_IMG_HASH_ALG_SHA256_DEPENDENCIES - bool - default y if BOOT_IMG_HASH_ALG_SHA256 - select PSA_WANT_ALG_SHA_256 - help - Dependencies for hashing with SHA256 - -config BOOT_ED25519_PSA_DEPENDENCIES - bool - select PSA_WANT_ALG_SHA_256 - select PSA_WANT_ALG_SHA_512 - select PSA_WANT_ALG_PURE_EDDSA - select PSA_WANT_ECC_TWISTED_EDWARDS_255 - select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT - help - Dependencies for ed25519 signature - -if BOOT_ENCRYPT_IMAGE - -config BOOT_X25519_PSA_DEPENDENCIES - bool - select PSA_WANT_ALG_ECDH - select PSA_WANT_ALG_HMAC - select PSA_WANT_ALG_HKDF - select PSA_WANT_ALG_CTR - select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT - select PSA_WANT_KEY_TYPE_DERIVE - select PSA_WANT_KEY_TYPE_AES - select PSA_WANT_ECC_MONTGOMERY_255 - help - Dependencies for x25519 shared-random key encryption and AES - encryption. The PSA_WANT_ALG_CTR and PSA_WANT_KEY_TYPE_AES - enable Counter based block cipher and AES key, and algorithm support, - to use with it; the others are used for shared key decryption - and derivation. - -endif # BOOT_ENCRYPT_IMAGE - -if MBEDTLS_ENABLE_HEAP - -config MBEDTLS_HEAP_SIZE - default 2048 if BOOT_USE_PSA_CRYPTO - help - The PSA internals need to be able to allocate memory for operation - and it uses mbedTLS heap for that. - -endif # MBEDTLS_ENABLE_HEAP - -endif # BOOT_USE_PSA_CRYPTO - menu "MCUBoot settings" config SINGLE_APPLICATION_SLOT @@ -178,7 +123,6 @@ endchoice # BOOT_IMG_HASH_ALG choice BOOT_SIGNATURE_TYPE prompt "Signature type" - default BOOT_SIGNATURE_TYPE_ED25519 if SOC_NRF54L15_CPUAPP default BOOT_SIGNATURE_TYPE_RSA config BOOT_SIGNATURE_TYPE_NONE @@ -233,24 +177,13 @@ if BOOT_SIGNATURE_TYPE_ED25519 choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" default BOOT_ED25519_TINYCRYPT - config BOOT_ED25519_TINYCRYPT bool "Use tinycrypt" select BOOT_USE_TINYCRYPT - depends on !NRF_SECURITY - config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS select MBEDTLS - depends on !NRF_SECURITY - -config BOOT_ED25519_PSA - bool "Use PSA crypto" - select BOOT_USE_PSA_CRYPTO - select BOOT_ED25519_PSA_DEPENDENCIES - select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE - endchoice endif @@ -295,13 +228,9 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. -if MBEDTLS - config MBEDTLS_CFG_FILE default "mcuboot-mbedtls-cfg.h" -endif - config BOOT_HW_KEY bool "Use HW key for image verification" default n diff --git a/boot/zephyr/include/mcuboot-mbedtls-cfg.h b/boot/zephyr/include/mcuboot-mbedtls-cfg.h index a46fbb09f..2bab537d7 100644 --- a/boot/zephyr/include/mcuboot-mbedtls-cfg.h +++ b/boot/zephyr/include/mcuboot-mbedtls-cfg.h @@ -23,7 +23,7 @@ #if defined(CONFIG_BOOT_SIGNATURE_TYPE_RSA) || defined(CONFIG_BOOT_ENCRYPT_RSA) #include "config-rsa.h" -#elif defined(CONFIG_BOOT_USE_PSA_CRYPTO) || defined(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) || \ +#elif defined(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) || \ defined(CONFIG_BOOT_ENCRYPT_EC256) || \ (defined(CONFIG_BOOT_ENCRYPT_X25519) && !defined(CONFIG_BOOT_SIGNATURE_TYPE_ED25519)) #include "config-asn1.h" From 20e6df9b7f1aeb3f0e7563010f80bd4bf83e7527 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 11/44] Revert "[nrf noup] Fix logging for ED25519_psa" This reverts commit f3c2fbc9234ab08f9f5fdd2f075397a4b3e1d00c. Signed-off-by: Dominik Ermel --- boot/bootutil/src/ed25519_psa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index e84b71d2a..3d7274307 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -13,7 +13,7 @@ #include #include -BOOT_LOG_MODULE_REGISTER(ed25519_psa); +BOOT_LOG_MODULE_DECLARE(ed25519_psa); #define SHA512_DIGEST_LENGTH 64 #define EDDSA_KEY_LENGTH 32 From 7af2e2a8b3c1dedda79dbe7afeef0757ff23afcc Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 12/44] Revert "[nrf noup] Remove setting default MCUboot mbedTLS config" This reverts commit 62929e493c6feb75fc83378d7235280e14a745cc. Signed-off-by: Dominik Ermel --- boot/zephyr/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 9ff1ba274..e4f7d9030 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -1,6 +1,7 @@ CONFIG_PM=n CONFIG_MAIN_STACK_SIZE=10240 +CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" CONFIG_BOOT_SWAP_SAVE_ENCTLV=n CONFIG_BOOT_ENCRYPT_IMAGE=n From 88b537bcc0ca66adcbe1e40d3f8149c503905d9b Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 13/44] Revert "[nrf noup] zephyr: Add support for ARM thumb filter" This reverts commit cbb7da0a51f469b775bcbf9662ae3a905917563b. Signed-off-by: Dominik Ermel --- boot/zephyr/decompression.c | 305 +++++++++--------------------------- 1 file changed, 71 insertions(+), 234 deletions(-) diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c index 35a1950b2..062cdbc61 100644 --- a/boot/zephyr/decompression.c +++ b/boot/zephyr/decompression.c @@ -29,14 +29,6 @@ #define EXPECTED_SIG_TLV IMAGE_TLV_ED25519 #endif -#define DECOMP_BUF_SIZE CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) -#define DECOMP_BUF_EXTRA_SIZE 2 -#else -#define DECOMP_BUF_EXTRA_SIZE 0 -#endif -#define DECOMP_BUF_ALLOC_SIZE (DECOMP_BUF_SIZE + DECOMP_BUF_EXTRA_SIZE) - /* Number of times that consumed data by decompression system can be 0 in a row before aborting */ #define OFFSET_ZERO_CHECK_TIMES 3 @@ -95,22 +87,13 @@ bool boot_is_compressed_header_valid(const struct image_header *hdr, const struc if (size >= size_check) { BOOT_LOG_ERR("Compressed image too large, decompressed image size: 0x%x, slot size: 0x%x", size, size_check); + return false; } return true; } -static bool is_compression_object_valid(struct nrf_compress_implementation *compression) -{ - if (compression == NULL || compression->init == NULL || compression->deinit == NULL || - compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { - return false; - } - - return true; -} - int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index, struct image_header *hdr, const struct flash_area *fap, uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, @@ -121,9 +104,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index uint32_t write_pos = 0; uint32_t protected_tlv_size = 0; uint32_t decompressed_image_size; - uint32_t output_size_total = 0; - struct nrf_compress_implementation *compression_lzma = NULL; - struct nrf_compress_implementation *compression_arm_thumb = NULL; + struct nrf_compress_implementation *compression = NULL; TARGET_STATIC struct image_header modified_hdr; bootutil_sha_context sha_ctx; uint8_t flash_erased_value; @@ -141,26 +122,27 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index */ BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); rc = BOOT_EBADIMAGE; + goto finish_without_clean; } - compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); + compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - if (!is_compression_object_valid(compression_lzma) || - !is_compression_object_valid(compression_arm_thumb)) { + if (compression == NULL || compression->init == NULL || compression->deinit == NULL || + compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { /* Compression library missing or missing required function pointer */ BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; + goto finish_without_clean; } - rc = compression_lzma->init(NULL); - rc = compression_arm_thumb->init(NULL); + rc = compression->init(NULL); if (rc) { BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; + goto finish_without_clean; } @@ -175,6 +157,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; + goto finish; } @@ -189,6 +172,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index if (rc) { BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); rc = BOOT_EBADIMAGE; + goto finish; } @@ -227,6 +211,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); rc = BOOT_EFLASH; + goto finish; } @@ -240,7 +225,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index uint32_t chunk_size; bool last_packet = false; - chunk_size = compression_lzma->decompress_bytes_needed(NULL); + chunk_size = compression->decompress_bytes_needed(NULL); if (chunk_size > (copy_size - tmp_off)) { chunk_size = (copy_size - tmp_off); @@ -250,12 +235,13 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index last_packet = true; } - rc = compression_lzma->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, - &offset, &output, &output_size); + rc = compression->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, &offset, + &output, &output_size); if (rc) { BOOT_LOG_ERR("Decompression error: %d", rc); rc = BOOT_EBADSTATUS; + goto finish; } @@ -265,6 +251,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index BOOT_LOG_ERR("Decompressed image larger than claimed TLV size, at least: %d", write_pos); rc = BOOT_EBADIMAGE; + goto finish; } @@ -273,6 +260,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index /* Last packet and we still have no output, this is a faulty update */ BOOT_LOG_ERR("All compressed data consumed without any output, image not valid"); rc = BOOT_EBADIMAGE; + goto finish; } @@ -283,6 +271,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index if (offset_zero_check >= OFFSET_ZERO_CHECK_TIMES) { BOOT_LOG_ERR("Decompression system returning no output data, image not valid"); rc = BOOT_EBADIMAGE; + goto finish; } @@ -293,48 +282,8 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index offset_zero_check = 0; } - /* Copy data to secondary buffer for calculating hash */ if (output_size > 0) { - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { - /* Run this through the ARM thumb filter */ - uint32_t offset_arm_thumb = 0; - uint8_t *output_arm_thumb = NULL; - uint32_t processed_size = 0; - uint32_t output_size_arm_thumb = 0; - - while (processed_size < output_size) { - uint32_t current_size = output_size - processed_size; - bool arm_thumb_last_packet = false; - - if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { - current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; - } - - if (last_packet && (processed_size + current_size) == - output_size) { - arm_thumb_last_packet = true; - } - - rc = compression_arm_thumb->decompress(NULL, &output[processed_size], - current_size, arm_thumb_last_packet, - &offset_arm_thumb, - &output_arm_thumb, - &output_size_arm_thumb); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - goto finish; - } - - bootutil_sha_update(&sha_ctx, output_arm_thumb, output_size_arm_thumb); - output_size_total += output_size_arm_thumb; - processed_size += current_size; - } - } else { - bootutil_sha_update(&sha_ctx, output, output_size); - output_size_total += output_size; - } + bootutil_sha_update(&sha_ctx, output, output_size); } tmp_off += offset; @@ -343,13 +292,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index read_pos += copy_size; } - if (modified_hdr.ih_img_size != output_size_total) { - BOOT_LOG_ERR("Decompression expected output_size mismatch: %d vs %d", - modified_hdr.ih_img_size, output_size_total); - rc = BOOT_EBADSTATUS; - goto finish; - } - /* If there are any protected TLVs present, add them after the main decompressed image */ if (modified_hdr.ih_protect_tlv_size > 0) { rc = boot_sha_protected_tlvs(hdr, fap, modified_hdr.ih_protect_tlv_size, tmp_buf, @@ -360,8 +302,7 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index finish: /* Clean up decompression system */ - (void)compression_lzma->deinit(NULL); - (void)compression_arm_thumb->deinit(NULL); + (void)compression->deinit(NULL); finish_without_clean: bootutil_sha_drop(&sha_ctx); @@ -412,6 +353,7 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; + goto out; } @@ -480,6 +422,7 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR( "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); + goto out; } @@ -495,6 +438,7 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; + goto out; } @@ -569,6 +513,7 @@ static int boot_sha_protected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR( "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off + read_off), copy_size, fap_src->fa_id, rc); + goto out; } @@ -681,6 +626,7 @@ int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flas */ BOOT_LOG_ERR("No unprotected TLVs in post-decompressed image output, image is invalid"); rc = BOOT_EBADIMAGE; + goto out; } @@ -735,6 +681,7 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; + goto out; } @@ -831,6 +778,7 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR( "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); + goto out; } @@ -846,6 +794,7 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr, "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; + goto out; } @@ -874,17 +823,11 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl uint32_t unprotected_tlv_size = 0; uint32_t tlv_write_size = 0; uint32_t decompressed_image_size; - struct nrf_compress_implementation *compression_lzma = NULL; - struct nrf_compress_implementation *compression_arm_thumb = NULL; + struct nrf_compress_implementation *compression = NULL; struct image_header *hdr; - TARGET_STATIC uint8_t decomp_buf[DECOMP_BUF_ALLOC_SIZE] __attribute__((aligned(4))); + TARGET_STATIC uint8_t decomp_buf[CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE] __attribute__((aligned(4))); TARGET_STATIC struct image_header modified_hdr; -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - uint8_t excess_data_buffer[DECOMP_BUF_EXTRA_SIZE]; - bool excess_data_buffer_full = false; -#endif - hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); /* Setup decompression system */ @@ -898,26 +841,27 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl */ BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); rc = BOOT_EBADIMAGE; + goto finish; } - compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); + compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - if (!is_compression_object_valid(compression_lzma) || - !is_compression_object_valid(compression_arm_thumb)) { + if (compression == NULL || compression->init == NULL || compression->deinit == NULL || + compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { /* Compression library missing or missing required function pointer */ BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; + goto finish; } - rc = compression_lzma->init(NULL); - rc = compression_arm_thumb->init(NULL); + rc = compression->init(NULL); if (rc) { BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; + goto finish; } @@ -930,6 +874,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; + goto finish; } @@ -942,6 +887,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); rc = BOOT_EBADIMAGE; + goto finish; } @@ -952,6 +898,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine unprotected TLV size of compressed image"); rc = BOOT_EBADIMAGE; + goto finish; } @@ -962,6 +909,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", off_dst, sizeof(modified_hdr), fap_dst->fa_id, rc); rc = BOOT_EFLASH; + goto finish; } @@ -980,6 +928,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_src + hdr->ih_hdr_size + pos), copy_size, fap_src->fa_id, rc); rc = BOOT_EFLASH; + goto finish; } @@ -994,7 +943,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl uint8_t *output = NULL; bool last_packet = false; - chunk_size = compression_lzma->decompress_bytes_needed(NULL); + chunk_size = compression->decompress_bytes_needed(NULL); if (chunk_size > (copy_size - tmp_off)) { chunk_size = (copy_size - tmp_off); @@ -1004,142 +953,47 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl last_packet = true; } - rc = compression_lzma->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, - &offset, &output, &output_size); + rc = compression->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, &offset, + &output, &output_size); if (rc) { BOOT_LOG_ERR("Decompression error: %d", rc); rc = BOOT_EBADSTATUS; + goto finish; } /* Copy data to secondary buffer for writing out */ while (output_size > 0) { - uint32_t data_size = (DECOMP_BUF_SIZE - decomp_buf_size); + uint32_t data_size = (sizeof(decomp_buf) - decomp_buf_size); if (data_size > output_size) { data_size = output_size; } -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { - memcpy(&decomp_buf[decomp_buf_size + DECOMP_BUF_EXTRA_SIZE], - &output[compression_buffer_pos], data_size); - } else -#endif - { - memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], - data_size); - } - + memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], data_size); compression_buffer_pos += data_size; decomp_buf_size += data_size; output_size -= data_size; /* Write data out from secondary buffer when it is full */ - if (decomp_buf_size == DECOMP_BUF_SIZE) { -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { - uint32_t filter_writeback_pos = 0; - uint32_t processed_size = 0; - - /* Run this through the ARM thumb filter */ - while (processed_size < DECOMP_BUF_SIZE) { - uint32_t offset_arm_thumb = 0; - uint32_t output_size_arm_thumb = 0; - uint8_t *output_arm_thumb = NULL; - uint32_t current_size = DECOMP_BUF_SIZE; - bool arm_thumb_last_packet = false; - - if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { - current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; - } - - if (last_packet && (processed_size + current_size) == DECOMP_BUF_SIZE - && output_size == 0) { - arm_thumb_last_packet = true; - } - - rc = compression_arm_thumb->decompress(NULL, - &decomp_buf[processed_size + - DECOMP_BUF_EXTRA_SIZE], - current_size, - arm_thumb_last_packet, - &offset_arm_thumb, - &output_arm_thumb, - &output_size_arm_thumb); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - goto finish; - } - - memcpy(&decomp_buf[filter_writeback_pos], output_arm_thumb, - output_size_arm_thumb); - filter_writeback_pos += output_size_arm_thumb; - processed_size += current_size; - } - - if (excess_data_buffer_full == true) - { - /* Restore extra data removed from previous iteration to the write - * buffer - */ - memmove(&decomp_buf[DECOMP_BUF_EXTRA_SIZE], decomp_buf, - filter_writeback_pos); - memcpy(decomp_buf, excess_data_buffer, DECOMP_BUF_EXTRA_SIZE); - excess_data_buffer_full = false; - filter_writeback_pos += DECOMP_BUF_EXTRA_SIZE; - } - - if ((filter_writeback_pos % sizeof(uint32_t)) != 0) - { - /* Since there are an extra 2 bytes here, remove them and stash for - * later usage to prevent flash write issues with non-word boundary - * writes - */ - memcpy(excess_data_buffer, &decomp_buf[filter_writeback_pos - - DECOMP_BUF_EXTRA_SIZE], - DECOMP_BUF_EXTRA_SIZE); - excess_data_buffer_full = true; - filter_writeback_pos -= DECOMP_BUF_EXTRA_SIZE; - } - - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), - decomp_buf, filter_writeback_pos); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), DECOMP_BUF_SIZE, - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - - write_pos += filter_writeback_pos; - decomp_buf_size = 0; - filter_writeback_pos = 0; - } else -#endif - { - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), - decomp_buf, DECOMP_BUF_SIZE); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), DECOMP_BUF_SIZE, - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - - write_pos += DECOMP_BUF_SIZE; - decomp_buf_size = 0; + if (decomp_buf_size == sizeof(decomp_buf)) { + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), + decomp_buf, sizeof(decomp_buf)); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), sizeof(decomp_buf), + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto finish; } + + write_pos += sizeof(decomp_buf); + decomp_buf_size = 0; } } @@ -1149,30 +1003,8 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl pos += copy_size; } -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT && decomp_buf_size > 0) { - /* Extra data that has not been written out that needs ARM thumb filter applied */ - uint32_t offset_arm_thumb = 0; - uint32_t output_size_arm_thumb = 0; - uint8_t *output_arm_thumb = NULL; - - rc = compression_arm_thumb->decompress(NULL, &decomp_buf[DECOMP_BUF_EXTRA_SIZE], - decomp_buf_size, true, &offset_arm_thumb, - &output_arm_thumb, &output_size_arm_thumb); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - goto finish; - } - - memcpy(decomp_buf, output_arm_thumb, output_size_arm_thumb); - } -#endif - /* Clean up decompression system */ - (void)compression_lzma->deinit(NULL); - (void)compression_arm_thumb->deinit(NULL); + (void)compression->deinit(NULL); if (protected_tlv_size > 0) { rc = boot_copy_protected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + @@ -1182,6 +1014,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); + goto finish; } @@ -1196,6 +1029,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); + goto finish; } @@ -1206,7 +1040,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl uint32_t write_padding_size = write_alignment - (decomp_buf_size % write_alignment); /* Check if additional write padding should be applied to meet the minimum write size */ - if (write_alignment > 1 && write_padding_size) { + if (write_padding_size) { uint8_t flash_erased_value; flash_erased_value = flash_area_erased_val(fap_dst); @@ -1222,6 +1056,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_size, fap_dst->fa_id, rc); rc = BOOT_EFLASH; + goto finish; } @@ -1263,6 +1098,7 @@ int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct fl if (len != sizeof(*img_decomp_size)) { BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); + return BOOT_EBADIMAGE; } @@ -1271,6 +1107,7 @@ int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct fl if (rc) { BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", off, len, fap->fa_id, rc); + return BOOT_EFLASH; } From cc47bbb28c8c567cab22f610c15fa7f14761bd6a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 14/44] Revert "[nrf noup] PSA implementation of x25519 and ed25519 verification" This reverts commit 1107145b8496acf8682d5ae223f942f861771405. Signed-off-by: Dominik Ermel --- .../include/bootutil/crypto/aes_ctr.h | 38 +- boot/bootutil/src/ed25519_psa.c | 71 --- boot/bootutil/src/encrypted.c | 114 +++-- boot/bootutil/src/encrypted_psa.c | 454 ------------------ boot/bootutil/src/image_ed25519.c | 13 +- 5 files changed, 59 insertions(+), 631 deletions(-) delete mode 100644 boot/bootutil/src/ed25519_psa.c delete mode 100644 boot/bootutil/src/encrypted_psa.c diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h index 44190361c..50d36a4fc 100644 --- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h @@ -15,8 +15,8 @@ #include "mcuboot_config/mcuboot_config.h" #if (defined(MCUBOOT_USE_MBED_TLS) + \ - defined(MCUBOOT_USE_TINYCRYPT) + defined(MCUBOOT_USE_PSA_CRYPTO)) != 1 - #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT or PSA" + defined(MCUBOOT_USE_TINYCRYPT)) != 1 + #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT" #endif #if defined(MCUBOOT_USE_MBED_TLS) @@ -38,46 +38,12 @@ #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE TC_AES_BLOCK_SIZE #endif /* MCUBOOT_USE_TINYCRYPT */ - -#if defined(MCUBOOT_USE_PSA_CRYPTO) - #include - #include "bootutil/enc_key_public.h" - #define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE - #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16) -#endif - #include #ifdef __cplusplus extern "C" { #endif -#if defined(MCUBOOT_USE_PSA_CRYPTO) -typedef struct { - /* Fixme: This should not be, here, psa_key_id should be passed */ - uint8_t key[BOOT_ENC_KEY_SIZE]; -} bootutil_aes_ctr_context; - -void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx); - -static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) -{ - memset(ctx, 0, sizeof(ctx)); -} - -static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) -{ - memcpy(ctx->key, k, sizeof(ctx->key)); - - return 0; -} - -int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, - const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c); -int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, - const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m); -#endif - #if defined(MCUBOOT_USE_MBED_TLS) typedef mbedtls_aes_context bootutil_aes_ctr_context; static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c deleted file mode 100644 index 3d7274307..000000000 --- a/boot/bootutil/src/ed25519_psa.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ -#include -#include -#include - -#include -#include "bootutil/bootutil_log.h" - -#include -#include - -BOOT_LOG_MODULE_DECLARE(ed25519_psa); - -#define SHA512_DIGEST_LENGTH 64 -#define EDDSA_KEY_LENGTH 32 -#define EDDSA_SIGNAGURE_LENGTH 64 - -int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], - const uint8_t public_key[EDDSA_KEY_LENGTH]) -{ - /* Set to any error */ - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t kid; - int ret = 0; /* Fail by default */ - - /* Initialize PSA Crypto */ - status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - BOOT_LOG_ERR("PSA crypto init failed %d\n", status); - return 0; - } - - status = PSA_ERROR_BAD_STATE; - - psa_set_key_type(&key_attr, - PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS)); - psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE); - psa_set_key_algorithm(&key_attr, PSA_ALG_PURE_EDDSA); - - status = psa_import_key(&key_attr, public_key, EDDSA_KEY_LENGTH, &kid); - if (status != PSA_SUCCESS) { - BOOT_LOG_ERR("ED25519 key import failed %d", status); - return 0; - } - - status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, message_len, - signature, EDDSA_SIGNAGURE_LENGTH); - if (status != PSA_SUCCESS) { - BOOT_LOG_ERR("ED25519 signature verification failed %d", status); - ret = 0; - /* Pass through to destroy key */ - } else { - ret = 1; - /* Pass through to destroy key */ - } - - status = psa_destroy_key(kid); - - if (status != PSA_SUCCESS) { - /* Just for logging */ - BOOT_LOG_WRN("Failed to destroy key %d", status); - } - - return ret; -} diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 67fa819bb..8449a28dd 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -25,7 +25,6 @@ #include "bootutil/crypto/ecdh_p256.h" #endif -#if !defined(MCUBOOT_USE_PSA_CRYPTO) #if defined(MCUBOOT_ENCRYPT_X25519) #include "bootutil/crypto/ecdh_x25519.h" #endif @@ -36,7 +35,6 @@ #include "mbedtls/oid.h" #include "mbedtls/asn1.h" #endif -#endif #include "bootutil/image.h" #include "bootutil/enc_key.h" @@ -45,30 +43,6 @@ #include "bootutil_priv.h" -#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE - -#if defined(MCUBOOT_ENCRYPT_RSA) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048 -#elif defined(MCUBOOT_ENCRYPT_KW) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW -#elif defined(MCUBOOT_ENCRYPT_EC256) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (65) -# define EC_CIPHERKEY_INDEX (65 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-P256 component indexes"); -#elif defined(MCUBOOT_ENCRYPT_X25519) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (32) -# define EC_CIPHERKEY_INDEX (32 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-X25519 component indexes"); -#endif - -/* NOUP Fixme: */ -#if !defined(CONFIG_BOOT_ED25519_PSA) #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) #if defined(_compare) static inline int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size) @@ -377,6 +351,60 @@ int boot_enc_retrieve_private_key(struct bootutil_key **private_key) } #endif /* !MCUBOOT_ENC_BUILTIN_KEY */ +int +boot_enc_init(struct enc_key_data *enc_state, uint8_t slot) +{ + bootutil_aes_ctr_init(&enc_state[slot].aes_ctr); + return 0; +} + +int +boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot) +{ + bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr); + enc_state[slot].valid = 0; + return 0; +} + +int +boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, + const struct boot_status *bs) +{ + int rc; + + rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]); + if (rc != 0) { + boot_enc_drop(enc_state, slot); + return -1; + } + + enc_state[slot].valid = 1; + + return 0; +} + +#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE + +#if defined(MCUBOOT_ENCRYPT_RSA) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048 +#elif defined(MCUBOOT_ENCRYPT_KW) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW +#elif defined(MCUBOOT_ENCRYPT_EC256) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256 +# define EC_PUBK_INDEX (0) +# define EC_TAG_INDEX (65) +# define EC_CIPHERKEY_INDEX (65 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-P256 component indexes"); +#elif defined(MCUBOOT_ENCRYPT_X25519) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 +# define EC_PUBK_INDEX (0) +# define EC_TAG_INDEX (32) +# define EC_CIPHERKEY_INDEX (32 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-X25519 component indexes"); +#endif + #if ( (defined(MCUBOOT_ENCRYPT_RSA) && defined(MCUBOOT_USE_MBED_TLS) && !defined(MCUBOOT_USE_PSA_CRYPTO)) || \ (defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS)) ) #if MBEDTLS_VERSION_NUMBER >= 0x03000000 @@ -599,7 +627,6 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return rc; } -#endif /* CONFIG_BOOT_ED25519_PSA */ /* * Load encryption key. @@ -654,39 +681,6 @@ boot_enc_load(struct enc_key_data *enc_state, int slot, return boot_decrypt_key(buf, bs->enckey[slot]); } -int -boot_enc_init(struct enc_key_data *enc_state, uint8_t slot) -{ - bootutil_aes_ctr_init(&enc_state[slot].aes_ctr); - return 0; -} - -int -boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot) -{ - bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr); - enc_state[slot].valid = 0; - return 0; -} - -int -boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, - const struct boot_status *bs) -{ - int rc; - - rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]); - if (rc != 0) { - boot_enc_drop(enc_state, slot); - return -1; - } - - enc_state[slot].valid = 1; - - return 0; -} - - bool boot_enc_valid(struct enc_key_data *enc_state, int slot) { diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c deleted file mode 100644 index c3f72884d..000000000 --- a/boot/bootutil/src/encrypted_psa.c +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include "mcuboot_config/mcuboot_config.h" - -#include -#include -#include - -/* We are not really using the MBEDTLS but need the ASN.1 parsing functions */ -#define MBEDTLS_ASN1_PARSE_C - -#include "bootutil/crypto/sha.h" -#include "mbedtls/oid.h" -#include "mbedtls/asn1.h" - -#include "bootutil/image.h" -#include "bootutil/enc_key.h" -#include "bootutil/sign_key.h" -#include "bootutil/crypto/common.h" - -#include "bootutil_priv.h" -#include "bootutil/bootutil_log.h" - -BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc); - -#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE -#define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 -#define EC_PUBK_INDEX (0) -#define EC_TAG_INDEX (32) -#define EC_CIPHERKEY_INDEX (32 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-X25519 component indexes"); - -#define X25519_OID "\x6e" -static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ - MBEDTLS_OID_ORG_GOV X25519_OID; - -#define SHARED_KEY_LEN 32 -#define PRIV_KEY_LEN 32 - -/* Fixme: This duplicates code from encrypted.c and depends on mbedtls */ -static int -parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) -{ - size_t len; - int version; - mbedtls_asn1_buf alg; - mbedtls_asn1_buf param; - - if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | - MBEDTLS_ASN1_SEQUENCE) != 0) { - return -1; - } - - if (*p + len != end) { - return -2; - } - - version = 0; - if (mbedtls_asn1_get_int(p, end, &version) || version != 0) { - return -3; - } - - if (mbedtls_asn1_get_alg(p, end, &alg, ¶m) != 0) { - return -4; - } - - if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || - memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { - return -5; - } - - if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) { - return -6; - } - - if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) { - return -7; - } - - if (len != PRIV_KEY_LEN) { - return -8; - } - - memcpy(private_key, *p, PRIV_KEY_LEN); - return 0; -} - -void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) -{ - psa_status_t psa_ret = psa_crypto_init(); - - (void)ctx; - - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES init PSA crypto init failed %d", psa_ret); - assert(0); - } -} - -#if defined(MCUBOOT_ENC_IMAGES) -extern const struct bootutil_key bootutil_enc_key; -/* - * Decrypt an encryption key TLV. - * - * @param buf An encryption TLV read from flash (build time fixed length) - * @param enckey An AES-128 or AES-256 key sized buffer to store to plain key. - */ -int -boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) -{ - uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; - uint8_t *cp; - uint8_t *cpend; - uint8_t private_key[PRIV_KEY_LEN]; - size_t len; - psa_status_t psa_ret = PSA_ERROR_BAD_STATE; - psa_status_t psa_cleanup_ret = PSA_ERROR_BAD_STATE; - psa_key_id_t kid; - psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; - psa_key_derivation_operation_t key_do = PSA_KEY_DERIVATION_OPERATION_INIT; - psa_algorithm_t key_do_alg; - int rc = -1; - - cp = (uint8_t *)bootutil_enc_key.key; - cpend = cp + *bootutil_enc_key.len; - - /* The psa_cipher_decrypt needs initialization vector of proper length at - * the beginning of the input buffer. - */ - uint8_t iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR) + - BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE]; - - psa_ret = psa_crypto_init(); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES crypto init failed %d", psa_ret); - return -1; - } - - /* - * Load the stored X25519 decryption private key - */ - rc = parse_x25519_enckey(&cp, cpend, private_key); - if (rc) { - return rc; - } - - psa_set_key_type(&kattr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY)); - psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DERIVE); - psa_set_key_algorithm(&kattr, PSA_ALG_ECDH); - - psa_ret = psa_import_key(&kattr, private_key, sizeof(private_key), &kid); - memset(private_key, 0, sizeof(private_key)); - psa_reset_key_attributes(&kattr); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("Built-in key import failed %d", psa_ret); - return -1; - } - - key_do_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - - psa_ret = psa_key_derivation_setup(&key_do, key_do_alg); - if (psa_ret != PSA_SUCCESS) { - psa_cleanup_ret = psa_destroy_key(kid); - if (psa_cleanup_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret); - } - BOOT_LOG_ERR("Key derivation setup failed %d", psa_ret); - return -1; - } - - /* Note: PSA 1.1.2 does not have psa_key_agreement that would be useful here - * as it could just add the derived key to the storage and return key id. - * Instead, we have to use the code below to generate derived key and put it - * into storage, to obtain the key id we can then use with psa_mac_* functions. - */ - psa_ret = psa_key_derivation_key_agreement(&key_do, PSA_KEY_DERIVATION_INPUT_SECRET, - kid, &buf[EC_PUBK_INDEX], - BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - psa_cleanup_ret = psa_destroy_key(kid); - if (psa_cleanup_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret); - } - if (psa_ret != PSA_SUCCESS) { - psa_cleanup_ret = psa_key_derivation_abort(&key_do); - if (psa_cleanup_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret); - } - - BOOT_LOG_ERR("Key derivation failed %d", psa_ret); - return -1; - } - - /* Only info, no salt */ - psa_ret = psa_key_derivation_input_bytes(&key_do, PSA_KEY_DERIVATION_INPUT_INFO, - "MCUBoot_ECIES_v1", 16); - if (psa_ret != PSA_SUCCESS) { - psa_cleanup_ret = psa_key_derivation_abort(&key_do); - if (psa_cleanup_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret); - } - BOOT_LOG_ERR("Key derivation failed %d", psa_ret); - return -1; - } - - len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; - psa_ret = psa_key_derivation_output_bytes(&key_do, derived_key, len); - psa_cleanup_ret = psa_key_derivation_abort(&key_do); - if (psa_cleanup_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("Key derivation cleanup failed %d", psa_ret); - } - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("Key derivation failed %d", psa_ret); - return -1; - } - - /* The derived key consists of BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE bytes - * followed by BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. Both parts will - * be imported at the point where needed and discarded immediately after. - */ - psa_set_key_type(&kattr, PSA_KEY_TYPE_HMAC); - psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_VERIFY_MESSAGE); - psa_set_key_algorithm(&kattr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); - - /* Import the MAC tag key part of derived key, that is the part that starts - * after BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE and has length of - * BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. - */ - psa_ret = psa_import_key(&kattr, - &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE], - BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, &kid); - psa_reset_key_attributes(&kattr); - if (psa_ret != PSA_SUCCESS) { - memset(derived_key, 0, sizeof(derived_key)); - BOOT_LOG_ERR("MAC key import failed %d", psa_ret); - return -1; - } - - /* Verify the MAC tag of the random encryption key */ - psa_ret = psa_mac_verify(kid, PSA_ALG_HMAC(PSA_ALG_SHA_256), - &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE, - &buf[EC_TAG_INDEX], - BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - psa_cleanup_ret = psa_destroy_key(kid); - if (psa_cleanup_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("MAC key destruction failed %d", psa_cleanup_ret); - } - if (psa_ret != PSA_SUCCESS) { - memset(derived_key, 0, sizeof(derived_key)); - BOOT_LOG_ERR("MAC verification failed %d", psa_ret); - return -1; - } - - /* The derived key is used in AES decryption of random key */ - psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); - psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&kattr, PSA_ALG_CTR); - - /* Import the AES partition of derived key, the first 16 bytes */ - psa_ret = psa_import_key(&kattr, &derived_key[0], - BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &kid); - memset(derived_key, 0, sizeof(derived_key)); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES key import failed %d", psa_ret); - return -1; - } - - /* Decrypt the random AES encryption key with AES and the key obtained - * at derivation. */ - memset(&iv_and_key[0], 0, PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)); - memcpy(&iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)], - &buf[EC_CIPHERKEY_INDEX], - sizeof(iv_and_key) - PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)); - - len = 0; - psa_ret = psa_cipher_decrypt(kid, PSA_ALG_CTR, iv_and_key, sizeof(iv_and_key), - enckey, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &len); - memset(iv_and_key, 0, sizeof(iv_and_key)); - psa_cleanup_ret = psa_destroy_key(kid); - if (psa_cleanup_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("AES key destruction failed %d", psa_cleanup_ret); - } - if (psa_ret != PSA_SUCCESS || len != BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE) { - memset(enckey, 0, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE); - BOOT_LOG_ERR("Random key decryption failed %d", psa_ret); - return -1; - } - - return 0; -} - -int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, - const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c) -{ - int ret = 0; - psa_status_t psa_ret = PSA_ERROR_BAD_STATE; - psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t kid; - psa_cipher_operation_t psa_op; - size_t elen = 0; /* Decrypted length */ - - /* Fixme: calling psa_crypto_init multiple times is not a problem, - * yet the code here is only present because there is not general - * crypto init. */ - psa_ret = psa_crypto_init(); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret); - ret = -1; - goto gone; - } - - psa_op = psa_cipher_operation_init(); - - /* Fixme: Import should happen when key is decrypted, but due to lack - * of key destruction there is no way to destroy key stored by - * psa other way than here. */ - psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); - psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_ENCRYPT); - psa_set_key_algorithm(&kattr, PSA_ALG_CTR); - - psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); - psa_reset_key_attributes(&kattr); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES enc import key failed %d", psa_ret); - ret = -1; - goto gone; - } - - /* This could be done with psa_cipher_decrypt one-shot operation, but - * multi-part operation is used to avoid re-allocating input buffer - * to account for IV in front of data. - */ - psa_ret = psa_cipher_encrypt_setup(&psa_op, kid, PSA_ALG_CTR); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES enc setup failed %d", psa_ret); - ret = -1; - goto gone_with_key; - } - - /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ - psa_ret = psa_cipher_set_iv(&psa_op, counter, 16); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES enc IV set failed %d", psa_ret); - ret = -1; - goto gone_after_setup; - } - - psa_ret = psa_cipher_update(&psa_op, m, mlen, c, mlen, &elen); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES enc encryption failed %d", psa_ret); - ret = -1; - goto gone_after_setup; - } - -gone_after_setup: - psa_ret = psa_cipher_abort(&psa_op); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("AES enc cipher abort failed %d", psa_ret); - /* Intentionally not changing the ret */ - } -gone_with_key: - /* Fixme: Should be removed once key is shared by id */ - psa_ret = psa_destroy_key(kid); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("AES enc destroy key failed %d", psa_ret); - /* Intentionally not changing the ret */ - } -gone: - return ret; -} - -int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, - const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m) -{ - int ret = 0; - psa_status_t psa_ret = PSA_ERROR_BAD_STATE; - psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t kid; - psa_cipher_operation_t psa_op; - size_t dlen = 0; /* Decrypted length */ - - /* Fixme: the init should already happen before calling the function, but - * somehow it does not, for example when recovering in swap. - */ - psa_ret = psa_crypto_init(); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret); - ret = -1; - goto gone; - } - - psa_op = psa_cipher_operation_init(); - - /* Fixme: Import should happen when key is decrypted, but due to lack - * of key destruction there is no way to destroy key stored by - * psa other way than here. */ - psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); - psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&kattr, PSA_ALG_CTR); - - psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); - psa_reset_key_attributes(&kattr); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES dec import key failed %d", psa_ret); - ret = -1; - goto gone; - } - - /* This could be done with psa_cipher_decrypt one-shot operation, but - * multi-part operation is used to avoid re-allocating input buffer - * to account for IV in front of data. - */ - psa_ret = psa_cipher_decrypt_setup(&psa_op, kid, PSA_ALG_CTR); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES dec setup failed %d", psa_ret); - ret = -1; - goto gone_with_key; - } - - /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ - psa_ret = psa_cipher_set_iv(&psa_op, counter, 16); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES dec IV set failed %d", psa_ret); - ret = -1; - goto gone_after_setup; - } - - psa_ret = psa_cipher_update(&psa_op, c, clen, m, clen, &dlen); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES dec decryption failed %d", psa_ret); - ret = -1; - goto gone_after_setup; - } - -gone_after_setup: - psa_ret = psa_cipher_abort(&psa_op); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("PSA dec abort failed %d", psa_ret); - /* Intentionally not changing the ret */ - } -gone_with_key: - psa_ret = psa_destroy_key(kid); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("PSA dec key failed %d", psa_ret); - /* Intentionally not changing the ret */ - } -gone: - return ret; -} -#endif /* defined(MCUBOOT_ENC_IMAGES) */ diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 897edcad1..4e2423a08 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -9,11 +9,6 @@ #include "mcuboot_config/mcuboot_config.h" -#if defined(CONFIG_NRF_SECURITY) -/* We are not really using the MBEDTLS but need the ASN.1 parsing funcitons */ -#define MBEDTLS_ASN1_PARSE_C -#endif - #ifdef MCUBOOT_SIGN_ED25519 #include "bootutil/sign_key.h" @@ -26,14 +21,12 @@ #include "bootutil/crypto/common.h" #include "bootutil/crypto/sha.h" -#define EDDSA_SIGNATURE_LENGTH 64 - static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; #define NUM_ED25519_BYTES 32 extern int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[EDDSA_SIGNATURE_LENGTH], - const uint8_t public_key[NUM_ED25519_BYTES]); + const uint8_t signature[64], + const uint8_t public_key[32]); /* * Parse the public key used for signing. @@ -83,7 +76,7 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t *pubkey; uint8_t *end; - if (hlen != IMAGE_HASH_SIZE || slen != EDDSA_SIGNATURE_LENGTH) { + if (hlen != IMAGE_HASH_SIZE || slen != 64) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } From 31c9761cd1361e70012537873294e629f7212b16 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 15/44] Revert "[nrf noup] zephyr: Add support for compressed image updates" This reverts commit 655eeacf16cfd090bb309ef06f940a943790e671. Signed-off-by: Dominik Ermel --- boot/bootutil/src/bootutil_misc.c | 80 +- boot/bootutil/src/image_validate.c | 226 ---- boot/bootutil/src/loader.c | 27 +- boot/zephyr/CMakeLists.txt | 6 - boot/zephyr/Kconfig | 10 +- boot/zephyr/decompression.c | 1115 ----------------- .../include/compression/decompression.h | 104 -- 7 files changed, 23 insertions(+), 1545 deletions(-) delete mode 100644 boot/zephyr/decompression.c delete mode 100644 boot/zephyr/include/compression/decompression.h diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index ac50eaa52..56859d515 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -42,11 +42,6 @@ #include "bootutil/enc_key.h" #endif -#if defined(MCUBOOT_DECOMPRESS_IMAGES) -#include -#include -#endif - BOOT_LOG_MODULE_DECLARE(mcuboot); /* Currently only used by imgmgr */ @@ -389,76 +384,35 @@ boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) goto done; } -#ifdef MCUBOOT_DECOMPRESS_IMAGES - if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), boot_img_hdr(state, slot))) { - uint32_t tmp_size = 0; - - rc = bootutil_get_img_decomp_size(boot_img_hdr(state, slot), fap, &tmp_size); - - if (rc) { - rc = BOOT_EBADIMAGE; - goto done; - } - - off = boot_img_hdr(state, slot)->ih_hdr_size + tmp_size; + off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); - rc = boot_size_protected_tlvs(boot_img_hdr(state, slot), fap, &tmp_size); - - if (rc) { - rc = BOOT_EBADIMAGE; - goto done; - } - - off += tmp_size; - - if (flash_area_read(fap, (BOOT_TLV_OFF(boot_img_hdr(state, slot)) + - boot_img_hdr(state, slot)->ih_protect_tlv_size), &info, - sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } + if (flash_area_read(fap, off, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } - if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; + if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { + if (protect_tlv_size != info.it_tlv_tot) { rc = BOOT_EBADIMAGE; goto done; } - *size = off + info.it_tlv_tot; - } else { -#else - if (1) { -#endif - off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); - - if (flash_area_read(fap, off, &info, sizeof(info))) { + if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { rc = BOOT_EFLASH; goto done; } + } else if (protect_tlv_size != 0) { + rc = BOOT_EBADIMAGE; + goto done; + } - protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; - if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { - if (protect_tlv_size != info.it_tlv_tot) { - rc = BOOT_EBADIMAGE; - goto done; - } - - if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } - } else if (protect_tlv_size != 0) { - rc = BOOT_EBADIMAGE; - goto done; - } - - if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { - rc = BOOT_EBADIMAGE; - goto done; - } - - *size = off + protect_tlv_size + info.it_tlv_tot; + if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + rc = BOOT_EBADIMAGE; + goto done; } + *size = off + protect_tlv_size + info.it_tlv_tot; rc = 0; done: diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index b1a50f126..ec5d986df 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -40,15 +40,6 @@ #include "mcuboot_config/mcuboot_config.h" -#if defined(MCUBOOT_DECOMPRESS_IMAGES) -#include -#include -#endif - -#include "bootutil/bootutil_log.h" - -BOOT_LOG_MODULE_DECLARE(mcuboot); - #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -425,68 +416,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, FIH_DECLARE(security_counter_valid, FIH_FAILURE); #endif -#ifdef MCUBOOT_DECOMPRESS_IMAGES - /* If the image is compressed, the integrity of the image must also be validated */ - if (MUST_DECOMPRESS(fap, image_index, hdr)) { - bool found_decompressed_size = false; - bool found_decompressed_sha = false; - bool found_decompressed_signature = false; - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(fap)) { - rc = -1; - goto out; - } - - while (true) { - uint16_t expected_size = 0; - bool *found_flag = NULL; - - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - break; - } - - switch (type) { - case IMAGE_TLV_DECOMP_SIZE: - expected_size = sizeof(size_t); - found_flag = &found_decompressed_size; - break; - case IMAGE_TLV_DECOMP_SHA: - expected_size = IMAGE_HASH_SIZE; - found_flag = &found_decompressed_sha; - break; - case IMAGE_TLV_DECOMP_SIGNATURE: - found_flag = &found_decompressed_signature; - break; - default: - continue; - }; - - if (type == IMAGE_TLV_DECOMP_SIGNATURE && !EXPECTED_SIG_LEN(len)) { - rc = -1; - goto out; - } else if (type != IMAGE_TLV_DECOMP_SIGNATURE && len != expected_size) { - rc = -1; - goto out; - } - - *found_flag = true; - } - - rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature); - if (rc) { - goto out; - } - } -#endif - rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); if (rc) { @@ -658,161 +587,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } #endif -#ifdef MCUBOOT_DECOMPRESS_IMAGES - /* Only after all previous verifications have passed, perform a dry-run of the decompression - * and ensure the image is valid - */ - if (!rc && MUST_DECOMPRESS(fap, image_index, hdr)) { - image_hash_valid = 0; - FIH_SET(valid_signature, FIH_FAILURE); - - rc = bootutil_img_hash_decompress(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz, - hash, seed, seed_len); - if (rc) { - goto out; - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SHA, true); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(fap)) { - rc = -1; - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - break; - } - - if (type == IMAGE_TLV_DECOMP_SHA) { - /* Verify the image hash. This must always be present. */ - if (len != sizeof(hash)) { - rc = -1; - goto out; - } - rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash)); - if (rc) { - goto out; - } - - FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash)); - if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; - } - - image_hash_valid = 1; - } - } - - rc = !image_hash_valid; - if (rc) { - goto out; - } - -#ifdef EXPECTED_SIG_TLV -#ifdef EXPECTED_KEY_TLV - rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(fap)) { - rc = -1; - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - break; - } - - if (type == EXPECTED_KEY_TLV) { - /* - * Determine which key we should be checking. - */ - if (len > KEY_BUF_SIZE) { - rc = -1; - goto out; - } -#ifndef MCUBOOT_HW_KEY - rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); - if (rc) { - goto out; - } - key_id = bootutil_find_key(buf, len); -#else - rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len); - if (rc) { - goto out; - } - key_id = bootutil_find_key(image_index, key_buf, len); -#endif /* !MCUBOOT_HW_KEY */ - /* - * The key may not be found, which is acceptable. There - * can be multiple signatures, each preceded by a key. - */ - } - } -#endif /* EXPECTED_KEY_TLV */ - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(fap)) { - rc = -1; - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIGNATURE) { - /* Ignore this signature if it is out of bounds. */ - if (key_id < 0 || key_id >= bootutil_key_cnt) { - key_id = -1; - continue; - } - - if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { - rc = -1; - goto out; - } - rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); - if (rc) { - goto out; - } - - FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), - buf, len, key_id); - key_id = -1; - } - } -#endif /* EXPECTED_SIG_TLV */ - } -#endif - -#ifdef EXPECTED_SIG_TLV - FIH_SET(fih_rc, valid_signature); -#endif - out: if (rc) { FIH_SET(fih_rc, FIH_FAILURE); diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a561d5cb7..4c61c4217 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -49,11 +49,6 @@ #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" -#if defined(MCUBOOT_DECOMPRESS_IMAGES) -#include -#include -#endif - #ifdef __ZEPHYR__ #include #endif @@ -918,10 +913,10 @@ boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fa return false; } #else - if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) { - if (!boot_is_compressed_header_valid(hdr, fap, state)) { - return false; - } + if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) && + (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) + { + return false; } #endif @@ -1135,7 +1130,6 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * attempts to validate and boot it. */ } - #if !defined(__BOOTSIM__) BOOT_LOG_ERR("Image in the %s slot is not valid!", (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary"); @@ -1612,9 +1606,6 @@ boot_copy_region(struct boot_loader_state *state, #else (void)state; #endif -#ifdef MCUBOOT_DECOMPRESS_IMAGES - struct image_header *hdr; -#endif TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4))); @@ -1640,16 +1631,6 @@ boot_copy_region(struct boot_loader_state *state, } #endif -#ifdef MCUBOOT_DECOMPRESS_IMAGES - hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); - - if (MUST_DECOMPRESS(fap_src, BOOT_CURR_IMG(state), hdr)) { - /* Use alternative function for compressed images */ - return boot_copy_region_decompress(state, fap_src, fap_dst, off_src, off_dst, sz, buf, - BUF_SZ); - } -#endif - bytes_copied = 0; while (bytes_copied < sz) { if (sz - bytes_copied > sizeof buf) { diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index fa9f4c68c..cdc32e346 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -259,12 +259,6 @@ if(CONFIG_BOOT_ENCRYPT_EC256) ) endif() -if(CONFIG_BOOT_DECOMPRESSION) - zephyr_library_sources( - decompression.c - ) -endif() - if(CONFIG_MCUBOOT_SERIAL) zephyr_sources(${BOOT_DIR}/zephyr/serial_adapter.c) zephyr_sources(${BOOT_DIR}/boot_serial/src/boot_serial.c) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 8f84e9275..a13201969 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -818,10 +818,6 @@ config BOOT_BANNER_STRING config BOOT_DECOMPRESSION_SUPPORT bool - depends on NRF_COMPRESS && NRF_COMPRESS_DECOMPRESSION && (NRF_COMPRESS_LZMA_VERSION_LZMA1 || NRF_COMPRESS_LZMA_VERSION_LZMA2) - depends on !SINGLE_APPLICATION_SLOT && !BOOT_ENCRYPT_IMAGE && BOOT_UPGRADE_ONLY - depends on UPDATEABLE_IMAGE_NUMBER = 1 - default y help Hidden symbol which should be selected if a system provided decompression support. @@ -829,8 +825,6 @@ if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION bool "Decompression" - select NRF_COMPRESS_CLEANUP - select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to @@ -839,9 +833,9 @@ menuconfig BOOT_DECOMPRESSION if BOOT_DECOMPRESSION config BOOT_DECOMPRESSION_BUFFER_SIZE - int + int "Write buffer size" range 16 16384 - default NRF_COMPRESS_CHUNK_SIZE + default 4096 help The size of a secondary buffer used for writing decompressed data to the storage device. diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c deleted file mode 100644 index 062cdbc61..000000000 --- a/boot/zephyr/decompression.c +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include -#include "compression/decompression.h" -#include "bootutil/crypto/sha.h" -#include "bootutil/bootutil_log.h" - -#if !defined(__BOOTSIM__) -#define TARGET_STATIC static -#else -#define TARGET_STATIC -#endif - -#if defined(MCUBOOT_SIGN_RSA) -#if MCUBOOT_SIGN_RSA_LEN == 2048 -#define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048_PSS -#elif MCUBOOT_SIGN_RSA_LEN == 3072 -#define EXPECTED_SIG_TLV IMAGE_TLV_RSA3072_PSS -#endif -#elif defined(MCUBOOT_SIGN_EC256) || \ - defined(MCUBOOT_SIGN_EC384) || \ - defined(MCUBOOT_SIGN_EC) -#define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG -#elif defined(MCUBOOT_SIGN_ED25519) -#define EXPECTED_SIG_TLV IMAGE_TLV_ED25519 -#endif - -/* Number of times that consumed data by decompression system can be 0 in a row before aborting */ -#define OFFSET_ZERO_CHECK_TIMES 3 - -BOOT_LOG_MODULE_DECLARE(mcuboot); - -static int boot_sha_protected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, uint32_t protected_size, - uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx); - -bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, - struct boot_loader_state *state) -{ - /* Image is compressed in secondary slot, need to check if fits into the primary slot */ - bool opened_flash_area = false; - int primary_fa_id; - int rc; - int size_check; - int size; - uint32_t protected_tlvs_size; - uint32_t decompressed_size; - - if (BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT) == NULL) { - opened_flash_area = true; - } - - primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); - rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); - assert(rc == 0); - - size_check = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); - - if (opened_flash_area) { - (void)flash_area_close(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); - } - - rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_size); - - if (rc) { - return false; - } - - if (!boot_u32_safe_add(&size, decompressed_size, hdr->ih_hdr_size)) { - return false; - } - - rc = boot_size_protected_tlvs(hdr, fap, &protected_tlvs_size); - - if (rc) { - return false; - } - - if (!boot_u32_safe_add(&size, size, protected_tlvs_size)) { - return false; - } - - if (size >= size_check) { - BOOT_LOG_ERR("Compressed image too large, decompressed image size: 0x%x, slot size: 0x%x", - size, size_check); - - return false; - } - - return true; -} - -int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index, - struct image_header *hdr, const struct flash_area *fap, - uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, - uint8_t *seed, int seed_len) -{ - int rc; - uint32_t read_pos = 0; - uint32_t write_pos = 0; - uint32_t protected_tlv_size = 0; - uint32_t decompressed_image_size; - struct nrf_compress_implementation *compression = NULL; - TARGET_STATIC struct image_header modified_hdr; - bootutil_sha_context sha_ctx; - uint8_t flash_erased_value; - - bootutil_sha_init(&sha_ctx); - - /* Setup decompression system */ -#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { -#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { -#endif - /* Compressed image does not use the correct compression type which is supported by this - * build - */ - BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); - rc = BOOT_EBADIMAGE; - - goto finish_without_clean; - } - - compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - - if (compression == NULL || compression->init == NULL || compression->deinit == NULL || - compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { - /* Compression library missing or missing required function pointer */ - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - - goto finish_without_clean; - } - - rc = compression->init(NULL); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - - goto finish_without_clean; - } - - /* We need a modified header which has the updated sizes, start with the original header */ - memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); - - /* Extract the decompressed image size from the protected TLV, set it and remove the - * compressed image flags - */ - rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; - modified_hdr.ih_img_size = decompressed_image_size; - - /* Calculate the protected TLV size, these will not include the decompressed - * sha/size/signature entries - */ - rc = boot_size_protected_tlvs(hdr, fap, &protected_tlv_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - modified_hdr.ih_protect_tlv_size = protected_tlv_size; - bootutil_sha_update(&sha_ctx, &modified_hdr, sizeof(modified_hdr)); - read_pos = sizeof(modified_hdr); - flash_erased_value = flash_area_erased_val(fap); - memset(tmp_buf, flash_erased_value, tmp_buf_sz); - - while (read_pos < modified_hdr.ih_hdr_size) { - uint32_t copy_size = tmp_buf_sz; - - if ((read_pos + copy_size) > modified_hdr.ih_hdr_size) { - copy_size = modified_hdr.ih_hdr_size - read_pos; - } - - bootutil_sha_update(&sha_ctx, tmp_buf, copy_size); - read_pos += copy_size; - } - - /* Read in compressed data, decompress and add to hash calculation */ - read_pos = 0; - - while (read_pos < hdr->ih_img_size) { - uint32_t copy_size = hdr->ih_img_size - read_pos; - uint32_t tmp_off = 0; - uint8_t offset_zero_check = 0; - - if (copy_size > tmp_buf_sz) { - copy_size = tmp_buf_sz; - } - - rc = flash_area_read(fap, (hdr->ih_hdr_size + read_pos), tmp_buf, copy_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); - rc = BOOT_EFLASH; - - goto finish; - } - - /* Decompress data in chunks, writing it back with a larger write offset of the primary - * slot than read size of the secondary slot - */ - while (tmp_off < copy_size) { - uint32_t offset = 0; - uint8_t *output = NULL; - uint32_t output_size = 0; - uint32_t chunk_size; - bool last_packet = false; - - chunk_size = compression->decompress_bytes_needed(NULL); - - if (chunk_size > (copy_size - tmp_off)) { - chunk_size = (copy_size - tmp_off); - } - - if ((read_pos + tmp_off + chunk_size) >= hdr->ih_img_size) { - last_packet = true; - } - - rc = compression->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, &offset, - &output, &output_size); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - - goto finish; - } - - write_pos += output_size; - - if (write_pos > decompressed_image_size) { - BOOT_LOG_ERR("Decompressed image larger than claimed TLV size, at least: %d", - write_pos); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - /* Additional dry-run validity checks */ - if (last_packet == true && write_pos == 0) { - /* Last packet and we still have no output, this is a faulty update */ - BOOT_LOG_ERR("All compressed data consumed without any output, image not valid"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - if (offset == 0) { - /* If the decompression system continually consumes 0 bytes, then there is a - * problem with this update image, abort and mark image as bad - */ - if (offset_zero_check >= OFFSET_ZERO_CHECK_TIMES) { - BOOT_LOG_ERR("Decompression system returning no output data, image not valid"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - ++offset_zero_check; - - break; - } else { - offset_zero_check = 0; - } - - if (output_size > 0) { - bootutil_sha_update(&sha_ctx, output, output_size); - } - - tmp_off += offset; - } - - read_pos += copy_size; - } - - /* If there are any protected TLVs present, add them after the main decompressed image */ - if (modified_hdr.ih_protect_tlv_size > 0) { - rc = boot_sha_protected_tlvs(hdr, fap, modified_hdr.ih_protect_tlv_size, tmp_buf, - tmp_buf_sz, &sha_ctx); - } - - bootutil_sha_finish(&sha_ctx, hash_result); - -finish: - /* Clean up decompression system */ - (void)compression->deinit(NULL); - -finish_without_clean: - bootutil_sha_drop(&sha_ctx); - - return rc; -} - -static int boot_copy_protected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_dst, - uint32_t protected_size, uint8_t *buf, size_t buf_size, - uint16_t *buf_pos, uint32_t *written) -{ - int rc; - uint32_t off; - uint32_t write_pos = 0; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - struct image_tlv tlv_header; - struct image_tlv_info tlv_info_header = { - .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, - .it_tlv_tot = protected_size, - }; - uint16_t info_size_left = sizeof(tlv_info_header); - - while (info_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - - if (info_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; - - if (single_copy_size > info_size_left) { - single_copy_size = info_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - - info_size_left], single_copy_size); - *buf_pos += single_copy_size; - info_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE) { - /* Skip these TLVs as they are not needed */ - continue; - } else { - uint16_t header_size_left = sizeof(tlv_header); - uint16_t data_size_left = len; - - tlv_header.it_type = type; - tlv_header.it_len = len; - - while (header_size_left > 0 || data_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - uint8_t *tlv_header_address = (uint8_t *)&tlv_header; - - if (header_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - - if (single_copy_size > header_size_left) { - single_copy_size = header_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - - header_size_left], - single_copy_size); - *buf_pos += single_copy_size; - copy_size -= single_copy_size; - header_size_left -= single_copy_size; - } - - if (data_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - - if (single_copy_size > data_size_left) { - single_copy_size = data_size_left; - } - - rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + (len - data_size_left)), - &buf[*buf_pos], single_copy_size); - - if (rc) { - BOOT_LOG_ERR( - "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); - - goto out; - } - - *buf_pos += single_copy_size; - data_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - } - } - - *written = write_pos; - -out: - return rc; -} - -static int boot_sha_protected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, uint32_t protected_size, - uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx) -{ - int rc; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - struct image_tlv tlv_header; - struct image_tlv_info tlv_info_header = { - .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, - .it_tlv_tot = protected_size, - }; - - bootutil_sha_update(sha_ctx, &tlv_info_header, sizeof(tlv_info_header)); - - rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); - if (rc) { - goto out; - } - - while (true) { - uint32_t read_off = 0; - - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE) { - /* Skip these TLVs as they are not needed */ - continue; - } - - tlv_header.it_type = type; - tlv_header.it_len = len; - - bootutil_sha_update(sha_ctx, &tlv_header, sizeof(tlv_header)); - - while (read_off < len) { - uint32_t copy_size = buf_size; - - if (copy_size > (len - read_off)) { - copy_size = len - read_off; - } - - rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + read_off), buf, copy_size); - - if (rc) { - BOOT_LOG_ERR( - "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off + read_off), copy_size, fap_src->fa_id, rc); - - goto out; - } - - bootutil_sha_update(sha_ctx, buf, copy_size); - read_off += copy_size; - } - } - -out: - return rc; -} - -int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *sz) -{ - int rc = 0; - uint32_t tlv_size; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - - *sz = 0; - tlv_size = hdr->ih_protect_tlv_size; - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE) { - /* Exclude these TLVs as they will be copied to the unprotected area */ - tlv_size -= len + sizeof(struct image_tlv); - } - } - - if (!rc) { - if (tlv_size == sizeof(struct image_tlv_info)) { - /* If there are no entries then omit protected TLV section entirely */ - tlv_size = 0; - } - - *sz = tlv_size; - } - -out: - return rc; -} - -int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *sz) -{ - int rc = 0; - uint32_t tlv_size; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - - *sz = 0; - tlv_size = sizeof(struct image_tlv_info); - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } else if (bootutil_tlv_iter_is_prot(&it, off) && type != IMAGE_TLV_DECOMP_SHA && - type != IMAGE_TLV_DECOMP_SIGNATURE) { - /* Include size of protected hash and signature as these will be replacing the - * original ones - */ - continue; - } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { - /* Exclude the original unprotected TLVs for signature and hash, the length of the - * signature of the compressed data might not be the same size as the signaute of the - * decompressed data, as is the case when using ECDSA-P256 - */ - continue; - } - - tlv_size += len + sizeof(struct image_tlv); - } - - if (!rc) { - if (tlv_size == sizeof(struct image_tlv_info)) { - /* If there are no entries in the unprotected TLV section then there is something wrong - * with this image - */ - BOOT_LOG_ERR("No unprotected TLVs in post-decompressed image output, image is invalid"); - rc = BOOT_EBADIMAGE; - - goto out; - } - - *sz = tlv_size; - } - -out: - return rc; -} - -static int boot_copy_unprotected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_dst, - uint32_t unprotected_size, uint8_t *buf, size_t buf_size, - uint16_t *buf_pos, uint32_t *written) -{ - int rc; - uint32_t write_pos = 0; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - struct image_tlv_iter it_protected; - struct image_tlv tlv_header; - struct image_tlv_info tlv_info_header = { - .it_magic = IMAGE_TLV_INFO_MAGIC, - .it_tlv_tot = unprotected_size, - }; - uint16_t info_size_left = sizeof(tlv_info_header); - - while (info_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - - if (info_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; - - if (single_copy_size > info_size_left) { - single_copy_size = info_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - - info_size_left], single_copy_size); - *buf_pos += single_copy_size; - info_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, false); - if (rc) { - goto out; - } - - while (true) { - uint16_t header_size_left = sizeof(tlv_header); - uint16_t data_size_left; - - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } else if (bootutil_tlv_iter_is_prot(&it, off)) { - /* Skip protected TLVs */ - continue; - } - - /* Change the values of these fields from having the data in the compressed image - * unprotected TLV (which is valid only for the compressed image data) to having the - * fields in the protected TLV section (which is valid for the decompressed image data). - * The compressed data is no longer needed - */ - if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { - rc = bootutil_tlv_iter_begin(&it_protected, hdr, fap_src, (type == EXPECTED_HASH_TLV ? - IMAGE_TLV_DECOMP_SHA : - IMAGE_TLV_DECOMP_SIGNATURE), - true); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it_protected, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - } - - if (type == IMAGE_TLV_DECOMP_SHA) { - type = EXPECTED_HASH_TLV; - } else { - type = EXPECTED_SIG_TLV; - } - } - - data_size_left = len; - tlv_header.it_type = type; - tlv_header.it_len = len; - - while (header_size_left > 0 || data_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - - if (header_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - uint8_t *tlv_header_address = (uint8_t *)&tlv_header; - - if (single_copy_size > header_size_left) { - single_copy_size = header_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - header_size_left], - single_copy_size); - *buf_pos += single_copy_size; - copy_size -= single_copy_size; - header_size_left -= single_copy_size; - } - - if (data_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - - if (single_copy_size > data_size_left) { - single_copy_size = data_size_left; - } - - rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + len - data_size_left), - &buf[*buf_pos], single_copy_size); - - if (rc) { - BOOT_LOG_ERR( - "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); - - goto out; - } - - *buf_pos += single_copy_size; - data_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - } - - *written = write_pos; - -out: - return rc; -} - -int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_src, - uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size) -{ - int rc; - uint32_t pos = 0; - uint16_t decomp_buf_size = 0; - uint16_t write_alignment; - uint32_t write_pos = 0; - uint32_t protected_tlv_size = 0; - uint32_t unprotected_tlv_size = 0; - uint32_t tlv_write_size = 0; - uint32_t decompressed_image_size; - struct nrf_compress_implementation *compression = NULL; - struct image_header *hdr; - TARGET_STATIC uint8_t decomp_buf[CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE] __attribute__((aligned(4))); - TARGET_STATIC struct image_header modified_hdr; - - hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); - - /* Setup decompression system */ -#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { -#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { -#endif - /* Compressed image does not use the correct compression type which is supported by this - * build - */ - BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - - if (compression == NULL || compression->init == NULL || compression->deinit == NULL || - compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { - /* Compression library missing or missing required function pointer */ - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - - goto finish; - } - - rc = compression->init(NULL); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - - goto finish; - } - - write_alignment = flash_area_align(fap_dst); - - memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); - - rc = bootutil_get_img_decomp_size(hdr, fap_src, &decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; - modified_hdr.ih_img_size = decompressed_image_size; - - /* Calculate protected TLV size for target image once items are removed */ - rc = boot_size_protected_tlvs(hdr, fap_src, &protected_tlv_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - modified_hdr.ih_protect_tlv_size = protected_tlv_size; - - rc = boot_size_unprotected_tlvs(hdr, fap_src, &unprotected_tlv_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine unprotected TLV size of compressed image"); - rc = BOOT_EBADIMAGE; - - goto finish; - } - - /* Write out the image header first, this should be a multiple of the write size */ - rc = flash_area_write(fap_dst, off_dst, &modified_hdr, sizeof(modified_hdr)); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - off_dst, sizeof(modified_hdr), fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto finish; - } - - /* Read in, decompress and write out data */ - while (pos < hdr->ih_img_size) { - uint32_t copy_size = hdr->ih_img_size - pos; - uint32_t tmp_off = 0; - - if (copy_size > buf_size) { - copy_size = buf_size; - } - - rc = flash_area_read(fap_src, off_src + hdr->ih_hdr_size + pos, buf, copy_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_src + hdr->ih_hdr_size + pos), copy_size, fap_src->fa_id, rc); - rc = BOOT_EFLASH; - - goto finish; - } - - /* Decompress data in chunks, writing it back with a larger write offset of the primary - * slot than read size of the secondary slot - */ - while (tmp_off < copy_size) { - uint32_t offset = 0; - uint32_t output_size = 0; - uint32_t chunk_size; - uint32_t compression_buffer_pos = 0; - uint8_t *output = NULL; - bool last_packet = false; - - chunk_size = compression->decompress_bytes_needed(NULL); - - if (chunk_size > (copy_size - tmp_off)) { - chunk_size = (copy_size - tmp_off); - } - - if ((pos + tmp_off + chunk_size) >= hdr->ih_img_size) { - last_packet = true; - } - - rc = compression->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, &offset, - &output, &output_size); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - - goto finish; - } - - /* Copy data to secondary buffer for writing out */ - while (output_size > 0) { - uint32_t data_size = (sizeof(decomp_buf) - decomp_buf_size); - - if (data_size > output_size) { - data_size = output_size; - } - - memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], data_size); - compression_buffer_pos += data_size; - - decomp_buf_size += data_size; - output_size -= data_size; - - /* Write data out from secondary buffer when it is full */ - if (decomp_buf_size == sizeof(decomp_buf)) { - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), - decomp_buf, sizeof(decomp_buf)); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), sizeof(decomp_buf), - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto finish; - } - - write_pos += sizeof(decomp_buf); - decomp_buf_size = 0; - } - } - - tmp_off += offset; - } - - pos += copy_size; - } - - /* Clean up decompression system */ - (void)compression->deinit(NULL); - - if (protected_tlv_size > 0) { - rc = boot_copy_protected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + - write_pos), protected_tlv_size, - decomp_buf, DECOMP_BUF_SIZE, &decomp_buf_size, - &tlv_write_size); - - if (rc) { - BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); - - goto finish; - } - - write_pos += tlv_write_size; - } - - tlv_write_size = 0; - rc = boot_copy_unprotected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + - write_pos), unprotected_tlv_size, - decomp_buf, DECOMP_BUF_SIZE, &decomp_buf_size, - &tlv_write_size); - - if (rc) { - BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); - - goto finish; - } - - write_pos += tlv_write_size; - - /* Check if we have unwritten data buffered up and, if so, write it out */ - if (decomp_buf_size > 0) { - uint32_t write_padding_size = write_alignment - (decomp_buf_size % write_alignment); - - /* Check if additional write padding should be applied to meet the minimum write size */ - if (write_padding_size) { - uint8_t flash_erased_value; - - flash_erased_value = flash_area_erased_val(fap_dst); - memset(&decomp_buf[decomp_buf_size], flash_erased_value, write_padding_size); - decomp_buf_size += write_padding_size; - } - - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf, - decomp_buf_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_size, - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto finish; - } - - write_pos += decomp_buf_size; - decomp_buf_size = 0; - } - -finish: - memset(decomp_buf, 0, sizeof(decomp_buf)); - - return rc; -} - -int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *img_decomp_size) -{ - struct image_tlv_iter it; - uint32_t off; - uint16_t len; - int32_t rc; - - if (hdr == NULL || fap == NULL || img_decomp_size == NULL) { - return BOOT_EBADARGS; - } else if (hdr->ih_protect_tlv_size == 0) { - return BOOT_EBADIMAGE; - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIZE, true); - - if (rc) { - return rc; - } - - rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); - - if (rc != 0) { - return -1; - } - - if (len != sizeof(*img_decomp_size)) { - BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); - - return BOOT_EBADIMAGE; - } - - rc = LOAD_IMAGE_DATA(hdr, fap, off, img_decomp_size, len); - - if (rc) { - BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - off, len, fap->fa_id, rc); - - return BOOT_EFLASH; - } - - return 0; -} diff --git a/boot/zephyr/include/compression/decompression.h b/boot/zephyr/include/compression/decompression.h deleted file mode 100644 index f8a676ac5..000000000 --- a/boot/zephyr/include/compression/decompression.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#ifndef H_DECOMPRESSION_ -#define H_DECOMPRESSION_ - -#include -#include -#include -#include "bootutil/bootutil.h" -#include "bootutil/bootutil_public.h" -#include "bootutil/image.h" -#include "../src/bootutil_priv.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Checks if a compressed image header is valid. - * - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param state Bootloader state object. - * - * @return true if valid; false if invalid. - */ -bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, - struct boot_loader_state *state); - -/** - * Reads in compressed image data from a slot, decompresses it and writes it out to a destination - * slot, including corresponding image headers and TLVs. - * - * @param state Bootloader state object. - * @param fap_src Flash area of the source slot. - * @param fap_dst Flash area of the destination slot. - * @param off_src Offset of the source slot to read from (should be 0). - * @param off_dst Offset of the destination slot to write to (should be 0). - * @param sz Size of the source slot data. - * @param buf Temporary buffer for reading data from. - * @param buf_size Size of temporary buffer. - * - * @return 0 on success; nonzero on failure. - */ -int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_src, - uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size); - -/** - * Gets the total data size (excluding headers and TLVs) of a compressed image when it is - * decompressed. - * - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param img_decomp_size Pointer to variable that will be updated with the decompressed image - * size. - * - * @return 0 on success; nonzero on failure. - */ -int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *img_decomp_size); - -/** - * Calculate MCUboot-compatible image hash of compressed image slot. - * - * @param enc_state Not currently used, set to NULL. - * @param image_index Image number. - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param tmp_buf Temporary buffer for reading data from. - * @param tmp_buf_sz Size of temporary buffer. - * @param hash_result Pointer to a variable that will be updated with the image hash. - * @param seed Not currently used, set to NULL. - * @param seed_len Not currently used, set to 0. - * - * @return 0 on success; nonzero on failure. - */ -int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index, - struct image_header *hdr, const struct flash_area *fap, - uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, - uint8_t *seed, int seed_len); - -/** - * Calculates the size that the compressed image protected TLV section will occupy once the image - * has been decompressed. - * - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param sz Pointer to variable that will be updated with the protected TLV size. - * - * @return 0 on success; nonzero on failure. - */ -int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap_src, - uint32_t *sz); - -#ifdef __cplusplus -} -#endif - -#endif /* H_DECOMPRESSION_ */ From ee74f6cfc9fde1c4f2c4b4b332d4682bf5a9742a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 14:44:12 +0000 Subject: [PATCH 16/44] Revert "[nrf noup] zephyr: Fix path variables" This reverts commit 4943e2f425738025e48efc74d323884c4effdf4d. Signed-off-by: Dominik Ermel --- boot/zephyr/CMakeLists.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index cdc32e346..6522f8572 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -27,20 +27,21 @@ assert_exists(FIAT_DIR) # Path to mbed-tls' asn1 parser library. set(MBEDTLS_ASN1_DIR "${MCUBOOT_DIR}/ext/mbedtls-asn1") assert_exists(MBEDTLS_ASN1_DIR) -set(MCUBOOT_NRF_EXT_DIR "${MCUBOOT_DIR}/ext/nrf") +set(NRF_DIR "${MCUBOOT_DIR}/ext/nrf") if(CONFIG_BOOT_USE_NRF_CC310_BL) - if(NOT EXISTS ${ZEPHYR_NRFXLIB_MODULE_DIR}) - message(FATAL_ERROR " +set(NRFXLIB_DIR ${ZEPHYR_BASE}/../nrfxlib) +if(NOT EXISTS ${NRFXLIB_DIR}) + message(FATAL_ERROR " ------------------------------------------------------------------------ - No such file or directory: ${ZEPHYR_NRFXLIB_MODULE_DIR} + No such file or directory: ${NRFXLIB_DIR} The current configuration enables nRF CC310 crypto accelerator hardware with the `CONFIG_BOOT_USE_NRF_CC310_BL` option. Please follow `ext/nrf/README.md` guide to fix your setup or use tinycrypt instead of the HW accelerator. To use the tinycrypt set `CONFIG_BOOT_ECDSA_TINYCRYPT` to y. ------------------------------------------------------------------------") - endif() +endif() endif() zephyr_library_include_directories( @@ -176,8 +177,8 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) ${TINYCRYPT_DIR}/source/utils.c ) elseif(CONFIG_BOOT_USE_NRF_CC310_BL) - zephyr_library_sources(${MCUBOOT_NRF_EXT_DIR}/cc310_glue.c) - zephyr_library_include_directories(${MCUBOOT_NRF_EXT_DIR}) + zephyr_library_sources(${NRF_DIR}/cc310_glue.c) + zephyr_library_include_directories(${NRF_DIR}) zephyr_link_libraries(nrfxlib_crypto) elseif(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) zephyr_include_directories(${BL_CRYPTO_DIR}/../include) From ed16d23e007e465d1fe5deade0fab88d3848dba8 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 22 Jan 2025 16:03:53 +0000 Subject: [PATCH 17/44] [nrf fromtree] zephyr: Fix usage of CONFIG_MBEDTLS_BUILTIN and ASN1 This commit fixes issue where even if Zephyr provided mbedTLS module was used, ASN1 decoding procedures have been taken from MCUboot own version of mbedTLS extracted sources for these functions. To be able to do that this commit changes config file used with mbedTLS with the one provided from Zephyr (the generic one), which allows to select required mbedTLS features via Kconfig options exposed by Zephyr. Signed-off-by: Dominik Ermel (cherry picked from commit 3f6721346f050edf69ce001da2f38be7060f96d9) --- boot/zephyr/CMakeLists.txt | 34 ++++++++++++++++++++++------------ boot/zephyr/Kconfig | 11 ++++++++++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 6522f8572..b0c119da4 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -25,8 +25,10 @@ assert_exists(TINYCRYPT_SHA512_DIR) set(FIAT_DIR "${MCUBOOT_DIR}/ext/fiat") assert_exists(FIAT_DIR) # Path to mbed-tls' asn1 parser library. -set(MBEDTLS_ASN1_DIR "${MCUBOOT_DIR}/ext/mbedtls-asn1") -assert_exists(MBEDTLS_ASN1_DIR) +if(NOT CONFIG_MBEDTLS_BUILTIN) + set(MBEDTLS_ASN1_DIR "${MCUBOOT_DIR}/ext/mbedtls-asn1") + assert_exists(MBEDTLS_ASN1_DIR) +endif() set(NRF_DIR "${MCUBOOT_DIR}/ext/nrf") if(CONFIG_BOOT_USE_NRF_CC310_BL) @@ -154,14 +156,16 @@ if(CONFIG_BOOT_RAM_LOAD OR CONFIG_SINGLE_APPLICATION_SLOT_RAM_LOAD) endif() if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) - zephyr_library_include_directories( - ${MBEDTLS_ASN1_DIR}/include + if(MBEDTLS_ASN1_DIR) + zephyr_library_include_directories( + ${MBEDTLS_ASN1_DIR}/include ) - zephyr_library_sources( - # Additionally pull in just the ASN.1 parser from mbedTLS. - ${MBEDTLS_ASN1_DIR}/src/asn1parse.c - ${MBEDTLS_ASN1_DIR}/src/platform_util.c + zephyr_library_sources( + # Additionally pull in just the ASN.1 parser from mbedTLS. + ${MBEDTLS_ASN1_DIR}/src/asn1parse.c + ${MBEDTLS_ASN1_DIR}/src/platform_util.c ) + endif() if(CONFIG_BOOT_USE_TINYCRYPT) # When using ECDSA signatures, pull in our copy of the tinycrypt library. zephyr_library_include_directories( @@ -213,8 +217,17 @@ elseif(CONFIG_BOOT_SIGNATURE_TYPE_RSA) endif() elseif(CONFIG_BOOT_SIGNATURE_TYPE_ED25519 OR CONFIG_BOOT_ENCRYPT_X25519) if(CONFIG_BOOT_USE_TINYCRYPT) + if(MBEDTLS_ASN1_DIR) + zephyr_library_include_directories( + ${MBEDTLS_ASN1_DIR}/include + ) + zephyr_library_sources( + # Additionally pull in just the ASN.1 parser from mbedTLS. + ${MBEDTLS_ASN1_DIR}/src/asn1parse.c + ${MBEDTLS_ASN1_DIR}/src/platform_util.c + ) + endif() zephyr_library_include_directories( - ${MBEDTLS_ASN1_DIR}/include ${BOOT_DIR}/zephyr/include ${TINYCRYPT_DIR}/include ${TINYCRYPT_SHA512_DIR}/include @@ -223,9 +236,6 @@ elseif(CONFIG_BOOT_SIGNATURE_TYPE_ED25519 OR CONFIG_BOOT_ENCRYPT_X25519) ${TINYCRYPT_DIR}/source/sha256.c ${TINYCRYPT_DIR}/source/utils.c ${TINYCRYPT_SHA512_DIR}/source/sha512.c - # Additionally pull in just the ASN.1 parser from mbedTLS. - ${MBEDTLS_ASN1_DIR}/src/asn1parse.c - ${MBEDTLS_ASN1_DIR}/src/platform_util.c ) zephyr_library_compile_definitions( MBEDTLS_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/include/mcuboot-mbedtls-cfg.h" diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a13201969..512f485f6 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -134,6 +134,8 @@ config BOOT_SIGNATURE_TYPE_RSA bool "RSA signatures" select BOOT_USE_MBEDTLS select MBEDTLS + select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN + select MBEDTLS_KEY_EXCHANGE_RSA_ENABLED if MBEDTLS_BUILTIN select BOOT_ENCRYPTION_SUPPORT select BOOT_IMG_HASH_ALG_SHA256_ALLOW @@ -184,6 +186,8 @@ config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS select MBEDTLS + select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN + endchoice endif @@ -228,8 +232,13 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. +if MBEDTLS + config MBEDTLS_CFG_FILE - default "mcuboot-mbedtls-cfg.h" + default "config-tls-generic.h" if MBEDTLS_BUILTIN + default "mcuboot-mbedtls-cfg.h" if BOOT_USE_MBEDTLS + +endif config BOOT_HW_KEY bool "Use HW key for image verification" From c92e60b7c43d77079c25a7092ab9d7fb86d2f572 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 2 Oct 2024 11:05:20 +0000 Subject: [PATCH 18/44] [nrf fromtree] bootutil: Allow SHA512 with TinyCrypt The commit enables SHA512 support, for image hashing, with TinyCrypt. Although on 32bit machines the SHA256 will be faster than SHA512, benefit of enabling the SHA512 is that you have only one algorithm compiled in which reduces size of code. Signed-off-by: Dominik Ermel (cherry picked from commit f72158ff313ac771c3b510adf64685cabf34f8c0) --- boot/bootutil/include/bootutil/crypto/sha.h | 20 ++++++++++++++++++++ boot/bootutil/src/image_ed25519.c | 9 ++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index 6ba8d946d..b83a3ec40 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -70,7 +70,11 @@ #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) +#if defined(MCUBOOT_SHA512) + #include +#else #include +#endif #include #endif /* MCUBOOT_USE_TINYCRYPT */ @@ -193,11 +197,19 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) +#if defined(MCUBOOT_SHA512) +typedef struct tc_sha512_state_struct bootutil_sha_context; +#else typedef struct tc_sha256_state_struct bootutil_sha_context; +#endif static inline int bootutil_sha_init(bootutil_sha_context *ctx) { +#if defined(MCUBOOT_SHA512) + tc_sha512_init(ctx); +#else tc_sha256_init(ctx); +#endif return 0; } @@ -211,13 +223,21 @@ static inline int bootutil_sha_update(bootutil_sha_context *ctx, const void *data, uint32_t data_len) { +#if defined(MCUBOOT_SHA512) + return tc_sha512_update(ctx, data, data_len); +#else return tc_sha256_update(ctx, data, data_len); +#endif } static inline int bootutil_sha_finish(bootutil_sha_context *ctx, uint8_t *output) { +#if defined(MCUBOOT_SHA512) + return tc_sha512_final(output, ctx); +#else return tc_sha256_final(output, ctx); +#endif } #endif /* MCUBOOT_USE_TINYCRYPT */ diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 4e2423a08..4a5755b66 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -21,12 +21,14 @@ #include "bootutil/crypto/common.h" #include "bootutil/crypto/sha.h" +#define EDDSA_SIGNATURE_LENGTH 64 + static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; #define NUM_ED25519_BYTES 32 extern int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[64], - const uint8_t public_key[32]); + const uint8_t signature[EDDSA_SIGNATURE_LENGTH], + const uint8_t public_key[NUM_ED25519_BYTES]); /* * Parse the public key used for signing. @@ -76,7 +78,8 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t *pubkey; uint8_t *end; - if (hlen != IMAGE_HASH_SIZE || slen != 64) { + if (hlen != IMAGE_HASH_SIZE || + slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } From ddf9d4cba50d152b02d4e65d39f19fa0efd0158f Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 5 Sep 2024 10:53:17 +0000 Subject: [PATCH 19/44] [nrf fromtree] bootutil: Enable hash calculation directly on storage The commit add support for passing storage device address space to hash calculation functions, which allows to use hardware accelerated hash calculation on storage. This feature only works when image encryption is not enabled and all slots are defined within internal storage of device. The feature is enabled with MCUboot configuration option MCUBOOT_HASH_STORAGE_DIRECTLY. Signed-off-by: Dominik Ermel (cherry picked from commit b43b8c80b87b9cf7a8efe35b7cdaea49ed0b457f) --- boot/bootutil/src/image_validate.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index ec5d986df..ae22e27ed 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -68,13 +68,15 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, uint8_t *seed, int seed_len) { bootutil_sha_context sha_ctx; - uint32_t blk_sz; uint32_t size; uint16_t hdr_size; - uint32_t off; - int rc; uint32_t blk_off; uint32_t tlv_off; +#if !defined(MCUBOOT_HASH_STORAGE_DIRECTLY) + int rc; + uint32_t off; + uint32_t blk_sz; +#endif #if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \ defined(MCUBOOT_RAM_LOAD) @@ -117,6 +119,12 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, /* If protected TLVs are present they are also hashed. */ size += hdr->ih_protect_tlv_size; +#ifdef MCUBOOT_HASH_STORAGE_DIRECTLY + /* No chunk loading, storage is mapped to address space and can + * be directly given to hashing function. + */ + bootutil_sha_update(&sha_ctx, (void *)flash_area_get_off(fap), size); +#else /* MCUBOOT_HASH_STORAGE_DIRECTLY */ #ifdef MCUBOOT_RAM_LOAD bootutil_sha_update(&sha_ctx, (void*)(IMAGE_RAM_BASE + hdr->ih_load_addr), @@ -161,6 +169,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, bootutil_sha_update(&sha_ctx, tmp_buf, blk_sz); } #endif /* MCUBOOT_RAM_LOAD */ +#endif /* MCUBOOT_HASH_STORAGE_DIRECTLY */ bootutil_sha_finish(&sha_ctx, hash_result); bootutil_sha_drop(&sha_ctx); From d3d39fb1ae34a6ddec557f4d12f5bc4cb04bd9d3 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 6 Sep 2024 16:16:28 +0000 Subject: [PATCH 20/44] [nrf fromtree] bootutil: PureEdDSA using ED25519 The commit adds support for PureEdDSA, which validates signature of image rather than hash. This is most secure, available, ED25519 usage in MCUboot, but due to requirement of PureEdDSA to be able to calculate signature at whole message at once, here image, it only works on setups where entire image can be mapped to device address space, so that PSA functions calculating the signature can see the whole image at once. The feature is enabled with MCUBOOT_SIGN_PURE MCUboot configuration option. Signed-off-by: Dominik Ermel (cherry picked from commit de9bc3d006b2ac44f056bb66ef1b2f60d15df11d) --- boot/bootutil/src/bootutil_priv.h | 9 +++ boot/bootutil/src/image_ed25519.c | 59 ++++++++++++++++-- boot/bootutil/src/image_validate.c | 96 ++++++++++++++++++++++++++++-- docs/design.md | 2 + 4 files changed, 154 insertions(+), 12 deletions(-) diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 345933a5f..5703f627a 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -267,9 +267,18 @@ struct boot_loader_state { #endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */ }; +/* The function is intended for verification of image hash against + * provided signature. + */ fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t key_id); +/* The function is intended for direct verification of image + * against provided signature. + */ +fih_ret bootutil_verify_img(uint8_t *img, uint32_t size, + uint8_t *sig, size_t slen, uint8_t key_id); + fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n); int boot_find_status(int image_index, const struct flash_area **fap); diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 4a5755b66..238c9d671 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -69,17 +69,23 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } -fih_ret -bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, - uint8_t key_id) +/* Signature verification base function. + * The function takes buffer of specified length and tries to verify + * it against provided signature. + * The function does key import and checks whether signature is + * of expected length. + */ +static fih_ret +bootutil_verify(uint8_t *buf, uint32_t blen, + uint8_t *sig, size_t slen, + uint8_t key_id) { int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); uint8_t *pubkey; uint8_t *end; - if (hlen != IMAGE_HASH_SIZE || - slen != EDDSA_SIGNATURE_LENGTH) { + if (slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } @@ -93,7 +99,7 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, goto out; } - rc = ED25519_verify(hash, IMAGE_HASH_SIZE, sig, pubkey); + rc = ED25519_verify(buf, blen, sig, pubkey); if (rc == 0) { /* if verify returns 0, there was an error. */ @@ -107,4 +113,45 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, FIH_RET(fih_rc); } +/* Hash signature verification function. + * Verifies hash against provided signature. + * The function verifies that hash is of expected size and then + * calls bootutil_verify to do the signature verification. + */ +fih_ret +bootutil_verify_sig(uint8_t *hash, uint32_t hlen, + uint8_t *sig, size_t slen, + uint8_t key_id) +{ + FIH_DECLARE(fih_rc, FIH_FAILURE); + + if (hlen != IMAGE_HASH_SIZE) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } + + FIH_CALL(bootutil_verify, fih_rc, hash, IMAGE_HASH_SIZE, sig, + slen, key_id); + +out: + FIH_RET(fih_rc); +} + +/* Image verification function. + * The function directly calls bootutil_verify to verify signature + * of image. + */ +fih_ret +bootutil_verify_img(uint8_t *img, uint32_t size, + uint8_t *sig, size_t slen, + uint8_t key_id) +{ + FIH_DECLARE(fih_rc, FIH_FAILURE); + + FIH_CALL(bootutil_verify, fih_rc, img, size, sig, + slen, key_id); + + FIH_RET(fih_rc); +} + #endif /* MCUBOOT_SIGN_ED25519 */ diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index ae22e27ed..e038f22fe 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -56,6 +56,7 @@ #include "bootutil_priv.h" +#ifndef MCUBOOT_SIGN_PURE /* * Compute SHA hash over the image. * (SHA384 if ECDSA-P384 is being used, @@ -175,6 +176,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, return 0; } +#endif /* * Currently, we only support being able to verify one type of @@ -361,6 +363,44 @@ bootutil_get_img_security_cnt(struct image_header *hdr, return 0; } +#if defined(MCUBOOT_SIGN_PURE) +/* Returns: + * 0 -- found + * 1 -- not found or found but not true + * -1 -- failed for some reason + * + * Value of TLV does not matter, presence decides. + */ +static int bootutil_check_for_pure(const struct image_header *hdr, + const struct flash_area *fap) +{ + struct image_tlv_iter it; + uint32_t off; + uint16_t len; + int32_t rc; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false); + if (rc) { + return -1; + } + + /* Search for the TLV */ + rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); + if (rc == 0 && len == 1) { + uint8_t val; + + rc = LOAD_IMAGE_DATA(hdr, fap, off, &val, sizeof(val)); + if (rc == 0) { + return (val == 1) ? 0 : 1; + } else { + return -1; + } + } + + return 1; +} +#endif + #ifndef ALLOW_ROGUE_TLVS /* * The following list of TLVs are the only entries allowed in the unprotected @@ -377,6 +417,9 @@ static const uint16_t allowed_unprot_tlvs[] = { IMAGE_TLV_ECDSA_SIG, IMAGE_TLV_RSA3072_PSS, IMAGE_TLV_ED25519, +#if defined(MCUBOOT_SIGN_PURE) + IMAGE_TLV_SIG_PURE, +#endif IMAGE_TLV_ENC_RSA2048, IMAGE_TLV_ENC_KW, IMAGE_TLV_ENC_EC256, @@ -399,7 +442,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, uint32_t off; uint16_t len; uint16_t type; - int image_hash_valid = 0; #ifdef EXPECTED_SIG_TLV FIH_DECLARE(valid_signature, FIH_FAILURE); #ifndef MCUBOOT_BUILTIN_KEY @@ -416,7 +458,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, #endif /* EXPECTED_SIG_TLV */ struct image_tlv_iter it; uint8_t buf[SIG_BUF_SIZE]; +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) + int image_hash_valid = 0; uint8_t hash[IMAGE_HASH_SIZE]; +#endif int rc = 0; FIH_DECLARE(fih_rc, FIH_FAILURE); #ifdef MCUBOOT_HW_ROLLBACK_PROT @@ -425,6 +470,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, FIH_DECLARE(security_counter_valid, FIH_FAILURE); #endif +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); if (rc) { @@ -434,6 +480,15 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (out_hash) { memcpy(out_hash, hash, IMAGE_HASH_SIZE); } +#endif + +#if defined(MCUBOOT_SIGN_PURE) + /* If Pure type signature is expected then it has to be there */ + rc = bootutil_check_for_pure(hdr, fap); + if (rc != 0) { + goto out; + } +#endif rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); if (rc) { @@ -477,8 +532,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } } #endif - - if (type == EXPECTED_HASH_TLV) { + switch(type) { +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) + case EXPECTED_HASH_TLV: + { /* Verify the image hash. This must always be present. */ if (len != sizeof(hash)) { rc = -1; @@ -496,8 +553,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } image_hash_valid = 1; + break; + } +#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */ #ifdef EXPECTED_KEY_TLV - } else if (type == EXPECTED_KEY_TLV) { + case EXPECTED_KEY_TLV: + { /* * Determine which key we should be checking. */ @@ -522,9 +583,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, * The key may not be found, which is acceptable. There * can be multiple signatures, each preceded by a key. */ + break; + } #endif /* EXPECTED_KEY_TLV */ #ifdef EXPECTED_SIG_TLV - } else if (type == EXPECTED_SIG_TLV) { + case EXPECTED_SIG_TLV: + { /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; @@ -538,12 +602,25 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (rc) { goto out; } +#ifndef MCUBOOT_SIGN_PURE FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), buf, len, key_id); +#else + /* Directly check signature on the image, by using the mapping of + * a device to memory. The pointer is beginning of image in flash, + * so offset of area, the range is header + image + protected tlvs. + */ + FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap), + hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size, + buf, len, key_id); +#endif key_id = -1; + break; + } #endif /* EXPECTED_SIG_TLV */ #ifdef MCUBOOT_HW_ROLLBACK_PROT - } else if (type == IMAGE_TLV_SEC_CNT) { + case IMAGE_TLV_SEC_CNT: + { /* * Verify the image's security counter. * This must always be present. @@ -578,14 +655,21 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, /* The image's security counter has been successfully verified. */ security_counter_valid = fih_rc; + break; + } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ } } +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = !image_hash_valid; if (rc) { goto out; } +#elif defined(MCUBOOT_SIGN_PURE) + /* This returns true on EQ, rc is err on non-0 */ + rc = FIH_NOT_EQ(valid_signature, FIH_SUCCESS); +#endif #ifdef EXPECTED_SIG_TLV FIH_SET(fih_rc, valid_signature); #endif diff --git a/docs/design.md b/docs/design.md index 7fa06fe6b..b1979a7c2 100755 --- a/docs/design.md +++ b/docs/design.md @@ -111,6 +111,8 @@ struct image_tlv { #define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ #define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */ #define IMAGE_TLV_ED25519 0x24 /* ED25519 of hash output */ +#define IMAGE_TLV_SIG_PURE 0x25 /* If true then any signature found has been + calculated over image directly. */ #define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */ #define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW-128 or 256 */ From 87507cc39932e1cd2ac5dff0610f8b8b5845945e Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 2 Oct 2024 11:05:20 +0000 Subject: [PATCH 21/44] [nrf fromtree] zephyr: Allow SHA512 with TinyCrypt Select BOOT_IMG_HASH_ALG_SHA512_ALLOW via BOOT_ED25519_TINYCRYPT. Signed-off-by: Dominik Ermel (cherry picked from commit 30e6adfe43bb0786d6c32426fdd11cb750f01ac6) --- boot/zephyr/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 512f485f6..915075819 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -182,6 +182,7 @@ choice BOOT_ED25519_IMPLEMENTATION config BOOT_ED25519_TINYCRYPT bool "Use tinycrypt" select BOOT_USE_TINYCRYPT + select BOOT_IMG_HASH_ALG_SHA512_ALLOW config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS From 5c0ac276f8f40fa6c559ff37463743b08f6411a0 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 5 Sep 2024 10:53:17 +0000 Subject: [PATCH 22/44] [nrf fromtree] zephyr: Add Kconfig and configuration for SHA on storage Adds CONFIG_BOOT_IMG_HASH_DIRECTLY_ON_STORAGE, which enables MCUBOOT_HASH_STORAGE_DIRECTLY for Zephyr. Signed-off-by: Dominik Ermel (cherry picked from commit 96f01aad668929cbcebc5c1395aa4af110e53a51) --- boot/zephyr/Kconfig | 16 ++++++++++++++++ .../include/mcuboot_config/mcuboot_config.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 915075819..33708b8a2 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -91,6 +91,22 @@ config BOOT_IMG_HASH_ALG_SHA512_ALLOW help Hidden option set by configurations that allow SHA512 +config BOOT_IMG_HASH_DIRECTLY_ON_STORAGE + bool "Hash calculation functions access storage through address space" + depends on !BOOT_ENCRYPT_IMAGE + help + When possible to map storage device, at least for read operations, + to address space or RAM area, enabling this option allows hash + calculation functions to directly access the storage through that address + space or using its own DMA. This reduces flash read overhead done + by MCUboot. + Notes: + - not supported when encrypted images are in use, because calculating + SHA requires image to be decrypted first, which is done in RAM. + - currently only supported on internal storage of devices; this + option will not work with devices that use external storage for + either of the image slots. + choice BOOT_IMG_HASH_ALG prompt "Selected image hash algorithm" default BOOT_IMG_HASH_ALG_SHA256 if BOOT_IMG_HASH_ALG_SHA256_ALLOW diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 4743539f1..cb3d26535 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -148,6 +148,13 @@ #define MCUBOOT_DECOMPRESS_IMAGES #endif +/* Invoke hashing functions directly on storage device. This requires the device + * be able to map storage to address space or RAM. + */ +#ifdef CONFIG_BOOT_IMG_HASH_DIRECTLY_ON_STORAGE +#define MCUBOOT_HASH_STORAGE_DIRECTLY +#endif + #ifdef CONFIG_BOOT_BOOTSTRAP #define MCUBOOT_BOOTSTRAP 1 #endif From 4389f0c19463f06b9144045db67a2e04ff3e3b36 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 6 Sep 2024 16:16:28 +0000 Subject: [PATCH 23/44] [nrf fromtree] zephyr: Add Kconfig option to select PureEdDS Commit adds CONFIG_BOOT_SIGNATURE_TYPE_PURE Kconfig option, which enables MCUBOOT_SIGN_PURE in MCUboot configuration. Signed-off-by: Dominik Ermel (cherry picked from commit 9668469f00a70d43e6b1fcaf8287833d102870b7) --- boot/zephyr/Kconfig | 30 +++++++++++++++++-- .../include/mcuboot_config/mcuboot_config.h | 4 +++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 33708b8a2..2b335498c 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -137,6 +137,14 @@ config BOOT_IMG_HASH_ALG_SHA512 endchoice # BOOT_IMG_HASH_ALG +config BOOT_SIGNATURE_TYPE_PURE_ALLOW + bool + help + Hidden option set by configurations that allow Pure variant, + for example ed25519. The pure variant means that image + signature is calculated over entire image instead of hash + of an image. + choice BOOT_SIGNATURE_TYPE prompt "Signature type" default BOOT_SIGNATURE_TYPE_RSA @@ -188,10 +196,28 @@ endif config BOOT_SIGNATURE_TYPE_ED25519 bool "Edwards curve digital signatures using ed25519" - select BOOT_ENCRYPTION_SUPPORT - select BOOT_IMG_HASH_ALG_SHA256_ALLOW + select BOOT_ENCRYPTION_SUPPORT if !BOOT_SIGNATURE_TYPE_PURE + select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !BOOT_SIGNATURE_TYPE_PURE + # The SHA is used only for key hashing, not for images. + select BOOT_SIGNATURE_TYPE_PURE_ALLOW + help + This is ed25519 signature calculated over SHA512 of SHA256 of application + image. + To check signature over entire image directly, rather than hash, + select BOOT_SIGNATURE_TYPE_PURE. if BOOT_SIGNATURE_TYPE_ED25519 + +config BOOT_SIGNATURE_TYPE_PURE + bool "Use Pure signature of image" + depends on BOOT_SIGNATURE_TYPE_PURE_ALLOW + help + The Pure signature is calculated directly over image rather than + hash of an image, as the BOOT_SIGNATURE_TYPE_ED25519 does by + default. + Image to be verified needs to be accessible through memory address + space that cryptography functions can access via pointers. + choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" default BOOT_ED25519_TINYCRYPT diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index cb3d26535..db80f1882 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -155,6 +155,10 @@ #define MCUBOOT_HASH_STORAGE_DIRECTLY #endif +#ifdef CONFIG_BOOT_SIGNATURE_TYPE_PURE +#define MCUBOOT_SIGN_PURE +#endif + #ifdef CONFIG_BOOT_BOOTSTRAP #define MCUBOOT_BOOTSTRAP 1 #endif From f1a9a95b4385adf4001daf3d9e286609299bdc3b Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 24 Jan 2025 17:05:18 +0000 Subject: [PATCH 24/44] [nrf fromtree] zephyr: Fix image encryption configuration for mbedTLS. Add a few missing Kconfig options. Signed-off-by: Dominik Ermel (cherry picked from commit 96b70086c8e3104564c72f718f5191aa18952f96) --- boot/zephyr/Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2b335498c..5de63a2e3 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -66,6 +66,15 @@ config NRF_CC310_BL bool default n +if BOOT_USE_MBEDTLS && MBEDTLS_BUILTIN + +config BOOT_AES_MBEDTLS_DEPENDENCIES + bool + select MBEDTLS_CIPHER_AES_ENABLED + select MBEDTLS_CIPHER_MODE_CTR_ENABLED + +endif + menu "MCUBoot settings" config SINGLE_APPLICATION_SLOT @@ -162,6 +171,7 @@ config BOOT_SIGNATURE_TYPE_RSA select MBEDTLS_KEY_EXCHANGE_RSA_ENABLED if MBEDTLS_BUILTIN select BOOT_ENCRYPTION_SUPPORT select BOOT_IMG_HASH_ALG_SHA256_ALLOW + select BOOT_AES_MBEDTLS_DEPENDENCIES if MBEDTLS_BUILTIN && BOOT_ENCRYPT_IMAGE if BOOT_SIGNATURE_TYPE_RSA config BOOT_SIGNATURE_TYPE_RSA_LEN @@ -230,6 +240,7 @@ config BOOT_ED25519_MBEDTLS select BOOT_USE_MBEDTLS select MBEDTLS select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN + select BOOT_AES_MBEDTLS_DEPENDENCIES if MBEDTLS_BUILTIN && BOOT_ENCRYPT_IMAGE endchoice endif From a49c95a4a131b978fd00e38919aaee666cd9930f Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 29 May 2024 17:46:17 +0000 Subject: [PATCH 25/44] [nrf fromtree] bootutil: PSA implementation of x25519 and ed25519 verification The commit provides implementation of image verification with ed25519 and encryption/decryption support where random key is encrypted using x25519. Signed-off-by: Dominik Ermel (cherry picked from commit 615a9dffd03e6ebcdd1bcc58a67cc92e5eafea7b) --- .../include/bootutil/crypto/aes_ctr.h | 37 +- boot/bootutil/pkg.yml | 2 + boot/bootutil/src/ed25519_psa.c | 71 +++ boot/bootutil/src/encrypted.c | 114 ++--- boot/bootutil/src/encrypted_psa.c | 454 ++++++++++++++++++ boot/bootutil/src/image_ed25519.c | 3 +- 6 files changed, 624 insertions(+), 57 deletions(-) create mode 100644 boot/bootutil/src/ed25519_psa.c create mode 100644 boot/bootutil/src/encrypted_psa.c diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h index 50d36a4fc..23862825c 100644 --- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h @@ -15,8 +15,8 @@ #include "mcuboot_config/mcuboot_config.h" #if (defined(MCUBOOT_USE_MBED_TLS) + \ - defined(MCUBOOT_USE_TINYCRYPT)) != 1 - #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT" + defined(MCUBOOT_USE_TINYCRYPT) + defined(MCUBOOT_USE_PSA_CRYPTO)) != 1 + #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT or PSA" #endif #if defined(MCUBOOT_USE_MBED_TLS) @@ -38,12 +38,45 @@ #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE TC_AES_BLOCK_SIZE #endif /* MCUBOOT_USE_TINYCRYPT */ +#if defined(MCUBOOT_USE_PSA_CRYPTO) + #include + #include "bootutil/enc_key_public.h" + #define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE + #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16) +#endif + #include #ifdef __cplusplus extern "C" { #endif +#if defined(MCUBOOT_USE_PSA_CRYPTO) +typedef struct { + /* Fixme: This should not be, here, psa_key_id should be passed */ + uint8_t key[BOOT_ENC_KEY_SIZE]; +} bootutil_aes_ctr_context; + +void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx); + +static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) +{ + memset(ctx, 0, sizeof(ctx)); +} + +static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) +{ + memcpy(ctx->key, k, sizeof(ctx->key)); + + return 0; +} + +int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c); +int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m); +#endif + #if defined(MCUBOOT_USE_MBED_TLS) typedef mbedtls_aes_context bootutil_aes_ctr_context; static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) diff --git a/boot/bootutil/pkg.yml b/boot/bootutil/pkg.yml index ed6f35810..4a7fabc1c 100644 --- a/boot/bootutil/pkg.yml +++ b/boot/bootutil/pkg.yml @@ -47,6 +47,8 @@ pkg.ign_files.BOOTUTIL_SINGLE_APPLICATION_SLOT: pkg.ign_files: - "ram_load.c" + - "ed25519_psa.c" # Currently no PSA for mynewet + - "encrypted_psa.c" pkg.deps.BOOTUTIL_USE_MBED_TLS: - "@apache-mynewt-core/crypto/mbedtls" diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c new file mode 100644 index 000000000..12ba20ac1 --- /dev/null +++ b/boot/bootutil/src/ed25519_psa.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include +#include "bootutil/bootutil_log.h" + +#include +#include + +BOOT_LOG_MODULE_REGISTER(ed25519_psa); + +#define SHA512_DIGEST_LENGTH 64 +#define EDDSA_KEY_LENGTH 32 +#define EDDSA_SIGNAGURE_LENGTH 64 + +int ED25519_verify(const uint8_t *message, size_t message_len, + const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], + const uint8_t public_key[EDDSA_KEY_LENGTH]) +{ + /* Set to any error */ + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t kid; + int ret = 0; /* Fail by default */ + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d\n", status); + return 0; + } + + status = PSA_ERROR_BAD_STATE; + + psa_set_key_type(&key_attr, + PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS)); + psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE); + psa_set_key_algorithm(&key_attr, PSA_ALG_PURE_EDDSA); + + status = psa_import_key(&key_attr, public_key, EDDSA_KEY_LENGTH, &kid); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("ED25519 key import failed %d", status); + return 0; + } + + status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, message_len, + signature, EDDSA_SIGNAGURE_LENGTH); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("ED25519 signature verification failed %d", status); + ret = 0; + /* Pass through to destroy key */ + } else { + ret = 1; + /* Pass through to destroy key */ + } + + status = psa_destroy_key(kid); + + if (status != PSA_SUCCESS) { + /* Just for logging */ + BOOT_LOG_WRN("Failed to destroy key %d", status); + } + + return ret; +} diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 8449a28dd..8c631d731 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -3,6 +3,7 @@ * * Copyright (c) 2018-2019 JUUL Labs * Copyright (c) 2019-2024 Arm Limited + * Copyright (c) 2025 Nordic Semiconductor ASA */ #include "mcuboot_config/mcuboot_config.h" @@ -25,6 +26,7 @@ #include "bootutil/crypto/ecdh_p256.h" #endif +#if !defined(MCUBOOT_USE_PSA_CRYPTO) #if defined(MCUBOOT_ENCRYPT_X25519) #include "bootutil/crypto/ecdh_x25519.h" #endif @@ -35,6 +37,7 @@ #include "mbedtls/oid.h" #include "mbedtls/asn1.h" #endif +#endif #include "bootutil/image.h" #include "bootutil/enc_key.h" @@ -43,6 +46,30 @@ #include "bootutil_priv.h" +#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE + +#if defined(MCUBOOT_ENCRYPT_RSA) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048 +#elif defined(MCUBOOT_ENCRYPT_KW) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW +#elif defined(MCUBOOT_ENCRYPT_EC256) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256 +# define EC_PUBK_INDEX (0) +# define EC_TAG_INDEX (65) +# define EC_CIPHERKEY_INDEX (65 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-P256 component indexes"); +#elif defined(MCUBOOT_ENCRYPT_X25519) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 +# define EC_PUBK_INDEX (0) +# define EC_TAG_INDEX (32) +# define EC_CIPHERKEY_INDEX (32 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-X25519 component indexes"); +#endif + +/* NOUP Fixme: */ +#if !defined(CONFIG_BOOT_ED25519_PSA) #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) #if defined(_compare) static inline int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size) @@ -351,60 +378,6 @@ int boot_enc_retrieve_private_key(struct bootutil_key **private_key) } #endif /* !MCUBOOT_ENC_BUILTIN_KEY */ -int -boot_enc_init(struct enc_key_data *enc_state, uint8_t slot) -{ - bootutil_aes_ctr_init(&enc_state[slot].aes_ctr); - return 0; -} - -int -boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot) -{ - bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr); - enc_state[slot].valid = 0; - return 0; -} - -int -boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, - const struct boot_status *bs) -{ - int rc; - - rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]); - if (rc != 0) { - boot_enc_drop(enc_state, slot); - return -1; - } - - enc_state[slot].valid = 1; - - return 0; -} - -#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE - -#if defined(MCUBOOT_ENCRYPT_RSA) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048 -#elif defined(MCUBOOT_ENCRYPT_KW) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW -#elif defined(MCUBOOT_ENCRYPT_EC256) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (65) -# define EC_CIPHERKEY_INDEX (65 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-P256 component indexes"); -#elif defined(MCUBOOT_ENCRYPT_X25519) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (32) -# define EC_CIPHERKEY_INDEX (32 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-X25519 component indexes"); -#endif - #if ( (defined(MCUBOOT_ENCRYPT_RSA) && defined(MCUBOOT_USE_MBED_TLS) && !defined(MCUBOOT_USE_PSA_CRYPTO)) || \ (defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS)) ) #if MBEDTLS_VERSION_NUMBER >= 0x03000000 @@ -627,6 +600,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return rc; } +#endif /* CONFIG_BOOT_ED25519_PSA */ /* * Load encryption key. @@ -681,6 +655,38 @@ boot_enc_load(struct enc_key_data *enc_state, int slot, return boot_decrypt_key(buf, bs->enckey[slot]); } +int +boot_enc_init(struct enc_key_data *enc_state, uint8_t slot) +{ + bootutil_aes_ctr_init(&enc_state[slot].aes_ctr); + return 0; +} + +int +boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot) +{ + bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr); + enc_state[slot].valid = 0; + return 0; +} + +int +boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, + const struct boot_status *bs) +{ + int rc; + + rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]); + if (rc != 0) { + boot_enc_drop(enc_state, slot); + return -1; + } + + enc_state[slot].valid = 1; + + return 0; +} + bool boot_enc_valid(struct enc_key_data *enc_state, int slot) { diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c new file mode 100644 index 000000000..441ce94df --- /dev/null +++ b/boot/bootutil/src/encrypted_psa.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mcuboot_config/mcuboot_config.h" + +#include +#include +#include + +/* We are not really using the MBEDTLS but need the ASN.1 parsing functions */ +#define MBEDTLS_ASN1_PARSE_C + +#include "bootutil/crypto/sha.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1.h" + +#include "bootutil/image.h" +#include "bootutil/enc_key.h" +#include "bootutil/sign_key.h" +#include "bootutil/crypto/common.h" + +#include "bootutil_priv.h" +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc); + +#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE +#define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 +#define EC_PUBK_INDEX (0) +#define EC_TAG_INDEX (32) +#define EC_CIPHERKEY_INDEX (32 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-X25519 component indexes"); + +#define X25519_OID "\x6e" +static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ + MBEDTLS_OID_ORG_GOV X25519_OID; + +#define SHARED_KEY_LEN 32 +#define PRIV_KEY_LEN 32 + +/* Fixme: This duplicates code from encrypted.c and depends on mbedtls */ +static int +parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) +{ + size_t len; + int version; + mbedtls_asn1_buf alg; + mbedtls_asn1_buf param; + + if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE) != 0) { + return -1; + } + + if (*p + len != end) { + return -2; + } + + version = 0; + if (mbedtls_asn1_get_int(p, end, &version) || version != 0) { + return -3; + } + + if (mbedtls_asn1_get_alg(p, end, &alg, ¶m) != 0) { + return -4; + } + + if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || + memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { + return -5; + } + + if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) { + return -6; + } + + if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) { + return -7; + } + + if (len != PRIV_KEY_LEN) { + return -8; + } + + memcpy(private_key, *p, PRIV_KEY_LEN); + return 0; +} + +void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) +{ + psa_status_t psa_ret = psa_crypto_init(); + + (void)ctx; + + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES init PSA crypto init failed %d", psa_ret); + assert(0); + } +} + +#if defined(MCUBOOT_ENC_IMAGES) +extern const struct bootutil_key bootutil_enc_key; +/* + * Decrypt an encryption key TLV. + * + * @param buf An encryption TLV read from flash (build time fixed length) + * @param enckey An AES-128 or AES-256 key sized buffer to store to plain key. + */ +int +boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) +{ + uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; + uint8_t *cp; + uint8_t *cpend; + uint8_t private_key[PRIV_KEY_LEN]; + size_t len; + psa_status_t psa_ret = PSA_ERROR_BAD_STATE; + psa_status_t psa_cleanup_ret = PSA_ERROR_BAD_STATE; + psa_key_id_t kid; + psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_derivation_operation_t key_do = PSA_KEY_DERIVATION_OPERATION_INIT; + psa_algorithm_t key_do_alg; + int rc = -1; + + cp = (uint8_t *)bootutil_enc_key.key; + cpend = cp + *bootutil_enc_key.len; + + /* The psa_cipher_decrypt needs initialization vector of proper length at + * the beginning of the input buffer. + */ + uint8_t iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR) + + BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE]; + + psa_ret = psa_crypto_init(); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES crypto init failed %d", psa_ret); + return -1; + } + + /* + * Load the stored X25519 decryption private key + */ + rc = parse_x25519_enckey(&cp, cpend, private_key); + if (rc) { + return rc; + } + + psa_set_key_type(&kattr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY)); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&kattr, PSA_ALG_ECDH); + + psa_ret = psa_import_key(&kattr, private_key, sizeof(private_key), &kid); + memset(private_key, 0, sizeof(private_key)); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("Built-in key import failed %d", psa_ret); + return -1; + } + + key_do_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + + psa_ret = psa_key_derivation_setup(&key_do, key_do_alg); + if (psa_ret != PSA_SUCCESS) { + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret); + } + BOOT_LOG_ERR("Key derivation setup failed %d", psa_ret); + return -1; + } + + /* Note: PSA 1.1.2 does not have psa_key_agreement that would be useful here + * as it could just add the derived key to the storage and return key id. + * Instead, we have to use the code below to generate derived key and put it + * into storage, to obtain the key id we can then use with psa_mac_* functions. + */ + psa_ret = psa_key_derivation_key_agreement(&key_do, PSA_KEY_DERIVATION_INPUT_SECRET, + kid, &buf[EC_PUBK_INDEX], + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret); + } + if (psa_ret != PSA_SUCCESS) { + psa_cleanup_ret = psa_key_derivation_abort(&key_do); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret); + } + + BOOT_LOG_ERR("Key derivation failed %d", psa_ret); + return -1; + } + + /* Only info, no salt */ + psa_ret = psa_key_derivation_input_bytes(&key_do, PSA_KEY_DERIVATION_INPUT_INFO, + "MCUBoot_ECIES_v1", 16); + if (psa_ret != PSA_SUCCESS) { + psa_cleanup_ret = psa_key_derivation_abort(&key_do); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret); + } + BOOT_LOG_ERR("Key derivation failed %d", psa_ret); + return -1; + } + + len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; + psa_ret = psa_key_derivation_output_bytes(&key_do, derived_key, len); + psa_cleanup_ret = psa_key_derivation_abort(&key_do); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Key derivation cleanup failed %d", psa_ret); + } + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("Key derivation failed %d", psa_ret); + return -1; + } + + /* The derived key consists of BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE bytes + * followed by BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. Both parts will + * be imported at the point where needed and discarded immediately after. + */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_HMAC); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_VERIFY_MESSAGE); + psa_set_key_algorithm(&kattr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + + /* Import the MAC tag key part of derived key, that is the part that starts + * after BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE and has length of + * BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. + */ + psa_ret = psa_import_key(&kattr, + &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE], + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, &kid); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + memset(derived_key, 0, sizeof(derived_key)); + BOOT_LOG_ERR("MAC key import failed %d", psa_ret); + return -1; + } + + /* Verify the MAC tag of the random encryption key */ + psa_ret = psa_mac_verify(kid, PSA_ALG_HMAC(PSA_ALG_SHA_256), + &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE, + &buf[EC_TAG_INDEX], + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("MAC key destruction failed %d", psa_cleanup_ret); + } + if (psa_ret != PSA_SUCCESS) { + memset(derived_key, 0, sizeof(derived_key)); + BOOT_LOG_ERR("MAC verification failed %d", psa_ret); + return -1; + } + + /* The derived key is used in AES decryption of random key */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&kattr, PSA_ALG_CTR); + + /* Import the AES partition of derived key, the first 16 bytes */ + psa_ret = psa_import_key(&kattr, &derived_key[0], + BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &kid); + memset(derived_key, 0, sizeof(derived_key)); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES key import failed %d", psa_ret); + return -1; + } + + /* Decrypt the random AES encryption key with AES and the key obtained + * at derivation. */ + memset(&iv_and_key[0], 0, PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)); + memcpy(&iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)], + &buf[EC_CIPHERKEY_INDEX], + sizeof(iv_and_key) - PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)); + + len = 0; + psa_ret = psa_cipher_decrypt(kid, PSA_ALG_CTR, iv_and_key, sizeof(iv_and_key), + enckey, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &len); + memset(iv_and_key, 0, sizeof(iv_and_key)); + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("AES key destruction failed %d", psa_cleanup_ret); + } + if (psa_ret != PSA_SUCCESS || len != BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE) { + memset(enckey, 0, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE); + BOOT_LOG_ERR("Random key decryption failed %d", psa_ret); + return -1; + } + + return 0; +} + +int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c) +{ + int ret = 0; + psa_status_t psa_ret = PSA_ERROR_BAD_STATE; + psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t kid; + psa_cipher_operation_t psa_op; + size_t elen = 0; /* Decrypted length */ + + /* Fixme: calling psa_crypto_init multiple times is not a problem, + * yet the code here is only present because there is not general + * crypto init. */ + psa_ret = psa_crypto_init(); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret); + ret = -1; + goto gone; + } + + psa_op = psa_cipher_operation_init(); + + /* Fixme: Import should happen when key is decrypted, but due to lack + * of key destruction there is no way to destroy key stored by + * psa other way than here. */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&kattr, PSA_ALG_CTR); + + psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc import key failed %d", psa_ret); + ret = -1; + goto gone; + } + + /* This could be done with psa_cipher_decrypt one-shot operation, but + * multi-part operation is used to avoid re-allocating input buffer + * to account for IV in front of data. + */ + psa_ret = psa_cipher_encrypt_setup(&psa_op, kid, PSA_ALG_CTR); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc setup failed %d", psa_ret); + ret = -1; + goto gone_with_key; + } + + /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ + psa_ret = psa_cipher_set_iv(&psa_op, counter, 16); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc IV set failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + + psa_ret = psa_cipher_update(&psa_op, m, mlen, c, mlen, &elen); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc encryption failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + +gone_after_setup: + psa_ret = psa_cipher_abort(&psa_op); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("AES enc cipher abort failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone_with_key: + /* Fixme: Should be removed once key is shared by id */ + psa_ret = psa_destroy_key(kid); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("AES enc destroy key failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone: + return ret; +} + +int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m) +{ + int ret = 0; + psa_status_t psa_ret = PSA_ERROR_BAD_STATE; + psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t kid; + psa_cipher_operation_t psa_op; + size_t dlen = 0; /* Decrypted length */ + + /* Fixme: the init should already happen before calling the function, but + * somehow it does not, for example when recovering in swap. + */ + psa_ret = psa_crypto_init(); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret); + ret = -1; + goto gone; + } + + psa_op = psa_cipher_operation_init(); + + /* Fixme: Import should happen when key is decrypted, but due to lack + * of key destruction there is no way to destroy key stored by + * psa other way than here. */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&kattr, PSA_ALG_CTR); + + psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec import key failed %d", psa_ret); + ret = -1; + goto gone; + } + + /* This could be done with psa_cipher_decrypt one-shot operation, but + * multi-part operation is used to avoid re-allocating input buffer + * to account for IV in front of data. + */ + psa_ret = psa_cipher_decrypt_setup(&psa_op, kid, PSA_ALG_CTR); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec setup failed %d", psa_ret); + ret = -1; + goto gone_with_key; + } + + /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ + psa_ret = psa_cipher_set_iv(&psa_op, counter, 16); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec IV set failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + + psa_ret = psa_cipher_update(&psa_op, c, clen, m, clen, &dlen); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec decryption failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + +gone_after_setup: + psa_ret = psa_cipher_abort(&psa_op); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("PSA dec abort failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone_with_key: + psa_ret = psa_destroy_key(kid); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("PSA dec key failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone: + return ret; +} +#endif /* defined(MCUBOOT_ENC_IMAGES) */ diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 238c9d671..0c5810666 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -3,6 +3,7 @@ * * Copyright (c) 2019 JUUL Labs * Copyright (c) 2021-2023 Arm Limited + * Copyright (c) 2025 Nordic Semiconductor ASA */ #include @@ -85,7 +86,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, uint8_t *pubkey; uint8_t *end; - if (slen != EDDSA_SIGNATURE_LENGTH) { + if (blen != IMAGE_HASH_SIZE || slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } From d7def4a3e25fad3ba4ad997038bf3e2d9fcfcbc0 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 24 Jan 2025 17:12:05 +0000 Subject: [PATCH 26/44] [nrf fromtree] zephyr: Enable building ed25519 PSA variant with Zephyr Adds Kconfig option CONFIG_BOOT_ED25519_PSA that allows to switch ed25519 to PSA backend. Signed-off-by: Dominik Ermel (cherry picked from commit f2b6def94041820ddb9f5c384d0406a3a8f91b4a) --- boot/bootutil/zephyr/CMakeLists.txt | 16 ++++--- boot/zephyr/CMakeLists.txt | 41 ++++++++++++----- boot/zephyr/Kconfig | 70 ++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 17 deletions(-) diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index 72a6a8638..f6d37441c 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Nordic Semiconductor ASA +# Copyright (c) 2020-2025 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -29,12 +29,18 @@ zephyr_library_link_libraries(MCUBOOT_BOOTUTIL) target_link_libraries(MCUBOOT_BOOTUTIL INTERFACE zephyr_interface) if(CONFIG_BOOT_USE_TINYCRYPT) -target_include_directories(MCUBOOT_BOOTUTIL INTERFACE - ../../../ext/tinycrypt/lib/include -) + target_include_directories(MCUBOOT_BOOTUTIL INTERFACE + ../../../ext/tinycrypt/lib/include + ) +endif() + +if(CONFIG_BOOT_USE_PSA_CRYPTO) + target_include_directories(MCUBOOT_BOOTUTIL INTERFACE + ${ZEPHYR_MBEDTLS_MODULE_DIR}/include + ) endif() -if(CONFIG_BOOT_USE_MBEDTLS) +if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO) zephyr_link_libraries(mbedTLS) endif() endif() diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index b0c119da4..cc74de180 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -1,7 +1,7 @@ # CMakeLists.txt for building mcuboot as a Zephyr project # # Copyright (c) 2017 Open Source Foundries Limited -# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023-2025 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -50,6 +50,12 @@ zephyr_library_include_directories( include ) +if(DEFINED CONFIG_MBEDTLS) + zephyr_library_include_directories( + ${ZEPHYR_MBEDTLS_MODULE_DIR}/include + ) +endif() + # Zephyr port-specific sources. zephyr_library_sources( main.c @@ -101,6 +107,10 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c ) +if(DEFINED CONFIG_BOOT_ENCRYPT_X25519 AND DEFINED CONFIG_BOOT_ED25519_PSA) + zephyr_library_sources(${BOOT_DIR}/bootutil/src/encrypted_psa.c) +endif() + if(DEFINED CONFIG_MEASURED_BOOT OR DEFINED CONFIG_BOOT_SHARE_DATA) zephyr_library_sources( ${BOOT_DIR}/bootutil/src/boot_record.c @@ -249,19 +259,28 @@ elseif(CONFIG_BOOT_SIGNATURE_TYPE_ED25519 OR CONFIG_BOOT_ENCRYPT_X25519) ${FIAT_DIR}/include/ ) - zephyr_library_sources( - ${FIAT_DIR}/src/curve25519.c - ) + if(NOT CONFIG_BOOT_ED25519_PSA) + zephyr_library_sources( + ${FIAT_DIR}/src/curve25519.c + ) + else() + zephyr_library_sources( + ${MBEDTLS_ASN1_DIR}/src/asn1parse.c + ${BOOT_DIR}/bootutil/src/ed25519_psa.c + ) + endif() endif() -if(CONFIG_BOOT_ENCRYPT_EC256 OR CONFIG_BOOT_ENCRYPT_X25519) - zephyr_library_sources( - ${TINYCRYPT_DIR}/source/aes_encrypt.c - ${TINYCRYPT_DIR}/source/aes_decrypt.c - ${TINYCRYPT_DIR}/source/ctr_mode.c - ${TINYCRYPT_DIR}/source/hmac.c - ${TINYCRYPT_DIR}/source/ecc_dh.c +if(NOT CONFIG_BOOT_ED25519_PSA) + if(CONFIG_BOOT_ENCRYPT_EC256 OR CONFIG_BOOT_ENCRYPT_X25519) + zephyr_library_sources( + ${TINYCRYPT_DIR}/source/aes_encrypt.c + ${TINYCRYPT_DIR}/source/aes_decrypt.c + ${TINYCRYPT_DIR}/source/ctr_mode.c + ${TINYCRYPT_DIR}/source/hmac.c + ${TINYCRYPT_DIR}/source/ecc_dh.c ) + endif() endif() if(CONFIG_BOOT_ENCRYPT_EC256) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 5de63a2e3..f9870248c 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -75,6 +75,60 @@ config BOOT_AES_MBEDTLS_DEPENDENCIES endif +if BOOT_USE_PSA_CRYPTO + +config BOOT_PSA_IMG_HASH_ALG_SHA256_DEPENDENCIES + bool + default y if BOOT_IMG_HASH_ALG_SHA256 + select PSA_WANT_ALG_SHA_256 + help + Dependencies for hashing with SHA256 + +config BOOT_ED25519_PSA_DEPENDENCIES + bool + select PSA_WANT_ALG_SHA_256 + select PSA_WANT_ALG_SHA_512 + select PSA_WANT_ALG_PURE_EDDSA + # Seems that upstream mbedTLS does not have TE + #select PSA_WANT_ECC_TWISTED_EDWARDS_255 + select PSA_WANT_ECC_MONTGOMERY_255 + select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + help + Dependencies for ed25519 signature + +if BOOT_ENCRYPT_IMAGE + +config BOOT_X25519_PSA_DEPENDENCIES + bool + select PSA_WANT_ALG_ECDH + select PSA_WANT_ALG_HMAC + select PSA_WANT_ALG_HKDF + select PSA_WANT_ALG_CTR + select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + select PSA_WANT_KEY_TYPE_DERIVE + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_ECC_MONTGOMERY_255 + help + Dependencies for x25519 shared-random key encryption and AES + encryption. The PSA_WANT_ALG_CTR and PSA_WANT_KEY_TYPE_AES + enable Counter based block cipher and AES key, and algorithm support, + to use with it; the others are used for shared key decryption + and derivation. + +endif # BOOT_ENCRYPT_IMAGE + +if MBEDTLS_ENABLE_HEAP + +config MBEDTLS_HEAP_SIZE + default 2048 if BOOT_USE_PSA_CRYPTO + help + The PSA internals need to be able to allocate memory for operation + and it uses mbedTLS heap for that. + +endif # MBEDTLS_ENABLE_HEAP + +endif # BOOT_USE_PSA_CRYPTO + menu "MCUBoot settings" config SINGLE_APPLICATION_SLOT @@ -156,6 +210,7 @@ config BOOT_SIGNATURE_TYPE_PURE_ALLOW choice BOOT_SIGNATURE_TYPE prompt "Signature type" + default BOOT_SIGNATURE_TYPE_ED25519 if SOC_NRF54L15_CPUAPP default BOOT_SIGNATURE_TYPE_RSA config BOOT_SIGNATURE_TYPE_NONE @@ -231,10 +286,12 @@ config BOOT_SIGNATURE_TYPE_PURE choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" default BOOT_ED25519_TINYCRYPT + config BOOT_ED25519_TINYCRYPT bool "Use tinycrypt" select BOOT_USE_TINYCRYPT select BOOT_IMG_HASH_ALG_SHA512_ALLOW + config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS @@ -242,6 +299,17 @@ config BOOT_ED25519_MBEDTLS select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN select BOOT_AES_MBEDTLS_DEPENDENCIES if MBEDTLS_BUILTIN && BOOT_ENCRYPT_IMAGE +config BOOT_ED25519_PSA + bool "Use PSA crypto" + select MBEDTLS + select BOOT_USE_PSA_CRYPTO + select MBEDTLS_PSA_CRYPTO_C + select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN + select PSA_CRYPTO_CLIENT + select PSA_CRYPTO_C + select BOOT_ED25519_PSA_DEPENDENCIES + select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE + endchoice endif @@ -289,7 +357,7 @@ config MCUBOOT_CLEANUP_RAM if MBEDTLS config MBEDTLS_CFG_FILE - default "config-tls-generic.h" if MBEDTLS_BUILTIN + default "config-tls-generic.h" if MBEDTLS_BUILTIN || BOOT_USE_PSA_CRYPTO default "mcuboot-mbedtls-cfg.h" if BOOT_USE_MBEDTLS endif From 8466eba41a73e5041f3db4a394fc5c1cc3d4de85 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 8 Oct 2024 16:31:48 +0000 Subject: [PATCH 27/44] [nrf fromtree] bootutil: Allow bypassing ASN.1 encoding for ED25519 key import The commit adds MCUBOOT_KEY_IMPORT_BYPASS_ASN configuration option that allows bypassing ASN.1 decoding of ED25519 public key, compiled into MCUboot. When the option is enabled the key will be accessed directly and ASN.1 processing is not compiled in, resulting in smaller footprint of MCUboot, at a cost of reduced detection of invalid key, i.e. public key designated for different method than compiled in. Signed-off-by: Dominik Ermel (cherry picked from commit 1dcfbdacc41762a89aeba9a5eb334b73563e3b43) --- boot/bootutil/src/image_ed25519.c | 22 +++++++++++++++++-- .../include/mcuboot_config/mcuboot_config.h | 4 ++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 0c5810666..01bef149d 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -13,27 +13,30 @@ #ifdef MCUBOOT_SIGN_ED25519 #include "bootutil/sign_key.h" +#if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) /* We are not really using the MBEDTLS but need the ASN.1 parsing functions */ #define MBEDTLS_ASN1_PARSE_C #include "mbedtls/oid.h" #include "mbedtls/asn1.h" +#endif #include "bootutil_priv.h" #include "bootutil/crypto/common.h" #include "bootutil/crypto/sha.h" #define EDDSA_SIGNATURE_LENGTH 64 - -static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; #define NUM_ED25519_BYTES 32 extern int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNATURE_LENGTH], const uint8_t public_key[NUM_ED25519_BYTES]); +#if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) /* * Parse the public key used for signing. */ +static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; + static int bootutil_import_key(uint8_t **cp, uint8_t *end) { @@ -69,6 +72,7 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } +#endif /* !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) */ /* Signature verification base function. * The function takes buffer of specified length and tries to verify @@ -94,11 +98,25 @@ bootutil_verify(uint8_t *buf, uint32_t blen, pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; +#if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) rc = bootutil_import_key(&pubkey, end); if (rc) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } +#else + /* Directly use the key contents from the ASN stream, + * these are the last NUM_ED25519_BYTES. + * There is no check whether this is the correct key, + * here, by the algorithm selected. + */ + if (*bootutil_keys[key_id].len < NUM_ED25519_BYTES) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } + + pubkey = end - NUM_ED25519_BYTES; +#endif rc = ED25519_verify(buf, blen, sig, pubkey); diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index db80f1882..01a9439aa 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -34,6 +34,10 @@ # error "One crypto library implementation allowed at a time." #endif +#if defined(CONFIG_BOOT_KEY_IMPORT_BYPASS_ASN) +#define MCUBOOT_KEY_IMPORT_BYPASS_ASN +#endif + #ifdef CONFIG_BOOT_USE_MBEDTLS #define MCUBOOT_USE_MBED_TLS #elif defined(CONFIG_BOOT_USE_TINYCRYPT) From 7d105004ef18e796d69f007c7bf4cd014a09e628 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 8 Oct 2024 16:36:15 +0000 Subject: [PATCH 28/44] [nrf fromtree] zephyr: Add Kconfig option CONFIG_BOOT_KEY_IMPORT_BYPASS_ASN The option enables MCUboot configuration option MCUBOOT_KEY_IMPORT_BYPASS_ASN. Signed-off-by: Dominik Ermel (cherry picked from commit 3ff75490e4a42096e07d38f8325953da334b367c) --- boot/zephyr/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index f9870248c..18bbcb134 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -311,6 +311,15 @@ config BOOT_ED25519_PSA select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE endchoice + +config BOOT_KEY_IMPORT_BYPASS_ASN + bool "Directly access key value without ASN.1 parsing" + help + Originally, public keys compiled into MCUboot were + stored in ASN.1 encoded format. Enabling this option + bypasses the ASN.1 decoding and directly accesses the key + in ASN.1 bitstream; this reduces MCUboot code by removing + the ASN.1 processing. endif endchoice From 821a3abf2fbb027400ed06541a4b399a05113040 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 12 Mar 2025 16:06:32 +0000 Subject: [PATCH 29/44] [nrf fromtree] bootutil: Fix ASN1 bypass not building One of includes is not available when bypassing ASN1 encoding as mbedTLS is no longer enabled for compilation. Discovered with zephyr, but common for other platforms, after recent changes in CMakeLists.txt. Signed-off-by: Dominik Ermel (cherry picked from commit a01ca4cf946badfc409c490850c335f7152bc391) --- boot/bootutil/src/image_ed25519.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 01bef149d..90e8300de 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -18,10 +18,10 @@ #define MBEDTLS_ASN1_PARSE_C #include "mbedtls/oid.h" #include "mbedtls/asn1.h" +#include "bootutil/crypto/common.h" #endif #include "bootutil_priv.h" -#include "bootutil/crypto/common.h" #include "bootutil/crypto/sha.h" #define EDDSA_SIGNATURE_LENGTH 64 From 94a1df6d334e3e532f5853eae4d24f0841e685fd Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 12 Mar 2025 16:09:12 +0000 Subject: [PATCH 30/44] [nrf fromtree] zephyr: Do not compile ASN1 code when bypassed Commit removes files needed for ASN1 parsing from compilation, when ASN1 bypass is enabled. Signed-off-by: Dominik Ermel (cherry picked from commit ec86244ac150d87b46e41d948ce7b655be672f88) --- boot/zephyr/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index cc74de180..2849e31fe 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -25,7 +25,7 @@ assert_exists(TINYCRYPT_SHA512_DIR) set(FIAT_DIR "${MCUBOOT_DIR}/ext/fiat") assert_exists(FIAT_DIR) # Path to mbed-tls' asn1 parser library. -if(NOT CONFIG_MBEDTLS_BUILTIN) +if(NOT CONFIG_MBEDTLS_BUILTIN AND NOT CONFIG_BOOT_KEY_IMPORT_BYPASS_ASN) set(MBEDTLS_ASN1_DIR "${MCUBOOT_DIR}/ext/mbedtls-asn1") assert_exists(MBEDTLS_ASN1_DIR) endif() From 3164c96bc27fbfebd4ea306d6f9f45e01e98aeef Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 12 Mar 2025 16:44:21 +0000 Subject: [PATCH 31/44] [nrf fromtree] zephyr: Prevent selecting MBEDTLS_ASN1_PARSE_C when not needed Make selection of MBEDTLS_ASN1_PARSE_C, in BOOT_ED25519_MBEDTLS, depending on ASN1 parsing being enabled. Signed-off-by: Dominik Ermel (cherry picked from commit 0ba80ffb1a0a2514385de47da67ac19c17ff23de) --- boot/zephyr/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 18bbcb134..17a7007c1 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -296,7 +296,7 @@ config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS select MBEDTLS - select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN + select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN && !BOOT_KEY_IMPORT_BYPASS_ASN select BOOT_AES_MBEDTLS_DEPENDENCIES if MBEDTLS_BUILTIN && BOOT_ENCRYPT_IMAGE config BOOT_ED25519_PSA From e4ff1b696e5d7442834eb2acbd087799bae08b59 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 12 Mar 2025 16:13:28 +0000 Subject: [PATCH 32/44] [nrf fromtree] zephyr: Fix ED25519 compilation with mbedTLS ED25519 with mbedTLS has not been linking due to missing SHA512, which is internally required by ED25519 implementation. Signed-off-by: Dominik Ermel (cherry picked from commit f523c60dbd60677557d192dcabd20af28a8470c3) --- boot/zephyr/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 17a7007c1..8ee906621 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -295,7 +295,9 @@ config BOOT_ED25519_TINYCRYPT config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS + select BOOT_IMG_HASH_ALG_SHA512_ALLOW select MBEDTLS + select MBEDTLS_SHA512 select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN && !BOOT_KEY_IMPORT_BYPASS_ASN select BOOT_AES_MBEDTLS_DEPENDENCIES if MBEDTLS_BUILTIN && BOOT_ENCRYPT_IMAGE From fdfd19ba321a58b7a7facaf4242ae9dea8e32934 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 13 Mar 2025 15:07:09 +0000 Subject: [PATCH 33/44] [nrf fromtree] zephyr: Add missing selection for allowed SHA algorithms All of ED25519 backends allow SHA512, together with SHA512. The ED25519 internally requires SHA512 for calculations, but image may be hashed with any SHA algorithm. The PSA has also been missing selecting of any SHA as allowed. Signed-off-by: Dominik Ermel (cherry picked from commit e5d8640cd49829a1d5916fbae04cb2c817fb6116) --- boot/zephyr/Kconfig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 8ee906621..5d8c66570 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -290,11 +290,13 @@ choice BOOT_ED25519_IMPLEMENTATION config BOOT_ED25519_TINYCRYPT bool "Use tinycrypt" select BOOT_USE_TINYCRYPT + select BOOT_IMG_HASH_ALG_SHA256_ALLOW select BOOT_IMG_HASH_ALG_SHA512_ALLOW config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS + select BOOT_IMG_HASH_ALG_SHA256_ALLOW select BOOT_IMG_HASH_ALG_SHA512_ALLOW select MBEDTLS select MBEDTLS_SHA512 @@ -305,10 +307,13 @@ config BOOT_ED25519_PSA bool "Use PSA crypto" select MBEDTLS select BOOT_USE_PSA_CRYPTO - select MBEDTLS_PSA_CRYPTO_C - select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN select PSA_CRYPTO_CLIENT select PSA_CRYPTO_C + select MBEDTLS_PSA_CRYPTO_C + select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN + select MBEDTLS_ENABLE_HEAP + select BOOT_IMG_HASH_ALG_SHA256_ALLOW + select BOOT_IMG_HASH_ALG_SHA512_ALLOW select BOOT_ED25519_PSA_DEPENDENCIES select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE From 24433b1042db1744065a0e217e17d09a7f4592a2 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 18 Mar 2025 12:40:06 +0000 Subject: [PATCH 34/44] [nrf fromlist] bootutil: Fix ed25519 pure signature verification Accidentally added check for size of blen against hash length, in bootutil_verify, was doubling check done in bootutli_verify_sig and prevented pure signature from working. Upstream PR #: 2237 Signed-off-by: Dominik Ermel --- boot/bootutil/src/image_ed25519.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 90e8300de..ffb8cec3b 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -90,7 +90,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, uint8_t *pubkey; uint8_t *end; - if (blen != IMAGE_HASH_SIZE || slen != EDDSA_SIGNATURE_LENGTH) { + if (slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } From f78a440f5617a97e1f42955d2fadc3940d8dd8f4 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 17:31:33 +0000 Subject: [PATCH 35/44] [nrf noup] zephyr: sdk-nrf specific overrides on PSA Kconfigs Select proper configuration and disable mbedTLS selection, as we are using NRF Security enabled Oberon. Signed-off-by: Dominik Ermel --- boot/bootutil/zephyr/CMakeLists.txt | 2 +- boot/zephyr/Kconfig | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index f6d37441c..44f78f395 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -40,7 +40,7 @@ if(CONFIG_BOOT_USE_PSA_CRYPTO) ) endif() -if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO) +if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO AND NOT CONFIG_NRF_SECURITY) zephyr_link_libraries(mbedTLS) endif() endif() diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 5d8c66570..a3bb0aab0 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -89,8 +89,7 @@ config BOOT_ED25519_PSA_DEPENDENCIES select PSA_WANT_ALG_SHA_256 select PSA_WANT_ALG_SHA_512 select PSA_WANT_ALG_PURE_EDDSA - # Seems that upstream mbedTLS does not have TE - #select PSA_WANT_ECC_TWISTED_EDWARDS_255 + select PSA_WANT_ECC_TWISTED_EDWARDS_255 select PSA_WANT_ECC_MONTGOMERY_255 select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT help @@ -285,6 +284,7 @@ config BOOT_SIGNATURE_TYPE_PURE choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" + default BOOT_ED25519_PSA if NRF_SECURITY default BOOT_ED25519_TINYCRYPT config BOOT_ED25519_TINYCRYPT @@ -305,7 +305,7 @@ config BOOT_ED25519_MBEDTLS config BOOT_ED25519_PSA bool "Use PSA crypto" - select MBEDTLS + depends on NRF_SECURITY select BOOT_USE_PSA_CRYPTO select PSA_CRYPTO_CLIENT select PSA_CRYPTO_C @@ -370,11 +370,11 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. -if MBEDTLS +if MBEDTLS || NRF_SECURITY config MBEDTLS_CFG_FILE default "config-tls-generic.h" if MBEDTLS_BUILTIN || BOOT_USE_PSA_CRYPTO - default "mcuboot-mbedtls-cfg.h" if BOOT_USE_MBEDTLS + default "mcuboot-mbedtls-cfg.h" if BOOT_USE_MBEDTLS && !NRF_SECURITY endif From 44b1e56121fd18f53051686dbc16ff442552f122 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Jul 2023 08:42:49 +0100 Subject: [PATCH 36/44] [nrf noup] zephyr: Fix path variables Fixes path variables to use the proper Zephyr module variables Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit d978f7b4e9c000d554242c65800fdee51381a3d2) (cherry picked from commit 4943e2f425738025e48efc74d323884c4effdf4d) --- boot/zephyr/CMakeLists.txt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 2849e31fe..7c60125bf 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -29,21 +29,20 @@ if(NOT CONFIG_MBEDTLS_BUILTIN AND NOT CONFIG_BOOT_KEY_IMPORT_BYPASS_ASN) set(MBEDTLS_ASN1_DIR "${MCUBOOT_DIR}/ext/mbedtls-asn1") assert_exists(MBEDTLS_ASN1_DIR) endif() -set(NRF_DIR "${MCUBOOT_DIR}/ext/nrf") +set(MCUBOOT_NRF_EXT_DIR "${MCUBOOT_DIR}/ext/nrf") if(CONFIG_BOOT_USE_NRF_CC310_BL) -set(NRFXLIB_DIR ${ZEPHYR_BASE}/../nrfxlib) -if(NOT EXISTS ${NRFXLIB_DIR}) - message(FATAL_ERROR " + if(NOT EXISTS ${ZEPHYR_NRFXLIB_MODULE_DIR}) + message(FATAL_ERROR " ------------------------------------------------------------------------ - No such file or directory: ${NRFXLIB_DIR} + No such file or directory: ${ZEPHYR_NRFXLIB_MODULE_DIR} The current configuration enables nRF CC310 crypto accelerator hardware with the `CONFIG_BOOT_USE_NRF_CC310_BL` option. Please follow `ext/nrf/README.md` guide to fix your setup or use tinycrypt instead of the HW accelerator. To use the tinycrypt set `CONFIG_BOOT_ECDSA_TINYCRYPT` to y. ------------------------------------------------------------------------") -endif() + endif() endif() zephyr_library_include_directories( @@ -191,8 +190,8 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) ${TINYCRYPT_DIR}/source/utils.c ) elseif(CONFIG_BOOT_USE_NRF_CC310_BL) - zephyr_library_sources(${NRF_DIR}/cc310_glue.c) - zephyr_library_include_directories(${NRF_DIR}) + 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) From 2d2033fb8d256e8ef8ad42f790e644cae5303fb3 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 22 Aug 2024 14:17:46 +0100 Subject: [PATCH 37/44] [nrf noup] zephyr: Add support for compressed image updates Adds support for LZMA-compressed firmware updates Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 474a92290901ffb468978574087e98fc89fb3e80) (cherry picked from commit 655eeacf16cfd090bb309ef06f940a943790e671) --- boot/bootutil/src/bootutil_misc.c | 80 +- boot/bootutil/src/image_validate.c | 226 ++++ boot/bootutil/src/loader.c | 27 +- boot/zephyr/CMakeLists.txt | 6 + boot/zephyr/Kconfig | 10 +- boot/zephyr/decompression.c | 1115 +++++++++++++++++ .../include/compression/decompression.h | 104 ++ 7 files changed, 1545 insertions(+), 23 deletions(-) create mode 100644 boot/zephyr/decompression.c create mode 100644 boot/zephyr/include/compression/decompression.h diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 56859d515..ac50eaa52 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -42,6 +42,11 @@ #include "bootutil/enc_key.h" #endif +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + BOOT_LOG_MODULE_DECLARE(mcuboot); /* Currently only used by imgmgr */ @@ -384,35 +389,76 @@ boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) goto done; } - off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); +#ifdef MCUBOOT_DECOMPRESS_IMAGES + if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), boot_img_hdr(state, slot))) { + uint32_t tmp_size = 0; - if (flash_area_read(fap, off, &info, sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } + rc = bootutil_get_img_decomp_size(boot_img_hdr(state, slot), fap, &tmp_size); - protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; - if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { - if (protect_tlv_size != info.it_tlv_tot) { + if (rc) { rc = BOOT_EBADIMAGE; goto done; } - if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { + off = boot_img_hdr(state, slot)->ih_hdr_size + tmp_size; + + rc = boot_size_protected_tlvs(boot_img_hdr(state, slot), fap, &tmp_size); + + if (rc) { + rc = BOOT_EBADIMAGE; + goto done; + } + + off += tmp_size; + + if (flash_area_read(fap, (BOOT_TLV_OFF(boot_img_hdr(state, slot)) + + boot_img_hdr(state, slot)->ih_protect_tlv_size), &info, + sizeof(info))) { rc = BOOT_EFLASH; goto done; } - } else if (protect_tlv_size != 0) { - rc = BOOT_EBADIMAGE; - goto done; - } - if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { - rc = BOOT_EBADIMAGE; - goto done; + if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + rc = BOOT_EBADIMAGE; + goto done; + } + + *size = off + info.it_tlv_tot; + } else { +#else + if (1) { +#endif + off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); + + if (flash_area_read(fap, off, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } + + protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; + if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { + if (protect_tlv_size != info.it_tlv_tot) { + rc = BOOT_EBADIMAGE; + goto done; + } + + if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } + } else if (protect_tlv_size != 0) { + rc = BOOT_EBADIMAGE; + goto done; + } + + if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + rc = BOOT_EBADIMAGE; + goto done; + } + + *size = off + protect_tlv_size + info.it_tlv_tot; } - *size = off + protect_tlv_size + info.it_tlv_tot; rc = 0; done: diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index e038f22fe..08f354be8 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -40,6 +40,15 @@ #include "mcuboot_config/mcuboot_config.h" +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -470,6 +479,68 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, FIH_DECLARE(security_counter_valid, FIH_FAILURE); #endif +#ifdef MCUBOOT_DECOMPRESS_IMAGES + /* If the image is compressed, the integrity of the image must also be validated */ + if (MUST_DECOMPRESS(fap, image_index, hdr)) { + bool found_decompressed_size = false; + bool found_decompressed_sha = false; + bool found_decompressed_signature = false; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(fap)) { + rc = -1; + goto out; + } + + while (true) { + uint16_t expected_size = 0; + bool *found_flag = NULL; + + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + break; + } + + switch (type) { + case IMAGE_TLV_DECOMP_SIZE: + expected_size = sizeof(size_t); + found_flag = &found_decompressed_size; + break; + case IMAGE_TLV_DECOMP_SHA: + expected_size = IMAGE_HASH_SIZE; + found_flag = &found_decompressed_sha; + break; + case IMAGE_TLV_DECOMP_SIGNATURE: + found_flag = &found_decompressed_signature; + break; + default: + continue; + }; + + if (type == IMAGE_TLV_DECOMP_SIGNATURE && !EXPECTED_SIG_LEN(len)) { + rc = -1; + goto out; + } else if (type != IMAGE_TLV_DECOMP_SIGNATURE && len != expected_size) { + rc = -1; + goto out; + } + + *found_flag = true; + } + + rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature); + if (rc) { + goto out; + } + } +#endif + #if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); @@ -680,6 +751,161 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } #endif +#ifdef MCUBOOT_DECOMPRESS_IMAGES + /* Only after all previous verifications have passed, perform a dry-run of the decompression + * and ensure the image is valid + */ + if (!rc && MUST_DECOMPRESS(fap, image_index, hdr)) { + image_hash_valid = 0; + FIH_SET(valid_signature, FIH_FAILURE); + + rc = bootutil_img_hash_decompress(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz, + hash, seed, seed_len); + if (rc) { + goto out; + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SHA, true); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(fap)) { + rc = -1; + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + break; + } + + if (type == IMAGE_TLV_DECOMP_SHA) { + /* Verify the image hash. This must always be present. */ + if (len != sizeof(hash)) { + rc = -1; + goto out; + } + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash)); + if (rc) { + goto out; + } + + FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash)); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } + + image_hash_valid = 1; + } + } + + rc = !image_hash_valid; + if (rc) { + goto out; + } + +#ifdef EXPECTED_SIG_TLV +#ifdef EXPECTED_KEY_TLV + rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(fap)) { + rc = -1; + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + break; + } + + if (type == EXPECTED_KEY_TLV) { + /* + * Determine which key we should be checking. + */ + if (len > KEY_BUF_SIZE) { + rc = -1; + goto out; + } +#ifndef MCUBOOT_HW_KEY + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); + if (rc) { + goto out; + } + key_id = bootutil_find_key(buf, len); +#else + rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len); + if (rc) { + goto out; + } + key_id = bootutil_find_key(image_index, key_buf, len); +#endif /* !MCUBOOT_HW_KEY */ + /* + * The key may not be found, which is acceptable. There + * can be multiple signatures, each preceded by a key. + */ + } + } +#endif /* EXPECTED_KEY_TLV */ + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(fap)) { + rc = -1; + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIGNATURE) { + /* Ignore this signature if it is out of bounds. */ + if (key_id < 0 || key_id >= bootutil_key_cnt) { + key_id = -1; + continue; + } + + if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { + rc = -1; + goto out; + } + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); + if (rc) { + goto out; + } + + FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), + buf, len, key_id); + key_id = -1; + } + } +#endif /* EXPECTED_SIG_TLV */ + } +#endif + +#ifdef EXPECTED_SIG_TLV + FIH_SET(fih_rc, valid_signature); +#endif + out: if (rc) { FIH_SET(fih_rc, FIH_FAILURE); diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 4c61c4217..a561d5cb7 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -49,6 +49,11 @@ #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + #ifdef __ZEPHYR__ #include #endif @@ -913,10 +918,10 @@ boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fa return false; } #else - if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) && - (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) - { - return false; + if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) { + if (!boot_is_compressed_header_valid(hdr, fap, state)) { + return false; + } } #endif @@ -1130,6 +1135,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * attempts to validate and boot it. */ } + #if !defined(__BOOTSIM__) BOOT_LOG_ERR("Image in the %s slot is not valid!", (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary"); @@ -1606,6 +1612,9 @@ boot_copy_region(struct boot_loader_state *state, #else (void)state; #endif +#ifdef MCUBOOT_DECOMPRESS_IMAGES + struct image_header *hdr; +#endif TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4))); @@ -1631,6 +1640,16 @@ boot_copy_region(struct boot_loader_state *state, } #endif +#ifdef MCUBOOT_DECOMPRESS_IMAGES + hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); + + if (MUST_DECOMPRESS(fap_src, BOOT_CURR_IMG(state), hdr)) { + /* Use alternative function for compressed images */ + return boot_copy_region_decompress(state, fap_src, fap_dst, off_src, off_dst, sz, buf, + BUF_SZ); + } +#endif + bytes_copied = 0; while (bytes_copied < sz) { if (sz - bytes_copied > sizeof buf) { diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 7c60125bf..a9a761a4d 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -288,6 +288,12 @@ if(CONFIG_BOOT_ENCRYPT_EC256) ) endif() +if(CONFIG_BOOT_DECOMPRESSION) + zephyr_library_sources( + decompression.c + ) +endif() + if(CONFIG_MCUBOOT_SERIAL) zephyr_sources(${BOOT_DIR}/zephyr/serial_adapter.c) zephyr_sources(${BOOT_DIR}/boot_serial/src/boot_serial.c) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a3bb0aab0..d68ac4f6e 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -965,6 +965,10 @@ config BOOT_BANNER_STRING config BOOT_DECOMPRESSION_SUPPORT bool + depends on NRF_COMPRESS && NRF_COMPRESS_DECOMPRESSION && (NRF_COMPRESS_LZMA_VERSION_LZMA1 || NRF_COMPRESS_LZMA_VERSION_LZMA2) + depends on !SINGLE_APPLICATION_SLOT && !BOOT_ENCRYPT_IMAGE && BOOT_UPGRADE_ONLY + depends on UPDATEABLE_IMAGE_NUMBER = 1 + default y help Hidden symbol which should be selected if a system provided decompression support. @@ -972,6 +976,8 @@ if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION bool "Decompression" + select NRF_COMPRESS_CLEANUP + select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to @@ -980,9 +986,9 @@ menuconfig BOOT_DECOMPRESSION if BOOT_DECOMPRESSION config BOOT_DECOMPRESSION_BUFFER_SIZE - int "Write buffer size" + int range 16 16384 - default 4096 + default NRF_COMPRESS_CHUNK_SIZE help The size of a secondary buffer used for writing decompressed data to the storage device. diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c new file mode 100644 index 000000000..062cdbc61 --- /dev/null +++ b/boot/zephyr/decompression.c @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include "compression/decompression.h" +#include "bootutil/crypto/sha.h" +#include "bootutil/bootutil_log.h" + +#if !defined(__BOOTSIM__) +#define TARGET_STATIC static +#else +#define TARGET_STATIC +#endif + +#if defined(MCUBOOT_SIGN_RSA) +#if MCUBOOT_SIGN_RSA_LEN == 2048 +#define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048_PSS +#elif MCUBOOT_SIGN_RSA_LEN == 3072 +#define EXPECTED_SIG_TLV IMAGE_TLV_RSA3072_PSS +#endif +#elif defined(MCUBOOT_SIGN_EC256) || \ + defined(MCUBOOT_SIGN_EC384) || \ + defined(MCUBOOT_SIGN_EC) +#define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG +#elif defined(MCUBOOT_SIGN_ED25519) +#define EXPECTED_SIG_TLV IMAGE_TLV_ED25519 +#endif + +/* Number of times that consumed data by decompression system can be 0 in a row before aborting */ +#define OFFSET_ZERO_CHECK_TIMES 3 + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +static int boot_sha_protected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, uint32_t protected_size, + uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx); + +bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, + struct boot_loader_state *state) +{ + /* Image is compressed in secondary slot, need to check if fits into the primary slot */ + bool opened_flash_area = false; + int primary_fa_id; + int rc; + int size_check; + int size; + uint32_t protected_tlvs_size; + uint32_t decompressed_size; + + if (BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT) == NULL) { + opened_flash_area = true; + } + + primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); + rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); + assert(rc == 0); + + size_check = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); + + if (opened_flash_area) { + (void)flash_area_close(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); + } + + rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_size); + + if (rc) { + return false; + } + + if (!boot_u32_safe_add(&size, decompressed_size, hdr->ih_hdr_size)) { + return false; + } + + rc = boot_size_protected_tlvs(hdr, fap, &protected_tlvs_size); + + if (rc) { + return false; + } + + if (!boot_u32_safe_add(&size, size, protected_tlvs_size)) { + return false; + } + + if (size >= size_check) { + BOOT_LOG_ERR("Compressed image too large, decompressed image size: 0x%x, slot size: 0x%x", + size, size_check); + + return false; + } + + return true; +} + +int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index, + struct image_header *hdr, const struct flash_area *fap, + uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, + uint8_t *seed, int seed_len) +{ + int rc; + uint32_t read_pos = 0; + uint32_t write_pos = 0; + uint32_t protected_tlv_size = 0; + uint32_t decompressed_image_size; + struct nrf_compress_implementation *compression = NULL; + TARGET_STATIC struct image_header modified_hdr; + bootutil_sha_context sha_ctx; + uint8_t flash_erased_value; + + bootutil_sha_init(&sha_ctx); + + /* Setup decompression system */ +#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { +#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { +#endif + /* Compressed image does not use the correct compression type which is supported by this + * build + */ + BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); + rc = BOOT_EBADIMAGE; + + goto finish_without_clean; + } + + compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + + if (compression == NULL || compression->init == NULL || compression->deinit == NULL || + compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { + /* Compression library missing or missing required function pointer */ + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + + goto finish_without_clean; + } + + rc = compression->init(NULL); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + + goto finish_without_clean; + } + + /* We need a modified header which has the updated sizes, start with the original header */ + memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); + + /* Extract the decompressed image size from the protected TLV, set it and remove the + * compressed image flags + */ + rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; + modified_hdr.ih_img_size = decompressed_image_size; + + /* Calculate the protected TLV size, these will not include the decompressed + * sha/size/signature entries + */ + rc = boot_size_protected_tlvs(hdr, fap, &protected_tlv_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + modified_hdr.ih_protect_tlv_size = protected_tlv_size; + bootutil_sha_update(&sha_ctx, &modified_hdr, sizeof(modified_hdr)); + read_pos = sizeof(modified_hdr); + flash_erased_value = flash_area_erased_val(fap); + memset(tmp_buf, flash_erased_value, tmp_buf_sz); + + while (read_pos < modified_hdr.ih_hdr_size) { + uint32_t copy_size = tmp_buf_sz; + + if ((read_pos + copy_size) > modified_hdr.ih_hdr_size) { + copy_size = modified_hdr.ih_hdr_size - read_pos; + } + + bootutil_sha_update(&sha_ctx, tmp_buf, copy_size); + read_pos += copy_size; + } + + /* Read in compressed data, decompress and add to hash calculation */ + read_pos = 0; + + while (read_pos < hdr->ih_img_size) { + uint32_t copy_size = hdr->ih_img_size - read_pos; + uint32_t tmp_off = 0; + uint8_t offset_zero_check = 0; + + if (copy_size > tmp_buf_sz) { + copy_size = tmp_buf_sz; + } + + rc = flash_area_read(fap, (hdr->ih_hdr_size + read_pos), tmp_buf, copy_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); + rc = BOOT_EFLASH; + + goto finish; + } + + /* Decompress data in chunks, writing it back with a larger write offset of the primary + * slot than read size of the secondary slot + */ + while (tmp_off < copy_size) { + uint32_t offset = 0; + uint8_t *output = NULL; + uint32_t output_size = 0; + uint32_t chunk_size; + bool last_packet = false; + + chunk_size = compression->decompress_bytes_needed(NULL); + + if (chunk_size > (copy_size - tmp_off)) { + chunk_size = (copy_size - tmp_off); + } + + if ((read_pos + tmp_off + chunk_size) >= hdr->ih_img_size) { + last_packet = true; + } + + rc = compression->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, &offset, + &output, &output_size); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + + goto finish; + } + + write_pos += output_size; + + if (write_pos > decompressed_image_size) { + BOOT_LOG_ERR("Decompressed image larger than claimed TLV size, at least: %d", + write_pos); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + /* Additional dry-run validity checks */ + if (last_packet == true && write_pos == 0) { + /* Last packet and we still have no output, this is a faulty update */ + BOOT_LOG_ERR("All compressed data consumed without any output, image not valid"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + if (offset == 0) { + /* If the decompression system continually consumes 0 bytes, then there is a + * problem with this update image, abort and mark image as bad + */ + if (offset_zero_check >= OFFSET_ZERO_CHECK_TIMES) { + BOOT_LOG_ERR("Decompression system returning no output data, image not valid"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + ++offset_zero_check; + + break; + } else { + offset_zero_check = 0; + } + + if (output_size > 0) { + bootutil_sha_update(&sha_ctx, output, output_size); + } + + tmp_off += offset; + } + + read_pos += copy_size; + } + + /* If there are any protected TLVs present, add them after the main decompressed image */ + if (modified_hdr.ih_protect_tlv_size > 0) { + rc = boot_sha_protected_tlvs(hdr, fap, modified_hdr.ih_protect_tlv_size, tmp_buf, + tmp_buf_sz, &sha_ctx); + } + + bootutil_sha_finish(&sha_ctx, hash_result); + +finish: + /* Clean up decompression system */ + (void)compression->deinit(NULL); + +finish_without_clean: + bootutil_sha_drop(&sha_ctx); + + return rc; +} + +static int boot_copy_protected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_dst, + uint32_t protected_size, uint8_t *buf, size_t buf_size, + uint16_t *buf_pos, uint32_t *written) +{ + int rc; + uint32_t off; + uint32_t write_pos = 0; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + struct image_tlv tlv_header; + struct image_tlv_info tlv_info_header = { + .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, + .it_tlv_tot = protected_size, + }; + uint16_t info_size_left = sizeof(tlv_info_header); + + while (info_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + + if (info_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; + + if (single_copy_size > info_size_left) { + single_copy_size = info_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - + info_size_left], single_copy_size); + *buf_pos += single_copy_size; + info_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || + type == IMAGE_TLV_DECOMP_SIGNATURE) { + /* Skip these TLVs as they are not needed */ + continue; + } else { + uint16_t header_size_left = sizeof(tlv_header); + uint16_t data_size_left = len; + + tlv_header.it_type = type; + tlv_header.it_len = len; + + while (header_size_left > 0 || data_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + uint8_t *tlv_header_address = (uint8_t *)&tlv_header; + + if (header_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + + if (single_copy_size > header_size_left) { + single_copy_size = header_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - + header_size_left], + single_copy_size); + *buf_pos += single_copy_size; + copy_size -= single_copy_size; + header_size_left -= single_copy_size; + } + + if (data_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + + if (single_copy_size > data_size_left) { + single_copy_size = data_size_left; + } + + rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + (len - data_size_left)), + &buf[*buf_pos], single_copy_size); + + if (rc) { + BOOT_LOG_ERR( + "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); + + goto out; + } + + *buf_pos += single_copy_size; + data_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + } + } + + *written = write_pos; + +out: + return rc; +} + +static int boot_sha_protected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, uint32_t protected_size, + uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx) +{ + int rc; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + struct image_tlv tlv_header; + struct image_tlv_info tlv_info_header = { + .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, + .it_tlv_tot = protected_size, + }; + + bootutil_sha_update(sha_ctx, &tlv_info_header, sizeof(tlv_info_header)); + + rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); + if (rc) { + goto out; + } + + while (true) { + uint32_t read_off = 0; + + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || + type == IMAGE_TLV_DECOMP_SIGNATURE) { + /* Skip these TLVs as they are not needed */ + continue; + } + + tlv_header.it_type = type; + tlv_header.it_len = len; + + bootutil_sha_update(sha_ctx, &tlv_header, sizeof(tlv_header)); + + while (read_off < len) { + uint32_t copy_size = buf_size; + + if (copy_size > (len - read_off)) { + copy_size = len - read_off; + } + + rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + read_off), buf, copy_size); + + if (rc) { + BOOT_LOG_ERR( + "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off + read_off), copy_size, fap_src->fa_id, rc); + + goto out; + } + + bootutil_sha_update(sha_ctx, buf, copy_size); + read_off += copy_size; + } + } + +out: + return rc; +} + +int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *sz) +{ + int rc = 0; + uint32_t tlv_size; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + + *sz = 0; + tlv_size = hdr->ih_protect_tlv_size; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || + type == IMAGE_TLV_DECOMP_SIGNATURE) { + /* Exclude these TLVs as they will be copied to the unprotected area */ + tlv_size -= len + sizeof(struct image_tlv); + } + } + + if (!rc) { + if (tlv_size == sizeof(struct image_tlv_info)) { + /* If there are no entries then omit protected TLV section entirely */ + tlv_size = 0; + } + + *sz = tlv_size; + } + +out: + return rc; +} + +int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *sz) +{ + int rc = 0; + uint32_t tlv_size; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + + *sz = 0; + tlv_size = sizeof(struct image_tlv_info); + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } else if (bootutil_tlv_iter_is_prot(&it, off) && type != IMAGE_TLV_DECOMP_SHA && + type != IMAGE_TLV_DECOMP_SIGNATURE) { + /* Include size of protected hash and signature as these will be replacing the + * original ones + */ + continue; + } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { + /* Exclude the original unprotected TLVs for signature and hash, the length of the + * signature of the compressed data might not be the same size as the signaute of the + * decompressed data, as is the case when using ECDSA-P256 + */ + continue; + } + + tlv_size += len + sizeof(struct image_tlv); + } + + if (!rc) { + if (tlv_size == sizeof(struct image_tlv_info)) { + /* If there are no entries in the unprotected TLV section then there is something wrong + * with this image + */ + BOOT_LOG_ERR("No unprotected TLVs in post-decompressed image output, image is invalid"); + rc = BOOT_EBADIMAGE; + + goto out; + } + + *sz = tlv_size; + } + +out: + return rc; +} + +static int boot_copy_unprotected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_dst, + uint32_t unprotected_size, uint8_t *buf, size_t buf_size, + uint16_t *buf_pos, uint32_t *written) +{ + int rc; + uint32_t write_pos = 0; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + struct image_tlv_iter it_protected; + struct image_tlv tlv_header; + struct image_tlv_info tlv_info_header = { + .it_magic = IMAGE_TLV_INFO_MAGIC, + .it_tlv_tot = unprotected_size, + }; + uint16_t info_size_left = sizeof(tlv_info_header); + + while (info_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + + if (info_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; + + if (single_copy_size > info_size_left) { + single_copy_size = info_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - + info_size_left], single_copy_size); + *buf_pos += single_copy_size; + info_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, false); + if (rc) { + goto out; + } + + while (true) { + uint16_t header_size_left = sizeof(tlv_header); + uint16_t data_size_left; + + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } else if (bootutil_tlv_iter_is_prot(&it, off)) { + /* Skip protected TLVs */ + continue; + } + + /* Change the values of these fields from having the data in the compressed image + * unprotected TLV (which is valid only for the compressed image data) to having the + * fields in the protected TLV section (which is valid for the decompressed image data). + * The compressed data is no longer needed + */ + if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { + rc = bootutil_tlv_iter_begin(&it_protected, hdr, fap_src, (type == EXPECTED_HASH_TLV ? + IMAGE_TLV_DECOMP_SHA : + IMAGE_TLV_DECOMP_SIGNATURE), + true); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it_protected, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + } + + if (type == IMAGE_TLV_DECOMP_SHA) { + type = EXPECTED_HASH_TLV; + } else { + type = EXPECTED_SIG_TLV; + } + } + + data_size_left = len; + tlv_header.it_type = type; + tlv_header.it_len = len; + + while (header_size_left > 0 || data_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + + if (header_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + uint8_t *tlv_header_address = (uint8_t *)&tlv_header; + + if (single_copy_size > header_size_left) { + single_copy_size = header_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - header_size_left], + single_copy_size); + *buf_pos += single_copy_size; + copy_size -= single_copy_size; + header_size_left -= single_copy_size; + } + + if (data_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + + if (single_copy_size > data_size_left) { + single_copy_size = data_size_left; + } + + rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + len - data_size_left), + &buf[*buf_pos], single_copy_size); + + if (rc) { + BOOT_LOG_ERR( + "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); + + goto out; + } + + *buf_pos += single_copy_size; + data_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + } + + *written = write_pos; + +out: + return rc; +} + +int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_src, + uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size) +{ + int rc; + uint32_t pos = 0; + uint16_t decomp_buf_size = 0; + uint16_t write_alignment; + uint32_t write_pos = 0; + uint32_t protected_tlv_size = 0; + uint32_t unprotected_tlv_size = 0; + uint32_t tlv_write_size = 0; + uint32_t decompressed_image_size; + struct nrf_compress_implementation *compression = NULL; + struct image_header *hdr; + TARGET_STATIC uint8_t decomp_buf[CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE] __attribute__((aligned(4))); + TARGET_STATIC struct image_header modified_hdr; + + hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); + + /* Setup decompression system */ +#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { +#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { +#endif + /* Compressed image does not use the correct compression type which is supported by this + * build + */ + BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + + if (compression == NULL || compression->init == NULL || compression->deinit == NULL || + compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { + /* Compression library missing or missing required function pointer */ + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + + goto finish; + } + + rc = compression->init(NULL); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + + goto finish; + } + + write_alignment = flash_area_align(fap_dst); + + memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); + + rc = bootutil_get_img_decomp_size(hdr, fap_src, &decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; + modified_hdr.ih_img_size = decompressed_image_size; + + /* Calculate protected TLV size for target image once items are removed */ + rc = boot_size_protected_tlvs(hdr, fap_src, &protected_tlv_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + modified_hdr.ih_protect_tlv_size = protected_tlv_size; + + rc = boot_size_unprotected_tlvs(hdr, fap_src, &unprotected_tlv_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine unprotected TLV size of compressed image"); + rc = BOOT_EBADIMAGE; + + goto finish; + } + + /* Write out the image header first, this should be a multiple of the write size */ + rc = flash_area_write(fap_dst, off_dst, &modified_hdr, sizeof(modified_hdr)); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + off_dst, sizeof(modified_hdr), fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto finish; + } + + /* Read in, decompress and write out data */ + while (pos < hdr->ih_img_size) { + uint32_t copy_size = hdr->ih_img_size - pos; + uint32_t tmp_off = 0; + + if (copy_size > buf_size) { + copy_size = buf_size; + } + + rc = flash_area_read(fap_src, off_src + hdr->ih_hdr_size + pos, buf, copy_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_src + hdr->ih_hdr_size + pos), copy_size, fap_src->fa_id, rc); + rc = BOOT_EFLASH; + + goto finish; + } + + /* Decompress data in chunks, writing it back with a larger write offset of the primary + * slot than read size of the secondary slot + */ + while (tmp_off < copy_size) { + uint32_t offset = 0; + uint32_t output_size = 0; + uint32_t chunk_size; + uint32_t compression_buffer_pos = 0; + uint8_t *output = NULL; + bool last_packet = false; + + chunk_size = compression->decompress_bytes_needed(NULL); + + if (chunk_size > (copy_size - tmp_off)) { + chunk_size = (copy_size - tmp_off); + } + + if ((pos + tmp_off + chunk_size) >= hdr->ih_img_size) { + last_packet = true; + } + + rc = compression->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, &offset, + &output, &output_size); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + + goto finish; + } + + /* Copy data to secondary buffer for writing out */ + while (output_size > 0) { + uint32_t data_size = (sizeof(decomp_buf) - decomp_buf_size); + + if (data_size > output_size) { + data_size = output_size; + } + + memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], data_size); + compression_buffer_pos += data_size; + + decomp_buf_size += data_size; + output_size -= data_size; + + /* Write data out from secondary buffer when it is full */ + if (decomp_buf_size == sizeof(decomp_buf)) { + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), + decomp_buf, sizeof(decomp_buf)); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), sizeof(decomp_buf), + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto finish; + } + + write_pos += sizeof(decomp_buf); + decomp_buf_size = 0; + } + } + + tmp_off += offset; + } + + pos += copy_size; + } + + /* Clean up decompression system */ + (void)compression->deinit(NULL); + + if (protected_tlv_size > 0) { + rc = boot_copy_protected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + + write_pos), protected_tlv_size, + decomp_buf, DECOMP_BUF_SIZE, &decomp_buf_size, + &tlv_write_size); + + if (rc) { + BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); + + goto finish; + } + + write_pos += tlv_write_size; + } + + tlv_write_size = 0; + rc = boot_copy_unprotected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + + write_pos), unprotected_tlv_size, + decomp_buf, DECOMP_BUF_SIZE, &decomp_buf_size, + &tlv_write_size); + + if (rc) { + BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); + + goto finish; + } + + write_pos += tlv_write_size; + + /* Check if we have unwritten data buffered up and, if so, write it out */ + if (decomp_buf_size > 0) { + uint32_t write_padding_size = write_alignment - (decomp_buf_size % write_alignment); + + /* Check if additional write padding should be applied to meet the minimum write size */ + if (write_padding_size) { + uint8_t flash_erased_value; + + flash_erased_value = flash_area_erased_val(fap_dst); + memset(&decomp_buf[decomp_buf_size], flash_erased_value, write_padding_size); + decomp_buf_size += write_padding_size; + } + + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf, + decomp_buf_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_size, + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + + goto finish; + } + + write_pos += decomp_buf_size; + decomp_buf_size = 0; + } + +finish: + memset(decomp_buf, 0, sizeof(decomp_buf)); + + return rc; +} + +int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *img_decomp_size) +{ + struct image_tlv_iter it; + uint32_t off; + uint16_t len; + int32_t rc; + + if (hdr == NULL || fap == NULL || img_decomp_size == NULL) { + return BOOT_EBADARGS; + } else if (hdr->ih_protect_tlv_size == 0) { + return BOOT_EBADIMAGE; + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIZE, true); + + if (rc) { + return rc; + } + + rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); + + if (rc != 0) { + return -1; + } + + if (len != sizeof(*img_decomp_size)) { + BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); + + return BOOT_EBADIMAGE; + } + + rc = LOAD_IMAGE_DATA(hdr, fap, off, img_decomp_size, len); + + if (rc) { + BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + off, len, fap->fa_id, rc); + + return BOOT_EFLASH; + } + + return 0; +} diff --git a/boot/zephyr/include/compression/decompression.h b/boot/zephyr/include/compression/decompression.h new file mode 100644 index 000000000..f8a676ac5 --- /dev/null +++ b/boot/zephyr/include/compression/decompression.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef H_DECOMPRESSION_ +#define H_DECOMPRESSION_ + +#include +#include +#include +#include "bootutil/bootutil.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/image.h" +#include "../src/bootutil_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Checks if a compressed image header is valid. + * + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param state Bootloader state object. + * + * @return true if valid; false if invalid. + */ +bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, + struct boot_loader_state *state); + +/** + * Reads in compressed image data from a slot, decompresses it and writes it out to a destination + * slot, including corresponding image headers and TLVs. + * + * @param state Bootloader state object. + * @param fap_src Flash area of the source slot. + * @param fap_dst Flash area of the destination slot. + * @param off_src Offset of the source slot to read from (should be 0). + * @param off_dst Offset of the destination slot to write to (should be 0). + * @param sz Size of the source slot data. + * @param buf Temporary buffer for reading data from. + * @param buf_size Size of temporary buffer. + * + * @return 0 on success; nonzero on failure. + */ +int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_src, + uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size); + +/** + * Gets the total data size (excluding headers and TLVs) of a compressed image when it is + * decompressed. + * + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param img_decomp_size Pointer to variable that will be updated with the decompressed image + * size. + * + * @return 0 on success; nonzero on failure. + */ +int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *img_decomp_size); + +/** + * Calculate MCUboot-compatible image hash of compressed image slot. + * + * @param enc_state Not currently used, set to NULL. + * @param image_index Image number. + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param tmp_buf Temporary buffer for reading data from. + * @param tmp_buf_sz Size of temporary buffer. + * @param hash_result Pointer to a variable that will be updated with the image hash. + * @param seed Not currently used, set to NULL. + * @param seed_len Not currently used, set to 0. + * + * @return 0 on success; nonzero on failure. + */ +int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index, + struct image_header *hdr, const struct flash_area *fap, + uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, + uint8_t *seed, int seed_len); + +/** + * Calculates the size that the compressed image protected TLV section will occupy once the image + * has been decompressed. + * + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param sz Pointer to variable that will be updated with the protected TLV size. + * + * @return 0 on success; nonzero on failure. + */ +int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap_src, + uint32_t *sz); + +#ifdef __cplusplus +} +#endif + +#endif /* H_DECOMPRESSION_ */ From 98b35415404363ebf5fd61496b862cfae6aa31df Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 2 Sep 2024 11:20:00 +0100 Subject: [PATCH 38/44] [nrf noup] zephyr: Add support for ARM thumb filter Adds support to the compressed image update for allowing encrypted images. Also removes the limit of having 1 updateable image Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 390c468afcdc4f3039a00efece68073355320a97) (cherry picked from commit cbb7da0a51f469b775bcbf9662ae3a905917563b) (cherry picked from commit 148712e7b4618aadbedd04e8d3ce5c3847d3be4f) --- boot/bootutil/src/loader.c | 2 +- boot/zephyr/Kconfig | 3 +- boot/zephyr/decompression.c | 439 +++++++++++++++++++++++++++++------- 3 files changed, 365 insertions(+), 79 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a561d5cb7..f9a9de71d 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1612,7 +1612,7 @@ boot_copy_region(struct boot_loader_state *state, #else (void)state; #endif -#ifdef MCUBOOT_DECOMPRESS_IMAGES +#if defined(MCUBOOT_DECOMPRESS_IMAGES) && !defined(MCUBOOT_ENC_IMAGES) struct image_header *hdr; #endif diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index d68ac4f6e..72eb8031b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -966,8 +966,7 @@ config BOOT_BANNER_STRING config BOOT_DECOMPRESSION_SUPPORT bool depends on NRF_COMPRESS && NRF_COMPRESS_DECOMPRESSION && (NRF_COMPRESS_LZMA_VERSION_LZMA1 || NRF_COMPRESS_LZMA_VERSION_LZMA2) - depends on !SINGLE_APPLICATION_SLOT && !BOOT_ENCRYPT_IMAGE && BOOT_UPGRADE_ONLY - depends on UPDATEABLE_IMAGE_NUMBER = 1 + depends on !SINGLE_APPLICATION_SLOT && BOOT_UPGRADE_ONLY default y help Hidden symbol which should be selected if a system provided decompression support. diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c index 062cdbc61..7a9507de6 100644 --- a/boot/zephyr/decompression.c +++ b/boot/zephyr/decompression.c @@ -29,6 +29,14 @@ #define EXPECTED_SIG_TLV IMAGE_TLV_ED25519 #endif +#define DECOMP_BUF_SIZE CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) +#define DECOMP_BUF_EXTRA_SIZE 2 +#else +#define DECOMP_BUF_EXTRA_SIZE 0 +#endif +#define DECOMP_BUF_ALLOC_SIZE (DECOMP_BUF_SIZE + DECOMP_BUF_EXTRA_SIZE) + /* Number of times that consumed data by decompression system can be 0 in a row before aborting */ #define OFFSET_ZERO_CHECK_TIMES 3 @@ -50,11 +58,17 @@ bool boot_is_compressed_header_valid(const struct image_header *hdr, const struc uint32_t protected_tlvs_size; uint32_t decompressed_size; + primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); + + if (primary_fa_id == fap->fa_id) { + BOOT_LOG_ERR("Primary slots cannot be compressed, image: %d", BOOT_CURR_IMG(state)); + return false; + } + if (BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT) == NULL) { opened_flash_area = true; } - primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); assert(rc == 0); @@ -87,13 +101,71 @@ bool boot_is_compressed_header_valid(const struct image_header *hdr, const struc if (size >= size_check) { BOOT_LOG_ERR("Compressed image too large, decompressed image size: 0x%x, slot size: 0x%x", size, size_check); - return false; } return true; } +static bool is_compression_object_valid(struct nrf_compress_implementation *compression) +{ + if (compression == NULL || compression->init == NULL || compression->deinit == NULL || + compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { + return false; + } + + return true; +} + +#ifdef MCUBOOT_ENC_IMAGES +int bootutil_get_img_decrypted_comp_size(const struct image_header *hdr, + const struct flash_area *fap, uint32_t *img_comp_size) +{ + if (hdr == NULL || fap == NULL || img_comp_size == NULL) { + return BOOT_EBADARGS; + } else if (hdr->ih_protect_tlv_size == 0) { + return BOOT_EBADIMAGE; + } + + if (!IS_ENCRYPTED(hdr)) { + /* Update is not encrypted so use size from header */ + *img_comp_size = hdr->ih_img_size; + } else { + struct image_tlv_iter it; + uint32_t off; + uint16_t len; + int32_t rc; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_COMP_DEC_SIZE, true); + + if (rc) { + return rc; + } + + rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); + + if (rc != 0) { + return -1; + } + + if (len != sizeof(*img_comp_size)) { + BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); + return BOOT_EBADIMAGE; + } + + rc = LOAD_IMAGE_DATA(hdr, fap, off, img_comp_size, len); + + if (rc) { + BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + off, len, fap->fa_id, rc); + return BOOT_EFLASH; + } + } + + return 0; +} +#endif + int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index, struct image_header *hdr, const struct flash_area *fap, uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, @@ -104,13 +176,35 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index uint32_t write_pos = 0; uint32_t protected_tlv_size = 0; uint32_t decompressed_image_size; - struct nrf_compress_implementation *compression = NULL; + uint32_t output_size_total = 0; + struct nrf_compress_implementation *compression_lzma = NULL; + struct nrf_compress_implementation *compression_arm_thumb = NULL; TARGET_STATIC struct image_header modified_hdr; bootutil_sha_context sha_ctx; uint8_t flash_erased_value; +#ifdef MCUBOOT_ENC_IMAGES + uint32_t comp_size = 0; + + rc = bootutil_get_img_decrypted_comp_size(hdr, fap, &comp_size); + + if (rc) { + BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); + rc = BOOT_EBADIMAGE; + goto finish_end; + } +#endif + bootutil_sha_init(&sha_ctx); +#ifdef MCUBOOT_ENC_IMAGES + /* Encrypted images only exist in the secondary slot */ + if (MUST_DECRYPT(fap, image_index, hdr) && + !boot_enc_valid(enc_state, 1)) { + return -1; + } +#endif + /* Setup decompression system */ #if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { @@ -122,27 +216,26 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index */ BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); rc = BOOT_EBADIMAGE; - goto finish_without_clean; } - compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); - if (compression == NULL || compression->init == NULL || compression->deinit == NULL || - compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { + if (!is_compression_object_valid(compression_lzma) || + !is_compression_object_valid(compression_arm_thumb)) { /* Compression library missing or missing required function pointer */ BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; - goto finish_without_clean; } - rc = compression->init(NULL); + rc = compression_lzma->init(NULL); + rc = compression_arm_thumb->init(NULL); if (rc) { BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; - goto finish_without_clean; } @@ -157,7 +250,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish; } @@ -172,7 +264,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index if (rc) { BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish; } @@ -196,8 +287,13 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index /* Read in compressed data, decompress and add to hash calculation */ read_pos = 0; +#ifdef MCUBOOT_ENC_IMAGES + while (read_pos < comp_size) { + uint32_t copy_size = comp_size - read_pos; +#else while (read_pos < hdr->ih_img_size) { uint32_t copy_size = hdr->ih_img_size - read_pos; +#endif uint32_t tmp_off = 0; uint8_t offset_zero_check = 0; @@ -211,10 +307,17 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); rc = BOOT_EFLASH; - goto finish; } +#ifdef MCUBOOT_ENC_IMAGES + if (MUST_DECRYPT(fap, image_index, hdr)) { + boot_enc_decrypt(enc_state, 1, read_pos, + copy_size, (read_pos & 0xf), + tmp_buf); + } +#endif + /* Decompress data in chunks, writing it back with a larger write offset of the primary * slot than read size of the secondary slot */ @@ -225,23 +328,26 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index uint32_t chunk_size; bool last_packet = false; - chunk_size = compression->decompress_bytes_needed(NULL); + chunk_size = compression_lzma->decompress_bytes_needed(NULL); if (chunk_size > (copy_size - tmp_off)) { chunk_size = (copy_size - tmp_off); } +#ifdef MCUBOOT_ENC_IMAGES + if ((read_pos + tmp_off + chunk_size) >= comp_size) { +#else if ((read_pos + tmp_off + chunk_size) >= hdr->ih_img_size) { +#endif last_packet = true; } - rc = compression->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, &offset, - &output, &output_size); + rc = compression_lzma->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, + &offset, &output, &output_size); if (rc) { BOOT_LOG_ERR("Decompression error: %d", rc); rc = BOOT_EBADSTATUS; - goto finish; } @@ -251,7 +357,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index BOOT_LOG_ERR("Decompressed image larger than claimed TLV size, at least: %d", write_pos); rc = BOOT_EBADIMAGE; - goto finish; } @@ -260,7 +365,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index /* Last packet and we still have no output, this is a faulty update */ BOOT_LOG_ERR("All compressed data consumed without any output, image not valid"); rc = BOOT_EBADIMAGE; - goto finish; } @@ -271,7 +375,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index if (offset_zero_check >= OFFSET_ZERO_CHECK_TIMES) { BOOT_LOG_ERR("Decompression system returning no output data, image not valid"); rc = BOOT_EBADIMAGE; - goto finish; } @@ -282,8 +385,48 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index offset_zero_check = 0; } + /* Copy data to secondary buffer for calculating hash */ if (output_size > 0) { - bootutil_sha_update(&sha_ctx, output, output_size); + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { + /* Run this through the ARM thumb filter */ + uint32_t offset_arm_thumb = 0; + uint8_t *output_arm_thumb = NULL; + uint32_t processed_size = 0; + uint32_t output_size_arm_thumb = 0; + + while (processed_size < output_size) { + uint32_t current_size = output_size - processed_size; + bool arm_thumb_last_packet = false; + + if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { + current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; + } + + if (last_packet && (processed_size + current_size) == + output_size) { + arm_thumb_last_packet = true; + } + + rc = compression_arm_thumb->decompress(NULL, &output[processed_size], + current_size, arm_thumb_last_packet, + &offset_arm_thumb, + &output_arm_thumb, + &output_size_arm_thumb); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + goto finish; + } + + bootutil_sha_update(&sha_ctx, output_arm_thumb, output_size_arm_thumb); + output_size_total += output_size_arm_thumb; + processed_size += current_size; + } + } else { + bootutil_sha_update(&sha_ctx, output, output_size); + output_size_total += output_size; + } } tmp_off += offset; @@ -292,6 +435,13 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index read_pos += copy_size; } + if (modified_hdr.ih_img_size != output_size_total) { + BOOT_LOG_ERR("Decompression expected output_size mismatch: %d vs %d", + modified_hdr.ih_img_size, output_size_total); + rc = BOOT_EBADSTATUS; + goto finish; + } + /* If there are any protected TLVs present, add them after the main decompressed image */ if (modified_hdr.ih_protect_tlv_size > 0) { rc = boot_sha_protected_tlvs(hdr, fap, modified_hdr.ih_protect_tlv_size, tmp_buf, @@ -302,11 +452,15 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index finish: /* Clean up decompression system */ - (void)compression->deinit(NULL); + (void)compression_lzma->deinit(NULL); + (void)compression_arm_thumb->deinit(NULL); finish_without_clean: bootutil_sha_drop(&sha_ctx); +#ifdef MCUBOOT_ENC_IMAGES +finish_end: +#endif return rc; } @@ -353,7 +507,6 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; - goto out; } @@ -379,7 +532,7 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, } if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE) { + type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { /* Skip these TLVs as they are not needed */ continue; } else { @@ -422,7 +575,6 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR( "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); - goto out; } @@ -438,7 +590,6 @@ static int boot_copy_protected_tlvs(const struct image_header *hdr, "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; - goto out; } @@ -490,7 +641,7 @@ static int boot_sha_protected_tlvs(const struct image_header *hdr, } if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE) { + type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { /* Skip these TLVs as they are not needed */ continue; } @@ -513,7 +664,6 @@ static int boot_sha_protected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR( "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off + read_off), copy_size, fap_src->fa_id, rc); - goto out; } @@ -556,7 +706,7 @@ int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_ } if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE) { + type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { /* Exclude these TLVs as they will be copied to the unprotected area */ tlv_size -= len + sizeof(struct image_tlv); } @@ -608,7 +758,7 @@ int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flas * original ones */ continue; - } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { + } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV || type == IMAGE_TLV_COMP_DEC_SIZE) { /* Exclude the original unprotected TLVs for signature and hash, the length of the * signature of the compressed data might not be the same size as the signaute of the * decompressed data, as is the case when using ECDSA-P256 @@ -626,7 +776,6 @@ int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flas */ BOOT_LOG_ERR("No unprotected TLVs in post-decompressed image output, image is invalid"); rc = BOOT_EBADIMAGE; - goto out; } @@ -681,7 +830,6 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; - goto out; } @@ -778,7 +926,6 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr, BOOT_LOG_ERR( "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); - goto out; } @@ -794,7 +941,6 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr, "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); rc = BOOT_EFLASH; - goto out; } @@ -823,13 +969,33 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl uint32_t unprotected_tlv_size = 0; uint32_t tlv_write_size = 0; uint32_t decompressed_image_size; - struct nrf_compress_implementation *compression = NULL; + struct nrf_compress_implementation *compression_lzma = NULL; + struct nrf_compress_implementation *compression_arm_thumb = NULL; struct image_header *hdr; - TARGET_STATIC uint8_t decomp_buf[CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE] __attribute__((aligned(4))); + TARGET_STATIC uint8_t decomp_buf[DECOMP_BUF_ALLOC_SIZE] __attribute__((aligned(4))); TARGET_STATIC struct image_header modified_hdr; +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + uint8_t excess_data_buffer[DECOMP_BUF_EXTRA_SIZE]; + bool excess_data_buffer_full = false; +#endif + +#ifdef MCUBOOT_ENC_IMAGES + uint32_t comp_size = 0; +#endif + hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); +#ifdef MCUBOOT_ENC_IMAGES + rc = bootutil_get_img_decrypted_comp_size(hdr, fap_src, &comp_size); + + if (rc) { + BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); + rc = BOOT_EBADIMAGE; + goto finish; + } +#endif + /* Setup decompression system */ #if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { @@ -841,27 +1007,26 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl */ BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); rc = BOOT_EBADIMAGE; - goto finish; } - compression = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); - if (compression == NULL || compression->init == NULL || compression->deinit == NULL || - compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { + if (!is_compression_object_valid(compression_lzma) || + !is_compression_object_valid(compression_arm_thumb)) { /* Compression library missing or missing required function pointer */ BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; - goto finish; } - rc = compression->init(NULL); + rc = compression_lzma->init(NULL); + rc = compression_arm_thumb->init(NULL); if (rc) { BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; - goto finish; } @@ -874,7 +1039,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish; } @@ -887,7 +1051,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish; } @@ -898,7 +1061,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine unprotected TLV size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish; } @@ -909,13 +1071,17 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", off_dst, sizeof(modified_hdr), fap_dst->fa_id, rc); rc = BOOT_EFLASH; - goto finish; } /* Read in, decompress and write out data */ +#ifdef MCUBOOT_ENC_IMAGES + while (pos < comp_size) { + uint32_t copy_size = comp_size - pos; +#else while (pos < hdr->ih_img_size) { uint32_t copy_size = hdr->ih_img_size - pos; +#endif uint32_t tmp_off = 0; if (copy_size > buf_size) { @@ -928,10 +1094,15 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", (off_src + hdr->ih_hdr_size + pos), copy_size, fap_src->fa_id, rc); rc = BOOT_EFLASH; - goto finish; } +#ifdef MCUBOOT_ENC_IMAGES + if (IS_ENCRYPTED(hdr)) { + boot_enc_decrypt(BOOT_CURR_ENC(state), 1, pos, copy_size, (pos & 0xf), buf); + } +#endif + /* Decompress data in chunks, writing it back with a larger write offset of the primary * slot than read size of the secondary slot */ @@ -943,57 +1114,156 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl uint8_t *output = NULL; bool last_packet = false; - chunk_size = compression->decompress_bytes_needed(NULL); + chunk_size = compression_lzma->decompress_bytes_needed(NULL); if (chunk_size > (copy_size - tmp_off)) { chunk_size = (copy_size - tmp_off); } +#ifdef MCUBOOT_ENC_IMAGES + if ((pos + tmp_off + chunk_size) >= comp_size) { +#else if ((pos + tmp_off + chunk_size) >= hdr->ih_img_size) { +#endif last_packet = true; } - rc = compression->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, &offset, - &output, &output_size); + rc = compression_lzma->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, + &offset, &output, &output_size); if (rc) { BOOT_LOG_ERR("Decompression error: %d", rc); rc = BOOT_EBADSTATUS; - goto finish; } /* Copy data to secondary buffer for writing out */ while (output_size > 0) { - uint32_t data_size = (sizeof(decomp_buf) - decomp_buf_size); + uint32_t data_size = (DECOMP_BUF_SIZE - decomp_buf_size); if (data_size > output_size) { data_size = output_size; } - memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], data_size); +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { + memcpy(&decomp_buf[decomp_buf_size + DECOMP_BUF_EXTRA_SIZE], + &output[compression_buffer_pos], data_size); + } else +#endif + { + memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], + data_size); + } + compression_buffer_pos += data_size; decomp_buf_size += data_size; output_size -= data_size; /* Write data out from secondary buffer when it is full */ - if (decomp_buf_size == sizeof(decomp_buf)) { - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), - decomp_buf, sizeof(decomp_buf)); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), sizeof(decomp_buf), - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - - goto finish; + if (decomp_buf_size == DECOMP_BUF_SIZE) { +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { + uint32_t filter_writeback_pos = 0; + uint32_t processed_size = 0; + + /* Run this through the ARM thumb filter */ + while (processed_size < DECOMP_BUF_SIZE) { + uint32_t offset_arm_thumb = 0; + uint32_t output_size_arm_thumb = 0; + uint8_t *output_arm_thumb = NULL; + uint32_t current_size = DECOMP_BUF_SIZE; + bool arm_thumb_last_packet = false; + + if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { + current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; + } + + if (last_packet && (processed_size + current_size) == DECOMP_BUF_SIZE + && output_size == 0) { + arm_thumb_last_packet = true; + } + + rc = compression_arm_thumb->decompress(NULL, + &decomp_buf[processed_size + + DECOMP_BUF_EXTRA_SIZE], + current_size, + arm_thumb_last_packet, + &offset_arm_thumb, + &output_arm_thumb, + &output_size_arm_thumb); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + goto finish; + } + + memcpy(&decomp_buf[filter_writeback_pos], output_arm_thumb, + output_size_arm_thumb); + filter_writeback_pos += output_size_arm_thumb; + processed_size += current_size; + } + + if (excess_data_buffer_full == true) + { + /* Restore extra data removed from previous iteration to the write + * buffer + */ + memmove(&decomp_buf[DECOMP_BUF_EXTRA_SIZE], decomp_buf, + filter_writeback_pos); + memcpy(decomp_buf, excess_data_buffer, DECOMP_BUF_EXTRA_SIZE); + excess_data_buffer_full = false; + filter_writeback_pos += DECOMP_BUF_EXTRA_SIZE; + } + + if ((filter_writeback_pos % sizeof(uint32_t)) != 0) + { + /* Since there are an extra 2 bytes here, remove them and stash for + * later usage to prevent flash write issues with non-word boundary + * writes + */ + memcpy(excess_data_buffer, &decomp_buf[filter_writeback_pos - + DECOMP_BUF_EXTRA_SIZE], + DECOMP_BUF_EXTRA_SIZE); + excess_data_buffer_full = true; + filter_writeback_pos -= DECOMP_BUF_EXTRA_SIZE; + } + + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), + decomp_buf, filter_writeback_pos); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), DECOMP_BUF_SIZE, + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + + write_pos += filter_writeback_pos; + decomp_buf_size = 0; + filter_writeback_pos = 0; + } else +#endif + { + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), + decomp_buf, DECOMP_BUF_SIZE); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), DECOMP_BUF_SIZE, + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + + write_pos += DECOMP_BUF_SIZE; + decomp_buf_size = 0; } - - write_pos += sizeof(decomp_buf); - decomp_buf_size = 0; } } @@ -1003,8 +1273,30 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl pos += copy_size; } +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT && decomp_buf_size > 0) { + /* Extra data that has not been written out that needs ARM thumb filter applied */ + uint32_t offset_arm_thumb = 0; + uint32_t output_size_arm_thumb = 0; + uint8_t *output_arm_thumb = NULL; + + rc = compression_arm_thumb->decompress(NULL, &decomp_buf[DECOMP_BUF_EXTRA_SIZE], + decomp_buf_size, true, &offset_arm_thumb, + &output_arm_thumb, &output_size_arm_thumb); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + goto finish; + } + + memcpy(decomp_buf, output_arm_thumb, output_size_arm_thumb); + } +#endif + /* Clean up decompression system */ - (void)compression->deinit(NULL); + (void)compression_lzma->deinit(NULL); + (void)compression_arm_thumb->deinit(NULL); if (protected_tlv_size > 0) { rc = boot_copy_protected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + @@ -1014,7 +1306,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); - goto finish; } @@ -1029,7 +1320,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); - goto finish; } @@ -1040,7 +1330,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl uint32_t write_padding_size = write_alignment - (decomp_buf_size % write_alignment); /* Check if additional write padding should be applied to meet the minimum write size */ - if (write_padding_size) { + if (write_alignment > 1 && write_padding_size) { uint8_t flash_erased_value; flash_erased_value = flash_area_erased_val(fap_dst); @@ -1056,7 +1346,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_size, fap_dst->fa_id, rc); rc = BOOT_EFLASH; - goto finish; } @@ -1098,7 +1387,6 @@ int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct fl if (len != sizeof(*img_decomp_size)) { BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); - return BOOT_EBADIMAGE; } @@ -1107,7 +1395,6 @@ int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct fl if (rc) { BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", off, len, fap->fa_id, rc); - return BOOT_EFLASH; } From dea42cb3c9cf0786fcba68495849ff12571ac0d7 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 17 Oct 2024 19:38:39 +0000 Subject: [PATCH 39/44] [nrf noup] Remove setting default MCUboot mbedTLS config This has been overriding logic that selects nrf-config.h when CONFIG_NRF_SECURITY=y. Signed-off-by: Dominik Ermel (cherry picked from commit ea00c047de0adbadc7162b945bfb139136f434cb) (cherry picked from commit 62929e493c6feb75fc83378d7235280e14a745cc) --- boot/zephyr/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index e4f7d9030..9ff1ba274 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -1,7 +1,6 @@ CONFIG_PM=n CONFIG_MAIN_STACK_SIZE=10240 -CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" CONFIG_BOOT_SWAP_SAVE_ENCTLV=n CONFIG_BOOT_ENCRYPT_IMAGE=n From bb7a99cc9119ff50ce3f894f4ee710d82931b66f Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 20 Sep 2024 16:34:00 +0000 Subject: [PATCH 40/44] [nrf noup] bootutil: Add support for KMU stored ED25519 signature key The commit adds verification of image using keys stored in KMU. Signed-off-by: Dominik Ermel (cherry picked from commit 6e0c2b8794daa33d7688b35fc4af04c4d8052d41) (cherry picked from commit b647a94a24b1a20b3cbbde41ff9a4a92be67a232) --- boot/bootutil/src/ed25519_psa.c | 51 ++++++++++++++++++++++++++++++ boot/bootutil/src/image_ed25519.c | 9 +++++- boot/bootutil/src/image_validate.c | 12 +++++-- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/Kconfig | 26 +++++++++++++++ 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 12ba20ac1..b6153f9a4 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -12,6 +12,9 @@ #include #include +#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#include +#endif BOOT_LOG_MODULE_REGISTER(ed25519_psa); @@ -19,6 +22,18 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #define EDDSA_KEY_LENGTH 32 #define EDDSA_SIGNAGURE_LENGTH 64 +#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +/* List of KMU stored key ids available for MCUboot */ +#define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) +static psa_key_id_t kmu_key_ids[3] = { + MAKE_PSA_KMU_KEY_ID(226), + MAKE_PSA_KMU_KEY_ID(228), + MAKE_PSA_KMU_KEY_ID(230) +}; +#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) +#endif + +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], const uint8_t public_key[EDDSA_KEY_LENGTH]) @@ -69,3 +84,39 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return ret; } +#else +int ED25519_verify(const uint8_t *message, size_t message_len, + const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], + const uint8_t public_key[EDDSA_KEY_LENGTH]) +{ + ARG_UNUSED(public_key); + /* Set to any error */ + psa_status_t status = PSA_ERROR_BAD_STATE; + int ret = 0; /* Fail by default */ + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d", status); + return 0; + } + + status = PSA_ERROR_BAD_STATE; + + for (int i = 0; i < KMU_KEY_COUNT; ++i) { + psa_key_id_t kid = kmu_key_ids[i]; + + status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, + message_len, signature, + EDDSA_SIGNAGURE_LENGTH); + if (status == PSA_SUCCESS) { + ret = 1; + break; + } + + BOOT_LOG_ERR("ED25519 signature verification failed %d", status); + } + + return ret; +} +#endif diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index ffb8cec3b..d5aee65bc 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -31,6 +31,7 @@ extern int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNATURE_LENGTH], const uint8_t public_key[NUM_ED25519_BYTES]); +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) /* * Parse the public key used for signing. @@ -73,6 +74,7 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } #endif /* !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) */ +#endif /* Signature verification base function. * The function takes buffer of specified length and tries to verify @@ -87,14 +89,17 @@ bootutil_verify(uint8_t *buf, uint32_t blen, { int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); - uint8_t *pubkey; + uint8_t *pubkey = NULL; +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) uint8_t *end; +#endif if (slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; @@ -116,6 +121,8 @@ bootutil_verify(uint8_t *buf, uint32_t blen, } pubkey = end - NUM_ED25519_BYTES; +#endif + #endif rc = ED25519_verify(buf, blen, sig, pubkey); diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 08f354be8..6f1cbc568 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -245,6 +245,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, # define KEY_BUF_SIZE (SIG_BUF_SIZE + 24) #endif /* !MCUBOOT_HW_KEY */ +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #if !defined(MCUBOOT_HW_KEY) static int bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) @@ -310,6 +311,7 @@ bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) } #endif /* !MCUBOOT_HW_KEY */ #endif /* !MCUBOOT_BUILTIN_KEY */ +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #endif /* EXPECTED_SIG_TLV */ /** @@ -627,6 +629,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, break; } #endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */ +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #ifdef EXPECTED_KEY_TLV case EXPECTED_KEY_TLV: { @@ -657,14 +660,17 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, break; } #endif /* EXPECTED_KEY_TLV */ +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #ifdef EXPECTED_SIG_TLV case EXPECTED_SIG_TLV: { +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; goto out; @@ -810,7 +816,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } #ifdef EXPECTED_SIG_TLV -#ifdef EXPECTED_KEY_TLV +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && defined(EXPECTED_KEY_TLV) rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); if (rc) { goto out; @@ -856,7 +862,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, */ } } -#endif /* EXPECTED_KEY_TLV */ +#endif /* !CONFIG_BOOT_SIGNATURE_USING_KMU && EXPECTED_KEY_TLV */ rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); if (rc) { @@ -879,10 +885,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Ignore this signature if it is out of bounds. */ +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } +#endif if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index a9a761a4d..537a7580c 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -315,7 +315,7 @@ if(CONFIG_MCUBOOT_SERIAL) endif() endif() -if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") +if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") # CONF_FILE points to the KConfig configuration files of the bootloader. foreach (filepath ${CONF_FILE}) file(READ ${filepath} temp_text) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 72eb8031b..a9289ccbd 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -331,6 +331,22 @@ endif endchoice +config BOOT_SIGNATURE_USING_KMU + bool "Use KMU stored keys for signature verification" + depends on NRF_SECURITY + depends on CRACEN_LIB_KMU + select PSA_WANT_ALG_GCM + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_AES_KEY_SIZE_256 + select PSA_WANT_ALG_SP800_108_COUNTER_CMAC + select PSA_WANT_ALG_CMAC + select PSA_WANT_ALG_ECB_NO_PADDING + help + MCUboot will use keys provisioned to the device key management unit for signature + verification instead of compiling in key data from a file. + +if !BOOT_SIGNATURE_USING_KMU + config BOOT_SIGNATURE_KEY_FILE string "PEM key file" default "root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 @@ -348,6 +364,8 @@ config BOOT_SIGNATURE_KEY_FILE with the public key information will be written in a format expected by MCUboot. +endif + config MCUBOOT_CLEANUP_ARM_CORE bool "Perform core cleanup before chain-load the application" depends on CPU_CORTEX_M @@ -370,6 +388,14 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. +# Disable MBEDTLS from being selected if NRF_SECURITY is enabled, and use default NRF_SECURITY +# configuration file for MBEDTLS +config MBEDTLS + depends on !NRF_SECURITY + +config NRF_SECURITY + select MBEDTLS_PROMPTLESS + if MBEDTLS || NRF_SECURITY config MBEDTLS_CFG_FILE From 672f5cfe7b150ee0600bafb1c4e4e2f8500209e3 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Nov 2024 10:53:06 +0000 Subject: [PATCH 41/44] [nrf noup] boot: zephyr: Add experimental selection to compression Adds selecting the experimental Kconfig when compession is in use Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit ff3c31fba7e8eb659d8505e9c635057a2ca53987) (cherry picked from commit 4ceb4773b31dd8d56dfcb6e0461a70bb161ca95f) --- boot/zephyr/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a9289ccbd..6af784f9a 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1000,9 +1000,10 @@ config BOOT_DECOMPRESSION_SUPPORT if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION - bool "Decompression" + bool "Decompression [EXPERIMENTAL]" select NRF_COMPRESS_CLEANUP select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP + select EXPERIMENTAL help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to From 810ee4e6de956e28eca5fea02b2308aa7711010a Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 2 Dec 2024 10:51:41 +0000 Subject: [PATCH 42/44] [nrf noup] boot: bootutil: Allow configuring number of KMU keys Adds a new Kconfig CONFIG_BOOT_SIGNATURE_KMU_SLOTS which allows specifying how many KMU key IDs are supported, the default is set to 1 instead of 3 which was set before NCSDK-30743 Signed-off-by: Jamie McCrae (cherry picked from commit 12e5ee106034972b0f1074d6f2261b2b39d1501b) (cherry picked from commit 2ca0efedf8d331028455f05d77f1c3c5064b773b) --- boot/bootutil/src/ed25519_psa.c | 7 +++++-- boot/zephyr/Kconfig | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index b6153f9a4..3e9cf2cbd 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -12,6 +12,7 @@ #include #include +#include #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #include #endif @@ -30,7 +31,9 @@ static psa_key_id_t kmu_key_ids[3] = { MAKE_PSA_KMU_KEY_ID(228), MAKE_PSA_KMU_KEY_ID(230) }; -#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) + +BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), + "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); #endif #if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) @@ -103,7 +106,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len, status = PSA_ERROR_BAD_STATE; - for (int i = 0; i < KMU_KEY_COUNT; ++i) { + for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { psa_key_id_t kid = kmu_key_ids[i]; status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 6af784f9a..99b946926 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -345,6 +345,18 @@ config BOOT_SIGNATURE_USING_KMU MCUboot will use keys provisioned to the device key management unit for signature verification instead of compiling in key data from a file. +if BOOT_SIGNATURE_USING_KMU + +config BOOT_SIGNATURE_KMU_SLOTS + int "KMU key slots" + range 1 3 + default 1 + help + Selects the number of KMU key slots (also known as generations) to use when verifying + an image. + +endif + if !BOOT_SIGNATURE_USING_KMU config BOOT_SIGNATURE_KEY_FILE From 0654e03a7ccb16d937f1562b8ff9f9eb311d7573 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 9 Jan 2025 11:09:49 +0000 Subject: [PATCH 43/44] [nrf fromtree] boot: bootutil: Add TLV for size of compressed but decrypted image This TLV is needed in order to know what the data length provided to the decompression system is to remove the padding that is a resultant of the encryption block size Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 4bda587549c0fccd5cd9b59d76c8edf061ee84c3) (cherry picked from commit bc8d277df74908cd52f24fd9a3744f225f21169e) --- boot/bootutil/include/bootutil/image.h | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 05e04438b..92adc605b 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -124,6 +124,7 @@ struct flash_area; * the format and size of the raw slot (compressed) * signature */ +#define IMAGE_TLV_COMP_DEC_SIZE 0x73 /* Compressed decrypted image size */ /* * vendor reserved TLVs at xxA0-xxFF, * where xx denotes the upper byte From ea76eeb812c16c5bab0475b08863379738295205 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 14 Mar 2025 17:51:23 +0000 Subject: [PATCH 44/44] [nrf noup] zephyr: Use mbedTLS specific C functions with RSA Use snprinf, alloc, calloc and free from mbedTLS rather than from Zephyr. Signed-off-by: Dominik Ermel --- boot/zephyr/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 99b946926..a2614917b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -223,6 +223,8 @@ config BOOT_SIGNATURE_TYPE_RSA select MBEDTLS select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN select MBEDTLS_KEY_EXCHANGE_RSA_ENABLED if MBEDTLS_BUILTIN + select MBEDTLS_PLATFORM_NO_STD_FUNCTIONS if MBEDTLS_BUILTIN + select MBEDTLS_PLATFORM_SNPRINTF_ALT if MBEDTLS_BUILTIN select BOOT_ENCRYPTION_SUPPORT select BOOT_IMG_HASH_ALG_SHA256_ALLOW select BOOT_AES_MBEDTLS_DEPENDENCIES if MBEDTLS_BUILTIN && BOOT_ENCRYPT_IMAGE