Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-oscore.c
blobd6bb09c790c32c1eb0ca84d64557a085556df280
1 /* packet-oscore.c
2 * Routines for Object Security for Constrained RESTful Environments dissection
3 * Copyright 2017, Malisa Vucinic <malishav@gmail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * rfc8613
16 #include <config.h>
18 #include <epan/packet.h> /* Should be first Wireshark include (other than config.h) */
19 #include <epan/proto_data.h>
20 #include <epan/expert.h> /* Include only as needed */
21 #include <epan/uat.h>
22 #include <epan/strutil.h>
23 #include <epan/prefs.h> /* Include only as needed */
24 #include <epan/to_str.h>
26 #include <wsutil/wsgcrypt.h>
27 #include "packet-ieee802154.h" /* We use CCM implementation available as part of 802.15.4 dissector */
28 #include "packet-coap.h" /* packet-coap.h includes packet-oscore.h */
30 /* Prototypes */
31 static unsigned oscore_alg_get_key_len(cose_aead_alg_t);
32 static unsigned oscore_alg_get_iv_len(cose_aead_alg_t);
33 static unsigned oscore_alg_get_tag_len(cose_aead_alg_t);
34 static bool oscore_context_derive_params(oscore_context_t *);
36 /* CBOR encoder prototypes */
37 static uint8_t cborencoder_put_text(uint8_t *buffer, const char *text, uint8_t text_len);
38 static uint8_t cborencoder_put_null(uint8_t *buffer);
39 static uint8_t cborencoder_put_unsigned(uint8_t *buffer, uint8_t value);
40 static uint8_t cborencoder_put_bytes(uint8_t *buffer, const uint8_t *bytes, uint8_t bytes_len);
41 static uint8_t cborencoder_put_array(uint8_t *buffer, uint8_t elements);
43 /* (Required to prevent [-Wmissing-prototypes] warnings */
44 void proto_reg_handoff_oscore(void);
45 void proto_register_oscore(void);
47 /* Initialize the protocol and registered fields */
48 static int proto_oscore;
49 static int proto_coap;
51 static int hf_oscore_tag;
53 static COAP_COMMON_LIST_T(dissect_oscore_hf);
55 static expert_field ei_oscore_partial_iv_not_found;
56 static expert_field ei_oscore_context_not_set;
57 static expert_field ei_oscore_message_too_small;
58 static expert_field ei_oscore_truncated;
59 static expert_field ei_oscore_tag_check_failed;
60 static expert_field ei_oscore_decrypt_error;
61 static expert_field ei_oscore_cbc_mac_failed;
62 static expert_field ei_oscore_piv_len_invalid;
63 static expert_field ei_oscore_info_fetch_failed;
65 /* Initialize the subtree pointers */
66 static int ett_oscore;
68 /* UAT variables */
69 static uat_t *oscore_context_uat;
70 static oscore_context_t *oscore_contexts;
71 static unsigned num_oscore_contexts;
73 /* Enumeration for COSE algorithms used by OSCORE */
74 static const value_string oscore_context_alg_vals[] = {
75 { COSE_AES_CCM_16_64_128, "AES-CCM-16-64-128 (CCM*)"},
76 { 0, NULL }
79 /* Field callbacks. */
80 UAT_CSTRING_CB_DEF(oscore_context_uat, master_secret_prefs, oscore_context_t)
81 UAT_CSTRING_CB_DEF(oscore_context_uat, master_salt_prefs, oscore_context_t)
82 UAT_CSTRING_CB_DEF(oscore_context_uat, id_context_prefs, oscore_context_t)
83 UAT_CSTRING_CB_DEF(oscore_context_uat, sender_id_prefs, oscore_context_t)
84 UAT_CSTRING_CB_DEF(oscore_context_uat, recipient_id_prefs, oscore_context_t)
85 UAT_VS_DEF(oscore_context_uat, algorithm, oscore_context_t, cose_aead_alg_t, COSE_AES_CCM_16_64_128, "AES-CCM-16-64-128 (CCM*)")
87 #define OSCORE_MIN_LENGTH 9 /* 1 byte for code plus 8 bytes for shortest authentication tag */
88 #define OSCORE_VERSION 1 /* rfc8613 */
89 #define TAG_MAX_LEN 16
90 #define AES_128_BLOCK_LEN 16
91 #define NONCE_MAX_LEN 13 /* longest nonce in RFC8152 is 13 bytes */
93 #define OSCORE_PIV_MAX_LEN 5 /* upper bound specified in the draft */
94 #define OSCORE_KID_MAX_LEN_CCM_STAR 7 /* upper bound on KID for AES-CCM-16-64-128 (CCM*) */
95 #define OSCORE_KID_MAX_LEN OSCORE_KID_MAX_LEN_CCM_STAR /* upper bound on KID coming from the default algorithm implemented */
96 #define OSCORE_KID_CONTEXT_MAX_LEN 64
98 /* Helper macros to correctly size the statically allocated buffers and verify if an overflow occurred */
100 #define OSCORE_INFO_MAX_LEN (1 + /* max return of cborencoder_put_array() */ \
101 2 + OSCORE_KID_MAX_LEN + /* max 2 to encode length, KID following */ \
102 2 + OSCORE_KID_CONTEXT_MAX_LEN + /* length + KID CONTEXT */ \
103 2 + /* max return of cborencoder_put_unsigned() */ \
104 2 + 3 + /* max 2 to encode length, "Key" following */ \
105 2 /* max return of cborencoder_put_unsigned() */ )
107 #define OSCORE_EXTERNAL_AAD_MAX_LEN (1 + /* max return of cborencoder_put_array() */ \
108 2 + /* max return of cborencoder_put_unsigned() */ \
109 1 + /* max return of cborencoder_put_array() */ \
110 2 + /* max return of cborencoder_put_unsigned() */ \
111 2 + OSCORE_KID_MAX_LEN + /* max 2 to encode length, KID following */ \
112 2 + OSCORE_PIV_MAX_LEN + /* max 2 to encode length, PIV following */ \
113 1 + 0 /* 1 to encode length, 0 bytes following */ )
115 #define OSCORE_AAD_MAX_LEN (1 + /* max return of cborencoder_put_array() */ \
116 2 + 8 +/* max 2 to encode length, "Encrypt0" following */ \
117 1 + 0 + /* 1 to encode length, 0 bytes following */ \
118 2 + OSCORE_EXTERNAL_AAD_MAX_LEN /* max 2 to encode length, external_aad following */ )
120 static void oscore_context_free_byte_arrays(oscore_context_t *rec) {
122 if (rec->master_secret) {
123 g_byte_array_free(rec->master_secret, true);
126 if (rec->master_salt) {
127 g_byte_array_free(rec->master_salt, true);
130 if (rec->id_context) {
131 g_byte_array_free(rec->id_context, true);
134 if (rec->sender_id) {
135 g_byte_array_free(rec->sender_id, true);
138 if (rec->recipient_id) {
139 g_byte_array_free(rec->recipient_id, true);
142 if (rec->request_decryption_key) {
143 g_byte_array_free(rec->request_decryption_key, true);
146 if (rec->response_decryption_key) {
147 g_byte_array_free(rec->response_decryption_key, true);
150 if (rec->common_iv) {
151 g_byte_array_free(rec->common_iv, true);
155 static void oscore_context_post_update_cb(void) {
156 unsigned i;
157 unsigned key_len;
158 unsigned iv_len;
160 for (i = 0; i < num_oscore_contexts; i++) {
162 /* Make sure to free the memory if it was allocated previously. */
163 oscore_context_free_byte_arrays(&oscore_contexts[i]);
165 oscore_contexts[i].master_secret = g_byte_array_new();
166 oscore_contexts[i].master_salt = g_byte_array_new();
167 oscore_contexts[i].id_context = g_byte_array_new();
168 oscore_contexts[i].sender_id = g_byte_array_new();
169 oscore_contexts[i].recipient_id = g_byte_array_new();
171 /* Convert strings to byte arrays */
172 hex_str_to_bytes(oscore_contexts[i].sender_id_prefs, oscore_contexts[i].sender_id, false);
173 hex_str_to_bytes(oscore_contexts[i].recipient_id_prefs, oscore_contexts[i].recipient_id, false);
174 hex_str_to_bytes(oscore_contexts[i].id_context_prefs, oscore_contexts[i].id_context, false);
175 hex_str_to_bytes(oscore_contexts[i].master_secret_prefs, oscore_contexts[i].master_secret, false);
176 hex_str_to_bytes(oscore_contexts[i].master_salt_prefs, oscore_contexts[i].master_salt, false);
178 /* Algorithm-dependent key and IV length */
179 key_len = oscore_alg_get_key_len(oscore_contexts[i].algorithm);
180 iv_len = oscore_alg_get_iv_len(oscore_contexts[i].algorithm);
182 /* Allocate memory for derived parameters */
183 oscore_contexts[i].request_decryption_key = g_byte_array_sized_new(key_len);
184 oscore_contexts[i].response_decryption_key = g_byte_array_sized_new(key_len);
185 oscore_contexts[i].common_iv = g_byte_array_sized_new(iv_len);
187 oscore_context_derive_params(&oscore_contexts[i]);
191 /* Check user input, do not allocate any memory */
192 static bool oscore_context_update_cb(void *r, char **err) {
193 oscore_context_t *rec = (oscore_context_t *) r;
194 GByteArray *bytes; /* temp array to verify each parameter */
196 bytes = g_byte_array_new();
198 if (hex_str_to_bytes(rec->sender_id_prefs, bytes, false) == false) {
199 *err = g_strdup("Sender ID is invalid.");
200 g_byte_array_free(bytes, true);
201 return false;
204 if (bytes->len > OSCORE_KID_MAX_LEN) {
205 *err = ws_strdup_printf("Should be %u bytes or less.", OSCORE_KID_MAX_LEN);
206 g_byte_array_free(bytes, true);
207 return false;
210 if (hex_str_to_bytes(rec->recipient_id_prefs, bytes, false) == false) {
211 *err = g_strdup("Recipient ID is invalid.");
212 g_byte_array_free(bytes, true);
213 return false;
216 if (bytes->len > OSCORE_KID_MAX_LEN) {
217 *err = ws_strdup_printf("Should be %u bytes or less.", OSCORE_KID_MAX_LEN);
218 g_byte_array_free(bytes, true);
219 return false;
222 if (hex_str_to_bytes(rec->id_context_prefs, bytes, false) == false) {
223 *err = g_strdup("ID Context is invalid.");
224 g_byte_array_free(bytes, true);
225 return false;
228 if (bytes->len > OSCORE_KID_CONTEXT_MAX_LEN) {
229 *err = ws_strdup_printf("Should be %u bytes or less.", OSCORE_KID_CONTEXT_MAX_LEN);
230 g_byte_array_free(bytes, true);
231 return false;
234 if (hex_str_to_bytes(rec->master_secret_prefs, bytes, false) == false) {
235 *err = g_strdup("Master Secret is invalid.");
236 g_byte_array_free(bytes, true);
237 return false;
240 /* No max length check on Master Secret. We use GByteArray to allocate memory
241 * and pass it to the context derivation routine */
242 if (bytes->len == 0) {
243 *err = g_strdup("Master Secret is mandatory.");
244 g_byte_array_free(bytes, true);
245 return false;
248 if (hex_str_to_bytes(rec->master_salt_prefs, bytes, false) == false) {
249 *err = g_strdup("Master Salt is invalid.");
250 g_byte_array_free(bytes, true);
251 return false;
254 /* No (max) length check on optional Master Salt. We use GByteArray to allocate memory
255 * and pass it to the context derivation routine */
257 g_byte_array_free(bytes, true);
258 return true;
261 static void* oscore_context_copy_cb(void *n, const void *o, size_t siz _U_) {
262 oscore_context_t *new_record = (oscore_context_t *) n;
263 const oscore_context_t *old_record = (const oscore_context_t *) o;
265 /* Pre-Shared Parameters */
266 new_record->master_secret_prefs = g_strdup(old_record->master_secret_prefs);
267 new_record->master_salt_prefs = g_strdup(old_record->master_salt_prefs);
268 new_record->id_context_prefs = g_strdup(old_record->id_context_prefs);
269 new_record->sender_id_prefs = g_strdup(old_record->sender_id_prefs);
270 new_record->recipient_id_prefs = g_strdup(old_record->recipient_id_prefs);
271 new_record->algorithm = old_record->algorithm;
273 /* Initialize all to NULL, overwrite as needed */
274 new_record->master_secret = NULL;
275 new_record->master_salt = NULL;
276 new_record->id_context = NULL;
277 new_record->sender_id = NULL;
278 new_record->recipient_id = NULL;
279 new_record->request_decryption_key = NULL;
280 new_record->response_decryption_key = NULL;
281 new_record->common_iv = NULL;
283 /* We rely on oscore_context_post_update_cb() to convert strings to GByteArrays and derive params */
285 return new_record;
288 static void oscore_context_free_cb(void *r) {
289 oscore_context_t *rec = (oscore_context_t *) r;
291 /* User-configured strings */
292 g_free(rec->master_secret_prefs);
293 g_free(rec->master_salt_prefs);
294 g_free(rec->id_context_prefs);
295 g_free(rec->sender_id_prefs);
296 g_free(rec->recipient_id_prefs);
298 /* Allocated byte arrays */
299 oscore_context_free_byte_arrays(rec);
302 /* GByteArrays within the oscore_context_t object should be initialized before calling this function */
303 static bool oscore_context_derive_params(oscore_context_t *context) {
304 const char *iv_label = "IV";
305 const char *key_label = "Key";
306 uint8_t prk[32]; /* Pseudo-random key from HKDF-Extract step. 32 for SHA256. */
307 unsigned key_len;
308 unsigned iv_len;
309 uint8_t info_buf[OSCORE_INFO_MAX_LEN];
310 unsigned info_len;
311 GByteArray *info;
313 key_len = oscore_alg_get_key_len(context->algorithm);
314 iv_len = oscore_alg_get_iv_len(context->algorithm);
316 info = g_byte_array_new();
318 /* Common HKDF-Extract step on master salt */
319 hkdf_extract(GCRY_MD_SHA256, context->master_salt->data, context->master_salt->len, context->master_secret->data, context->master_secret->len, prk);
321 /* Request Decryption Key */
322 info_len = 0;
323 info_len += cborencoder_put_array(&info_buf[info_len], 5);
324 info_len += cborencoder_put_bytes(&info_buf[info_len], context->sender_id->data, context->sender_id->len);
325 if (context->id_context->len) {
326 info_len += cborencoder_put_bytes(&info_buf[info_len], context->id_context->data, context->id_context->len);
327 } else {
328 info_len += cborencoder_put_null(&info_buf[info_len]);
330 info_len += cborencoder_put_unsigned(&info_buf[info_len], context->algorithm);
331 info_len += cborencoder_put_text(&info_buf[info_len], key_label, 3);
332 info_len += cborencoder_put_unsigned(&info_buf[info_len], key_len);
333 /* sender_id->len comes from user input, it is validated by the UAT callback and the max length is accounted for
334 * in OSCORE_INFO_MAX_LEN */
335 DISSECTOR_ASSERT(info_len < OSCORE_INFO_MAX_LEN);
336 g_byte_array_append(info, info_buf, info_len);
337 g_byte_array_set_size(context->request_decryption_key, key_len);
338 hkdf_expand(GCRY_MD_SHA256, prk, sizeof(prk), info->data, info->len, context->request_decryption_key->data, key_len); /* 32 for SHA256 */
342 /* Response Decryption Key */
343 info_len = 0;
344 g_byte_array_set_size(info, 0);
345 info_len += cborencoder_put_array(&info_buf[info_len], 5);
346 info_len += cborencoder_put_bytes(&info_buf[info_len], context->recipient_id->data, context->recipient_id->len);
347 if (context->id_context->len) {
348 info_len += cborencoder_put_bytes(&info_buf[info_len], context->id_context->data, context->id_context->len);
349 } else {
350 info_len += cborencoder_put_null(&info_buf[info_len]);
352 info_len += cborencoder_put_unsigned(&info_buf[info_len], context->algorithm);
353 info_len += cborencoder_put_text(&info_buf[info_len], key_label, 3);
354 info_len += cborencoder_put_unsigned(&info_buf[info_len], key_len);
355 /* recipient_id->len comes from user input, it is validated by the UAT callback and the max length is accounted for
356 * in OSCORE_INFO_MAX_LEN */
357 DISSECTOR_ASSERT(info_len < OSCORE_INFO_MAX_LEN);
358 g_byte_array_append(info, info_buf, info_len);
359 g_byte_array_set_size(context->response_decryption_key, key_len);
360 hkdf_expand(GCRY_MD_SHA256, prk, sizeof(prk), info->data, info->len, context->response_decryption_key->data, key_len); /* 32 for SHA256 */
362 /* Common IV */
363 info_len = 0;
364 g_byte_array_set_size(info, 0);
365 info_len += cborencoder_put_array(&info_buf[info_len], 5);
366 info_len += cborencoder_put_bytes(&info_buf[info_len], NULL, 0);
367 if (context->id_context->len) {
368 info_len += cborencoder_put_bytes(&info_buf[info_len], context->id_context->data, context->id_context->len);
369 } else {
370 info_len += cborencoder_put_null(&info_buf[info_len]);
372 info_len += cborencoder_put_unsigned(&info_buf[info_len], context->algorithm);
373 info_len += cborencoder_put_text(&info_buf[info_len], iv_label, 2);
374 info_len += cborencoder_put_unsigned(&info_buf[info_len], iv_len);
375 /* all static lengths, accounted for in OSCORE_INFO_MAX_LEN */
376 DISSECTOR_ASSERT(info_len < OSCORE_INFO_MAX_LEN);
377 g_byte_array_append(info, info_buf, info_len);
378 g_byte_array_set_size(context->common_iv, iv_len);
379 hkdf_expand(GCRY_MD_SHA256, prk, sizeof(prk), info->data, info->len, context->common_iv->data, iv_len); /* 32 for SHA256 */
381 g_byte_array_free(info, true);
382 return true;
385 static unsigned oscore_alg_get_key_len(cose_aead_alg_t algorithm) {
386 switch(algorithm) {
387 case COSE_AES_CCM_16_64_128:
388 return 16; /* RFC8152 */
389 /* unsupported */
390 default:
391 return 0;
395 static unsigned oscore_alg_get_tag_len(cose_aead_alg_t algorithm) {
396 switch(algorithm) {
397 case COSE_AES_CCM_16_64_128:
398 return 8; /* RFC8152 */
399 /* unsupported */
400 default:
401 return 0;
405 static unsigned oscore_alg_get_iv_len(cose_aead_alg_t algorithm) {
406 switch(algorithm) {
407 case COSE_AES_CCM_16_64_128:
408 return 13; /* RFC8152 */
409 /* unsupported */
410 default:
411 return 0;
415 static oscore_context_t * oscore_find_context(oscore_info_t *info) {
416 unsigned i;
418 for (i = 0; i < num_oscore_contexts; i++) {
419 if ((info->kid_len == oscore_contexts[i].sender_id->len) &&
420 memcmp(oscore_contexts[i].sender_id->data, info->kid, info->kid_len) == 0 &&
421 (info->kid_context_len == oscore_contexts[i].id_context->len) &&
422 memcmp(oscore_contexts[i].id_context->data, info->kid_context, info->kid_context_len) == 0) {
423 return &oscore_contexts[i];
426 return NULL;
430 CBOR encoding functions needed to construct HKDF info and aad.
431 Author Martin Gunnarsson <martin.gunnarsson@ri.se>
432 Modified by Malisa Vucinic <malishav@gmail.com>
434 static uint8_t
435 cborencoder_put_text(uint8_t *buffer, const char *text, uint8_t text_len) {
436 uint8_t ret = 0;
438 if(text_len > 23 ){
439 buffer[ret++] = 0x78;
440 buffer[ret++] = text_len;
441 } else {
442 buffer[ret++] = (0x60 | text_len);
445 if (text_len != 0 && text != NULL) {
446 memcpy(&buffer[ret], text, text_len);
447 ret += text_len;
450 return ret;
453 static uint8_t
454 cborencoder_put_array(uint8_t *buffer, uint8_t elements) {
455 uint8_t ret = 0;
457 if(elements > 15){
458 return 0;
461 buffer[ret++] = (0x80 | elements);
462 return ret;
465 static uint8_t
466 cborencoder_put_bytes(uint8_t *buffer, const uint8_t *bytes, uint8_t bytes_len) {
467 uint8_t ret = 0;
469 if(bytes_len > 23){
470 buffer[ret++] = 0x58;
471 buffer[ret++] = bytes_len;
472 } else {
473 buffer[ret++] = (0x40 | bytes_len);
476 if (bytes_len != 0 && bytes != NULL){
477 memcpy(&buffer[ret], bytes, bytes_len);
478 ret += bytes_len;
481 return ret;
484 static uint8_t
485 cborencoder_put_unsigned(uint8_t *buffer, uint8_t value) {
486 uint8_t ret = 0;
488 if(value > 0x17 ){
489 buffer[ret++] = 0x18;
490 buffer[ret++] = value;
491 return ret;
494 buffer[ret++] = value;
495 return ret;
498 static uint8_t
499 cborencoder_put_null(uint8_t *buffer) {
500 uint8_t ret = 0;
502 buffer[ret++] = 0xf6;
503 return ret;
506 /* out should hold NONCE_MAX_LEN bytes at most */
507 static void
508 oscore_create_nonce(uint8_t *out,
509 oscore_context_t *context,
510 oscore_info_t *info) {
512 unsigned i = 0;
513 char piv_extended[NONCE_MAX_LEN] = { 0 };
514 unsigned nonce_len;
515 uint8_t *piv;
516 uint8_t piv_len;
517 GByteArray *piv_generator;
519 DISSECTOR_ASSERT(out != NULL);
520 DISSECTOR_ASSERT(context != NULL);
521 DISSECTOR_ASSERT(info != NULL);
523 nonce_len = oscore_alg_get_iv_len(context->algorithm);
524 DISSECTOR_ASSERT(nonce_len <= NONCE_MAX_LEN);
526 /* Recipient ID is the PIV generator ID if the PIV is present in the response */
527 if (info->response && info->piv_len) {
528 piv_generator = context->recipient_id;
529 piv = info->piv;
530 piv_len = info->piv_len;
531 } else {
532 piv_generator = context->sender_id;
533 piv = info->request_piv;
534 piv_len = info->request_piv_len;
537 /* AEAD nonce is the XOR of Common IV left-padded to AEAD nonce length and the concatenation of:
538 * Step 3: Size of ID of the entity that generated PIV (1 byte),
539 * Step 2: ID of the entity that generated PIV (left-padded to "AEAD nonce length - 6 bytes"),
540 * Step 1: Partial IV (left-padded to OSCORE_PIV_MAX_LEN bytes).
543 /* Step 1 */
544 DISSECTOR_ASSERT(piv_len <= OSCORE_PIV_MAX_LEN);
545 memcpy(&piv_extended[nonce_len - piv_len], piv, piv_len);
547 /* Step 2 */
548 DISSECTOR_ASSERT(piv_generator->len <= nonce_len - 6);
549 memcpy(&piv_extended[nonce_len - OSCORE_PIV_MAX_LEN - piv_generator->len], piv_generator->data, piv_generator->len);
551 /* Step 3 */
552 piv_extended[0] = piv_generator->len;
554 /* Now XOR with Common IV */
555 for (i = 0; i < nonce_len; i++) {
556 out[i] = piv_extended[i] ^ context->common_iv->data[i];
561 static oscore_decryption_status_t
562 oscore_decrypt_and_verify(tvbuff_t *tvb_ciphertext,
563 packet_info *pinfo,
564 int *offset,
565 proto_tree *tree,
566 oscore_context_t *context,
567 oscore_info_t *info,
568 tvbuff_t **tvb_plaintext) {
570 bool have_tag = false;
571 uint8_t nonce[NONCE_MAX_LEN];
572 uint8_t tmp[AES_128_BLOCK_LEN];
573 uint8_t *text;
574 uint8_t rx_tag[TAG_MAX_LEN];
575 unsigned tag_len = 0;
576 uint8_t gen_tag[TAG_MAX_LEN];
577 uint8_t external_aad[OSCORE_EXTERNAL_AAD_MAX_LEN];
578 uint8_t external_aad_len = 0;
579 uint8_t aad[OSCORE_AAD_MAX_LEN];
580 uint8_t aad_len = 0;
581 uint8_t *decryption_key;
582 int ciphertext_captured_len;
583 int ciphertext_reported_len;
584 const char *encrypt0 = "Encrypt0";
585 proto_item *item = NULL;
587 tag_len = oscore_alg_get_tag_len(context->algorithm);
589 ciphertext_reported_len = tvb_reported_length_remaining(tvb_ciphertext, *offset + tag_len);
591 if (ciphertext_reported_len == 0) {
592 return STATUS_ERROR_MESSAGE_TOO_SMALL;
595 /* Check if the payload is truncated. */
596 if (tvb_bytes_exist(tvb_ciphertext, *offset, ciphertext_reported_len)) {
597 ciphertext_captured_len = ciphertext_reported_len;
599 else {
600 ciphertext_captured_len = tvb_captured_length_remaining(tvb_ciphertext, *offset);
603 /* Check if the tag is present in the captured data. */
604 have_tag = tvb_bytes_exist(tvb_ciphertext, *offset + ciphertext_reported_len, tag_len);
605 if (have_tag) {
606 DISSECTOR_ASSERT(tag_len <= sizeof(rx_tag));
607 tvb_memcpy(tvb_ciphertext, rx_tag, *offset + ciphertext_reported_len, tag_len);
610 if (info->response) {
611 decryption_key = context->response_decryption_key->data;
612 } else {
613 decryption_key = context->request_decryption_key->data;
616 /* Create nonce to use for decryption and authenticity check */
617 oscore_create_nonce(nonce, context, info);
620 * Create the CCM* initial block for decryption (Adata=0, M=0, counter=0).
621 * XXX: This only handles AES-CCM-16-64-128, add generic algorithm handling
622 * */
623 ccm_init_block(tmp, false, 0, 0, 0, 0, 0, nonce);
626 * Make a copy of the ciphertext in heap memory.
628 * We will decrypt the message in-place and then use the buffer as the
629 * real data for the new tvb.
631 text = (uint8_t *)tvb_memdup(pinfo->pool, tvb_ciphertext, *offset, ciphertext_captured_len);
634 * Perform CTR-mode transformation and decrypt the tag.
635 * XXX: This only handles AES-CCM-16-64-128, add generic algorithm handling
636 * */
637 if(ccm_ctr_encrypt(decryption_key, tmp, rx_tag, text, ciphertext_captured_len) == false) {
638 return STATUS_ERROR_DECRYPT_FAILED;
641 /* Create a tvbuff for the plaintext. */
642 *tvb_plaintext = tvb_new_real_data(text, ciphertext_captured_len, ciphertext_reported_len);
643 tvb_set_child_real_data_tvbuff(tvb_ciphertext, *tvb_plaintext);
644 add_new_data_source(pinfo, *tvb_plaintext, "Decrypted OSCORE");
646 if (have_tag) {
647 /* Construct external_aad to be able to verify the tag */
649 /* Note that OSCORE_EXTERNAL_AAD_MAX_LEN calculation depends on the following construct.
650 * If this is updated - e.g. due to spec changes, added support for Class I options, or added
651 * support for other algorithms which would change max length of KID - do not forget to update the macro.
652 * */
653 external_aad_len += cborencoder_put_array(&external_aad[external_aad_len], 5); /* 5 elements in the array */
654 external_aad_len += cborencoder_put_unsigned(&external_aad[external_aad_len], OSCORE_VERSION);
655 external_aad_len += cborencoder_put_array(&external_aad[external_aad_len], 1);
656 external_aad_len += cborencoder_put_unsigned(&external_aad[external_aad_len], context->algorithm);
657 external_aad_len += cborencoder_put_bytes(&external_aad[external_aad_len], info->kid, info->kid_len);
658 external_aad_len += cborencoder_put_bytes(&external_aad[external_aad_len], info->request_piv, info->request_piv_len);
659 external_aad_len += cborencoder_put_bytes(&external_aad[external_aad_len], NULL, 0); // Class I options not implemented/standardized yet
661 /* info->kid_len and info->piv_len come from the lower layer, other parameters are local.
662 * we end up here only if kid_len is matched to the one from the configured context through oscore_find_context()
663 * and piv_len is verified in the main dissection routine */
664 DISSECTOR_ASSERT(external_aad_len < OSCORE_EXTERNAL_AAD_MAX_LEN);
666 /* Note that OSCORE_AAD_MAX_LEN calculation depends on the following construct.
667 * If the construct below is modified, do not forget to update the macro.
668 * */
669 aad_len += cborencoder_put_array(&aad[aad_len], 3); // COSE Encrypt0 structure with 3 elements
670 aad_len += cborencoder_put_text(&aad[aad_len], encrypt0, 8); /* Text string "Encrypt0" */
671 aad_len += cborencoder_put_bytes(&aad[aad_len], NULL, 0); /* Empty byte string */
672 aad_len += cborencoder_put_bytes(&aad[aad_len], external_aad, external_aad_len); /* OSCORE external_aad */
674 DISSECTOR_ASSERT(aad_len < OSCORE_AAD_MAX_LEN);
676 /* Compute CBC-MAC authentication tag. */
679 * Create the CCM* initial block for authentication (Adata!=0, M!=0, counter=l(m)).
680 * XXX: This only handles AES-CCM-16-64-128, add generic algorithm handling
681 * */
682 DISSECTOR_ASSERT(tag_len <= sizeof(gen_tag));
683 ccm_init_block(tmp, true, tag_len, 0, 0, 0, ciphertext_captured_len, nonce);
684 /* text is already a raw buffer containing the plaintext since we just decrypted it in-place */
685 if (!ccm_cbc_mac(decryption_key, tmp, aad, aad_len, text, ciphertext_captured_len, gen_tag)) {
686 return STATUS_ERROR_CBCMAC_FAILED;
688 /* Compare the received tag with the one we generated. */
689 else if (memcmp(gen_tag, rx_tag, tag_len) != 0) {
690 return STATUS_ERROR_TAG_CHECK_FAILED;
693 /* Display the tag. */
694 if (tag_len) {
695 item = proto_tree_add_bytes(tree, hf_oscore_tag, tvb_ciphertext, ciphertext_captured_len, tag_len, rx_tag);
696 proto_item_set_generated(item);
699 return STATUS_SUCCESS_DECRYPTED_TAG_CHECKED;
700 } /* if (have_tag) */
702 return STATUS_SUCCESS_DECRYPTED_TAG_TRUNCATED;
705 /* Code to actually dissect the packets */
706 static int
707 oscore_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
708 void *data)
710 /* Set up structures needed to add the protocol subtree and manage it */
711 proto_item *ti;
712 proto_tree *oscore_tree;
713 /* Other misc. local variables. */
714 int offset = 0;
715 oscore_info_t *info = (oscore_info_t *) data;
716 oscore_context_t *context = NULL;
717 oscore_decryption_status_t status;
718 tvbuff_t *tvb_decrypted = NULL;
719 coap_info *coinfo;
720 int oscore_length;
721 uint8_t code_class;
723 /* Check that the packet is long enough for it to belong to us. */
724 if (tvb_reported_length(tvb) < OSCORE_MIN_LENGTH) {
725 return 0;
729 /* Set the Protocol column to the constant string of oscore */
730 col_set_str(pinfo->cinfo, COL_PROTOCOL, "OSCORE");
732 /* create display subtree for the protocol */
733 ti = proto_tree_add_item(tree, proto_oscore, tvb, 0, -1, ENC_NA);
735 oscore_tree = proto_item_add_subtree(ti, ett_oscore);
737 if (info->piv == NULL && info->request_piv == NULL) {
738 expert_add_info(pinfo, oscore_tree, &ei_oscore_partial_iv_not_found);
739 return tvb_reported_length(tvb);
742 if ((context = oscore_find_context(info)) == NULL) {
743 expert_add_info(pinfo, oscore_tree, &ei_oscore_context_not_set);
744 return tvb_reported_length(tvb);
747 if (info->piv_len > OSCORE_PIV_MAX_LEN) {
748 expert_add_info(pinfo, oscore_tree, &ei_oscore_piv_len_invalid);
749 return tvb_reported_length(tvb);
752 status = oscore_decrypt_and_verify(tvb, pinfo, &offset, oscore_tree, context, info, &tvb_decrypted);
754 switch (status) {
755 case STATUS_ERROR_DECRYPT_FAILED:
756 expert_add_info(pinfo, oscore_tree, &ei_oscore_decrypt_error);
757 return tvb_reported_length(tvb);
758 case STATUS_ERROR_CBCMAC_FAILED:
759 expert_add_info(pinfo, oscore_tree, &ei_oscore_cbc_mac_failed);
760 return tvb_reported_length(tvb);
761 case STATUS_ERROR_TAG_CHECK_FAILED:
762 expert_add_info(pinfo, oscore_tree, &ei_oscore_tag_check_failed);
763 return tvb_reported_length(tvb);
764 case STATUS_ERROR_MESSAGE_TOO_SMALL:
765 expert_add_info(pinfo, oscore_tree, &ei_oscore_message_too_small);
766 return tvb_reported_length(tvb);
767 case STATUS_SUCCESS_DECRYPTED_TAG_TRUNCATED:
768 expert_add_info(pinfo, oscore_tree, &ei_oscore_truncated);
769 /* do not return, attempt dissection */
770 break;
771 case STATUS_SUCCESS_DECRYPTED_TAG_CHECKED:
772 break;
775 DISSECTOR_ASSERT(tvb_decrypted);
777 oscore_length = tvb_reported_length(tvb_decrypted);
779 /* Fetch CoAP info */
780 coinfo = (coap_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_coap, 0);
782 if (coinfo) {
783 dissect_coap_code(tvb_decrypted, oscore_tree, &offset, &dissect_oscore_hf, &code_class);
784 offset = dissect_coap_options(tvb_decrypted, pinfo, oscore_tree, offset, oscore_length, code_class, coinfo, &dissect_oscore_hf);
785 if (oscore_length > offset) {
786 dissect_coap_payload(tvb_decrypted, pinfo, oscore_tree, tree, offset, oscore_length, code_class, coinfo, &dissect_oscore_hf, true);
788 } else {
789 /* We don't support OSCORE over HTTP at the moment, where coinfo fetch will fail */
790 expert_add_info(pinfo, oscore_tree, &ei_oscore_info_fetch_failed);
793 return tvb_captured_length(tvb);
796 /* Register the protocol with Wireshark.
798 * This format is required because a script is used to build the C function that
799 * calls all the protocol registration.
801 void
802 proto_register_oscore(void)
804 module_t *oscore_module;
805 expert_module_t *expert_oscore;
807 static hf_register_info hf[] = {
808 { &hf_oscore_tag,
809 { "Decrypted Authentication Tag", "oscore.tag", FT_BYTES, BASE_NONE, NULL, 0x0,
810 NULL, HFILL }
812 COAP_COMMON_HF_LIST(dissect_oscore_hf, "oscore")
815 /* Setup protocol subtree array */
816 static int *ett[] = {
817 &ett_oscore,
818 COAP_COMMON_ETT_LIST(dissect_oscore_hf)
821 /* Setup protocol expert items */
822 static ei_register_info ei[] = {
823 { &ei_oscore_partial_iv_not_found,
824 { "oscore.partial_iv_not_found", PI_UNDECODED, PI_WARN,
825 "Partial IV not found - can't decrypt", EXPFILL
828 { &ei_oscore_context_not_set,
829 { "oscore.context_not_set", PI_UNDECODED, PI_WARN,
830 "Security context not set - can't decrypt", EXPFILL
833 { &ei_oscore_message_too_small,
834 { "oscore.message_too_small", PI_UNDECODED, PI_WARN,
835 "Message too small", EXPFILL
838 { &ei_oscore_truncated,
839 { "oscore.truncated", PI_UNDECODED, PI_WARN,
840 "Message truncated, cannot verify authentication tag, but decryption is attempted", EXPFILL
843 { &ei_oscore_cbc_mac_failed,
844 { "oscore.cbc_mac_failed", PI_UNDECODED, PI_WARN,
845 "Call to CBC-MAC failed", EXPFILL
848 { &ei_oscore_tag_check_failed,
849 { "oscore.tag_check_failed", PI_UNDECODED, PI_WARN,
850 "Authentication tag check failed", EXPFILL
853 { &ei_oscore_decrypt_error,
854 { "oscore.decrypt_error", PI_UNDECODED, PI_WARN,
855 "Decryption error", EXPFILL
858 { &ei_oscore_info_fetch_failed,
859 { "oscore.info_fetch_failed", PI_UNDECODED, PI_WARN,
860 "Failed to fetch info from the lower layer - OSCORE over HTTP is not supported", EXPFILL
863 { &ei_oscore_piv_len_invalid,
864 { "oscore.piv_len_invalid", PI_UNDECODED, PI_WARN,
865 "Partial IV length from the lower layer is invalid", EXPFILL
868 COAP_COMMON_EI_LIST(dissect_oscore_hf, "oscore")
871 static uat_field_t oscore_context_uat_flds[] = {
872 UAT_FLD_CSTRING(oscore_context_uat,sender_id_prefs,"Sender ID",
873 "Sender ID as HEX string. Should be 7 bytes or less. Mandatory."),
874 UAT_FLD_CSTRING(oscore_context_uat,recipient_id_prefs,"Recipient ID",
875 "Recipient ID as HEX string. Should be 7 bytes or less. Mandatory."),
876 UAT_FLD_CSTRING(oscore_context_uat,master_secret_prefs,"Master Secret",
877 "Master Secret as HEX string. Mandatory."),
878 UAT_FLD_CSTRING(oscore_context_uat,master_salt_prefs,"Master Salt",
879 "Master Salt as HEX string. Optional."),
880 UAT_FLD_CSTRING(oscore_context_uat,id_context_prefs,"ID Context",
881 "ID Context as HEX string. Optional."),
882 UAT_FLD_VS(oscore_context_uat, algorithm, "Algorithm", oscore_context_alg_vals, "Decryption algorithm."),
883 UAT_END_FIELDS
886 /* Register the protocol name and description */
887 proto_oscore = proto_register_protocol("Object Security for Constrained RESTful Environments",
888 "OSCORE", "oscore");
890 /* Required function calls to register the header fields and subtrees */
891 proto_register_field_array(proto_oscore, hf, array_length(hf));
892 proto_register_subtree_array(ett, array_length(ett));
894 /* Required function calls to register expert items */
895 expert_oscore = expert_register_protocol(proto_oscore);
896 expert_register_field_array(expert_oscore, ei, array_length(ei));
898 oscore_module = prefs_register_protocol(proto_oscore, NULL);
900 /* Create a UAT for security context management. */
901 oscore_context_uat = uat_new("Security Contexts",
902 sizeof(oscore_context_t), /* record size */
903 "oscore_contexts", /* filename */
904 true, /* from_profile */
905 &oscore_contexts, /* data_ptr */
906 &num_oscore_contexts, /* numitems_ptr */
907 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
908 NULL, /* help */
909 oscore_context_copy_cb, /* copy callback */
910 oscore_context_update_cb, /* update callback */
911 oscore_context_free_cb, /* free callback */
912 oscore_context_post_update_cb, /* post update callback */
913 NULL, /* reset callback */
914 oscore_context_uat_flds); /* UAT field definitions */
916 prefs_register_uat_preference(oscore_module, "contexts",
917 "Security Contexts",
918 "Security context configuration data",
919 oscore_context_uat);
921 register_dissector("oscore", oscore_dissect, proto_oscore);
923 proto_coap = proto_get_id_by_short_name("CoAP");
926 /* We're called only by dissector name. */
927 void proto_reg_handoff_oscore(void)
932 * Editor modelines - https://www.wireshark.org/tools/modelines.html
934 * Local variables:
935 * c-basic-offset: 4
936 * tab-width: 8
937 * indent-tabs-mode: nil
938 * End:
940 * vi: set shiftwidth=4 tabstop=8 expandtab:
941 * :indentSize=4:tabSize=8:noTabs=true: