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