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-cose.c
Line
Count
Source
1
/* packet-cose.c
2
 * Routines for CBOR Object Signing and Encryption (COSE) dissection
3
 * References:
4
 *     RFC 8949: https://tools.ietf.org/html/rfc8949
5
 *     RFC 9052: https://tools.ietf.org/html/rfc9052
6
 *     RFC 9053: https://tools.ietf.org/html/rfc9053
7
 *     RFC 9360: https://tools.ietf.org/html/rfc9360
8
 *     RFC 9459: https://tools.ietf.org/html/rfc9459
9
 *     RFC 9861: https://tools.ietf.org/html/rfc9861
10
 *
11
 * Copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
12
 *
13
 * Wireshark - Network traffic analyzer
14
 * By Gerald Combs <gerald@wireshark.org>
15
 * Copyright 1998 Gerald Combs
16
 *
17
 * SPDX-License-Identifier: LGPL-2.1-or-later
18
 */
19
20
#include "config.h"
21
#define WS_LOG_DOMAIN "packet-cose"
22
23
#include "packet-cose.h"
24
#include "packet-media-type.h"
25
#include <epan/wscbor.h>
26
#include <epan/packet.h>
27
#include <epan/prefs.h>
28
#include <epan/proto.h>
29
#include <epan/media_params.h>
30
#include <epan/expert.h>
31
#include <epan/exceptions.h>
32
#include <wsutil/array.h>
33
#include <gcrypt.h>
34
#include <inttypes.h>
35
36
void proto_register_cose(void);
37
void proto_reg_handoff_cose(void);
38
39
/// Protocol column name
40
static const char *const proto_name_cose = "COSE";
41
42
/// Protocol preferences and defaults
43
44
/// Protocol handles
45
static int proto_cose;
46
static int proto_cose_params;
47
48
/// Dissect opaque CBOR data
49
static dissector_handle_t handle_cbor;
50
/// Dissector handles
51
static dissector_handle_t handle_cose_msg_hdr;
52
static dissector_handle_t handle_cose_msg_tagged;
53
static dissector_handle_t handle_cose_media_type;
54
static dissector_handle_t handle_cose_sign;
55
static dissector_handle_t handle_cose_sign1;
56
static dissector_handle_t handle_cose_encrypt;
57
static dissector_handle_t handle_cose_encrypt0;
58
static dissector_handle_t handle_cose_mac;
59
static dissector_handle_t handle_cose_mac0;
60
static dissector_handle_t handle_cose_key;
61
static dissector_handle_t handle_cose_key_set;
62
63
/// Dissect opaque data
64
static dissector_table_t table_media;
65
/// Dissect extension items
66
static dissector_table_t table_cose_msg_tag;
67
static dissector_table_t table_cose_media_subtype;
68
static dissector_table_t table_header;
69
static dissector_table_t table_keyparam;
70
71
static const val64_string alg_vals[] = {
72
    {-65535, "RS1"},
73
    {-65534, "A128CTR"},
74
    {-65533, "A192CTR"},
75
    {-65532, "A256CTR"},
76
    {-65531, "A128CBC"},
77
    {-65530, "A192CBC"},
78
    {-65529, "A256CBC"},
79
    {-268, "ESB512"},
80
    {-267, "ESB384"},
81
    {-266, "ESB320"},
82
    {-265, "ESB256"},
83
    {-264, "KT256"},
84
    {-263, "KT128"},
85
    {-260, "WalnutDSA"},
86
    {-259, "RS512"},
87
    {-258, "RS384"},
88
    {-257, "RS256"},
89
    {-53, "Ed448"},
90
    {-52, "ESP512"},
91
    {-51, "ESP384"},
92
    {-50, "ML-DSA-87"},
93
    {-49, "ML-DSA-65"},
94
    {-48, "ML-DSA-44"},
95
    {-47, "ES256K"},
96
    {-46, "HSS-LMS"},
97
    {-45, "SHAKE256"},
98
    {-44, "SHA-512"},
99
    {-43, "SHA-384"},
100
    {-42, "RSAES-OAEP w/ SHA-512"},
101
    {-41, "RSAES-OAEP w/ SHA-256"},
102
    {-40, "RSAES-OAEP w/ SHA-1"},
103
    {-39, "PS512"},
104
    {-38, "PS384"},
105
    {-37, "PS256"},
106
    {-36, "ES512"},
107
    {-35, "ES384"},
108
    {-34, "ECDH-SS + A256KW"},
109
    {-33, "ECDH-SS + A192KW"},
110
    {-32, "ECDH-SS + A128KW"},
111
    {-31, "ECDH-ES + A256KW"},
112
    {-30, "ECDH-ES + A192KW"},
113
    {-29, "ECDH-ES + A128KW"},
114
    {-28, "ECDH-SS + HKDF-512"},
115
    {-27, "ECDH-SS + HKDF-256"},
116
    {-26, "ECDH-ES + HKDF-512"},
117
    {-25, "ECDH-ES + HKDF-256"},
118
    {-19, "Ed25519"},
119
    {-18, "SHAKE128"},
120
    {-17, "SHA-512/256"},
121
    {-16, "SHA-256"},
122
    {-15, "SHA-256/64"},
123
    {-14, "SHA-1"},
124
    {-13, "direct+HKDF-AES-256"},
125
    {-12, "direct+HKDF-AES-128"},
126
    {-11, "direct+HKDF-SHA-512"},
127
    {-10, "direct+HKDF-SHA-256"},
128
    {-9, "ESP256"},
129
    {-8, "EdDSA"},
130
    {-7, "ES256"},
131
    {-6, "direct"},
132
    {-5, "A256KW"},
133
    {-4, "A192KW"},
134
    {-3, "A128KW"},
135
    {0, "Reserved"},
136
    {1, "A128GCM"},
137
    {2, "A192GCM"},
138
    {3, "A256GCM"},
139
    {4, "HMAC 256/64"},
140
    {5, "HMAC 256/256"},
141
    {6, "HMAC 384/384"},
142
    {7, "HMAC 512/512"},
143
    {10, "AES-CCM-16-64-128"},
144
    {11, "AES-CCM-16-64-256"},
145
    {12, "AES-CCM-64-64-128"},
146
    {13, "AES-CCM-64-64-256"},
147
    {14, "AES-MAC 128/64"},
148
    {15, "AES-MAC 256/64"},
149
    {24, "ChaCha20/Poly1305"},
150
    {25, "AES-MAC 128/128"},
151
    {26, "AES-MAC 256/128"},
152
    {30, "AES-CCM-16-128-128"},
153
    {31, "AES-CCM-16-128-256"},
154
    {32, "AES-CCM-64-128-128"},
155
    {33, "AES-CCM-64-128-256"},
156
    {34, "IV-GENERATION"},
157
    {0, NULL},
158
};
159
160
static const val64_string kty_vals[] = {
161
    {0, "Reserved"},
162
    {1, "OKP"},
163
    {2, "EC2"},
164
    {3, "RSA"},
165
    {4, "Symmetric"},
166
    {5, "HSS-LMS"},
167
    {6, "WalnutDSA"},
168
    {7, "AKP"},
169
    {0, NULL},
170
};
171
172
static const val64_string keyops_vals[] = {
173
    {1, "sign"},
174
    {2, "verify"},
175
    {3, "encrypt"},
176
    {4, "decrypt"},
177
    {5, "key wrap"},
178
    {6, "key unwrap"},
179
    {7, "derive key"},
180
    {8, "derive bits"},
181
    {9, "MAC create"},
182
    {10, "MAC verify"},
183
    {0, NULL},
184
};
185
186
static const val64_string crv_vals[] = {
187
    {0, "Reserved"},
188
    {1, "P-256"},
189
    {2, "P-384"},
190
    {3, "P-521"},
191
    {4, "X25519"},
192
    {5, "X448"},
193
    {6, "Ed25519"},
194
    {7, "Ed448"},
195
    {0, NULL},
196
};
197
198
static int hf_msg_tag;
199
static int hf_hdr_prot_bstr;
200
static int hf_hdr_unprot;
201
static int hf_payload_null;
202
static int hf_payload_bstr;
203
static int hf_cose_signature_list;
204
static int hf_cose_signature;
205
static int hf_signature;
206
static int hf_ciphertext_null;
207
static int hf_ciphertext_bstr;
208
static int hf_cose_recipient_list;
209
static int hf_cose_recipient;
210
static int hf_tag;
211
212
static int hf_hdr_label_int;
213
static int hf_hdr_label_tstr;
214
215
static int hf_hdr_salt;
216
static int hf_hdr_static_key;
217
static int hf_hdr_ephem_key;
218
static int hf_hdr_alg_int;
219
static int hf_hdr_alg_tstr;
220
static int hf_hdr_crit_list;
221
static int hf_hdr_ctype_uint;
222
static int hf_hdr_ctype_tstr;
223
static int hf_hdr_kid;
224
static int hf_hdr_kid_text;
225
static int hf_hdr_iv;
226
static int hf_hdr_piv;
227
static int hf_hdr_x5bag;
228
static int hf_hdr_x5chain;
229
static int hf_hdr_x5t;
230
static int hf_hdr_x5t_hash;
231
static int hf_hdr_x5u;
232
233
static int hf_key;
234
235
static int hf_keyparam_kty_int;
236
static int hf_keyparam_kty_tstr;
237
static int hf_keyparam_keyops_list;
238
static int hf_keyparam_keyops_int;
239
static int hf_keyparam_keyops_tstr;
240
static int hf_keyparam_baseiv;
241
static int hf_keyparam_crv_int;
242
static int hf_keyparam_crv_tstr;
243
static int hf_keyparam_xcoord;
244
static int hf_keyparam_ycoord;
245
static int hf_keyparam_dcoord;
246
static int hf_keyparam_k;
247
static int hf_keyparam_pub;
248
static int hf_keyparam_priv;
249
250
/// Field definitions
251
static hf_register_info fields[] = {
252
    {&hf_msg_tag, {"Message type tag", "cose.msgtag", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
253
    {&hf_hdr_prot_bstr, {"Protected Headers (bstr)", "cose.msg.prot_bstr", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
254
    {&hf_hdr_unprot, {"Unprotected Headers", "cose.msg.unprot", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
255
256
    {&hf_payload_null, {"Payload Detached", "cose.msg.detached_payload", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
257
    {&hf_payload_bstr, {"Payload", "cose.msg.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
258
    {&hf_signature, {"Signature", "cose.msg.signature", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
259
    {&hf_cose_signature_list, {"Signature List, Count", "cose.msg.signature_list", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
260
    {&hf_cose_signature, {"COSE_Signature", "cose.msg.cose_signature", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
261
    {&hf_ciphertext_null, {"Ciphertext Detached", "cose.msg.detached_ciphertext", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
262
    {&hf_ciphertext_bstr, {"Ciphertext", "cose.msg.ciphertext", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
263
    {&hf_cose_recipient_list, {"Recipient List, Count", "cose.msg.recipient_list", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
264
    {&hf_cose_recipient, {"COSE_Recipient", "cose.msg.cose_recipient", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
265
    {&hf_tag, {"Tag", "cose.msg.mac_tag", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
266
267
    {&hf_hdr_label_int, {"Label", "cose.header_label.int", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
268
    {&hf_hdr_label_tstr, {"Label", "cose.header_label.tstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
269
270
    {&hf_hdr_salt, {"Salt", "cose.salt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
271
    {&hf_hdr_static_key, {"Static Key", "cose.static_key", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
272
    {&hf_hdr_ephem_key, {"Ephemeral Key", "cose.ephem_key", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
273
    {&hf_hdr_alg_int, {"Algorithm", "cose.alg.int", FT_INT64, BASE_DEC | BASE_VAL64_STRING, VALS64(alg_vals), 0x0, NULL, HFILL}},
274
    {&hf_hdr_alg_tstr, {"Algorithm", "cose.alg.tstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
275
    {&hf_hdr_crit_list, {"Critical Headers, Count", "cose.crit", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
276
    {&hf_hdr_ctype_uint, {"Content-Format", "cose.content-type.uint", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
277
    {&hf_hdr_ctype_tstr, {"Content-Type", "cose.content-type.tstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
278
    {&hf_hdr_kid, {"Key identifier", "cose.kid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
279
    {&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}},
280
    {&hf_hdr_iv, {"IV", "cose.iv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
281
    {&hf_hdr_piv, {"Partial IV", "cose.piv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
282
283
    {&hf_hdr_x5bag, {"X509 Bag (x5bag)", "cose.x5bag", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
284
    {&hf_hdr_x5chain, {"X509 Chain (x5chain)", "cose.x5chain", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
285
    {&hf_hdr_x5t, {"X509 Thumbprint (x5t)", "cose.x5t", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
286
    {&hf_hdr_x5t_hash, {"Hash Value", "cose.x5t.hash", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
287
    {&hf_hdr_x5u, {"X509 URI (x5u)", "cose.x5u", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
288
289
    {&hf_key, {"COSE_Key", "cose.key", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
290
291
    {&hf_keyparam_kty_int, {"Key Type", "cose.kty.int", FT_INT64, BASE_DEC | BASE_VAL64_STRING, VALS64(kty_vals), 0x0, NULL, HFILL}},
292
    {&hf_keyparam_kty_tstr, {"Key Type", "cose.kty.tstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
293
    {&hf_keyparam_keyops_list, {"Key Operations", "cose.keyops", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
294
    {&hf_keyparam_keyops_int, {"Operation", "cose.keyops.int", FT_INT64, BASE_DEC | BASE_VAL64_STRING, VALS64(keyops_vals), 0x0, NULL, HFILL}},
295
    {&hf_keyparam_keyops_tstr, {"Operation", "cose.keyops.tstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
296
    {&hf_keyparam_baseiv, {"Base IV", "cose.baseiv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
297
    {&hf_keyparam_crv_int, {"Curve Type", "cose.crv.int", FT_INT64, BASE_DEC | BASE_VAL64_STRING, VALS64(crv_vals), 0x0, NULL, HFILL}},
298
    {&hf_keyparam_crv_tstr, {"Curve Type", "cose.crv.tstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
299
    {&hf_keyparam_xcoord, {"X-coordinate", "cose.key.xcoord", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
300
    {&hf_keyparam_ycoord, {"Y-coordinate", "cose.key.ycoord", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
301
    {&hf_keyparam_dcoord, {"Private Key", "cose.key.dcoord", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
302
    {&hf_keyparam_k, {"Key", "cose.key.k", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
303
    {&hf_keyparam_pub, {"Public key", "cose.key.pub", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
304
    {&hf_keyparam_priv, {"Private key", "cose.key.priv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
305
};
306
307
static int ett_msg;
308
static int ett_sig_list;
309
static int ett_sig;
310
static int ett_recip_list;
311
static int ett_recip;
312
static int ett_prot_bstr;
313
static int ett_unprot;
314
static int ett_hdr_map;
315
static int ett_hdr_label;
316
static int ett_hdr_kid;
317
static int ett_hdr_static_key;
318
static int ett_hdr_ephem_key;
319
static int ett_hdr_crit_list;
320
static int ett_hdr_x5cert_list;
321
static int ett_hdr_x5t_list;
322
static int ett_key;
323
static int ett_key_set;
324
static int ett_keyops_list;
325
/// Tree structures
326
static int *ett[] = {
327
    &ett_msg,
328
    &ett_sig_list,
329
    &ett_sig,
330
    &ett_recip_list,
331
    &ett_recip,
332
    &ett_prot_bstr,
333
    &ett_unprot,
334
    &ett_hdr_map,
335
    &ett_hdr_label,
336
    &ett_hdr_kid,
337
    &ett_hdr_static_key,
338
    &ett_hdr_ephem_key,
339
    &ett_hdr_crit_list,
340
    &ett_hdr_x5cert_list,
341
    &ett_hdr_x5t_list,
342
    &ett_key,
343
    &ett_key_set,
344
    &ett_keyops_list,
345
};
346
347
static expert_field ei_invalid_tag;
348
static expert_field ei_value_partial_decode;
349
static ei_register_info expertitems[] = {
350
    {&ei_invalid_tag, { "cose.invalid_tag", PI_UNDECODED, PI_WARN, "COSE dissector did not match any known tag", EXPFILL}},
351
    {&ei_value_partial_decode, { "cose.partial_decode", PI_MALFORMED, PI_WARN, "Value is only partially decoded", EXPFILL}},
352
};
353
354
/* Compatible with GHashFunc signature. */
355
11.0k
static unsigned cose_param_key_hash(const void *ptr) {
356
11.0k
    const cose_param_key_t *obj = (const cose_param_key_t *)ptr;
357
11.0k
    unsigned val = 0;
358
11.0k
    if (obj->principal) {
359
5.03k
        val ^= g_int64_hash(obj->principal);
360
5.03k
    }
361
11.0k
    if (obj->label) {
362
9.07k
        val ^= g_variant_hash(obj->label);
363
9.07k
    }
364
11.0k
    return val;
365
11.0k
}
366
367
/* Compatible with GEqualFunc signature. */
368
8.49k
static gboolean cose_param_key_equal(const void *a, const void *b) {
369
8.49k
    const cose_param_key_t *aobj = (const cose_param_key_t *)a;
370
8.49k
    const cose_param_key_t *bobj = (const cose_param_key_t *)b;
371
372
8.49k
    if (aobj->principal && bobj->principal) {
373
1.20k
        if (!g_variant_equal(aobj->principal, bobj->principal)) {
374
879
            return FALSE;
375
879
        }
376
1.20k
    }
377
7.28k
    else if ((aobj->principal == NULL) != (bobj->principal == NULL)) {
378
0
        return FALSE;
379
0
    }
380
381
7.61k
    gboolean match;
382
7.61k
    if (aobj->label && bobj->label) {
383
5.40k
        match = g_variant_equal(aobj->label, bobj->label);
384
5.40k
    }
385
2.20k
    else {
386
        // don't care
387
2.20k
        match = FALSE;
388
2.20k
    }
389
7.61k
    return match;
390
8.49k
}
391
392
/* Compatible with GDestroyNotify signature. */
393
0
static void cose_param_key_free(void *ptr) {
394
0
    cose_param_key_t *obj = (cose_param_key_t *)ptr;
395
0
    if (obj->principal) {
396
0
        g_variant_unref(obj->principal);
397
0
    }
398
0
    if (obj->label) {
399
0
        g_variant_unref(obj->label);
400
0
    }
401
0
    g_free(obj);
402
0
}
403
404
/// Known hash properties
405
static const cose_hash_props_t cose_hash_props_list[] = {
406
    {-45, GCRY_MD_SHAKE256, 64},
407
    {-44, GCRY_MD_SHA512, 64},
408
    {-43, GCRY_MD_SHA384, 48},
409
    {-18, GCRY_MD_SHAKE128, 32},
410
    {-17, GCRY_MD_SHA512, 32}, // truncated
411
    {-16, GCRY_MD_SHA256, 32},
412
    {-15, GCRY_MD_SHA256, 16}, // truncated
413
    {-14, GCRY_MD_SHA1, 20},
414
};
415
/// Derived lookup map
416
static GHashTable *cose_hash_props_map = NULL;
417
418
0
const cose_hash_props_t * cose_get_hash_props(int64_t alg) {
419
0
    if (cose_hash_props_map) {
420
        // fast lookup when available
421
0
        return g_hash_table_lookup(cose_hash_props_map, &alg);
422
0
    }
423
0
    else {
424
0
        return NULL;
425
0
    }
426
0
}
427
428
/// Known AEAD properties
429
static const cose_aead_props_t cose_aead_props_list[] = {
430
    {1, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_GCM, 16, 12, 16},
431
    {2, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_GCM, 24, 12, 16},
432
    {3, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 32, 12, 16},
433
434
    {10, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 16, 13, 8},
435
    {11, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 32, 13, 8},
436
    {12, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 16, 7, 8},
437
    {13, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 32, 7, 8},
438
439
    {24, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_POLY1305, 32, 12, 16},
440
441
    {30, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 16, 13, 16},
442
    {31, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 32, 13, 16},
443
    {32, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 16, 7, 16},
444
    {33, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CCM, 32, 7, 16},
445
};
446
/// Derived lookup map
447
static GHashTable *cose_aead_props_map = NULL;
448
449
0
const cose_aead_props_t * cose_get_aead_props(int64_t alg) {
450
0
    if (cose_aead_props_map) {
451
        // fast lookup when available
452
0
        return g_hash_table_lookup(cose_aead_props_map, &alg);
453
0
    }
454
0
    else {
455
0
        return NULL;
456
0
    }
457
0
}
458
459
/// Known curve properties
460
static const cose_ecc_props_t cose_ecc_props_list[] = {
461
    {1, 32}, // P-256
462
    {2, 48}, // P-384
463
    {3, 66}, // P-521
464
    {4, 32}, // X25519
465
    {5, 57}, // X448
466
    {6, 32}, // Ed25519
467
    {7, 57}, // Ed448
468
    {8, 32}, // secp256k1
469
};
470
/// Derived lookup map
471
static GHashTable *cose_ecc_props_map = NULL;
472
473
0
const cose_ecc_props_t * cose_get_ecc_props(int64_t crv) {
474
0
    if (cose_ecc_props_map) {
475
        // fast lookup when available
476
0
        return g_hash_table_lookup(cose_ecc_props_map, &crv);
477
0
    }
478
0
    else {
479
0
        return NULL;
480
0
    }
481
0
}
482
483
/** Get a specific item value (map key or value) from a header map.
484
 * @param alloc The allocator for temporary data.
485
 * @param tvb The buffer to read from.
486
 * @param[in,out] offset The starting offset to read and advance.
487
 * @return A pointer to the simple value or NULL.
488
 */
489
8.02k
static GVariant * get_header_value(wmem_allocator_t *alloc, tvbuff_t *tvb, int *offset) {
490
8.02k
    GVariant *result = NULL;
491
492
8.02k
    wscbor_chunk_t *chunk = wscbor_chunk_read(alloc, tvb, offset);
493
8.02k
    switch (chunk->type_major) {
494
3.36k
        case CBOR_TYPE_UINT:
495
4.28k
        case CBOR_TYPE_NEGINT: {
496
4.28k
            int64_t *label = wscbor_require_int64(alloc, chunk);
497
4.28k
            if (label) {
498
4.28k
                result = g_variant_new_int64(*label);
499
4.28k
            }
500
4.28k
            break;
501
3.36k
        }
502
833
        case CBOR_TYPE_STRING: {
503
833
            const char *label = wscbor_require_tstr(alloc, chunk);
504
833
            if (label) {
505
831
                result = g_variant_new_string(label);
506
831
            }
507
833
            break;
508
3.36k
        }
509
2.89k
        default:
510
2.89k
            break;
511
8.02k
    }
512
8.00k
    wscbor_chunk_free(chunk);
513
8.00k
    return result;
514
8.02k
}
515
516
/** Dissect an ID-value pair within a context.
517
 *
518
 * @param dis_table The cose_param_key_t dissector table.
519
 * @param[in,out] ctx The context from other pairs.
520
 * @return True if the pair was dissected (even as opaque CBOR data).
521
 */
522
5.47k
static bool dissect_header_pair(dissector_table_t dis_table, cose_header_context_t *ctx, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
523
5.47k
    wscbor_chunk_t *chunk_label = wscbor_chunk_read(pinfo->pool, tvb, offset);
524
525
5.47k
    proto_item *item_label = NULL;
526
5.47k
    proto_tree *volatile tree_label = NULL;
527
5.47k
    tvbuff_t *volatile tvb_value = NULL;
528
529
5.47k
    cose_param_key_t key = { 0 };
530
531
5.47k
    const char *label_str = NULL;
532
5.47k
    switch (chunk_label->type_major) {
533
3.02k
        case CBOR_TYPE_UINT:
534
4.10k
        case CBOR_TYPE_NEGINT: {
535
4.10k
            int64_t *label = wscbor_require_int64(pinfo->pool, chunk_label);
536
4.10k
            item_label = proto_tree_add_cbor_int64(tree, hf_hdr_label_int, pinfo, tvb, chunk_label, label);
537
4.10k
            if (label) {
538
4.10k
                key.label = ctx->label =
539
4.10k
                    g_variant_new_int64(*label);
540
4.10k
                label_str = wmem_strdup_printf(pinfo->pool, "%" PRId64, *label);
541
4.10k
            }
542
4.10k
            break;
543
3.02k
        }
544
369
        case CBOR_TYPE_STRING: {
545
369
            const char *label = wscbor_require_tstr(pinfo->pool, chunk_label);
546
369
            item_label = proto_tree_add_cbor_tstr(tree, hf_hdr_label_tstr, pinfo, tvb, chunk_label);
547
369
            if (label) {
548
355
                key.label = ctx->label =
549
355
                    g_variant_new_string(label);
550
355
                label_str = label;
551
355
            }
552
369
            break;
553
3.02k
        }
554
976
        default:
555
976
            break;
556
5.47k
    }
557
558
    // First attempt with context then without
559
5.43k
    key.principal = ctx->principal;
560
5.43k
    dissector_handle_t dissector = dissector_get_custom_table_handle(dis_table, &key);
561
5.43k
    if (!dissector) {
562
5.05k
        key.principal = NULL;
563
5.05k
        dissector = dissector_get_custom_table_handle(dis_table, &key);
564
5.05k
    }
565
5.43k
    const char *dis_name = dissector_handle_get_description(dissector);
566
5.43k
    if (item_label && dis_name) {
567
1.38k
        proto_item_set_text(item_label, "%s: %s (%s)",
568
1.38k
                            PITEM_HFINFO(item_label)->name, dis_name, label_str);
569
1.38k
    }
570
571
5.43k
    tree_label = proto_item_add_subtree(item_label, ett_hdr_label);
572
573
    // Peek into the value as tvb
574
5.43k
    const int offset_value = *offset;
575
5.43k
    if (!wscbor_skip_next_item(pinfo->pool, tvb, offset)) {
576
265
        return false;
577
265
    }
578
5.17k
    tvb_value = tvb_new_subset_length(tvb, offset_value, *offset - offset_value);
579
580
5.17k
    int sublen = 0;
581
5.17k
    if (dissector) {
582
1.37k
        sublen = call_dissector_only(dissector, tvb_value, pinfo, tree_label, ctx);
583
1.37k
        if ((sublen < 0) ||
584
1.37k
            ((sublen > 0) && ((unsigned)sublen < tvb_reported_length(tvb_value)))) {
585
21
            expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_value_partial_decode);
586
21
        }
587
1.37k
    }
588
5.17k
    if (ctx->label) {
589
4.31k
        g_variant_unref(ctx->label);
590
4.31k
        ctx->label = NULL;
591
4.31k
    }
592
5.17k
    if (sublen == 0) {
593
3.78k
        TRY {
594
3.78k
            call_dissector(handle_cbor, tvb_value, pinfo, tree_label);
595
3.78k
        }
596
3.78k
        CATCH_ALL {}
597
3.78k
        ENDTRY;
598
3.78k
    }
599
5.17k
    return true;
600
5.43k
}
601
602
static void
603
403
cose_header_context_cleanup(void *user_data) {
604
403
    cose_header_context_t *ctx = (cose_header_context_t *)user_data;
605
606
403
    if (ctx->principal) {
607
231
        g_variant_unref(ctx->principal);
608
231
    }
609
403
    if (ctx->label) {
610
148
        g_variant_unref(ctx->label);
611
148
        ctx->label = NULL;
612
148
    }
613
403
}
614
615
static void
616
5.43k
g_variant_cleanup(void *user_data) {
617
5.43k
    GVariant *var = (GVariant *)user_data;
618
5.43k
    g_variant_unref(var);
619
5.43k
}
620
621
/** Dissect an entire header map, either for messages, recipients, or keys.
622
 *
623
 * @param dis_table The cose_param_key_t dissector table.
624
 * @param tvb The source data.
625
 * @param tree The parent of the header map.
626
 * @param[in,out] offset The data offset.
627
 * @param principal_key The map key associated with a principal value to read first.
628
 */
629
5.43k
static void dissect_header_map(dissector_table_t dis_table, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, GVariant *principal_key) {
630
5.43k
    wscbor_chunk_t *chunk_hdr_map = wscbor_chunk_read(pinfo->pool, tvb, offset);
631
5.43k
    wscbor_require_map(chunk_hdr_map);
632
5.43k
    proto_item *item_hdr_map = proto_tree_get_parent(tree);
633
5.43k
    wscbor_chunk_mark_errors(pinfo, item_hdr_map, chunk_hdr_map);
634
5.43k
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, offset, chunk_hdr_map)) {
635
403
        proto_tree *tree_hdr_map = proto_item_add_subtree(item_hdr_map, ett_hdr_map);
636
637
403
        cose_header_context_t *ctx = wmem_new0(pinfo->pool, cose_header_context_t);
638
403
        CLEANUP_PUSH(cose_header_context_cleanup, ctx);
639
640
        // Peek ahead to principal key (and value) first
641
403
        if (principal_key) {
642
403
            int peek_offset = *offset;
643
7.87k
            for (uint64_t ix = 0; ix < chunk_hdr_map->head_value; ++ix) {
644
7.70k
                GVariant *key = get_header_value(pinfo->pool, tvb, &peek_offset);
645
7.70k
                if (key) {
646
                    /* Release the key before reading the value, which can throw */
647
4.88k
                    bool is_principal = g_variant_equal(key, principal_key);
648
4.88k
                    g_variant_unref(key);
649
4.88k
                    if (is_principal) {
650
324
                        ctx->principal = get_header_value(pinfo->pool, tvb, &peek_offset);
651
324
                    }
652
4.88k
                    if (ctx->principal) {
653
231
                        break;
654
231
                    }
655
4.88k
                }
656
                // ignore non-principal value entirely
657
7.47k
                wscbor_skip_next_item(pinfo->pool, tvb, &peek_offset);
658
7.47k
            }
659
403
        }
660
661
5.60k
        for (uint64_t ix = 0; ix < chunk_hdr_map->head_value; ++ix) {
662
5.47k
            if (!dissect_header_pair(dis_table, ctx, tvb, pinfo, tree_hdr_map, offset)) {
663
265
                break;
664
265
            }
665
5.47k
        }
666
667
403
        CLEANUP_CALL_AND_POP;
668
403
        wmem_free(pinfo->pool, ctx);
669
403
    }
670
671
5.43k
    proto_item_set_len(item_hdr_map, *offset - chunk_hdr_map->start);
672
5.43k
}
673
674
0
static int dissect_cose_msg_header_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
675
0
    int offset = 0;
676
0
    GVariant *alg_key = g_variant_new_int64(1);
677
0
    CLEANUP_PUSH(g_variant_cleanup, alg_key);
678
679
0
    dissect_header_map(table_header, tvb, pinfo, tree, &offset, alg_key);
680
681
0
    CLEANUP_CALL_AND_POP;
682
0
    return offset;
683
0
}
684
685
/** Indicate the tag which informed the message type.
686
 */
687
0
static void dissect_msg_tag(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree_msg, const wscbor_chunk_t *chunk_msg _U_, const void *data) {
688
0
    if (!data) {
689
0
        return;
690
0
    }
691
0
    const wscbor_tag_t *tag = (const wscbor_tag_t *)data;
692
693
0
    proto_tree_add_uint64(tree_msg, hf_msg_tag, tvb, tag->start, tag->length, tag->value);
694
0
}
695
696
/** Common behavior for pair of header maps.
697
 */
698
0
static void dissect_headers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
699
    // Protected in bstr
700
0
    wscbor_chunk_t *chunk_prot_bstr = wscbor_chunk_read(pinfo->pool, tvb, offset);
701
0
    tvbuff_t *tvb_prot = wscbor_require_bstr(pinfo->pool, chunk_prot_bstr);
702
0
    proto_item *item_prot_bstr = proto_tree_add_cbor_bstr(tree, hf_hdr_prot_bstr, pinfo, tvb, chunk_prot_bstr);
703
0
    if (tvb_prot) {
704
0
        proto_tree *tree_prot = proto_item_add_subtree(item_prot_bstr, ett_prot_bstr);
705
706
0
        if (tvb_reported_length(tvb_prot) > 0) {
707
0
            dissect_cose_msg_header_map(tvb_prot, pinfo, tree_prot, NULL);
708
0
        }
709
0
    }
710
711
    // Unprotected
712
0
    tvbuff_t *tvb_unprot = tvb_new_subset_remaining(tvb, *offset);
713
0
    proto_item *item_unprot = proto_tree_add_item(tree, hf_hdr_unprot, tvb_unprot, 0, -1, ENC_NA);
714
0
    proto_tree *tree_unprot = proto_item_add_subtree(item_unprot, ett_unprot);
715
0
    const int sublen = dissect_cose_msg_header_map(tvb_unprot, pinfo, tree_unprot, NULL);
716
0
    *offset += sublen;
717
0
    proto_item_set_len(item_unprot, sublen);
718
0
}
719
720
/** Common behavior for payload.
721
 */
722
0
static void dissect_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
723
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, offset);
724
0
    if (chunk->type_major == CBOR_TYPE_FLOAT_CTRL) {
725
0
        proto_tree_add_cbor_ctrl(tree, hf_payload_null, pinfo, tvb, chunk);
726
0
    }
727
0
    else {
728
0
        wscbor_require_bstr(pinfo->pool, chunk);
729
0
        proto_tree_add_cbor_bstr(tree, hf_payload_bstr, pinfo, tvb, chunk);
730
0
    }
731
0
}
732
0
static void dissect_signature(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
733
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, offset);
734
0
    wscbor_require_bstr(pinfo->pool, chunk);
735
0
    proto_tree_add_cbor_bstr(tree, hf_signature, pinfo, tvb, chunk);
736
0
}
737
0
static void dissect_cose_signature(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
738
0
    wscbor_chunk_t *chunk_sig = wscbor_chunk_read(pinfo->pool, tvb, offset);
739
0
    wscbor_require_array_size(chunk_sig, 3, 3);
740
0
    proto_item *item_sig = proto_tree_add_cbor_container(tree, hf_cose_signature, pinfo, tvb, chunk_sig);
741
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, offset, chunk_sig)) {
742
0
        proto_tree *tree_sig = proto_item_add_subtree(item_sig, ett_sig);
743
744
0
        dissect_headers(tvb, pinfo, tree_sig, offset);
745
0
        dissect_signature(tvb, pinfo, tree_sig, offset);
746
0
    }
747
0
    proto_item_set_len(item_sig, *offset - chunk_sig->start);
748
0
}
749
0
static void dissect_ciphertext(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
750
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, offset);
751
0
    if (chunk->type_major == CBOR_TYPE_FLOAT_CTRL) {
752
0
        proto_tree_add_cbor_ctrl(tree, hf_ciphertext_null, pinfo, tvb, chunk);
753
0
    }
754
0
    else {
755
0
        wscbor_require_bstr(pinfo->pool, chunk);
756
0
        proto_tree_add_cbor_bstr(tree, hf_ciphertext_bstr, pinfo, tvb, chunk);
757
0
    }
758
0
}
759
static void dissect_cose_recipient(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset);
760
761
// NOLINTNEXTLINE(misc-no-recursion)
762
0
static void dissect_cose_recipient_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
763
0
    wscbor_chunk_t *chunk_list = wscbor_chunk_read(pinfo->pool, tvb, offset);
764
0
    wscbor_require_array(chunk_list);
765
0
    proto_item *item_list = proto_tree_add_cbor_container(tree, hf_cose_recipient_list, pinfo, tvb, chunk_list);
766
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, offset, chunk_list)) {
767
0
        proto_tree *tree_recip_list = proto_item_add_subtree(item_list, ett_recip_list);
768
769
0
        for (uint64_t ix = 0; ix < chunk_list->head_value; ++ix) {
770
0
            dissect_cose_recipient(tvb, pinfo, tree_recip_list, offset);
771
0
        }
772
0
    }
773
0
    proto_item_set_len(item_list, *offset - chunk_list->start);
774
0
}
775
776
// NOLINTNEXTLINE(misc-no-recursion)
777
0
static void dissect_cose_recipient(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
778
0
    wscbor_chunk_t *chunk_recip = wscbor_chunk_read(pinfo->pool, tvb, offset);
779
0
    wscbor_require_array_size(chunk_recip, 3, 4);
780
0
    proto_item *item_recip = proto_tree_add_cbor_container(tree, hf_cose_recipient, pinfo, tvb, chunk_recip);
781
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, offset, chunk_recip)) {
782
0
        proto_tree *tree_recip = proto_item_add_subtree(item_recip, ett_recip);
783
784
0
        dissect_headers(tvb, pinfo, tree_recip, offset);
785
0
        dissect_ciphertext(tvb, pinfo, tree_recip, offset);
786
0
        if (chunk_recip->head_value > 3) {
787
0
            increment_dissection_depth(pinfo);
788
0
            dissect_cose_recipient_list(tvb, pinfo, tree_recip, offset);
789
0
            decrement_dissection_depth(pinfo);
790
0
        }
791
0
    }
792
0
    proto_item_set_len(item_recip, *offset - chunk_recip->start);
793
794
0
}
795
0
static void dissect_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
796
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, offset);
797
0
    wscbor_require_bstr(pinfo->pool, chunk);
798
0
    proto_tree_add_cbor_bstr(tree, hf_tag, pinfo, tvb, chunk);
799
0
}
800
801
// Top-level protocol dissectors
802
0
static int dissect_cose_sign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
803
0
    int offset = 0;
804
805
0
    wscbor_chunk_t *chunk_msg = wscbor_chunk_read(pinfo->pool, tvb, &offset);
806
0
    wscbor_require_array_size(chunk_msg, 4, 4);
807
0
    proto_item *item_msg = proto_tree_add_cbor_container(tree, proto_cose, pinfo, tvb, chunk_msg);
808
0
    proto_item_append_text(item_msg, ": COSE_Sign");
809
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_msg)) {
810
0
        proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_msg);
811
0
        dissect_msg_tag(tvb, pinfo, tree_msg, chunk_msg, data);
812
813
0
        dissect_headers(tvb, pinfo, tree_msg, &offset);
814
0
        dissect_payload(tvb, pinfo, tree_msg, &offset);
815
816
0
        wscbor_chunk_t *chunk_sig_list = wscbor_chunk_read(pinfo->pool, tvb, &offset);
817
0
        wscbor_require_array(chunk_sig_list);
818
0
        proto_item *item_sig_list = proto_tree_add_cbor_container(tree_msg, hf_cose_signature_list, pinfo, tvb, chunk_sig_list);
819
0
        if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_sig_list)) {
820
0
            proto_tree *tree_sig_list = proto_item_add_subtree(item_sig_list, ett_sig_list);
821
822
0
            for (uint64_t ix = 0; ix < chunk_sig_list->head_value; ++ix) {
823
0
                dissect_cose_signature(tvb, pinfo, tree_sig_list, &offset);
824
0
            }
825
0
        }
826
0
        proto_item_set_len(item_sig_list, offset - chunk_sig_list->start);
827
0
    }
828
829
0
    return offset;
830
0
}
831
832
0
static int dissect_cose_sign1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
833
0
    int offset = 0;
834
835
0
    wscbor_chunk_t *chunk_msg = wscbor_chunk_read(pinfo->pool, tvb, &offset);
836
0
    wscbor_require_array_size(chunk_msg, 4, 4);
837
0
    proto_item *item_msg = proto_tree_add_cbor_container(tree, proto_cose, pinfo, tvb, chunk_msg);
838
0
    proto_item_append_text(item_msg, ": COSE_Sign1");
839
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_msg)) {
840
0
        proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_msg);
841
0
        dissect_msg_tag(tvb, pinfo, tree_msg, chunk_msg, data);
842
843
0
        dissect_headers(tvb, pinfo, tree_msg, &offset);
844
0
        dissect_payload(tvb, pinfo, tree_msg, &offset);
845
0
        dissect_signature(tvb, pinfo, tree_msg, &offset);
846
0
    }
847
848
0
    return offset;
849
0
}
850
851
0
static int dissect_cose_encrypt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
852
0
    int offset = 0;
853
854
0
    wscbor_chunk_t *chunk_msg = wscbor_chunk_read(pinfo->pool, tvb, &offset);
855
0
    wscbor_require_array_size(chunk_msg, 4, 4);
856
0
    proto_item *item_msg = proto_tree_add_cbor_container(tree, proto_cose, pinfo, tvb, chunk_msg);
857
0
    proto_item_append_text(item_msg, ": COSE_Encrypt");
858
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_msg)) {
859
0
        proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_msg);
860
0
        dissect_msg_tag(tvb, pinfo, tree_msg, chunk_msg, data);
861
862
0
        dissect_headers(tvb, pinfo, tree_msg, &offset);
863
0
        dissect_ciphertext(tvb, pinfo, tree_msg, &offset);
864
0
        dissect_cose_recipient_list(tvb, pinfo, tree_msg, &offset);
865
0
    }
866
867
0
    return offset;
868
0
}
869
870
0
static int dissect_cose_encrypt0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
871
0
    int offset = 0;
872
873
0
    wscbor_chunk_t *chunk_msg = wscbor_chunk_read(pinfo->pool, tvb, &offset);
874
0
    wscbor_require_array_size(chunk_msg, 3, 3);
875
0
    proto_item *item_msg = proto_tree_add_cbor_container(tree, proto_cose, pinfo, tvb, chunk_msg);
876
0
    proto_item_append_text(item_msg, ": COSE_Encrypt0");
877
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_msg)) {
878
0
        proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_msg);
879
0
        dissect_msg_tag(tvb, pinfo, tree_msg, chunk_msg, data);
880
881
0
        dissect_headers(tvb, pinfo, tree_msg, &offset);
882
0
        dissect_ciphertext(tvb, pinfo, tree_msg, &offset);
883
0
    }
884
885
0
    return offset;
886
0
}
887
888
0
static int dissect_cose_mac(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
889
0
    int offset = 0;
890
891
0
    wscbor_chunk_t *chunk_msg = wscbor_chunk_read(pinfo->pool, tvb, &offset);
892
0
    wscbor_require_array_size(chunk_msg, 5, 5);
893
0
    proto_item *item_msg = proto_tree_add_cbor_container(tree, proto_cose, pinfo, tvb, chunk_msg);
894
0
    proto_item_append_text(item_msg, ": COSE_Mac");
895
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_msg)) {
896
0
        proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_msg);
897
0
        dissect_msg_tag(tvb, pinfo, tree_msg, chunk_msg, data);
898
899
0
        dissect_headers(tvb, pinfo, tree_msg, &offset);
900
0
        dissect_payload(tvb, pinfo, tree_msg, &offset);
901
0
        dissect_tag(tvb, pinfo, tree_msg, &offset);
902
0
        dissect_cose_recipient_list(tvb, pinfo, tree_msg, &offset);
903
0
    }
904
905
0
    return offset;
906
0
}
907
908
0
static int dissect_cose_mac0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
909
0
    int offset = 0;
910
911
0
    wscbor_chunk_t *chunk_msg = wscbor_chunk_read(pinfo->pool, tvb, &offset);
912
0
    wscbor_require_array_size(chunk_msg, 4, 4);
913
0
    proto_item *item_msg = proto_tree_add_cbor_container(tree, proto_cose, pinfo, tvb, chunk_msg);
914
0
    proto_item_append_text(item_msg, ": COSE_Mac0");
915
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_msg)) {
916
0
        proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_msg);
917
0
        dissect_msg_tag(tvb, pinfo, tree_msg, chunk_msg, data);
918
919
0
        dissect_headers(tvb, pinfo, tree_msg, &offset);
920
0
        dissect_payload(tvb, pinfo, tree_msg, &offset);
921
0
        dissect_tag(tvb, pinfo, tree_msg, &offset);
922
0
    }
923
924
0
    return offset;
925
0
}
926
927
/** Dissect a tagged COSE message.
928
 */
929
0
static int dissect_cose_msg_tagged(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
930
0
    int offset = 0;
931
932
    // All messages have the same base structure, attempt all tags present
933
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
934
0
    for (wmem_list_frame_t *it = wmem_list_head(chunk->tags); it;
935
0
            it = wmem_list_frame_next(it)) {
936
0
        wscbor_tag_t *tag = (wscbor_tag_t *) wmem_list_frame_data(it);
937
        // first usable tag wins
938
0
        dissector_handle_t dissector = dissector_get_custom_table_handle(table_cose_msg_tag, &(tag->value));
939
0
        if (!dissector) {
940
0
            continue;
941
0
        }
942
0
        int sublen = call_dissector_only(dissector, tvb, pinfo, tree, tag);
943
0
        if (sublen > 0) {
944
0
            return sublen;
945
0
        }
946
0
    }
947
948
0
    proto_item *item_msg = proto_tree_add_item(tree, proto_cose, tvb, 0, -1, ENC_NA);
949
0
    expert_add_info(pinfo, item_msg, &ei_invalid_tag);
950
0
    return -1;
951
0
}
952
953
/** Dissect the application/cose media type with optional parameters.
954
 */
955
0
static int dissect_cose_media_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
956
0
    const media_content_info_t *content_info = (media_content_info_t *)data;
957
958
0
    const char *subtype = NULL;
959
    /* Some media_type callers (AMQP, OBEX, ID3v2) pass no media_content_info_t */
960
0
    if (content_info && content_info->media_str) {
961
0
        subtype = ws_find_media_type_parameter(pinfo->pool, content_info->media_str, "cose-type");
962
0
    }
963
964
0
    dissector_handle_t dissector;
965
0
    if (subtype) {
966
0
        dissector = dissector_get_string_handle(table_cose_media_subtype, subtype);
967
0
    }
968
0
    else {
969
        // no media type parameter, require tagged message
970
0
        dissector = handle_cose_msg_tagged;
971
0
    }
972
973
0
    if (dissector) {
974
0
        int sublen = call_dissector_only(dissector, tvb, pinfo, tree, NULL);
975
0
        if (sublen > 0) {
976
0
            return sublen;
977
0
        }
978
0
    }
979
980
0
    proto_item *item_msg = proto_tree_add_item(tree, proto_cose, tvb, 0, -1, ENC_NA);
981
0
    expert_add_info(pinfo, item_msg, &ei_invalid_tag);
982
0
    return -1;
983
0
}
984
985
112
static void dissect_value_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
986
112
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, offset);
987
112
    switch (chunk->type_major) {
988
91
        case CBOR_TYPE_UINT:
989
98
        case CBOR_TYPE_NEGINT: {
990
98
            int64_t *val = wscbor_require_int64(pinfo->pool, chunk);
991
98
            proto_tree_add_cbor_int64(tree, hf_hdr_alg_int, pinfo, tvb, chunk, val);
992
98
            break;
993
91
        }
994
0
        case CBOR_TYPE_STRING: {
995
0
            proto_tree_add_cbor_tstr(tree, hf_hdr_alg_tstr, pinfo, tvb, chunk);
996
0
            break;
997
91
        }
998
14
        default:
999
14
            break;
1000
112
    }
1001
112
}
1002
1003
0
static int dissect_header_salt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1004
0
    int offset = 0;
1005
1006
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1007
0
    wscbor_require_bstr(pinfo->pool, chunk);
1008
0
    proto_tree_add_cbor_bstr(tree, hf_hdr_salt, pinfo, tvb, chunk);
1009
1010
0
    return offset;
1011
0
}
1012
1013
5.43k
static void dissect_value_cose_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
1014
5.43k
    GVariant *kty_key = g_variant_new_int64(1);
1015
5.43k
    CLEANUP_PUSH(g_variant_cleanup, kty_key);
1016
1017
5.43k
    dissect_header_map(table_keyparam, tvb, pinfo, tree, offset, kty_key);
1018
1019
5.43k
    CLEANUP_CALL_AND_POP;
1020
5.43k
}
1021
1022
0
static int dissect_header_static_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1023
0
    int offset = 0;
1024
0
    proto_item *item_ctr = proto_tree_add_item(tree, hf_hdr_static_key, tvb, 0, -1, ENC_NA);
1025
0
    proto_tree *tree_ctr = proto_item_add_subtree(item_ctr, ett_hdr_static_key);
1026
0
    dissect_value_cose_key(tvb, pinfo, tree_ctr, &offset);
1027
0
    return offset;
1028
0
}
1029
1030
0
static int dissect_header_ephem_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1031
0
    int offset = 0;
1032
0
    proto_item *item_ctr = proto_tree_add_item(tree, hf_hdr_ephem_key, tvb, 0, -1, ENC_NA);
1033
0
    proto_tree *tree_ctr = proto_item_add_subtree(item_ctr, ett_hdr_ephem_key);
1034
0
    dissect_value_cose_key(tvb, pinfo, tree_ctr, &offset);
1035
0
    return offset;
1036
0
}
1037
1038
112
static int dissect_header_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1039
112
    int offset = 0;
1040
112
    dissect_value_alg(tvb, pinfo, tree, &offset);
1041
112
    return offset;
1042
112
}
1043
1044
0
static int dissect_header_crit(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1045
0
    int offset = 0;
1046
1047
0
    wscbor_chunk_t *chunk_list = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1048
0
    wscbor_require_array(chunk_list);
1049
0
    proto_item *item_list = proto_tree_add_cbor_container(tree, hf_hdr_crit_list, pinfo, tvb, chunk_list);
1050
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_list)) {
1051
0
        proto_tree *tree_list = proto_item_add_subtree(item_list, ett_hdr_crit_list);
1052
1053
0
        for (uint64_t ix = 0; ix < chunk_list->head_value; ++ix) {
1054
0
            wscbor_chunk_t *chunk_label = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1055
0
            switch (chunk_label->type_major) {
1056
0
                case CBOR_TYPE_UINT:
1057
0
                case CBOR_TYPE_NEGINT: {
1058
0
                    int64_t *label = wscbor_require_int64(pinfo->pool, chunk_label);
1059
0
                    proto_tree_add_cbor_int64(tree_list, hf_hdr_label_int, pinfo, tvb, chunk_label, label);
1060
0
                    break;
1061
0
                }
1062
0
                case CBOR_TYPE_STRING: {
1063
0
                    proto_tree_add_cbor_tstr(tree_list, hf_hdr_label_tstr, pinfo, tvb, chunk_label);
1064
0
                    break;
1065
0
                }
1066
0
                default:
1067
0
                    break;
1068
0
            }
1069
0
        }
1070
0
    }
1071
1072
0
    proto_item_set_len(item_list, offset);
1073
0
    return offset;
1074
0
}
1075
1076
0
static int dissect_header_ctype(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1077
0
    int offset = 0;
1078
1079
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1080
0
    switch (chunk->type_major) {
1081
0
        case CBOR_TYPE_UINT: {
1082
0
            uint64_t *val = wscbor_require_uint64(pinfo->pool, chunk);
1083
0
            proto_tree_add_cbor_uint64(tree, hf_hdr_ctype_uint, pinfo, tvb, chunk, val);
1084
0
            break;
1085
0
        }
1086
0
        case CBOR_TYPE_STRING: {
1087
0
            proto_tree_add_cbor_tstr(tree, hf_hdr_ctype_tstr, pinfo, tvb, chunk);
1088
0
            break;
1089
0
        }
1090
0
        default:
1091
0
            break;
1092
0
    }
1093
1094
0
    return offset;
1095
0
}
1096
1097
359
static int dissect_header_kid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1098
359
    int offset = 0;
1099
1100
359
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1101
359
    tvbuff_t *val = wscbor_require_bstr(pinfo->pool, chunk);
1102
359
    proto_item *item_kid = proto_tree_add_cbor_bstr(tree, hf_hdr_kid, pinfo, tvb, chunk);
1103
1104
359
    if (val && tvb_utf_8_isprint_remaining(val, 0)) {
1105
10
        proto_tree *tree_kid = proto_item_add_subtree(item_kid, ett_hdr_kid);
1106
10
        proto_item *kid_text = proto_tree_add_item(tree_kid, hf_hdr_kid_text, val, 0, tvb_reported_length(val), ENC_UTF_8);
1107
10
        proto_item_set_generated(kid_text);
1108
10
    }
1109
1110
359
    return offset;
1111
359
}
1112
1113
0
static int dissect_header_iv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1114
0
    int offset = 0;
1115
1116
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1117
0
    wscbor_require_bstr(pinfo->pool, chunk);
1118
0
    proto_tree_add_cbor_bstr(tree, hf_hdr_iv, pinfo, tvb, chunk);
1119
1120
0
    return offset;
1121
0
}
1122
1123
0
static int dissect_header_piv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1124
0
    int offset = 0;
1125
1126
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1127
0
    wscbor_require_bstr(pinfo->pool, chunk);
1128
0
    proto_tree_add_cbor_bstr(tree, hf_hdr_piv, pinfo, tvb, chunk);
1129
1130
0
    return offset;
1131
0
}
1132
1133
0
static void dissect_value_x5cert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset) {
1134
0
    wscbor_chunk_t *chunk_item = wscbor_chunk_read(pinfo->pool, tvb, offset);
1135
0
    tvbuff_t *tvb_item = wscbor_require_bstr(pinfo->pool, chunk_item);
1136
1137
0
    if (tvb_item) {
1138
        // disallow column text rewrite
1139
0
        char *info_text = wmem_strdup(pinfo->pool, col_get_text(pinfo->cinfo, COL_INFO));
1140
1141
0
        TRY {
1142
0
            dissector_try_string_with_data(
1143
0
                table_media,
1144
0
                "application/pkix-cert",
1145
0
                tvb_item,
1146
0
                pinfo,
1147
0
                tree,
1148
0
                true,
1149
0
                NULL
1150
0
            );
1151
0
        }
1152
0
        CATCH_ALL {}
1153
0
        ENDTRY;
1154
1155
0
        col_add_str(pinfo->cinfo, COL_INFO, info_text);
1156
0
    }
1157
1158
0
}
1159
0
static void dissect_value_cosex509(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int hfindex, int *offset) {
1160
0
    proto_item *item_ctr = proto_tree_add_item(tree, hfindex, tvb, 0, -1, ENC_NA);
1161
0
    proto_tree *tree_ctr = proto_item_add_subtree(item_ctr, ett_hdr_x5cert_list);
1162
1163
0
    wscbor_chunk_t *chunk_ctr = wscbor_chunk_read(pinfo->pool, tvb, offset);
1164
0
    switch (chunk_ctr->type_major) {
1165
0
        case CBOR_TYPE_ARRAY: {
1166
0
            wscbor_require_array(chunk_ctr);
1167
0
            if (!wscbor_skip_if_errors(pinfo->pool, tvb, offset, chunk_ctr)) {
1168
0
                for (uint64_t ix = 0; ix < chunk_ctr->head_value; ++ix) {
1169
0
                    dissect_value_x5cert(tvb, pinfo, tree_ctr, offset);
1170
0
                }
1171
0
            }
1172
0
            break;
1173
0
        }
1174
0
        case CBOR_TYPE_BYTESTRING: {
1175
            // re-read this chunk as cert
1176
0
            *offset = chunk_ctr->start;
1177
0
            dissect_value_x5cert(tvb, pinfo, tree_ctr, offset);
1178
0
            break;
1179
0
        }
1180
0
        default:
1181
0
            break;
1182
0
    }
1183
1184
0
}
1185
0
static int dissect_header_x5bag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1186
0
    int offset = 0;
1187
0
    dissect_value_cosex509(tvb, pinfo, tree, hf_hdr_x5bag, &offset);
1188
0
    return offset;
1189
0
}
1190
0
static int dissect_header_x5chain(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1191
0
    int offset = 0;
1192
0
    dissect_value_cosex509(tvb, pinfo, tree, hf_hdr_x5chain, &offset);
1193
0
    return offset;
1194
0
}
1195
1196
0
static int dissect_header_x5t(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1197
0
    int offset = 0;
1198
1199
0
    wscbor_chunk_t *chunk_list = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1200
0
    wscbor_require_array_size(chunk_list, 2, 2);
1201
0
    proto_item *item_list = proto_tree_add_cbor_container(tree, hf_hdr_x5t, pinfo, tvb, chunk_list);
1202
0
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_list)) {
1203
0
        proto_tree *tree_list = proto_item_add_subtree(item_list, ett_hdr_x5t_list);
1204
1205
0
        dissect_value_alg(tvb, pinfo, tree_list, &offset);
1206
1207
0
        wscbor_chunk_t *chunk_hash = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1208
0
        wscbor_require_bstr(pinfo->pool, chunk_hash);
1209
0
        proto_tree_add_cbor_bstr(tree_list, hf_hdr_x5t_hash, pinfo, tvb, chunk_hash);
1210
1211
0
    }
1212
1213
0
    return offset;
1214
0
}
1215
1216
0
static int dissect_header_x5u(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1217
0
    int offset = 0;
1218
1219
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1220
0
    wscbor_require_major_type(chunk, CBOR_TYPE_STRING);
1221
0
    proto_tree_add_cbor_tstr(tree, hf_hdr_x5u, pinfo, tvb, chunk);
1222
1223
0
    return offset;
1224
0
}
1225
1226
134
static int dissect_cose_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1227
134
    int offset = 0;
1228
1229
134
    proto_item *item_key = proto_tree_add_item(tree, proto_cose, tvb, 0, -1, ENC_NA);
1230
134
    proto_item_append_text(item_key, ": COSE_Key");
1231
134
    proto_tree *tree_key = proto_item_add_subtree(item_key, ett_key);
1232
1233
134
    dissect_value_cose_key(tvb, pinfo, tree_key, &offset);
1234
1235
134
    return offset;
1236
134
}
1237
1238
24
static int dissect_cose_key_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1239
24
    int offset = 0;
1240
1241
24
    wscbor_chunk_t *chunk_set = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1242
24
    wscbor_require_array(chunk_set);
1243
24
    proto_item *item_set = proto_tree_add_cbor_container(tree, proto_cose, pinfo, tvb, chunk_set);
1244
24
    proto_item_append_text(item_set, ": COSE_KeySet");
1245
24
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_set)) {
1246
24
        proto_tree *tree_set = proto_item_add_subtree(item_set, ett_key_set);
1247
1248
5.33k
        for (uint64_t ix = 0; ix < chunk_set->head_value; ++ix) {
1249
5.30k
            proto_item *item_key = proto_tree_add_item(tree_set, hf_key, tvb, offset, -1, ENC_NA);
1250
5.30k
            proto_tree *tree_key = proto_item_add_subtree(item_key, ett_key);
1251
1252
5.30k
            const int offset_key = offset;
1253
5.30k
            dissect_value_cose_key(tvb, pinfo, tree_key, &offset);
1254
5.30k
            proto_item_set_len(item_key, offset - offset_key);
1255
5.30k
        }
1256
24
    }
1257
1258
24
    proto_item_set_len(item_set, offset);
1259
24
    return offset;
1260
24
}
1261
1262
380
static int dissect_keyparam_kty(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1263
380
    int offset = 0;
1264
1265
380
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1266
380
    switch (chunk->type_major) {
1267
247
        case CBOR_TYPE_UINT:
1268
321
        case CBOR_TYPE_NEGINT: {
1269
321
            int64_t *val = wscbor_require_int64(pinfo->pool, chunk);
1270
321
            proto_tree_add_cbor_int64(tree, hf_keyparam_kty_int, pinfo, tvb, chunk, val);
1271
321
            break;
1272
247
        }
1273
32
        case CBOR_TYPE_STRING: {
1274
32
            proto_tree_add_cbor_tstr(tree, hf_keyparam_kty_tstr, pinfo, tvb, chunk);
1275
32
            break;
1276
247
        }
1277
27
        default:
1278
27
            break;
1279
380
    }
1280
1281
380
    return offset;
1282
380
}
1283
1284
80
static int dissect_keyparam_keyops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1285
80
    int offset = 0;
1286
1287
80
    wscbor_chunk_t *chunk_list = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1288
80
    wscbor_require_array(chunk_list);
1289
80
    proto_item *item_list = proto_tree_add_cbor_container(tree, hf_keyparam_keyops_list, pinfo, tvb, chunk_list);
1290
80
    if (!wscbor_skip_if_errors(pinfo->pool, tvb, &offset, chunk_list)) {
1291
0
        proto_tree *tree_list = proto_item_add_subtree(item_list, ett_keyops_list);
1292
1293
0
        for (uint64_t ix = 0; ix < chunk_list->head_value; ++ix) {
1294
0
            wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1295
0
            switch (chunk->type_major) {
1296
0
                case CBOR_TYPE_UINT:
1297
0
                case CBOR_TYPE_NEGINT: {
1298
0
                    int64_t *val = wscbor_require_int64(pinfo->pool, chunk);
1299
0
                    proto_tree_add_cbor_int64(tree_list, hf_keyparam_keyops_int, pinfo, tvb, chunk, val);
1300
0
                    break;
1301
0
                }
1302
0
                case CBOR_TYPE_STRING: {
1303
0
                    proto_tree_add_cbor_tstr(tree_list, hf_keyparam_keyops_tstr, pinfo, tvb, chunk);
1304
0
                    break;
1305
0
                }
1306
0
                default:
1307
0
                    break;
1308
0
            }
1309
0
        }
1310
0
    }
1311
80
    proto_item_set_len(item_list, offset - chunk_list->start);
1312
1313
80
    return offset;
1314
80
}
1315
1316
114
static int dissect_keyparam_baseiv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1317
114
    int offset = 0;
1318
1319
114
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1320
114
    wscbor_require_bstr(pinfo->pool, chunk);
1321
114
    proto_tree_add_cbor_bstr(tree, hf_keyparam_baseiv, pinfo, tvb, chunk);
1322
1323
114
    return offset;
1324
114
}
1325
1326
210
static int dissect_keyparam_crv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1327
210
    int offset = 0;
1328
1329
210
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1330
210
    switch (chunk->type_major) {
1331
34
        case CBOR_TYPE_UINT:
1332
189
        case CBOR_TYPE_NEGINT: {
1333
189
            int64_t *val = wscbor_require_int64(pinfo->pool, chunk);
1334
189
            proto_tree_add_cbor_int64(tree, hf_keyparam_crv_int, pinfo, tvb, chunk, val);
1335
189
            break;
1336
34
        }
1337
1
        case CBOR_TYPE_STRING: {
1338
1
            proto_tree_add_cbor_tstr(tree, hf_keyparam_crv_tstr, pinfo, tvb, chunk);
1339
1
            break;
1340
34
        }
1341
20
        default:
1342
20
            break;
1343
210
    }
1344
1345
210
    return offset;
1346
210
}
1347
1348
5
static int dissect_keyparam_xcoord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1349
5
    int offset = 0;
1350
1351
5
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1352
5
    wscbor_require_bstr(pinfo->pool, chunk);
1353
5
    proto_tree_add_cbor_bstr(tree, hf_keyparam_xcoord, pinfo, tvb, chunk);
1354
1355
5
    return offset;
1356
5
}
1357
1358
45
static int dissect_keyparam_ycoord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1359
45
    int offset = 0;
1360
1361
45
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1362
45
    switch (chunk->type_major) {
1363
1
        case CBOR_TYPE_FLOAT_CTRL: {
1364
1
            proto_tree_add_item(tree, hf_keyparam_ycoord, tvb, 0, 0, ENC_NA);
1365
1
            break;
1366
0
        }
1367
0
        case CBOR_TYPE_BYTESTRING: {
1368
0
            proto_tree_add_cbor_bstr(tree, hf_keyparam_ycoord, pinfo, tvb, chunk);
1369
0
            break;
1370
0
        }
1371
44
        default:
1372
44
            break;
1373
45
    }
1374
1375
45
    return offset;
1376
45
}
1377
1378
24
static int dissect_keyparam_dcoord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1379
24
    int offset = 0;
1380
1381
24
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1382
24
    wscbor_require_bstr(pinfo->pool, chunk);
1383
24
    proto_tree_add_cbor_bstr(tree, hf_keyparam_dcoord, pinfo, tvb, chunk);
1384
1385
24
    return offset;
1386
24
}
1387
1388
39
static int dissect_keyparam_k(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1389
39
    int offset = 0;
1390
1391
39
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1392
39
    wscbor_require_bstr(pinfo->pool, chunk);
1393
39
    proto_tree_add_cbor_bstr(tree, hf_keyparam_k, pinfo, tvb, chunk);
1394
1395
39
    return offset;
1396
39
}
1397
1398
0
static int dissect_keyparam_pub(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1399
0
    int offset = 0;
1400
1401
0
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1402
0
    wscbor_require_bstr(pinfo->pool, chunk);
1403
0
    proto_tree_add_cbor_bstr(tree, hf_keyparam_pub, pinfo, tvb, chunk);
1404
1405
0
    return offset;
1406
0
}
1407
1408
2
static int dissect_keyparam_priv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
1409
2
    int offset = 0;
1410
1411
2
    wscbor_chunk_t *chunk = wscbor_chunk_read(pinfo->pool, tvb, &offset);
1412
2
    wscbor_require_bstr(pinfo->pool, chunk);
1413
2
    proto_tree_add_cbor_bstr(tree, hf_keyparam_priv, pinfo, tvb, chunk);
1414
1415
2
    return offset;
1416
2
}
1417
1418
/** Register a message dissector.
1419
 */
1420
96
static void register_msg_dissector(dissector_handle_t dis_h, uint64_t tag_int, const char *media_subtype) {
1421
96
    uint64_t *key_int = g_new(uint64_t, 1);
1422
96
    *key_int = tag_int;
1423
96
    dissector_add_custom_table_handle("cose.msgtag", key_int, dis_h);
1424
1425
96
    dissector_add_string("cose.mediasub", media_subtype, dis_h);
1426
96
}
1427
1428
/** Register a header dissector.
1429
 * @param dissector The dissector function.
1430
 * @param label The associated map label.
1431
 * @param name The header name.
1432
 */
1433
272
static void register_header_dissector(dissector_t dissector, GVariant *label, const char *name) {
1434
272
    dissector_handle_t dis_h = create_dissector_handle_with_name_and_description(dissector, proto_cose_params, NULL, name);
1435
1436
272
    cose_param_key_t *key = g_new0(cose_param_key_t, 1);
1437
272
    key->label = label;
1438
1439
272
    dissector_add_custom_table_handle("cose.header", key, dis_h);
1440
272
}
1441
1442
/** Register a key parameter dissector.
1443
 * @param dissector The dissector function.
1444
 * @param kty The associated key type "kty" or NULL.
1445
 * @param label The associated map label.
1446
 * @param name The header name.
1447
 */
1448
256
static void register_keyparam_dissector(dissector_t dissector, GVariant *kty, GVariant *label, const char *name) {
1449
256
    dissector_handle_t dis_h = create_dissector_handle_with_name_and_description(dissector, proto_cose_params, NULL, name);
1450
1451
256
    cose_param_key_t *key = g_new0(cose_param_key_t, 1);
1452
256
    if (kty) {
1453
176
        g_variant_ref(kty);
1454
176
        key->principal = kty;
1455
176
    }
1456
256
    key->label = label;
1457
1458
256
    dissector_add_custom_table_handle("cose.keyparam", key, dis_h);
1459
256
}
1460
1461
/// Shutdown global stores
1462
0
static void cose_shutdown(void) {
1463
0
    g_hash_table_unref(cose_hash_props_map);
1464
0
    cose_hash_props_map = NULL;
1465
0
    g_hash_table_unref(cose_aead_props_map);
1466
0
    cose_aead_props_map = NULL;
1467
0
    g_hash_table_unref(cose_ecc_props_map);
1468
0
    cose_ecc_props_map = NULL;
1469
0
}
1470
1471
/// Re-initialize after a configuration change
1472
16
static void cose_reinit(void) {
1473
16
}
1474
1475
/// Overall registration of the protocol
1476
16
void proto_register_cose(void) {
1477
    // Global scope data
1478
16
    register_shutdown_routine(&cose_shutdown);
1479
16
    cose_hash_props_map = g_hash_table_new(g_int64_hash, g_int64_equal);
1480
16
    for (const cose_hash_props_t *item = cose_hash_props_list;
1481
144
            item < cose_hash_props_list + array_length(cose_hash_props_list); ++item) {
1482
128
        g_hash_table_insert(cose_hash_props_map, (void *)&(item->value), (void *)item);
1483
128
    }
1484
16
    cose_aead_props_map = g_hash_table_new(g_int64_hash, g_int64_equal);
1485
16
    for (const cose_aead_props_t *item = cose_aead_props_list;
1486
208
            item < cose_aead_props_list + array_length(cose_aead_props_list); ++item) {
1487
192
        g_hash_table_insert(cose_aead_props_map, (void *)&(item->value), (void *)item);
1488
192
    }
1489
16
    cose_ecc_props_map = g_hash_table_new(g_int64_hash, g_int64_equal);
1490
16
    for (const cose_ecc_props_t *item = cose_ecc_props_list;
1491
144
            item < cose_ecc_props_list + array_length(cose_ecc_props_list); ++item) {
1492
128
        g_hash_table_insert(cose_ecc_props_map, (void *)&(item->value), (void *)item);
1493
128
    }
1494
1495
16
    proto_cose = proto_register_protocol("CBOR Object Signing and Encryption", proto_name_cose, "cose");
1496
16
    proto_cose_params = proto_register_protocol_in_name_only(
1497
16
        "COSE Parameter Subdissectors",
1498
16
        "COSE Parameter Subdissectors",
1499
16
        "cose_params",
1500
16
        proto_cose,
1501
16
        FT_PROTOCOL
1502
16
    );
1503
1504
16
    proto_register_field_array(proto_cose, fields, array_length(fields));
1505
16
    proto_register_subtree_array(ett, array_length(ett));
1506
16
    expert_module_t *expert = expert_register_protocol(proto_cose);
1507
16
    expert_register_field_array(expert, expertitems, array_length(expertitems));
1508
1509
16
    handle_cose_msg_hdr = register_dissector("cose.msg.headers", dissect_cose_msg_header_map, proto_cose);
1510
1511
16
    table_cose_msg_tag = register_custom_dissector_table("cose.msgtag", "COSE Message Tag", proto_cose, g_int64_hash, g_int64_equal, g_free);
1512
16
    table_cose_media_subtype = register_dissector_table("cose.mediasub", "COSE Media Subtype", proto_cose, FT_STRINGZ, STRING_CASE_INSENSITIVE);
1513
1514
16
    handle_cose_msg_tagged = register_dissector("cose", dissect_cose_msg_tagged, proto_cose_params);
1515
16
    handle_cose_media_type = create_dissector_handle_with_name(dissect_cose_media_type, proto_cose, "cose");
1516
1517
    // RFC 9052 data item names (Table 1)
1518
16
    handle_cose_sign = register_dissector_with_description("cose_sign", "COSE_Sign", dissect_cose_sign, proto_cose);
1519
16
    handle_cose_sign1 = register_dissector_with_description("cose_sign1", "COSE_Sign1", dissect_cose_sign1, proto_cose);
1520
16
    handle_cose_encrypt = register_dissector_with_description("cose_encrypt", "COSE_Encrypt", dissect_cose_encrypt, proto_cose);
1521
16
    handle_cose_encrypt0 = register_dissector_with_description("cose_encrypt0", "COSE_Encrypt0", dissect_cose_encrypt0, proto_cose);
1522
16
    handle_cose_mac = register_dissector_with_description("cose_mac", "COSE_Mac", dissect_cose_mac, proto_cose);
1523
16
    handle_cose_mac0 = register_dissector_with_description("cose_mac0", "COSE_Mac0", dissect_cose_mac0, proto_cose);
1524
1525
16
    table_header = register_custom_dissector_table("cose.header", "COSE Header Parameter", proto_cose, cose_param_key_hash, cose_param_key_equal, cose_param_key_free);
1526
1527
    // RFC 9052 data item names (Section 11.3.2)
1528
16
    handle_cose_key = register_dissector_with_description("cose_key", "COSE_Key", dissect_cose_key, proto_cose);
1529
16
    handle_cose_key_set = register_dissector_with_description("cose_key_set", "COSE_KeySet", dissect_cose_key_set, proto_cose);
1530
1531
16
    table_keyparam = register_custom_dissector_table("cose.keyparam", "COSE Key Parameter", proto_cose, cose_param_key_hash, cose_param_key_equal, cose_param_key_free);
1532
1533
16
    module_t *module_cose = prefs_register_protocol(proto_cose, cose_reinit);
1534
16
    (void)module_cose;
1535
16
}
1536
1537
16
void proto_reg_handoff_cose(void) {
1538
16
    table_media = find_dissector_table("media_type");
1539
16
    handle_cbor = find_dissector("cbor");
1540
1541
16
    dissector_add_string("media_type", "application/cose", handle_cose_media_type);
1542
16
    dissector_add_string("media_type.suffix", "cose", handle_cose_media_type);
1543
1544
    // RFC 9052 tags and media type "cose-type" names (Table 1)
1545
16
    register_msg_dissector(handle_cose_sign, 98, "cose-sign");
1546
16
    register_msg_dissector(handle_cose_sign1, 18, "cose-sign1");
1547
16
    register_msg_dissector(handle_cose_encrypt, 96, "cose-encrypt");
1548
16
    register_msg_dissector(handle_cose_encrypt0, 16, "cose-encrypt0");
1549
16
    register_msg_dissector(handle_cose_mac, 97, "cose-mac");
1550
16
    register_msg_dissector(handle_cose_mac0, 17, "cose-mac0");
1551
1552
    // RFC 9053 header labels
1553
16
    register_header_dissector(dissect_header_salt, g_variant_new_int64(-20), "salt");
1554
16
    register_header_dissector(dissect_header_kid, g_variant_new_int64(-3), "static kid");
1555
16
    register_header_dissector(dissect_header_static_key, g_variant_new_int64(-2), "static key");
1556
16
    register_header_dissector(dissect_header_ephem_key, g_variant_new_int64(-1), "ephemeral key");
1557
16
    register_header_dissector(dissect_header_alg, g_variant_new_int64(1), "alg");
1558
16
    register_header_dissector(dissect_header_crit, g_variant_new_int64(2), "crit");
1559
16
    register_header_dissector(dissect_header_ctype, g_variant_new_int64(3), "content type");
1560
16
    register_header_dissector(dissect_header_kid, g_variant_new_int64(4), "kid");
1561
16
    register_header_dissector(dissect_header_iv, g_variant_new_int64(5), "IV");
1562
16
    register_header_dissector(dissect_header_piv, g_variant_new_int64(6), "Partial IV");
1563
    // RFC 9360 header labels
1564
16
    register_header_dissector(dissect_header_x5chain, g_variant_new_int64(-29), "x5chain-sender");
1565
16
    register_header_dissector(dissect_header_x5u, g_variant_new_int64(-28), "x5u-sender");
1566
16
    register_header_dissector(dissect_header_x5t, g_variant_new_int64(-27), "x5t-sender");
1567
16
    register_header_dissector(dissect_header_x5bag, g_variant_new_int64(32), "x5bag");
1568
16
    register_header_dissector(dissect_header_x5chain, g_variant_new_int64(33), "x5chain");
1569
16
    register_header_dissector(dissect_header_x5t, g_variant_new_int64(34), "x5t");
1570
16
    register_header_dissector(dissect_header_x5u, g_variant_new_int64(35), "x5u");
1571
1572
16
    dissector_add_string("media_type", "application/cose-key", handle_cose_key);
1573
16
    dissector_add_string("media_type", "application/cose-key-set", handle_cose_key_set);
1574
    // RFC 9052 key parameter labels
1575
16
    register_keyparam_dissector(dissect_keyparam_kty, NULL, g_variant_new_int64(1), "kty");
1576
16
    register_keyparam_dissector(dissect_header_kid, NULL, g_variant_new_int64(2), "kid");
1577
16
    register_keyparam_dissector(dissect_header_alg, NULL, g_variant_new_int64(3), "alg");
1578
16
    register_keyparam_dissector(dissect_keyparam_keyops, NULL, g_variant_new_int64(4), "key_ops");
1579
16
    register_keyparam_dissector(dissect_keyparam_baseiv, NULL, g_variant_new_int64(5), "Base IV");
1580
    // kty-specific parameters
1581
16
    {
1582
16
        GVariant *kty = g_variant_new_int64(1);
1583
16
        register_keyparam_dissector(dissect_keyparam_crv, kty, g_variant_new_int64(-1), "crv");
1584
16
        register_keyparam_dissector(dissect_keyparam_xcoord, kty, g_variant_new_int64(-2), "x");
1585
16
        register_keyparam_dissector(dissect_keyparam_dcoord, kty, g_variant_new_int64(-3), "d");
1586
16
        g_variant_unref(kty);
1587
16
    }
1588
16
    {
1589
16
        GVariant *kty = g_variant_new_int64(2);
1590
16
        register_keyparam_dissector(dissect_keyparam_crv, kty, g_variant_new_int64(-1), "crv");
1591
16
        register_keyparam_dissector(dissect_keyparam_xcoord, kty, g_variant_new_int64(-2), "x");
1592
16
        register_keyparam_dissector(dissect_keyparam_ycoord, kty, g_variant_new_int64(-3), "y");
1593
16
        register_keyparam_dissector(dissect_keyparam_dcoord, kty, g_variant_new_int64(-4), "d");
1594
16
        g_variant_unref(kty);
1595
16
    }
1596
16
    {
1597
16
        GVariant *kty = g_variant_new_int64(4);
1598
16
        register_keyparam_dissector(dissect_keyparam_k, kty, g_variant_new_int64(-1), "k");
1599
16
        g_variant_unref(kty);
1600
16
    }
1601
16
    {
1602
16
        GVariant *kty = g_variant_new_int64(5);
1603
16
        register_keyparam_dissector(dissect_keyparam_pub, kty, g_variant_new_int64(-1), "pub");
1604
16
        g_variant_unref(kty);
1605
16
    }
1606
16
    {
1607
16
        GVariant *kty = g_variant_new_int64(7);
1608
16
        register_keyparam_dissector(dissect_keyparam_pub, kty, g_variant_new_int64(-1), "pub");
1609
16
        register_keyparam_dissector(dissect_keyparam_priv, kty, g_variant_new_int64(-2), "priv");
1610
16
        g_variant_unref(kty);
1611
16
    }
1612
1613
16
    cose_reinit();
1614
16
}