2 * Routines for Concise Binary Object Representation (CBOR) (RFC 7049) dissection
4 * RFC 7049: https://tools.ietf.org/html/rfc7049
5 * RFC 8742: https://tools.ietf.org/html/rfc8742
7 * Copyright 2015, Hauke Mehrtens <hauke@hauke-m.de>
8 * Copyright 2022, Stig Bjorlykke <stig@bjorlykke.org>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
21 #include <epan/packet.h>
22 #include <epan/expert.h>
23 #include <epan/proto_data.h>
24 #include <wsutil/str_util.h>
26 void proto_register_cbor(void);
27 void proto_reg_handoff_cbor(void);
29 static int proto_cbor
;
31 static int hf_cbor_item_major_type
;
32 static int hf_cbor_item_integer_size
;
33 static int hf_cbor_item_length_size
;
34 static int hf_cbor_item_length5
;
35 static int hf_cbor_item_length
;
36 static int hf_cbor_item_items5
;
37 static int hf_cbor_item_items
;
38 static int hf_cbor_item_pairs5
;
39 static int hf_cbor_item_pairs
;
40 static int hf_cbor_item_float_simple_type
;
41 static int hf_cbor_item_unsigned_integer
;
42 static int hf_cbor_item_negative_integer
;
43 static int hf_cbor_item_text_string
;
44 static int hf_cbor_item_byte_string
;
45 static int hf_cbor_item_array
;
46 static int hf_cbor_item_map
;
47 static int hf_cbor_item_tag
;
48 static int hf_cbor_item_float_simple
;
49 static int hf_cbor_type_uint5
;
50 static int hf_cbor_type_uint
;
51 static int hf_cbor_type_nint
;
52 static int hf_cbor_type_byte_string
;
53 static int hf_cbor_type_byte_string_indef
;
54 static int hf_cbor_type_text_string
;
55 static int hf_cbor_type_text_string_indef
;
56 static int hf_cbor_type_tag5
;
57 static int hf_cbor_type_tag
;
58 static int hf_cbor_type_simple_data5
;
59 static int hf_cbor_type_simple_data8
;
60 static int hf_cbor_type_float16
;
61 static int hf_cbor_type_float32
;
62 static int hf_cbor_type_float64
;
65 static int ett_cbor_type
;
66 static int ett_cbor_unsigned_integer
;
67 static int ett_cbor_negative_integer
;
68 static int ett_cbor_byte_string
;
69 static int ett_cbor_byte_string_indef
;
70 static int ett_cbor_text_string
;
71 static int ett_cbor_text_string_indef
;
72 static int ett_cbor_array
;
73 static int ett_cbor_map
;
74 static int ett_cbor_tag
;
75 static int ett_cbor_float_simple
;
77 static expert_field ei_cbor_invalid_minor_type
;
78 static expert_field ei_cbor_invalid_element
;
79 static expert_field ei_cbor_too_long_length
;
80 static expert_field ei_cbor_max_recursion_depth_reached
;
82 static dissector_handle_t cbor_handle
;
83 static dissector_handle_t cborseq_handle
;
85 #define CBOR_TYPE_USIGNED_INT 0
86 #define CBOR_TYPE_NEGATIVE_INT 1
87 #define CBOR_TYPE_BYTE_STRING 2
88 #define CBOR_TYPE_TEXT_STRING 3
89 #define CBOR_TYPE_ARRAY 4
90 #define CBOR_TYPE_MAP 5
91 #define CBOR_TYPE_TAGGED 6
92 #define CBOR_TYPE_FLOAT 7
94 static const value_string major_type_vals
[] = {
95 { 0, "Unsigned Integer" },
96 { 1, "Negative Integer" },
102 { 7, "Floating-Point or Simple" },
106 static const value_string integer_size_vals
[] = {
111 { 28, "Reserved for future additions" },
112 { 29, "Reserved for future additions" },
113 { 30, "Reserved for future additions" },
114 { 31, "No argument value is derived" },
118 static const value_string length_size_vals
[] = {
123 { 28, "Reserved for future additions" },
124 { 29, "Reserved for future additions" },
125 { 30, "Reserved for future additions" },
126 { 31, "Indefinite Length" },
130 static const value_string float_simple_type_vals
[] = {
131 { 24, "Simple value" },
132 { 25, "IEEE 754 Half-Precision Float" },
133 { 26, "IEEE 754 Single-Precision Float" },
134 { 27, "IEEE 754 Double-Precision Float" },
135 { 28, "Reserved for future additions" },
136 { 29, "Reserved for future additions" },
137 { 30, "Reserved for future additions" },
138 { 31, "Break indefinite length" },
142 /* see https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml#tags */
143 static const value_string tag32_vals
[] = {
144 { 0, "Standard date/time string" },
145 { 1, "Epoch-based date/time" },
146 { 2, "Positive bignum" },
147 { 3, "Negative bignum" },
148 { 4, "Decimal fraction" },
150 { 21, "Expected conversion to base64url encoding" },
151 { 22, "Expected conversion to base64 encoding" },
152 { 23, "Expected conversion to base16 encoding" },
153 { 24, "Encoded CBOR data item" },
154 { 25, "reference the nth previously seen string" },
155 { 26, "Serialised Perl object with classname and constructor arguments" },
156 { 27, "Serialised language-independent object with type name and constructor arguments" },
157 { 28, "mark value as (potentially) shared" },
158 { 29, "reference nth marked value" },
159 { 30, "Rational number" },
163 { 35, "Regular expression" },
164 { 36, "MIME message" },
165 { 37, "Binary UUID" },
166 { 38, "Language-tagged string" },
167 { 39, "Identifier" },
168 { 256, "mark value as having string references" },
169 { 257, "Binary MIME message" },
170 { 264, "Decimal fraction with arbitrary exponent" },
171 { 265, "Bigfloat with arbitrary exponent" },
172 { 22098, "hint that indicates an additional level of indirection" },
173 { 55799, "Self-describe CBOR" },
177 static const val64_string tag64_vals
[] = {
178 { 0, "Standard date/time string" },
179 { 1, "Epoch-based date/time" },
180 { 2, "Positive bignum" },
181 { 3, "Negative bignum" },
182 { 4, "Decimal fraction" },
184 { 21, "Expected conversion to base64url encoding" },
185 { 22, "Expected conversion to base64 encoding" },
186 { 23, "Expected conversion to base16 encoding" },
187 { 24, "Encoded CBOR data item" },
188 { 25, "reference the nth previously seen string" },
189 { 26, "Serialised Perl object with classname and constructor arguments" },
190 { 27, "Serialised language-independent object with type name and constructor arguments" },
191 { 28, "mark value as (potentially) shared" },
192 { 29, "reference nth marked value" },
193 { 30, "Rational number" },
197 { 35, "Regular expression" },
198 { 36, "MIME message" },
199 { 37, "Binary UUID" },
200 { 38, "Language-tagged string" },
201 { 39, "Identifier" },
202 { 256, "mark value as having string references" },
203 { 257, "Binary MIME message" },
204 { 264, "Decimal fraction with arbitrary exponent" },
205 { 265, "Bigfloat with arbitrary exponent" },
206 { 22098, "hint that indicates an additional level of indirection" },
207 { 55799, "Self-describe CBOR" },
211 static const value_string vals_simple_data
[] = {
220 dissect_cbor_main_type(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
);
223 dissect_cbor_float_simple_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
);
226 dissect_cbor_unsigned_integer(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
232 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_unsigned_integer
, tvb
, *offset
, -1, ENC_NA
);
233 subtree
= proto_item_add_subtree(item
, ett_cbor_unsigned_integer
);
235 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
236 if (type_minor
<= 0x17) {
237 proto_tree_add_item(subtree
, hf_cbor_type_uint5
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
240 proto_tree_add_item(subtree
, hf_cbor_item_integer_size
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
244 switch (type_minor
) {
246 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_uint
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &value
);
250 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_uint
, tvb
, *offset
, 2, ENC_BIG_ENDIAN
, &value
);
254 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_uint
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
, &value
);
258 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_uint
, tvb
, *offset
, 8, ENC_BIG_ENDIAN
, &value
);
262 if (type_minor
> 0x17) {
263 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
264 "invalid minor type %i in unsigned integer", type_minor
);
270 proto_item_append_text(item
, ": %" PRIu64
, value
);
271 proto_item_set_end(item
, tvb
, *offset
);
277 dissect_cbor_negative_integer(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
283 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_negative_integer
, tvb
, *offset
, -1, ENC_NA
);
284 subtree
= proto_item_add_subtree(item
, ett_cbor_negative_integer
);
286 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
287 if (type_minor
<= 0x17) {
288 value
= (int64_t)-1 - type_minor
;
289 /* Keep correct bit representation with a modified value. */
290 proto_tree_add_int64_bits_format_value(subtree
, hf_cbor_type_nint
, tvb
, 3, 5, type_minor
, ENC_BIG_ENDIAN
, "%" PRId64
, value
);
292 proto_tree_add_item(subtree
, hf_cbor_item_integer_size
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
296 switch (type_minor
) {
298 value
= (int64_t)-1 - tvb_get_uint8(tvb
, *offset
);
299 proto_tree_add_int64(subtree
, hf_cbor_type_nint
, tvb
, *offset
, 1, value
);
303 value
= (int64_t)-1 - tvb_get_ntohs(tvb
, *offset
);
304 proto_tree_add_int64(subtree
, hf_cbor_type_nint
, tvb
, *offset
, 2, value
);
308 value
= (int64_t)-1 - tvb_get_ntohl(tvb
, *offset
);
309 proto_tree_add_int64(subtree
, hf_cbor_type_nint
, tvb
, *offset
, 4, value
);
313 /* TODO: an overflow could happen here, for negative int < INT64_MIN */
314 value
= (int64_t)-1 - tvb_get_ntoh64(tvb
, *offset
);
316 expert_add_info_format(pinfo
, subtree
, &ei_cbor_too_long_length
,
317 "The value is too small, Wireshark can not display it correctly");
319 proto_tree_add_int64(subtree
, hf_cbor_type_nint
, tvb
, *offset
, 8, value
);
323 if (type_minor
> 0x17) {
324 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
325 "invalid minor type %i in negative integer", type_minor
);
331 proto_item_append_text(item
, ": %" PRId64
, value
);
332 proto_item_set_end(item
, tvb
, *offset
);
338 // NOLINTNEXTLINE(misc-no-recursion)
339 dissect_cbor_byte_string(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
346 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_byte_string
, tvb
, *offset
, -1, ENC_NA
);
347 subtree
= proto_item_add_subtree(item
, ett_cbor_byte_string
);
349 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
350 if (type_minor
<= 0x17) {
351 proto_tree_add_item(subtree
, hf_cbor_item_length5
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
354 proto_tree_add_item(subtree
, hf_cbor_item_length_size
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
358 switch (type_minor
) {
360 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &length
);
364 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 2, ENC_BIG_ENDIAN
, &length
);
368 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
, &length
);
372 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 8, ENC_BIG_ENDIAN
, &length
);
376 proto_item_append_text(item
, ": (indefinite length)");
377 item
= proto_tree_add_item(subtree
, hf_cbor_type_byte_string_indef
, tvb
, *offset
, 1, ENC_NA
);
378 subtree
= proto_item_add_subtree(item
, ett_cbor_byte_string_indef
);
380 eof_type
= tvb_get_uint8(tvb
, *offset
);
381 if (eof_type
== 0xff) {
382 dissect_cbor_float_simple_data(tvb
, pinfo
, subtree
, offset
, 0x1f);
383 proto_item_set_end(item
, tvb
, *offset
);
387 if (((eof_type
& 0xe0) >> 5) != CBOR_TYPE_BYTE_STRING
) {
388 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_element
,
389 "invalid element %i, expected byte string", (eof_type
& 0xe0) >> 5);
393 unsigned recursion_depth
= p_get_proto_depth(pinfo
, proto_cbor
);
394 if (recursion_depth
> prefs
.gui_max_tree_depth
) {
395 proto_tree_add_expert(subtree
, pinfo
, &ei_cbor_max_recursion_depth_reached
, tvb
, 0, 0);
398 p_set_proto_depth(pinfo
, proto_cbor
, recursion_depth
+ 1);
400 bool recursed
= dissect_cbor_byte_string(tvb
, pinfo
, subtree
, offset
, eof_type
& 0x1f);
401 p_set_proto_depth(pinfo
, proto_cbor
, recursion_depth
);
407 DISSECTOR_ASSERT_NOT_REACHED();
410 if (type_minor
> 0x17) {
411 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
412 "invalid minor type %i in byte string", type_minor
);
418 if (length
> INT32_MAX
|| *offset
+ (int)length
< *offset
) {
419 expert_add_info_format(pinfo
, subtree
, &ei_cbor_too_long_length
,
420 "the length (%" PRIu64
") of the byte string too long", length
);
424 proto_tree_add_item(subtree
, hf_cbor_type_byte_string
, tvb
, *offset
, (int)length
, ENC_BIG_ENDIAN
|ENC_NA
);
425 *offset
+= (int)length
;
427 proto_item_append_text(item
, ": (%" PRIu64
" byte%s)", length
, plurality(length
, "", "s"));
428 proto_item_set_end(item
, tvb
, *offset
);
434 // NOLINTNEXTLINE(misc-no-recursion)
435 dissect_cbor_text_string(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
437 const uint8_t *value
= NULL
;
443 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_text_string
, tvb
, *offset
, -1, ENC_NA
);
444 subtree
= proto_item_add_subtree(item
, ett_cbor_text_string
);
446 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
447 if (type_minor
<= 0x17) {
448 proto_tree_add_item(subtree
, hf_cbor_item_length5
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
451 proto_tree_add_item(subtree
, hf_cbor_item_length_size
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
455 switch (type_minor
) {
457 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &length
);
461 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 2, ENC_BIG_ENDIAN
, &length
);
465 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
, &length
);
469 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_length
, tvb
, *offset
, 8, ENC_BIG_ENDIAN
, &length
);
473 proto_item_append_text(item
, ": (indefinite length)");
474 item
= proto_tree_add_item(subtree
, hf_cbor_type_text_string_indef
, tvb
, *offset
, 1, ENC_NA
);
475 subtree
= proto_item_add_subtree(item
, ett_cbor_text_string_indef
);
477 eof_type
= tvb_get_uint8(tvb
, *offset
);
478 if (eof_type
== 0xff) {
479 dissect_cbor_float_simple_data(tvb
, pinfo
, subtree
, offset
, 0x1f);
480 proto_item_set_end(item
, tvb
, *offset
);
484 if (((eof_type
& 0xe0) >> 5) != CBOR_TYPE_TEXT_STRING
) {
485 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_element
,
486 "invalid element %i, expected text string", (eof_type
& 0xe0) >> 5);
490 unsigned recursion_depth
= p_get_proto_depth(pinfo
, proto_cbor
);
491 if (recursion_depth
> prefs
.gui_max_tree_depth
) {
492 proto_tree_add_expert(subtree
, pinfo
, &ei_cbor_max_recursion_depth_reached
, tvb
, 0, 0);
495 p_set_proto_depth(pinfo
, proto_cbor
, recursion_depth
+ 1);
497 bool recursed
= dissect_cbor_text_string(tvb
, pinfo
, subtree
, offset
, eof_type
& 0x1f);
498 p_set_proto_depth(pinfo
, proto_cbor
, recursion_depth
);
504 DISSECTOR_ASSERT_NOT_REACHED();
507 if (type_minor
> 0x17) {
508 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
509 "invalid minor type %i in text string", type_minor
);
515 if (length
> INT32_MAX
|| *offset
+ (int)length
< *offset
) {
516 expert_add_info_format(pinfo
, subtree
, &ei_cbor_too_long_length
,
517 "the length (%" PRIu64
") of the text string too long", length
);
521 proto_tree_add_item_ret_string(subtree
, hf_cbor_type_text_string
, tvb
, *offset
, (int)length
, ENC_BIG_ENDIAN
|ENC_UTF_8
, pinfo
->pool
, &value
);
522 *offset
+= (int)length
;
524 proto_item_append_text(item
, ": %s", value
);
525 proto_item_set_end(item
, tvb
, *offset
);
531 // NOLINTNEXTLINE(misc-no-recursion)
532 dissect_cbor_array(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
537 bool indefinite
= false;
539 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_array
, tvb
, *offset
, -1, ENC_NA
);
540 subtree
= proto_item_add_subtree(item
, ett_cbor_array
);
542 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
544 if (type_minor
<= 0x17) {
545 proto_tree_add_item(subtree
, hf_cbor_item_items5
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
548 proto_tree_add_item(subtree
, hf_cbor_item_length_size
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
552 switch (type_minor
) {
554 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_items
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &length
);
558 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_items
, tvb
, *offset
, 2, ENC_BIG_ENDIAN
, &length
);
562 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_items
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
, &length
);
566 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_items
, tvb
, *offset
, 8, ENC_BIG_ENDIAN
, &length
);
574 if (type_minor
> 0x17) {
575 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
576 "invalid minor type %i in array", type_minor
);
582 for (uint64_t i
= 0; i
< length
; i
++) {
584 int value
= tvb_get_uint8(tvb
, *offset
);
586 dissect_cbor_float_simple_data(tvb
, pinfo
, subtree
, offset
, 0x1f);
591 if (!dissect_cbor_main_type(tvb
, pinfo
, subtree
, offset
)) {
597 proto_item_append_text(item
, ": (indefinite length)");
599 proto_item_append_text(item
, ": (%" PRIu64
" item%s)", length
, plurality(length
, "", "s"));
601 proto_item_set_end(item
, tvb
, *offset
);
607 // NOLINTNEXTLINE(misc-no-recursion)
608 dissect_cbor_map(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
613 bool indefinite
= false;
615 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_map
, tvb
, *offset
, -1, ENC_NA
);
616 subtree
= proto_item_add_subtree(item
, ett_cbor_map
);
618 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
620 if (type_minor
<= 0x17) {
621 proto_tree_add_item(subtree
, hf_cbor_item_pairs5
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
624 proto_tree_add_item(subtree
, hf_cbor_item_length_size
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
628 switch (type_minor
) {
630 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_pairs
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &length
);
634 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_pairs
, tvb
, *offset
, 2, ENC_BIG_ENDIAN
, &length
);
638 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_pairs
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
, &length
);
642 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_item_pairs
, tvb
, *offset
, 8, ENC_BIG_ENDIAN
, &length
);
650 if (type_minor
> 0x17) {
651 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
652 "invalid minor type %i in map", type_minor
);
658 for (uint64_t i
= 0; i
< length
; i
++) {
660 int value
= tvb_get_uint8(tvb
, *offset
);
662 dissect_cbor_float_simple_data(tvb
, pinfo
, subtree
, offset
, 0x1f);
667 if (!dissect_cbor_main_type(tvb
, pinfo
, subtree
, offset
)) {
671 if (!dissect_cbor_main_type(tvb
, pinfo
, subtree
, offset
)) {
677 proto_item_append_text(item
, ": (indefinite length)");
679 proto_item_append_text(item
, ": (%" PRIu64
" pair%s)", length
, plurality(length
, "", "s"));
681 proto_item_set_end(item
, tvb
, *offset
);
687 // NOLINTNEXTLINE(misc-no-recursion)
688 dissect_cbor_tag(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
694 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_tag
, tvb
, *offset
, -1, ENC_NA
);
695 subtree
= proto_item_add_subtree(item
, ett_cbor_tag
);
697 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
699 if (type_minor
<= 0x17) {
700 proto_tree_add_item(subtree
, hf_cbor_type_tag5
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
703 proto_tree_add_item(subtree
, hf_cbor_item_integer_size
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
707 switch (type_minor
) {
709 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_tag
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &tag
);
713 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_tag
, tvb
, *offset
, 2, ENC_BIG_ENDIAN
, &tag
);
717 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_tag
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
, &tag
);
721 proto_tree_add_item_ret_uint64(subtree
, hf_cbor_type_tag
, tvb
, *offset
, 8, ENC_BIG_ENDIAN
, &tag
);
725 if (type_minor
> 0x17) {
726 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
727 "invalid minor type %i in tag", type_minor
);
733 if (!dissect_cbor_main_type(tvb
, pinfo
, subtree
, offset
)) {
737 proto_item_append_text(item
, ": %s (%" PRIu64
")", val64_to_str(tag
, tag64_vals
, "Unknown"), tag
);
738 proto_item_set_end(item
, tvb
, *offset
);
743 /* based on code from rfc7049 appendix-D */
745 decode_half(tvbuff_t
*tvb
, proto_tree
*tree
, proto_item
*item
, int *offset
, int hfindex
)
748 int half
, exponent
, mantissa
;
751 half
= tvb_get_ntohs(tvb
, *offset
);
752 exponent
= (half
>> 10) & 0x1f;
753 mantissa
= half
& 0x3ff;
756 val
= ldexpf((float)mantissa
, -24);
760 proto_tree_add_float(tree
, hfindex
, tvb
, *offset
, 2, val
);
761 proto_item_set_text(item
, "Float: %." G_STRINGIFY(FLT_DIG
) "g", val
);
762 } else if (exponent
!= 31) {
763 val
= ldexpf((float)(mantissa
+ 1024), exponent
- 25);
767 proto_tree_add_float(tree
, hfindex
, tvb
, *offset
, 2, val
);
768 proto_item_set_text(item
, "Float: %." G_STRINGIFY(FLT_DIG
) "g", val
);
770 snprintf(value
, sizeof(value
), "%s%s", half
& 0x8000 ? "-" : "", mantissa
== 0 ? "inf" : "nan");
771 proto_tree_add_float_format_value(tree
, hfindex
, tvb
, *offset
, 2, 0, "%s", value
);
772 proto_item_set_text(item
, "Float: %s", value
);
777 dissect_cbor_float_simple_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
, uint8_t type_minor
)
785 item
= proto_tree_add_item(cbor_tree
, hf_cbor_item_float_simple
, tvb
, *offset
, -1, ENC_NA
);
786 subtree
= proto_item_add_subtree(item
, ett_cbor_float_simple
);
788 proto_tree_add_item(subtree
, hf_cbor_item_major_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
790 if (type_minor
<= 0x17) {
791 proto_tree_add_item_ret_uint(subtree
, hf_cbor_type_simple_data5
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &simple
);
792 proto_item_set_text(item
, "Simple: %s (%u)", val_to_str_const(simple
, vals_simple_data
, "Unknown"), simple
);
794 proto_tree_add_item(subtree
, hf_cbor_item_float_simple_type
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
);
798 switch (type_minor
) {
800 proto_tree_add_item_ret_uint(subtree
, hf_cbor_type_simple_data8
, tvb
, *offset
, 1, ENC_BIG_ENDIAN
, &simple
);
801 proto_item_set_text(item
, "Simple: %s (%u)", val_to_str_const(simple
, vals_simple_data
, "Unknown"), simple
);
805 decode_half(tvb
, subtree
, item
, offset
, hf_cbor_type_float16
);
809 f_value
= tvb_get_ntohieee_float(tvb
, *offset
);
810 proto_tree_add_item(subtree
, hf_cbor_type_float32
, tvb
, *offset
, 4, ENC_BIG_ENDIAN
);
811 proto_item_set_text(item
, "Float: %." G_STRINGIFY(FLT_DIG
) "g", f_value
);
815 d_value
= tvb_get_ntohieee_double(tvb
, *offset
);
816 proto_tree_add_item(subtree
, hf_cbor_type_float64
, tvb
, *offset
, 8, ENC_BIG_ENDIAN
);
817 proto_item_set_text(item
, "Float: %." G_STRINGIFY(DBL_DIG
) "g", d_value
);
821 proto_item_set_text(item
, "Break indefinite length (%u)", type_minor
);
824 if (type_minor
> 0x17) {
825 expert_add_info_format(pinfo
, subtree
, &ei_cbor_invalid_minor_type
,
826 "invalid minor type %i in simple data and float", type_minor
);
832 proto_item_set_end(item
, tvb
, *offset
);
839 // NOLINTNEXTLINE(misc-no-recursion)
840 dissect_cbor_main_type(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*cbor_tree
, int *offset
)
846 type
= tvb_get_uint8(tvb
, *offset
);
848 type_major
= (type
& 0xe0) >> 5;
849 type_minor
= (type
& 0x1f);
851 unsigned recursion_depth
= p_get_proto_depth(pinfo
, proto_cbor
);
853 /* dissect_cbor_main_type and dissect_cbor_tag/dissect_cbor_map can exhaust
854 * the stack calling each other recursively on malformed packets otherwise */
855 if (recursion_depth
> prefs
.gui_max_tree_depth
) {
856 proto_tree_add_expert(cbor_tree
, pinfo
, &ei_cbor_max_recursion_depth_reached
, tvb
, 0, 0);
859 p_set_proto_depth(pinfo
, proto_cbor
, recursion_depth
+ 1);
862 switch (type_major
) {
863 case CBOR_TYPE_USIGNED_INT
:
864 valid
= dissect_cbor_unsigned_integer(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
866 case CBOR_TYPE_NEGATIVE_INT
:
867 valid
= dissect_cbor_negative_integer(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
869 case CBOR_TYPE_BYTE_STRING
:
870 valid
= dissect_cbor_byte_string(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
872 case CBOR_TYPE_TEXT_STRING
:
873 valid
= dissect_cbor_text_string(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
875 case CBOR_TYPE_ARRAY
:
876 valid
= dissect_cbor_array(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
879 valid
= dissect_cbor_map(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
881 case CBOR_TYPE_TAGGED
:
882 valid
= dissect_cbor_tag(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
884 case CBOR_TYPE_FLOAT
:
885 valid
= dissect_cbor_float_simple_data(tvb
, pinfo
, cbor_tree
, offset
, type_minor
);
888 DISSECTOR_ASSERT_NOT_REACHED();
891 p_set_proto_depth(pinfo
, proto_cbor
, recursion_depth
);
896 dissect_cbor(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
899 proto_item
*cbor_root
;
900 proto_tree
*cbor_tree
;
902 cbor_root
= proto_tree_add_item(parent_tree
, proto_cbor
, tvb
, offset
, -1, ENC_NA
);
903 cbor_tree
= proto_item_add_subtree(cbor_root
, ett_cbor
);
904 dissect_cbor_main_type(tvb
, pinfo
, cbor_tree
, &offset
);
906 proto_item_set_len(cbor_root
, offset
);
911 dissect_cborseq(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
914 proto_item
*cbor_root
;
915 proto_tree
*cbor_tree
;
917 cbor_root
= proto_tree_add_item(parent_tree
, proto_cbor
, tvb
, offset
, -1, ENC_NA
);
918 proto_item_append_text(cbor_root
, " Sequence");
919 cbor_tree
= proto_item_add_subtree(cbor_root
, ett_cbor
);
920 while ((unsigned)offset
< tvb_reported_length(tvb
)) {
921 if (!dissect_cbor_main_type(tvb
, pinfo
, cbor_tree
, &offset
)) {
930 proto_register_cbor(void)
932 static hf_register_info hf
[] = {
933 { &hf_cbor_item_major_type
,
934 { "Major Type", "cbor.item.major_type",
935 FT_UINT8
, BASE_DEC
, VALS(major_type_vals
), 0xe0,
938 { &hf_cbor_item_integer_size
,
939 { "Size", "cbor.item.size",
940 FT_UINT8
, BASE_DEC
, VALS(integer_size_vals
), 0x1f,
943 { &hf_cbor_item_length_size
,
944 { "Size", "cbor.item.size",
945 FT_UINT8
, BASE_DEC
, VALS(length_size_vals
), 0x1f,
948 { &hf_cbor_item_length5
,
949 { "Length", "cbor.item.length5",
950 FT_UINT8
, BASE_DEC
, NULL
, 0x1f,
953 { &hf_cbor_item_length
,
954 { "Length", "cbor.item.length",
955 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
958 { &hf_cbor_item_items5
,
959 { "Items", "cbor.item.items5",
960 FT_UINT8
, BASE_DEC
, NULL
, 0x1f,
963 { &hf_cbor_item_items
,
964 { "Items", "cbor.item.items",
965 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
968 { &hf_cbor_item_pairs5
,
969 { "Pairs", "cbor.item.pairs",
970 FT_UINT8
, BASE_DEC
, NULL
, 0x1f,
973 { &hf_cbor_item_pairs
,
974 { "Pairs", "cbor.item.pairs",
975 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
978 { &hf_cbor_item_float_simple_type
,
979 { "Type", "cbor.item.float_simple_type",
980 FT_UINT8
, BASE_DEC
, VALS(float_simple_type_vals
), 0x1f,
983 { &hf_cbor_item_unsigned_integer
,
984 { "Unsigned Integer", "cbor.item.unsigned_integer",
985 FT_NONE
, BASE_NONE
, NULL
, 0x00,
988 { &hf_cbor_item_negative_integer
,
989 { "Negative Integer", "cbor.item.negative_integer",
990 FT_NONE
, BASE_NONE
, NULL
, 0x00,
993 { &hf_cbor_item_text_string
,
994 { "Text String", "cbor.item.textstring",
995 FT_NONE
, BASE_NONE
, NULL
, 0x00,
998 { &hf_cbor_item_byte_string
,
999 { "Byte String", "cbor.item.bytestring",
1000 FT_NONE
, BASE_NONE
, NULL
, 0x00,
1003 { &hf_cbor_item_array
,
1004 { "Array", "cbor.item.array",
1005 FT_NONE
, BASE_NONE
, NULL
, 0x00,
1008 { &hf_cbor_item_map
,
1009 { "Map", "cbor.item.map",
1010 FT_NONE
, BASE_NONE
, NULL
, 0x00,
1013 { &hf_cbor_item_tag
,
1014 { "Tag", "cbor.item.tag",
1015 FT_NONE
, BASE_NONE
, NULL
, 0x00,
1018 { &hf_cbor_item_float_simple
,
1019 { "Floating-point or Simple", "cbor.item.float_or_simple",
1020 FT_NONE
, BASE_NONE
, NULL
, 0x00,
1023 { &hf_cbor_type_uint5
,
1024 { "Unsigned Integer", "cbor.type.uint",
1025 FT_UINT8
, BASE_DEC
, NULL
, 0x1f,
1028 { &hf_cbor_type_uint
,
1029 { "Unsigned Integer", "cbor.type.uint",
1030 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
1033 { &hf_cbor_type_nint
,
1034 { "Negative Integer", "cbor.type.nint",
1035 FT_INT64
, BASE_DEC
, NULL
, 0x00,
1038 { &hf_cbor_type_byte_string
,
1039 { "Byte String", "cbor.type.bytestring",
1040 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
1043 { &hf_cbor_type_byte_string_indef
,
1044 { "Byte String (indefinite length)", "cbor.type.bytestring.indef",
1045 FT_NONE
, BASE_NONE
, NULL
, 0x0,
1048 { &hf_cbor_type_text_string
,
1049 { "Text String", "cbor.type.textstring",
1050 FT_STRING
, BASE_NONE
, NULL
, 0x00,
1053 { &hf_cbor_type_text_string_indef
,
1054 { "Text String (indefinite length)", "cbor.type.textstring.indef",
1055 FT_NONE
, BASE_NONE
, NULL
, 0x0,
1058 { &hf_cbor_type_tag5
,
1059 { "Tag", "cbor.type.tag",
1060 FT_UINT8
, BASE_DEC
, VALS(tag32_vals
), 0x1f,
1063 { &hf_cbor_type_tag
,
1064 { "Tag", "cbor.type.tag",
1065 FT_UINT64
, BASE_DEC
|BASE_VAL64_STRING
, VALS64(tag64_vals
), 0x00,
1068 { &hf_cbor_type_simple_data5
,
1069 { "Simple data", "cbor.type.simple_data",
1070 FT_UINT8
, BASE_DEC
, VALS(vals_simple_data
), 0x1f,
1073 { &hf_cbor_type_simple_data8
,
1074 { "Simple data", "cbor.type.simple_data",
1075 FT_UINT8
, BASE_DEC
, VALS(vals_simple_data
), 0x00,
1078 { &hf_cbor_type_float16
,
1079 { "Float 16 Bit", "cbor.type.float16",
1080 FT_FLOAT
, BASE_NONE
, NULL
, 0x00,
1083 { &hf_cbor_type_float32
,
1084 { "Float 32 Bit", "cbor.type.float32",
1085 FT_FLOAT
, BASE_NONE
, NULL
, 0x00,
1088 { &hf_cbor_type_float64
,
1089 { "Float 64 Bit", "cbor.type.float64",
1090 FT_DOUBLE
, BASE_NONE
, NULL
, 0x00,
1095 static int *ett
[] = {
1098 &ett_cbor_unsigned_integer
,
1099 &ett_cbor_negative_integer
,
1100 &ett_cbor_byte_string
,
1101 &ett_cbor_byte_string_indef
,
1102 &ett_cbor_text_string
,
1103 &ett_cbor_text_string_indef
,
1107 &ett_cbor_float_simple
1110 static ei_register_info ei
[] = {
1111 { &ei_cbor_invalid_minor_type
,
1112 { "cbor.invalid_minor_type", PI_MALFORMED
, PI_WARN
, "Invalid minor type", EXPFILL
}},
1113 { &ei_cbor_invalid_element
,
1114 { "cbor.invalid_element", PI_MALFORMED
, PI_WARN
, "Invalid element", EXPFILL
}},
1115 { &ei_cbor_too_long_length
,
1116 { "cbor.too_long_length", PI_MALFORMED
, PI_WARN
, "Too long length", EXPFILL
}},
1117 { &ei_cbor_max_recursion_depth_reached
,
1118 { "cbor.max_recursion_depth_reached", PI_PROTOCOL
, PI_WARN
, "Maximum allowed recursion depth reached. Dissection stopped.", EXPFILL
}},
1121 expert_module_t
*expert_cbor
;
1123 proto_cbor
= proto_register_protocol("Concise Binary Object Representation", "CBOR", "cbor");
1124 proto_register_field_array(proto_cbor
, hf
, array_length(hf
));
1125 proto_register_subtree_array(ett
, array_length(ett
));
1126 expert_cbor
= expert_register_protocol(proto_cbor
);
1127 expert_register_field_array(expert_cbor
, ei
, array_length(ei
));
1129 cbor_handle
= register_dissector("cbor", dissect_cbor
, proto_cbor
);
1130 cborseq_handle
= register_dissector_with_description("cborseq", "CBOR Sequence", dissect_cborseq
, proto_cbor
);
1134 proto_reg_handoff_cbor(void)
1136 dissector_add_string("media_type", "application/cbor", cbor_handle
); /* RFC 7049 */
1137 dissector_add_string("media_type", "application/senml+cbor", cbor_handle
); /* RFC 8428 */
1138 dissector_add_string("media_type", "application/sensml+cbor", cbor_handle
); /* RFC 8428 */
1139 dissector_add_string("media_type", "application/cbor-seq", cborseq_handle
); /* RFC 8742 */
1141 dissector_add_string("media_type.suffix", "cbor", cbor_handle
);
1142 dissector_add_string("media_type.suffix", "cbor-seq", cborseq_handle
);
1146 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1151 * indent-tabs-mode: t
1154 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1155 * :indentSize=8:tabSize=8:noTabs=false: