Skip to content

Add vendor and image class UUID support #2409

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 3 commits 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
2 changes: 2 additions & 0 deletions boot/bootutil/include/bootutil/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ extern "C" {
* ...
* 0xffa0 - 0xfffe
*/
#define IMAGE_TLV_UUID_VID 0x80 /* Vendor unique identifier */
#define IMAGE_TLV_UUID_CID 0x81 /* Device class unique identifier */
#define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */

#define VERSION_DEP_SLOT_ACTIVE 0x00 /* Check dependency against active slot. */
Expand Down
63 changes: 63 additions & 0 deletions boot/bootutil/include/bootutil/mcuboot_uuid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __MCUBOOT_UUID_H__
#define __MCUBOOT_UUID_H__

/**
* @file uuid.h
*
* @note A vendor ID as well as class ID values may be statically generated
* using CMake, based on the vendor domain name as well as product name.
* It is advised to use vendor ID as an input while generating device
* class ID to avoid collisions between UUIDs from two different vendors.
*/

#include <stdint.h>
#include "bootutil/fault_injection_hardening.h"

#ifdef __cplusplus
extern "C" {
#endif


/** The 128-bit UUID, used for identifying vendors as well as image classes. */
struct image_uuid {
uint8_t raw[16];
};

/**
* @brief Initialises the UUID module.
*
* @return FIH_SUCCESS on success
*/
fih_ret boot_uuid_init(void);

/**
* @brief Check if the specified vendor UUID is allowed for a given image.
*
* @param[in] image_id Index of the image (from 0).
* @param[in] uuid_vid The reference to the image's vendor ID value.
*
* @return FIH_SUCCESS on success.
*/
fih_ret boot_uuid_vid_match(uint32_t image_id, const struct image_uuid *uuid_vid);

/**
* @brief Check if the specified image class UUID is allowed for a given image.
*
* @param[in] image_id Index of the image (from 0).
* @param[in] uuid_cid The reference to the image's class ID value.
*
* @return FIH_SUCCESS on success
*/
fih_ret boot_uuid_cid_match(uint32_t image_id, const struct image_uuid *uuid_cid);

#ifdef __cplusplus
}
#endif

#endif /* __MCUBOOT_UUID_H__ */
85 changes: 84 additions & 1 deletion boot/bootutil/src/image_validate.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
#include "bootutil/bootutil_log.h"

BOOT_LOG_MODULE_DECLARE(mcuboot);
#if defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID)
#include "bootutil/mcuboot_uuid.h"
#endif /* MCUBOOT_UUID_VID || MCUBOOT_UUID_CID */

#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
Expand Down Expand Up @@ -507,7 +510,8 @@ bootutil_img_validate(struct boot_loader_state *state,
int seed_len, uint8_t *out_hash
)
{
#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT)
#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) \
|| defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID)
int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state));
#endif
uint32_t off;
Expand Down Expand Up @@ -541,6 +545,14 @@ bootutil_img_validate(struct boot_loader_state *state,
uint32_t img_security_cnt = 0;
FIH_DECLARE(security_counter_valid, FIH_FAILURE);
#endif
#ifdef MCUBOOT_UUID_VID
struct image_uuid img_uuid_vid = {0x00};
FIH_DECLARE(uuid_vid_valid, FIH_FAILURE);
#endif
#ifdef MCUBOOT_UUID_CID
struct image_uuid img_uuid_cid = {0x00};
FIH_DECLARE(uuid_cid_valid, FIH_FAILURE);
#endif

BOOT_LOG_DBG("bootutil_img_validate: flash area %p", fap);

Expand Down Expand Up @@ -749,6 +761,64 @@ bootutil_img_validate(struct boot_loader_state *state,
break;
}
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
#ifdef MCUBOOT_UUID_VID
case IMAGE_TLV_UUID_VID:
{
/*
* Verify the image's vendor ID length.
* This must always be present.
*/
if (len != sizeof(img_uuid_vid)) {
/* Vendor UUID is not valid. */
rc = -1;
goto out;
}

rc = LOAD_IMAGE_DATA(hdr, fap, off, img_uuid_vid.raw, len);
if (rc) {
goto out;
}

FIH_CALL(boot_uuid_vid_match, fih_rc, image_index, &img_uuid_vid);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}

/* The image's vendor identifier has been successfully verified. */
uuid_vid_valid = fih_rc;
break;
}
#endif
#ifdef MCUBOOT_UUID_CID
case IMAGE_TLV_UUID_CID:
{
/*
* Verify the image's class ID length.
* This must always be present.
*/
if (len != sizeof(img_uuid_cid)) {
/* Image class UUID is not valid. */
rc = -1;
goto out;
}

rc = LOAD_IMAGE_DATA(hdr, fap, off, img_uuid_cid.raw, len);
if (rc) {
goto out;
}

FIH_CALL(boot_uuid_cid_match, fih_rc, image_index, &img_uuid_cid);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}

/* The image's class identifier has been successfully verified. */
uuid_cid_valid = fih_rc;
break;
}
#endif
}
}

Expand All @@ -771,6 +841,19 @@ bootutil_img_validate(struct boot_loader_state *state,
}
#endif

#ifdef MCUBOOT_UUID_VID
if (FIH_NOT_EQ(uuid_vid_valid, FIH_SUCCESS)) {
rc = -1;
goto out;
}
#endif
#ifdef MCUBOOT_UUID_CID
if (FIH_NOT_EQ(uuid_cid_valid, FIH_SUCCESS)) {
rc = -1;
goto out;
}
#endif

out:
if (rc) {
FIH_SET(fih_rc, FIH_FAILURE);
Expand Down
53 changes: 53 additions & 0 deletions boot/zephyr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,59 @@ if(DEFINED CONFIG_MEASURED_BOOT OR DEFINED CONFIG_BOOT_SHARE_DATA)
)
endif()

# Include the sample implementation.
if(CONFIG_MCUBOOT_UUID_VID OR CONFIG_MCUBOOT_UUID_CID)
zephyr_library_sources(
mcuboot_uuid.c
)
endif()

# Generate VID value and raw value definition
if(CONFIG_MCUBOOT_UUID_VID OR CONFIG_MCUBOOT_UUID_CID)
string(REGEX MATCHALL "^([0-9A-F][0-9A-F]|\-)+$" match_parts ${CONFIG_MCUBOOT_UUID_VID_VALUE})
if ("${match_parts}" STREQUAL "${CONFIG_MCUBOOT_UUID_VID_VALUE}")
set(UUID_VID ${match_parts})
else()
set(UUID_DNS_NAMESPACE 6ba7b810-9dad-11d1-80b4-00c04fd430c8)
string(
UUID UUID_VID
NAMESPACE ${UUID_DNS_NAMESPACE}
NAME ${CONFIG_MCUBOOT_UUID_VID_VALUE}
TYPE SHA1 UPPER
)
endif()

# Convert UUID into C array.
string(REGEX REPLACE "([0-9A-F][0-9A-F])\-?" "0x\\1, " UUID_VID_RAW ${UUID_VID})
add_compile_definitions(MCUBOOT_UUID_VID_VALUE=${UUID_VID_RAW})
endif()

# Generate VID value(s) and raw value definition(s)
if(CONFIG_MCUBOOT_UUID_CID)
set(MCUBOOT_IMAGES_COUNT 4)
foreach(image_id RANGE ${MCUBOOT_IMAGES_COUNT})
if(CONFIG_MCUBOOT_UUID_CID_IMAGE_${image_id})
# Check if RAW UUID format is used
string(REGEX MATCHALL "^([0-9A-F][0-9A-F]|\-)+$" match_parts ${CONFIG_MCUBOOT_UUID_CID_IMAGE_${image_id}_VALUE})
if ("${match_parts}" STREQUAL "${CONFIG_MCUBOOT_UUID_CID_IMAGE_${image_id}_VALUE}")
set(UUID_CID_IMAGE_${image_id} ${match_parts})
else()
# If not - generate UUID based on VID and CID values
string(
UUID UUID_CID_IMAGE_${image_id}
NAMESPACE ${UUID_VID}
NAME ${CONFIG_MCUBOOT_UUID_CID_IMAGE_${image_id}_VALUE}
TYPE SHA1 UPPER
)
endif()

# Convert UUID into C array.
string(REGEX REPLACE "([0-9A-F][0-9A-F])\-?" "0x\\1, " UUID_CID_IMAGE_${image_id}_RAW ${UUID_CID_IMAGE_${image_id}})
add_compile_definitions(MCUBOOT_UUIC_CID_IMAGE_${image_id}_VALUE=${UUID_CID_IMAGE_${image_id}_RAW})
endif()
endforeach()
endif()

# library which might be common source code for MCUBoot and an application
zephyr_link_libraries(MCUBOOT_BOOTUTIL)

Expand Down
38 changes: 38 additions & 0 deletions boot/zephyr/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,44 @@ config MCUBOOT_HW_DOWNGRADE_PREVENTION

endchoice

config MCUBOOT_UUID_VID
bool "Expect vendor unique identifier in image's TLV"
help
Provide a vendor identification scheme to prevent processing images
generated by a different vendor.

config MCUBOOT_UUID_CID
bool "Expect image class unique identifier in image's TLV"
help
Provide an image class identification scheme to prevent processing
images for a different CPU or device produced by the same vendor.

config MCUBOOT_UUID_VID_VALUE
string "Vendor name"
default ""
depends on MCUBOOT_UUID_VID || MCUBOOT_UUID_CID
help
The vendor unique identifier.
The following formats are supported:
- Domain name (i.e. amce.corp) used to generate RFC 9562 UUID5
identifier.
- Raw UUID (i.e. 12345678-1234-5678-1234-567812345678)

if MCUBOOT_UUID_CID

image=0
rsource "Kconfig.uuid.template"
image=1
rsource "Kconfig.uuid.template"
image=2
rsource "Kconfig.uuid.template"
image=3
rsource "Kconfig.uuid.template"
image=4
rsource "Kconfig.uuid.template"

endif # MCUBOOT_UUID_CID

config BOOT_WATCHDOG_FEED
bool "Feed the watchdog while doing swap"
default y if WATCHDOG
Expand Down
19 changes: 19 additions & 0 deletions boot/zephyr/Kconfig.uuid.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
config MCUBOOT_UUID_CID_IMAGE_$(image)_VALUE
string "Image class name (image $(image))"
default ""
help
The image class unique identifier.
The following formats are supported:
- Image class name (i.e. nRF5340_door_lock_btperipheral).
This format requires MCUBOOT_UUID_VID_VALUE to be defined
as the VID UUID is used as the namespace for generating RFC 9562
UUID5 identifier.
- Raw UUID (i.e. 12345678-1234-5678-1234-567812345678)

config MCUBOOT_UUID_CID_IMAGE_$(image)
bool
default y
depends on MCUBOOT_UUID_CID_IMAGE_$(image)_VALUE != ""
help
Helper symbol to simplify the active CId list generation.

8 changes: 8 additions & 0 deletions boot/zephyr/include/mcuboot_config/mcuboot_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@
#define MCUBOOT_HW_ROLLBACK_PROT
#endif

#ifdef CONFIG_MCUBOOT_UUID_VID
#define MCUBOOT_UUID_VID
#endif

#ifdef CONFIG_MCUBOOT_UUID_CID
#define MCUBOOT_UUID_CID
#endif

#ifdef CONFIG_MEASURED_BOOT
#define MCUBOOT_MEASURED_BOOT
#endif
Expand Down
12 changes: 12 additions & 0 deletions boot/zephyr/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
#include "bootutil/mcuboot_status.h"
#include "flash_map_backend/flash_map_backend.h"

#if defined(CONFIG_MCUBOOT_UUID_VID) || defined(CONFIG_MCUBOOT_UUID_CID)
#include "bootutil/mcuboot_uuid.h"
#endif /* CONFIG_MCUBOOT_UUID_VID || CONFIG_MCUBOOT_UUID_CID */

/* Check if Espressif target is supported */
#ifdef CONFIG_SOC_FAMILY_ESPRESSIF_ESP32

Expand Down Expand Up @@ -540,6 +544,14 @@ int main(void)

mcuboot_status_change(MCUBOOT_STATUS_STARTUP);

#if defined(CONFIG_MCUBOOT_UUID_VID) || defined(CONFIG_MCUBOOT_UUID_CID)
FIH_CALL(boot_uuid_init, fih_rc);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
BOOT_LOG_ERR("Unable to initialize UUID module: %d", fih_rc);
FIH_PANIC;
}
#endif /* CONFIG_MCUBOOT_UUID_VID || CONFIG_MCUBOOT_UUID_CID */

#ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO
BOOT_LOG_DBG("Checking GPIO for serial recovery");
if (io_detect_pin() &&
Expand Down
Loading
Loading