Skip to content
Draft
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
21 changes: 21 additions & 0 deletions boot/bootutil/include/bootutil/boot_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@

#endif /* MCUBOOT_FIND_NEXT_SLOT_HOOKS */

#ifdef MCUBOOT_LOAD_AND_VALIDATE_IMAGES_HOOKS

#define BOOT_HOOK_LOAD_AND_VALIDATE_IMAGES_CALL_FIH(f, fih_ret_default, fih_rc, ...) \
DO_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, __VA_ARGS__);

#else

#define BOOT_HOOK_LOAD_AND_VALIDATE_IMAGES_CALL_FIH(f, fih_ret_default, fih_rc, ...) \
HOOK_CALL_FIH_NOP(f, fih_ret_default, fih_rc, __VA_ARGS__)

#endif /* MCUBOOT_LOAD_AND_VALIDATE_IMAGES_HOOKS */

#ifdef MCUBOOT_FLASH_AREA_HOOKS

#define BOOT_HOOK_FLASH_AREA_CALL(f, ret_default, ...) \
Expand Down Expand Up @@ -284,4 +296,13 @@ int flash_area_get_device_id_hook(const struct flash_area *fa,
*/
int boot_find_next_slot_hook(struct boot_loader_state *state, uint8_t image, enum boot_slot *active_slot);

/**
* Tries to load a slot for all the images with validation.
*
* @param state Boot loader status information.
*
* @return 0 on success; nonzero on failure.
*/
fih_ret boot_load_and_validate_images_hook(struct boot_loader_state *state);

#endif /*H_BOOTUTIL_HOOKS*/
1 change: 1 addition & 0 deletions boot/bootutil/include/bootutil/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ extern "C" {
#define IMAGE_TLV_COMP_DEC_SIZE 0x73 /* Compressed decrypted image size */
#define IMAGE_TLV_UUID_VID 0x74 /* Vendor unique identifier */
#define IMAGE_TLV_UUID_CID 0x75 /* Device class unique identifier */
#define IMAGE_TLV_MANIFEST 0x76 /* Transaction manifest */
/*
* vendor reserved TLVs at xxA0-xxFF,
* where xx denotes the upper byte
Expand Down
96 changes: 96 additions & 0 deletions boot/bootutil/include/bootutil/mcuboot_manifest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __MCUBOOT_MANIFEST_H__
#define __MCUBOOT_MANIFEST_H__

/**
* @file mcuboot_manifest.h
*
* @note This file is only used when MCUBOOT_MANIFEST_UPDATES is enabled.
*/

#include <stdint.h>
#include "bootutil/bootutil.h"
#include "bootutil/crypto/sha.h"

#ifndef __packed
#define __packed __attribute__((__packed__))
#endif

#ifdef __cplusplus
extern "C" {
#endif

/** Manifest structure for image updates. */
struct mcuboot_manifest {
uint32_t format;
uint32_t image_count;
/* Skip a digest of the MCUBOOT_MANIFEST_IMAGE_NUMBER image. */
uint8_t image_hash[BOOT_IMAGE_NUMBER - 1][IMAGE_HASH_SIZE];
} __packed;

/**
* @brief Check if the specified manifest has the correct format.
*
* @param[in] manifest The reference to the manifest structure.
*
* @return true on success.
*/
static inline bool bootutil_verify_manifest(const struct mcuboot_manifest *manifest)
{
if (manifest == NULL) {
return false;
}

/* Currently only the simplest manifest format is supported */
if (manifest->format != 0x1) {
return false;
}

if (manifest->image_count != BOOT_IMAGE_NUMBER - 1) {
return false;
}

return true;
}

/**
* @brief Get the image hash from the manifest.
*
* @param[in] manifest The reference to the manifest structure.
* @param[in] image_index The index of the image to get the hash for.
* Must be in range <0, BOOT_IMAGE_NUMBER - 1>, but
* must not be equal to MCUBOOT_MANIFEST_IMAGE_NUMBER.
*
* @return A pointer to the image hash, or NULL if the image_index is out of range
* of allowed values.
*/
static inline const uint8_t *bootutil_get_image_hash(const struct mcuboot_manifest *manifest,
uint32_t image_index)
{
if (!bootutil_verify_manifest(manifest)) {
return NULL;
}

if (image_index >= BOOT_IMAGE_NUMBER) {
return NULL;
}

if (image_index < MCUBOOT_MANIFEST_IMAGE_NUMBER) {
return manifest->image_hash[image_index];
} else if (image_index > MCUBOOT_MANIFEST_IMAGE_NUMBER) {
return manifest->image_hash[image_index - 1];
}

return NULL;
}

#ifdef __cplusplus
}
#endif

#endif /* __MCUBOOT_MANIFEST_H__ */
35 changes: 35 additions & 0 deletions boot/bootutil/src/bootutil_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
#include "bootutil/enc_key.h"
#endif

#ifdef MCUBOOT_MANIFEST_UPDATES
#include "bootutil/mcuboot_manifest.h"
#endif /* MCUBOOT_MANIFEST_UPDATES */

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -287,6 +291,11 @@ struct boot_loader_state {
#endif
} slot_usage[BOOT_IMAGE_NUMBER];
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */

#if defined(MCUBOOT_MANIFEST_UPDATES)
struct mcuboot_manifest manifest[BOOT_NUM_SLOTS];
bool manifest_valid[BOOT_NUM_SLOTS];
#endif
};

struct boot_sector_buffer {
Expand Down Expand Up @@ -397,6 +406,32 @@ uint32_t boot_scratch_trailer_sz(uint32_t min_write_sz);
bool bootutil_buffer_is_erased(const struct flash_area *area,
const void *buffer, size_t len);

/*
* Check that there is a valid image in a slot
*
* @returns
* FIH_SUCCESS if image was successfully validated
* FIH_NO_BOOTABLE_IMAGE if no bootloable image was found
* FIH_FAILURE on any errors
*/
fih_ret boot_validate_slot(struct boot_loader_state *state, int slot,
struct boot_status *bs, int expected_swap_type);
/**
* Compare image version numbers
*
* By default, the comparison does not take build number into account.
* Enable MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER to take the build number into account.
*
* @param ver1 Pointer to the first image version to compare.
* @param ver2 Pointer to the second image version to compare.
*
* @retval -1 If ver1 is less than ver2.
* @retval 0 If the image version numbers are equal.
* @retval 1 If ver1 is greater than ver2.
*/
int boot_version_cmp(const struct image_version *ver1,
const struct image_version *ver2);

/**
* Opens the flash areas of all images.
*
Expand Down
87 changes: 86 additions & 1 deletion boot/bootutil/src/image_validate.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ BOOT_LOG_MODULE_DECLARE(mcuboot);
#include "bootutil/mcuboot_uuid.h"
#endif /* MCUBOOT_UUID_VID || MCUBOOT_UUID_CID */

#ifdef MCUBOOT_MANIFEST_UPDATES
#include "bootutil/mcuboot_manifest.h"
#endif /* MCUBOOT_MANIFEST_UPDATES */

#if defined(MCUBOOT_DECOMPRESS_IMAGES)
#include <nrf_compress/implementation.h>
#include <compression/decompression.h>
Expand Down Expand Up @@ -212,7 +216,7 @@ bootutil_img_validate(struct boot_loader_state *state,
{
#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) \
|| defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) || defined(MCUBOOT_DECOMPRESS_IMAGES) \
|| defined(MCUBOOT_BUILTIN_KEY)
|| defined(MCUBOOT_BUILTIN_KEY) || defined(MCUBOOT_MANIFEST_UPDATES)
int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state));
#endif
uint32_t off;
Expand Down Expand Up @@ -258,6 +262,12 @@ bootutil_img_validate(struct boot_loader_state *state,
goto out;
}
#endif
#ifdef MCUBOOT_MANIFEST_UPDATES
bool manifest_found = false;
bool manifest_valid = false;
uint8_t slot = (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index) ? 1 : 0);
const uint8_t *image_hash = NULL;
#endif
#ifdef MCUBOOT_UUID_VID
struct image_uuid img_uuid_vid = {0x00};
FIH_DECLARE(uuid_vid_valid, FIH_FAILURE);
Expand Down Expand Up @@ -431,6 +441,41 @@ bootutil_img_validate(struct boot_loader_state *state,
goto out;
}

#ifdef MCUBOOT_MANIFEST_UPDATES
/* If manifest is present, verify that the image hash matches the
* one in the manifest.
*/
if (!state->manifest_valid[slot]) {
/* Manifest TLV must be processed before any of the image's hash TLV. */
BOOT_LOG_INF("bootutil_img_validate: image rejected, no valid manifest for slot %d",
slot);
rc = -1;
goto out;
}

if (image_index == MCUBOOT_MANIFEST_IMAGE_NUMBER) {
/* Manifest image does not have hash in the manifest. */
image_hash_valid = 1;
break;
}

/* Any image, not described by the manifest is considered as invalid. */
image_hash = bootutil_get_image_hash(&state->manifest[slot], image_index);
if (image_hash == NULL) {
/* Manifest TLV must be processed before any of the image's hash TLV. */
BOOT_LOG_INF("bootutil_img_validate: image rejected, no valid manifest for image %d slot %d",
image_index, slot);
rc = -1;
goto out;
}

FIH_CALL(boot_fih_memequal, fih_rc, hash, image_hash, sizeof(hash));
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
BOOT_LOG_INF("bootutil_img_validate: image rejected, hash does not match manifest contents");
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
#endif
image_hash_valid = 1;
break;
}
Expand Down Expand Up @@ -568,6 +613,39 @@ bootutil_img_validate(struct boot_loader_state *state,
break;
}
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
#ifdef MCUBOOT_MANIFEST_UPDATES
case IMAGE_TLV_MANIFEST:
{
/* There can be only one manifest and must be a part of image with specific index. */
if (manifest_found || image_index != MCUBOOT_MANIFEST_IMAGE_NUMBER ||
len != sizeof(struct mcuboot_manifest) || state->manifest_valid[slot]) {
BOOT_LOG_INF("bootutil_img_validate: image %d slot %d rejected, unexpected manifest TLV",
image_index, slot);
rc = -1;
goto out;
}

manifest_found = true;

rc = LOAD_IMAGE_DATA(hdr, fap, off, &state->manifest[slot], sizeof(struct mcuboot_manifest));
if (rc) {
BOOT_LOG_INF("bootutil_img_validate: slot %d rejected, unable to load manifest", slot);
goto out;
}

manifest_valid = bootutil_verify_manifest(&state->manifest[slot]);
if (!manifest_valid) {
BOOT_LOG_INF("bootutil_img_validate: slot %d rejected, invalid manifest contents", slot);
rc = -1;
goto out;
}

/* The image's manifest has been successfully verified. */
state->manifest_valid[slot] = true;
BOOT_LOG_INF("bootutil_img_validate: slot %d manifest verified", slot);
break;
}
#endif
#ifdef MCUBOOT_UUID_VID
case IMAGE_TLV_UUID_VID:
{
Expand Down Expand Up @@ -654,6 +732,13 @@ bootutil_img_validate(struct boot_loader_state *state,
skip_security_counter_check:
#endif

#ifdef MCUBOOT_MANIFEST_UPDATES
if (image_index == MCUBOOT_MANIFEST_IMAGE_NUMBER && (!manifest_found || !manifest_valid)) {
BOOT_LOG_INF("bootutil_img_validate: slot %d rejected, manifest missing or invalid", slot);
rc = -1;
goto out;
}
#endif
#ifdef MCUBOOT_UUID_VID
if (FIH_NOT_EQ(uuid_vid_valid, FIH_SUCCESS)) {
rc = -1;
Expand Down
11 changes: 8 additions & 3 deletions boot/bootutil/src/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp)
* @retval 0 If the image version numbers are equal.
* @retval 1 If ver1 is greater than ver2.
*/
static int
int
boot_version_cmp(const struct image_version *ver1,
const struct image_version *ver2)
{
Expand Down Expand Up @@ -985,7 +985,7 @@ boot_rom_address_check(struct boot_loader_state *state)
* FIH_NO_BOOTABLE_IMAGE if no bootloable image was found
* FIH_FAILURE on any errors
*/
static fih_ret
fih_ret
boot_validate_slot(struct boot_loader_state *state, int slot,
struct boot_status *bs, int expected_swap_type)
{
Expand Down Expand Up @@ -3565,7 +3565,12 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
#if (BOOT_IMAGE_NUMBER > 1)
while (true) {
#endif
FIH_CALL(boot_load_and_validate_images, fih_rc, state);
BOOT_HOOK_LOAD_AND_VALIDATE_IMAGES_CALL_FIH(
boot_load_and_validate_images_hook, FIH_BOOT_HOOK_REGULAR, fih_rc,
state);
if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) {
FIH_CALL(boot_load_and_validate_images, fih_rc, state);
}
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
goto close;
Expand Down
Loading
Loading