1 /*
2 * Copyright (c) 2019-2023, 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 "attest_key.h"
10 #include <stdint.h>
11 #include <stddef.h>
12 #include "config_tfm.h"
13 #include "tfm_plat_defs.h"
14 #include "tfm_plat_device_id.h"
15 #include "t_cose_standard_constants.h"
16 #include "q_useful_buf.h"
17 #include "qcbor/qcbor.h"
18 #include "tfm_crypto_defs.h"
19
20 #define ATTEST_ECC_PUBLIC_KEY_SIZE \
21 PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(ATTEST_KEY_BITS)
22
23 /**
24 * The size of X and Y coordinate in 2 parameter style EC public
25 * key. Format is as defined in [COSE (RFC 8152)]
26 * (https://tools.ietf.org/html/rfc8152) and [SEC 1: Elliptic Curve
27 * Cryptography](http://www.secg.org/sec1-v2.pdf).
28 *
29 * This size is well-known and documented in public standards.
30 */
31 #define ECC_P256_COORD_SIZE PSA_BITS_TO_BYTES(256) /* 256 bits -> 32 bytes */
32
33 static uint8_t attestation_public_key[ATTEST_ECC_PUBLIC_KEY_SIZE];
34 static size_t attestation_public_key_len = 0;
35 static psa_ecc_family_t attestation_key_curve;
36
37 #if ATTEST_INCLUDE_COSE_KEY_ID
38 /* 32bytes */
39 static uint8_t attestation_key_id[PSA_HASH_LENGTH(PSA_ALG_SHA_256)];
40 #endif
41
42 /* Instance ID for asymmetric IAK */
43 static uint8_t instance_id_buf[INSTANCE_ID_MAX_SIZE];
44 static size_t instance_id_len = 0U;
45
attest_load_public_key(void)46 static enum psa_attest_err_t attest_load_public_key(void)
47 {
48 psa_status_t crypto_res;
49 psa_key_attributes_t attr;
50 psa_key_handle_t handle = TFM_BUILTIN_KEY_ID_IAK;
51
52 crypto_res = psa_get_key_attributes(handle, &attr);
53 if (crypto_res != PSA_SUCCESS) {
54 return PSA_ATTEST_ERR_GENERAL;
55 }
56
57 attestation_key_curve = PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(&attr));
58
59 crypto_res = psa_export_public_key(handle, attestation_public_key,
60 sizeof(attestation_public_key),
61 &attestation_public_key_len);
62 if (crypto_res != PSA_SUCCESS) {
63 return PSA_ATTEST_ERR_GENERAL;
64 }
65
66 return PSA_ATTEST_ERR_SUCCESS;
67 }
68
69 /*!
70 * \brief Static function to calculate instance id.
71 *
72 * \return Returns error code as specified in \ref psa_attest_err_t
73 */
attest_calc_instance_id(void)74 static enum psa_attest_err_t attest_calc_instance_id(void)
75 {
76 psa_status_t crypto_res;
77 enum psa_attest_err_t attest_res;
78 psa_hash_operation_t hash = psa_hash_operation_init();
79
80 if (attestation_public_key_len == 0U) {
81 attest_res = attest_load_public_key();
82 if (attest_res != PSA_ATTEST_ERR_SUCCESS) {
83 return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
84 }
85 }
86
87 crypto_res = psa_hash_setup(&hash, PSA_ALG_SHA_256);
88 if (crypto_res != PSA_SUCCESS) {
89 return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
90 }
91
92 crypto_res = psa_hash_update(&hash, attestation_public_key,
93 attestation_public_key_len);
94 if (crypto_res != PSA_SUCCESS) {
95 return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
96 }
97
98 /* The hash starts from the second byte, leaving the first free. */
99 crypto_res = psa_hash_finish(&hash, instance_id_buf + 1,
100 INSTANCE_ID_MAX_SIZE - 1,
101 &instance_id_len);
102 if (crypto_res != PSA_SUCCESS) {
103 return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
104 }
105
106 /* Add UEID type byte 0x01 */
107 instance_id_buf[0] = 0x01;
108 instance_id_len = instance_id_len + 1;
109
110 return PSA_ATTEST_ERR_SUCCESS;
111 }
112
113 enum psa_attest_err_t
attest_get_instance_id(struct q_useful_buf_c * id_buf)114 attest_get_instance_id(struct q_useful_buf_c *id_buf)
115 {
116 if (instance_id_len == 0U) {
117 if (attest_calc_instance_id() != PSA_ATTEST_ERR_SUCCESS) {
118 return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
119 }
120 }
121
122 if (id_buf == NULL) {
123 return PSA_ATTEST_ERR_GENERAL;
124 }
125
126 id_buf->ptr = instance_id_buf;
127 id_buf->len = instance_id_len;
128
129 return PSA_ATTEST_ERR_SUCCESS;
130 }
131
132 #if ATTEST_INCLUDE_COSE_KEY_ID
133
134 #define MAX_ENCODED_COSE_KEY_SIZE \
135 1 + /* 1 byte to encode map */ \
136 2 + /* 2 bytes to encode key type */ \
137 2 + /* 2 bytes to encode curve */ \
138 2 * /* the X and Y coordinates at 32 bytes each */ \
139 (ECC_P256_COORD_SIZE + 1 + 2)
140
141 /**
142 * \brief Map PSA curve types to the curve type defined by RFC 8152
143 * chapter 13.1.
144 *
145 * \param[in] psa_curve PSA curve type definition \ref psa_ecc_family_t.
146 *
147 * \return Return COSE curve type. If mapping is not possible then return
148 * with -1.
149 */
150 static inline int32_t
attest_map_psa_ecc_curve_to_cose_ecc_curve(psa_ecc_family_t psa_curve)151 attest_map_psa_ecc_curve_to_cose_ecc_curve(psa_ecc_family_t psa_curve)
152 {
153 int32_t cose_curve;
154
155 /* Note: Mapping is not complete. */
156 switch (psa_curve) {
157 case PSA_ECC_FAMILY_SECP_R1:
158 cose_curve = COSE_ELLIPTIC_CURVE_P_256;
159 break;
160 default:
161 /* Initial attestation currently supports only ECDSA P256 signature
162 * therefore the other options are not mapped to save object code
163 */
164 cose_curve = -1;
165 }
166
167 return cose_curve;
168 }
169
170 /**
171 * \brief CBOR encode a public key as a \c COSE_Key
172 *
173 * \param[in] psa_ecc_curve PSA elliptic curve identifiers
174 * \param[in] attest_public_key Pointer and length of the buffer, which
175 * holds the attestation public key encoded as
176 * defined by SEC1 §2.3.3.
177 * \param[in] buffer_for_cose_key Pointer and length of buffer into which
178 * the encoded \c COSE_Key is put.
179 * \param[out] cose_key Pointer and length of the encoded
180 * \c COSE_Key.
181 *
182 * \return This returns one of the error codes defined by \ref psa_attest_err_t.
183 *
184 * \c COSE_Key is the COSE-defined format for serializing a key for
185 * transmission in a protocol. This function encodes an EC public key
186 * expressed as an X and Y coordinate.
187 */
188 static enum psa_attest_err_t
attest_encode_key_to_cose_key(psa_ecc_family_t psa_ecc_curve,struct q_useful_buf_c attest_public_key,struct q_useful_buf buffer_for_cose_key,struct q_useful_buf_c * cose_key)189 attest_encode_key_to_cose_key(psa_ecc_family_t psa_ecc_curve,
190 struct q_useful_buf_c attest_public_key,
191 struct q_useful_buf buffer_for_cose_key,
192 struct q_useful_buf_c *cose_key)
193 {
194 QCBORError qcbor_result;
195 QCBOREncodeContext cbor_encode_ctx;
196 struct q_useful_buf_c x_coord;
197 struct q_useful_buf_c y_coord;
198 struct q_useful_buf_c encoded_key_id;
199 size_t key_coord_len;
200 int32_t cose_ecc_curve;
201 uint8_t *x_coord_ptr;
202 uint8_t *y_coord_ptr;
203 Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_x_coord, ECC_P256_COORD_SIZE);
204 Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_y_coord, ECC_P256_COORD_SIZE);
205
206 /* Key is made up of a 0x4 byte and two coordinates
207 * 0x04 || X_COORD || Y_COORD
208 */
209 key_coord_len = (attest_public_key.len - 1) / 2;
210 x_coord_ptr = ((uint8_t *)attest_public_key.ptr) + 1;
211 y_coord_ptr = ((uint8_t *)attest_public_key.ptr) + 1 + key_coord_len;
212
213 /* Place they key parts into the x and y buffers. Stars at index 1 to skip
214 * the 0x4 byte.
215 */
216 x_coord = q_useful_buf_copy_ptr(buffer_for_x_coord,
217 x_coord_ptr,
218 key_coord_len);
219
220 y_coord = q_useful_buf_copy_ptr(buffer_for_y_coord,
221 y_coord_ptr,
222 key_coord_len);
223
224 if (q_useful_buf_c_is_null(x_coord) || q_useful_buf_c_is_null(y_coord)) {
225 return PSA_ATTEST_ERR_GENERAL;
226 }
227
228 cose_ecc_curve = attest_map_psa_ecc_curve_to_cose_ecc_curve(psa_ecc_curve);
229 if (cose_ecc_curve == -1) {
230 return PSA_ATTEST_ERR_GENERAL;
231 }
232
233 /* Encode it into a COSE_Key structure */
234 QCBOREncode_Init(&cbor_encode_ctx, buffer_for_cose_key);
235 QCBOREncode_OpenMap(&cbor_encode_ctx);
236 QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
237 COSE_KEY_COMMON_KTY,
238 COSE_KEY_TYPE_EC2);
239 QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
240 COSE_KEY_PARAM_CRV,
241 cose_ecc_curve);
242 QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
243 COSE_KEY_PARAM_X_COORDINATE,
244 x_coord);
245 QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
246 COSE_KEY_PARAM_Y_COORDINATE,
247 y_coord);
248 QCBOREncode_CloseMap(&cbor_encode_ctx);
249
250 qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &encoded_key_id);
251 if (qcbor_result != QCBOR_SUCCESS) {
252 /* Mainly means that the COSE_Key was too big for buffer_for_cose_key */
253 return PSA_ATTEST_ERR_GENERAL;
254 }
255
256 /* Finish up and return */
257 *cose_key = encoded_key_id;
258
259 return PSA_ATTEST_ERR_SUCCESS;
260 }
261
262 /**
263 * \brief Make a key ID based on the public key to go in the kid
264 * unprotected header.
265 *
266 * \param[in] psa_ecc_curve PSA elliptic curve identifiers.
267 * \param[in] attest_public_key Pointer and length of the buffer, which
268 * holds the attestation public key
269 * encoded as defined by SEC1 §2.3.3.
270 * \param[in] buffer_for_attest_key_id Pointer and length of buffer into which
271 * the encoded \c COSE_Key is put.
272 * \param[out] attest_key_id Pointer and length of the attestation
273 * key id.
274 *
275 * \return This returns one of the error codes defined by \ref psa_attest_err_t.
276 */
277 enum psa_attest_err_t
attest_get_cose_key_id(psa_ecc_family_t psa_ecc_curve,struct q_useful_buf_c attest_public_key,struct q_useful_buf buffer_for_attest_key_id,struct q_useful_buf_c * attest_key_id)278 attest_get_cose_key_id(psa_ecc_family_t psa_ecc_curve,
279 struct q_useful_buf_c attest_public_key,
280 struct q_useful_buf buffer_for_attest_key_id,
281 struct q_useful_buf_c *attest_key_id)
282 {
283 enum psa_attest_err_t attest_res;
284 psa_status_t crypto_res;
285 struct q_useful_buf_c cose_key;
286 psa_hash_operation_t hash = psa_hash_operation_init();
287 Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_cose_key, MAX_ENCODED_COSE_KEY_SIZE);
288
289 /* Encode the attestation public key to COSE_Key structure */
290 attest_res = attest_encode_key_to_cose_key(psa_ecc_curve,
291 attest_public_key,
292 buffer_for_cose_key,
293 &cose_key);
294 if(attest_res != PSA_ATTEST_ERR_SUCCESS) {
295 return attest_res;
296 }
297
298 crypto_res = psa_hash_setup(&hash, PSA_ALG_SHA_256);
299 if (crypto_res != PSA_SUCCESS) {
300 return PSA_ATTEST_ERR_GENERAL;
301 }
302
303 crypto_res = psa_hash_update(&hash, cose_key.ptr, cose_key.len);
304 if (crypto_res != PSA_SUCCESS) {
305 return PSA_ATTEST_ERR_GENERAL;
306 }
307
308 crypto_res = psa_hash_finish(&hash,
309 buffer_for_attest_key_id.ptr,
310 buffer_for_attest_key_id.len,
311 &buffer_for_attest_key_id.len);
312 if (crypto_res != PSA_SUCCESS) {
313 return PSA_ATTEST_ERR_GENERAL;
314 }
315
316 attest_key_id->ptr = buffer_for_attest_key_id.ptr;
317 attest_key_id->len = buffer_for_attest_key_id.len;
318
319 return PSA_ATTEST_ERR_SUCCESS;
320 }
321
322 enum psa_attest_err_t
attest_get_initial_attestation_key_id(struct q_useful_buf_c * attest_key_id)323 attest_get_initial_attestation_key_id(struct q_useful_buf_c *attest_key_id)
324 {
325 enum psa_attest_err_t attest_res;
326 static uint8_t attest_key_id_calculated;
327 struct q_useful_buf_c buffer_for_attest_public_key;
328 struct q_useful_buf buffer_for_attest_key_id;
329
330 buffer_for_attest_key_id.ptr = attestation_key_id;
331 buffer_for_attest_key_id.len = PSA_HASH_LENGTH(PSA_ALG_SHA_256);
332
333 if (attestation_public_key_len == 0U) {
334 attest_res = attest_load_public_key();
335 if (attest_res != PSA_ATTEST_ERR_SUCCESS) {
336 return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
337 }
338 }
339
340 /* Needs to calculate only once */
341 if (attest_key_id_calculated == 0) {
342 buffer_for_attest_public_key.ptr = attestation_public_key;
343 buffer_for_attest_public_key.len = attestation_public_key_len;
344
345 attest_res = attest_get_cose_key_id(attestation_key_curve,
346 buffer_for_attest_public_key,
347 buffer_for_attest_key_id,
348 attest_key_id);
349 if (attest_res != PSA_ATTEST_ERR_SUCCESS) {
350 return attest_res;
351 }
352 attest_key_id_calculated = 1;
353 } else {
354 attest_key_id->ptr = (const void *)buffer_for_attest_key_id.ptr;
355 attest_key_id->len = buffer_for_attest_key_id.len;
356 }
357
358 return PSA_ATTEST_ERR_SUCCESS;
359 }
360 #endif /* ATTEST_INCLUDE_COSE_KEY_ID */
361