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