aboutsummaryrefslogtreecommitdiffstats
path: root/epan/wscbor.h
blob: 51d612cb218972cbae51a7c26894f5e6a490e929 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/** @file
 * Definitions for the Wireshark CBOR item decoding API.
 * References:
 *     RFC 8949: https://tools.ietf.org/html/rfc8949
 *
 * Copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#ifndef __WSCBOR_H__
#define __WSCBOR_H__

#include <ws_symbol_export.h>
#include <epan/tvbuff.h>
#include <epan/proto.h>
#include <epan/expert.h>
#include <wsutil/wmem/wmem_list.h>

#ifdef __cplusplus
extern "C" {
#endif

/** Register expert info and other wireshark data.
 */
WS_DLL_PUBLIC
void wscbor_init(void);

/** Expose available expert info for this library.
 * @param[out] size Set to the size of the array.
 * @return The array of expert info objects.
 */
WS_DLL_PUBLIC
const ei_register_info * wscbor_expert_items(int *size);

/// The same enumeration from libcbor-0.5
typedef enum cbor_type {
    CBOR_TYPE_UINT = 0, ///< positive integers
    CBOR_TYPE_NEGINT = 1, ///< negative integers
    CBOR_TYPE_BYTESTRING = 2, ///< byte strings
    CBOR_TYPE_STRING = 3, ///< text strings
    CBOR_TYPE_ARRAY = 4, ///< arrays
    CBOR_TYPE_MAP = 5, ///< maps
    CBOR_TYPE_TAG = 6, ///< tags
    CBOR_TYPE_FLOAT_CTRL = 7, ///< decimals and special values (true, false, nil, ...)
} cbor_type;

/// The same enumeration from libcbor-0.5
typedef enum {
    CBOR_CTRL_NONE = 0,
    CBOR_CTRL_FALSE = 20,
    CBOR_CTRL_TRUE = 21,
    CBOR_CTRL_NULL = 22,
    CBOR_CTRL_UNDEF = 23
} _cbor_ctrl;

/// Decoding or require_* error
typedef struct {
    /// The associated expert info
    expert_field *ei;
    /// Optional specific text
    const char *msg;
} wscbor_error_t;

/** Construct a new error object.
 *
 * @param alloc The allocator to use.
 * @param ei The specific error type.
 * @param format If non-NULL, a message format string.
 * @return The new object.
 */
WS_DLL_PUBLIC
wscbor_error_t * wscbor_error_new(wmem_allocator_t *alloc, expert_field *ei, const char *format, ...);

/// Tag metadata and value
typedef struct {
    /// The start offset of this tag head
    gint start;
    /// The length of just this tag head
    gint length;
    /// The tag value
    guint64 value;
} wscbor_tag_t;

struct _wscbor_chunk_priv_t;
typedef struct _wscbor_chunk_priv_t wscbor_chunk_priv_t;
/// A data-containing, optionally-tagged chunk of CBOR
typedef struct {
    /// Internal private data
    wscbor_chunk_priv_t *_priv;

    /// The start offset of this chunk
    gint start;
    /// The length of just this header and any preceding tags
    gint head_length;
    /// The length of this chunk and its immediate definite data (i.e. strings)
    gint data_length;
    /// Errors processing this chunk (type wscbor_error_t*)
    wmem_list_t *errors;
    /// Tags on this chunk, in encoded order (type wscbor_tag_t*)
    wmem_list_t *tags;

    /// Major type of this block.
    /// This will be one of the cbor_type values.
    cbor_type type_major;
    /// Minor type of this item
    guint8 type_minor;
    /// The header-encoded value
    guint64 head_value;
} wscbor_chunk_t;

/** Scan for a tagged chunk of headers.
 * The chunk of byte string and text string items includes the data content
 * in its @c offset.
 *
 * @param alloc The allocator to use.
 * @param tvb The TVB to read from.
 * @param[in,out] offset The offset with in @c tvb.
 * This is updated to be just past the new chunk.
 * @return The chunk of data found, including any errors.
 * This never returns NULL.
 * @post This can throw ReportedBoundsError or ContainedBoundsError
 * if the read itself ran out of data.
 */
WS_DLL_PUBLIC
wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset);

/** Free a chunk and its lists.
 */
WS_DLL_PUBLIC
void wscbor_chunk_free(wscbor_chunk_t *chunk);

/** After both reading and decoding a chunk, report on any errors found.
 * @param pinfo The associated packet.
 * @param item The associated tree item.
 * @param chunk The chunk with possible errors.
 * @return The error count.
 */
WS_DLL_PUBLIC
guint64 wscbor_chunk_mark_errors(packet_info *pinfo, proto_item *item, const wscbor_chunk_t *chunk);

/** Determine if a chunk has errors.
 * @param chunk The chunk with possible errors.
 * @return The error count.
 */
WS_DLL_PUBLIC
guint wscbor_has_errors(const wscbor_chunk_t *chunk);

/** Determine if an indefinite break is present.
 *
 * @param chunk The chunk to check.
 * @return True if it's an indefinite break.
 */
WS_DLL_PUBLIC
gboolean wscbor_is_indefinite_break(const wscbor_chunk_t *chunk);

/** Recursively skip items from a stream.
 *
 * @param alloc The allocator to use.
 * @param tvb The data buffer.
 * @param[in,out] offset The initial offset to read and skip over.
 * Will be set to one-past the last valid CBOR (possibly nested) present.
 * @return True if the skipped item was fully valid.
 * @post This can throw ReportedBoundsError or ContainedBoundsError
 * if the read itself ran out of data.
 */
WS_DLL_PUBLIC
gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset);

/** Skip over an item if a chunk has errors.
 * This allows skipping an entire array or map if the major type or size is
 * not as expected.
 *
 * @param alloc The allocator to use.
 * @param tvb The data buffer.
 * @param[in,out] offset The initial offset to read and skip over.
 * @param chunk The chunk with possible errors.
 * @return True if there were errors and the item skipped.
 */
WS_DLL_PUBLIC
gboolean wscbor_skip_if_errors(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset, const wscbor_chunk_t *chunk);


/** Require a specific item major type.
 *
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @param major The required major type.
 * @return True if the item is that type.
 */
WS_DLL_PUBLIC
gboolean wscbor_require_major_type(wscbor_chunk_t *chunk, cbor_type major);

/** Require an array item.
 *
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @return True if the item is an array.
 */
WS_DLL_PUBLIC
gboolean wscbor_require_array(wscbor_chunk_t *chunk);

/** Require an array have a specific ranged size.
 *
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @param count_min The minimum acceptable size.
 * @param count_max The maximum acceptable size.
 * @return True if the size is acceptable.
 */
WS_DLL_PUBLIC
gboolean wscbor_require_array_size(wscbor_chunk_t *chunk, guint64 count_min, guint64 count_max);

/** Require a map item.
 *
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @return True if the item is a map.
 */
WS_DLL_PUBLIC
gboolean wscbor_require_map(wscbor_chunk_t *chunk);

/** Require a CBOR item to have a boolean value.
 *
 * @param alloc The allocator to use.
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @return Pointer to the boolean value, if the item was boolean.
 * The value can be deleted with wscbor_require_delete().
 */
WS_DLL_PUBLIC
gboolean * wscbor_require_boolean(wmem_allocator_t *alloc, wscbor_chunk_t *chunk);

/** Require a CBOR item to have an unsigned-integer value.
 * @note This reader will clip the most significant bit of the value.
 *
 * @param alloc The allocator to use.
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @return Pointer to the boolean value, if the item was an integer.
 * The value can be deleted with wscbor_require_delete().
 */
WS_DLL_PUBLIC
guint64 * wscbor_require_uint64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk);

/** Require a CBOR item to have an signed- or unsigned-integer value.
 * @note This reader will clip the most significant bit of the value.
 *
 * @param alloc The allocator to use.
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @return Pointer to the value, if the item was an integer.
 * The value can be deleted with wscbor_require_delete().
 */
WS_DLL_PUBLIC
gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk);

/** Require a CBOR item to have a text-string value.
 * If the actual text string is not needed, use the following to avoid an
 * unnecessary allocation.
 * @code
 * wscbor_require_major_type(chunk, CBOR_TYPE_STRING)
 * @endcode
 *
 * @param alloc The allocator to use.
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @return Pointer to the null-terminated UTF-8, if the item was a tstr.
 * @post This can throw ContainedBoundsError string ran out of data.
 */
WS_DLL_PUBLIC
char * wscbor_require_tstr(wmem_allocator_t *alloc, wscbor_chunk_t *chunk);

/** Require a CBOR item to have a byte-string value.
 * Use tvb_memdup() or similar if the raw byte-string is needed.
 *
 * @param alloc The allocator to use.
 * @param[in,out] chunk The chunk to read from and write errors on.
 * @return Pointer to the value, if the item was an bstr.
 * The value is memory managed by wireshark.
 */
WS_DLL_PUBLIC
tvbuff_t * wscbor_require_bstr(wmem_allocator_t *alloc, wscbor_chunk_t *chunk);

/** Add an item representing an array or map container.
 * If the item is type FT_UINT* or FT_INT* the count of (array) items
 * or map (pairs) is used as the iterm value.
 */
WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_container(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk);

/** Add an item representing a non-boolean, non-float control value.
 */
WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_ctrl(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk);

WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_boolean(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk, const gboolean *value);

WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_uint64(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk, const guint64 *value);

WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_int64(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk, const gint64 *value);

WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_bitmask(proto_tree *tree, int hfindex, const gint ett, int *const *fields, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk, const guint64 *value);

WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk);

WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk);

/** Add an item representing the length of a bstr or tstr value.
 */
WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_strlen(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk);

#ifdef __cplusplus
}
#endif

#endif /* __WSCBOR_H__ */