Wireshark-dev: [Wireshark-dev] working with header data

From: Ed Beroset <beroset@xxxxxxxxxxxxxx>
Date: Fri, 14 Oct 2011 09:03:38 -0400
I've written a dissector for a protocol (ANSI C12.22) which employs cryptography for both assuring the integrity of the message (including the unencrypted header) and the confidentiality of the payload (by encrypting it). It uses what's called an AEAD (Authenticated Encryption with Associated Data) mode. The cryptography part is working just fine, but there have been questions about what the code is doing mucking about in the header, so I'll try to both answer that here and also try to ask if there is any better way to do it. (To be very clear, I'm not asking for crypto help, but Wireshark help!)

There is a portion of the code called canonify_unencrypted_header(). In order to cryptographically process the ASN.1 components of the header, the data must be canonified. To do this, the dissector must process the pieces of the header in a particular order no matter what order these were actually sent. Additionally, the entire BER encoding must be processed, and not just the data with a [tag, length, value] triplet.

I can think of two ways to do this (and indeed, have done it both ways). First, I can rely on the ASN.1 parser to break things into their respective fields and then process the components. This approach has two problems. The first problem is that because the entire encoding must be processed, the tag and length must be reconstructed which is a bit messy and complex. The more serious problem is that to enable filtering based on crypto results (e.g. "c1222.crypto_good == true"), the code must also work on packets that haven't yet been parsed. For those reasons, this approach was tried and rejected.

The second way to do this is to use the contents of the tvb of the whole packet and do this parsing in a memory copy. This also has some drawbacks. First, because the packet may or may not be parsed, the routine is either handed an unparsed entire packet, or the user_information element within a parsed packet. To accomodate either, the code does a test to see if it's a user_information element, and if so, navigates to the grandmother node which is the entire packet. The code to do that looks like this:

  if (PNODE_FINFO(tree)->hfinfo->id == hf_c1222_user_information)
    pkt_tree = proto_item_get_parent_nth(tree, 2);
  else
    pkt_tree = tree;


Second, operating on a copy of the tvb in memory requires intruding deep into the structure of a pnode, which I have isolated to a single line of code, but it's not pretty:

  /* fetch a memory copy of the data for processing */
hdr = tvb_memdup(PNODE_FINFO(pkt_tree)->ds_tvb, PNODE_FINFO(pkt_tree)->start, PNODE_FINFO(pkt_tree)->length);
  for (i=0; canonifyTable[i].hf_id != NULL; i++)
status |= find_and_copy_element_raw(hdr, PNODE_FINFO(pkt_tree)->length, canonbuff, offset, length, i, key_id);
  g_free(hdr);

This code works and has been fuzz tested as well on multiple platforms (Windows & Linux). If there's a better way to do this, please let me know what that might be.

For reference the whole of the source code and sample data are here:

https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5531

Ed