/* * SPDX-License-Identifier: Apache-2.0 * * Copyright (c) 2017-2019 Linaro LTD * Copyright (c) 2016-2019 JUUL Labs * Copyright (c) 2019-2024 Arm Limited * * Original license: * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include "bootutil/image.h" #include "bootutil/crypto/sha.h" #include "bootutil/sign_key.h" #include "bootutil/security_cnt.h" #include "bootutil/fault_injection_hardening.h" #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 #if defined(MCUBOOT_SIGN_RSA) #include "mbedtls/rsa.h" #endif #if defined(MCUBOOT_SIGN_EC256) #include "mbedtls/ecdsa.h" #endif #if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SIGN_RSA) || \ defined(MCUBOOT_SIGN_EC256) #include "mbedtls/asn1.h" #endif #include "bootutil_priv.h" #ifndef MCUBOOT_SIGN_PURE /* * Compute SHA hash over the image. * (SHA384 if ECDSA-P384 is being used, * SHA256 otherwise). */ static int bootutil_img_hash(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) { bootutil_sha_context sha_ctx; uint32_t size; uint16_t hdr_size; 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) (void)enc_state; (void)image_index; (void)hdr_size; (void)blk_off; (void)tlv_off; #ifdef MCUBOOT_RAM_LOAD (void)blk_sz; (void)off; (void)rc; (void)fap; (void)tmp_buf; (void)tmp_buf_sz; #endif #endif #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 bootutil_sha_init(&sha_ctx); /* in some cases (split image) the hash is seeded with data from * the loader image */ if (seed && (seed_len > 0)) { bootutil_sha_update(&sha_ctx, seed, seed_len); } /* Hash is computed over image header and image itself. */ size = hdr_size = hdr->ih_hdr_size; size += hdr->ih_img_size; tlv_off = size; /* 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), size); #else for (off = 0; off < size; off += blk_sz) { blk_sz = size - off; if (blk_sz > tmp_buf_sz) { blk_sz = tmp_buf_sz; } #ifdef MCUBOOT_ENC_IMAGES /* The only data that is encrypted in an image is the payload; * both header and TLVs (when protected) are not. */ if ((off < hdr_size) && ((off + blk_sz) > hdr_size)) { /* read only the header */ blk_sz = hdr_size - off; } if ((off < tlv_off) && ((off + blk_sz) > tlv_off)) { /* read only up to the end of the image payload */ blk_sz = tlv_off - off; } #endif rc = flash_area_read(fap, off, tmp_buf, blk_sz); if (rc) { bootutil_sha_drop(&sha_ctx); return rc; } #ifdef MCUBOOT_ENC_IMAGES if (MUST_DECRYPT(fap, image_index, hdr)) { /* Only payload is encrypted (area between header and TLVs) */ int slot = flash_area_id_to_multi_image_slot(image_index, flash_area_get_id(fap)); if (off >= hdr_size && off < tlv_off) { blk_off = (off - hdr_size) & 0xf; boot_enc_decrypt(enc_state, slot, off - hdr_size, blk_sz, blk_off, tmp_buf); } } #endif 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); return 0; } #endif /* * Currently, we only support being able to verify one type of * signature, because there is a single verification function that we * call. List the type of TLV we are expecting. If we aren't * configured for any signature, don't define this macro. */ #if (defined(MCUBOOT_SIGN_RSA) + \ defined(MCUBOOT_SIGN_EC256) + \ defined(MCUBOOT_SIGN_EC384) + \ defined(MCUBOOT_SIGN_ED25519)) > 1 #error "Only a single signature type is supported!" #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 # else # error "Unsupported RSA signature length" # endif # define SIG_BUF_SIZE (MCUBOOT_SIGN_RSA_LEN / 8) # define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE) /* 2048 bits */ #elif defined(MCUBOOT_SIGN_EC256) || \ defined(MCUBOOT_SIGN_EC384) || \ defined(MCUBOOT_SIGN_EC) # define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG # define SIG_BUF_SIZE 128 # define EXPECTED_SIG_LEN(x) (1) /* always true, ASN.1 will validate */ #elif defined(MCUBOOT_SIGN_ED25519) # define EXPECTED_SIG_TLV IMAGE_TLV_ED25519 # define SIG_BUF_SIZE 64 # define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE) #else # define SIG_BUF_SIZE 32 /* no signing, sha256 digest only */ #endif #if (defined(MCUBOOT_HW_KEY) + \ defined(MCUBOOT_BUILTIN_KEY)) > 1 #error "Please use either MCUBOOT_HW_KEY or the MCUBOOT_BUILTIN_KEY feature." #endif #ifdef EXPECTED_SIG_TLV #if !defined(MCUBOOT_BUILTIN_KEY) #if !defined(MCUBOOT_HW_KEY) /* The key TLV contains the hash of the public key. */ # define EXPECTED_KEY_TLV IMAGE_TLV_KEYHASH # define KEY_BUF_SIZE IMAGE_HASH_SIZE #else /* The key TLV contains the whole public key. * Add a few extra bytes to the key buffer size for encoding and * for public exponent. */ # define EXPECTED_KEY_TLV IMAGE_TLV_PUBKEY # 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) { bootutil_sha_context sha_ctx; int i; const struct bootutil_key *key; uint8_t hash[IMAGE_HASH_SIZE]; if (keyhash_len > IMAGE_HASH_SIZE) { return -1; } for (i = 0; i < bootutil_key_cnt; i++) { key = &bootutil_keys[i]; bootutil_sha_init(&sha_ctx); bootutil_sha_update(&sha_ctx, key->key, *key->len); bootutil_sha_finish(&sha_ctx, hash); if (!memcmp(hash, keyhash, keyhash_len)) { bootutil_sha_drop(&sha_ctx); return i; } } bootutil_sha_drop(&sha_ctx); return -1; } #else /* !MCUBOOT_HW_KEY */ extern unsigned int pub_key_len; static int bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) { bootutil_sha_context sha_ctx; uint8_t hash[IMAGE_HASH_SIZE]; uint8_t key_hash[IMAGE_HASH_SIZE]; size_t key_hash_size = sizeof(key_hash); int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); bootutil_sha_init(&sha_ctx); bootutil_sha_update(&sha_ctx, key, key_len); bootutil_sha_finish(&sha_ctx, hash); bootutil_sha_drop(&sha_ctx); rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size); if (rc) { return -1; } /* Adding hardening to avoid this potential attack: * - Image is signed with an arbitrary key and the corresponding public * key is added as a TLV field. * - During public key validation (comparing against key-hash read from * HW) a fault is injected to accept the public key as valid one. */ FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size); if (FIH_EQ(fih_rc, FIH_SUCCESS)) { bootutil_keys[0].key = key; pub_key_len = key_len; return 0; } return -1; } #endif /* !MCUBOOT_HW_KEY */ #endif /* !MCUBOOT_BUILTIN_KEY */ #endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #endif /* EXPECTED_SIG_TLV */ /** * Reads the value of an image's security counter. * * @param hdr Pointer to the image header structure. * @param fap Pointer to a description structure of the image's * flash area. * @param security_cnt Pointer to store the security counter value. * * @return 0 on success; nonzero on failure. */ int32_t bootutil_get_img_security_cnt(struct image_header *hdr, const struct flash_area *fap, uint32_t *img_security_cnt) { struct image_tlv_iter it; uint32_t off; uint16_t len; int32_t rc; if ((hdr == NULL) || (fap == NULL) || (img_security_cnt == NULL)) { /* Invalid parameter. */ return BOOT_EBADARGS; } /* The security counter TLV is in the protected part of the TLV area. */ if (hdr->ih_protect_tlv_size == 0) { return BOOT_EBADIMAGE; } rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SEC_CNT, true); if (rc) { return rc; } /* Traverse through the protected TLV area to find * the security counter TLV. */ rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); if (rc != 0) { /* Security counter TLV has not been found. */ return -1; } if (len != sizeof(*img_security_cnt)) { /* Security counter is not valid. */ return BOOT_EBADIMAGE; } rc = LOAD_IMAGE_DATA(hdr, fap, off, img_security_cnt, len); if (rc != 0) { return BOOT_EFLASH; } 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 * TLV section. All other TLV entries must be in the protected section. */ static const uint16_t allowed_unprot_tlvs[] = { IMAGE_TLV_KEYHASH, IMAGE_TLV_PUBKEY, IMAGE_TLV_SHA256, IMAGE_TLV_SHA384, IMAGE_TLV_SHA512, IMAGE_TLV_RSA2048_PSS, IMAGE_TLV_ECDSA224, 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, IMAGE_TLV_ENC_X25519, /* Mark end with ANY. */ IMAGE_TLV_ANY, }; #endif /* * Verify the integrity of the image. * Return non-zero if image could not be validated/does not validate. */ fih_ret bootutil_img_validate(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 *seed, int seed_len, uint8_t *out_hash) { uint32_t off; uint16_t len; uint16_t type; #ifdef EXPECTED_SIG_TLV FIH_DECLARE(valid_signature, FIH_FAILURE); #ifndef MCUBOOT_BUILTIN_KEY int key_id = -1; #else /* Pass a key ID equal to the image index, the underlying crypto library * is responsible for mapping the image index to a builtin key ID. */ int key_id = image_index; #endif /* !MCUBOOT_BUILTIN_KEY */ #ifdef MCUBOOT_HW_KEY uint8_t key_buf[KEY_BUF_SIZE]; #endif #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 fih_int security_cnt = fih_int_encode(INT_MAX); uint32_t img_security_cnt = 0; 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); if (rc) { goto out; } 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) { goto out; } if (it.tlv_end > bootutil_max_image_size(fap)) { rc = -1; goto out; } /* * Traverse through all of the TLVs, performing any checks we know * and are able to do. */ while (true) { rc = bootutil_tlv_iter_next(&it, &off, &len, &type); if (rc < 0) { goto out; } else if (rc > 0) { break; } #ifndef ALLOW_ROGUE_TLVS /* * Ensure that the non-protected TLV only has entries necessary to hold * the signature. We also allow encryption related keys to be in the * unprotected area. */ if (!bootutil_tlv_iter_is_prot(&it, off)) { bool found = false; for (const uint16_t *p = allowed_unprot_tlvs; *p != IMAGE_TLV_ANY; p++) { if (type == *p) { found = true; break; } } if (!found) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } } #endif 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; 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; 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: { /* * 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. */ 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; } rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); 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: { /* * Verify the image's security counter. * This must always be present. */ if (len != sizeof(img_security_cnt)) { /* Security counter is not valid. */ rc = -1; goto out; } rc = LOAD_IMAGE_DATA(hdr, fap, off, &img_security_cnt, len); if (rc) { goto out; } FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index, &security_cnt); if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } /* Compare the new image's security counter value against the * stored security counter value. */ fih_rc = fih_ret_encode_zero_equality(img_security_cnt < (uint32_t)fih_int_decode(security_cnt)); if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } /* 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 #ifdef MCUBOOT_HW_ROLLBACK_PROT if (FIH_NOT_EQ(security_counter_valid, FIH_SUCCESS)) { rc = -1; goto out; } #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); } FIH_RET(fih_rc); }