blob: 2a1b13f8ea4b0f3e02592bc041970bb7aa322b70 [file] [log] [blame]
Maulik Pateld3142702022-06-22 10:09:13 +01001/*
2 * Copyright (c) 2022, Arm Limited. All rights reserved.
3 *
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,
106 const uint8_t *signer_id)
107{
108 if (is_signer_id_different(slot_index, signer_id)) {
109 /* The client signer id is different from the current slot signer id */
110 if (measurement_slot[slot_index].is_common) {
111 /* This slot holds common measurement and must be accessible to
112 * all
113 */
114 return false;
115 } else {
116 /* Check for read/extend permissions; deny access for now */
117 return true;
118 }
119 }
120
121 /* The client signer id is same as the current slot signer id; hence it
122 * must be allowed full access
123 */
124 return false;
125}
126
127/* TODO: Implement updates for access control strategy here. */
128static bool is_read_access_prohibited(uint8_t slot_index)
129{
130 return false;
131}
132
133static inline bool is_measurement_slot_populated(const uint8_t index)
134{
135 /* Extension is required if any previous measurement value already exists
136 * in this slot
137 */
138 return (measurement_slot[index].is_populated);
139}
140
141psa_status_t measured_boot_read_measurement(uint8_t index,
142 uint8_t *signer_id,
143 size_t signer_id_size,
144 size_t *signer_id_len,
145 uint8_t *version,
146 size_t version_size,
147 uint8_t *version_len,
148 uint32_t *measurement_algo,
149 uint8_t *sw_type,
150 size_t sw_type_size,
151 uint8_t *sw_type_len,
152 uint8_t *measurement_value,
153 size_t measurement_value_size,
154 size_t *measurement_value_len,
155 uint8_t *is_locked)
156{
157 struct measurement_t *src_measurement =
158 &measurement_slot[index].measurement;
159
160 if (is_read_access_prohibited(index)) {
161 return PSA_ERROR_NOT_PERMITTED;
162 }
163
164 if (is_measurement_slot_populated(index)) {
165 if ((version_size < src_measurement->metadata.version_size) ||
166 (sw_type_size < src_measurement->metadata.sw_type_size) ||
167 (signer_id_size < src_measurement->metadata.signer_id_size) ||
168 (measurement_value_size < src_measurement->value.hash_buf_size)) {
169 /* The size of one of the arguments is incorrect */
170 return PSA_ERROR_INVALID_ARGUMENT;
171 }
172
173 *signer_id_len = src_measurement->metadata.signer_id_size;
174 memcpy(signer_id, src_measurement->metadata.signer_id, *signer_id_len);
175
176 *version_len = src_measurement->metadata.version_size;
177 memcpy(version, src_measurement->metadata.version, *version_len);
178
179 *sw_type_len = src_measurement->metadata.sw_type_size;
180 memcpy(sw_type, src_measurement->metadata.sw_type, *sw_type_len);
181
182 *measurement_algo = src_measurement->metadata.measurement_algo;
183
184 *measurement_value_len = src_measurement->value.hash_buf_size;
185 memcpy(measurement_value, src_measurement->value.hash_buf,
186 *measurement_value_len);
187
188 *is_locked = measurement_slot[index].is_locked;
189 } else {
190 /* Measurement slot is not populated. */
191 return PSA_ERROR_DOES_NOT_EXIST;
192 }
193
194 return PSA_SUCCESS;
195}
196
197static void update_metadata(const uint8_t index,
198 const uint8_t *signer_id,
199 const size_t signer_id_size,
200 const uint8_t *version,
201 const size_t version_size,
202 const uint32_t measurement_algo,
203 const uint8_t *sw_type,
204 const size_t sw_type_size)
205{
206 struct measurement_metadata_t *dest_metadata =
207 &measurement_slot[index].measurement.metadata;
208
209 /* Copy metadata for corresponding measurement slot */
210 dest_metadata->signer_id_size = signer_id_size;
211 dest_metadata->version_size = version_size;
212 dest_metadata->sw_type_size = sw_type_size;
213
214 memcpy(dest_metadata->signer_id, signer_id, signer_id_size);
215 memcpy(dest_metadata->version, version, version_size);
216 dest_metadata->measurement_algo = measurement_algo;
217 memcpy(dest_metadata->sw_type, sw_type, sw_type_size);
218}
219
220static void extend_metadata(const uint8_t index)
221{
222 struct measurement_metadata_t *dest_metadata =
223 &measurement_slot[index].measurement.metadata;
224
225 /* Do not update Signer ID as it should be the same */
226 /* Do not update Measurement algo as it should be the same */
227 /* Clear Version info and Software component description */
228 dest_metadata->version_size = 0;
229 dest_metadata->sw_type_size = 0;
230 (void)memset(dest_metadata->version, 0, VERSION_MAX_SIZE);
231 (void)memset(dest_metadata->sw_type, 0, SW_TYPE_MAX_SIZE);
232}
233
234static void store_measurement_value(const uint8_t index,
235 const uint8_t *src_value,
236 const size_t measurement_size)
237{
238 memcpy(&measurement_slot[index].measurement.value.hash_buf[0], src_value,
239 measurement_size);
240 measurement_slot[index].measurement.value.hash_buf_size = measurement_size;
241}
242
243static inline void lock_measurement_slot(const uint8_t index)
244{
245 measurement_slot[index].is_locked = true;
246}
247
248static inline void get_stored_measurement_value(const uint8_t index,
249 uint8_t *output_buffer,
250 const size_t measurement_size)
251{
252 memcpy(output_buffer,
253 &measurement_slot[index].measurement.value.hash_buf[0],
254 MEASUREMENT_VALUE_SIZE);
255}
256
257static psa_status_t extend_measurement_value(const uint8_t index,
258 const uint8_t *measurement,
259 const size_t measurement_size,
260 uint8_t *hash_result,
261 size_t *hash_len)
262{
263 uint8_t temp_buffer[TEMP_BUFFER_SIZE];
264 size_t total_size;
265
266 /* Read previous measurement */
267 get_stored_measurement_value(index, temp_buffer, MEASUREMENT_VALUE_SIZE);
268
269 /* concatenate new measurement */
270 memcpy(&temp_buffer[MEASUREMENT_VALUE_SIZE], measurement, measurement_size);
271 total_size = measurement_size + MEASUREMENT_VALUE_SIZE;
272
273 /* Perform hash calculation */
274 return psa_hash_compute(TFM_MEASURED_BOOT_HASH_ALG, temp_buffer,
275 total_size, hash_result, MEASUREMENT_VALUE_SIZE,
276 hash_len);
277}
278
279static inline bool is_measurement_slot_locked(const uint8_t index)
280{
281 return measurement_slot[index].is_locked;
282}
283
284static inline void mark_slot_as_occupied(const uint8_t index)
285{
286 measurement_slot[index].is_populated = true;
287}
288
289/* This API is used to extend and store measurement and the corresponding
290 * metadata / boot-record (if provided).
291 */
292psa_status_t measured_boot_extend_measurement(uint8_t index,
293 const uint8_t *signer_id,
294 size_t signer_id_size,
295 const uint8_t *version,
296 uint8_t version_size,
297 uint32_t measurement_algo,
298 const uint8_t *sw_type,
299 uint8_t sw_type_size,
300 const uint8_t *measurement_value,
301 size_t measurement_value_size,
302 uint8_t lock_measurement)
303{
304 psa_status_t status = PSA_SUCCESS;
305 uint8_t hash_result[MEASUREMENT_VALUE_SIZE] = {0};
306 size_t hash_len;
307
308 log_extend_measurement(index,
309 signer_id, signer_id_size,
310 version, version_size,
311 measurement_algo,
312 sw_type, sw_type_size,
313 measurement_value, measurement_value_size,
314 lock_measurement);
315
316 if (is_slot_access_prohibited(index, signer_id)) {
317 status = PSA_ERROR_NOT_PERMITTED;
318 goto error;
319 }
320
321 if (is_measurement_slot_locked(index)) {
322 /* Cannot write to measurement slot once locked */
323 status = PSA_ERROR_BAD_STATE;
324 goto error;
325 }
326
327 /* Check how metadata needs updating for the requested slot */
328 if (is_measurement_slot_populated(index)) {
329 /* Extend metadata */
330 extend_metadata(index);
331 } else {
332 /* Store the corresponding metadata */
333 update_metadata(index,
334 signer_id, signer_id_size,
335 version, version_size,
336 measurement_algo,
337 sw_type, sw_type_size);
338 /* Indicate that the slot is not empty anymore */
339 mark_slot_as_occupied(index);
340 }
341
342 /* Extend current measurement with new measured value */
343 status = extend_measurement_value(index,
344 measurement_value,
345 measurement_value_size,
346 hash_result, &hash_len);
347 if (status != PSA_SUCCESS) {
348 goto error;
349 }
350
351 /* Store calculated extended value */
352 store_measurement_value(index, hash_result, hash_len);
353
354 if (lock_measurement) {
355 /* lock measurement slot if requested */
356 lock_measurement_slot(index);
357 }
358
359error:
360 if (status != PSA_SUCCESS) {
361 LOG_DBGFMT("Measured Boot : measurement extension failed.\r\n");
362 } else {
363 LOG_DBGFMT("Measured Boot : measurement extended successfully.\r\n");
364 }
365
366 return status;
367}
368
369void initialise_all_measurements(void)
370{
371 uint32_t i;
372
373 for (i = 0; i < NUM_OF_MEASUREMENT_SLOTS; i++) {
374 measurement_slot[i].is_locked = false;
375 measurement_slot[i].is_populated = false;
376 /* By default, mark all slots as "not common" to avoid accidental extend
377 * and write by a different signer id
378 */
379 measurement_slot[i].is_common = false;
380
381 /* Clear all metadata for corresponding measurement slot */
382 (void)memset(&measurement_slot[i].measurement.metadata, 0,
383 sizeof(struct measurement_metadata_t));
384 /* Initialise measurement values to default pattern */
385 (void)memset(&measurement_slot[i].measurement.value.hash_buf[0],
386 MEASUREMENT_VALUE_INIT_PATTERN,
387 sizeof(measurement_slot[i].measurement.value.hash_buf));
388 }
389}
390
Jamie Fox5fb7a132022-08-01 17:26:03 +0100391#ifdef CONFIG_TFM_BOOT_STORE_MEASUREMENTS
Maulik Pateld3142702022-06-22 10:09:13 +0100392psa_status_t collect_shared_measurements(void)
393{
394 struct shared_data_tlv_entry tlv_entry;
395 struct boot_measurement_metadata *metadata_ptr;
396 uint8_t *tlv_end;
397 uint8_t *tlv_curr;
398 uint8_t claim;
399 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
400 int32_t rc;
401
402 /* Collect the measurements from the shared data area and store them. */
403 rc = tfm_core_get_boot_data(TLV_MAJOR_MBS,
404 (struct tfm_boot_data *)&boot_measurements,
405 sizeof(boot_measurements));
406 if (rc != (int32_t)TFM_SUCCESS) {
407 return PSA_ERROR_GENERIC_ERROR;
408 }
409
410 if (boot_measurements.header.tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
411 /* Boot measurement information is malformed. */
412 return PSA_ERROR_GENERIC_ERROR;
413 }
414
415 /* Get the boundaries of TLV section where to lookup. */
416 tlv_curr = boot_measurements.data;
417 tlv_end = (uint8_t *)&boot_measurements
418 + boot_measurements.header.tlv_tot_len;
419
420 while (tlv_curr < tlv_end) {
421 /* Copy TLV entry header - the measurement metadata must come first. */
422 (void)memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE);
423 if ((GET_MBS_CLAIM(tlv_entry.tlv_type) != SW_MEASURE_METADATA) ||
424 (tlv_entry.tlv_len != sizeof(struct boot_measurement_metadata))) {
425 /* Boot measurement information is malformed. */
426 status = PSA_ERROR_GENERIC_ERROR;
427 break;
428 }
429
430 metadata_ptr = (struct boot_measurement_metadata *)
431 (tlv_curr + SHARED_DATA_ENTRY_HEADER_SIZE);
432
433 /* Copy next TLV entry header - it must belong to the measurement. */
434 tlv_curr += (SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len);
435 (void)memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE);
436 claim = GET_MBS_CLAIM(tlv_entry.tlv_type);
437
438 if ((claim != SW_MEASURE_VALUE) &&
439 (claim != SW_MEASURE_VALUE_NON_EXTENDABLE)) {
440 /* Boot measurement information is malformed. */
441 status = PSA_ERROR_GENERIC_ERROR;
442 break;
443 } else {
444 /* Validate size limits of metadata items (if applicable) and
445 * the size limits of measurement value before storing it.
446 */
447 if ((metadata_ptr->signer_id_size < SIGNER_ID_MIN_SIZE) ||
448 (metadata_ptr->signer_id_size > SIGNER_ID_MAX_SIZE) ||
449 (tlv_entry.tlv_len < MEASUREMENT_VALUE_MIN_SIZE) ||
450 (tlv_entry.tlv_len > MEASUREMENT_VALUE_MAX_SIZE)) {
451 status = PSA_ERROR_GENERIC_ERROR;
452 break;
453 }
454
455 /* Store the measurement and associated metadata. */
456 status = measured_boot_extend_measurement(
457 (uint8_t)GET_MBS_SLOT(tlv_entry.tlv_type),
458 metadata_ptr->signer_id,
459 metadata_ptr->signer_id_size,
460 (const uint8_t*)metadata_ptr->sw_version,
461 tfm_strnlen(metadata_ptr->sw_version,
462 sizeof(metadata_ptr->sw_version)),
463 metadata_ptr->measurement_type,
464 (const uint8_t*)metadata_ptr->sw_type,
465 tfm_strnlen(metadata_ptr->sw_type,
466 sizeof(metadata_ptr->sw_type)),
467 tlv_curr + SHARED_DATA_ENTRY_HEADER_SIZE,
468 tlv_entry.tlv_len,
469 (claim == SW_MEASURE_VALUE_NON_EXTENDABLE) ? true : false);
470 if (status != PSA_SUCCESS) {
471 /* Failed to store measurement. */
472 break;
473 }
474 }
475 /* Move to the next TLV entry. */
476 tlv_curr += (SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len);
477 }
478
479 return status;
480}
Jamie Fox5fb7a132022-08-01 17:26:03 +0100481#endif /* CONFIG_TFM_BOOT_STORE_MEASUREMENTS */