Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/wscbor.c
Line
Count
Source
1
/* wscbor.c
2
 * Wireshark CBOR item decoding API.
3
 * References:
4
 *     RFC 8949: https://tools.ietf.org/html/rfc8949
5
 *
6
 * Copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
7
 *
8
 * Wireshark - Network traffic analyzer
9
 * By Gerald Combs <gerald@wireshark.org>
10
 * Copyright 1998 Gerald Combs
11
 *
12
 * SPDX-License-Identifier: LGPL-2.1-or-later
13
 */
14
#include "config.h"
15
16
#include <wsutil/array.h>
17
#include <epan/exceptions.h>
18
#include <epan/expert.h>
19
#include <epan/prefs.h>
20
#include <stdio.h>
21
#include <inttypes.h>
22
#include "wscbor.h"
23
24
/// Pseudo-protocol to register expert info
25
static int proto_wscbor;
26
27
static expert_field ei_cbor_invalid;
28
static expert_field ei_cbor_overflow;
29
static expert_field ei_cbor_wrong_type;
30
static expert_field ei_cbor_array_wrong_size;
31
static expert_field ei_cbor_indef_string;
32
static ei_register_info expertitems[] = {
33
    {&ei_cbor_invalid, {"_ws.wscbor.cbor_invalid", PI_MALFORMED, PI_ERROR, "CBOR cannot be decoded", EXPFILL}},
34
    {&ei_cbor_overflow, {"_ws.wscbor.cbor_overflow", PI_UNDECODED, PI_ERROR, "CBOR overflow of Wireshark value", EXPFILL}},
35
    {&ei_cbor_wrong_type, {"_ws.wscbor.cbor_wrong_type", PI_MALFORMED, PI_ERROR, "CBOR is wrong type", EXPFILL}},
36
    {&ei_cbor_array_wrong_size, {"_ws.wscbor.array_wrong_size", PI_MALFORMED, PI_WARN, "CBOR array is the wrong size", EXPFILL}},
37
    {&ei_cbor_indef_string, {"_ws.wscbor.indef_string", PI_COMMENTS_GROUP, PI_COMMENT, "String uses indefinite-length encoding", EXPFILL}},
38
};
39
40
/// The basic header structure of CBOR encoding
41
typedef struct {
42
    /// The start offset of this header
43
    int start;
44
    /// The length of just this header
45
    int length;
46
    /// The expert info object (if error)
47
    expert_field *error;
48
49
    /// Major type of this item (cbor_type)
50
    uint8_t type_major;
51
    /// Minor type of this item
52
    uint8_t type_minor;
53
    /// Raw head "value" which may be from the @c type_minor
54
    uint64_t rawvalue;
55
} wscbor_head_t;
56
57
/** Read the raw value from a CBOR head.
58
 * @param[in,out] head The head to read into.
59
 * @param tvb The buffer to read from.
60
 */
61
334k
static void wscbor_read_unsigned(wscbor_head_t *head, tvbuff_t *tvb) {
62
334k
    switch (head->type_minor) {
63
5.57k
        case 0x18:
64
5.57k
            head->rawvalue = tvb_get_uint8(tvb, head->start + head->length);
65
5.57k
            head->length += 1;
66
5.57k
            break;
67
3.34k
        case 0x19:
68
3.34k
            head->rawvalue = tvb_get_uint16(tvb, head->start + head->length, ENC_BIG_ENDIAN);
69
3.34k
            head->length += 2;
70
3.34k
            break;
71
2.26k
        case 0x1A:
72
2.26k
            head->rawvalue = tvb_get_uint32(tvb, head->start + head->length, ENC_BIG_ENDIAN);
73
2.26k
            head->length += 4;
74
2.26k
            break;
75
2.79k
        case 0x1B:
76
2.79k
            head->rawvalue = tvb_get_uint64(tvb, head->start + head->length, ENC_BIG_ENDIAN);
77
2.79k
            head->length += 8;
78
2.79k
            break;
79
320k
        default:
80
320k
            if (head->type_minor <= 0x17) {
81
272k
                head->rawvalue = head->type_minor;
82
272k
            }
83
320k
            break;
84
334k
    }
85
334k
}
86
87
/** Read just the CBOR head octet.
88
 * @param alloc The allocator to use.
89
 * @param tvb The TVB to read from.
90
 * @param[in,out] offset The offset with in @c tvb.
91
 * This is updated with just the head length.
92
 * @return The new head object.
93
 * This never returns NULL.
94
 * @post Will throw wireshark exception if read fails.
95
 */
96
334k
static wscbor_head_t * wscbor_head_read(wmem_allocator_t *alloc, tvbuff_t *tvb, int *offset) {
97
334k
    wscbor_head_t *head = wmem_new0(alloc, wscbor_head_t);
98
99
334k
    head->start = *offset;
100
334k
    const uint8_t first = tvb_get_uint8(tvb, head->start);
101
334k
    head->length += 1;
102
103
    // Match libcbor enums
104
334k
    head->type_major = (first & 0xe0) >> 5;
105
334k
    head->type_minor = (first & 0x1f);
106
334k
    switch ((cbor_type)(head->type_major)) {
107
127k
        case CBOR_TYPE_UINT:
108
161k
        case CBOR_TYPE_NEGINT:
109
177k
        case CBOR_TYPE_TAG:
110
177k
            wscbor_read_unsigned(head, tvb);
111
177k
            if (head->type_minor > 0x1B) {
112
6.78k
                head->error = &ei_cbor_invalid;
113
6.78k
            }
114
177k
            break;
115
8.89k
        case CBOR_TYPE_BYTESTRING:
116
22.8k
        case CBOR_TYPE_STRING:
117
81.4k
        case CBOR_TYPE_ARRAY:
118
115k
        case CBOR_TYPE_MAP:
119
157k
        case CBOR_TYPE_FLOAT_CTRL:
120
157k
            wscbor_read_unsigned(head, tvb);
121
157k
            if ((head->type_minor > 0x1B) && (head->type_minor < 0x1F)) {
122
11.4k
                head->error = &ei_cbor_invalid;
123
11.4k
            }
124
157k
            break;
125
126
0
        default:
127
0
            head->error = &ei_cbor_invalid;
128
0
            break;
129
334k
    }
130
131
334k
    if (ckd_add(offset, *offset, head->length)) {
132
0
        THROW(ReportedBoundsError);
133
0
    }
134
334k
    return head;
135
334k
}
136
137
/** Force a head to be freed.
138
 */
139
334k
static void wscbor_head_free(wmem_allocator_t *alloc, wscbor_head_t *head) {
140
334k
    wmem_free(alloc, head);
141
334k
}
142
143
struct _wscbor_chunk_priv_t {
144
    /// The allocator used for wscbor_chunk_t.errors and wscbor_chunk_t.tags
145
    wmem_allocator_t *alloc;
146
    /// Non-error expert info on this chunk (type wscbor_error_t*)
147
    wmem_list_t *infos;
148
    /// For string types, including indefinite length, the item payload.
149
    /// Otherwise NULL.
150
    tvbuff_t *str_value;
151
};
152
153
/** Get a clamped string length suitable for tvb functions.
154
 * @param[in,out] chunk The chunk to set errors on if the length is clamped.
155
 * @param[in,out] offset The current offset to advance to no more than INT_MAX.
156
 * @param head_value The value to clamp.
157
 * @return The clamped length value.
158
 */
159
21.6k
static int wscbor_get_length(wscbor_chunk_t *chunk, int *offset, uint64_t head_value) {
160
21.6k
    int start_offset = *offset;
161
21.6k
    int length;
162
    /* Truncate the length so that the offset doesn't overflow.
163
     * This prevents an exception reading this chunk, but will
164
     * throw an exception reading the head of the next chunk
165
     * at least when advancing the offset there.
166
     */
167
21.6k
    if (ckd_add(offset, start_offset, head_value)) {
168
70
        wmem_list_append(chunk->errors, wscbor_error_new(
169
70
                chunk->_priv->alloc, &ei_cbor_overflow,
170
70
                NULL
171
70
        ));
172
70
        *offset = INT_MAX;
173
70
        length = INT_MAX - start_offset;
174
70
    }
175
21.5k
    else {
176
21.5k
        length = (int) head_value;
177
21.5k
    }
178
21.6k
    return length;
179
21.6k
}
180
181
77.1k
wscbor_error_t * wscbor_error_new(wmem_allocator_t *alloc, expert_field *ei, const char *format, ...) {
182
77.1k
    wscbor_error_t *err = wmem_new0(alloc, wscbor_error_t);
183
77.1k
    err->ei = ei;
184
77.1k
    if (format) {
185
58.2k
        wmem_strbuf_t *buf = wmem_strbuf_new(alloc, "");
186
187
58.2k
        va_list ap;
188
58.2k
        va_start(ap, format);
189
58.2k
        wmem_strbuf_append_vprintf(buf, format, ap);
190
58.2k
        va_end(ap);
191
192
58.2k
        err->msg = wmem_strbuf_finalize(buf);
193
58.2k
    }
194
77.1k
    return err;
195
77.1k
}
196
197
305k
wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, int *offset) {
198
305k
    DISSECTOR_ASSERT(alloc != NULL);
199
305k
    DISSECTOR_ASSERT(offset != NULL);
200
305k
    DISSECTOR_ASSERT(tvb != NULL);
201
202
305k
    wscbor_chunk_t *chunk = wmem_new0(alloc, wscbor_chunk_t);
203
305k
    chunk->_priv = wmem_new0(alloc, struct _wscbor_chunk_priv_t);
204
305k
    chunk->_priv->alloc = alloc;
205
305k
    chunk->_priv->infos = wmem_list_new(alloc);
206
305k
    chunk->errors = wmem_list_new(alloc);
207
305k
    chunk->tags = wmem_list_new(alloc);
208
305k
    chunk->start = *offset;
209
210
305k
    CLEANUP_PUSH(((void (*)(void *))wscbor_chunk_free), chunk);
211
212
    // Read a sequence of tags followed by an item header
213
319k
    while (true) {
214
        // This will break out of the loop if it runs out of buffer
215
319k
        wscbor_head_t *head = wscbor_head_read(alloc, tvb, offset);
216
319k
        chunk->head_length += head->length;
217
319k
        if (head->error) {
218
16.8k
            wmem_list_append(chunk->errors, wscbor_error_new(alloc, head->error, NULL));
219
16.8k
        }
220
319k
        if (head->type_major == CBOR_TYPE_TAG) {
221
14.4k
            wscbor_tag_t *tag = wmem_new(alloc, wscbor_tag_t);
222
14.4k
            tag->start = head->start;
223
14.4k
            tag->length = head->length;
224
14.4k
            tag->value = head->rawvalue;
225
14.4k
            wmem_list_append(chunk->tags, tag);
226
            // same chunk, next part
227
14.4k
            wscbor_head_free(alloc, head);
228
14.4k
            continue;
229
14.4k
        }
230
231
        // An actual (non-tag) header
232
305k
        chunk->type_major = (cbor_type)head->type_major;
233
305k
        chunk->type_minor = head->type_minor;
234
305k
        chunk->head_value = head->rawvalue;
235
236
305k
        wscbor_head_free(alloc, head);
237
305k
        break;
238
319k
    }
239
240
    // Data beyond the tags and item head
241
305k
    chunk->data_length = chunk->head_length;
242
305k
    switch (chunk->type_major) {
243
7.89k
        case CBOR_TYPE_BYTESTRING:
244
20.4k
        case CBOR_TYPE_STRING:
245
20.4k
            if (chunk->type_minor != 31) {
246
19.9k
                const int datalen = wscbor_get_length(chunk, offset, chunk->head_value);
247
                // skip over definite data
248
19.9k
                chunk->data_length += datalen;
249
                // allow even zero-length strings
250
19.9k
                chunk->_priv->str_value = tvb_new_subset_length(tvb, chunk->start + chunk->head_length, datalen);
251
19.9k
            }
252
524
            else {
253
                // indefinite length, sequence of definite items
254
524
                chunk->_priv->str_value = NULL;
255
256
15.1k
                while (true) {
257
15.1k
                    wscbor_head_t *head = wscbor_head_read(alloc, tvb, offset);
258
15.1k
                    chunk->data_length += head->length;
259
15.1k
                    if (head->error) {
260
1.39k
                        wmem_list_append(chunk->errors, wscbor_error_new(alloc, head->error, NULL));
261
1.39k
                    }
262
15.1k
                    const bool is_break = (
263
15.1k
                        (head->type_major == CBOR_TYPE_FLOAT_CTRL)
264
2.13k
                        && (head->type_minor == 31)
265
15.1k
                    );
266
15.1k
                    if (!is_break) {
267
14.6k
                        if (head->type_major != chunk->type_major) {
268
12.8k
                            wmem_list_append(chunk->errors, wscbor_error_new(
269
12.8k
                                    chunk->_priv->alloc, &ei_cbor_wrong_type,
270
12.8k
                                    "Indefinite sub-string item has major type %d, should be %d",
271
12.8k
                                    head->type_major, chunk->type_major
272
12.8k
                            ));
273
12.8k
                        }
274
1.74k
                        else {
275
1.74k
                            const int datalen = wscbor_get_length(chunk, offset, head->rawvalue);
276
1.74k
                            chunk->data_length += datalen;
277
1.74k
                            if(datalen) {
278
692
                                if (!chunk->_priv->str_value) {
279
222
                                    chunk->_priv->str_value = tvb_new_composite ();
280
222
                                }
281
692
                                tvb_composite_append(
282
692
                                    chunk->_priv->str_value,
283
692
                                    tvb_new_subset_length(tvb, head->start + head->length, datalen)
284
692
                                );
285
692
                            }
286
1.74k
                        }
287
14.6k
                    }
288
289
15.1k
                    wscbor_head_free(alloc, head);
290
15.1k
                    if (is_break) {
291
465
                        break;
292
465
                    }
293
15.1k
                }
294
295
524
                wmem_list_append(chunk->_priv->infos, wscbor_error_new(
296
524
                        chunk->_priv->alloc, &ei_cbor_indef_string,
297
524
                        NULL
298
524
                ));
299
300
524
                if (chunk->_priv->str_value) {
301
179
                    tvb_composite_finalize(chunk->_priv->str_value);
302
179
                }
303
345
                else {
304
                    // Create an empty subset tvb. str_value is expected to be non-NULL for string types.
305
345
                    chunk->_priv->str_value = tvb_new_subset_length (tvb, 0, 0);
306
345
                }
307
524
            }
308
20.4k
            break;
309
284k
        default:
310
284k
            break;
311
305k
    }
312
313
304k
    CLEANUP_POP;
314
315
304k
    return chunk;
316
305k
}
317
318
25.7k
static void wscbor_subitem_free(void *data, void *userdata) {
319
25.7k
    wmem_allocator_t *alloc = (wmem_allocator_t *) userdata;
320
25.7k
    wmem_free(alloc, data);
321
25.7k
}
322
323
127k
void wscbor_chunk_free(wscbor_chunk_t *chunk) {
324
127k
    DISSECTOR_ASSERT(chunk);
325
127k
    wmem_allocator_t *alloc = chunk->_priv->alloc;
326
127k
    wmem_list_foreach(chunk->_priv->infos, wscbor_subitem_free, alloc);
327
127k
    wmem_destroy_list(chunk->_priv->infos);
328
127k
    wmem_list_foreach(chunk->errors, wscbor_subitem_free, alloc);
329
127k
    wmem_destroy_list(chunk->errors);
330
127k
    wmem_list_foreach(chunk->tags, wscbor_subitem_free, alloc);
331
127k
    wmem_destroy_list(chunk->tags);
332
127k
    wmem_free(alloc, chunk);
333
127k
}
334
335
/// User data for wscbor_expert_add()
336
typedef struct {
337
    packet_info *pinfo;
338
    proto_item *item;
339
} wscbor_expert_add_t;
340
341
/// A callback for wmem_list_foreach() to add the info
342
55.0k
static void wscbor_expert_add(void *data, void *userdata) {
343
55.0k
    const wscbor_error_t *err = (const wscbor_error_t *)data;
344
55.0k
    wscbor_expert_add_t *ctx = (wscbor_expert_add_t *)userdata;
345
346
55.0k
    if (err->msg) {
347
48.5k
        expert_add_info_format(ctx->pinfo, ctx->item, err->ei, "%s", err->msg);
348
48.5k
    }
349
6.49k
    else {
350
6.49k
        expert_add_info(ctx->pinfo, ctx->item, err->ei);
351
6.49k
    }
352
55.0k
}
353
354
83.5k
uint64_t wscbor_chunk_mark_errors(packet_info *pinfo, proto_item *item, const wscbor_chunk_t *chunk) {
355
83.5k
    wscbor_expert_add_t ctx = {pinfo, item};
356
83.5k
    wmem_list_foreach(chunk->errors, wscbor_expert_add, &ctx);
357
83.5k
    wmem_list_foreach(chunk->_priv->infos, wscbor_expert_add, &ctx);
358
359
83.5k
    return wmem_list_count(chunk->errors);
360
83.5k
}
361
362
209k
unsigned wscbor_has_errors(const wscbor_chunk_t *chunk) {
363
209k
    return wmem_list_count(chunk->errors);
364
209k
}
365
366
110k
bool wscbor_is_indefinite_break(const wscbor_chunk_t *chunk) {
367
110k
    return (
368
110k
        (chunk->type_major == CBOR_TYPE_FLOAT_CTRL)
369
17.3k
        && (chunk->type_minor == 31)
370
110k
    );
371
110k
}
372
373
/** Add output parameter to indicate internal state.
374
 * @param alloc The allocator to use.
375
 * @param tvb The data buffer.
376
 * @param[in,out] offset The initial offset to read and skip over.
377
 * @param[out] is_break If non-null, set to true only when the item was
378
 * an indefinite break.
379
 * @return True if the skipped item was fully valid.
380
 */
381
// NOLINTNEXTLINE(misc-no-recursion)
382
172k
static bool wscbor_skip_next_item_internal(wmem_allocator_t *alloc, tvbuff_t *tvb, int *offset, bool *is_break, unsigned depth) {
383
172k
    if (depth > prefs.gui_max_tree_depth) {
384
385
121
        return false;
386
121
    }
387
172k
    wscbor_chunk_t *chunk = wscbor_chunk_read(alloc, tvb, offset);
388
172k
    if (wscbor_has_errors(chunk)) {
389
6.23k
        wscbor_chunk_free(chunk);
390
6.23k
        return false;
391
6.23k
    }
392
166k
    switch (chunk->type_major) {
393
53.3k
        case CBOR_TYPE_UINT:
394
67.6k
        case CBOR_TYPE_NEGINT:
395
67.6k
        case CBOR_TYPE_TAG:
396
83.6k
        case CBOR_TYPE_FLOAT_CTRL:
397
83.6k
            break;
398
2.55k
        case CBOR_TYPE_BYTESTRING:
399
7.07k
        case CBOR_TYPE_STRING:
400
            // wscbor_chunk_read() sets offset past string value
401
7.07k
            break;
402
47.9k
        case CBOR_TYPE_ARRAY: {
403
47.9k
            if (chunk->type_minor == 31) {
404
                // wait for indefinite break
405
1.26k
                bool was_break = false;
406
3.33k
                do {
407
3.33k
                    if (!wscbor_skip_next_item_internal(alloc, tvb, offset, &was_break, depth + 1)) {
408
835
                        return false;
409
835
                    }
410
3.33k
                }
411
2.49k
                while (!was_break);
412
1.26k
            }
413
46.6k
            else {
414
46.6k
                const uint64_t count = chunk->head_value;
415
58.9k
                for (uint64_t ix = 0; ix < count; ++ix) {
416
55.3k
                    if (!wscbor_skip_next_item_internal(alloc, tvb, offset, NULL, depth + 1)) {
417
43.1k
                        return false;
418
43.1k
                    }
419
55.3k
                }
420
46.6k
            }
421
4.01k
            break;
422
47.9k
        }
423
27.6k
        case CBOR_TYPE_MAP: {
424
27.6k
            if (chunk->type_minor == 31) {
425
                // wait for indefinite break
426
1.52k
                bool was_break = false;
427
4.68k
                do {
428
4.68k
                    if (!wscbor_skip_next_item_internal(alloc, tvb, offset, &was_break, depth + 1)) {
429
1.04k
                        return false;
430
1.04k
                    }
431
4.68k
                }
432
3.64k
                while (!was_break);
433
1.52k
            }
434
26.1k
            else {
435
26.1k
                const uint64_t count = chunk->head_value;
436
31.3k
                for (uint64_t ix = 0; ix < count; ++ix) {
437
29.6k
                    if (!wscbor_skip_next_item_internal(alloc, tvb, offset, NULL, depth + 1)) {
438
23.7k
                        return false;
439
23.7k
                    }
440
5.85k
                    if (!wscbor_skip_next_item_internal(alloc, tvb, offset, NULL, depth + 1)) {
441
605
                        return false;
442
605
                    }
443
5.85k
                }
444
26.1k
            }
445
2.22k
            break;
446
27.6k
        }
447
166k
    }
448
96.5k
    const bool got_break = wscbor_is_indefinite_break(chunk);
449
96.5k
    if (is_break) {
450
6.09k
        *is_break = got_break;
451
6.09k
    }
452
96.5k
    wscbor_chunk_free(chunk);
453
    // RFC 8949 Sec 3.2.1: a break code outside of an indefinite container is
454
    // not valid, and is_break is non-null only in indefinite container.
455
96.5k
    return is_break || !got_break;
456
166k
}
457
458
73.9k
bool wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, int *offset) {
459
73.9k
    return wscbor_skip_next_item_internal(alloc, tvb, offset, NULL, 0);
460
73.9k
}
461
462
37.1k
bool wscbor_skip_if_errors(wmem_allocator_t *alloc, tvbuff_t *tvb, int *offset, const wscbor_chunk_t *chunk) {
463
37.1k
    if (wscbor_has_errors(chunk) == 0) {
464
3.06k
        return false;
465
3.06k
    }
466
467
34.0k
    *offset = chunk->start;
468
34.0k
    wscbor_skip_next_item(alloc, tvb, offset);
469
34.0k
    return true;
470
37.1k
}
471
472
15
void wscbor_init(void) {
473
15
    proto_wscbor = proto_register_protocol("CBOR Item Decoder", "CBOR Item Decoder", "_ws.wscbor");
474
475
15
    expert_module_t *expert_wscbor = expert_register_protocol(proto_wscbor);
476
    /* This isn't really a protocol, it's an error indication;
477
       disabling them makes no sense. */
478
15
    proto_set_cant_toggle(proto_wscbor);
479
480
15
    expert_register_field_array(expert_wscbor, expertitems, array_length(expertitems));
481
15
}
482
483
0
const ei_register_info * wscbor_expert_items(int *size) {
484
0
    if (size) {
485
0
        *size = array_length(expertitems);
486
0
    }
487
0
    return expertitems;
488
0
}
489
490
51.1k
bool wscbor_require_major_type(wscbor_chunk_t *chunk, cbor_type major) {
491
51.1k
    if (chunk->type_major == major) {
492
12.1k
        return true;
493
12.1k
    }
494
38.9k
    wmem_list_append(chunk->errors, wscbor_error_new(
495
38.9k
            chunk->_priv->alloc, &ei_cbor_wrong_type,
496
38.9k
            "Item has major type %d, should be %d",
497
38.9k
            chunk->type_major, major
498
38.9k
    ));
499
38.9k
    return false;
500
51.1k
}
501
502
16.1k
bool wscbor_require_array(wscbor_chunk_t *chunk) {
503
16.1k
    return wscbor_require_major_type(chunk, CBOR_TYPE_ARRAY);
504
16.1k
}
505
506
15.2k
bool wscbor_require_array_size(wscbor_chunk_t *chunk, uint64_t count_min, uint64_t count_max) {
507
15.2k
    if (!wscbor_require_array(chunk)) {
508
12.9k
        return false;
509
12.9k
    }
510
2.24k
    if ((chunk->head_value < count_min) || (chunk->head_value > count_max)) {
511
855
        wmem_list_append(chunk->errors, wscbor_error_new(
512
855
                chunk->_priv->alloc, &ei_cbor_array_wrong_size,
513
855
                "Array has %" PRId64 " items, should be within [%"PRId64", %"PRId64"]",
514
855
                chunk->head_value, count_min, count_max
515
855
        ));
516
855
        return false;
517
855
    }
518
1.39k
    return true;
519
2.24k
}
520
521
22.2k
bool wscbor_require_map(wscbor_chunk_t *chunk) {
522
22.2k
    return wscbor_require_major_type(chunk, CBOR_TYPE_MAP);
523
22.2k
}
524
525
70
bool * wscbor_require_boolean(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
526
70
    if (!wscbor_require_major_type(chunk, CBOR_TYPE_FLOAT_CTRL)) {
527
0
        return NULL;
528
0
    }
529
530
70
    switch (chunk->type_minor) {
531
1
        case CBOR_CTRL_TRUE:
532
1
        case CBOR_CTRL_FALSE: {
533
1
            bool *value = NULL;
534
1
            value = wmem_new(alloc, bool);
535
1
            *value = (chunk->type_minor == CBOR_CTRL_TRUE);
536
1
            return value;
537
1
        }
538
69
        default:
539
69
            wmem_list_append(chunk->errors, wscbor_error_new(
540
69
                    chunk->_priv->alloc, &ei_cbor_wrong_type,
541
69
                    "Item has minor type %d, should be %d or %d",
542
69
                    chunk->type_minor, CBOR_CTRL_TRUE, CBOR_CTRL_FALSE
543
69
            ));
544
69
            break;
545
70
    }
546
69
    return NULL;
547
70
}
548
549
6.04k
uint64_t * wscbor_require_uint64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
550
6.04k
    if (!wscbor_require_major_type(chunk, CBOR_TYPE_UINT)) {
551
2.30k
        return NULL;
552
2.30k
    }
553
554
3.73k
    uint64_t *result = wmem_new(alloc, uint64_t);
555
3.73k
    *result = chunk->head_value;
556
3.73k
    return result;
557
6.04k
}
558
559
42.5k
int64_t * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
560
42.5k
    int64_t *result = NULL;
561
42.5k
    switch (chunk->type_major) {
562
28.0k
        case CBOR_TYPE_UINT:
563
37.0k
        case CBOR_TYPE_NEGINT: {
564
37.0k
            int64_t clamped;
565
37.0k
            if (chunk->head_value > INT64_MAX) {
566
147
                clamped = INT64_MAX;
567
147
                wmem_list_append(chunk->errors, wscbor_error_new(
568
147
                        chunk->_priv->alloc, &ei_cbor_overflow,
569
147
                        NULL
570
147
                ));
571
147
            }
572
36.8k
            else {
573
36.8k
                clamped = chunk->head_value;
574
36.8k
            }
575
576
37.0k
            result = wmem_new(alloc, int64_t);
577
37.0k
            if (chunk->type_major == CBOR_TYPE_NEGINT) {
578
9.01k
                *result = -clamped - 1;
579
9.01k
            }
580
28.0k
            else {
581
28.0k
                *result = clamped;
582
28.0k
            }
583
37.0k
            break;
584
28.0k
        }
585
5.50k
        default:
586
5.50k
            wmem_list_append(chunk->errors, wscbor_error_new(
587
5.50k
                    chunk->_priv->alloc, &ei_cbor_wrong_type,
588
5.50k
                    "Item has major type %d, should be %d or %d",
589
5.50k
                    chunk->type_major, CBOR_TYPE_UINT, CBOR_TYPE_NEGINT
590
5.50k
            ));
591
5.50k
            break;
592
42.5k
    }
593
42.5k
    return result;
594
42.5k
}
595
596
3.06k
char * wscbor_require_tstr(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
597
3.06k
    if (!wscbor_require_major_type(chunk, CBOR_TYPE_STRING)) {
598
0
        return NULL;
599
0
    }
600
601
3.06k
    return (char *)tvb_get_string_enc(alloc, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), ENC_UTF_8);
602
3.06k
}
603
604
3.47k
tvbuff_t * wscbor_require_bstr(wmem_allocator_t *alloc _U_, wscbor_chunk_t *chunk) {
605
3.47k
    if (!wscbor_require_major_type(chunk, CBOR_TYPE_BYTESTRING)) {
606
2.59k
        return NULL;
607
2.59k
    }
608
609
877
    return chunk->_priv->str_value;
610
3.47k
}
611
612
747
proto_item * proto_tree_add_cbor_container(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
613
747
    const header_field_info *hfinfo = proto_registrar_get_nth(hfindex);
614
747
    proto_item *item;
615
747
    if (FT_IS_UINT(hfinfo->type)) {
616
157
        item = proto_tree_add_uint64(tree, hfindex, tvb, chunk->start, chunk->head_length, chunk->head_value);
617
157
    }
618
590
    else if (FT_IS_INT(hfinfo->type)) {
619
0
        item = proto_tree_add_int64(tree, hfindex, tvb, chunk->start, chunk->head_length, chunk->head_value);
620
0
    }
621
590
    else {
622
590
        item = proto_tree_add_item(tree, hfindex, tvb, chunk->start, -1, 0);
623
590
    }
624
747
    wscbor_chunk_mark_errors(pinfo, item, chunk);
625
747
    return item;
626
747
}
627
628
146
proto_item * proto_tree_add_cbor_ctrl(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
629
146
    proto_item *item = proto_tree_add_item(tree, hfindex, tvb, chunk->start, chunk->head_length, 0);
630
146
    wscbor_chunk_mark_errors(pinfo, item, chunk);
631
146
    return item;
632
146
}
633
634
70
proto_item * proto_tree_add_cbor_boolean(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk, const bool *value) {
635
70
    proto_item *item = proto_tree_add_boolean(tree, hfindex, tvb, chunk->start, chunk->data_length, value ? *value : false);
636
70
    wscbor_chunk_mark_errors(pinfo, item, chunk);
637
70
    return item;
638
70
}
639
640
4.78k
proto_item * proto_tree_add_cbor_uint64(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk, const uint64_t *value) {
641
4.78k
    proto_item *item = proto_tree_add_uint64(tree, hfindex, tvb, chunk->start, chunk->head_length, value ? *value : 0);
642
4.78k
    wscbor_chunk_mark_errors(pinfo, item, chunk);
643
4.78k
    return item;
644
4.78k
}
645
646
35.2k
proto_item * proto_tree_add_cbor_int64(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk, const int64_t *value) {
647
35.2k
    proto_item *item = proto_tree_add_int64(tree, hfindex, tvb, chunk->start, chunk->head_length, value ? *value : 0);
648
35.2k
    wscbor_chunk_mark_errors(pinfo, item, chunk);
649
35.2k
    return item;
650
35.2k
}
651
652
proto_item * proto_tree_add_cbor_bitmask(proto_tree *tree, int hfindex, const int ett,
653
                                        int *const *fields, packet_info *pinfo,
654
                                        tvbuff_t *tvb, const wscbor_chunk_t *chunk,
655
                                        const uint64_t *value)
656
1.25k
{
657
1.25k
    const uint64_t v = value ? *value : 0;
658
659
1.25k
    proto_item *ti = proto_tree_add_uint64(tree, hfindex, tvb, chunk->start, chunk->head_length, v);
660
1.25k
    proto_tree *sub = proto_item_add_subtree(ti, ett);
661
662
1.25k
    if (fields) {
663
7.63k
        for (int i = 0; fields[i] != NULL; i++) {
664
6.37k
            proto_tree_add_boolean(sub, *fields[i], tvb, chunk->start, chunk->head_length, v);
665
6.37k
        }
666
1.25k
    }
667
668
1.25k
    wscbor_chunk_mark_errors(pinfo, ti, chunk);
669
1.25k
    return ti;
670
1.25k
}
671
672
1.19k
proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
673
1.19k
    proto_item *item;
674
1.19k
    if (chunk->_priv->str_value) {
675
1.19k
        item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), ENC_UTF_8);
676
1.19k
    }
677
0
    else {
678
        // still show an empty item with errors
679
0
        item = proto_tree_add_item(tree, hfindex, tvb, chunk->start, 0, 0);
680
0
    }
681
1.19k
    wscbor_chunk_mark_errors(pinfo, item, chunk);
682
1.19k
    return item;
683
1.19k
}
684
685
3.44k
proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
686
3.44k
    proto_item *item;
687
3.44k
    if (chunk->_priv->str_value) {
688
934
        item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
689
934
    }
690
2.51k
    else {
691
        // still show an empty item with errors
692
2.51k
        item = proto_tree_add_item(tree, hfindex, tvb, chunk->start, 0, 0);
693
2.51k
    }
694
3.44k
    wscbor_chunk_mark_errors(pinfo, item, chunk);
695
3.44k
    return item;
696
3.44k
}
697
698
967
proto_item * proto_tree_add_cbor_strlen(proto_tree *tree, int hfindex, packet_info *pinfo _U_, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
699
967
    const unsigned str_len = (chunk->_priv->str_value ? tvb_reported_length(chunk->_priv->str_value) : 0);
700
967
    proto_item *item = proto_tree_add_uint64(tree, hfindex, tvb, chunk->start, chunk->head_length, str_len);
701
967
    return item;
702
967
}