blob: e5ac0e44ec5f4cdba09b4ef6bf6d9c061b41412b [file] [log] [blame]
Maulik Pateld3142702022-06-22 10:09:13 +01001/*
Maulik Patel537ddc82023-01-27 11:56:36 +00002 * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
Maulik Pateld3142702022-06-22 10:09:13 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include "measured_boot.h"
9#include "measured_boot_utils.h"
10#include "measured_boot_api.h"
11#include "psa/crypto.h"
12#include "tfm_api.h"
13#include "tfm_boot_status.h"
14#include "boot_hal.h"
15#include "service_api.h"
16#include "tfm_strnlen.h"
17#include "tfm_sp_log.h"
18#include <stdint.h>
19#include <string.h>
20#include <stdbool.h>
Jamie Fox884371e2023-07-24 15:33:08 +010021#include <stdio.h>
Maulik Pateld3142702022-06-22 10:09:13 +010022
23#define TEMP_BUFFER_SIZE (MEASUREMENT_VALUE_SIZE + MEASUREMENT_VALUE_MAX_SIZE)
24
Jamie Fox5fb7a132022-08-01 17:26:03 +010025#ifdef CONFIG_TFM_BOOT_STORE_MEASUREMENTS
Maulik Pateld3142702022-06-22 10:09:13 +010026/* Size of 1 complete measurement (value + metadata) in TLV format. */
27#define SHARED_BOOT_MEASUREMENT_SIZE \
28 ((2 * SHARED_DATA_ENTRY_HEADER_SIZE) \
29 + sizeof(struct boot_measurement_metadata) \
30 + MEASUREMENT_VALUE_MAX_SIZE)
31
32/* 2 measurements from the BL1 stages and 1 measurement per image from BL2. */
33#define MAX_SHARED_BOOT_DATA_LENGTH ((2 + MCUBOOT_IMAGE_NUMBER) \
34 * SHARED_BOOT_MEASUREMENT_SIZE)
35
36/*!
37 * \struct boot_measurement_data
38 *
39 * \brief Contains all the measurement and related metadata (from BL1 and BL2).
40 *
41 * \details This is a redefinition of \ref tfm_boot_data to allocate the
42 * appropriate, service dependent size of \ref boot_data.
43 */
44struct boot_measurement_data {
45 struct shared_data_tlv_header header;
46 uint8_t data[MAX_SHARED_BOOT_DATA_LENGTH];
47};
48
49/*!
50 * \var boot_measurements
51 *
52 * \brief Store the boot measurements in the service's memory.
53 *
54 * \details Boot measurements come from the BL1 and BL2 boot stages and stored
55 * on a memory area which is shared between the bootloaders and SPM.
56 * SPM provides the \ref tfm_core_get_boot_data() API to retrieve
57 * the service related data from shared area.
58 */
59__attribute__ ((aligned(4)))
60static struct boot_measurement_data boot_measurements;
Jamie Fox5fb7a132022-08-01 17:26:03 +010061#endif /* CONFIG_TFM_BOOT_STORE_MEASUREMENTS */
Maulik Pateld3142702022-06-22 10:09:13 +010062
63struct measurement_metadata_t {
64 uint8_t signer_id[SIGNER_ID_MAX_SIZE];
65 size_t signer_id_size;
66 uint8_t version[VERSION_MAX_SIZE];
67 uint8_t version_size;
68 uint32_t measurement_algo;
69 uint8_t sw_type[SW_TYPE_MAX_SIZE];
70 uint8_t sw_type_size;
71};
72
73struct measurement_value_t {
74 uint8_t hash_buf[MEASUREMENT_VALUE_MAX_SIZE];
75 uint8_t hash_buf_size;
76};
77
78struct measurement_t {
79 struct measurement_value_t value; /* measurement value */
80 struct measurement_metadata_t metadata; /* metadata */
81};
82
83struct measured_boot_slot_t {
84 bool is_locked;
85 bool is_populated;
86 bool is_common;
87 struct measurement_t measurement;
88};
89
90static struct measured_boot_slot_t measurement_slot[NUM_OF_MEASUREMENT_SLOTS];
91
92static bool is_signer_id_different(uint8_t index, const uint8_t *signer_id)
93{
94 uint8_t *stored_signer_id =
95 &measurement_slot[index].measurement.metadata.signer_id[0];
96 uint8_t stored_signer_id_size =
97 measurement_slot[index].measurement.metadata.signer_id_size;
98
99 if (memcmp(signer_id, stored_signer_id, stored_signer_id_size) != 0) {
100 return true;
101 }
102 return false;
103}
104
105/* TODO: Access control strategy to be updated */
106static bool is_slot_access_prohibited(uint8_t slot_index,
Maulik Patel537ddc82023-01-27 11:56:36 +0000107 const uint8_t *signer_id,
108 uint32_t measurement_algo)
Maulik Pateld3142702022-06-22 10:09:13 +0100109{
Maulik Patel537ddc82023-01-27 11:56:36 +0000110 if (measurement_algo != measurement_slot[slot_index].measurement.metadata.measurement_algo) {
111 /* The client hash algorithm is different from the current slot hash algorithm */
112 return true;
113 }
114
Maulik Pateld3142702022-06-22 10:09:13 +0100115 if (is_signer_id_different(slot_index, signer_id)) {
116 /* The client signer id is different from the current slot signer id */
Maulik Patel537ddc82023-01-27 11:56:36 +0000117 if (!measurement_slot[slot_index].is_common) {
118 /* This slot does NOT hold common measurements */
Maulik Pateld3142702022-06-22 10:09:13 +0100119 return true;
120 }
121 }
122
Maulik Patel537ddc82023-01-27 11:56:36 +0000123 /* The client signer id and hash algo is same as the current slot signer id
124 * and hash algo respectively; hence it must be allowed full access
Maulik Pateld3142702022-06-22 10:09:13 +0100125 */
126 return false;
127}
128
129/* TODO: Implement updates for access control strategy here. */
130static bool is_read_access_prohibited(uint8_t slot_index)
131{
132 return false;
133}
134
135static inline bool is_measurement_slot_populated(const uint8_t index)
136{
137 /* Extension is required if any previous measurement value already exists
138 * in this slot
139 */
140 return (measurement_slot[index].is_populated);
141}
142
143psa_status_t measured_boot_read_measurement(uint8_t index,
144 uint8_t *signer_id,
145 size_t signer_id_size,
146 size_t *signer_id_len,
147 uint8_t *version,
148 size_t version_size,
149 uint8_t *version_len,
150 uint32_t *measurement_algo,
151 uint8_t *sw_type,
152 size_t sw_type_size,
153 uint8_t *sw_type_len,
154 uint8_t *measurement_value,
155 size_t measurement_value_size,
156 size_t *measurement_value_len,
157 uint8_t *is_locked)
158{
159 struct measurement_t *src_measurement =
160 &measurement_slot[index].measurement;
161
162 if (is_read_access_prohibited(index)) {
163 return PSA_ERROR_NOT_PERMITTED;
164 }
165
166 if (is_measurement_slot_populated(index)) {
167 if ((version_size < src_measurement->metadata.version_size) ||
168 (sw_type_size < src_measurement->metadata.sw_type_size) ||
169 (signer_id_size < src_measurement->metadata.signer_id_size) ||
170 (measurement_value_size < src_measurement->value.hash_buf_size)) {
171 /* The size of one of the arguments is incorrect */
172 return PSA_ERROR_INVALID_ARGUMENT;
173 }
174
175 *signer_id_len = src_measurement->metadata.signer_id_size;
176 memcpy(signer_id, src_measurement->metadata.signer_id, *signer_id_len);
177
178 *version_len = src_measurement->metadata.version_size;
179 memcpy(version, src_measurement->metadata.version, *version_len);
180
181 *sw_type_len = src_measurement->metadata.sw_type_size;
182 memcpy(sw_type, src_measurement->metadata.sw_type, *sw_type_len);
183
184 *measurement_algo = src_measurement->metadata.measurement_algo;
185
186 *measurement_value_len = src_measurement->value.hash_buf_size;
187 memcpy(measurement_value, src_measurement->value.hash_buf,
188 *measurement_value_len);
189
190 *is_locked = measurement_slot[index].is_locked;
191 } else {
192 /* Measurement slot is not populated. */
193 return PSA_ERROR_DOES_NOT_EXIST;
194 }
195
196 return PSA_SUCCESS;
197}
198
199static void update_metadata(const uint8_t index,
200 const uint8_t *signer_id,
201 const size_t signer_id_size,
202 const uint8_t *version,
203 const size_t version_size,
204 const uint32_t measurement_algo,
205 const uint8_t *sw_type,
206 const size_t sw_type_size)
207{
208 struct measurement_metadata_t *dest_metadata =
209 &measurement_slot[index].measurement.metadata;
210
211 /* Copy metadata for corresponding measurement slot */
212 dest_metadata->signer_id_size = signer_id_size;
213 dest_metadata->version_size = version_size;
214 dest_metadata->sw_type_size = sw_type_size;
215
216 memcpy(dest_metadata->signer_id, signer_id, signer_id_size);
217 memcpy(dest_metadata->version, version, version_size);
218 dest_metadata->measurement_algo = measurement_algo;
219 memcpy(dest_metadata->sw_type, sw_type, sw_type_size);
220}
221
222static void extend_metadata(const uint8_t index)
223{
224 struct measurement_metadata_t *dest_metadata =
225 &measurement_slot[index].measurement.metadata;
226
227 /* Do not update Signer ID as it should be the same */
228 /* Do not update Measurement algo as it should be the same */
229 /* Clear Version info and Software component description */
230 dest_metadata->version_size = 0;
231 dest_metadata->sw_type_size = 0;
232 (void)memset(dest_metadata->version, 0, VERSION_MAX_SIZE);
233 (void)memset(dest_metadata->sw_type, 0, SW_TYPE_MAX_SIZE);
234}
235
236static void store_measurement_value(const uint8_t index,
237 const uint8_t *src_value,
238 const size_t measurement_size)
239{
240 memcpy(&measurement_slot[index].measurement.value.hash_buf[0], src_value,
241 measurement_size);
242 measurement_slot[index].measurement.value.hash_buf_size = measurement_size;
243}
244
245static inline void lock_measurement_slot(const uint8_t index)
246{
247 measurement_slot[index].is_locked = true;
248}
249
250static inline void get_stored_measurement_value(const uint8_t index,
251 uint8_t *output_buffer,
252 const size_t measurement_size)
253{
254 memcpy(output_buffer,
255 &measurement_slot[index].measurement.value.hash_buf[0],
256 MEASUREMENT_VALUE_SIZE);
257}
258
259static psa_status_t extend_measurement_value(const uint8_t index,
260 const uint8_t *measurement,
261 const size_t measurement_size,
262 uint8_t *hash_result,
263 size_t *hash_len)
264{
265 uint8_t temp_buffer[TEMP_BUFFER_SIZE];
266 size_t total_size;
267
268 /* Read previous measurement */
269 get_stored_measurement_value(index, temp_buffer, MEASUREMENT_VALUE_SIZE);
270
271 /* concatenate new measurement */
272 memcpy(&temp_buffer[MEASUREMENT_VALUE_SIZE], measurement, measurement_size);
273 total_size = measurement_size + MEASUREMENT_VALUE_SIZE;
274
275 /* Perform hash calculation */
276 return psa_hash_compute(TFM_MEASURED_BOOT_HASH_ALG, temp_buffer,
277 total_size, hash_result, MEASUREMENT_VALUE_SIZE,
278 hash_len);
279}
280
281static inline bool is_measurement_slot_locked(const uint8_t index)
282{
283 return measurement_slot[index].is_locked;
284}
285
286static inline void mark_slot_as_occupied(const uint8_t index)
287{
288 measurement_slot[index].is_populated = true;
289}
290
291/* This API is used to extend and store measurement and the corresponding
292 * metadata / boot-record (if provided).
293 */
294psa_status_t measured_boot_extend_measurement(uint8_t index,
295 const uint8_t *signer_id,
296 size_t signer_id_size,
297 const uint8_t *version,
298 uint8_t version_size,
299 uint32_t measurement_algo,
300 const uint8_t *sw_type,
301 uint8_t sw_type_size,
302 const uint8_t *measurement_value,
303 size_t measurement_value_size,
304 uint8_t lock_measurement)
305{
306 psa_status_t status = PSA_SUCCESS;
307 uint8_t hash_result[MEASUREMENT_VALUE_SIZE] = {0};
308 size_t hash_len;
309
310 log_extend_measurement(index,
311 signer_id, signer_id_size,
312 version, version_size,
313 measurement_algo,
314 sw_type, sw_type_size,
315 measurement_value, measurement_value_size,
316 lock_measurement);
317
Maulik Pateld3142702022-06-22 10:09:13 +0100318 if (is_measurement_slot_locked(index)) {
319 /* Cannot write to measurement slot once locked */
320 status = PSA_ERROR_BAD_STATE;
321 goto error;
322 }
323
324 /* Check how metadata needs updating for the requested slot */
325 if (is_measurement_slot_populated(index)) {
Maulik Patel537ddc82023-01-27 11:56:36 +0000326 if (is_slot_access_prohibited(index, signer_id, measurement_algo)) {
327 status = PSA_ERROR_NOT_PERMITTED;
328 goto error;
329 }
330
Maulik Pateld3142702022-06-22 10:09:13 +0100331 /* Extend metadata */
332 extend_metadata(index);
333 } else {
334 /* Store the corresponding metadata */
335 update_metadata(index,
336 signer_id, signer_id_size,
337 version, version_size,
338 measurement_algo,
339 sw_type, sw_type_size);
340 /* Indicate that the slot is not empty anymore */
341 mark_slot_as_occupied(index);
342 }
343
344 /* Extend current measurement with new measured value */
345 status = extend_measurement_value(index,
346 measurement_value,
347 measurement_value_size,
348 hash_result, &hash_len);
349 if (status != PSA_SUCCESS) {
350 goto error;
351 }
352
353 /* Store calculated extended value */
354 store_measurement_value(index, hash_result, hash_len);
355
356 if (lock_measurement) {
357 /* lock measurement slot if requested */
358 lock_measurement_slot(index);
359 }
360
361error:
362 if (status != PSA_SUCCESS) {
363 LOG_DBGFMT("Measured Boot : measurement extension failed.\r\n");
364 } else {
365 LOG_DBGFMT("Measured Boot : measurement extended successfully.\r\n");
366 }
367
368 return status;
369}
370
371void initialise_all_measurements(void)
372{
373 uint32_t i;
374
375 for (i = 0; i < NUM_OF_MEASUREMENT_SLOTS; i++) {
376 measurement_slot[i].is_locked = false;
377 measurement_slot[i].is_populated = false;
378 /* By default, mark all slots as "not common" to avoid accidental extend
379 * and write by a different signer id
380 */
381 measurement_slot[i].is_common = false;
382
383 /* Clear all metadata for corresponding measurement slot */
384 (void)memset(&measurement_slot[i].measurement.metadata, 0,
385 sizeof(struct measurement_metadata_t));
386 /* Initialise measurement values to default pattern */
387 (void)memset(&measurement_slot[i].measurement.value.hash_buf[0],
388 MEASUREMENT_VALUE_INIT_PATTERN,
389 sizeof(measurement_slot[i].measurement.value.hash_buf));
390 }
391}
392
Jamie Fox5fb7a132022-08-01 17:26:03 +0100393#ifdef CONFIG_TFM_BOOT_STORE_MEASUREMENTS
Maulik Pateld3142702022-06-22 10:09:13 +0100394psa_status_t collect_shared_measurements(void)
395{
396 struct shared_data_tlv_entry tlv_entry;
397 struct boot_measurement_metadata *metadata_ptr;
398 uint8_t *tlv_end;
399 uint8_t *tlv_curr;
400 uint8_t claim;
401 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
402 int32_t rc;
Jamie Fox884371e2023-07-24 15:33:08 +0100403 uint8_t version[VERSION_MAX_SIZE];
404 int version_size;
Maulik Pateld3142702022-06-22 10:09:13 +0100405
406 /* Collect the measurements from the shared data area and store them. */
407 rc = tfm_core_get_boot_data(TLV_MAJOR_MBS,
408 (struct tfm_boot_data *)&boot_measurements,
409 sizeof(boot_measurements));
410 if (rc != (int32_t)TFM_SUCCESS) {
411 return PSA_ERROR_GENERIC_ERROR;
412 }
413
414 if (boot_measurements.header.tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
415 /* Boot measurement information is malformed. */
416 return PSA_ERROR_GENERIC_ERROR;
417 }
418
419 /* Get the boundaries of TLV section where to lookup. */
420 tlv_curr = boot_measurements.data;
421 tlv_end = (uint8_t *)&boot_measurements
422 + boot_measurements.header.tlv_tot_len;
423
424 while (tlv_curr < tlv_end) {
425 /* Copy TLV entry header - the measurement metadata must come first. */
426 (void)memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE);
427 if ((GET_MBS_CLAIM(tlv_entry.tlv_type) != SW_MEASURE_METADATA) ||
428 (tlv_entry.tlv_len != sizeof(struct boot_measurement_metadata))) {
429 /* Boot measurement information is malformed. */
430 status = PSA_ERROR_GENERIC_ERROR;
431 break;
432 }
433
434 metadata_ptr = (struct boot_measurement_metadata *)
435 (tlv_curr + SHARED_DATA_ENTRY_HEADER_SIZE);
436
437 /* Copy next TLV entry header - it must belong to the measurement. */
438 tlv_curr += (SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len);
439 (void)memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE);
440 claim = GET_MBS_CLAIM(tlv_entry.tlv_type);
441
442 if ((claim != SW_MEASURE_VALUE) &&
443 (claim != SW_MEASURE_VALUE_NON_EXTENDABLE)) {
444 /* Boot measurement information is malformed. */
445 status = PSA_ERROR_GENERIC_ERROR;
446 break;
447 } else {
448 /* Validate size limits of metadata items (if applicable) and
449 * the size limits of measurement value before storing it.
450 */
451 if ((metadata_ptr->signer_id_size < SIGNER_ID_MIN_SIZE) ||
452 (metadata_ptr->signer_id_size > SIGNER_ID_MAX_SIZE) ||
453 (tlv_entry.tlv_len < MEASUREMENT_VALUE_MIN_SIZE) ||
454 (tlv_entry.tlv_len > MEASUREMENT_VALUE_MAX_SIZE)) {
455 status = PSA_ERROR_GENERIC_ERROR;
456 break;
457 }
458
Jamie Fox884371e2023-07-24 15:33:08 +0100459 /* Format the version into a string "major.minor.revision+build" */
460 version_size = snprintf((char *)version, sizeof(version),
461 "%u.%u.%u+%u",
462 metadata_ptr->sw_version.major,
463 metadata_ptr->sw_version.minor,
464 metadata_ptr->sw_version.revision,
465 metadata_ptr->sw_version.build_num);
466 if (version_size < 0 || version_size >= sizeof(version)) {
467 status = PSA_ERROR_GENERIC_ERROR;
468 break;
469 }
470
Maulik Pateld3142702022-06-22 10:09:13 +0100471 /* Store the measurement and associated metadata. */
472 status = measured_boot_extend_measurement(
473 (uint8_t)GET_MBS_SLOT(tlv_entry.tlv_type),
474 metadata_ptr->signer_id,
475 metadata_ptr->signer_id_size,
Jamie Fox884371e2023-07-24 15:33:08 +0100476 version,
477 version_size,
Maulik Pateld3142702022-06-22 10:09:13 +0100478 metadata_ptr->measurement_type,
479 (const uint8_t*)metadata_ptr->sw_type,
480 tfm_strnlen(metadata_ptr->sw_type,
481 sizeof(metadata_ptr->sw_type)),
482 tlv_curr + SHARED_DATA_ENTRY_HEADER_SIZE,
483 tlv_entry.tlv_len,
484 (claim == SW_MEASURE_VALUE_NON_EXTENDABLE) ? true : false);
485 if (status != PSA_SUCCESS) {
486 /* Failed to store measurement. */
487 break;
488 }
489 }
490 /* Move to the next TLV entry. */
491 tlv_curr += (SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len);
492 }
493
494 return status;
495}
Jamie Fox5fb7a132022-08-01 17:26:03 +0100496#endif /* CONFIG_TFM_BOOT_STORE_MEASUREMENTS */