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