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