1 /*
2 * Copyright (c) 2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <string.h>
9 #include <stddef.h>
10 #include <stdbool.h>
11 #include "attest_boot_data.h"
12 #include "tfm_boot_status.h"
13 #include "tfm_attest_iat_defs.h"
14 #include "q_useful_buf.h"
15 #ifdef TFM_PARTITION_MEASURED_BOOT
16 #include "measured_boot_api.h"
17 #include "boot_measurement.h"
18 #include "psa/crypto.h"
19 #endif /* TFM_PARTITION_MEASURED_BOOT */
20
21 #define MAX_BOOT_STATUS 512
22
23 /*!
24 * \struct attest_boot_data
25 *
26 * \brief Contains the received boot status information from bootloader
27 *
28 * \details This is a redefinition of \ref tfm_boot_data to allocate the
29 * appropriate, service dependent size of \ref boot_data.
30 */
31 struct attest_boot_data {
32 struct shared_data_tlv_header header;
33 uint8_t data[MAX_BOOT_STATUS];
34 };
35
36 /*!
37 * \var boot_data
38 *
39 * \brief Store the boot status in service's memory.
40 *
41 * \details Boot status comes from the secure bootloader and primarily stored
42 * on a memory area which is shared between bootloader and SPM.
43 * SPM provides the \ref tfm_core_get_boot_data() API to retrieve
44 * the service related data from shared area.
45 */
46 __attribute__ ((aligned(4)))
47 static struct attest_boot_data boot_data;
48
49 /*!
50 * \brief Static function to look up all entries in the shared data area
51 * (boot status) which belong to a specific module.
52 *
53 * \param[in] module The identifier of SW module to look up based on this
54 * \param[out] claim The type of SW module's attribute
55 * \param[out] tlv_len Length of the shared data entry
56 * \param[in/out] tlv_ptr Pointer to the shared data entry. If its value NULL as
57 * input then it will starts the look up from the
58 * beginning of the shared data section. If not NULL then
59 * it continue look up from the next entry. It returns
60 * the address of next found entry which belongs to
61 * module.
62 *
63 * \retval -1 Error, boot status is malformed
64 * \retval 0 Entry not found
65 * \retval 1 Entry found
66 */
attest_get_tlv_by_module(uint8_t module,uint8_t * claim,uint16_t * tlv_len,uint8_t ** tlv_ptr)67 static int32_t attest_get_tlv_by_module(uint8_t module,
68 uint8_t *claim,
69 uint16_t *tlv_len,
70 uint8_t **tlv_ptr)
71 {
72 struct shared_data_tlv_entry tlv_entry;
73 uint8_t *tlv_end;
74 uint8_t *tlv_curr;
75
76 if (boot_data.header.tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
77 return -1;
78 }
79
80 /* Get the boundaries of TLV section where to lookup*/
81 tlv_end = (uint8_t *)&boot_data + boot_data.header.tlv_tot_len;
82 if (*tlv_ptr == NULL) {
83 /* At first call set to the beginning of the TLV section */
84 tlv_curr = boot_data.data;
85 } else {
86 /* Any subsequent call set to the next TLV entry */
87 (void)memcpy(&tlv_entry, *tlv_ptr, SHARED_DATA_ENTRY_HEADER_SIZE);
88
89 tlv_curr = (*tlv_ptr) + SHARED_DATA_ENTRY_HEADER_SIZE
90 + tlv_entry.tlv_len;
91 }
92
93 /* Iterates over the TLV section and returns the address and size of TLVs
94 * with requested module identifier
95 */
96 while (tlv_curr < tlv_end) {
97 /* Create local copy to avoid unaligned access */
98 (void)memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE);
99 if (GET_IAS_MODULE(tlv_entry.tlv_type) == module) {
100 *claim = GET_IAS_CLAIM(tlv_entry.tlv_type);
101 *tlv_ptr = tlv_curr;
102 *tlv_len = tlv_entry.tlv_len;
103 return 1;
104 }
105
106 tlv_curr += (SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len);
107 }
108
109 return 0;
110 }
111
attest_get_tlv_by_id(uint8_t claim,uint16_t * tlv_len,uint8_t ** tlv_ptr)112 int32_t attest_get_tlv_by_id(uint8_t claim,
113 uint16_t *tlv_len,
114 uint8_t **tlv_ptr)
115 {
116 uint8_t tlv_id;
117 uint8_t module = SW_GENERAL;
118 int32_t found;
119
120 /* Ensure that look up starting from the beginning of the boot status */
121 *tlv_ptr = NULL;
122
123 /* Look up specific TLV entry which belongs to SW_GENERAL module */
124 do {
125 /* Look up next entry */
126 found = attest_get_tlv_by_module(module, &tlv_id,
127 tlv_len, tlv_ptr);
128 if (found != 1) {
129 break;
130 }
131 /* At least one entry was found which belongs to SW_GENERAL,
132 * check whether this one is looked for
133 */
134 if (claim == tlv_id) {
135 break;
136 }
137 } while (found == 1);
138
139 return found;
140 }
141
142 #ifdef TFM_PARTITION_MEASURED_BOOT
143 /*!
144 * \brief Static function to get a string representing the measurement algorithm
145 *
146 * \param[in] algorithm Algorithm identifier
147 * \param[out] measurement_desc Structure to carry the output string:
148 * pointer + string length, not including
149 * the null-terminator
150 *
151 * \return Returns error code as specified in \ref psa_attest_err_t
152 */
153 static inline enum psa_attest_err_t
get_measurement_description(psa_algorithm_t algorithm,struct q_useful_buf_c * measurement_desc)154 get_measurement_description(psa_algorithm_t algorithm,
155 struct q_useful_buf_c *measurement_desc)
156 {
157 switch (algorithm) {
158 case PSA_ALG_SHA_256:
159 measurement_desc->ptr = "sha-256";
160 measurement_desc->len = 7; /* Not including the null-terminator. */
161 break;
162 case PSA_ALG_SHA_384:
163 measurement_desc->ptr = "sha-384";
164 measurement_desc->len = 7; /* Not including the null-terminator. */
165 case PSA_ALG_SHA_512:
166 measurement_desc->ptr = "sha-512";
167 measurement_desc->len = 7; /* Not including the null-terminator. */
168 break;
169 default:
170 /* Algorithm not supported. */
171 return PSA_ATTEST_ERR_INVALID_INPUT;
172 }
173
174 return PSA_ATTEST_ERR_SUCCESS;
175 }
176
177 /*!
178 * \brief Static function to encode the properties of a SW component as a map
179 *
180 * \param[in] encode_ctx The encoding context to open the map in
181 * \param[in] signer_id Pointer to buffer which stores the signer ID
182 * \param[in] sw_version Pointer to buffer which stores the SW version
183 * \param[in] sw_type Pointer to buffer which stores the SW type
184 * \param[in] measurement_desc Pointer to buffer which stores the
185 * measurement description
186 * \param[in] measurement Pointer to buffer which stores the
187 * measurement value
188 *
189 * \return Returns error code as specified in \ref psa_attest_err_t
190 */
191 static enum psa_attest_err_t
attest_encode_sw_component(QCBOREncodeContext * encode_ctx,const struct q_useful_buf_c * signer_id,const struct q_useful_buf_c * sw_version,const struct q_useful_buf_c * sw_type,const struct q_useful_buf_c * measurement_desc,const struct q_useful_buf_c * measurement)192 attest_encode_sw_component(QCBOREncodeContext *encode_ctx,
193 const struct q_useful_buf_c *signer_id,
194 const struct q_useful_buf_c *sw_version,
195 const struct q_useful_buf_c *sw_type,
196 const struct q_useful_buf_c *measurement_desc,
197 const struct q_useful_buf_c *measurement)
198 {
199 if (encode_ctx == NULL || signer_id == NULL || sw_version == NULL ||
200 sw_type == NULL || measurement_desc == NULL || measurement == NULL) {
201 return PSA_ATTEST_ERR_INVALID_INPUT;
202 }
203
204 QCBOREncode_OpenMap(encode_ctx);
205
206 /* Encode signer ID as byte string. */
207 QCBOREncode_AddBytesToMapN(encode_ctx,
208 IAT_SW_COMPONENT_SIGNER_ID,
209 *signer_id);
210
211 /* Encode component version as text string. */
212 QCBOREncode_AddTextToMapN(encode_ctx,
213 IAT_SW_COMPONENT_VERSION,
214 *sw_version);
215
216 /* Encode software component type as text string. */
217 QCBOREncode_AddTextToMapN(encode_ctx,
218 IAT_SW_COMPONENT_MEASUREMENT_TYPE,
219 *sw_type);
220
221 /* Encode measurement description as text string. */
222 QCBOREncode_AddTextToMapN(encode_ctx,
223 IAT_SW_COMPONENT_MEASUREMENT_DESC,
224 *measurement_desc);
225
226 /* Encode measurement value as byte string. */
227 QCBOREncode_AddBytesToMapN(encode_ctx,
228 IAT_SW_COMPONENT_MEASUREMENT_VALUE,
229 *measurement);
230
231 QCBOREncode_CloseMap(encode_ctx);
232
233 return PSA_ATTEST_ERR_SUCCESS;
234 }
235 #endif /* TFM_PARTITION_MEASURED_BOOT */
236
237 enum psa_attest_err_t
attest_encode_sw_components_array(QCBOREncodeContext * encode_ctx,const int32_t * map_label,uint32_t * cnt)238 attest_encode_sw_components_array(QCBOREncodeContext *encode_ctx,
239 const int32_t *map_label,
240 uint32_t *cnt)
241 {
242 #ifdef TFM_PARTITION_MEASURED_BOOT
243 uint8_t slot_index;
244
245 Q_USEFUL_BUF_MAKE_STACK_UB(measurement_buf, MEASUREMENT_VALUE_MAX_SIZE);
246 Q_USEFUL_BUF_MAKE_STACK_UB(signer_id_buf, SIGNER_ID_MAX_SIZE);
247 Q_USEFUL_BUF_MAKE_STACK_UB(sw_version_buf, VERSION_MAX_SIZE);
248 Q_USEFUL_BUF_MAKE_STACK_UB(sw_type_buf, SW_TYPE_MAX_SIZE);
249 struct q_useful_buf_c measurement_desc = NULL_Q_USEFUL_BUF_C;
250 uint32_t measurement_algo;
251 bool is_locked;
252 enum psa_attest_err_t err;
253 psa_status_t status;
254
255 if ((encode_ctx == NULL) || (cnt == NULL)) {
256 return PSA_ATTEST_ERR_INVALID_INPUT;
257 }
258
259 *cnt = 0;
260
261 /* Retrieve all the measurements from the Measured Boot partition
262 * which are accessible to the Attestation partition.
263 */
264 for (slot_index = 0; slot_index < NUM_OF_MEASUREMENT_SLOTS; slot_index++) {
265 measurement_buf.len = MEASUREMENT_VALUE_MAX_SIZE;
266 signer_id_buf.len = SIGNER_ID_MAX_SIZE;
267 sw_version_buf.len = VERSION_MAX_SIZE;
268 sw_type_buf.len = SW_TYPE_MAX_SIZE;
269
270 status = tfm_measured_boot_read_measurement(slot_index,
271 signer_id_buf.ptr,
272 signer_id_buf.len,
273 &signer_id_buf.len,
274 sw_version_buf.ptr,
275 sw_version_buf.len,
276 &sw_version_buf.len,
277 &measurement_algo,
278 sw_type_buf.ptr,
279 sw_type_buf.len,
280 &sw_type_buf.len,
281 measurement_buf.ptr,
282 measurement_buf.len,
283 &measurement_buf.len,
284 &is_locked);
285 if (status != PSA_SUCCESS) {
286 continue;
287 }
288
289 (*cnt)++;
290 if (*cnt == 1) {
291 /* Open array which stores SW components claims. */
292 if (map_label != NULL) {
293 QCBOREncode_OpenArrayInMapN(encode_ctx, *map_label);
294 } else {
295 QCBOREncode_OpenArray(encode_ctx);
296 }
297 }
298
299 err = get_measurement_description(measurement_algo, &measurement_desc);
300 if (err != PSA_ATTEST_ERR_SUCCESS) {
301 return PSA_ATTEST_ERR_GENERAL;
302 }
303
304 err = attest_encode_sw_component(
305 encode_ctx,
306 (struct q_useful_buf_c *)&signer_id_buf,
307 (struct q_useful_buf_c *)&sw_version_buf,
308 (struct q_useful_buf_c *)&sw_type_buf,
309 &measurement_desc,
310 (struct q_useful_buf_c *)&measurement_buf);
311 if (err != PSA_ATTEST_ERR_SUCCESS) {
312 return PSA_ATTEST_ERR_GENERAL;
313 }
314 }
315
316 #else /* TFM_PARTITION_MEASURED_BOOT */
317 struct q_useful_buf_c encoded_const = NULL_Q_USEFUL_BUF_C;
318 uint16_t tlv_len;
319 uint8_t *tlv_ptr;
320 uint8_t tlv_id;
321 uint8_t module = 0;
322 int32_t found;
323
324 if ((encode_ctx == NULL) || (cnt == NULL)) {
325 return PSA_ATTEST_ERR_INVALID_INPUT;
326 }
327
328 *cnt = 0;
329
330 /* Extract all boot records (measurements) from the boot status information
331 * that was received from the secure bootloader.
332 */
333 for (module = 0; module < SW_MAX; ++module) {
334 /* Indicates to restart the look up from the beginning of the shared
335 * data section.
336 */
337 tlv_ptr = NULL;
338
339 /* Look up the first TLV entry which belongs to the SW module */
340 found = attest_get_tlv_by_module(module, &tlv_id,
341 &tlv_len, &tlv_ptr);
342 if (found == -1) {
343 /* Boot status area is malformed. */
344 return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
345 } else if ((found == 1) && (tlv_id == SW_BOOT_RECORD)) {
346 (*cnt)++;
347 if (*cnt == 1) {
348 /* Open array which stores SW components claims. */
349 if (map_label != NULL) {
350 QCBOREncode_OpenArrayInMapN(encode_ctx, *map_label);
351 } else {
352 QCBOREncode_OpenArray(encode_ctx);
353 }
354 }
355
356 encoded_const.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
357 encoded_const.len = tlv_len;
358 QCBOREncode_AddEncoded(encode_ctx, encoded_const);
359 }
360 }
361 #endif /* TFM_PARTITION_MEASURED_BOOT */
362
363 if (*cnt != 0) {
364 /* Close array which stores SW components claims. */
365 QCBOREncode_CloseArray(encode_ctx);
366 }
367
368 return PSA_ATTEST_ERR_SUCCESS;
369 }
370
attest_boot_data_init(void)371 enum psa_attest_err_t attest_boot_data_init(void)
372 {
373 return attest_get_boot_data(TLV_MAJOR_IAS,
374 (struct tfm_boot_data *)&boot_data,
375 MAX_BOOT_STATUS);
376 }
377