wireshark/epan/wscbor.h

321 lines
11 KiB
C

/** @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__ */