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