1 /*
2  * qcbor_util.h
3  *
4  * Copyright (c) 2019, Laurence Lundblade.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * See BSD-3-Clause license in README.md
9  */
10 
11 #ifndef __QCBOR_UTILS_H__
12 #define __QCBOR_UTILS_H__
13 
14 
15 #include "qcbor/qcbor.h"
16 #include "q_useful_buf.h"
17 #include "attest_token.h" /* For error codes */
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 /**
24  *\file qcbor_util.h
25  *
26  * \brief Some utility functions for decoding CBOR with QCBOR.
27  *
28  * All functions search only for integer labeled data items. If data
29  * items labeled otherwise are present, they will be skipped over.
30  *
31  * These functions may eventually expand in to a more general and
32  * useful set of decoding utilities.
33  *
34  * \c uint_fast8_t is used for type and nest levels. They are
35  * 8-bit quantities, but making using uint8_t variables
36  * and parameters can result in bigger, slower code.
37  * \c uint_fast8_t is part of \c <stdint.h>. It is not
38  * used in structures where it is more important to keep
39  * the size smaller.
40  */
41 
42 
43 /**
44  *\brief Consume a data item, particularly a map or array.
45  *
46  * \param[in] decode_context   The CBOR context from which to
47  *                             consume the map or array.
48  * \param[in] item_to_consume  The item to consume.
49  * \param[out] next_nest_level The nesting level of the item
50  *                             that would be consumed next.
51  *
52  * \return A \c  QCBORError when there is something wrong with the
53  *               encoded CBOR.
54  *
55  * If the \c item_to_consume is not a map or array this does nothing
56  * but return the \c next_nest_level (which is just copied from \c
57  * item_to_consume). If it is a map or array all subordinate items
58  * will be consumed from the \c decode_context.
59  */
60 QCBORError
61 qcbor_util_consume_item(QCBORDecodeContext *decode_context,
62                         const QCBORItem *item_to_consume,
63                         uint_fast8_t *next_nest_level);
64 
65 
66 /**
67  * Descriptor for a single labeled item to be retrieved by
68  * qcbor_util_get_items_in_map().  An array of these is passed to
69  * qcbor_util_get_items_in_map() terminated by one of these with label
70  * 0.
71  */
72 struct qcbor_util_items_to_get_t {
73     /**
74      * The integer label to search for. List terminated by label 0.
75      */
76     int64_t   label;
77     /**
78      * Where the retrieved item is returned. Item.uDataType is
79      * QCBOR_TYPE_NONE if not found
80      */
81     QCBORItem item;
82 };
83 
84 
85 /**
86  * \brief Search a CBOR map for multiple integer-labeled items.
87  *
88  * \param[in,out] decode_context  The QCBOR decode context to
89  *                                consume and look through.
90  * \param[in,out] items           The array of labels to search for
91  *                                and the places to return what was
92  *                                found. See \ref
93  *                                qcbor_util_items_to_get_t.
94  *
95  * \retval ATTEST_TOKEN_ERR_CBOR_STRUCTURE
96  *         The next item in the decode context is not a map.
97  * \retval ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED
98  *         The CBOR is not well-formed.
99  * \retval ATTEST_TOKEN_ERR_SUCCESS
100  *         Success. This just means the map was searched, not that
101  *         anything was found. The contents of \c items must be
102  *         checked to see what was found.
103  *
104  * The next item from \c decode_context must be a map. This is the map
105  * that will be searched. Only items at the immediate subordinate
106  * level in the map will be checked for label matches. This will
107  * consume the all the data items in the map.
108  *
109  * Note that this cannot be used for finding maps and arrays in at map
110  * and decoding them since it consumes them and does not return their
111  * contents. qcbor_util_decode_to_labeled_item() is more useful for
112  * this.
113  *
114  * This will ignore any data items that do not have integer labels.
115  */
116 enum attest_token_err_t
117 qcbor_util_get_items_in_map(QCBORDecodeContext *decode_context,
118                             struct qcbor_util_items_to_get_t *items);
119 
120 
121 /**
122  * \brief Decode a map up to a particular label and stop.
123  *
124  * \param[in,out] decode_context The QCBOR decode context to
125  *                               consume and look through.
126  * \param[in] label              The label of the item being sought.
127  * \param[out] item              The item that is filled in with the
128  *                               when the match is found.
129  *
130  * \retval ATTEST_TOKEN_ERR_CBOR_STRUCTURE
131  *         The next item in the decode context is not a map.
132  * \retval ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED
133  *         The CBOR is not well-formed.
134  * \retval ATTEST_TOKEN_ERR_SUCCESS
135  *         The labeled item was found.
136  * \retval ATTEST_TOKEN_ERR_NOT_FOUND
137            The entire map was consumed without finding \c label.
138  *
139  * The next item from \c decode_context must be a map. This is the map
140  * that will be searched.
141 
142  * This will decode consuming data items from \c decode_context until
143  * the labeled item is found. It will consume all items in any map or
144  * array encountered before finding \c label.
145  *
146  * Typically this is used to decode to the start of a map or array.
147  * The next data item from \c decode_context will be the first item in
148  * the map or the array.
149  *
150  * This works for any CBOR data type, not just maps or arrays.
151  *
152  * This will ignore any data items that do not have integer labels.
153  **/
154 enum attest_token_err_t
155 qcbor_util_decode_to_labeled_item(QCBORDecodeContext *decode_context,
156                                   int32_t label,
157                                   QCBORItem *item);
158 
159 
160 /**
161  * \brief Search a map for one particular integer labeled item.
162  *
163  * \param[in,out] decode_context The QCBOR decode context to
164  *                               consume and look through.
165  * \param[in] label              The label of the item being sought.
166  * \param[out] item              The item that is filled in when
167  *                               the match is found.
168  *
169  * \retval ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED
170  *         CBOR was not well-formed
171  * \retval ATTEST_TOKEN_ERR_CBOR_STRUCTURE
172  *         Starting item on \c decode context was not a map.
173  * \retval ATTEST_TOKEN_ERR_SUCCESS
174  *         The labeled item was found and returned.
175  * \retval ATTEST_TOKEN_ERR_NOT_FOUND
176  *         The entire map was consumed without finding \c label.
177  *
178  * This is qcbor_util_get_items_in_map() for just one item.
179  *
180  * This will consume the whole map. It is most useful for getting
181  * unstructured data items like integers and strings, but not good for
182  * arrays and maps. See qcbor_util_decode_to_labeled_item() for arrays
183  * and maps.
184  */
185 enum attest_token_err_t
186 qcbor_util_get_item_in_map(QCBORDecodeContext *decode_context,
187                            int32_t label,
188                            QCBORItem *item);
189 
190 
191 /**
192  * \brief Search encoded CBOR from beginning to end for labeled item.
193  *
194  * \param[in] payload     Encoded chunk of CBOR to decode.
195  * \param[in] label       Integer label of item to look for.
196  * \param[in] qcbor_type  One of \c QCBOR_TYPE_xxx indicating the
197  *                        type of the data item expected.
198  * \param[out] item       Place to copy the \c QCBORItem to that
199  *                        describes what was found.
200  *
201  * \retval ATTEST_TOKEN_ERR_CBOR_TYPE
202  *        The labeled item was found, but it didn't match \c qcbor_type.
203  * \retval ATTEST_TOKEN_ERR_SUCCESS
204  *        The labeled item was found and returned.
205  * \retval ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED
206  *         CBOR was not well-formed
207  * \retval ATTEST_TOKEN_ERR_CBOR_STRUCTURE
208  *         A map was expected.
209  * \retval ATTEST_TOKEN_ERR_NOT_FOUND
210  *         The entire map was consumed without finding \c label.
211  *
212  * This will decode the \c payload from beginning to end. If there are
213  * extra bytes at the end of it or all the maps and arrays in it are
214  * not closed this will return an error.
215  *
216  * Since this decodes the payload from start to finish to find one
217  * item, calling this multiple times to get multiple items will cause
218  * the payload to be completely decoded multiple times. This is not as
219  * efficient as qcbor_util_get_items_in_map(), but not that costly
220  * either.
221  *
222  * This uses qcbor_util_get_item_in_map() to do its work.
223  */
224 enum attest_token_err_t
225 qcbor_util_get_top_level_item_in_map(struct q_useful_buf_c payload,
226                                      int32_t label,
227                                      uint_fast8_t qcbor_type,
228                                      QCBORItem *item);
229 
230 
231 #ifdef __cplusplus
232 }
233 #endif
234 
235 #endif /* __QCBOR_UTILS_H__ */
236