aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorBrian Sipos <brian.sipos@gmail.com>2024-02-17 13:22:31 -0500
committerJohn Thacker <johnthacker@gmail.com>2024-02-23 00:12:00 +0000
commit40b210e1d62103bc7df56557300ec273f085f140 (patch)
treeb1cd5b634744a6db7a6a0b67fd319be5ed43d382 /epan
parent8f49a831cf7fe6b57a93f080f3cc6af89bd4a6e7 (diff)
cose: Peek ahead for map principal value before dissecting map items
This change updates references to obsoleted RFCs and I-Ds, provides human-readable interpretation of kid values, and fixes the text encoding type in proto_tree_add_cbor_tstr(). Fixes #19659
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/packet-cose.c140
-rw-r--r--epan/dissectors/packet-cose.h2
-rw-r--r--epan/wscbor.c2
3 files changed, 96 insertions, 48 deletions
diff --git a/epan/dissectors/packet-cose.c b/epan/dissectors/packet-cose.c
index ef62ea928e..884a28a546 100644
--- a/epan/dissectors/packet-cose.c
+++ b/epan/dissectors/packet-cose.c
@@ -1,8 +1,10 @@
/* packet-cose.c
* Routines for CBOR Object Signing and Encryption (COSE) dissection
* References:
- * RFC 8152: https://tools.ietf.org/html/rfc8152
* RFC 8949: https://tools.ietf.org/html/rfc8949
+ * RFC 9052: https://tools.ietf.org/html/rfc9052
+ * RFC 9053: https://tools.ietf.org/html/rfc9053
+ * RFC 9360: https://tools.ietf.org/html/rfc9360
*
* Copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
*
@@ -190,6 +192,7 @@ static int hf_hdr_crit_list;
static int hf_hdr_ctype_uint;
static int hf_hdr_ctype_tstr;
static int hf_hdr_kid;
+static int hf_hdr_kid_text;
static int hf_hdr_iv;
static int hf_hdr_piv;
static int hf_hdr_x5bag;
@@ -242,6 +245,7 @@ static hf_register_info fields[] = {
{&hf_hdr_ctype_uint, {"Content-Format", "cose.content-type.uint", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{&hf_hdr_ctype_tstr, {"Content-Type", "cose.content-type.tstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_hdr_kid, {"Key identifier", "cose.kid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
+ {&hf_hdr_kid_text, {"As Text", "cose.kid.as_text", FT_STRING, BASE_NONE, NULL, 0x0, "The kid byte string interpreted as UTF-8 text", HFILL}},
{&hf_hdr_iv, {"IV", "cose.iv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_hdr_piv, {"Partial IV", "cose.piv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
@@ -276,6 +280,7 @@ static int ett_prot_bstr;
static int ett_unprot;
static int ett_hdr_map;
static int ett_hdr_label;
+static int ett_hdr_kid;
static int ett_hdr_static_key;
static int ett_hdr_ephem_key;
static int ett_hdr_crit_list;
@@ -295,6 +300,7 @@ static int *ett[] = {
&ett_unprot,
&ett_hdr_map,
&ett_hdr_label,
+ &ett_hdr_kid,
&ett_hdr_static_key,
&ett_hdr_ephem_key,
&ett_hdr_crit_list,
@@ -359,6 +365,39 @@ void cose_param_key_free(gpointer ptr) {
g_free(obj);
}
+/** Get a specific item value (map key or value) from a header map.
+ * @param alloc The allocator for temporary data.
+ * @param tvb The buffer to read from.
+ * @param[in,out] offset The starting offset to read and advance.
+ * @return A pointer to the simple value or NULL.
+ */
+static GVariant * get_header_value(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset) {
+ GVariant *result = NULL;
+
+ wscbor_chunk_t *chunk = wscbor_chunk_read(alloc, tvb, offset);
+ switch (chunk->type_major) {
+ case CBOR_TYPE_UINT:
+ case CBOR_TYPE_NEGINT: {
+ gint64 *label = wscbor_require_int64(alloc, chunk);
+ if (label) {
+ result = g_variant_new_int64(*label);
+ }
+ break;
+ }
+ case CBOR_TYPE_STRING: {
+ const char *label = wscbor_require_tstr(alloc, chunk);
+ if (label) {
+ result = g_variant_new_string(label);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ wscbor_chunk_free(chunk);
+ return result;
+}
+
/** Dissect an ID-value pair within a context.
*
* @param dis_table The cose_param_key_t dissector table.
@@ -447,8 +486,7 @@ static gboolean dissect_header_pair(dissector_table_t dis_table, cose_header_con
static void
cose_header_context_cleanup(void *user_data) {
-
- cose_header_context_t *ctx = (cose_header_context_t*)user_data;
+ cose_header_context_t *ctx = (cose_header_context_t *)user_data;
if (ctx->principal) {
g_variant_unref(ctx->principal);
@@ -459,14 +497,21 @@ cose_header_context_cleanup(void *user_data) {
}
}
+static void
+g_variant_cleanup(void *user_data) {
+ GVariant *var = (GVariant *)user_data;
+ g_variant_unref(var);
+}
+
/** Dissect an entire header map, either for messages, recipients, or keys.
*
* @param dis_table The cose_param_key_t dissector table.
* @param tvb The source data.
* @param tree The parent of the header map.
* @param[in,out] offset The data offset.
+ * @param principal_key The map key associated with a principal value to read first.
*/
-static void dissect_header_map(dissector_table_t dis_table, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
+static void dissect_header_map(dissector_table_t dis_table, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset, GVariant *principal_key) {
wscbor_chunk_t *chunk_hdr_map = wscbor_chunk_read(pinfo->pool, tvb, offset);
wscbor_require_map(chunk_hdr_map);
proto_item *item_hdr_map = proto_tree_get_parent(tree);
@@ -475,9 +520,27 @@ static void dissect_header_map(dissector_table_t dis_table, tvbuff_t *tvb, packe
proto_tree *tree_hdr_map = proto_item_add_subtree(item_hdr_map, ett_hdr_map);
cose_header_context_t *ctx = wmem_new0(pinfo->pool, cose_header_context_t);
-
CLEANUP_PUSH(cose_header_context_cleanup, ctx);
+ // Peek ahead to principal key (and value) first
+ if (principal_key) {
+ gint peek_offset = *offset;
+ for (guint64 ix = 0; ix < chunk_hdr_map->head_value; ++ix) {
+ GVariant *key = get_header_value(pinfo->pool, tvb, &peek_offset);
+ if (key) {
+ if (g_variant_equal(key, principal_key)) {
+ ctx->principal = get_header_value(pinfo->pool, tvb, &peek_offset);
+ }
+ g_variant_unref(key);
+ if (ctx->principal) {
+ break;
+ }
+ }
+ // ignore non-principal value entirely
+ wscbor_skip_next_item(pinfo->pool, tvb, &peek_offset);
+ }
+ }
+
for (guint64 ix = 0; ix < chunk_hdr_map->head_value; ++ix) {
if (!dissect_header_pair(dis_table, ctx, tvb, pinfo, tree_hdr_map, offset)) {
break;
@@ -485,7 +548,6 @@ static void dissect_header_map(dissector_table_t dis_table, tvbuff_t *tvb, packe
}
CLEANUP_CALL_AND_POP;
-
wmem_free(pinfo->pool, ctx);
}
@@ -494,7 +556,12 @@ static void dissect_header_map(dissector_table_t dis_table, tvbuff_t *tvb, packe
static int dissect_cose_msg_header_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
gint offset = 0;
- dissect_header_map(table_header, tvb, pinfo, tree, &offset);
+ GVariant *alg_key = g_variant_new_int64(1);
+ CLEANUP_PUSH(g_variant_cleanup, alg_key);
+
+ dissect_header_map(table_header, tvb, pinfo, tree, &offset, alg_key);
+
+ CLEANUP_CALL_AND_POP;
return offset;
}
@@ -781,30 +848,17 @@ static int dissect_cose_msg_tagged(tvbuff_t *tvb, packet_info *pinfo, proto_tree
return -1;
}
-static void dissect_value_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset, GVariant **value) {
+static void dissect_value_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, offset);
switch (chunk->type_major) {
case CBOR_TYPE_UINT:
case CBOR_TYPE_NEGINT: {
gint64 *val = wscbor_require_int64(pinfo->pool, chunk);
proto_tree_add_cbor_int64(tree, hf_hdr_alg_int, pinfo, tvb, chunk, val);
- if (value && val) {
- if (*value) {
- g_variant_unref(*value);
- }
- *value = g_variant_new_int64(*val);
- }
break;
}
case CBOR_TYPE_STRING: {
- const char *val = wscbor_require_tstr(pinfo->pool, chunk);
proto_tree_add_cbor_tstr(tree, hf_hdr_alg_tstr, pinfo, tvb, chunk);
- if (value && val) {
- if (*value) {
- g_variant_unref(*value);
- }
- *value = g_variant_new_string(val);
- }
break;
}
default:
@@ -823,7 +877,12 @@ static int dissect_header_salt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
}
static void dissect_value_cose_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
- dissect_header_map(table_keyparam, tvb, pinfo, tree, offset);
+ GVariant *kty_key = g_variant_new_int64(1);
+ CLEANUP_PUSH(g_variant_cleanup, kty_key);
+
+ dissect_header_map(table_keyparam, tvb, pinfo, tree, offset, kty_key);
+
+ CLEANUP_CALL_AND_POP;
}
static int dissect_header_static_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
@@ -842,12 +901,9 @@ static int dissect_header_ephem_key(tvbuff_t *tvb, packet_info *pinfo, proto_tre
return offset;
}
-static int dissect_header_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
- cose_header_context_t *ctx = (cose_header_context_t *)data;
+static int dissect_header_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
gint offset = 0;
-
- dissect_value_alg(tvb, pinfo, tree, &offset, &(ctx->principal));
-
+ dissect_value_alg(tvb, pinfo, tree, &offset);
return offset;
}
@@ -908,8 +964,14 @@ static int dissect_header_kid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
- wscbor_require_bstr(pinfo->pool, chunk);
- proto_tree_add_cbor_bstr(tree, hf_hdr_kid, pinfo, tvb, chunk);
+ tvbuff_t *val = wscbor_require_bstr(pinfo->pool, chunk);
+ proto_item *item_kid = proto_tree_add_cbor_bstr(tree, hf_hdr_kid, pinfo, tvb, chunk);
+
+ if (val && tvb_utf_8_isprint(val, 0, -1)) {
+ proto_tree *tree_kid = proto_item_add_subtree(item_kid, ett_hdr_kid);
+ proto_item *kid_text = proto_tree_add_item(tree_kid, hf_hdr_kid_text, val, 0, tvb_reported_length(val), ENC_UTF_8);
+ proto_item_set_generated(kid_text);
+ }
return offset;
}
@@ -1005,7 +1067,7 @@ static int dissect_header_x5t(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_list)) {
proto_tree *tree_list = proto_item_add_subtree(item_list, ett_hdr_x5t_list);
- dissect_value_alg(tvb, pinfo, tree_list, &offset, NULL);
+ dissect_value_alg(tvb, pinfo, tree_list, &offset);
wscbor_chunk_t *chunk_hash = wscbor_chunk_read(pinfo->pool, tvb, &offset);
wscbor_require_bstr(pinfo->pool, chunk_hash);
@@ -1061,8 +1123,7 @@ static int dissect_cose_key_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
return offset;
}
-static int dissect_keyparam_kty(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
- cose_header_context_t *ctx = (cose_header_context_t *)data;
+static int dissect_keyparam_kty(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
@@ -1071,23 +1132,10 @@ static int dissect_keyparam_kty(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
case CBOR_TYPE_NEGINT: {
gint64 *val = wscbor_require_int64(pinfo->pool, chunk);
proto_tree_add_cbor_int64(tree, hf_keyparam_kty_int, pinfo, tvb, chunk, val);
- if (val) {
- if (ctx->principal) {
- g_variant_unref(ctx->principal);
- }
- ctx->principal = g_variant_new_int64(*val);
- }
break;
}
case CBOR_TYPE_STRING: {
- const char *val = wscbor_require_tstr(pinfo->pool, chunk);
proto_tree_add_cbor_tstr(tree, hf_keyparam_kty_tstr, pinfo, tvb, chunk);
- if (val) {
- if (ctx->principal) {
- g_variant_unref(ctx->principal);
- }
- ctx->principal = g_variant_new_string(val);
- }
break;
}
default:
@@ -1341,7 +1389,7 @@ void proto_reg_handoff_cose(void) {
register_header_dissector(dissect_header_kid, g_variant_new_int64(4), "kid");
register_header_dissector(dissect_header_iv, g_variant_new_int64(5), "IV");
register_header_dissector(dissect_header_piv, g_variant_new_int64(6), "Partial IV");
- // draft-ietf-cose-x509 header labels
+ // RFC 9360 header labels
register_header_dissector(dissect_header_x5bag, g_variant_new_int64(32), "x5bag");
register_header_dissector(dissect_header_x5chain, g_variant_new_int64(33), "x5chain");
register_header_dissector(dissect_header_x5t, g_variant_new_int64(34), "x5t");
diff --git a/epan/dissectors/packet-cose.h b/epan/dissectors/packet-cose.h
index b04e48e23d..8a844aaa63 100644
--- a/epan/dissectors/packet-cose.h
+++ b/epan/dissectors/packet-cose.h
@@ -1,7 +1,7 @@
/* packet-cose.h
* Definitions for CBOR Object Signing and Encryption (COSE) dissection
* References:
- * RFC 8152: https://tools.ietf.org/html/rfc8152
+ * RFC 9052: https://tools.ietf.org/html/rfc9052
*
* Copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
*
diff --git a/epan/wscbor.c b/epan/wscbor.c
index 424dfb80bc..66ef1bd9eb 100644
--- a/epan/wscbor.c
+++ b/epan/wscbor.c
@@ -675,7 +675,7 @@ proto_item * proto_tree_add_cbor_bitmask(proto_tree *tree, int hfindex, const gi
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;
if (chunk->_priv->str_value) {
- item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
+ item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), ENC_UTF_8);
}
else {
// still show an empty item with errors