diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 2bd20061d..b331026f0 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -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. */ diff --git a/boot/bootutil/include/bootutil/mcuboot_uuid.h b/boot/bootutil/include/bootutil/mcuboot_uuid.h new file mode 100644 index 000000000..7ae603657 --- /dev/null +++ b/boot/bootutil/include/bootutil/mcuboot_uuid.h @@ -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 +#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__ */ diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 38fd2d291..f7ac4610a 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -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" @@ -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; @@ -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); @@ -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 } } @@ -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); diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index e93cd9f48..711f8bd1d 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -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) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4de80ec0e..bad65e070 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -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 diff --git a/boot/zephyr/Kconfig.uuid.template b/boot/zephyr/Kconfig.uuid.template new file mode 100644 index 000000000..523bd36f8 --- /dev/null +++ b/boot/zephyr/Kconfig.uuid.template @@ -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. + diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 49043051d..73d161722 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -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 diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index f19c609c1..797ebe3b7 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -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 @@ -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() && diff --git a/boot/zephyr/mcuboot_uuid.c b/boot/zephyr/mcuboot_uuid.c new file mode 100644 index 000000000..e7f15f4b1 --- /dev/null +++ b/boot/zephyr/mcuboot_uuid.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#define IMAGE_ID_COUNT 5 +#define CID_INIT(index, label) \ + static const struct image_uuid label = {{ \ + MCUBOOT_UUIC_CID_IMAGE_## index ##_VALUE \ + }} +#define CID_CONFIG(index) UTIL_CAT(CONFIG_MCUBOOT_UUID_CID_IMAGE_, index) +#define CID_DEFINE(index, prefix) \ + IF_ENABLED(CID_CONFIG(index), (CID_INIT(index, prefix##index))) + +#define CID_CONDITION(index, label) \ + if (image_id == index) { \ + *uuid_cid = &label; \ + FIH_RET(FIH_SUCCESS); \ + } +#define CID_CHECK(index, prefix) \ + IF_ENABLED(CID_CONFIG(index), (CID_CONDITION(index, prefix##index))) + +static fih_ret boot_uuid_compare(const struct image_uuid *uuid1, const struct image_uuid *uuid2) +{ + return fih_ret_encode_zero_equality(memcmp(uuid1->raw, uuid2->raw, + ARRAY_SIZE(uuid1->raw))); +} + +#ifdef CONFIG_MCUBOOT_UUID_CID +LISTIFY(IMAGE_ID_COUNT, CID_DEFINE, (;), uuid_cid_image_); + +static fih_ret boot_uuid_cid_get(uint32_t image_id, const struct image_uuid **uuid_cid) +{ + if (uuid_cid != NULL) { + LISTIFY(IMAGE_ID_COUNT, CID_CHECK, (), uuid_cid_image_) + } + + FIH_RET(FIH_FAILURE); +} +#endif /* CONFIG_MCUBOOT_UUID_CID */ + +fih_ret boot_uuid_init(void) +{ + FIH_RET(FIH_SUCCESS); +} + +#ifdef CONFIG_MCUBOOT_UUID_VID +fih_ret boot_uuid_vid_match(uint32_t image_id, const struct image_uuid *uuid_vid) +{ + const struct image_uuid uuid_vid_c = {{ + MCUBOOT_UUID_VID_VALUE + }}; + + return boot_uuid_compare(uuid_vid, &uuid_vid_c); +} +#endif /* CONFIG_MCUBOOT_UUID_VID */ + +#ifdef CONFIG_MCUBOOT_UUID_CID +fih_ret boot_uuid_cid_match(uint32_t image_id, const struct image_uuid *uuid_cid) +{ + FIH_DECLARE(ret_code, FIH_FAILURE); + const struct image_uuid *exp_uuid_cid = NULL; + + FIH_CALL(boot_uuid_cid_get, ret_code, image_id, &exp_uuid_cid); + if (FIH_NOT_EQ(ret_code, FIH_SUCCESS) && FIH_NOT_EQ(ret_code, FIH_FAILURE)) { + FIH_RET(FIH_FAILURE); + } + + return boot_uuid_compare(uuid_cid, exp_uuid_cid); +} +#endif /* CONFIG_MCUBOOT_UUID_CID */ diff --git a/docs/design.md b/docs/design.md index e4da1bfa8..8ab7e3680 100755 --- a/docs/design.md +++ b/docs/design.md @@ -104,22 +104,54 @@ struct image_tlv { /* * Image trailer TLV types. */ -#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */ -#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ -#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */ -#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */ -#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ -#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */ -#define IMAGE_TLV_ED25519 0x24 /* ED25519 of hash output */ -#define IMAGE_TLV_SIG_PURE 0x25 /* If true then any signature found has been - calculated over image directly. */ -#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */ -#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW-128 or - 256 */ -#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-P256 */ -#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */ -#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */ -#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */ +#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */ +#define IMAGE_TLV_PUBKEY 0x02 /* public key */ +#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ +#define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */ +#define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */ +#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */ +#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */ +#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ +#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */ +#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */ +#define IMAGE_TLV_SIG_PURE 0x25 /* Indicator that attached signature has been prepared + * over image rather than its digest. + */ +#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */ +#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/ +#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */ +#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */ +#define IMAGE_TLV_ENC_X25519_SHA512 0x34 /* Key exchange using ECIES-X25519 and SHA512 for MAC + * tag and HKDF in key derivation process + */ +#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */ +#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */ +#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */ +/* The following flags relate to compressed images and are for the decompressed image data */ +#define IMAGE_TLV_DECOMP_SIZE 0x70 /* Decompressed image size excluding header/TLVs */ +#define IMAGE_TLV_DECOMP_SHA 0x71 /* + * Decompressed image shaX hash, this field must match + * the format and size of the raw slot (compressed) + * shaX hash + */ +#define IMAGE_TLV_DECOMP_SIGNATURE 0x72 /* + * Decompressed image signature, this field must match + * the format and size of the raw slot (compressed) + * signature + */ +#define IMAGE_TLV_COMP_DEC_SIZE 0x73 /* Compressed decrypted image size */ + /* + * vendor reserved TLVs at xxA0-xxFF, + * where xx denotes the upper byte + * range. Examples: + * 0x00a0 - 0x00ff + * 0x01a0 - 0x01ff + * 0x02a0 - 0x02ff + * ... + * 0xffa0 - 0xfffe + */ +#define IMAGE_TLV_UUID_VID 0x80 /* Vendor unique identifier */ +#define IMAGE_TLV_UUID_CID 0x81 /* Device class unique identifier */ ``` Optional type-length-value records (TLVs) containing image metadata are placed diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index e26440ef2..67544986e 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -30,7 +30,9 @@ import hashlib import array import os.path +import re import struct +import uuid from enum import Enum import click @@ -96,6 +98,8 @@ 'DECOMP_SHA': 0x71, 'DECOMP_SIGNATURE': 0x72, 'COMP_DEC_SIZE' : 0x73, + 'UUID_VID': 0x80, + 'UUID_CID': 0x81, } TLV_SIZE = 4 @@ -254,6 +258,23 @@ def tlv_matches_key_type(tlv_type, key): return False +def parse_uuid(namespace, value): + # Check if UUID is in the RAW format (12345678-1234-5678-1234-567812345678) + uuid_re = r'[0-9A-f]{8}-[0-9A-f]{4}-[0-9A-f]{4}-[0-9A-f]{4}-[0-9A-f]{12}' + if re.match(uuid_re, value): + uuid_bytes = bytes.fromhex(value.replace('-', '')) + + # Check if UUID is in the string format + elif value.isprintable(): + if namespace is not None: + uuid_bytes = uuid.uuid5(namespace, value).bytes + else: + raise ValueError(f"Unknown namespace for UUID: {value}") + else: + raise ValueError(f"Unknown UUID format: {value}") + + return uuid_bytes + class Image: @@ -263,7 +284,7 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, overwrite_only=False, endian="little", load_addr=0, rom_fixed=None, erased_val=None, save_enctlv=False, security_counter=None, max_align=None, - non_bootable=False): + non_bootable=False, vid=None, cid=None): if load_addr and rom_fixed: raise click.UsageError("Can not set rom_fixed and load_addr at the same time") @@ -292,6 +313,8 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, self.enctlv_len = 0 self.max_align = max(DEFAULT_MAX_ALIGN, align) if max_align is None else int(max_align) self.non_bootable = non_bootable + self.vid = vid + self.cid = cid if self.max_align == DEFAULT_MAX_ALIGN: self.boot_magic = bytes([ @@ -321,7 +344,7 @@ def __repr__(self): return "".format( + payloadlen=0x{:x}, vid={}, cid={}>".format( self.version, self.header_size, self.security_counter, @@ -333,7 +356,9 @@ def __repr__(self): self.overwrite_only, self.endian, self.__class__.__name__, - len(self.payload)) + len(self.payload), + self.vid, + self.cid) def load(self, path): """Load an image from a given file""" @@ -500,6 +525,16 @@ def create(self, key, public_key_format, enckey, dependencies=None, # = 4 + 4 = 8 Bytes protected_tlv_size += TLV_SIZE + 4 + if self.vid is not None: + # Size of the VID TLV: header ('HH') + payload ('16s') + # = 4 + 16 = 20 Bytes + protected_tlv_size += TLV_SIZE + 16 + + if self.cid is not None: + # Size of the CID TLV: header ('HH') + payload ('16s') + # = 4 + 16 = 20 Bytes + protected_tlv_size += TLV_SIZE + 16 + if sw_type is not None: if len(sw_type) > MAX_SW_TYPE_LENGTH: msg = "'{}' is too long ({} characters) for sw_type. Its " \ @@ -603,6 +638,21 @@ def create(self, key, public_key_format, enckey, dependencies=None, if compression_tlvs is not None: for tag, value in compression_tlvs.items(): prot_tlv.add(tag, value) + + if self.vid is not None: + vid = parse_uuid(uuid.NAMESPACE_DNS, self.vid) + payload = struct.pack(e + '16s', vid) + prot_tlv.add('UUID_VID', payload) + + if self.cid is not None: + if self.vid is not None: + namespace = uuid.UUID(bytes=vid) + else: + namespace = None + cid = parse_uuid(namespace, self.cid) + payload = struct.pack(e + '16s', cid) + prot_tlv.add('UUID_CID', payload) + if custom_tlvs is not None: for tag, value in custom_tlvs.items(): prot_tlv.add(tag, value) diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index 7f9a53657..646c9e961 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -473,13 +473,17 @@ def convert(self, value, param, ctx): @click.command(help='''Create a signed or unsigned image\n INFILE and OUTFILE are parsed as Intel HEX if the params have .hex extension, otherwise binary format is used''') +@click.option('--vid', default=None, required=False, + help='Unique vendor identifier, format: (|') +@click.option('--cid', default=None, required=False, + help='Unique image class identifier, format: (|)') def sign(key, public_key_format, align, version, pad_sig, header_size, pad_header, slot_size, pad, confirm, max_sectors, overwrite_only, endian, encrypt_keylen, encrypt, compression, infile, outfile, dependencies, load_addr, hex_addr, erased_val, save_enctlv, security_counter, boot_record, custom_tlv, rom_fixed, max_align, clear, fix_sig, fix_sig_pubkey, sig_out, user_sha, hmac_sha, is_pure, - vector_to_sign, non_bootable): + vector_to_sign, non_bootable, vid, cid): if confirm: # Confirmed but non-padded images don't make much sense, because @@ -492,7 +496,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, endian=endian, load_addr=load_addr, rom_fixed=rom_fixed, erased_val=erased_val, save_enctlv=save_enctlv, security_counter=security_counter, max_align=max_align, - non_bootable=non_bootable) + non_bootable=non_bootable, vid=vid, cid=cid) compression_tlvs = {} img.load(infile) key = load_key(key) if key else None @@ -563,7 +567,8 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, overwrite_only=overwrite_only, endian=endian, load_addr=load_addr, rom_fixed=rom_fixed, erased_val=erased_val, save_enctlv=save_enctlv, - security_counter=security_counter, max_align=max_align) + security_counter=security_counter, max_align=max_align, + vid=vid, cid=cid) compression_filters = [ {"id": lzma.FILTER_LZMA2, "preset": comp_default_preset, "dict_size": comp_default_dictsize, "lp": comp_default_lp,