TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
attest_token_decode_common.c
Go to the documentation of this file.
1 /*
2  * attest_token_decode_common.c
3  *
4  * Copyright (c) 2019, Laurence Lundblade.
5  * Copyright (c) 2020, 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_decode.h"
13 #include "attest.h"
14 #include "q_useful_buf.h"
15 #include "qcbor_util.h"
16 
46 #define CLAIM_PRESENT_BIT(item_index) (0x01U << (item_index))
47 
48 
49 /*
50  * Public function. See attest_token_decode.h
51  */
53  uint32_t options)
54 {
55  memset(me, 0, sizeof(struct attest_token_decode_context));
56  me->options = options;
58 }
59 
60 /*
61  * Public function. See attest_token_decode.h
62  */
65  int32_t label,
66  struct q_useful_buf_c *claim)
67 {
68  enum attest_token_err_t return_value;
69  QCBORItem item;
70 
72  return_value = me->last_error;
73  *claim = NULL_Q_USEFUL_BUF_C;
74  goto Done;
75  }
76 
77  return_value = qcbor_util_get_top_level_item_in_map(me->payload,
78  label,
79  QCBOR_TYPE_BYTE_STRING,
80  &item);
81  if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
82  goto Done;
83  }
84 
85  *claim = item.val.string;
86 
87 Done:
88  return return_value;
89 }
90 
91 
92 /*
93  * Public function. See attest_token_decode.h
94  */
97  int32_t label,
98  struct q_useful_buf_c *claim)
99 {
100  enum attest_token_err_t return_value;
101  QCBORItem item;
102 
104  return_value = me->last_error;
105  *claim = NULL_Q_USEFUL_BUF_C;
106  goto Done;
107  }
108 
109  return_value = qcbor_util_get_top_level_item_in_map(me->payload,
110  label,
111  QCBOR_TYPE_TEXT_STRING,
112  &item);
113  if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
114  goto Done;
115  }
116 
117  *claim = item.val.string;
118 
119 Done:
120  return return_value;
121 }
122 
123 
124 /*
125  * Public function. See attest_token_decode.h
126  */
129  int32_t label,
130  int64_t *integer)
131 {
132  enum attest_token_err_t return_value;
133  QCBORItem item;
134  QCBORDecodeContext decode_context;
135 
137  return_value = me->last_error;
138  *integer = 0;
139  goto Done;
140  }
141 
142  QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
143 
144  return_value = qcbor_util_get_item_in_map(&decode_context,
145  label,
146  &item);
147  if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
148  goto Done;
149  }
150 
151  if(QCBORDecode_Finish(&decode_context)) {
152  return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
153  }
154 
155  if(item.uDataType == QCBOR_TYPE_INT64) {
156  *integer = item.val.int64;
157  } else if(item.uDataType == QCBOR_TYPE_UINT64) {
158  if(item.val.uint64 < INT64_MAX) {
159  *integer = (int64_t)item.val.uint64;
160  } else {
161  return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
162  }
163  } else {
164  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
165  }
166 
167 Done:
168  return return_value;
169 }
170 
171 
172 /*
173  * Public function. See attest_token_decode.h
174  */
177  int32_t label,
178  uint64_t *integer)
179 {
180  enum attest_token_err_t return_value;
181  QCBORItem item;
182  QCBORDecodeContext decode_context;
183 
185  return_value = me->last_error;
186  *integer = 0;
187  goto Done;
188  }
189 
190  QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
191 
192  return_value = qcbor_util_get_item_in_map(&decode_context,
193  label,
194  &item);
195  if(return_value != 0) {
196  goto Done;
197  }
198 
199  if(QCBORDecode_Finish(&decode_context)) {
200  return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
201  }
202 
203  if(item.uDataType == QCBOR_TYPE_UINT64) {
204  *integer = item.val.uint64;
205  } else if(item.uDataType == QCBOR_TYPE_INT64) {
206  if(item.val.int64 >= 0) {
207  *integer = (uint64_t)item.val.int64;
208  } else {
209  return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
210  }
211  } else {
212  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
213  }
214 
215 Done:
216  return return_value;
217 }
218 
219 
220 /*
221  * Public function. See attest_token_decode.h
222  */
225  struct q_useful_buf_c *payload)
226 {
227  enum attest_token_err_t return_value;
228 
230  return_value = me->last_error;
231  *payload = NULL_Q_USEFUL_BUF_C;
232  goto Done;
233  }
234 
235  if(q_useful_buf_c_is_null_or_empty(me->payload)) {
236  return_value = ATTEST_TOKEN_ERR_NO_VALID_TOKEN;
237  goto Done;
238  }
239 
240  *payload = me->payload;
241  return_value = ATTEST_TOKEN_ERR_SUCCESS;
242 
243 Done:
244  return return_value;
245 }
246 
247 
248 /*
249  * Public function. See attest_token_decode.h
250  */
253  struct attest_token_iat_simple_t *items)
254 {
255  struct qcbor_util_items_to_get_t list[NUMBER_OF_ITEMS+1];
256  QCBORDecodeContext decode_context;
257  int64_t client_id_64;
258  enum attest_token_err_t return_value;
259 
260  /* Set all q_useful_bufs to NULL and flags to 0 */
261  memset(items, 0, sizeof(struct attest_token_iat_simple_t));
262 
263  /* Re use flags as array indexes because it works nicely */
265  list[UEID_FLAG].label = EAT_CBOR_ARM_LABEL_UEID;
273  list[NUMBER_OF_ITEMS].label = 0; /* terminate the list. */
274 
276  return_value = me->last_error;
277  goto Done;
278  }
279 
280  QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
281 
282  return_value = qcbor_util_get_items_in_map(&decode_context,
283  list);
284  if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
285  goto Done;
286  }
287 
288  /* ---- NONCE ---- */
289  if(list[NONCE_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
290  items->nonce = list[NONCE_FLAG].item.val.string;
292  }
293 
294  /* ---- UEID -------*/
295  if(list[UEID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
296  items->ueid = list[UEID_FLAG].item.val.string;
298  }
299 
300  /* ---- BOOT SEED -------*/
301  if(list[BOOT_SEED_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
302  items->boot_seed = list[BOOT_SEED_FLAG].item.val.string;
304  }
305 
306  /* ---- HW VERSION -------*/
307  if(list[HW_VERSION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
308  items->hw_version = list[HW_VERSION_FLAG].item.val.string;
310 
311  }
312 
313  /* ----IMPLEMENTATION ID -------*/
314  if(list[IMPLEMENTATION_ID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
315  items->implementation_id = list[IMPLEMENTATION_ID_FLAG].item.val.string;
317  }
318 
319  /* ----CLIENT ID -------*/
320  if(list[CLIENT_ID_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
321  client_id_64 = list[CLIENT_ID_FLAG].item.val.int64;
322  if(client_id_64 < INT32_MAX || client_id_64 > INT32_MIN) {
323  items->client_id = (int32_t)client_id_64;
325  }
326  }
327 
328  /* ----SECURITY LIFECYCLE -------*/
329  if(list[SECURITY_LIFECYCLE_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
330  if(list[SECURITY_LIFECYCLE_FLAG].item.val.int64 < UINT32_MAX) {
331  items->security_lifecycle =
332  (uint32_t)list[SECURITY_LIFECYCLE_FLAG].item.val.int64;
334  }
335  }
336 
337  /* ---- PROFILE_DEFINITION -------*/
338  if(list[PROFILE_DEFINITION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
339  items->profile_definition=list[PROFILE_DEFINITION_FLAG].item.val.string;
341  }
342 
343  /* ---- ORIGINATION -------*/
344  if(list[ORIGINATION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
345  items->origination = list[ORIGINATION_FLAG].item.val.string;
347  }
348 
349 Done:
350  return return_value;
351 }
352 
353 
354 /*
355  * Public function. See attest_token_decode.h
356  */
359  uint32_t *num_sw_components)
360 {
361  enum attest_token_err_t return_value;
362  QCBORItem item;
363 
365  return_value = me->last_error;
366  goto Done;
367  }
368 
369  return_value = qcbor_util_get_top_level_item_in_map(me->payload,
371  QCBOR_TYPE_ARRAY,
372  &item);
373  if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
374  if(return_value != ATTEST_TOKEN_ERR_NOT_FOUND) {
375  /* Something very wrong. Bail out passing on the return_value */
376  goto Done;
377  } else {
378  /* Now decide if it was intentionally left out. */
379  return_value = qcbor_util_get_top_level_item_in_map(me->payload,
381  QCBOR_TYPE_INT64,
382  &item);
383  if(return_value == ATTEST_TOKEN_ERR_SUCCESS) {
384  if(item.val.int64 == NO_SW_COMPONENT_FIXED_VALUE) {
385  /* Successful omission of SW components. Pass on the
386  * success return_value */
387  *num_sw_components = 0;
388  } else {
389  /* Indicator for no SW components malformed */
391  }
392  } else if(return_value == ATTEST_TOKEN_ERR_NOT_FOUND) {
393  /* Should have been an indicator for no SW components */
395  }
396  }
397  } else {
398  /* The SW components claim exists */
399  if(item.val.uCount == 0) {
400  /* Empty SW component not allowed */
402  } else {
403  /* SUCESSS! Pass on the success return_value */
404  /* Note that this assumes the array is definite length */
405  *num_sw_components = item.val.uCount;
406  }
407  }
408 
409 Done:
410  return return_value;
411 }
412 
413 
425 static inline enum attest_token_err_t
426 decode_sw_component(QCBORDecodeContext *decode_context,
427  const QCBORItem *sw_component_item,
428  struct attest_token_sw_component_t *sw_component)
429 {
430  enum attest_token_err_t return_value;
431  QCBORItem claim_item;
432  QCBORError cbor_error;
433  uint_fast8_t next_nest_level; /* nest levels are 8-bit, but a uint8_t
434  var is often slower and more code */
435 
436  if(sw_component_item->uDataType != QCBOR_TYPE_MAP) {
437  return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
438  goto Done;
439  }
440 
441  /* Zero it, setting booleans to false, pointers to NULL and
442  lengths to 0 */
443  memset(sw_component, 0, sizeof(struct attest_token_sw_component_t));
444 
445  return_value = ATTEST_TOKEN_ERR_SUCCESS;
446 
447  while(1) {
448  cbor_error = QCBORDecode_GetNext(decode_context, &claim_item);
449  if(cbor_error != QCBOR_SUCCESS) {
450  /* no tolerance for any errors here */
452  goto Done;
453  }
454 
455  if(claim_item.uLabelType == QCBOR_TYPE_INT64) {
456  switch(claim_item.label.int64) {
458  if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
459  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
460  goto Done;
461  }
462  sw_component->measurement_type = claim_item.val.string;
463  sw_component->item_flags |=
465 
466  break;
467 
469  if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
470  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
471  goto Done;
472  }
473  sw_component->measurement_val = claim_item.val.string;
474  sw_component->item_flags |=
476  break;
477 
479  if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
480  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
481  goto Done;
482  }
483  sw_component->version = claim_item.val.string;
484  sw_component->item_flags |=
486  break;
487 
489  if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
490  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
491  goto Done;
492  }
493  sw_component->signer_id = claim_item.val.string;
494  sw_component->item_flags |=
496  break;
497 
499  if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
500  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
501  goto Done;
502  }
503  sw_component->measurement_desc = claim_item.val.string;
504  sw_component->item_flags |=
506  break;
507  }
508  }
509 
510  if(qcbor_util_consume_item(decode_context,
511  &claim_item,
512  &next_nest_level)) {
514  goto Done;
515  }
516  if(next_nest_level < sw_component_item->uNextNestLevel) {
517  /* Got all the items in the map */
518  break;
519  }
520  }
521 
522 Done:
523  return return_value;
524 }
525 
526 
527 /*
528  * Public function. See attest_token_decode.h
529  */
532  uint32_t requested_index,
533  struct attest_token_sw_component_t *sw_components)
534 {
535  enum attest_token_err_t return_value;
536  QCBORItem sw_components_array_item;
537  QCBORDecodeContext decode_context;
538  QCBORItem sw_component_item;
539  QCBORError qcbor_error;
540  uint_fast8_t exit_array_level;
541 
543  return_value = me->last_error;
544  goto Done;
545  }
546 
547  QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
548 
549  /* Find the map containing all the SW Components */
550  return_value = qcbor_util_decode_to_labeled_item(&decode_context,
552  &sw_components_array_item);
553  if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
554  goto Done;
555  }
556 
557  if(sw_components_array_item.uDataType != QCBOR_TYPE_ARRAY) {
558  return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
559  goto Done;
560  }
561 
562  exit_array_level = sw_components_array_item.uNextNestLevel;
563 
564  /* Loop over contents of SW Components array */
565  while(1) {
566  qcbor_error = QCBORDecode_GetNext(&decode_context, &sw_component_item);
567  if(qcbor_error) {
568  /* no tolerance for any errors here */
570  goto Done;
571  }
572 
573  if(sw_component_item.uNextNestLevel <= exit_array_level) {
574  /* Next item will be outside the array */
575  return_value = ATTEST_TOKEN_ERR_NOT_FOUND;
576  /* The end of the array containing SW components
577  and didn't get to the requested_index. */
578  goto Done;
579  }
580 
581  if(requested_index == 0) {
582  /* Found the one of interest. Decode it and break out */
583  return_value = decode_sw_component(&decode_context,
584  &sw_component_item,
585  sw_components);
586  break; /* The normal, non-error exit from this loop */
587  }
588 
589  /* Every member in the array counts even if they are not
590  * what is expected */
591  requested_index--;
592 
593  if(qcbor_util_consume_item(&decode_context, &sw_component_item, NULL)) {
595  goto Done;
596  }
597  }
598 
599 Done:
600  return return_value;
601 }
enum attest_token_err_t last_error
struct q_useful_buf_c implementation_id
enum attest_token_err_t attest_token_get_num_sw_components(struct attest_token_decode_context *me, uint32_t *num_sw_components)
Get the number of SW components in the token.
#define EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE
#define EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS
Attestation Token Decoding Interface.
enum attest_token_err_t attest_token_decode_get_payload(struct attest_token_decode_context *me, struct q_useful_buf_c *payload)
Get undecoded CBOR payload from the token.
attest_token_err_t
Definition: attest_token.h:50
#define NO_SW_COMPONENT_FIXED_VALUE
struct q_useful_buf_c measurement_type
struct q_useful_buf_c version
#define EAT_CBOR_ARM_LABEL_UEID
enum attest_token_err_t attest_token_decode_get_iat_simple(struct attest_token_decode_context *me, struct attest_token_iat_simple_t *items)
Batch fetch of all simple data items in a token.
struct q_useful_buf_c hw_version
struct q_useful_buf_c origination
#define EAT_CBOR_SW_COMPONENT_SIGNER_ID
#define EAT_CBOR_ARM_LABEL_CLIENT_ID
#define EAT_CBOR_ARM_LABEL_ORIGINATION
#define EAT_CBOR_ARM_LABEL_SW_COMPONENTS
enum attest_token_err_t attest_token_decode_get_bstr(struct attest_token_decode_context *me, int32_t label, struct q_useful_buf_c *claim)
Get a top-level claim, by integer label that is a byte string.
#define EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE
enum attest_token_err_t attest_token_decode_get_uint(struct attest_token_decode_context *me, int32_t label, uint64_t *integer)
Get a top-level claim by integer label who's value is an unsigned integer.
enum attest_token_err_t attest_token_get_sw_component(struct attest_token_decode_context *me, uint32_t requested_index, struct attest_token_sw_component_t *sw_components)
Get the nth SW component.
#define CLAIM_PRESENT_BIT(item_index)
struct q_useful_buf_c signer_id
struct q_useful_buf_c measurement_val
struct q_useful_buf_c nonce
#define EAT_CBOR_SW_COMPONENT_VERSION
struct q_useful_buf_c payload
enum attest_token_err_t attest_token_decode_get_int(struct attest_token_decode_context *me, int32_t label, int64_t *integer)
Get a top-level claim by integer label who's value is a signed integer.
struct q_useful_buf_c ueid
struct q_useful_buf_c boot_seed
#define EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION
struct q_useful_buf_c measurement_desc
#define EAT_CBOR_ARM_LABEL_HW_VERSION
#define EAT_CBOR_ARM_LABEL_CHALLENGE
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC
void attest_token_decode_init(struct attest_token_decode_context *me, uint32_t options)
Initialize token decoder.
void * memset(void *s, int c, size_t n)
Definition: crt_memset.c:10
enum attest_token_err_t attest_token_decode_get_tstr(struct attest_token_decode_context *me, int32_t label, struct q_useful_buf_c *claim)
Get a top-level claim, by integer label that is a text string.
struct q_useful_buf_c profile_definition
#define EAT_CBOR_ARM_LABEL_BOOT_SEED