1 /*
2  * attest_token_encode.c
3  *
4  * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
5  * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  * See BSD-3-Clause license in README.md
10  */
11 
12 #include "attest_token.h"
13 #include "config_tfm.h"
14 #include "qcbor/qcbor.h"
15 #ifdef SYMMETRIC_INITIAL_ATTESTATION
16 #include "t_cose_mac0_sign.h"
17 #else
18 #include "t_cose_sign1_sign.h"
19 #endif
20 #include "t_cose_common.h"
21 #include "q_useful_buf.h"
22 #include "psa/crypto.h"
23 #include "attest_key.h"
24 #include "tfm_crypto_defs.h"
25 
26 
27 /**
28  * \file attest_token_encode.c
29  *
30  * \brief Attestation token creation implementation
31  */
32 
33 /**
34  * \brief Map t_cose error to attestation token error.
35  *
36  * \param[in] err   The t_cose error to map.
37  *
38  * \return the attestation token error.
39  */
t_cose_err_to_attest_err(enum t_cose_err_t err)40 static enum attest_token_err_t t_cose_err_to_attest_err(enum t_cose_err_t err)
41 {
42     switch(err) {
43 
44     case T_COSE_SUCCESS:
45         return ATTEST_TOKEN_ERR_SUCCESS;
46 
47     case T_COSE_ERR_UNSUPPORTED_HASH:
48         return ATTEST_TOKEN_ERR_HASH_UNAVAILABLE;
49 
50     case T_COSE_ERR_TOO_SMALL:
51         return ATTEST_TOKEN_ERR_TOO_SMALL;
52 
53     default:
54         /* A lot of the errors are not mapped because they are
55          * primarily internal errors that should never happen. They
56          * end up here.
57          */
58         return ATTEST_TOKEN_ERR_GENERAL;
59     }
60 }
61 
62 #ifdef SYMMETRIC_INITIAL_ATTESTATION
63 /*
64  * Outline of token creation. Much of this occurs inside
65  * t_cose_mac0_encode_parameters() and t_cose_mac0_encode_tag().
66  *
67  * - Create encoder context
68  * - Open the CBOR array that hold the \c COSE_Mac0
69  * - Write COSE Headers
70  *   - Protected Header
71  *      - Algorithm ID
72  *   - Unprotected Headers
73  *     - Key ID
74  * - Open payload bstr
75  *   - Write payload data, maybe lots of it
76  *   - Get bstr that is the encoded payload
77  * - Compute tag
78  *   - Create a separate encoder context for \c MAC_structure
79  *     - Encode CBOR context identifier
80  *     - Encode protected headers
81  *     - Encode an empty bstr for external_aad
82  *     - Add one more empty bstr that is a "fake payload"
83  *     - Close off \c MAC_structure
84  *   - Call MAC API to compute the tag of all but "fake payload" of
85  *     \c MAC_structure
86  *   - Get payload bstr ptr and length
87  *   - Update the real encoded payload into MAC operation
88  *   - Complete MAC operation
89  * - Write tag into the CBOR output
90  * - Close CBOR array holding the \c COSE_Mac0
91  */
92 
93 /*
94  * Public function. See attest_token.h
95  */
96 enum attest_token_err_t
attest_token_encode_start(struct attest_token_encode_ctx * me,uint32_t opt_flags,int32_t key_select,int32_t cose_alg_id,const struct q_useful_buf * out_buf)97 attest_token_encode_start(struct attest_token_encode_ctx *me,
98                           uint32_t opt_flags,
99                           int32_t key_select,
100                           int32_t cose_alg_id,
101                           const struct q_useful_buf *out_buf)
102 {
103     psa_key_handle_t key_handle = TFM_BUILTIN_KEY_ID_IAK;
104     struct t_cose_key attest_key;
105     enum psa_attest_err_t attest_ret;
106     enum t_cose_err_t cose_ret;
107     int32_t t_cose_options = 0;
108     enum attest_token_err_t return_value = ATTEST_TOKEN_ERR_SUCCESS;
109     struct q_useful_buf_c attest_key_id;
110 
111     /* Remember some of the configuration values */
112     me->opt_flags  = opt_flags;
113     me->key_select = key_select;
114 
115     if (opt_flags & TOKEN_OPT_SHORT_CIRCUIT_SIGN) {
116         t_cose_options |= T_COSE_OPT_SHORT_CIRCUIT_TAG;
117     }
118 
119     t_cose_mac0_sign_init(&(me->mac_ctx), t_cose_options, cose_alg_id);
120 
121     attest_key.crypto_lib = T_COSE_CRYPTO_LIB_PSA;
122     attest_key.k.key_handle = (uint64_t)key_handle;
123 
124     attest_ret = attest_get_initial_attestation_key_id(&attest_key_id);
125     if (attest_ret != PSA_ATTEST_ERR_SUCCESS) {
126         return ATTEST_TOKEN_ERR_GENERAL;
127     } else if (!attest_key_id.ptr || !attest_key_id.len) {
128         /* In case kid value is invalid, set it to NULL */
129         attest_key_id = NULL_Q_USEFUL_BUF_C;
130     }
131 
132     t_cose_mac0_set_signing_key(&(me->mac_ctx),
133                                 attest_key,
134                                 attest_key_id);
135 
136     /* Spin up the CBOR encoder */
137     QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf);
138 
139     /* This will cause the cose headers to be encoded and written into
140      *  out_buf using me->cbor_enc_ctx
141      */
142     cose_ret = t_cose_mac0_encode_parameters(&(me->mac_ctx),
143                                              &(me->cbor_enc_ctx));
144     if (cose_ret != T_COSE_SUCCESS) {
145         return_value = t_cose_err_to_attest_err(cose_ret);
146     }
147 
148     QCBOREncode_OpenMap(&(me->cbor_enc_ctx));
149 
150     return return_value;
151 }
152 
153 /*
154  * Public function. See attest_token.h
155  */
156 enum attest_token_err_t
attest_token_encode_finish(struct attest_token_encode_ctx * me,struct q_useful_buf_c * completed_token)157 attest_token_encode_finish(struct attest_token_encode_ctx *me,
158                            struct q_useful_buf_c *completed_token)
159 {
160     enum attest_token_err_t return_value = ATTEST_TOKEN_ERR_SUCCESS;
161     /* The completed and tagged encoded COSE_Mac0 */
162     struct q_useful_buf_c   completed_token_ub;
163     QCBORError              qcbor_result;
164     enum t_cose_err_t       cose_return_value;
165 
166     QCBOREncode_CloseMap(&(me->cbor_enc_ctx));
167 
168     /* -- Finish up the COSE_Mac0. This is where the MAC happens -- */
169     cose_return_value = t_cose_mac0_encode_tag(&(me->mac_ctx),
170                                                &(me->cbor_enc_ctx));
171     if (cose_return_value) {
172         /* Main errors are invoking the tagging */
173         return_value = t_cose_err_to_attest_err(cose_return_value);
174         goto Done;
175     }
176 
177     /* Finally close off the CBOR formatting and get the pointer and length
178      * of the resulting COSE_Mac0
179      */
180     qcbor_result = QCBOREncode_Finish(&(me->cbor_enc_ctx), &completed_token_ub);
181     if (qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) {
182            return_value = ATTEST_TOKEN_ERR_TOO_SMALL;
183     } else if (qcbor_result != QCBOR_SUCCESS) {
184         /* likely from array not closed, too many closes, ... */
185         return_value = ATTEST_TOKEN_ERR_CBOR_FORMATTING;
186     } else {
187         *completed_token = completed_token_ub;
188     }
189 
190 Done:
191     return return_value;
192 }
193 #else /* SYMMETRIC_INITIAL_ATTESTATION */
194 /*
195  * Outline of token creation. Much of this occurs inside
196  * t_cose_sign1_encode_parameters() and t_cose_sign1_encode_signature().
197  *
198  * - Create encoder context
199  * - Open the CBOR array that hold the \c COSE_Sign1
200  * - Write COSE Headers
201  *   - Protected Header
202  *      - Algorithm ID
203  *   - Unprotected Headers
204  *     - Key ID
205  * - Open payload bstr
206  *   - Write payload data, maybe lots of it
207  *   - Get bstr that is the encoded payload
208  * - Compute signature
209  *   - Create a separate encoder context for \c Sig_structure
210  *     - Encode CBOR context identifier
211  *     - Encode protected headers
212  *     - Encode two empty bstr
213  *     - Add one more empty bstr that is a "fake payload"
214  *     - Close off \c Sig_structure
215  *   - Hash all but "fake payload" of \c Sig_structure
216  *   - Get payload bstr ptr and length
217  *   - Continue hash of the real encoded payload
218  *   - Run ECDSA
219  * - Write signature into the CBOR output
220  * - Close CBOR array holding the \c COSE_Sign1
221  */
222 
223 /*
224  * Public function. See attest_token.h
225  */
226 enum attest_token_err_t
attest_token_encode_start(struct attest_token_encode_ctx * me,uint32_t opt_flags,int32_t key_select,int32_t cose_alg_id,const struct q_useful_buf * out_buf)227 attest_token_encode_start(struct attest_token_encode_ctx *me,
228                           uint32_t opt_flags,
229                           int32_t key_select,
230                           int32_t cose_alg_id,
231                           const struct q_useful_buf *out_buf)
232 {
233     enum psa_attest_err_t attest_ret;
234     enum t_cose_err_t cose_ret;
235     int32_t                 t_cose_options = 0;
236     struct t_cose_key attest_key;
237     psa_key_handle_t private_key = TFM_BUILTIN_KEY_ID_IAK;
238     struct q_useful_buf_c attest_key_id = NULL_Q_USEFUL_BUF_C;
239 
240     /* Remember some of the configuration values */
241     me->opt_flags  = opt_flags;
242     me->key_select = key_select;
243 
244 
245     if (opt_flags & TOKEN_OPT_SHORT_CIRCUIT_SIGN) {
246         t_cose_options |= T_COSE_OPT_SHORT_CIRCUIT_SIG;
247     } else {
248         attest_ret = attest_get_initial_attestation_key_id(&attest_key_id);
249         if (attest_ret != PSA_ATTEST_ERR_SUCCESS) {
250             return ATTEST_TOKEN_ERR_GENERAL;
251         }
252     }
253 
254     t_cose_sign1_sign_init(&(me->signer_ctx), t_cose_options, cose_alg_id);
255 
256     attest_key.crypto_lib = T_COSE_CRYPTO_LIB_PSA;
257     attest_key.k.key_handle = private_key;
258 
259     t_cose_sign1_set_signing_key(&(me->signer_ctx),
260                                  attest_key,
261                                  attest_key_id);
262 
263     /* Spin up the CBOR encoder */
264     QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf);
265 
266     /* This will cause the cose headers to be encoded and written into
267      *  out_buf using me->cbor_enc_ctx
268      */
269     cose_ret = t_cose_sign1_encode_parameters(&(me->signer_ctx),
270                                               &(me->cbor_enc_ctx));
271     if (cose_ret) {
272         return t_cose_err_to_attest_err(cose_ret);
273     }
274 
275     QCBOREncode_OpenMap(&(me->cbor_enc_ctx));
276 
277     return ATTEST_TOKEN_ERR_SUCCESS;
278 }
279 
280 /*
281  * Public function. See attest_token.h
282  */
283 enum attest_token_err_t
attest_token_encode_finish(struct attest_token_encode_ctx * me,struct q_useful_buf_c * completed_token)284 attest_token_encode_finish(struct attest_token_encode_ctx *me,
285                            struct q_useful_buf_c *completed_token)
286 {
287     enum attest_token_err_t return_value = ATTEST_TOKEN_ERR_SUCCESS;
288     /* The completed and signed encoded cose_sign1 */
289     struct q_useful_buf_c   completed_token_ub;
290     QCBORError              qcbor_result;
291     enum t_cose_err_t       cose_return_value;
292 
293     QCBOREncode_CloseMap(&(me->cbor_enc_ctx));
294 
295     /* -- Finish up the COSE_Sign1. This is where the signing happens -- */
296     cose_return_value = t_cose_sign1_encode_signature(&(me->signer_ctx),
297                                                       &(me->cbor_enc_ctx));
298     if (cose_return_value) {
299         /* Main errors are invoking the hash or signature */
300         return_value = t_cose_err_to_attest_err(cose_return_value);
301         goto Done;
302     }
303 
304     /* Finally close off the CBOR formatting and get the pointer and length
305      * of the resulting COSE_Sign1
306      */
307     qcbor_result = QCBOREncode_Finish(&(me->cbor_enc_ctx), &completed_token_ub);
308     if (qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) {
309            return_value = ATTEST_TOKEN_ERR_TOO_SMALL;
310        } else if (qcbor_result != QCBOR_SUCCESS) {
311            /* likely from array not closed, too many closes, ... */
312            return_value = ATTEST_TOKEN_ERR_CBOR_FORMATTING;
313        } else {
314            *completed_token = completed_token_ub;
315        }
316 
317 Done:
318         return return_value;
319 }
320 #endif /* SYMMETRIC_INITIAL_ATTESTATION */
321 
322 /*
323  * Public function. See attest_token.h
324  */
325 QCBOREncodeContext *
attest_token_encode_borrow_cbor_cntxt(struct attest_token_encode_ctx * me)326 attest_token_encode_borrow_cbor_cntxt(struct attest_token_encode_ctx *me)
327 {
328     return &(me->cbor_enc_ctx);
329 }
330 
331 
332 /*
333  * Public function. See attest_token.h
334  */
attest_token_encode_add_integer(struct attest_token_encode_ctx * me,int32_t label,int64_t Value)335 void attest_token_encode_add_integer(struct attest_token_encode_ctx *me,
336                                      int32_t label,
337                                      int64_t Value)
338 {
339     QCBOREncode_AddInt64ToMapN(&(me->cbor_enc_ctx), label, Value);
340 }
341 
342 
343 /*
344  * Public function. See attest_token.h
345  */
attest_token_encode_add_bstr(struct attest_token_encode_ctx * me,int32_t label,const struct q_useful_buf_c * bstr)346 void attest_token_encode_add_bstr(struct attest_token_encode_ctx *me,
347                                   int32_t label,
348                                   const struct q_useful_buf_c *bstr)
349 {
350     QCBOREncode_AddBytesToMapN(&(me->cbor_enc_ctx),
351                                label,
352                                *bstr);
353 }
354 
355 
356 /*
357  * Public function. See attest_token.h
358  */
attest_token_encode_add_tstr(struct attest_token_encode_ctx * me,int32_t label,const struct q_useful_buf_c * tstr)359 void attest_token_encode_add_tstr(struct attest_token_encode_ctx *me,
360                                   int32_t label,
361                                   const struct q_useful_buf_c *tstr)
362 {
363     QCBOREncode_AddTextToMapN(&(me->cbor_enc_ctx), label, *tstr);
364 }
365 
366 
367 /*
368  * Public function. See attest_token.h
369  */
attest_token_encode_add_cbor(struct attest_token_encode_ctx * me,int32_t label,const struct q_useful_buf_c * encoded)370 void attest_token_encode_add_cbor(struct attest_token_encode_ctx *me,
371                                   int32_t label,
372                                   const struct q_useful_buf_c *encoded)
373 {
374     QCBOREncode_AddEncodedToMapN(&(me->cbor_enc_ctx), label, *encoded);
375 }
376