1 /*
2  * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdint.h>
9 #include <string.h>
10 #include <stddef.h>
11 #include "psa/client.h"
12 #include "attest.h"
13 #include "attest_boot_data.h"
14 #include "attest_key.h"
15 #include "attest_token.h"
16 #include "config_attest.h"
17 #include "tfm_plat_defs.h"
18 #include "tfm_plat_device_id.h"
19 #include "tfm_plat_boot_seed.h"
20 #include "tfm_attest_hal.h"
21 #include "tfm_attest_iat_defs.h"
22 #include "t_cose_common.h"
23 #include "tfm_crypto_defs.h"
24 
25 #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(*(array)))
26 
27 /*!
28  * \brief Static function to map return values between \ref psa_attest_err_t
29  *        and \ref psa_status_t
30  *
31  * \param[in]  attest_err  Attestation error code
32  *
33  * \return Returns error code as specified in \ref psa_status_t
34  */
35 static inline psa_status_t
error_mapping_to_psa_status_t(enum psa_attest_err_t attest_err)36 error_mapping_to_psa_status_t(enum psa_attest_err_t attest_err)
37 {
38     switch (attest_err) {
39     case PSA_ATTEST_ERR_SUCCESS:
40         return PSA_SUCCESS;
41         break;
42     case PSA_ATTEST_ERR_INIT_FAILED:
43         return PSA_ERROR_SERVICE_FAILURE;
44         break;
45     case PSA_ATTEST_ERR_BUFFER_OVERFLOW:
46         return PSA_ERROR_BUFFER_TOO_SMALL;
47         break;
48     case PSA_ATTEST_ERR_CLAIM_UNAVAILABLE:
49         return PSA_ERROR_GENERIC_ERROR;
50         break;
51     case PSA_ATTEST_ERR_INVALID_INPUT:
52         return PSA_ERROR_INVALID_ARGUMENT;
53         break;
54     case PSA_ATTEST_ERR_GENERAL:
55         return PSA_ERROR_GENERIC_ERROR;
56         break;
57     default:
58         return PSA_ERROR_GENERIC_ERROR;
59     }
60 }
61 
attest_init(void)62 psa_status_t attest_init(void)
63 {
64     enum psa_attest_err_t res;
65 
66     res = attest_boot_data_init();
67 
68     return error_mapping_to_psa_status_t(res);
69 }
70 
71 /*!
72  * \brief Static function to map return values between \ref attest_token_err_t
73  *        and \ref psa_attest_err_t
74  *
75  * \param[in]  token_err  Token encoding return value
76  *
77  * \return Returns error code as specified in \ref psa_attest_err_t
78  */
79 static inline enum psa_attest_err_t
error_mapping_to_psa_attest_err_t(enum attest_token_err_t token_err)80 error_mapping_to_psa_attest_err_t(enum attest_token_err_t token_err)
81 {
82     switch (token_err) {
83     case ATTEST_TOKEN_ERR_SUCCESS:
84         return PSA_ATTEST_ERR_SUCCESS;
85         break;
86     case ATTEST_TOKEN_ERR_TOO_SMALL:
87         return PSA_ATTEST_ERR_BUFFER_OVERFLOW;
88         break;
89     default:
90         return PSA_ATTEST_ERR_GENERAL;
91     }
92 }
93 
94 /*!
95  * \brief Static function to convert a pointer and size info to unsigned
96  *        integer number. Max 32bits unsigned integers are supported.
97  *
98  * This implementation assumes that the endianness of the sender and receiver
99  * of the data is the same because they are actually running on the same CPU
100  * instance. If this assumption is not true than this function must be
101  * refactored accordingly.
102  *
103  * \param[in]  int_ptr  Pointer to the unsigned integer
104  * \param[in]  len      Size of the unsigned integers in bytes
105  * \param[in]  value    Pointer where to store the converted value
106  *
107  * \return Returns 0 on success and -1 on error.
108  */
get_uint(const void * int_ptr,size_t len,uint32_t * value)109 static inline int32_t get_uint(const void *int_ptr,
110                                size_t len,
111                                uint32_t *value)
112 {
113     uint16_t uint16;
114 
115     switch (len) {
116     case 1:
117         *value = (uint32_t)(*(uint8_t  *)(int_ptr));
118         break;
119     case 2:
120         /* Avoid unaligned access */
121         (void)memcpy(&uint16, int_ptr, sizeof(uint16));
122         *value = (uint32_t)uint16;
123         break;
124     case 4:
125         /* Avoid unaligned access */
126         (void)memcpy(value, int_ptr, sizeof(uint32_t));
127         break;
128     default:
129         return -1;
130     }
131 
132     return 0;
133 }
134 
135 /*!
136  * \brief Static function to add the claims of all SW components to the
137  *        attestation token.
138  *
139  * \param[in]  token_ctx  Token encoding context
140  *
141  * \return Returns error code as specified in \ref psa_attest_err_t
142  */
143 static enum psa_attest_err_t
attest_add_all_sw_components(struct attest_token_encode_ctx * token_ctx)144 attest_add_all_sw_components(struct attest_token_encode_ctx *token_ctx)
145 {
146     QCBOREncodeContext *cbor_encode_ctx = NULL;
147     uint32_t component_cnt;
148     int32_t map_label = IAT_SW_COMPONENTS;
149     enum psa_attest_err_t err;
150 
151     cbor_encode_ctx = attest_token_encode_borrow_cbor_cntxt(token_ctx);
152 
153     err = attest_encode_sw_components_array(cbor_encode_ctx,
154                                             &map_label,
155                                             &component_cnt);
156     if (err != PSA_ATTEST_ERR_SUCCESS) {
157         return err;
158     }
159 
160     if (component_cnt == 0) {
161 #if ATTEST_TOKEN_PROFILE_PSA_IOT_1
162         /* Allowed to not have SW components claim, but it must be indicated
163          * that this state is intentional. In this case, include the
164          * IAT_NO_SW_COMPONENTS claim with a fixed value.
165          */
166         attest_token_encode_add_integer(token_ctx,
167                                         IAT_NO_SW_COMPONENTS,
168                                         (int64_t)NO_SW_COMPONENT_FIXED_VALUE);
169 #else
170         /* Mandatory to have SW components claim in the token */
171         return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
172 #endif
173     }
174 
175     return PSA_ATTEST_ERR_SUCCESS;
176 }
177 
178 /*!
179  * \brief Static function to add implementation id claim to attestation token.
180  *
181  * \param[in]  token_ctx  Token encoding context
182  *
183  * \return Returns error code as specified in \ref psa_attest_err_t
184  */
185 static enum psa_attest_err_t
attest_add_implementation_id_claim(struct attest_token_encode_ctx * token_ctx)186 attest_add_implementation_id_claim(struct attest_token_encode_ctx *token_ctx)
187 {
188     uint8_t implementation_id[IMPLEMENTATION_ID_MAX_SIZE];
189     enum tfm_plat_err_t res_plat;
190     uint32_t size = sizeof(implementation_id);
191     struct q_useful_buf_c claim_value;
192 
193     res_plat = tfm_plat_get_implementation_id(&size, implementation_id);
194     if (res_plat != TFM_PLAT_ERR_SUCCESS) {
195         return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
196     }
197 
198     claim_value.ptr = implementation_id;
199     claim_value.len  = size;
200     attest_token_encode_add_bstr(token_ctx,
201                                  IAT_IMPLEMENTATION_ID,
202                                  &claim_value);
203 
204     return PSA_ATTEST_ERR_SUCCESS;
205 }
206 
207 /*!
208  * \brief Static function to add instance id claim to attestation token.
209  *
210  * \param[in]  token_ctx  Token encoding context
211  *
212  * \note This mandatory claim represents the unique identifier of the instance.
213  *       So far, only GUID type is supported.
214  *
215  * \return Returns error code as specified in \ref psa_attest_err_t
216  */
217 static enum psa_attest_err_t
attest_add_instance_id_claim(struct attest_token_encode_ctx * token_ctx)218 attest_add_instance_id_claim(struct attest_token_encode_ctx *token_ctx)
219 {
220     struct q_useful_buf_c claim_value;
221     enum psa_attest_err_t err;
222 
223     /* Leave the first byte for UEID type byte */
224     err = attest_get_instance_id(&claim_value);
225     if (err != PSA_ATTEST_ERR_SUCCESS) {
226         return err;
227     }
228 
229     attest_token_encode_add_bstr(token_ctx,
230                                  IAT_INSTANCE_ID,
231                                  &claim_value);
232 
233     return PSA_ATTEST_ERR_SUCCESS;
234 }
235 
236 /*!
237  * \brief Static function to add security lifecycle claim to attestation token.
238  *
239  * \param[in]  token_ctx  Token encoding context
240  *
241  * \return Returns error code as specified in \ref psa_attest_err_t
242  */
243 static enum psa_attest_err_t
attest_add_security_lifecycle_claim(struct attest_token_encode_ctx * token_ctx)244 attest_add_security_lifecycle_claim(struct attest_token_encode_ctx *token_ctx)
245 {
246     enum tfm_security_lifecycle_t security_lifecycle;
247     uint32_t slc_value;
248     int32_t res;
249     struct q_useful_buf_c claim_value = {0};
250     uint16_t tlv_len;
251     uint8_t *tlv_ptr = NULL;
252     int32_t found = 0;
253 
254     /* First look up lifecycle state in boot status, it might comes
255      * from bootloader
256      */
257     found = attest_get_tlv_by_id(SECURITY_LIFECYCLE, &tlv_len, &tlv_ptr);
258     if (found == 1) {
259         claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
260         claim_value.len = tlv_len;
261         res = get_uint(claim_value.ptr, claim_value.len, &slc_value);
262         if (res) {
263             return PSA_ATTEST_ERR_GENERAL;
264         }
265         security_lifecycle = (enum tfm_security_lifecycle_t)slc_value;
266     } else {
267         /* If not found in boot status then use callback function to get it
268          * from runtime SW
269          */
270         security_lifecycle = tfm_attest_hal_get_security_lifecycle();
271     }
272 
273     /* Sanity check */
274     if (security_lifecycle > TFM_SLC_MAX_VALUE) {
275         return PSA_ATTEST_ERR_GENERAL;
276     }
277 
278     attest_token_encode_add_integer(token_ctx,
279                                     IAT_SECURITY_LIFECYCLE,
280                                     (int64_t)security_lifecycle);
281 
282     return PSA_ATTEST_ERR_SUCCESS;
283 }
284 
285 /*!
286  * \brief Static function to add the name of the profile definition document
287  *
288  * \note This function would be optional for PSA IoT 1/2 profiles but we keep it
289  *       as mandatory for both CCA and PSA IoT for simplicity
290  *
291  * \param[in]  token_ctx  Token encoding context
292  *
293  * \return Returns error code as specified in \ref psa_attest_err_t
294  */
295 static enum psa_attest_err_t
attest_add_profile_definition(struct attest_token_encode_ctx * token_ctx)296 attest_add_profile_definition(struct attest_token_encode_ctx *token_ctx)
297 {
298     struct q_useful_buf_c profile;
299     uint8_t buf[PROFILE_DEFINITION_MAX_SIZE];
300     uint32_t size = sizeof(buf);
301     enum tfm_plat_err_t err;
302 
303     err = tfm_attest_hal_get_profile_definition(&size, buf);
304     if (err != TFM_PLAT_ERR_SUCCESS) {
305         return PSA_ATTEST_ERR_GENERAL;
306     }
307 
308     profile.ptr = &buf;
309     profile.len = size;
310     attest_token_encode_add_tstr(token_ctx,
311                                  IAT_PROFILE_DEFINITION,
312                                  &profile);
313 
314     return PSA_ATTEST_ERR_SUCCESS;
315 }
316 
317 #if ATTEST_INCLUDE_OPTIONAL_CLAIMS
318 /*!
319  * \brief Static function to add the verification service indicator claim
320  *        to the attestation token.
321  *
322  * \param[in]  token_ctx  Token encoding context
323  *
324  * \return Returns error code as specified in \ref psa_attest_err_t
325  */
326 static enum psa_attest_err_t
attest_add_verification_service(struct attest_token_encode_ctx * token_ctx)327 attest_add_verification_service(struct attest_token_encode_ctx *token_ctx)
328 {
329     struct q_useful_buf_c service;
330     uint8_t buf[VERIFICATION_URL_MAX_SIZE];
331     uint32_t size = sizeof(buf);
332     enum tfm_plat_err_t err;
333 
334     err = tfm_attest_hal_get_verification_service(&size, buf);
335     if (err != TFM_PLAT_ERR_SUCCESS) {
336         return PSA_ATTEST_ERR_GENERAL;
337     }
338 
339     service.ptr = &buf;
340     service.len = size;
341     attest_token_encode_add_tstr(token_ctx,
342                                  IAT_VERIFICATION_SERVICE,
343                                  &service);
344 
345     return PSA_ATTEST_ERR_SUCCESS;
346 }
347 #endif /* ATTEST_INCLUDE_OPTIONAL_CLAIMS */
348 
349 #if ATTEST_TOKEN_PROFILE_PSA_IOT_1 || ATTEST_TOKEN_PROFILE_PSA_2_0_0
350 /*!
351  * \brief Static function to add boot seed claim to attestation token.
352  *
353  * \param[in]  token_ctx  Token encoding context
354  *
355  * \return Returns error code as specified in \ref psa_attest_err_t
356  */
357 static enum psa_attest_err_t
attest_add_boot_seed_claim(struct attest_token_encode_ctx * token_ctx)358 attest_add_boot_seed_claim(struct attest_token_encode_ctx *token_ctx)
359 {
360     uint8_t boot_seed[BOOT_SEED_SIZE];
361     enum tfm_plat_err_t res;
362     struct q_useful_buf_c claim_value = {0};
363     uint16_t tlv_len;
364     uint8_t *tlv_ptr = NULL;
365     int32_t found = 0;
366 
367     /* First look up BOOT_SEED in boot status, it might comes from bootloader */
368     found = attest_get_tlv_by_id(BOOT_SEED, &tlv_len, &tlv_ptr);
369     if (found == 1) {
370         claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
371         claim_value.len = tlv_len;
372     } else {
373         /* If not found in boot status then use callback function to get it
374          * from runtime SW
375          */
376         res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed);
377         if (res != TFM_PLAT_ERR_SUCCESS) {
378             return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
379         }
380         claim_value.ptr = boot_seed;
381         claim_value.len = BOOT_SEED_SIZE;
382     }
383 
384     attest_token_encode_add_bstr(token_ctx,
385                                  IAT_BOOT_SEED,
386                                  &claim_value);
387 
388     return PSA_ATTEST_ERR_SUCCESS;
389 }
390 
391 /*!
392  * \brief Static function to add caller id claim to attestation token.
393  *
394  * \param[in]  token_ctx  Token encoding context
395  *
396  * \return Returns error code as specified in \ref psa_attest_err_t
397  */
398 static enum psa_attest_err_t
attest_add_caller_id_claim(struct attest_token_encode_ctx * token_ctx)399 attest_add_caller_id_claim(struct attest_token_encode_ctx *token_ctx)
400 {
401     enum psa_attest_err_t res;
402     int32_t caller_id;
403 
404     res = attest_get_caller_client_id(&caller_id);
405     if (res != PSA_ATTEST_ERR_SUCCESS) {
406         return res;
407     }
408 
409     attest_token_encode_add_integer(token_ctx,
410                                     IAT_CLIENT_ID,
411                                     (int64_t)caller_id);
412 
413     return PSA_ATTEST_ERR_SUCCESS;
414 }
415 
416 #if ATTEST_INCLUDE_OPTIONAL_CLAIMS
417 /*!
418  * \brief Static function to add certification reference claim to attestation
419  *        token.
420  *
421  * \param[in]  token_ctx  Token encoding context
422  *
423  * \return Returns error code as specified in \ref psa_attest_err_t
424  */
425 static enum psa_attest_err_t
attest_add_cert_ref_claim(struct attest_token_encode_ctx * token_ctx)426 attest_add_cert_ref_claim(struct attest_token_encode_ctx *token_ctx)
427 {
428     uint8_t buf[CERTIFICATION_REF_MAX_SIZE];
429     enum tfm_plat_err_t res_plat;
430     uint32_t size = sizeof(buf);
431     struct q_useful_buf_c claim_value = {0};
432     uint16_t tlv_len;
433     uint8_t *tlv_ptr = NULL;
434     int32_t found = 0;
435 
436     /* First look up the certification reference in the boot status, it might
437      * comes from the bootloader.
438      */
439     found = attest_get_tlv_by_id(CERT_REF, &tlv_len, &tlv_ptr);
440     if (found == 1) {
441         claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
442         claim_value.len = tlv_len;
443     } else {
444         /* If not found in boot status then use callback function to get it
445          * from runtime SW
446          */
447         res_plat = tfm_plat_get_cert_ref(&size, buf);
448         if (res_plat != TFM_PLAT_ERR_SUCCESS) {
449             return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
450         }
451         claim_value.ptr = buf;
452         claim_value.len = size;
453     }
454 
455     attest_token_encode_add_tstr(token_ctx,
456                                  IAT_CERTIFICATION_REFERENCE,
457                                  &claim_value);
458 
459     return PSA_ATTEST_ERR_SUCCESS;
460 }
461 #endif /* ATTEST_INCLUDE_OPTIONAL_CLAIMS */
462 #endif /* ATTEST_TOKEN_PROFILE_PSA_IOT_1 || ATTEST_TOKEN_PROFILE_PSA_2_0_0 */
463 
464 #if ATTEST_TOKEN_PROFILE_ARM_CCA
465 /*!
466  * \brief Static function to add the platform hash algorithm identifier
467  *        claim to the attestation token. This hash algo is used for extending
468  *        the boot measurements.
469  *
470  * \param[in]  token_ctx  Token encoding context
471  * \param[in]  challenge  Pointer to buffer which stores the hash algo.
472  *
473  * \return Returns error code as specified in \ref psa_attest_err_t
474  */
475 static enum psa_attest_err_t
attest_add_hash_algo_claim(struct attest_token_encode_ctx * token_ctx)476 attest_add_hash_algo_claim(struct attest_token_encode_ctx *token_ctx)
477 {
478     struct q_useful_buf_c hash_algo;
479     uint8_t buf[PLATFORM_HASH_ALGO_ID_MAX_SIZE];
480     uint32_t size = sizeof(buf);
481     enum tfm_plat_err_t err;
482 
483     err = tfm_attest_hal_get_platform_hash_algo(&size, buf);
484     if (err != TFM_PLAT_ERR_SUCCESS) {
485         return PSA_ATTEST_ERR_GENERAL;
486     }
487 
488     hash_algo.ptr = &buf;
489     hash_algo.len = size;
490     attest_token_encode_add_tstr(token_ctx,
491                                  IAT_PLATFORM_HASH_ALGO_ID,
492                                  &hash_algo);
493 
494     return PSA_ATTEST_ERR_SUCCESS;
495 }
496 
497 /*!
498  * \brief Static function to add the platform hash algorithm identifier
499  *        claim to the attestation token. This hash algo is used for extending
500  *        the boot measurements.
501  *
502  * \param[in]  token_ctx  Token encoding context
503  * \param[in]  challenge  Pointer to buffer which stores the hash algo.
504  *
505  * \return Returns error code as specified in \ref psa_attest_err_t
506  */
507 static enum psa_attest_err_t
attest_add_platform_config_claim(struct attest_token_encode_ctx * token_ctx)508 attest_add_platform_config_claim(struct attest_token_encode_ctx *token_ctx)
509 {
510 
511     uint8_t plat_config[PLATFORM_CONFIG_MAX_SIZE];
512     enum tfm_plat_err_t res;
513     uint32_t size = sizeof(plat_config);
514     struct q_useful_buf_c claim_value;
515 
516     res = tfm_attest_hal_get_platform_config(&size, plat_config);
517     if (res != TFM_PLAT_ERR_SUCCESS) {
518         return PSA_ATTEST_ERR_GENERAL;
519     }
520 
521     claim_value.ptr = plat_config;
522     claim_value.len = size;
523 
524     attest_token_encode_add_bstr(token_ctx,
525                                  IAT_PLATFORM_CONFIG,
526                                  &claim_value);
527 
528     return PSA_ATTEST_ERR_SUCCESS;
529 }
530 #endif /* ATTEST_TOKEN_PROFILE_ARM_CCA */
531 
532 /*!
533  * \brief Static function to add the nonce claim to attestation token.
534  *
535  * \param[in]  token_ctx  Token encoding context
536  * \param[in]  nonce      Pointer to buffer which stores the challenge
537  *
538  * \return Returns error code as specified in \ref psa_attest_err_t
539  */
540 static enum psa_attest_err_t
attest_add_nonce_claim(struct attest_token_encode_ctx * token_ctx,const struct q_useful_buf_c * nonce)541 attest_add_nonce_claim(struct attest_token_encode_ctx   *token_ctx,
542                        const struct q_useful_buf_c      *nonce)
543 {
544     attest_token_encode_add_bstr(token_ctx,
545                                  IAT_NONCE,
546                                  nonce);
547 
548     return PSA_ATTEST_ERR_SUCCESS;
549 }
550 
551 /*!
552  * \brief Static function to verify the input challenge size
553  *
554  *  Only discrete sizes are accepted.
555  *
556  * \param[in] challenge_size  Size of challenge object in bytes.
557  *
558  * \retval  PSA_ATTEST_ERR_SUCCESS
559  * \retval  PSA_ATTEST_ERR_INVALID_INPUT
560  */
attest_verify_challenge_size(size_t challenge_size)561 static enum psa_attest_err_t attest_verify_challenge_size(size_t challenge_size)
562 {
563     switch (challenge_size) {
564     /* Intentional fall through */
565     case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32:
566     case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48:
567     case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64:
568         return PSA_ATTEST_ERR_SUCCESS;
569     }
570 
571     return PSA_ATTEST_ERR_INVALID_INPUT;
572 }
573 
574 #ifdef INCLUDE_TEST_CODE
575 /*!
576  * \brief Static function to get the option flags from challenge object
577  *
578  * Option flags are passed in if the challenge is 64 bytes long and the last
579  * 60 bytes are all 0. In this case the first 4 bytes of the challenge is
580  * the option flags for test.
581  *
582  * See flag definition in attest_token.h
583  *
584  * \param[in]  challenge     Structure to carry the challenge value:
585  *                           pointer + challeng's length.
586  * \param[out] option_flags  Flags to select different custom options,
587  *                           for example \ref TOKEN_OPT_OMIT_CLAIMS.
588  * \param[out] key_select    Selects which attestation key to sign with.
589  */
attest_get_option_flags(struct q_useful_buf_c * challenge,uint32_t * option_flags,int32_t * key_select)590 static void attest_get_option_flags(struct q_useful_buf_c *challenge,
591                                     uint32_t *option_flags,
592                                     int32_t  *key_select)
593 {
594     uint32_t found_option_flags = 1;
595     uint32_t option_flags_size = sizeof(uint32_t);
596     uint8_t *challenge_end;
597     uint8_t *challenge_data;
598 
599     /* Get option flags if there is encoded in the challenge object */
600     if ((challenge->len == PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64) &&
601         (challenge->ptr)) {
602         challenge_end  = ((uint8_t *)challenge->ptr) + challenge->len;
603         challenge_data = ((uint8_t *)challenge->ptr) + option_flags_size;
604 
605         /* Compare bytes(4-63) with 0 */
606         while (challenge_data < challenge_end) {
607             if (*challenge_data++ != 0) {
608                 found_option_flags = 0;
609                 break;
610             }
611         }
612     } else {
613         found_option_flags = 0;
614     }
615 
616     if (found_option_flags) {
617         (void)memcpy(option_flags, challenge->ptr, option_flags_size);
618 
619         /* Lower three bits are the key select */
620         *key_select = *option_flags & 0x7;
621     } else {
622         *option_flags = 0;
623         *key_select = 0;
624     }
625 }
626 #endif /* INCLUDE_TEST_CODE */
627 
attest_get_t_cose_algorithm(int32_t * cose_algorithm_id)628 static enum psa_attest_err_t attest_get_t_cose_algorithm(
629         int32_t *cose_algorithm_id)
630 {
631     psa_status_t status;
632     psa_key_attributes_t attr;
633     psa_key_handle_t handle = TFM_BUILTIN_KEY_ID_IAK;
634     psa_key_type_t key_type;
635 
636     status = psa_get_key_attributes(handle, &attr);
637     if (status != PSA_SUCCESS) {
638         return PSA_ATTEST_ERR_GENERAL;
639     }
640 
641     key_type = psa_get_key_type(&attr);
642     if (status != PSA_SUCCESS) {
643         return PSA_ATTEST_ERR_GENERAL;
644     }
645 
646     if (PSA_KEY_TYPE_IS_ECC(key_type) &&
647         PSA_KEY_TYPE_ECC_GET_FAMILY(key_type) == PSA_ECC_FAMILY_SECP_R1) {
648         switch (psa_get_key_bits(&attr)) {
649         case 256:
650             *cose_algorithm_id = T_COSE_ALGORITHM_ES256;
651             break;
652         case 384:
653             *cose_algorithm_id = T_COSE_ALGORITHM_ES384;
654             break;
655         case 512:
656             *cose_algorithm_id = T_COSE_ALGORITHM_ES512;
657             break;
658         default:
659             return PSA_ATTEST_ERR_GENERAL;
660         }
661     } else if (key_type == PSA_KEY_TYPE_HMAC) {
662         switch (psa_get_key_bits(&attr)) {
663         case 256:
664             *cose_algorithm_id = T_COSE_ALGORITHM_HMAC256;
665             break;
666         case 384:
667             *cose_algorithm_id = T_COSE_ALGORITHM_HMAC384;
668             break;
669         case 512:
670             *cose_algorithm_id = T_COSE_ALGORITHM_HMAC512;
671             break;
672         default:
673             return PSA_ATTEST_ERR_GENERAL;
674         }
675     } else {
676         return PSA_ATTEST_ERR_GENERAL;
677     }
678 
679     return PSA_ATTEST_ERR_SUCCESS;
680 }
681 
682 #if ATTEST_TOKEN_PROFILE_PSA_IOT_1 || ATTEST_TOKEN_PROFILE_PSA_2_0_0
683     static enum psa_attest_err_t
684     (*claim_query_funcs[])(struct attest_token_encode_ctx *) = {
685         &attest_add_boot_seed_claim,
686         &attest_add_instance_id_claim,
687         &attest_add_implementation_id_claim,
688         &attest_add_caller_id_claim,
689         &attest_add_security_lifecycle_claim,
690         &attest_add_all_sw_components,
691         &attest_add_profile_definition,
692 #if ATTEST_INCLUDE_OPTIONAL_CLAIMS
693         &attest_add_verification_service,
694         &attest_add_cert_ref_claim
695 #endif
696     };
697 #elif ATTEST_TOKEN_PROFILE_ARM_CCA
698 
699     static enum psa_attest_err_t
700     (*claim_query_funcs[])(struct attest_token_encode_ctx *) = {
701         &attest_add_instance_id_claim,
702         &attest_add_implementation_id_claim,
703         &attest_add_security_lifecycle_claim,
704         &attest_add_all_sw_components,
705         &attest_add_profile_definition,
706         &attest_add_hash_algo_claim,
707         &attest_add_platform_config_claim,
708 #if ATTEST_INCLUDE_OPTIONAL_CLAIMS
709         &attest_add_verification_service,
710 #endif
711     };
712 #endif
713 
714 /*!
715  * \brief Static function to create the initial attestation token
716  *
717  * \param[in]  challenge        Structure to carry the challenge value:
718  *                              pointer + challeng's length
719  * \param[in]  token            Structure to carry the token info, where to
720  *                              create it: pointer + buffer's length
721  * \param[out] completed_token  Structure to carry the info about the created
722  *                              token: pointer + final token's length
723  *
724  * \return Returns error code as specified in \ref psa_attest_err_t
725  */
726 static enum psa_attest_err_t
attest_create_token(struct q_useful_buf_c * challenge,struct q_useful_buf * token,struct q_useful_buf_c * completed_token)727 attest_create_token(struct q_useful_buf_c *challenge,
728                     struct q_useful_buf   *token,
729                     struct q_useful_buf_c *completed_token)
730 {
731     enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
732     enum attest_token_err_t token_err;
733     struct attest_token_encode_ctx attest_token_ctx;
734     int32_t key_select = 0;
735     uint32_t option_flags = 0;
736     int i;
737     int32_t cose_algorithm_id;
738 
739     attest_err = attest_get_t_cose_algorithm(&cose_algorithm_id);
740     if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
741         return attest_err;
742     }
743 
744 #ifdef INCLUDE_TEST_CODE
745     attest_get_option_flags(challenge, &option_flags, &key_select);
746     if (option_flags) {
747         /* If any option flags are provided (TOKEN_OPT_OMIT_CLAIMS or
748          * TOKEN_OPT_SHORT_CIRCUIT_SIGN) then force the cose_algorithm_id
749          * to be either:
750          *  - T_COSE_ALGORITHM_ES256 or  (SYMMETRIC_INITIAL_ATTESTATION=OFF)
751          *  - T_COSE_ALGORITHM_HMAC256   (SYMMETRIC_INITIAL_ATTESTATION=ON)
752          * for testing purposes to match with expected minimal token.
753          */
754         /* ESxxx range is smaller than 0; HMACxxx range is greater than 0 */
755         cose_algorithm_id = cose_algorithm_id < 0 ? T_COSE_ALGORITHM_ES256 :
756                                                     T_COSE_ALGORITHM_HMAC256;
757     }
758 #endif
759 
760     /* Get started creating the token. This sets up the CBOR and COSE contexts
761      * which causes the COSE headers to be constructed.
762      */
763     token_err = attest_token_encode_start(&attest_token_ctx,
764                                           option_flags,      /* option_flags */
765                                           key_select,        /* key_select   */
766                                           cose_algorithm_id, /* alg_select   */
767                                           token);
768 
769     if (token_err != ATTEST_TOKEN_ERR_SUCCESS) {
770         attest_err = error_mapping_to_psa_attest_err_t(token_err);
771         goto error;
772     }
773 
774     attest_err = attest_add_nonce_claim(&attest_token_ctx,
775                                         challenge);
776     if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
777         goto error;
778     }
779 
780     if (!(option_flags & TOKEN_OPT_OMIT_CLAIMS)) {
781         for (i = 0; i < ARRAY_LENGTH(claim_query_funcs); ++i) {
782             /* Calling the attest_add_XXX_claim functions */
783             attest_err = claim_query_funcs[i](&attest_token_ctx);
784             if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
785                 goto error;
786             }
787         }
788     }
789 
790     /* Finish up creating the token. This is where the actual signature
791      * is generated. This finishes up the CBOR encoding too.
792      */
793     token_err = attest_token_encode_finish(&attest_token_ctx, completed_token);
794     attest_err = error_mapping_to_psa_attest_err_t(token_err);
795 
796 error:
797     return attest_err;
798 }
799 
800 psa_status_t
initial_attest_get_token(const void * challenge_buf,size_t challenge_size,void * token_buf,size_t token_buf_size,size_t * token_size)801 initial_attest_get_token(const void *challenge_buf, size_t challenge_size,
802                          void *token_buf, size_t token_buf_size,
803                          size_t *token_size)
804 {
805     enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
806     struct q_useful_buf_c challenge;
807     struct q_useful_buf token;
808     struct q_useful_buf_c completed_token;
809 
810     challenge.ptr = challenge_buf;
811     challenge.len = challenge_size;
812     token.ptr = token_buf;
813     token.len = token_buf_size;
814 
815     attest_err = attest_verify_challenge_size(challenge.len);
816     if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
817         goto error;
818     }
819 
820     if (token.len == 0) {
821         attest_err = PSA_ATTEST_ERR_INVALID_INPUT;
822         goto error;
823     }
824 
825     attest_err = attest_create_token(&challenge, &token, &completed_token);
826     if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
827         goto error;
828     }
829 
830     *token_size  = completed_token.len;
831 
832 error:
833     return error_mapping_to_psa_status_t(attest_err);
834 }
835 
836 psa_status_t
initial_attest_get_token_size(const size_t challenge_size,size_t * token_size)837 initial_attest_get_token_size(const size_t challenge_size,
838                               size_t *token_size)
839 {
840     enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
841     struct q_useful_buf_c challenge;
842     struct q_useful_buf token;
843     struct q_useful_buf_c completed_token;
844 
845     /* Only the size of the challenge is needed */
846     challenge.ptr = NULL;
847     challenge.len = challenge_size;
848 
849     /* Special value to get the size of the token, but token is not created */
850     token.ptr = NULL;
851     token.len = INT32_MAX;
852 
853     attest_err = attest_verify_challenge_size(challenge_size);
854     if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
855         goto error;
856     }
857 
858     attest_err = attest_create_token(&challenge, &token, &completed_token);
859     if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
860         goto error;
861     }
862 
863     *token_size = completed_token.len;
864 
865 error:
866     return error_mapping_to_psa_status_t(attest_err);
867 }
868