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 &sect;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 &sect;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