Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-bpsec-cose.c
Line
Count
Source
1
/* packet-bpsec-cose.c
2
 * BPSec COSE Context
3
 * References:
4
 *     https://datatracker.ietf.org/doc/draft-ietf-dtn-bpsec-cose/
5
 *
6
 * Copyright 2019-2024, Brian Sipos <brian.sipos@gmail.com>
7
 *
8
 * Wireshark - Network traffic analyzer
9
 * By Gerald Combs <gerald@wireshark.org>
10
 * Copyright 1998 Gerald Combs
11
 *
12
 * SPDX-License-Identifier: LGPL-2.1-or-later
13
 */
14
#include "config.h"
15
#include <stdint.h>
16
17
#include "packet-bpsec.h"
18
#include <epan/packet.h>
19
#include <epan/prefs.h>
20
#include <epan/proto.h>
21
#include <epan/tfs.h>
22
#include <epan/wscbor.h>
23
#include <epan/expert.h>
24
#include <epan/to_str.h>
25
#include <inttypes.h>
26
27
void proto_register_bpsec_cose(void);
28
void proto_reg_handoff_bpsec_cose(void);
29
30
/** AAD Scope parameter.
31
 * Section 3.2.2.
32
 */
33
typedef enum {
34
    AAD_METADATA = 0x01,
35
    AAD_BTSD = 0x02,
36
} AadScopeFlag;
37
38
/// IANA registered security context ID
39
static const int64_t bpsec_cose_ctxid = 3;
40
41
/// Protocol handles
42
static int proto_bpsec_cose;
43
44
/// Dissect opaque CBOR parameters/results
45
static dissector_table_t table_cose_msg;
46
/// Handle for COSE header maps
47
static dissector_handle_t handle_cose_msg_hdr;
48
49
// Field definitions
50
static int hf_aad_scope;
51
static int hf_aad_blknum;
52
static int hf_aad_flags;
53
static int hf_aad_flags_metadata;
54
static int hf_aad_flags_btsd;
55
static int hf_addl_prot_bstr;
56
static int hf_addl_unprot_bstr;
57
static int hf_cose_msg;
58
59
static int *const aad_flags[] = {
60
    &hf_aad_flags_metadata,
61
    &hf_aad_flags_btsd,
62
    NULL
63
};
64
65
// Tree structures
66
static int ett_aad_scope;
67
static int ett_aad_blknum;
68
static int ett_aad_flags;
69
static int ett_addl_hdr_bstr;
70
static int ett_addl_hdr;
71
static int ett_cose_msg;
72
73
/** Dissector for AAD Scope parameter.
74
 */
75
0
static int dissect_param_scope(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
76
0
    int offset = 0;
77
78
0
    wscbor_chunk_t *chunk_aad_map = wscbor_chunk_read(pinfo->pool, tvb, &offset);
79
0
    wscbor_require_map(chunk_aad_map);
80
0
    proto_item *item_aad_map = proto_tree_add_cbor_container(tree, hf_aad_scope, pinfo, tvb, chunk_aad_map);
81
0
    wscbor_chunk_mark_errors(pinfo, item_aad_map, chunk_aad_map);
82
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_aad_map)) {
83
0
        proto_tree *tree_aad_map = proto_item_add_subtree(item_aad_map, ett_aad_scope);
84
85
0
        for (uint64_t ix = 0; ix < chunk_aad_map->head_value; ++ix) {
86
0
            wscbor_chunk_t *chunk_blknum = wscbor_chunk_read(pinfo->pool, tvb, &offset);
87
0
            int64_t *blknum = wscbor_require_int64(pinfo->pool, chunk_blknum);
88
0
            proto_item *item_blknum = proto_tree_add_cbor_int64(tree_aad_map, hf_aad_blknum, pinfo, tvb, chunk_blknum, blknum);
89
0
            proto_tree *tree_blknum = proto_item_add_subtree(item_blknum, ett_aad_blknum);
90
91
0
            wscbor_chunk_t *chunk_flags = wscbor_chunk_read(pinfo->pool, tvb, &offset);
92
0
            uint64_t *flags = wscbor_require_uint64(pinfo->pool, chunk_flags);
93
0
            proto_tree_add_cbor_bitmask(tree_blknum, hf_aad_flags, ett_aad_flags, aad_flags, pinfo, tvb, chunk_flags, flags);
94
0
        }
95
0
    }
96
0
    proto_item_set_len(item_aad_map, offset);
97
98
0
    return offset;
99
0
}
100
101
/** Dissector for COSE protected header.
102
 */
103
0
static int dissect_addl_protected(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
104
0
    int offset = 0;
105
106
0
    wscbor_chunk_t *chunk_hdr_bstr = wscbor_chunk_read(pinfo->pool, tvb, &offset);
107
0
    tvbuff_t *hdr_bstr = wscbor_require_bstr(pinfo->pool, chunk_hdr_bstr);
108
0
    proto_item *item_hdr_bstr = proto_tree_add_cbor_bstr(tree, hf_addl_prot_bstr, pinfo, tvb, chunk_hdr_bstr);
109
0
    if (hdr_bstr) {
110
0
        proto_tree *tree_hdr_bstr = proto_item_add_subtree(item_hdr_bstr, ett_addl_hdr_bstr);
111
112
0
        int sublen = call_dissector(handle_cose_msg_hdr, hdr_bstr, pinfo, tree_hdr_bstr);
113
0
        if (sublen < 0) {
114
0
            return sublen;
115
0
        }
116
0
        offset += sublen;
117
0
    }
118
119
0
    return offset;
120
0
}
121
122
/** Dissector for COSE unprotected header.
123
 */
124
0
static int dissect_addl_unprotected(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
125
0
    int offset = 0;
126
127
0
    wscbor_chunk_t *chunk_hdr_bstr = wscbor_chunk_read(pinfo->pool, tvb, &offset);
128
0
    tvbuff_t *hdr_bstr = wscbor_require_bstr(pinfo->pool, chunk_hdr_bstr);
129
0
    proto_item *item_hdr_bstr = proto_tree_add_cbor_bstr(tree, hf_addl_unprot_bstr, pinfo, tvb, chunk_hdr_bstr);
130
0
    if (hdr_bstr) {
131
0
        proto_tree *tree_hdr_bstr = proto_item_add_subtree(item_hdr_bstr, ett_addl_hdr_bstr);
132
133
0
        int sublen = call_dissector(handle_cose_msg_hdr, hdr_bstr, pinfo, tree_hdr_bstr);
134
0
        if (sublen < 0) {
135
0
            return sublen;
136
0
        }
137
0
        offset += sublen;
138
0
    }
139
140
0
    return offset;
141
0
}
142
143
/** Dissector for bstr-wrapped CBOR.
144
 */
145
0
static int dissect_cose_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
146
0
    bpsec_id_t *secid = data;
147
0
    DISSECTOR_ASSERT(secid != NULL);
148
0
    int offset = 0;
149
150
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
151
0
    tvbuff_t *tvb_data = wscbor_require_bstr(pinfo->pool, chunk);
152
153
0
    proto_item *item_msg = proto_tree_add_cbor_bstr(tree, hf_cose_msg, pinfo, tvb, chunk);
154
0
    proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_cose_msg);
155
156
0
    if (tvb_data) {
157
0
        dissector_handle_t dissector = dissector_get_custom_table_handle(table_cose_msg, &(secid->type_id));
158
0
        int sublen = call_dissector(dissector, tvb_data, pinfo, tree_msg);
159
0
        if (sublen < 0) {
160
0
            return sublen;
161
0
        }
162
0
    }
163
164
0
    return offset;
165
0
}
166
167
/// Re-initialize after a configuration change
168
16
static void reinit_bpsec_cose(void) {
169
16
}
170
171
/// Overall registration of the protocol
172
16
void proto_register_bpsec_cose(void) {
173
16
    static hf_register_info fields[] = {
174
16
        {&hf_aad_scope, {"AAD Scope, Block count", "bpsec-cose.aad_scope", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
175
16
        {&hf_aad_blknum, {"Block Number", "bpsec-cose.aad_scope.blknum", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
176
16
        {&hf_aad_flags, {"Flags", "bpsec-cose.aad_scope.flags", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}},
177
16
        {&hf_aad_flags_metadata, {"Metadata", "bpsec-cose.aad_scope.flags.metadata", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AAD_METADATA, NULL, HFILL}},
178
16
        {&hf_aad_flags_btsd, {"BTSD", "bpsec-cose.aad_scope.flags.btsd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AAD_BTSD, NULL, HFILL}},
179
16
        {&hf_addl_prot_bstr, {"Additional Protected Headers (bstr)", "bpsec-cose.addl_protected_bstr", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
180
16
        {&hf_addl_unprot_bstr, {"Additional Unprotected Headers (bstr)", "bpsec-cose.addl_unprotected", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
181
16
        {&hf_cose_msg, {"COSE Message (bstr)", "bpsec-cose.msg", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
182
16
    };
183
16
    static int *ett[] = {
184
16
        &ett_aad_scope,
185
16
        &ett_aad_blknum,
186
16
        &ett_aad_flags,
187
16
        &ett_addl_hdr_bstr,
188
16
        &ett_addl_hdr,
189
16
        &ett_cose_msg,
190
16
    };
191
192
16
    proto_bpsec_cose = proto_register_protocol("BPSec COSE Context", "BPSec COSE", "bpsec-cose");
193
194
16
    proto_register_field_array(proto_bpsec_cose, fields, array_length(fields));
195
16
    proto_register_subtree_array(ett, array_length(ett));
196
197
16
    prefs_register_protocol(proto_bpsec_cose, reinit_bpsec_cose);
198
16
}
199
200
96
static void bpsec_cose_result_register(int64_t result_id, const char *dis_name) {
201
96
    bpsec_id_t *rkey = bpsec_id_new(NULL, bpsec_cose_ctxid, result_id);
202
96
    const char *description = dissector_handle_get_description(find_dissector_add_dependency(dis_name, proto_bpsec_cose));
203
96
    dissector_handle_t hdl = create_dissector_handle_with_name_and_description(dissect_cose_msg, proto_bpsec_cose, NULL, description);
204
96
    dissector_add_custom_table_handle("bpsec.result", rkey, hdl);
205
206
96
}
207
208
16
void proto_reg_handoff_bpsec_cose(void) {
209
16
    table_cose_msg = find_dissector_table("cose.msgtag");
210
16
    handle_cose_msg_hdr = find_dissector_add_dependency("cose.msg.headers", proto_bpsec_cose);
211
212
    /* Packaged extensions */
213
16
    {
214
16
        int64_t *key = g_new0(int64_t, 1);
215
16
        *key = 3;
216
16
        dissector_handle_t hdl = create_dissector_handle_with_name_and_description(NULL, proto_bpsec_cose, NULL, "COSE");
217
16
        dissector_add_custom_table_handle("bpsec.ctx", key, hdl);
218
16
    }
219
16
    {
220
16
        bpsec_id_t *key = bpsec_id_new(NULL, bpsec_cose_ctxid, 3);
221
16
        dissector_handle_t hdl = create_dissector_handle_with_name_and_description(dissect_addl_protected, proto_bpsec_cose, NULL, "Additional Protected Headers");
222
16
        dissector_add_custom_table_handle("bpsec.param", key, hdl);
223
16
    }
224
16
    {
225
16
        bpsec_id_t *key = bpsec_id_new(NULL, bpsec_cose_ctxid, 4);
226
16
        dissector_handle_t hdl = create_dissector_handle_with_name_and_description(dissect_addl_unprotected, proto_bpsec_cose, NULL, "Additional Unprotected Headers");
227
16
        dissector_add_custom_table_handle("bpsec.param", key, hdl);
228
16
    }
229
16
    {
230
16
        bpsec_id_t *key = bpsec_id_new(NULL, bpsec_cose_ctxid, 5);
231
16
        dissector_handle_t hdl = create_dissector_handle_with_name_and_description(dissect_param_scope, proto_bpsec_cose, NULL, "AAD Scope");
232
16
        dissector_add_custom_table_handle("bpsec.param", key, hdl);
233
16
    }
234
235
    // Propagate COSE tags as result IDs
236
16
    bpsec_cose_result_register(98, "cose_sign");
237
16
    bpsec_cose_result_register(18, "cose_sign1");
238
16
    bpsec_cose_result_register(96, "cose_encrypt");
239
16
    bpsec_cose_result_register(16, "cose_encrypt0");
240
16
    bpsec_cose_result_register(97, "cose_mac");
241
16
    bpsec_cose_result_register(17, "cose_mac0");
242
243
16
    reinit_bpsec_cose();
244
16
}