1 /*
2  * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3  * Copyright (c) 2018-2019, Laurence Lundblade.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  */
8 
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12 
13 #include "attest_key.h"
14 #include "config_tfm.h"
15 #include "tfm_plat_defs.h"
16 #include "psa/crypto.h"
17 #include "tfm_crypto_defs.h"
18 
19 /* Only support HMAC as MAC algorithm in COSE_Mac0 so far */
20 #define SYMMETRIC_IAK_MAX_SIZE        PSA_MAC_MAX_SIZE
21 
22 /* Hash algorithm for calculating Instance ID */
23 #define INSTANCE_ID_HASH_ALG          PSA_ALG_SHA_256
24 
25 /* Length of kid buffer */
26 #define KID_BUF_LEN                   32
27 
28 /* Instance ID for symmetric IAK */
29 static uint8_t instance_id_buf[PSA_HASH_LENGTH(INSTANCE_ID_HASH_ALG) + 1];
30 static size_t instance_id_len = 0;
31 
32 #if ATTEST_INCLUDE_COSE_KEY_ID
33 /* kid buffer */
34 static uint8_t kid_buf[KID_BUF_LEN];
35 /* Actual kid length */
36 static size_t kid_len = 0;
37 #endif
38 
39 /**
40  * \brief Static function to execute hash computation of symmetric IAK once.
41  *
42  * \param[in]  iak_buf      Buffer containing the IAK raw data
43  * \param[in]  iak_len      The length of IAK raw data
44  * \param[out] hash_buf     The buffer to be written with hash data
45  * \param[in]  hash_size    The size of hash_buf
46  * \param[out] hash_len     The actual length of hash data
47  *
48  * \return Returns error code as specified in \ref psa_status_t
49  */
symmetric_iak_hash(const uint8_t * iak_buf,size_t iak_len,uint8_t * hash_buf,size_t hash_size,size_t * hash_len)50 static psa_status_t symmetric_iak_hash(const uint8_t *iak_buf,
51                                        size_t        iak_len,
52                                        uint8_t       *hash_buf,
53                                        size_t        hash_size,
54                                        size_t        *hash_len)
55 {
56     psa_hash_operation_t hash_op = psa_hash_operation_init();
57     psa_status_t status;
58 
59     if (!iak_buf || !hash_buf || !hash_len) {
60         return PSA_ERROR_INVALID_ARGUMENT;
61     }
62 
63     status = psa_hash_setup(&hash_op, INSTANCE_ID_HASH_ALG);
64     if (status != PSA_SUCCESS) {
65         return status;
66     }
67 
68     status = psa_hash_update(&hash_op, iak_buf, iak_len);
69     if (status != PSA_SUCCESS) {
70         return status;
71     }
72 
73     status = psa_hash_finish(&hash_op, hash_buf, hash_size, hash_len);
74 
75     return status;
76 }
77 
78 /*
79  * Hash a symmetric Initial Attestation Key (IAK) twice to get the Instance ID.
80  *
81  * \note Please note that this function will corrupt the original IAK data in
82  *       iak_buf.
83  *       It can save a 32-byte buffer to put the intermediate data of the first
84  *       hash into iak_buf.
85  */
attest_calc_instance_id(void)86 static psa_status_t attest_calc_instance_id(void)
87 {
88     psa_status_t status;
89     /* Leave the first byte for UEID type byte */
90     uint8_t *id_ptr = instance_id_buf + 1;
91     size_t id_len = sizeof(instance_id_buf) - 1;
92     uint8_t iak_buf[SYMMETRIC_IAK_MAX_SIZE];
93     size_t iak_len;
94 
95     status = psa_export_key(TFM_BUILTIN_KEY_ID_IAK, iak_buf, sizeof(iak_buf),
96                             &iak_len);
97     if (status != PSA_SUCCESS) {
98         instance_id_len = 0;
99         return status;
100     }
101 
102     status = symmetric_iak_hash(iak_buf, iak_len, id_ptr, id_len,
103                                 &instance_id_len);
104     if (status != PSA_SUCCESS) {
105         instance_id_len = 0;
106         return status;
107     }
108 
109     /*
110      * instance_id_len = SHA-256 block size < key_len <= key_buf size
111      * It should be safe to directly copy without boundary check.
112      */
113     memcpy(iak_buf, id_ptr, instance_id_len);
114 
115     status = symmetric_iak_hash(iak_buf, instance_id_len, id_ptr, id_len,
116                                 &instance_id_len);
117     if (status == PSA_SUCCESS) {
118         /* Add UEID type byte 0x01 */
119         instance_id_buf[0] = 0x01;
120         instance_id_len++;
121     } else {
122         instance_id_len = 0;
123     }
124 
125     return status;
126 }
127 
128 enum psa_attest_err_t
attest_get_instance_id(struct q_useful_buf_c * id_buf)129 attest_get_instance_id(struct q_useful_buf_c *id_buf)
130 {
131     enum psa_attest_err_t err;
132 
133     if (!id_buf) {
134         return PSA_ATTEST_ERR_GENERAL;
135     }
136 
137     if (instance_id_len == 0U) {
138         err = attest_calc_instance_id();
139         if (err != PSA_ATTEST_ERR_SUCCESS) {
140             return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
141         }
142     }
143 
144     id_buf->ptr = instance_id_buf;
145     id_buf->len = instance_id_len;
146 
147     return PSA_ATTEST_ERR_SUCCESS;
148 }
149 
150 #if ATTEST_INCLUDE_COSE_KEY_ID
151 enum psa_attest_err_t
attest_get_initial_attestation_key_id(struct q_useful_buf_c * attest_key_id)152 attest_get_initial_attestation_key_id(struct q_useful_buf_c *attest_key_id)
153 {
154     enum tfm_plat_err_t plat_res;
155 
156     if (!attest_key_id) {
157         return PSA_ATTEST_ERR_GENERAL;
158     }
159 
160     /* The kid has not been fetched previously */
161     if (!kid_len) {
162         plat_res = tfm_plat_get_symmetric_iak_id(kid_buf,
163                                                  sizeof(kid_buf),
164                                                  &kid_len);
165         /* In case the buffer size was not checked, although unlikely */
166         if (sizeof(kid_buf) < kid_len) {
167             /*
168              * Something critical following kid_buf may be overwritten.
169              * Directly jump into fatal error handling.
170              *
171              * TODO: Should be replaced by a call to psa_panic() when it
172              * becomes available.
173              */
174             while (1) {
175                 ;
176             }
177         }
178 
179         if (plat_res != TFM_PLAT_ERR_SUCCESS) {
180             return PSA_ATTEST_ERR_GENERAL;
181         }
182     }
183 
184     attest_key_id->ptr = (const void *)&kid_buf;
185     attest_key_id->len = kid_len;
186 
187     return PSA_ATTEST_ERR_SUCCESS;
188 }
189 #endif /* ATTEST_INCLUDE_COSE_KEY_ID */
190