COSE: Handle indefinite tstr/bstr encodings
This commit is contained in:
parent
39036a0a30
commit
bc3bced07d
|
@ -2038,6 +2038,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
|
|||
wscbor_chunk_mark_errors@Base 3.5.1
|
||||
wscbor_chunk_read@Base 3.5.1
|
||||
wscbor_error_new@Base 3.5.1
|
||||
wscbor_expert_items@Base 3.5.1
|
||||
wscbor_has_errors@Base 3.5.1
|
||||
wscbor_init@Base 3.5.1
|
||||
wscbor_is_indefinite_break@Base 3.5.1
|
||||
|
|
|
@ -369,7 +369,7 @@ static void dissect_header_pair(dissector_table_t dis_table, cose_header_context
|
|||
break;
|
||||
}
|
||||
case CBOR_TYPE_STRING: {
|
||||
const char *label = wscbor_require_tstr(wmem_packet_scope(), tvb, chunk_label);
|
||||
const char *label = wscbor_require_tstr(wmem_packet_scope(), chunk_label);
|
||||
item_label = proto_tree_add_cbor_tstr(tree, hf_hdr_label_tstr, pinfo, tvb, chunk_label);
|
||||
if (label) {
|
||||
key.label = ctx->label =
|
||||
|
@ -467,7 +467,7 @@ static void dissect_msg_tag(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t
|
|||
static void dissect_headers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
|
||||
// Protected in bstr
|
||||
wscbor_chunk_t *chunk_prot_bstr = wscbor_chunk_read(wmem_packet_scope(), tvb, offset);
|
||||
tvbuff_t *tvb_prot = wscbor_require_bstr(tvb, chunk_prot_bstr);
|
||||
tvbuff_t *tvb_prot = wscbor_require_bstr(wmem_packet_scope(), chunk_prot_bstr);
|
||||
proto_item *item_prot_bstr = proto_tree_add_cbor_bstr(tree, hf_hdr_prot_bstr, pinfo, tvb, chunk_prot_bstr);
|
||||
if (tvb_prot) {
|
||||
proto_tree *tree_prot = proto_item_add_subtree(item_prot_bstr, ett_prot_bstr);
|
||||
|
@ -494,13 +494,13 @@ static void dissect_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|||
proto_tree_add_cbor_ctrl(tree, hf_payload_null, pinfo, tvb, chunk);
|
||||
}
|
||||
else {
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_payload_bstr, pinfo, tvb, chunk);
|
||||
}
|
||||
}
|
||||
static void dissect_signature(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_signature, pinfo, tvb, chunk);
|
||||
}
|
||||
static void dissect_cose_signature(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
|
||||
|
@ -521,7 +521,7 @@ static void dissect_ciphertext(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
|
|||
proto_tree_add_cbor_ctrl(tree, hf_ciphertext_null, pinfo, tvb, chunk);
|
||||
}
|
||||
else {
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_ciphertext_bstr, pinfo, tvb, chunk);
|
||||
}
|
||||
}
|
||||
|
@ -557,7 +557,7 @@ static void dissect_cose_recipient(tvbuff_t *tvb, packet_info *pinfo, proto_tree
|
|||
}
|
||||
static void dissect_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_tag, pinfo, tvb, chunk);
|
||||
}
|
||||
|
||||
|
@ -723,7 +723,7 @@ static void dissect_value_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
|
|||
break;
|
||||
}
|
||||
case CBOR_TYPE_STRING: {
|
||||
const char *val = wscbor_require_tstr(wmem_packet_scope(), tvb, chunk);
|
||||
const char *val = wscbor_require_tstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_tstr(tree, hf_hdr_alg_tstr, pinfo, tvb, chunk);
|
||||
if (value && val) {
|
||||
*value = g_variant_new_string(val);
|
||||
|
@ -739,7 +739,7 @@ static int dissect_header_salt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_hdr_salt, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
@ -831,7 +831,7 @@ static int dissect_header_kid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_hdr_kid, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
@ -841,7 +841,7 @@ static int dissect_header_iv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_hdr_iv, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
@ -851,7 +851,7 @@ static int dissect_header_piv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_hdr_piv, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
@ -859,7 +859,7 @@ static int dissect_header_piv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
|
|||
|
||||
static void dissect_value_x5cert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
|
||||
wscbor_chunk_t *chunk_item = wscbor_chunk_read(wmem_packet_scope(), tvb, offset);
|
||||
tvbuff_t *tvb_item = wscbor_require_bstr(tvb, chunk_item);
|
||||
tvbuff_t *tvb_item = wscbor_require_bstr(wmem_packet_scope(), chunk_item);
|
||||
|
||||
if (tvb_item) {
|
||||
// disallow column text rewrite
|
||||
|
@ -931,7 +931,7 @@ static int dissect_header_x5t(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
|
|||
dissect_value_alg(tvb, pinfo, tree_list, &offset, NULL);
|
||||
|
||||
wscbor_chunk_t *chunk_hash = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk_hash);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk_hash);
|
||||
proto_tree_add_cbor_bstr(tree_list, hf_hdr_x5t_hash, pinfo, tvb, chunk_hash);
|
||||
|
||||
}
|
||||
|
@ -1000,7 +1000,7 @@ static int dissect_keyparam_kty(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
|
|||
break;
|
||||
}
|
||||
case CBOR_TYPE_STRING: {
|
||||
const char *val = wscbor_require_tstr(wmem_packet_scope(), tvb, chunk);
|
||||
const char *val = wscbor_require_tstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_tstr(tree, hf_keyparam_kty_tstr, pinfo, tvb, chunk);
|
||||
if (val) {
|
||||
ctx->principal = g_variant_new_string(val);
|
||||
|
@ -1050,7 +1050,7 @@ static int dissect_keyparam_baseiv(tvbuff_t *tvb, packet_info *pinfo, proto_tree
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_keyparam_baseiv, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
@ -1082,7 +1082,7 @@ static int dissect_keyparam_xcoord(tvbuff_t *tvb, packet_info *pinfo, proto_tree
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_keyparam_xcoord, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
@ -1112,7 +1112,7 @@ static int dissect_keyparam_dcoord(tvbuff_t *tvb, packet_info *pinfo, proto_tree
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_keyparam_dcoord, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
@ -1122,7 +1122,7 @@ static int dissect_keyparam_k(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
|
|||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
|
||||
wscbor_require_bstr(tvb, chunk);
|
||||
wscbor_require_bstr(wmem_packet_scope(), chunk);
|
||||
proto_tree_add_cbor_bstr(tree, hf_keyparam_k, pinfo, tvb, chunk);
|
||||
|
||||
return offset;
|
||||
|
|
157
epan/wscbor.c
157
epan/wscbor.c
|
@ -26,11 +26,13 @@ static expert_field ei_cbor_invalid = EI_INIT;
|
|||
static expert_field ei_cbor_overflow = EI_INIT;
|
||||
static expert_field ei_cbor_wrong_type = EI_INIT;
|
||||
static expert_field ei_cbor_array_wrong_size = EI_INIT;
|
||||
static expert_field ei_cbor_indef_string = EI_INIT;
|
||||
static ei_register_info expertitems[] = {
|
||||
{&ei_cbor_invalid, {"_ws.wscbor.cbor_invalid", PI_MALFORMED, PI_ERROR, "CBOR cannot be decoded", EXPFILL}},
|
||||
{&ei_cbor_overflow, {"_ws.wscbor.cbor_overflow", PI_UNDECODED, PI_ERROR, "CBOR overflow of Wireshark value", EXPFILL}},
|
||||
{&ei_cbor_wrong_type, {"_ws.wscbor.cbor_wrong_type", PI_MALFORMED, PI_ERROR, "CBOR is wrong type", EXPFILL}},
|
||||
{&ei_cbor_array_wrong_size, {"_ws.wscbor.array_wrong_size", PI_MALFORMED, PI_WARN, "CBOR array is the wrong size", EXPFILL}},
|
||||
{&ei_cbor_indef_string, {"_ws.wscbor.indef_string", PI_COMMENTS_GROUP, PI_COMMENT, "String uses indefinite-length encoding", EXPFILL}},
|
||||
};
|
||||
|
||||
/// The basic header structure of CBOR encoding
|
||||
|
@ -81,12 +83,18 @@ static void wscbor_read_unsigned(wscbor_head_t *head, tvbuff_t *tvb) {
|
|||
}
|
||||
|
||||
/** Read just the CBOR head octet.
|
||||
* @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 with just the head length.
|
||||
* @return The new head object.
|
||||
* This never returns NULL.
|
||||
* @post Will throw wireshark exception if read fails.
|
||||
*/
|
||||
static wscbor_head_t * wscbor_head_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint start) {
|
||||
static wscbor_head_t * wscbor_head_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset) {
|
||||
wscbor_head_t *head = wmem_new0(alloc, wscbor_head_t);
|
||||
|
||||
head->start = start;
|
||||
head->start = *offset;
|
||||
const guint8 first = tvb_get_guint8(tvb, head->start);
|
||||
head->length += 1;
|
||||
|
||||
|
@ -118,6 +126,7 @@ static wscbor_head_t * wscbor_head_read(wmem_allocator_t *alloc, tvbuff_t *tvb,
|
|||
break;
|
||||
}
|
||||
|
||||
*offset += head->length;
|
||||
return head;
|
||||
}
|
||||
|
||||
|
@ -127,21 +136,31 @@ static void wscbor_head_free(wmem_allocator_t *alloc, wscbor_head_t *head) {
|
|||
wmem_free(alloc, head);
|
||||
}
|
||||
|
||||
struct _wscbor_chunk_priv_t {
|
||||
/// The allocator used for wscbor_chunk_t.errors and wscbor_chunk_t.tags
|
||||
wmem_allocator_t *alloc;
|
||||
/// For string types, including indefinite length, the item payload.
|
||||
/// Otherwise NULL.
|
||||
tvbuff_t *str_value;
|
||||
|
||||
};
|
||||
|
||||
/** Get a clamped string length suitable for tvb functions.
|
||||
* @param[in,out] chunk The chunk to read and set errors on.
|
||||
* @param[in,out] chunk The chunk to set errors on.
|
||||
* @param head_value The value to clamp.
|
||||
* @return The clamped length value.
|
||||
*/
|
||||
static gint wscbor_get_length(const wscbor_chunk_t *chunk) {
|
||||
static gint wscbor_get_length(wscbor_chunk_t *chunk, guint64 head_value) {
|
||||
gint length;
|
||||
if (chunk->head_value > G_MAXINT) {
|
||||
if (head_value > G_MAXINT) {
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_alloc, &ei_cbor_overflow,
|
||||
chunk->_priv->alloc, &ei_cbor_overflow,
|
||||
NULL
|
||||
));
|
||||
length = G_MAXINT;
|
||||
}
|
||||
else {
|
||||
length = (gint) chunk->head_value;
|
||||
length = (gint) head_value;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
@ -168,7 +187,8 @@ wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint
|
|||
DISSECTOR_ASSERT(tvb != NULL);
|
||||
|
||||
wscbor_chunk_t *chunk = wmem_new0(alloc, wscbor_chunk_t);
|
||||
chunk->_alloc = alloc;
|
||||
chunk->_priv = wmem_new0(alloc, struct _wscbor_chunk_priv_t);
|
||||
chunk->_priv->alloc = alloc;
|
||||
chunk->errors = wmem_list_new(alloc);
|
||||
chunk->tags = wmem_list_new(alloc);
|
||||
chunk->start = *offset;
|
||||
|
@ -176,8 +196,7 @@ wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint
|
|||
// Read a sequence of tags followed by an item header
|
||||
while (TRUE) {
|
||||
// This will break out of the loop if it runs out of buffer
|
||||
wscbor_head_t *head = wscbor_head_read(alloc, tvb, *offset);
|
||||
*offset += head->length;
|
||||
wscbor_head_t *head = wscbor_head_read(alloc, tvb, offset);
|
||||
chunk->head_length += head->length;
|
||||
if (head->error) {
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(alloc, head->error, NULL));
|
||||
|
@ -198,25 +217,72 @@ wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint
|
|||
chunk->type_minor = head->type_minor;
|
||||
chunk->head_value = head->rawvalue;
|
||||
|
||||
chunk->data_length = chunk->head_length;
|
||||
switch ((cbor_type)(head->type_major)) {
|
||||
case CBOR_TYPE_BYTESTRING:
|
||||
case CBOR_TYPE_STRING:
|
||||
if (chunk->type_minor != 31) {
|
||||
const gint datalen = wscbor_get_length(chunk);
|
||||
// skip over definite data
|
||||
*offset += datalen;
|
||||
chunk->data_length += datalen;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
wscbor_head_free(alloc, head);
|
||||
break;
|
||||
}
|
||||
|
||||
// Data beyond the tags and item head
|
||||
chunk->data_length = chunk->head_length;
|
||||
switch (chunk->type_major) {
|
||||
case CBOR_TYPE_BYTESTRING:
|
||||
case CBOR_TYPE_STRING:
|
||||
if (chunk->type_minor != 31) {
|
||||
const gint datalen = wscbor_get_length(chunk, chunk->head_value);
|
||||
// skip over definite data
|
||||
*offset += datalen;
|
||||
chunk->data_length += datalen;
|
||||
chunk->_priv->str_value = tvb_new_subset_length(tvb, chunk->start + chunk->head_length, datalen);
|
||||
}
|
||||
else {
|
||||
// indefinite length, sequence of definite items
|
||||
chunk->_priv->str_value = tvb_new_composite();
|
||||
|
||||
while (TRUE) {
|
||||
wscbor_head_t *head = wscbor_head_read(alloc, tvb, offset);
|
||||
chunk->data_length += head->length;
|
||||
if (head->error) {
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(alloc, head->error, NULL));
|
||||
}
|
||||
const gboolean is_break = (
|
||||
(head->type_major == CBOR_TYPE_FLOAT_CTRL)
|
||||
&& (head->type_minor == 31)
|
||||
);
|
||||
if (!is_break) {
|
||||
if (head->type_major != chunk->type_major) {
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_priv->alloc, &ei_cbor_wrong_type,
|
||||
"Indefinite sub-string item has major type %d, should be %d",
|
||||
head->type_major, chunk->type_major
|
||||
));
|
||||
}
|
||||
else {
|
||||
const gint datalen = wscbor_get_length(chunk, head->rawvalue);
|
||||
*offset += datalen;
|
||||
chunk->data_length += datalen;
|
||||
tvb_composite_append(
|
||||
chunk->_priv->str_value,
|
||||
tvb_new_subset_length(tvb, head->start + head->length, datalen)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
wscbor_head_free(alloc, head);
|
||||
if (is_break) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_priv->alloc, &ei_cbor_indef_string,
|
||||
NULL
|
||||
));
|
||||
tvb_composite_finalize(chunk->_priv->str_value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
@ -227,7 +293,7 @@ static void wscbor_subitem_free(gpointer data, gpointer userdata) {
|
|||
|
||||
void wscbor_chunk_free(wscbor_chunk_t *chunk) {
|
||||
DISSECTOR_ASSERT(chunk);
|
||||
wmem_allocator_t *alloc = chunk->_alloc;
|
||||
wmem_allocator_t *alloc = chunk->_priv->alloc;
|
||||
wmem_list_foreach(chunk->errors, wscbor_subitem_free, alloc);
|
||||
wmem_destroy_list(chunk->errors);
|
||||
wmem_list_foreach(chunk->tags, wscbor_subitem_free, alloc);
|
||||
|
@ -270,11 +336,7 @@ gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *off
|
|||
break;
|
||||
case CBOR_TYPE_BYTESTRING:
|
||||
case CBOR_TYPE_STRING:
|
||||
if (chunk->type_minor == 31) {
|
||||
// wait for indefinite break
|
||||
while (!wscbor_skip_next_item(alloc, tvb, offset)) {}
|
||||
}
|
||||
// wscbor_read_chunk() sets offset past definite value
|
||||
// wscbor_read_chunk() sets offset past string value
|
||||
break;
|
||||
case CBOR_TYPE_ARRAY: {
|
||||
if (chunk->type_minor == 31) {
|
||||
|
@ -334,12 +396,19 @@ void wscbor_init(void) {
|
|||
expert_register_field_array(expert_wscbor, expertitems, array_length(expertitems));
|
||||
}
|
||||
|
||||
const ei_register_info * wscbor_expert_items(int *size) {
|
||||
if (size) {
|
||||
*size = array_length(expertitems);
|
||||
}
|
||||
return expertitems;
|
||||
}
|
||||
|
||||
gboolean wscbor_require_major_type(wscbor_chunk_t *chunk, cbor_type major) {
|
||||
if (chunk->type_major == major) {
|
||||
return TRUE;
|
||||
}
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_alloc, &ei_cbor_wrong_type,
|
||||
chunk->_priv->alloc, &ei_cbor_wrong_type,
|
||||
"Item has major type %d, should be %d",
|
||||
chunk->type_major, major
|
||||
));
|
||||
|
@ -356,7 +425,7 @@ gboolean wscbor_require_array_size(wscbor_chunk_t *chunk, guint64 count_min, gui
|
|||
}
|
||||
if ((chunk->head_value < count_min) || (chunk->head_value > count_max)) {
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_alloc, &ei_cbor_array_wrong_size,
|
||||
chunk->_priv->alloc, &ei_cbor_array_wrong_size,
|
||||
"Array has %" PRId64 " items, should be within [%"PRId64", %"PRId64"]",
|
||||
chunk->head_value, count_min, count_max
|
||||
));
|
||||
|
@ -384,7 +453,7 @@ gboolean * wscbor_require_boolean(wmem_allocator_t *alloc, wscbor_chunk_t *chunk
|
|||
}
|
||||
default:
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_alloc, &ei_cbor_wrong_type,
|
||||
chunk->_priv->alloc, &ei_cbor_wrong_type,
|
||||
"Item has minor type %d, should be %d or %d",
|
||||
chunk->type_minor, CBOR_CTRL_TRUE, CBOR_CTRL_FALSE
|
||||
));
|
||||
|
@ -412,7 +481,7 @@ gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
|
|||
if (chunk->head_value > INT64_MAX) {
|
||||
clamped = INT64_MAX;
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_alloc, &ei_cbor_overflow,
|
||||
chunk->_priv->alloc, &ei_cbor_overflow,
|
||||
NULL
|
||||
));
|
||||
}
|
||||
|
@ -431,7 +500,7 @@ gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
|
|||
}
|
||||
default:
|
||||
wmem_list_append(chunk->errors, wscbor_error_new(
|
||||
chunk->_alloc, &ei_cbor_wrong_type,
|
||||
chunk->_priv->alloc, &ei_cbor_wrong_type,
|
||||
"Item has major type %d, should be %d or %d",
|
||||
chunk->type_major, CBOR_TYPE_UINT, CBOR_TYPE_NEGINT
|
||||
));
|
||||
|
@ -440,20 +509,20 @@ gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
|
|||
return result;
|
||||
}
|
||||
|
||||
char * wscbor_require_tstr(wmem_allocator_t *alloc, tvbuff_t *parent, wscbor_chunk_t *chunk) {
|
||||
char * wscbor_require_tstr(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) {
|
||||
if (!wscbor_require_major_type(chunk, CBOR_TYPE_STRING)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)tvb_get_string_enc(alloc, parent, chunk->start + chunk->head_length, wscbor_get_length(chunk), ENC_UTF_8);
|
||||
return (char *)tvb_get_string_enc(alloc, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), ENC_UTF_8);
|
||||
}
|
||||
|
||||
tvbuff_t * wscbor_require_bstr(tvbuff_t *parent, wscbor_chunk_t *chunk) {
|
||||
tvbuff_t * wscbor_require_bstr(wmem_allocator_t *alloc _U_, wscbor_chunk_t *chunk) {
|
||||
if (!wscbor_require_major_type(chunk, CBOR_TYPE_BYTESTRING)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tvb_new_subset_length(parent, chunk->start + chunk->head_length, wscbor_get_length(chunk));
|
||||
return chunk->_priv->str_value;
|
||||
}
|
||||
|
||||
proto_item * proto_tree_add_cbor_container(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
|
||||
|
@ -533,14 +602,14 @@ proto_item * proto_tree_add_cbor_bitmask(proto_tree *tree, int hfindex, const gi
|
|||
return item;
|
||||
}
|
||||
|
||||
proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
|
||||
proto_item *item = proto_tree_add_item(tree, hfindex, tvb, chunk->start + chunk->head_length, wscbor_get_length(chunk), 0);
|
||||
proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb _U_, const wscbor_chunk_t *chunk) {
|
||||
proto_item *item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
|
||||
wscbor_chunk_mark_errors(pinfo, item, chunk);
|
||||
return item;
|
||||
}
|
||||
|
||||
proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
|
||||
proto_item *item = proto_tree_add_item(tree, hfindex, tvb, chunk->start + chunk->head_length, wscbor_get_length(chunk), 0);
|
||||
proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb _U_, const wscbor_chunk_t *chunk) {
|
||||
proto_item *item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
|
||||
wscbor_chunk_mark_errors(pinfo, item, chunk);
|
||||
return item;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,13 @@ extern "C" {
|
|||
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
|
||||
|
@ -79,10 +86,12 @@ typedef struct {
|
|||
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 {
|
||||
/// The allocator used for #errors and #tags
|
||||
wmem_allocator_t *_alloc;
|
||||
/// Internal private data
|
||||
wscbor_chunk_priv_t *_priv;
|
||||
|
||||
/// The start offset of this chunk
|
||||
gint start;
|
||||
|
@ -111,9 +120,11 @@ typedef struct {
|
|||
* @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 if the read itself ran out of data.
|
||||
* @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);
|
||||
|
@ -239,24 +250,30 @@ 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 parent The containing buffer.
|
||||
* @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, tvbuff_t *parent, wscbor_chunk_t *chunk);
|
||||
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 parent The containing buffer.
|
||||
* @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 string.
|
||||
* @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(tvbuff_t *parent, wscbor_chunk_t *chunk);
|
||||
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
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <epan/wmem_scopes.h>
|
||||
#include <epan/exceptions.h>
|
||||
#include <wsutil/wmem/wmem_list.h>
|
||||
#include <wsutil/wmem/wmem_map.h>
|
||||
|
||||
#include <ws_diag_control.h>
|
||||
|
||||
|
@ -41,7 +42,9 @@ DIAG_OFF_PEDANTIC
|
|||
example_s ex_uint = {1, (const guint8 *)"\x01", 1, 1, CBOR_TYPE_UINT, 1};
|
||||
example_s ex_nint = {1, (const guint8 *)"\x20", 1, 1, CBOR_TYPE_NEGINT, 0};
|
||||
example_s ex_bstr = {3, (const guint8 *)"\x42\x68\x69", 1, 3, CBOR_TYPE_BYTESTRING, 2};
|
||||
example_s ex_bstr_indef = {6, (const guint8 *)"\x5F\x41\x68\x41\x69\xFF", 1, 6, CBOR_TYPE_BYTESTRING, 0};
|
||||
example_s ex_tstr = {3, (const guint8 *)"\x62\x68\x69", 1, 3, CBOR_TYPE_STRING, 2};
|
||||
example_s ex_tstr_indef = {6, (const guint8 *)"\x7F\x61\x68\x61\x69\xFF", 1, 6, CBOR_TYPE_STRING, 0};
|
||||
example_s ex_false = {1, (const guint8 *)"\xF4", 1, 1, CBOR_TYPE_FLOAT_CTRL, CBOR_CTRL_FALSE};
|
||||
example_s ex_true = {1, (const guint8 *)"\xF5", 1, 1, CBOR_TYPE_FLOAT_CTRL, CBOR_CTRL_TRUE};
|
||||
example_s ex_null = {1, (const guint8 *)"\xF6", 1, 1, CBOR_TYPE_FLOAT_CTRL, CBOR_CTRL_NULL};
|
||||
|
@ -57,10 +60,25 @@ DIAG_ON_PEDANTIC
|
|||
|
||||
static const example_s * all_examples[] = {
|
||||
&ex_uint, &ex_nint,
|
||||
&ex_bstr, &ex_bstr_short, &ex_tstr,
|
||||
&ex_bstr, &ex_bstr_indef,
|
||||
&ex_tstr, &ex_tstr_indef,
|
||||
&ex_false, &ex_true, &ex_null, &ex_undef, &ex_break
|
||||
};
|
||||
|
||||
static wmem_map_t *real_errors = NULL;
|
||||
|
||||
static gint has_real_errors(const wscbor_chunk_t *chunk) {
|
||||
gint count = 0;
|
||||
wmem_list_frame_t *frm = wmem_list_head(chunk->errors);
|
||||
for (; frm; frm = wmem_list_frame_next(frm)) {
|
||||
const wscbor_error_t *err = wmem_list_frame_data(frm);
|
||||
if (wmem_map_contains(real_errors, err->ei)) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* These test are organized in order of the appearance, in wscbor.h, of
|
||||
* the basic functions that they test. This makes it easier to
|
||||
|
@ -71,7 +89,7 @@ static const example_s * all_examples[] = {
|
|||
/* WSCBOR TESTING FUNCTIONS (/wscbor/) */
|
||||
|
||||
static void
|
||||
wscbor_test_read_simple(void)
|
||||
wscbor_test_chunk_read_simple(void)
|
||||
{
|
||||
for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) {
|
||||
const example_s *ex = all_examples[ex_ix];
|
||||
|
@ -82,7 +100,7 @@ wscbor_test_read_simple(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
g_assert_cmpuint(chunk->head_length, ==, ex->head_length);
|
||||
g_assert_cmpuint(chunk->data_length, ==, ex->data_length);
|
||||
|
@ -96,7 +114,7 @@ wscbor_test_read_simple(void)
|
|||
}
|
||||
|
||||
static void
|
||||
wscbor_test_read_simple_tags(void)
|
||||
wscbor_test_chunk_read_simple_tags(void)
|
||||
{
|
||||
const guint8 *const tags = (const guint8 *)"\xC1\xD8\xC8";
|
||||
tvbuff_t *tvb_tags = tvb_new_real_data(tags, 3, 3);
|
||||
|
@ -114,7 +132,7 @@ wscbor_test_read_simple_tags(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
g_assert_cmpuint(chunk->head_length, ==, ex->head_length + 3);
|
||||
g_assert_cmpuint(chunk->data_length, ==, ex->data_length + 3);
|
||||
|
@ -146,7 +164,7 @@ wscbor_test_read_simple_tags(void)
|
|||
}
|
||||
|
||||
static void
|
||||
wscbor_test_read_invalid(void)
|
||||
wscbor_test_chunk_read_invalid(void)
|
||||
{
|
||||
tvbuff_t *tvb = tvb_new_real_data((const guint8 *)"\x00\x01\x02\xC1", 4, 2);
|
||||
gint offset = 2;
|
||||
|
@ -154,33 +172,33 @@ wscbor_test_read_invalid(void)
|
|||
{ // last valid item
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(chunk->type_major, ==, CBOR_TYPE_UINT);
|
||||
g_assert_cmpuint(chunk->head_value, ==, 2);
|
||||
wscbor_chunk_free(chunk);
|
||||
}
|
||||
g_assert_cmpint(offset, ==, 3);
|
||||
{ // Tag without item
|
||||
guint caught = 0;
|
||||
volatile gulong caught = 0;
|
||||
TRY {
|
||||
wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(FALSE);
|
||||
}
|
||||
CATCH(ReportedBoundsError) {
|
||||
caught = ReportedBoundsError;
|
||||
CATCH_BOUNDS_ERRORS {
|
||||
caught = exc->except_id.except_code;
|
||||
}
|
||||
ENDTRY;
|
||||
g_assert_cmpuint(caught, ==, ReportedBoundsError);
|
||||
}
|
||||
g_assert_cmpint(offset, ==, 4);
|
||||
{ // Read past the end
|
||||
volatile guint caught = 0;
|
||||
volatile gulong caught = 0;
|
||||
TRY {
|
||||
wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(FALSE);
|
||||
}
|
||||
CATCH(ReportedBoundsError) {
|
||||
caught = ReportedBoundsError;
|
||||
CATCH_BOUNDS_ERRORS {
|
||||
caught = exc->except_id.except_code;
|
||||
}
|
||||
ENDTRY;
|
||||
g_assert_cmpuint(caught, ==, ReportedBoundsError);
|
||||
|
@ -202,17 +220,17 @@ wscbor_test_is_indefinite_break(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
// this test never modifies the chunk
|
||||
const gboolean val = wscbor_is_indefinite_break(chunk);
|
||||
if (memcmp(ex->enc, "\xFF", 1) == 0) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
}
|
||||
else {
|
||||
g_assert(!val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
}
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
|
@ -221,22 +239,44 @@ wscbor_test_is_indefinite_break(void)
|
|||
}
|
||||
|
||||
static void
|
||||
wscbor_test_skip_next_item(void)
|
||||
wscbor_test_skip_next_item_simple(void)
|
||||
{
|
||||
// skip simple items
|
||||
for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) {
|
||||
const example_s *ex = all_examples[ex_ix];
|
||||
printf("simple #%zu\n", ex_ix);
|
||||
|
||||
tvbuff_t *tvb = tvb_new_real_data(ex->enc, ex->enc_len, ex->enc_len);
|
||||
gint offset = 0;
|
||||
wscbor_skip_next_item(test_scope, tvb, &offset);
|
||||
g_assert_cmpint(offset, ==, ex->data_length);
|
||||
|
||||
tvb_free(tvb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wscbor_test_skip_next_item_multiple(void)
|
||||
{
|
||||
tvbuff_t *tvb = tvb_new_real_data((const guint8 *)"\x00\x01\x02\x03", 4, 4);
|
||||
gint offset = 3;
|
||||
gint offset = 2;
|
||||
|
||||
gboolean res = wscbor_skip_next_item(test_scope, tvb, &offset);
|
||||
g_assert(!res);
|
||||
g_assert_cmpint(offset, ==, 3);
|
||||
|
||||
res = wscbor_skip_next_item(test_scope, tvb, &offset);
|
||||
g_assert(!res);
|
||||
g_assert_cmpint(offset, ==, 4);
|
||||
|
||||
{ // Read past the end
|
||||
guint caught = 0;
|
||||
volatile gulong caught = 0;
|
||||
TRY {
|
||||
wscbor_skip_next_item(test_scope, tvb, &offset);
|
||||
g_assert(FALSE);
|
||||
}
|
||||
CATCH(ReportedBoundsError) {
|
||||
caught = ReportedBoundsError;
|
||||
CATCH_BOUNDS_ERRORS {
|
||||
caught = exc->except_id.except_code;
|
||||
}
|
||||
ENDTRY;
|
||||
g_assert_cmpuint(caught, ==, ReportedBoundsError);
|
||||
|
@ -258,14 +298,14 @@ wscbor_test_require_major_type(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
g_assert(wscbor_require_major_type(chunk, ex->type_major));
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
// any other type
|
||||
g_assert(!wscbor_require_major_type(chunk, ex->type_major + 1));
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
tvb_free(tvb);
|
||||
|
@ -273,7 +313,7 @@ wscbor_test_require_major_type(void)
|
|||
}
|
||||
|
||||
static void
|
||||
wscbor_test_require_boolean(void)
|
||||
wscbor_test_require_boolean_simple(void)
|
||||
{
|
||||
for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) {
|
||||
const example_s *ex = all_examples[ex_ix];
|
||||
|
@ -284,18 +324,18 @@ wscbor_test_require_boolean(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
const gboolean *val = wscbor_require_boolean(test_scope, chunk);
|
||||
if ((ex->type_major == CBOR_TYPE_FLOAT_CTRL)
|
||||
&& ((ex->head_value == CBOR_CTRL_FALSE) || (ex->head_value == CBOR_CTRL_TRUE))) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpint(*val, ==, ex->head_value == CBOR_CTRL_TRUE);
|
||||
}
|
||||
else {
|
||||
g_assert(!val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
}
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
|
@ -304,7 +344,7 @@ wscbor_test_require_boolean(void)
|
|||
}
|
||||
|
||||
static void
|
||||
wscbor_test_require_int64(void)
|
||||
wscbor_test_require_int64_simple(void)
|
||||
{
|
||||
for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) {
|
||||
const example_s *ex = all_examples[ex_ix];
|
||||
|
@ -315,22 +355,22 @@ wscbor_test_require_int64(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
const gint64 *val = wscbor_require_int64(test_scope, chunk);
|
||||
if (ex->type_major == CBOR_TYPE_UINT) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpint(*val, ==, ex->head_value);
|
||||
}
|
||||
else if (ex->type_major == CBOR_TYPE_NEGINT) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpint(*val, ==, -1 - ex->head_value);
|
||||
}
|
||||
else {
|
||||
g_assert(!val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
}
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
|
@ -353,24 +393,24 @@ wscbor_test_require_int64_overflow(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
|
||||
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
|
||||
|
||||
const gint64 *val = wscbor_require_int64(test_scope, chunk);
|
||||
if (ex->type_major == CBOR_TYPE_UINT) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
g_assert_cmpint(*val, ==, G_MAXINT64);
|
||||
}
|
||||
else if (ex->type_major == CBOR_TYPE_NEGINT) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
g_assert_cmpint(*val, ==, G_MININT64);
|
||||
}
|
||||
else {
|
||||
g_assert(!val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
}
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
|
@ -379,7 +419,7 @@ wscbor_test_require_int64_overflow(void)
|
|||
}
|
||||
|
||||
static void
|
||||
wscbor_test_require_tstr(void)
|
||||
wscbor_test_require_tstr_simple(void)
|
||||
{
|
||||
for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) {
|
||||
const example_s *ex = all_examples[ex_ix];
|
||||
|
@ -390,18 +430,20 @@ wscbor_test_require_tstr(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
const char *val = wscbor_require_tstr(test_scope, tvb, chunk);
|
||||
const char *val = wscbor_require_tstr(test_scope, chunk);
|
||||
if (ex->type_major == CBOR_TYPE_STRING) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
// only works because this is Latin-1 text
|
||||
g_assert_cmpint(strlen(val), ==, ex->head_value);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
if (ex->head_value > 0) {
|
||||
// only works because this is Latin-1 text
|
||||
g_assert_cmpmem(val, strlen(val), ex->enc + ex->head_length, ex->head_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
g_assert(!val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
}
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
|
@ -427,20 +469,20 @@ wscbor_test_require_tstr_short(void)
|
|||
|
||||
chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
|
||||
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
|
||||
|
||||
volatile guint caught = 0;
|
||||
volatile gulong caught = 0;
|
||||
TRY {
|
||||
wscbor_require_tstr(test_scope, tvb, chunk);
|
||||
wscbor_require_tstr(test_scope, chunk);
|
||||
g_assert(FALSE);
|
||||
}
|
||||
CATCH(ReportedBoundsError) {
|
||||
caught = ReportedBoundsError;
|
||||
CATCH_BOUNDS_ERRORS {
|
||||
caught = exc->except_id.except_code;
|
||||
}
|
||||
ENDTRY;
|
||||
g_assert_cmpuint(caught, ==, ReportedBoundsError);
|
||||
g_assert_cmpuint(caught, ==, ContainedBoundsError);
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
tvb_free(tvb);
|
||||
|
@ -448,7 +490,7 @@ wscbor_test_require_tstr_short(void)
|
|||
}
|
||||
|
||||
static void
|
||||
wscbor_test_require_bstr(void)
|
||||
wscbor_test_require_bstr_simple(void)
|
||||
{
|
||||
for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) {
|
||||
const example_s *ex = all_examples[ex_ix];
|
||||
|
@ -459,18 +501,25 @@ wscbor_test_require_bstr(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
|
||||
const tvbuff_t *val = wscbor_require_bstr(tvb, chunk);
|
||||
tvbuff_t *val = wscbor_require_bstr(test_scope, chunk);
|
||||
if (ex->type_major == CBOR_TYPE_BYTESTRING) {
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
|
||||
g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value);
|
||||
g_assert_cmpuint(tvb_captured_length(val), <=, ex->head_value);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
if (ex->head_value > 0) {
|
||||
g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value);
|
||||
g_assert_cmpuint(tvb_captured_length(val), ==, ex->head_value);
|
||||
|
||||
const gint buflen = tvb_reported_length(val);
|
||||
void *buf = tvb_memdup(test_scope, val, 0, buflen);
|
||||
g_assert(buf);
|
||||
g_assert_cmpmem(buf, buflen, ex->enc + ex->head_length, ex->head_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
g_assert(!val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
}
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
|
@ -478,6 +527,49 @@ wscbor_test_require_bstr(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wscbor_test_require_bstr_short(void)
|
||||
{
|
||||
const example_s * examples[] = {
|
||||
&ex_bstr_short,
|
||||
};
|
||||
for (size_t ex_ix = 0; ex_ix < (sizeof(examples) / sizeof(example_s*)); ++ex_ix) {
|
||||
const example_s *ex = examples[ex_ix];
|
||||
printf("simple #%zu\n", ex_ix);
|
||||
|
||||
tvbuff_t *tvb = tvb_new_real_data(ex->enc, ex->enc_len, ex->enc_len);
|
||||
gint offset = 0;
|
||||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
|
||||
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
|
||||
|
||||
// no exception, but truncated captured length
|
||||
tvbuff_t *val = wscbor_require_bstr(test_scope, chunk);
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 0);
|
||||
g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value);
|
||||
g_assert_cmpuint(tvb_captured_length(val), <, ex->head_value);
|
||||
|
||||
volatile gulong caught = 0;
|
||||
TRY {
|
||||
const gint buflen = tvb_reported_length(val);
|
||||
tvb_memdup(test_scope, val, 0, buflen);
|
||||
g_assert(FALSE);
|
||||
}
|
||||
CATCH_BOUNDS_ERRORS {
|
||||
caught = exc->except_id.except_code;
|
||||
}
|
||||
ENDTRY;
|
||||
g_assert_cmpuint(caught, ==, ContainedBoundsError);
|
||||
|
||||
wscbor_chunk_free(chunk);
|
||||
tvb_free(tvb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wscbor_test_require_bstr_overflow(void)
|
||||
{
|
||||
|
@ -493,13 +585,13 @@ wscbor_test_require_bstr_overflow(void)
|
|||
|
||||
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
|
||||
g_assert(chunk);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
|
||||
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
|
||||
|
||||
const tvbuff_t *val = wscbor_require_bstr(tvb, chunk);
|
||||
const tvbuff_t *val = wscbor_require_bstr(test_scope, chunk);
|
||||
g_assert(val);
|
||||
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 2);
|
||||
g_assert_cmpuint(has_real_errors(chunk), ==, 1);
|
||||
g_assert_cmpuint(tvb_reported_length(val), ==, G_MAXINT);
|
||||
g_assert_cmpuint(tvb_captured_length(val), ==, 2);
|
||||
|
||||
|
@ -515,22 +607,35 @@ main(int argc, char **argv)
|
|||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func("/wscbor/read/simple", wscbor_test_read_simple);
|
||||
g_test_add_func("/wscbor/read/simple_tags", wscbor_test_read_simple_tags);
|
||||
g_test_add_func("/wscbor/read/invalid", wscbor_test_read_invalid);
|
||||
g_test_add_func("/wscbor/chunk_read/simple", wscbor_test_chunk_read_simple);
|
||||
g_test_add_func("/wscbor/chunk_read/simple_tags", wscbor_test_chunk_read_simple_tags);
|
||||
g_test_add_func("/wscbor/chunk_read/invalid", wscbor_test_chunk_read_invalid);
|
||||
g_test_add_func("/wscbor/is_indefinite_break", wscbor_test_is_indefinite_break);
|
||||
g_test_add_func("/wscbor/skip_next_item", wscbor_test_skip_next_item);
|
||||
g_test_add_func("/wscbor/skip_next_item/simple", wscbor_test_skip_next_item_simple);
|
||||
g_test_add_func("/wscbor/skip_next_item/multiple", wscbor_test_skip_next_item_multiple);
|
||||
g_test_add_func("/wscbor/require_major_type", wscbor_test_require_major_type);
|
||||
g_test_add_func("/wscbor/require_boolean", wscbor_test_require_boolean);
|
||||
g_test_add_func("/wscbor/require_int64", wscbor_test_require_int64);
|
||||
g_test_add_func("/wscbor/require_int64_overflow", wscbor_test_require_int64_overflow);
|
||||
g_test_add_func("/wscbor/require_tstr", wscbor_test_require_tstr);
|
||||
g_test_add_func("/wscbor/require_tstr_short", wscbor_test_require_tstr_short);
|
||||
g_test_add_func("/wscbor/require_bstr", wscbor_test_require_bstr);
|
||||
g_test_add_func("/wscbor/require_bstr_overflow", wscbor_test_require_bstr_overflow);
|
||||
g_test_add_func("/wscbor/require_boolean/simple", wscbor_test_require_boolean_simple);
|
||||
g_test_add_func("/wscbor/require_int64/simple", wscbor_test_require_int64_simple);
|
||||
g_test_add_func("/wscbor/require_int64/overflow", wscbor_test_require_int64_overflow);
|
||||
g_test_add_func("/wscbor/require_tstr/simple", wscbor_test_require_tstr_simple);
|
||||
g_test_add_func("/wscbor/require_tstr/short", wscbor_test_require_tstr_short);
|
||||
g_test_add_func("/wscbor/require_bstr/simple", wscbor_test_require_bstr_simple);
|
||||
g_test_add_func("/wscbor/require_bstr/short", wscbor_test_require_bstr_short);
|
||||
g_test_add_func("/wscbor/require_bstr/overflow", wscbor_test_require_bstr_overflow);
|
||||
wmem_init_scopes();
|
||||
|
||||
test_scope = wmem_allocator_new(WMEM_ALLOCATOR_STRICT);
|
||||
{
|
||||
// Extract high-severity errors
|
||||
int ex_size = 0;
|
||||
const ei_register_info *ex_items = wscbor_expert_items(&ex_size);
|
||||
real_errors = wmem_map_new(test_scope, g_direct_hash, g_direct_equal);
|
||||
for (int ix = 0; ix < ex_size; ++ix) {
|
||||
if (ex_items[ix].eiinfo.severity & (PI_NOTE|PI_WARN|PI_ERROR)) {
|
||||
wmem_map_insert(real_errors, ex_items[ix].ids, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
//cannot use: wscbor_init();
|
||||
result = g_test_run();
|
||||
//none needed: wscbor_cleanup();
|
||||
|
|
Loading…
Reference in New Issue