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