1 /*
2  * t_cose_parameters.c
3  *
4  * Copyright 2019-2020, Laurence Lundblade
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * See BSD-3-Clause license in README.md
9  */
10 
11 
12 #include "t_cose_parameters.h"
13 #include "t_cose_standard_constants.h"
14 
15 
16 /**
17  * \file t_cose_headers.c
18  *
19  * \brief Implementation of the header parsing functions.
20  *
21  */
22 
23 
24 /**
25  * \brief Consume a CBOR item, particularly a map or array.
26  *
27  * \param[in] decode_context   Context to read data items from.
28  * \param[in] item_to_consume  The already-read item that is being consumed.
29  * \param[out] next_nest_level Nesting level of the next item that will be read.
30  *
31  * \returns A CBOR decoding error or QCBOR_SUCCESS.
32  *
33  * The primary purpose of this is to consume (read) all the members of
34  * a map or an array, however deeply nested it is.
35  *
36  * This doesn't do much work for non-nested data items.
37  */
38 static inline QCBORError
consume_item(QCBORDecodeContext * decode_context,const QCBORItem * item_to_consume,uint_fast8_t * next_nest_level)39 consume_item(QCBORDecodeContext *decode_context,
40              const QCBORItem    *item_to_consume,
41              uint_fast8_t       *next_nest_level)
42 {
43     /* Stack use: 4 + 56 = 60 */
44     QCBORError return_value;
45     QCBORItem  item;
46 
47     if(item_to_consume->uDataType == QCBOR_TYPE_MAP || item_to_consume->uDataType == QCBOR_TYPE_ARRAY) {
48         /* There is only real work to do for maps and arrays */
49 
50         /* This works for definite and indefinite length maps and
51          * arrays by using the nesting level
52          */
53         do {
54             return_value = QCBORDecode_GetNext(decode_context, &item);
55             if(return_value != QCBOR_SUCCESS) {
56                 goto Done;
57             }
58         } while(item.uNextNestLevel >= item_to_consume->uNextNestLevel);
59 
60         *next_nest_level = item.uNextNestLevel;
61         return_value = QCBOR_SUCCESS;
62 
63     } else {
64         /* item_to_consume is not a map or array.  Just pass the
65          * nesting level through */
66         *next_nest_level = item_to_consume->uNextNestLevel;
67         return_value = QCBOR_SUCCESS;
68     }
69 
70 Done:
71     return return_value;
72 }
73 
74 
75 
76 
77 /**
78  * \brief Add a new label to the end of the label list.
79  *
80  * \param[in] item             Data item to add to the label list.
81  * \param[in,out] label_list   The list to add to.
82  *
83  * \retval T_COSE_SUCCESS                  If added correctly.
84  * \retval T_COSE_ERR_TOO_MANY_PARAMETERS  Label list is full.
85  * \retval T_COSE_ERR_PARAMETER_CBOR       The item to add doesn't have a label
86  *                                         type that is understood
87  *
88  * The label / key from \c item is added to \c label_list.
89  */
90 static inline enum t_cose_err_t
add_label_to_list(const QCBORItem * item,struct t_cose_label_list * label_list)91 add_label_to_list(const QCBORItem          *item,
92                   struct t_cose_label_list *label_list)
93 {
94     enum t_cose_err_t return_value;
95     uint_fast8_t      n;
96 
97     /* Assume success until an error adding is encountered. */
98     return_value = T_COSE_SUCCESS;
99 
100     if(item->uLabelType == QCBOR_TYPE_INT64) {
101         /* Add an integer-labeled parameter to the end of the list */
102         for(n = 0; label_list->int_labels[n] != LABEL_LIST_TERMINATOR; n++);
103         if(n == T_COSE_PARAMETER_LIST_MAX) {
104             /* List is full -- error out */
105             return_value = T_COSE_ERR_TOO_MANY_PARAMETERS;
106             goto Done;
107         }
108         label_list->int_labels[n] = item->label.int64;
109 
110     } else if(item->uLabelType == QCBOR_TYPE_TEXT_STRING) {
111         /* Add a string-labeled parameter to the end of the list */
112         for(n = 0; !q_useful_buf_c_is_null(label_list->tstr_labels[n]); n++);
113         if(n == T_COSE_PARAMETER_LIST_MAX) {
114             /* List is full -- error out */
115             return_value = T_COSE_ERR_TOO_MANY_PARAMETERS;
116             goto Done;
117         }
118         label_list->tstr_labels[n] = item->label.string;
119     } else {
120         /* error because label is neither integer or string */
121         /* Should never occur because this is caught earlier, but
122          * leave it to be safe and because inlining and optimization
123          * should take out any unneeded code
124          */
125         return_value = T_COSE_ERR_PARAMETER_CBOR;
126     }
127 
128 Done:
129     return return_value;
130 }
131 
132 
133 
134 
135 /**
136  * \brief Decode the parameter containing the labels of parameters considered
137  *        critical.
138  *
139  * \param[in,out]  decode_context          Decode context to read critical
140  *                                         parameter list from.
141  * \param[in]      crit_parameter_item     Data item of array holding critical
142  *                                         labels.
143  * \param[out]     critical_labels         List of labels of critical
144  *                                         parameters.
145  * \param[out]     return_next_nest_level  Place to return nesting level of
146  *                                         next data item.
147  *
148  * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED  Undecodable CBOR.
149  * \retval T_COSE_ERR_TOO_MANY_PARAMETERS   More critical labels than this
150  *                                          implementation can handle.
151  * \retval T_COSE_ERR_PARAMETER_CBOR        Unexpected CBOR data type.
152  */
153 static inline enum t_cose_err_t
decode_critical_parameter(QCBORDecodeContext * decode_context,const QCBORItem * crit_parameter_item,struct t_cose_label_list * critical_labels,uint_fast8_t * return_next_nest_level)154 decode_critical_parameter(QCBORDecodeContext       *decode_context,
155                           const QCBORItem          *crit_parameter_item,
156                           struct t_cose_label_list *critical_labels,
157                           uint_fast8_t             *return_next_nest_level)
158 {
159     /* Stack use 64-bit: 56 + 40 = 96
160      *           32-bit: 52 + 20 = 72
161      */
162     QCBORItem         item;
163     uint_fast8_t      num_int_labels;
164     uint_fast8_t      num_tstr_labels;
165     enum t_cose_err_t return_value;
166     QCBORError        cbor_result;
167     uint_fast8_t      next_nest_level;
168     uint_fast8_t      array_nest_level;
169 
170     num_int_labels  = 0;
171     num_tstr_labels = 0;
172 
173     array_nest_level = crit_parameter_item->uNestingLevel;
174     next_nest_level  = crit_parameter_item->uNextNestLevel;
175 
176     if(crit_parameter_item->uDataType != QCBOR_TYPE_ARRAY) {
177         return_value = T_COSE_ERR_CRIT_PARAMETER;
178         goto Done;
179     }
180 
181     while(next_nest_level > array_nest_level) {
182         cbor_result = QCBORDecode_GetNext(decode_context, &item);
183         if(cbor_result != QCBOR_SUCCESS) {
184             return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
185             goto Done;
186         }
187 
188         if(item.uDataType == QCBOR_TYPE_INT64) {
189             if(num_int_labels >= T_COSE_PARAMETER_LIST_MAX) {
190                 return_value = T_COSE_ERR_CRIT_PARAMETER;
191                 goto Done;
192             }
193             critical_labels->int_labels[num_int_labels++] = item.val.int64;
194         } else if(item.uDataType == QCBOR_TYPE_TEXT_STRING) {
195             if(num_tstr_labels >= T_COSE_PARAMETER_LIST_MAX) {
196                 return_value = T_COSE_ERR_CRIT_PARAMETER;
197                 goto Done;
198             }
199             critical_labels->tstr_labels[num_tstr_labels++] = item.val.string;
200         } else {
201             return_value = T_COSE_ERR_CRIT_PARAMETER;
202             goto Done;
203         }
204         next_nest_level = item.uNextNestLevel;
205     }
206 
207     if(is_label_list_clear(critical_labels)) {
208         /* Per RFC 8152 crit parameter can't be empty */
209         return_value = T_COSE_ERR_CRIT_PARAMETER;
210         goto Done;
211     }
212 
213     return_value = T_COSE_SUCCESS;
214 
215 Done:
216     *return_next_nest_level = next_nest_level;
217     return return_value;
218 }
219 
220 
221 /**
222  * Public function. See t_cose_parameters.h
223  */
224 enum t_cose_err_t
check_critical_labels(const struct t_cose_label_list * critical_labels,const struct t_cose_label_list * unknown_labels)225 check_critical_labels(const struct t_cose_label_list *critical_labels,
226                       const struct t_cose_label_list *unknown_labels)
227 {
228     enum t_cose_err_t return_value;
229     uint_fast8_t      num_unknown;
230     uint_fast8_t      num_critical;
231 
232     /* Assume success until an unhandled critical label is found */
233     return_value = T_COSE_SUCCESS;
234 
235     /* Iterate over unknown integer parameters */
236     for(num_unknown = 0; unknown_labels->int_labels[num_unknown]; num_unknown++) {
237         /* Iterate over critical int labels looking for the unknown label */
238         for(num_critical = 0;
239             critical_labels->int_labels[num_critical];
240             num_critical++) {
241             if(critical_labels->int_labels[num_critical] == unknown_labels->int_labels[num_unknown]) {
242                 /* Found a critical label that is unknown to us */
243                 return_value = T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER;
244                 goto Done;
245             }
246         }
247         /* Exit from loop here means all no unknown label was critical */
248     }
249 
250     /* Iterate over unknown string labels */
251     for(num_unknown = 0; !q_useful_buf_c_is_null(unknown_labels->tstr_labels[num_unknown]); num_unknown++) {
252         /* iterate over critical string labels looking for the unknown param */
253         for(num_critical = 0; !q_useful_buf_c_is_null(critical_labels->tstr_labels[num_critical]); num_critical++) {
254             if(!q_useful_buf_compare(critical_labels->tstr_labels[num_critical],
255                                      unknown_labels->tstr_labels[num_unknown])){
256                 /* Found a critical label that is unknown to us */
257                 return_value = T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER;
258                 goto Done;
259             }
260         }
261         /* Exit from loop here means all no unknown label was critical */
262     }
263 
264 Done:
265     return return_value;
266 }
267 
268 
269 
270 
271 /**
272  * \brief Add unknown parameter to unknown labels list and fully consume it
273  *
274  * \param[in] decode_context       CBOR decode context to read from.
275  * \param[in] unknown_parameter    The data item for the unknown parameter.
276  * \param[in,out] unknown_labels   The list of unknown labels to which to add
277  *                                 this new unknown label to.
278  * \param[out] next_nest_level     The nest level of the next item that will be
279  *                                 fetched. Helps to know if at end of list.
280  *
281  * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED  The CBOR is not well-formed.
282  * \retval T_COSE_ERR_TOO_MANY_PARAMETERS   The unknown labels list is full.
283  * \retval T_COSE_ERR_CBOR_STRUCTURE        The CBOR structure not as expected.
284  */
285 static enum t_cose_err_t
process_unknown_parameter(QCBORDecodeContext * decode_context,const QCBORItem * unknown_parameter,struct t_cose_label_list * unknown_labels,uint_fast8_t * next_nest_level)286 process_unknown_parameter(QCBORDecodeContext        *decode_context,
287                           const QCBORItem           *unknown_parameter,
288                           struct t_cose_label_list *unknown_labels,
289                           uint_fast8_t              *next_nest_level)
290 {
291     enum t_cose_err_t return_value;
292 
293     return_value = add_label_to_list(unknown_parameter, unknown_labels);
294     if(return_value) {
295         goto Done;
296     }
297 
298     /* The full unknown parameter must be consumed. It could be
299      complex deeply-nested CBOR */
300     if(consume_item(decode_context, unknown_parameter, next_nest_level)) {
301         return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
302     }
303 
304 Done:
305     return return_value;
306 }
307 
308 
309 
310 
311 /**
312  * \brief Clear a struct t_cose_parameters to empty
313  *
314  * \param[in,out] parameters   Parameter list to clear.
315  */
clear_cose_parameters(struct t_cose_parameters * parameters)316 static inline void clear_cose_parameters(struct t_cose_parameters *parameters)
317 {
318 #if COSE_ALGORITHM_RESERVED != 0
319 #error Invalid algorithm designator not 0. Parameter list initialization fails.
320 #endif
321 
322 #if T_COSE_UNSET_ALGORITHM_ID != COSE_ALGORITHM_RESERVED
323 #error Constant for unset algorithm ID not aligned with COSE_ALGORITHM_RESERVED
324 #endif
325 
326     /* This clears all the useful_bufs to NULL_Q_USEFUL_BUF_C
327      * and the cose_algorithm_id to COSE_ALGORITHM_RESERVED
328      */
329     memset(parameters, 0, sizeof(struct t_cose_parameters));
330 
331 #ifndef T_COSE_DISABLE_CONTENT_TYPE
332     /* The only non-zero clear-state value. (0 is plain text in CoAP
333      * content format) */
334     parameters->content_type_uint =  T_COSE_EMPTY_UINT_CONTENT_TYPE;
335 #endif
336 }
337 
338 
339 /**
340  * \brief Parse some COSE header parameters.
341  *
342  * \param[in] decode_context        The QCBOR decode context to read from.
343  * \param[out] returned_parameters  The parsed parameters being returned.
344  *
345  * \retval T_COSE_SUCCESS                     The parameters were decoded
346  *                                            correctly.
347  * \retval T_COSE_ERR_PARAMETER_CBOR          CBOR is parsable, but not the
348  *                                            right structure (e.g. array
349  *                                            instead of a map)
350  * \retval T_COSE_ERR_TOO_MANY_PARAMETERS     More than
351  *                                            \ref T_COSE_PARAMETER_LIST_MAX
352  *                                            parameters.
353  * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED    The CBOR is not parsable.
354  * \retval T_COSE_ERR_NON_INTEGER_ALG_ID      The algorithm ID is not an
355  *                                            integer. This implementation
356  *                                            doesn't support string algorithm
357  *                                            IDs.
358  * \retval T_COSE_ERR_BAD_CONTENT_TYPE        Error in content type parameter.
359  * \retval T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER   A label marked critical is
360  *                                                 present and not understood.
361  *
362  * No parameters are mandatory. Which parameters were present or not
363  * is indicated in \c returned_parameters.  It is OK for there to be
364  * no parameters at all.
365  *
366  * The first item to be read from the decode_context must be the map
367  * data item that contains the parameters.
368  */
369 static enum t_cose_err_t
parse_cose_header_parameters(QCBORDecodeContext * decode_context,struct t_cose_parameters * returned_parameters,struct t_cose_label_list * critical_labels,struct t_cose_label_list * unknown_labels)370 parse_cose_header_parameters(QCBORDecodeContext        *decode_context,
371                              struct t_cose_parameters  *returned_parameters,
372                              struct t_cose_label_list  *critical_labels,
373                              struct t_cose_label_list  *unknown_labels)
374 {
375     /* Local stack use 64-bit: 56 + 24 + 488 = 568
376      * Local stack use 32-bit: 52 + 12 + 352 = 414
377      * Total stack use 64-bit: 568 + 96 + 50 = 694
378      * Total stack use 32-bit: 414 + 72 + 25 = 501
379      */
380     QCBORItem          item;
381     enum t_cose_err_t  return_value;
382     uint_fast8_t       map_nest_level;
383     uint_fast8_t       next_nest_level;
384     QCBORError         qcbor_result;
385 
386     clear_cose_parameters(returned_parameters);
387 
388     if(critical_labels != NULL) {
389         clear_label_list(critical_labels);
390     }
391 
392     /* Get the data item that is the map that is being searched */
393     qcbor_result = QCBORDecode_GetNext(decode_context, &item);
394     if(qcbor_result == QCBOR_ERR_NO_MORE_ITEMS) {
395         return_value = T_COSE_SUCCESS;
396         goto Done;
397     }
398     if(qcbor_result != QCBOR_SUCCESS) {
399         return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
400         goto Done;
401     }
402     if(item.uDataType != QCBOR_TYPE_MAP) {
403         return_value = T_COSE_ERR_PARAMETER_CBOR;
404         goto Done;
405     }
406 
407     /* Loop over all the items in the map. The map may contain further
408      * maps and arrays. This also needs to handle definite and
409      * indefinite length maps and array.
410      *
411      * map_nest_level is the nesting level of the data item opening
412      * the map that is being scanned. All data items inside this map
413      * have a nesting level greater than it. The data item following
414      * the map being scanned has a nesting level that is equal to or
415      * higher than map_nest_level.
416      */
417     map_nest_level  = item.uNestingLevel;
418     next_nest_level = item.uNextNestLevel;
419     while(next_nest_level > map_nest_level) {
420 
421         if(QCBORDecode_GetNext(decode_context, &item) != QCBOR_SUCCESS) {
422             /* Got not-well-formed CBOR */
423             return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
424             goto Done;
425         }
426 
427         if(item.uLabelType != QCBOR_TYPE_INT64) {
428             /* Non integer label. We don't handle those. */
429             return_value = process_unknown_parameter(decode_context,
430                                                   &item,
431                                                   unknown_labels,
432                                                   &next_nest_level);
433             if(return_value) {
434                 goto Done;
435             }
436 
437         } else {
438             next_nest_level = item.uNextNestLevel;
439             switch(item.label.int64) {
440 
441             case COSE_HEADER_PARAM_ALG:
442                 if(critical_labels == NULL) {
443                     return_value = T_COSE_ERR_PARAMETER_NOT_PROTECTED;
444                     goto Done;
445                 }
446                 if(item.uDataType != QCBOR_TYPE_INT64) {
447                     return_value = T_COSE_ERR_NON_INTEGER_ALG_ID;
448                     goto Done;
449                 }
450                 if(item.val.int64 == COSE_ALGORITHM_RESERVED || item.val.int64 > INT32_MAX) {
451                     return_value = T_COSE_ERR_NON_INTEGER_ALG_ID;
452                     goto Done;
453                 }
454                 if(returned_parameters->cose_algorithm_id != COSE_ALGORITHM_RESERVED) {
455                     return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
456                     goto Done;
457                 }
458                 returned_parameters->cose_algorithm_id = (int32_t)item.val.int64;
459                 break;
460 
461             case COSE_HEADER_PARAM_KID:
462                 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
463                     return_value = T_COSE_ERR_PARAMETER_CBOR;
464                     goto Done;
465                 }
466                 if(!q_useful_buf_c_is_null_or_empty(returned_parameters->kid)) {
467                     return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
468                     goto Done;
469                 }
470                 returned_parameters->kid = item.val.string;
471                 break;
472 
473             case COSE_HEADER_PARAM_IV:
474                 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
475                     return_value = T_COSE_ERR_PARAMETER_CBOR;
476                     goto Done;
477                 }
478                 if(!q_useful_buf_c_is_null_or_empty(returned_parameters->iv)) {
479                     return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
480                     goto Done;
481                 }
482                 returned_parameters->iv = item.val.string;
483                 break;
484 
485             case COSE_HEADER_PARAM_PARTIAL_IV:
486                 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
487                     return_value = T_COSE_ERR_PARAMETER_CBOR;
488                     goto Done;
489                 }
490                 if(!q_useful_buf_c_is_null_or_empty(returned_parameters->partial_iv)) {
491                     return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
492                     goto Done;
493                 }
494                 returned_parameters->partial_iv = item.val.string;
495                 break;
496 
497             case COSE_HEADER_PARAM_CRIT:
498                 if(critical_labels == NULL) {
499                     /* crit parameter occuring in non-protected bucket */
500                     return_value = T_COSE_ERR_PARAMETER_NOT_PROTECTED;
501                     goto Done;
502                 }
503                 if(!is_label_list_clear(critical_labels)) {
504                     /* Duplicate detection must be here because it is not
505                      * done in check_and_copy_parameters()
506                      */
507                     return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
508                     goto Done;
509                 }
510                 /* decode_critical_parameter() consumes all the items in the
511                  * crit parameter array */
512                 return_value = decode_critical_parameter(decode_context,
513                                                         &item,
514                                                          critical_labels,
515                                                         &next_nest_level);
516                 if(return_value) {
517                     goto Done;
518                 }
519                 break;
520 
521 #ifndef T_COSE_DISABLE_CONTENT_TYPE
522             case COSE_HEADER_PARAM_CONTENT_TYPE:
523                 if(item.uDataType == QCBOR_TYPE_TEXT_STRING) {
524                     if(!q_useful_buf_c_is_null_or_empty(returned_parameters->content_type_tstr)) {
525                         return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
526                         goto Done;
527                     }
528                     returned_parameters->content_type_tstr = item.val.string;
529                 } else if(item.uDataType == QCBOR_TYPE_INT64) {
530                     if(item.val.int64 < 0 || item.val.int64 > UINT16_MAX) {
531                         return_value = T_COSE_ERR_BAD_CONTENT_TYPE;
532                         goto Done;
533                     }
534                     if(returned_parameters->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
535                         return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
536                         goto Done;
537                     }
538                     returned_parameters->content_type_uint = (uint32_t)item.val.int64;
539                 } else {
540                     return_value = T_COSE_ERR_BAD_CONTENT_TYPE;
541                     goto Done;
542                 }
543                 break;
544 #endif
545 
546             default:
547                 /* The parameter is not recognized. Its label has to
548                  * be added to the the list of unknown labels so it
549                  * can be checked against the list of critical labels.
550                  */
551                 return_value = process_unknown_parameter(decode_context,
552                                                         &item,
553                                                          unknown_labels,
554                                                         &next_nest_level);
555                 if(return_value) {
556                     goto Done;
557                 }
558                 break;
559             }
560         }
561     }
562     return_value = T_COSE_SUCCESS;
563 
564 Done:
565     return return_value;
566 }
567 
568 
569 /**
570  * Public function. See t_cose_parameters.h
571  */
572 enum t_cose_err_t
parse_protected_header_parameters(const struct q_useful_buf_c encoded_protected_parameters,struct t_cose_parameters * returned_params,struct t_cose_label_list * critical_labels,struct t_cose_label_list * unknown)573 parse_protected_header_parameters(const struct q_useful_buf_c encoded_protected_parameters,
574                                   struct t_cose_parameters   *returned_params,
575                                   struct t_cose_label_list   *critical_labels,
576                                   struct t_cose_label_list   *unknown)
577 {
578     /* Local stack use 64-bit: 144 + 8 = 152
579      * Local stack use 32-bit: 108 + 4 = 112
580      * Total stack use 64-bit: 694 + 144 = 838
581      * Total stack use 32-bit: 501 + 112 = 613
582      */
583     QCBORDecodeContext decode_context;
584     enum t_cose_err_t  return_value;
585 
586     QCBORDecode_Init(&decode_context, encoded_protected_parameters, QCBOR_DECODE_MODE_NORMAL);
587 
588     return_value = parse_cose_header_parameters(&decode_context,
589                                                  returned_params,
590                                                  critical_labels,
591                                                  unknown);
592     if(return_value != T_COSE_SUCCESS) {
593         goto Done;
594     }
595 
596     if(QCBORDecode_Finish(&decode_context)) {
597         /* A CBOR error here is always not-well-formed */
598         return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
599     }
600 
601 Done:
602     return return_value;
603 }
604 
605 
606 /*
607  * Static inline implementation. See documentation above.
608  */
609 enum t_cose_err_t
parse_unprotected_header_parameters(QCBORDecodeContext * decode_context,struct t_cose_parameters * returned_params,struct t_cose_label_list * unknown_labels)610 parse_unprotected_header_parameters(QCBORDecodeContext *decode_context,
611                                     struct t_cose_parameters *returned_params,
612                                     struct t_cose_label_list *unknown_labels)
613 {
614     return parse_cose_header_parameters(decode_context,
615                                         returned_params,
616                                         NULL,
617                                         unknown_labels);
618 }
619 
620 
621 /**
622  * Public function. See t_cose_parameters.h
623  */
624 enum t_cose_err_t
check_and_copy_parameters(const struct t_cose_parameters * protected,const struct t_cose_parameters * unprotected,struct t_cose_parameters * returned_params)625 check_and_copy_parameters(const struct t_cose_parameters  *protected,
626                           const struct t_cose_parameters  *unprotected,
627                           struct t_cose_parameters        *returned_params)
628 {
629     enum t_cose_err_t return_value;
630 
631     /* -- Copy all the unprotected parameters -- */
632     if(returned_params) {
633         *returned_params = *unprotected;
634     }
635 
636     /* Go one at at time and check the protected parameters. If the
637      * parameter is not NULL and there is the same un protected
638      * parameter error out. If it is not NULL and there is no
639      * unprotected parameter, copy it */
640     if(protected->cose_algorithm_id != COSE_ALGORITHM_RESERVED) {
641         if(unprotected->cose_algorithm_id != COSE_ALGORITHM_RESERVED) {
642             return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
643             goto Done;
644         }
645         if(returned_params) {
646             returned_params->cose_algorithm_id = protected->cose_algorithm_id;
647         }
648     }
649 
650     if(!q_useful_buf_c_is_null_or_empty(protected->kid)) {
651         if(!q_useful_buf_c_is_null_or_empty(unprotected->kid)) {
652             return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
653             goto Done;
654         }
655         if(returned_params) {
656             returned_params->kid = protected->kid;
657         }
658     }
659 
660     if(!q_useful_buf_c_is_null_or_empty(protected->iv)) {
661         if( !q_useful_buf_c_is_null_or_empty(unprotected->iv)) {
662             return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
663             goto Done;
664         }
665         if(returned_params) {
666             returned_params->iv = protected->iv;
667         }
668     }
669 
670     if(!q_useful_buf_c_is_null_or_empty(protected->partial_iv)) {
671         if( !q_useful_buf_c_is_null_or_empty(unprotected->partial_iv)) {
672             return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
673             goto Done;
674         }
675         if(returned_params) {
676             returned_params->partial_iv = protected->partial_iv;
677         }
678     }
679 
680 #ifndef T_COSE_DISABLE_CONTENT_TYPE
681     if(!q_useful_buf_c_is_null_or_empty(protected->content_type_tstr)) {
682         if( !q_useful_buf_c_is_null_or_empty(unprotected->content_type_tstr)) {
683             return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
684             goto Done;
685         }
686         if(returned_params) {
687             returned_params->content_type_tstr = protected->content_type_tstr;
688         }
689     }
690 
691     if(protected->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
692         if(unprotected->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
693             return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
694             goto Done;
695         }
696         if(returned_params) {
697             returned_params->content_type_uint = protected->content_type_uint;
698         }
699     }
700 #endif
701 
702     return_value = T_COSE_SUCCESS;
703 
704 Done:
705     return return_value;
706 }
707 
708