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