Skip to content
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
1 change: 1 addition & 0 deletions boot/bootutil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ target_sources(bootutil
src/image_rsa.c
src/image_validate.c
src/loader.c
src/loader_manifest_xip.c
src/swap_misc.c
src/swap_move.c
src/swap_scratch.c
Expand Down
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__ */
12 changes: 12 additions & 0 deletions boot/bootutil/src/bootutil_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,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 @@ -271,6 +275,14 @@ 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];
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET)
enum boot_slot matching_manifest[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
#endif
#endif
};

struct boot_sector_buffer {
Expand Down
128 changes: 127 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 */

#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
Expand Down Expand Up @@ -206,7 +210,7 @@ bootutil_img_validate(struct boot_loader_state *state,
{
#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || \
(defined(EXPECTED_SIG_TLV) && defined(MCUBOOT_BUILTIN_KEY)) || \
defined(MCUBOOT_HW_ROLLBACK_PROT) || \
defined(MCUBOOT_HW_ROLLBACK_PROT) || defined(MCUBOOT_MANIFEST_UPDATES) || \
defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID)
int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state));
#endif
Expand Down Expand Up @@ -244,6 +248,12 @@ bootutil_img_validate(struct boot_loader_state *state,
uint32_t img_security_cnt = 0;
FIH_DECLARE(security_counter_valid, FIH_FAILURE);
#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 @@ -356,6 +366,82 @@ bootutil_img_validate(struct boot_loader_state *state,
goto out;
}

#ifdef MCUBOOT_MANIFEST_UPDATES
if (image_index == MCUBOOT_MANIFEST_IMAGE_NUMBER) {
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, manifest not found before image %d hash",
image_index);
rc = -1;
goto out;
}
/* Manifest image does not have hash in the manifest. */
image_hash_valid = 1;
break;
}
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET)
state->matching_manifest[image_index][slot] = BOOT_SLOT_NONE;
/* Try to match with the primary manifest first. */
if (state->manifest_valid[BOOT_SLOT_PRIMARY]) {
image_hash = bootutil_get_image_hash(&state->manifest[BOOT_SLOT_PRIMARY], image_index);
if (image_hash != NULL) {
FIH_CALL(boot_fih_memequal, fih_rc, hash, image_hash, sizeof(hash));
if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
state->matching_manifest[image_index][slot] = BOOT_SLOT_PRIMARY;
}
}
}

/* Try to match with the secondary manifest if not matched with the primary. */
if(state->matching_manifest[image_index][slot] == BOOT_SLOT_NONE &&
state->manifest_valid[BOOT_SLOT_SECONDARY]) {
image_hash = bootutil_get_image_hash(&state->manifest[BOOT_SLOT_SECONDARY], image_index);
if (image_hash != NULL) {
FIH_CALL(boot_fih_memequal, fih_rc, hash, image_hash, sizeof(hash));
if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
state->matching_manifest[image_index][slot] = BOOT_SLOT_SECONDARY;
}
}
}

/* No matching manifest found. */
if (state->matching_manifest[image_index][slot] == BOOT_SLOT_NONE) {
BOOT_LOG_INF("bootutil_img_validate: image rejected, no valid manifest for image %d slot %d",
image_index, slot);
rc = -1;
goto out;
} else {
BOOT_LOG_INF("bootutil_img_validate: image %d slot %d matches manifest in slot %d",
image_index, slot, state->matching_manifest[image_index][slot]);
}
#else /* MCUBOOT_SWAP_USING_SCRATCH || MCUBOOT_SWAP_USING_MOVE || MCUBOOT_SWAP_USING_OFFSET */
/* Manifest image for a given slot must precede any of other images. */
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;
}

/* 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 /* MCUBOOT_SWAP_USING_SCRATCH || MCUBOOT_SWAP_USING_MOVE || MCUBOOT_SWAP_USING_OFFSET */
#endif /* MCUBOOT_MANIFEST_UPDATES */
image_hash_valid = 1;
break;
}
Expand Down Expand Up @@ -484,6 +570,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)) {
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 @@ -564,6 +683,13 @@ bootutil_img_validate(struct boot_loader_state *state,
}
#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
4 changes: 4 additions & 0 deletions boot/bootutil/src/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
#include "bootutil/mcuboot_status.h"
#include "bootutil_loader.h"

#ifndef MCUBOOT_MANIFEST_UPDATES

#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
Expand Down Expand Up @@ -2498,3 +2500,5 @@ uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state,
return 0;
}
#endif

#endif /* !MCUBOOT_MANIFEST_UPDATES */
Loading
Loading