Skip to content

bootutil: (refactor) split image_validate.c into separate files #2383

New issue

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

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

Already on GitHub? Sign in to your account

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions boot/bootutil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ target_include_directories(bootutil
target_sources(bootutil
PRIVATE
src/boot_record.c
src/bootutil_find_key.c
src/bootutil_img_hash.c
src/bootutil_img_security_cnt.c
src/bootutil_misc.c
src/bootutil_public.c
src/caps.c
Expand Down
15 changes: 15 additions & 0 deletions boot/bootutil/include/bootutil/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,21 @@ int32_t bootutil_get_img_security_cnt(struct boot_loader_state *state, int slot,
const struct flash_area *fap,
uint32_t *img_security_cnt);

#if !defined(MCUBOOT_HW_KEY)
int bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len);
#else
int bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len);
#endif

int bootutil_img_hash(struct boot_loader_state *state,
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
#if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY)
, uint32_t start_offset
#endif
);

#ifdef __cplusplus
}
#endif
Expand Down
132 changes: 132 additions & 0 deletions boot/bootutil/src/bootutil_find_key.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2025 Arm Limited
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* 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 <stdint.h>

#include "bootutil/crypto/sha.h"
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/image.h"
#include "bootutil/sign_key.h"
#include "bootutil_priv.h"
#include "mcuboot_config/mcuboot_config.h"
#include "bootutil/bootutil_log.h"

BOOT_LOG_MODULE_DECLARE(mcuboot);

#if defined(MCUBOOT_SIGN_RSA) || \
defined(MCUBOOT_SIGN_EC256) || \
defined(MCUBOOT_SIGN_EC384) || \
defined(MCUBOOT_SIGN_EC) || \
defined(MCUBOOT_SIGN_ED25519)
#define EXPECTED_SIG_TLV
#else
/* no signing, sha256 digest only */
#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(MCUBOOT_HW_KEY)
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];

BOOT_LOG_DBG("bootutil_find_key");

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);
bootutil_sha_drop(&sha_ctx);
if (!memcmp(hash, keyhash, keyhash_len)) {
return i;
}
}
return -1;
}
#else /* !MCUBOOT_HW_KEY */
extern unsigned int pub_key_len;
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);

BOOT_LOG_DBG("bootutil_find_key: image_index %d", image_index);

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 /* EXPECTED_SIG_TLV */
200 changes: 200 additions & 0 deletions boot/bootutil/src/bootutil_img_hash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2025 Arm Limited
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* 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 <stdint.h>
#include <flash_map_backend/flash_map_backend.h>

#include "bootutil/crypto/sha.h"
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/image.h"
#include "bootutil_priv.h"
#include "mcuboot_config/mcuboot_config.h"
#include "bootutil/bootutil_log.h"

BOOT_LOG_MODULE_DECLARE(mcuboot);

#ifndef MCUBOOT_SIGN_PURE
/*
* Compute SHA hash over the image.
* (SHA384 if ECDSA-P384 is being used,
* SHA256 otherwise).
*/
int
bootutil_img_hash(struct boot_loader_state *state,
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
#ifdef MCUBOOT_HASH_STORAGE_DIRECTLY
uintptr_t base = 0;
int fa_ret;
#endif
#if defined(MCUBOOT_ENC_IMAGES)
struct enc_key_data *enc_state;
int image_index;
#endif
#if defined(MCUBOOT_SWAP_USING_OFFSET)
uint32_t sector_off = 0;
#endif

#if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \
defined(MCUBOOT_RAM_LOAD)
(void)state;
(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
BOOT_LOG_DBG("bootutil_img_hash");

#ifdef MCUBOOT_ENC_IMAGES
if (state == NULL) {
enc_state = NULL;
image_index = 0;
} else {
enc_state = BOOT_CURR_ENC(state);
image_index = BOOT_CURR_IMG(state);
}

/* Encrypted images only exist in the secondary slot */
if (MUST_DECRYPT(fap, image_index, hdr) &&
!boot_enc_valid(enc_state, 1)) {
BOOT_LOG_DBG("bootutil_img_hash: error encrypted image found in primary slot");
return -1;
}
#endif

#if defined(MCUBOOT_SWAP_USING_OFFSET)
/* For swap using offset mode, the image starts in the second sector of the upgrade slot, so
* apply the offset when this is needed
*/
sector_off = boot_get_state_secondary_offset(state, fap);
#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.
*/
fa_ret = flash_device_base(flash_area_get_device_id(fap), &base);
if (fa_ret != 0) {
base = 0;
}

bootutil_sha_update(&sha_ctx, (void *)(base + 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
#if defined(MCUBOOT_SWAP_USING_OFFSET)
rc = flash_area_read(fap, off + sector_off, tmp_buf, blk_sz);
#else
rc = flash_area_read(fap, off, tmp_buf, blk_sz);
#endif
if (rc) {
bootutil_sha_drop(&sha_ctx);
BOOT_LOG_DBG("bootutil_img_validate Error %d reading data chunk %p %u %u",
rc, fap, off, blk_sz);
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 /* !MCUBOOT_SIGN_PURE */
Loading
Loading