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