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