|
| 1 | +From db2499cea8ad437dc00295b16772d4d45a0cdef3 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Maulik Patel < [email protected]> |
| 3 | +Date: Wed, 14 May 2025 10:28:07 +0100 |
| 4 | +Subject: [PATCH 1/4] bootutil: Parse key id for built in keys |
| 5 | + |
| 6 | +When MCUBOOT_BUILTIN_KEY is enabled, the key id TLV entry is added |
| 7 | +to the image. Parse this entry while validating the image to identify |
| 8 | +the key used to sign the image. |
| 9 | + |
| 10 | +This enables future support for scenarios such as multiple built-in keys |
| 11 | +or multi-signature. |
| 12 | + |
| 13 | +Signed-off-by: Maulik Patel < [email protected]> |
| 14 | +Change-Id: Ibe26bc2b09e63350f4214719606a5aa4bc1be93c |
| 15 | +--- |
| 16 | + boot/bootutil/include/bootutil/crypto/ecdsa.h | 5 --- |
| 17 | + boot/bootutil/include/bootutil/image.h | 1 + |
| 18 | + boot/bootutil/include/bootutil/sign_key.h | 11 +++++ |
| 19 | + boot/bootutil/src/image_validate.c | 40 ++++++++++++++----- |
| 20 | + scripts/imgtool/image.py | 24 ++++++++++- |
| 21 | + 5 files changed, 64 insertions(+), 17 deletions(-) |
| 22 | + |
| 23 | +diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h |
| 24 | +index 3b054107..e0cf493c 100644 |
| 25 | +--- a/boot/bootutil/include/bootutil/crypto/ecdsa.h |
| 26 | ++++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h |
| 27 | +@@ -392,11 +392,6 @@ static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) |
| 28 | + ctx->required_algorithm = 0; |
| 29 | + |
| 30 | + #else /* !MCUBOOT_BUILTIN_KEY */ |
| 31 | +- /* The incoming key ID is equal to the image index. The key ID value must be |
| 32 | +- * shifted (by one in this case) because zero is reserved (PSA_KEY_ID_NULL) |
| 33 | +- * and considered invalid. |
| 34 | +- */ |
| 35 | +- ctx->key_id++; /* Make sure it is not equal to 0. */ |
| 36 | + #if defined(MCUBOOT_SIGN_EC256) |
| 37 | + ctx->curve_byte_count = 32; |
| 38 | + ctx->required_algorithm = PSA_ALG_SHA_256; |
| 39 | +diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h |
| 40 | +index 15de3e01..cd3a8bf5 100644 |
| 41 | +--- a/boot/bootutil/include/bootutil/image.h |
| 42 | ++++ b/boot/bootutil/include/bootutil/image.h |
| 43 | +@@ -100,6 +100,7 @@ struct flash_area; |
| 44 | + */ |
| 45 | + #define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */ |
| 46 | + #define IMAGE_TLV_PUBKEY 0x02 /* public key */ |
| 47 | ++#define IMAGE_TLV_KEYID 0x03 /* Key ID */ |
| 48 | + #define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ |
| 49 | + #define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */ |
| 50 | + #define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */ |
| 51 | +diff --git a/boot/bootutil/include/bootutil/sign_key.h b/boot/bootutil/include/bootutil/sign_key.h |
| 52 | +index a5e81d35..58bfaf5b 100644 |
| 53 | +--- a/boot/bootutil/include/bootutil/sign_key.h |
| 54 | ++++ b/boot/bootutil/include/bootutil/sign_key.h |
| 55 | +@@ -39,6 +39,17 @@ struct bootutil_key { |
| 56 | + }; |
| 57 | + |
| 58 | + extern const struct bootutil_key bootutil_keys[]; |
| 59 | ++#ifdef MCUBOOT_BUILTIN_KEY |
| 60 | ++/** |
| 61 | ++ * Verify that the specified key ID is valid for authenticating the given image. |
| 62 | ++ * |
| 63 | ++ * @param[in] image_index Index of the image to be verified. |
| 64 | ++ * @param[in] key_id Identifier of the key to be verified against the image. |
| 65 | ++ * |
| 66 | ++ * @return 0 if the key ID is valid for the image; nonzero on failure. |
| 67 | ++ */ |
| 68 | ++int boot_verify_key_id_for_image(uint8_t image_index, uint32_t key_id); |
| 69 | ++#endif /* MCUBOOT_BUILTIN_KEY */ |
| 70 | + #else |
| 71 | + struct bootutil_key { |
| 72 | + uint8_t *key; |
| 73 | +diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c |
| 74 | +index 521251a4..33dc945a 100644 |
| 75 | +--- a/boot/bootutil/src/image_validate.c |
| 76 | ++++ b/boot/bootutil/src/image_validate.c |
| 77 | +@@ -273,12 +273,12 @@ bootutil_img_hash(struct boot_loader_state *state, |
| 78 | + |
| 79 | + #if !defined(MCUBOOT_HW_KEY) |
| 80 | + static int |
| 81 | +-bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) |
| 82 | ++bootutil_find_key(uint8_t image_index, uint8_t *keyhash, uint8_t keyhash_len) |
| 83 | + { |
| 84 | + bootutil_sha_context sha_ctx; |
| 85 | + int i; |
| 86 | + const struct bootutil_key *key; |
| 87 | +- uint8_t hash[IMAGE_HASH_SIZE]; |
| 88 | ++ (void)image_index; |
| 89 | + |
| 90 | + if (keyhash_len > IMAGE_HASH_SIZE) { |
| 91 | + return -1; |
| 92 | +@@ -334,6 +334,32 @@ bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) |
| 93 | + return -1; |
| 94 | + } |
| 95 | + #endif /* !MCUBOOT_HW_KEY */ |
| 96 | ++ |
| 97 | ++#else |
| 98 | ++/* For MCUBOOT_BUILTIN_KEY, key id is passed */ |
| 99 | ++#define EXPECTED_KEY_TLV IMAGE_TLV_KEYID |
| 100 | ++#define KEY_BUF_SIZE sizeof(int32_t) |
| 101 | ++ |
| 102 | ++static int bootutil_find_key(uint8_t image_index, uint8_t *key_id_buf, uint8_t key_id_buf_len) |
| 103 | ++{ |
| 104 | ++ int rc; |
| 105 | ++ FIH_DECLARE(fih_rc, FIH_FAILURE); |
| 106 | ++ |
| 107 | ++ /* Key id is passed */ |
| 108 | ++ assert(key_id_buf_len == sizeof(int32_t)); |
| 109 | ++ int32_t key_id = (((int32_t)key_id_buf[0] << 24) | |
| 110 | ++ ((int32_t)key_id_buf[1] << 16) | |
| 111 | ++ ((int32_t)key_id_buf[2] << 8) | |
| 112 | ++ ((int32_t)key_id_buf[3])); |
| 113 | ++ |
| 114 | ++ /* Check if key id is associated with the image */ |
| 115 | ++ FIH_CALL(boot_verify_key_id_for_image, fih_rc, image_index, key_id); |
| 116 | ++ if (FIH_EQ(fih_rc, FIH_SUCCESS)) { |
| 117 | ++ return key_id; |
| 118 | ++ } |
| 119 | ++ |
| 120 | ++ return -1; |
| 121 | ++} |
| 122 | + #endif /* !MCUBOOT_BUILTIN_KEY */ |
| 123 | + #endif /* EXPECTED_SIG_TLV */ |
| 124 | + |
| 125 | +@@ -449,6 +475,7 @@ static int bootutil_check_for_pure(const struct image_header *hdr, |
| 126 | + static const uint16_t allowed_unprot_tlvs[] = { |
| 127 | + IMAGE_TLV_KEYHASH, |
| 128 | + IMAGE_TLV_PUBKEY, |
| 129 | ++ IMAGE_TLV_KEYID, |
| 130 | + IMAGE_TLV_SHA256, |
| 131 | + IMAGE_TLV_SHA384, |
| 132 | + IMAGE_TLV_SHA512, |
| 133 | +@@ -492,14 +519,7 @@ bootutil_img_validate(struct boot_loader_state *state, |
| 134 | + uint32_t img_sz; |
| 135 | + #ifdef EXPECTED_SIG_TLV |
| 136 | + FIH_DECLARE(valid_signature, FIH_FAILURE); |
| 137 | +-#ifndef MCUBOOT_BUILTIN_KEY |
| 138 | + int key_id = -1; |
| 139 | +-#else |
| 140 | +- /* Pass a key ID equal to the image index, the underlying crypto library |
| 141 | +- * is responsible for mapping the image index to a builtin key ID. |
| 142 | +- */ |
| 143 | +- int key_id = image_index; |
| 144 | +-#endif /* !MCUBOOT_BUILTIN_KEY */ |
| 145 | + #ifdef MCUBOOT_HW_KEY |
| 146 | + uint8_t key_buf[KEY_BUF_SIZE]; |
| 147 | + #endif |
| 148 | +@@ -637,7 +657,7 @@ bootutil_img_validate(struct boot_loader_state *state, |
| 149 | + if (rc) { |
| 150 | + goto out; |
| 151 | + } |
| 152 | +- key_id = bootutil_find_key(buf, len); |
| 153 | ++ key_id = bootutil_find_key(image_index, buf, len); |
| 154 | + #else |
| 155 | + rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len); |
| 156 | + if (rc) { |
| 157 | +diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py |
| 158 | +index 566a47e0..747e19cf 100644 |
| 159 | +--- a/scripts/imgtool/image.py |
| 160 | ++++ b/scripts/imgtool/image.py |
| 161 | +@@ -76,6 +76,7 @@ IMAGE_F = { |
| 162 | + TLV_VALUES = { |
| 163 | + 'KEYHASH': 0x01, |
| 164 | + 'PUBKEY': 0x02, |
| 165 | ++ 'KEYID': 0x03, |
| 166 | + 'SHA256': 0x10, |
| 167 | + 'SHA384': 0x11, |
| 168 | + 'SHA512': 0x12, |
| 169 | +@@ -135,13 +136,19 @@ class TLV(): |
| 170 | + """ |
| 171 | + e = STRUCT_ENDIAN_DICT[self.endian] |
| 172 | + if isinstance(kind, int): |
| 173 | +- if not TLV_VENDOR_RES_MIN <= kind <= TLV_VENDOR_RES_MAX: |
| 174 | ++ if kind in TLV_VALUES.values(): |
| 175 | ++ buf = struct.pack(e + 'BBH', kind, 0, len(payload)) |
| 176 | ++ elif TLV_VENDOR_RES_MIN <= kind <= TLV_VENDOR_RES_MAX: |
| 177 | ++ # Custom vendor-reserved tag |
| 178 | ++ buf = struct.pack(e + 'HH', kind, len(payload)) |
| 179 | ++ else: |
| 180 | + msg = "Invalid custom TLV type value '0x{:04x}', allowed " \ |
| 181 | + "value should be between 0x{:04x} and 0x{:04x}".format( |
| 182 | + kind, TLV_VENDOR_RES_MIN, TLV_VENDOR_RES_MAX) |
| 183 | + raise click.UsageError(msg) |
| 184 | +- buf = struct.pack(e + 'HH', kind, len(payload)) |
| 185 | + else: |
| 186 | ++ if kind not in TLV_VALUES: |
| 187 | ++ raise click.UsageError(f"Unknown TLV type string: {kind}") |
| 188 | + buf = struct.pack(e + 'BBH', TLV_VALUES[kind], 0, len(payload)) |
| 189 | + self.buf += buf |
| 190 | + self.buf += payload |
| 191 | +@@ -632,6 +639,9 @@ class Image: |
| 192 | + print(os.path.basename(__file__) + ': export digest') |
| 193 | + return |
| 194 | + |
| 195 | ++ if self.key_ids is not None: |
| 196 | ++ self._add_key_id_tlv_to_unprotected(tlv, self.key_ids[0]) |
| 197 | ++ |
| 198 | + if key is not None or fixed_sig is not None: |
| 199 | + if public_key_format == 'hash': |
| 200 | + tlv.add('KEYHASH', pubbytes) |
| 201 | +@@ -883,3 +893,13 @@ class Image: |
| 202 | + pass |
| 203 | + tlv_off += TLV_SIZE + tlv_len |
| 204 | + return VerifyResult.INVALID_SIGNATURE, None, None, None |
| 205 | ++ |
| 206 | ++ def set_key_ids(self, key_ids): |
| 207 | ++ """Set list of key IDs (integers) to be inserted before each signature.""" |
| 208 | ++ self.key_ids = key_ids |
| 209 | ++ |
| 210 | ++ def _add_key_id_tlv_to_unprotected(self, tlv, key_id: int): |
| 211 | ++ """Add a key ID TLV into the *unprotected* TLV area.""" |
| 212 | ++ tag = TLV_VALUES['KEYID'] |
| 213 | ++ value = key_id.to_bytes(4, self.endian) |
| 214 | ++ tlv.add(tag, value) |
| 215 | +\ No newline at end of file |
| 216 | +-- |
| 217 | +2.34.1 |
| 218 | + |
0 commit comments