1 /*
2  * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 #include <string.h>
8 #include "bootutil/boot_record.h"
9 #include "bootutil/boot_status.h"
10 #include "bootutil/image.h"
11 #include "flash_map/flash_map.h"
12 #include "sysflash/sysflash.h"
13 #include "mcuboot_config/mcuboot_config.h"
14 
15 #ifdef TFM_MEASURED_BOOT_API
16 #include "boot_hal.h"
17 #include "tfm_boot_measurement.h"
18 #include "bootutil/crypto/sha.h"
19 #include "bootutil_priv.h"
20 #include "psa/crypto.h"
21 
22 #if defined(MCUBOOT_SIGN_EC384)
23 #define MCUBOOT_HASH_ALG    PSA_ALG_SHA_384
24 #define MCUBOOT_HASH_SIZE   (48)
25 #else
26 #define MCUBOOT_HASH_ALG    PSA_ALG_SHA_256
27 #define MCUBOOT_HASH_SIZE   (32)
28 #endif /* MCUBOOT_SIGN_EC384 */
29 
30 #ifdef MCUBOOT_HW_KEY
31 #if defined(MCUBOOT_SIGN_RSA)
32 #define SIG_BUF_SIZE (MCUBOOT_SIGN_RSA_LEN / 8)
33 #define SIG_EXTRA_BYTES     (24) /* Few extra bytes for encoding and for public exponent. */
34 #elif defined(MCUBOOT_SIGN_EC256)
35 #define SIG_BUF_SIZE        (64) /* Curve byte (32) * 2 for EC-256 */
36 #define SIG_EXTRA_BYTES     (32)
37 #elif defined(MCUBOOT_SIGN_EC384)
38 #define SIG_BUF_SIZE        (96) /* Curve byte (48) * 2 for EC-384 */
39 #define SIG_EXTRA_BYTES     (48)
40 #endif /* MCUBOOT_SIGN_RSA */
41 #endif /* MCUBOOT_HW_KEY */
42 #endif /* TFM_MEASURED_BOOT_API */
43 
44 /* Firmware Update specific macros */
45 #define TLV_MAJOR_FWU   0x2
46 #define MODULE_MASK     0x3F           /* 6 bit */
47 #define CLAIM_MASK      0x3F           /* 6 bit */
48 
49 #define SET_FWU_MINOR(sw_module, claim)  \
50                      ((uint16_t)((sw_module & MODULE_MASK) << 6) | \
51                       (uint16_t)(claim & CLAIM_MASK))
52 
53 #ifdef TFM_PARTITION_FIRMWARE_UPDATE
54 extern int boot_add_data_to_shared_area(uint8_t        major_type,
55                                         uint16_t       minor_type,
56                                         size_t         size,
57                                         const uint8_t *data);
58 #endif /* TFM_PARTITION_FIRMWARE_UPDATE */
59 
60 
61 #ifdef TFM_MEASURED_BOOT_API
62 /**
63  * Collect boot measurement and available associated metadata from the
64  * TLV area of an image.
65  *
66  * @param[in]  hdr        Pointer to the image header stored in RAM.
67  * @param[in]  fap        Pointer to the flash area where image is stored.
68  * @param[out] metadata   Pointer to measurement metadata structure.
69  * @param[out] measurement_buf          Buffer to store the boot measurement.
70  * @param[in]  measurement_buf_size     As an input value it indicates the size
71  *                                      of the measurement buffer in bytes.
72  *
73  * @return                0 on success; nonzero on failure.
74  *
75  */
collect_image_measurement_and_metadata(const struct image_header * hdr,const struct flash_area * fap,struct boot_measurement_metadata * metadata,uint8_t * measurement_buf,size_t measurement_buf_size)76 static int collect_image_measurement_and_metadata(
77                                     const struct image_header *hdr,
78                                     const struct flash_area *fap,
79                                     struct boot_measurement_metadata *metadata,
80                                     uint8_t *measurement_buf,
81                                     size_t   measurement_buf_size)
82 {
83     struct image_tlv_iter it;
84     uint32_t off;
85     uint16_t len;
86     uint16_t type;
87 #ifdef MCUBOOT_HW_KEY
88     /* Few extra bytes for encoding and for public exponent. */
89     uint8_t key_buf[SIG_BUF_SIZE + SIG_EXTRA_BYTES];
90     bootutil_sha_context sha_ctx;
91 #endif
92     int rc;
93 
94     /* Copy the software version information from the image header. */
95     metadata->sw_version.major = hdr->ih_ver.iv_major;
96     metadata->sw_version.minor = hdr->ih_ver.iv_minor;
97     metadata->sw_version.revision = hdr->ih_ver.iv_revision;
98     metadata->sw_version.build_num = hdr->ih_ver.iv_build_num;
99 
100     /* Traverse through all of the TLVs for the required items. */
101     rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
102     if (rc) {
103         return rc;
104     }
105 
106     while (true) {
107         rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
108         if (rc < 0) {
109             return -1;
110         } else if (rc > 0) {
111             break;
112         }
113 
114         if (type == EXPECTED_HASH_TLV) {
115             /* Retrieve the image hash (measurement value) from the TLV area. */
116             if (len > measurement_buf_size) {
117                 return -1;
118             }
119             rc = LOAD_IMAGE_DATA(hdr, fap, off, measurement_buf, len);
120             if (rc) {
121                 return -1;
122             }
123 #ifdef MCUBOOT_HW_KEY
124         } else if (type == IMAGE_TLV_PUBKEY) {
125             /* Retrieve the signer ID (hash of PUBKEY) from the TLV area. */
126             if (len > sizeof(key_buf)) {
127                 /* Something is wrong with the public key, proceed without
128                  * the signer ID.
129                  */
130                 continue;
131             }
132             rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
133             if (rc) {
134                 /* Proceed without this piece of data. */
135                 continue;
136             }
137 
138             /* Calculate the hash of the public key (signer ID). */
139             bootutil_sha_init(&sha_ctx);
140             bootutil_sha_update(&sha_ctx, key_buf, len);
141             bootutil_sha_finish(&sha_ctx, metadata->signer_id);
142 #else
143         } else if (type == IMAGE_TLV_KEYHASH) {
144             /* Retrieve the signer ID (hash of PUBKEY) from the TLV area. */
145             if (len != MCUBOOT_HASH_SIZE) {
146                 /* Something is wrong with the key hash, proceed without
147                  * the signer ID.
148                  */
149                 continue;
150             }
151             rc = LOAD_IMAGE_DATA(hdr, fap, off,
152                                  metadata->signer_id, MCUBOOT_HASH_SIZE);
153             if (rc) {
154                 /* Proceed without this piece of data. */
155                 continue;
156             }
157 #endif /* MCUBOOT_HW_KEY */
158             metadata->signer_id_size = MCUBOOT_HASH_SIZE;
159         }
160     }
161 
162     return 0;
163 }
164 #endif /* TFM_MEASURED_BOOT_API */
165 
166 /**
167  * Add application specific data to the shared memory area between the
168  * bootloader and runtime SW.
169  *
170  * @param[in]  hdr           Pointer to the image header stored in RAM.
171  * @param[in]  fap           Pointer to the flash area where image is stored.
172  * @param[in]  active_slot   Which slot is active (to boot).
173  * @param[in]  max_app_sizes The maximum sizes of images that can be loaded.
174  *
175  * @return                0 on success; nonzero on failure.
176  */
boot_save_shared_data(const struct image_header * hdr,const struct flash_area * fap,const uint8_t active_slot,const struct image_max_size * max_app_sizes)177 int boot_save_shared_data(const struct image_header *hdr,
178                           const struct flash_area *fap,
179                           const uint8_t active_slot,
180                           const struct image_max_size *max_app_sizes)
181 {
182     const struct flash_area *temp_fap;
183     uint8_t mcuboot_image_id = 0;
184     uint8_t i;
185 #if defined(TFM_PARTITION_FIRMWARE_UPDATE) || defined(TFM_MEASURED_BOOT_API)
186     int32_t rc;
187 #endif
188 #ifdef TFM_PARTITION_FIRMWARE_UPDATE
189     struct image_version image_ver;
190     uint16_t fwu_minor;
191 #endif
192 #ifdef TFM_MEASURED_BOOT_API
193     enum boot_measurement_slot_t slot_id;
194     uint8_t image_hash[MCUBOOT_HASH_SIZE];
195     struct boot_measurement_metadata metadata = {
196         .measurement_type = MCUBOOT_HASH_ALG,
197         .signer_id = { 0 },
198         .signer_id_size = 0,
199         .sw_type = "",
200         .sw_version = { 0 },
201     };
202 #endif /* TFM_MEASURED_BOOT_API */
203 
204     (void)active_slot;
205     (void)max_app_sizes;
206 
207     if ((hdr == NULL) || (fap == NULL)) {
208         return -1;
209     }
210 
211     /* Look for the given flash area to determine the image ID. */
212     for (i = 0; i < MCUBOOT_IMAGE_NUMBER; i++) {
213         if ((flash_area_open(FLASH_AREA_IMAGE_PRIMARY(i), &temp_fap) == 0) &&
214             (fap == temp_fap)) {
215             mcuboot_image_id = i;
216             break;
217         }
218 #if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
219         else if (flash_area_open(FLASH_AREA_IMAGE_SECONDARY(i), &temp_fap) == 0 &&
220                  fap == temp_fap) {
221             mcuboot_image_id = i;
222             break;
223         }
224 #endif
225     }
226 
227     if (i == MCUBOOT_IMAGE_NUMBER) {
228         return -1;
229     }
230 
231 #ifdef TFM_PARTITION_FIRMWARE_UPDATE
232     image_ver = hdr->ih_ver;
233 
234     /* Currently hardcode it to 0 which indicates the full image. */
235     fwu_minor = SET_FWU_MINOR(mcuboot_image_id, SW_VERSION);
236     rc = boot_add_data_to_shared_area(TLV_MAJOR_FWU,
237                                       fwu_minor,
238                                       sizeof(image_ver),
239                                       (const uint8_t *)&image_ver);
240     if (rc) {
241         return rc;
242     }
243 #endif /* TFM_PARTITION_FIRMWARE_UPDATE */
244 
245 #ifdef TFM_MEASURED_BOOT_API
246     /* Determine the index of the measurement slot. */
247     slot_id = BOOT_MEASUREMENT_SLOT_RT_0 + mcuboot_image_id;
248 
249     switch (slot_id) {
250     case BOOT_MEASUREMENT_SLOT_RT_0:
251         if (sizeof(metadata.sw_type) < sizeof("RT_0")) {
252             return 1;
253         }
254         memcpy(metadata.sw_type, "RT_0", sizeof("RT_0"));
255         break;
256     case BOOT_MEASUREMENT_SLOT_RT_1:
257         if (sizeof(metadata.sw_type) < sizeof("RT_1")) {
258             return 1;
259         }
260         memcpy(metadata.sw_type, "RT_1", sizeof("RT_1"));
261         break;
262     case BOOT_MEASUREMENT_SLOT_RT_2:
263         if (sizeof(metadata.sw_type) < sizeof("RT_2")) {
264             return 1;
265         }
266         memcpy(metadata.sw_type, "RT_2", sizeof("RT_2"));
267         break;
268     default:
269         /* Proceed without this piece of data. */
270         break;
271     }
272 
273     rc = collect_image_measurement_and_metadata(hdr, fap,
274                                                 &metadata,
275                                                 image_hash,
276                                                 sizeof(image_hash));
277     if (rc) {
278         return rc;
279     }
280 
281     /* Save the boot measurement(s) about the runtime image(s).
282      * If there are multiple images, the measurement slot will be extended
283      * with the subsequent measurements.
284      */
285     rc = boot_store_measurement((uint8_t)slot_id, image_hash,
286                                 sizeof(image_hash), &metadata, false);
287     if (rc) {
288         return rc;
289     }
290 #endif /* TFM_MEASURED_BOOT_API */
291 
292     return 0;
293 }
294