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