/*! * Decodes a Text-string from the protocol data * Text-string = [Quote] *TEXT End-of-string * Quote = <Octet 127> * End-of-string = <Octet 0> * * \todo Shouldn't we be sharing this with WSP (packet-wap.c)? * * \param tvb The buffer with PDU-data * \param offset Offset within that buffer * \param strval Pointer to variable into which to put pointer to * buffer allocated to hold the text; must be freed * when no longer used * * \return The length in bytes of the entire field */ static guint get_text_string(tvbuff_t *tvb, guint offset, const char **strval) { guint len; DebugLog(("get_text_string(tvb = %p, offset = %u, **strval) - start\n", tvb, offset)); len = tvb_strsize(tvb, offset); DebugLog((" [1] tvb_strsize(tvb, offset) == %u\n", len)); if (tvb_get_guint8(tvb, offset) == MM_QUOTE) *strval = (const char *)ep_tvb_memdup(tvb, offset+1, len-1); else *strval = (const char *)ep_tvb_memdup(tvb, offset, len); DebugLog((" [3] Return(len) == %u\n", len)); return len; }
static int dissect_bmc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint8 message_type; guint8 *p_rev, *reversing_buffer; gint offset = 0; gint i, len; proto_item *ti; proto_tree *bmc_tree; tvbuff_t *bit_reversed_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "BMC"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_bmc, tvb, 0, -1, ENC_NA); bmc_tree = proto_item_add_subtree(ti, ett_bmc); /* Needs bit-reversing. Create a new buffer, copy the message to it and bit-reverse */ len = tvb_length(tvb); reversing_buffer = ep_tvb_memdup(tvb, offset, len); p_rev = reversing_buffer; /* Entire message is bit reversed */ for (i=0; i<len; i++, p_rev++) *p_rev = BIT_SWAP(*p_rev); /* Make this new buffer part of the display and provide a way to dispose of it */ bit_reversed_tvb = tvb_new_child_real_data(tvb, reversing_buffer, len, len); add_new_data_source(pinfo, bit_reversed_tvb, "Bit-reversed Data"); message_type = tvb_get_guint8(bit_reversed_tvb, offset); proto_tree_add_item(bmc_tree, hf_bmc_message_type, bit_reversed_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(message_type, message_type_vals,"Reserved 0x%02x")); switch (message_type) { case MESSAGE_TYPE_CBS_MESSAGE: offset = dissect_bmc_cbs_message(bit_reversed_tvb, pinfo, bmc_tree); break; case MESSAGE_TYPE_SCHEDULE_MESSAGE: offset = dissect_bmc_schedule_message(bit_reversed_tvb, pinfo, bmc_tree); break; case MESSAGE_TYPE_CBS41_MESSAGE: offset = dissect_bmc_cbs41_message(bit_reversed_tvb, pinfo, bmc_tree); break; default: break; } return offset; }
WSLUA_METHOD TvbRange_bytes(lua_State* L) { /* Obtain a ByteArray */ TvbRange tvbr = checkTvbRange(L,1); GByteArray* ba; if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } ba = g_byte_array_new(); g_byte_array_append(ba,ep_tvb_memdup(tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len),tvbr->len); pushByteArray(L,ba); WSLUA_RETURN(1); /* The ByteArray */ }
/* Code to actually dissect the packets */ static int dissect_wol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint len; gint offset; guint8 sync[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; guint8 *mac; const guint8 *passwd; /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_item *mti; proto_tree *wol_tree; proto_tree *mac_tree; /* First, if at all possible, do some heuristics to check if the packet cannot * possibly belong to your protocol. This is especially important for * protocols directly on top of TCP or UDP where port collisions are * common place (e.g., even though your protocol uses a well known port, * someone else may set up, for example, a web server on that port which, * if someone analyzed that web server's traffic in Wireshark, would result * in Wireshark handing an HTTP packet to your dissector). For example: */ /* Check that there's enough data */ len = tvb_length(tvb); if ( len < 102 ) /* wol's smallest packet size is 102 */ return (0); /* Get some values from the packet header, probably using tvb_get_*() */ /* Regardless of what the AMD white paper states, don't search the entire * tvb for the synchronization stream. My feeling is that this could be * quite expensive and seriously hinder Wireshark performance. For now, * unless we need to change it later, just compare the 1st 6 bytes. */ if ( tvb_memeql(tvb, 0, sync, 6) != 0 ) return (0); /* So far so good. Now get the next 6 bytes, which we'll assume is the * target's MAC address, and do 15 memory chunk comparisons, since if this * is a real MagicPacket, the target's MAC will be duplicated 16 times. */ mac = ep_tvb_memdup(tvb, 6, 6); for ( offset = 12; offset < 102; offset += 6 ) if ( tvb_memeql(tvb, offset, mac, 6) != 0 ) return (0); /* OK, we're going to assume it's a MagicPacket. If there's a password, * grab it now, and in case there's any extra bytes after the only 3 valid * and expected lengths, truncate the length so the extra byte(s) aren't * included as being part of the WOL payload. */ if ( len >= 106 && len < 108 ) { len = 106; passwd = tvb_ip_to_str(tvb, 102); } else if ( len >= 108 ) { len = 108; passwd = ether_to_str(ep_tvb_memdup(tvb, 102, 6)); } else { len = 102; passwd = NULL; } /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "WOL"); /* This field shows up as the "Info" column in the display; you should use it, if possible, to summarize what's in the packet, so that a user looking at the list of packets can tell what type of packet it is. See section 1.5 for more information. Before changing the contents of a column you should make sure the column is active by calling "check_col(pinfo->cinfo, COL_*)". If it is not active don't bother setting it. If you are setting the column to a constant string, use "col_set_str()", as it's more efficient than the other "col_set_XXX()" calls. If you're setting it to a string you've constructed, or will be appending to the column later, use "col_add_str()". "col_add_fstr()" can be used instead of "col_add_str()"; it takes "printf()"-like arguments. Don't use "col_add_fstr()" with a format string of "%s" - just use "col_add_str()" or "col_set_str()", as it's more efficient than "col_add_fstr()". If you will be fetching any data from the packet before filling in the Info column, clear that column first, in case the calls to fetch data from the packet throw an exception because they're fetching data past the end of the packet, so that the Info column doesn't have data left over from the previous dissector; do col_clear(pinfo->cinfo, COL_INFO); */ if ( check_col(pinfo->cinfo, COL_INFO) ) { col_add_fstr(pinfo->cinfo, COL_INFO, "MagicPacket for %s (%s)", get_ether_name(mac), ether_to_str(mac)); /* NOTE: ether-wake uses a dotted-decimal format for specifying a * 4-byte password or an Ethernet mac address format for specifying * a 6-byte password, so display them in that format, even if the * password isn't really an IP or MAC address. */ if ( passwd ) col_append_fstr(pinfo->cinfo, COL_INFO, ", password %s", passwd); } /* A protocol dissector can be called in 2 different ways: (a) Operational dissection In this mode, Wireshark is only interested in the way protocols interact, protocol conversations are created, packets are reassembled and handed over to higher-level protocol dissectors. In this mode Wireshark does not build a so-called "protocol tree". (b) Detailed dissection In this mode, Wireshark is also interested in all details of a given protocol, so a "protocol tree" is created. Wireshark distinguishes between the 2 modes with the proto_tree pointer: (a) <=> tree == NULL (b) <=> tree != NULL In the interest of speed, if "tree" is NULL, avoid building a protocol tree and adding stuff to it, or even looking at any packet data needed only if you're building the protocol tree, if possible. Note, however, that you must fill in column information, create conversations, reassemble packets, build any other persistent state needed for dissection, and call subdissectors regardless of whether "tree" is NULL or not. This might be inconvenient to do without doing most of the dissection work; the routines for adding items to the protocol tree can be passed a null protocol tree pointer, in which case they'll return a null item pointer, and "proto_item_add_subtree()" returns a null tree pointer if passed a null item pointer, so, if you're careful not to dereference any null tree or item pointers, you can accomplish this by doing all the dissection work. This might not be as efficient as skipping that work if you're not building a protocol tree, but if the code would have a lot of tests whether "tree" is null if you skipped that work, you might still be better off just doing all that work regardless of whether "tree" is null or not. */ if (tree) { /* NOTE: The offset and length values in the call to "proto_tree_add_item()" define what data bytes to highlight in the hex display window when the line in the protocol tree display corresponding to that item is selected. Supplying a length of -1 is the way to highlight all data from the offset to the end of the packet. */ /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_wol, tvb, 0, len, FALSE); proto_item_append_text(ti, ", MAC: %s (%s)", get_ether_name(mac), ether_to_str(mac)); if ( passwd ) proto_item_append_text(ti, ", password: %s", passwd); wol_tree = proto_item_add_subtree(ti, ett_wol); /* add an item to the subtree, see section 1.6 for more information */ proto_tree_add_item(wol_tree, hf_wol_sync, tvb, 0, 6, FALSE); /* Continue adding tree items to process the packet here */ mti = proto_tree_add_text(wol_tree, tvb, 6, 96, "MAC: %s (%s)", get_ether_name(mac), ether_to_str(mac)); mac_tree = proto_item_add_subtree(mti, ett_wol_macblock); for ( offset = 6; offset < 102; offset += 6 ) proto_tree_add_ether(mac_tree, hf_wol_mac, tvb, offset, 6, mac); if ( len == 106 ) proto_tree_add_bytes_format(wol_tree, hf_wol_passwd, tvb, offset, 4, passwd, "Password: %s", passwd); else if ( len == 108 ) proto_tree_add_bytes_format(wol_tree, hf_wol_passwd, tvb, offset, 6, passwd, "Password: %s", passwd); } /* If this protocol has a sub-dissector call it here, see section 1.8 */ /* Return the amount of data this dissector was able to dissect */ if ( pinfo->ethertype == ETHERTYPE_WOL ) return (len); /* Heuristic dissectors return TRUE/FALSE. */ return (TRUE); }
/* * Dissector that returns: * * The amount of data in the protocol's PDU, if it was able to * dissect all the data; * * 0, if the tvbuff doesn't contain a PDU for that protocol; * * The negative of the amount of additional data needed, if * we need more data (e.g., from subsequent TCP segments) to * dissect the entire PDU. */ static int dissect_ccn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint tvb_size = 0; proto_tree *ccn_tree; proto_item *ti = NULL; const unsigned char *ccnb; struct ccn_skeleton_decoder skel_decoder; struct ccn_skeleton_decoder *sd; struct ccn_charbuf *c; int packet_type = 0; int packet_type_length = 0; /* a couple of basic checks to rule out packets that are definitely not ours */ tvb_size = tvb_length(tvb); if (tvb_size < CCN_MIN_PACKET_SIZE || tvb_get_guint8(tvb, 0) == 0) return (0); sd = &skel_decoder; memset(sd, 0, sizeof(*sd)); sd->state |= CCN_DSTATE_PAUSE; ccnb = ep_tvb_memdup(tvb, 0, tvb_size); ccn_skeleton_decode(sd, ccnb, tvb_size); if (sd->state < 0) return (0); if (CCN_GET_TT_FROM_DSTATE(sd->state) == CCN_DTAG) { packet_type = sd->numval; packet_type_length = sd->index; } else { return (0); } memset(sd, 0, sizeof(*sd)); ccn_skeleton_decode(sd, ccnb, tvb_size); if (!CCN_FINAL_DSTATE(sd->state)) { pinfo->desegment_offset = 0; pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; return (-1); /* what should this be? */ } /* Make it visible that we're taking this packet */ if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCN"); } /* Clear out stuff in the info column */ if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); } c = ccn_charbuf_create(); ccn_uri_append(c, ccnb, tvb_size, 1); /* Add the packet type and CCN URI to the info column */ if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(packet_type, VALS(ccn_dtag_dict.dict), "Unknown (0x%02x")); col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, ccn_charbuf_as_string(c)); } if (tree == NULL) { ccn_charbuf_destroy(&c); return (sd->index); } ti = proto_tree_add_protocol_format(tree, proto_ccn, tvb, 0, -1, "Content-centric Networking Protocol, %s, %s", val_to_str(packet_type, VALS(ccn_dtag_dict.dict), "Unknown (0x%02x"), ccn_charbuf_as_string(c)); ccn_tree = proto_item_add_subtree(ti, ett_ccn); ccn_charbuf_destroy(&c); ti = proto_tree_add_uint(ccn_tree, hf_ccn_type, tvb, 0, packet_type_length, packet_type); switch (packet_type) { case CCN_DTAG_ContentObject: if (0 > dissect_ccn_contentobject(ccnb, sd->index, tvb, pinfo, ccn_tree)) return (0); break; case CCN_DTAG_Interest: if (0 > dissect_ccn_interest(ccnb, sd->index, tvb, pinfo, ccn_tree)) return (0); break; } return (sd->index); }
/*FUNCTION:------------------------------------------------------ * NAME * dissect_zbee_secure * DESCRIPTION * Dissects and decrypts secured ZigBee frames. * * Will return a valid tvbuff only if security processing was * successful. If processing fails, then this function will * handle internally and return NULL. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * guint offset - pointer to the start of the auxilliary security header. * guint64 src64 - extended source address, or 0 if unknown. * RETURNS * tvbuff_t * *--------------------------------------------------------------- */ tvbuff_t * dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset) { proto_tree *sec_tree = NULL; proto_item *sec_root; proto_tree *field_tree; proto_item *ti; zbee_security_packet packet; guint mic_len; gint payload_len; tvbuff_t *payload_tvb; #ifdef HAVE_LIBGCRYPT guint8 *enc_buffer; guint8 *dec_buffer; gboolean decrypted; GSList **nwk_keyring; GSList *GSList_i; key_record_t *key_rec = NULL; #endif zbee_nwk_hints_t *nwk_hints; ieee802154_hints_t *ieee_hints; ieee802154_map_rec *map_rec = NULL; /* Init */ memset(&packet, 0, sizeof(zbee_security_packet)); /* Get pointers to any useful frame data from lower layers */ nwk_hints = (zbee_nwk_hints_t *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK)); ieee_hints = (ieee802154_hints_t *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN)); /* Create a subtree for the security information. */ if (tree) { sec_root = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "ZigBee Security Header"); sec_tree = proto_item_add_subtree(sec_root, ett_zbee_sec); } /* Get and display the Security control field */ packet.control = tvb_get_guint8(tvb, offset); /* Patch the security level. */ packet.control &= ~ZBEE_SEC_CONTROL_LEVEL; packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level); /* * Eww, I think I just threw up a little... ZigBee requires this field * to be patched before computing the MIC, but we don't have write-access * to the tvbuff. So we need to allocate a copy of the whole thing just * so we can fix these 3 bits. Memory allocated by ep_tvb_memdup() is * automatically freed before the next packet is processed. */ #ifdef HAVE_LIBGCRYPT enc_buffer = (guint8 *)ep_tvb_memdup(tvb, 0, tvb_length(tvb)); /* * Override the const qualifiers and patch the security level field, we * know it is safe to overide the const qualifiers because we just * allocated this memory via ep_tvb_memdup(). */ enc_buffer[offset] = packet.control; #endif /* HAVE_LIBGCRYPT */ packet.level = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL); packet.key_id = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); packet.nonce = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE); if (tree) { ti = proto_tree_add_text(sec_tree, tvb, offset, 1, "Security Control Field"); field_tree = proto_item_add_subtree(ti, ett_zbee_sec_control); proto_tree_add_uint(field_tree, hf_zbee_sec_key_id, tvb, offset, 1, packet.control & ZBEE_SEC_CONTROL_KEY); proto_tree_add_boolean(field_tree, hf_zbee_sec_nonce, tvb, offset, 1, packet.control & ZBEE_SEC_CONTROL_NONCE); } offset += 1; /* Get and display the frame counter field. */ packet.counter = tvb_get_letohl(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_counter, tvb, offset, 4, packet.counter); } offset += 4; if (packet.nonce) { /* Get and display the source address of the device that secured this payload. */ packet.src64 = tvb_get_letoh64(tvb, offset); if (tree) { proto_tree_add_item(sec_tree, hf_zbee_sec_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN); } #if 1 if (!pinfo->fd->flags.visited) { switch ( packet.key_id ) { case ZBEE_SEC_KEY_LINK: if (nwk_hints) { /* Map this long address with the nwk layer short address. */ nwk_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, nwk_hints->src, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->fd->num); } break; case ZBEE_SEC_KEY_NWK: if (ieee_hints) { /* Map this long address with the ieee short address. */ ieee_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, ieee_hints->src16, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->fd->num); } break; /* We ignore the extended source addresses used to encrypt payloads with these * types of keys, because they can emerge from APS tunnels created by nodes whose * short address is not recorded in the packet. */ case ZBEE_SEC_KEY_TRANSPORT: case ZBEE_SEC_KEY_LOAD: break; } } #endif offset += 8; } else { /* Look for a source address in hints */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: /* use the ieee extended source address for NWK decryption */ if ( ieee_hints && (map_rec = ieee_hints->map_rec) ) packet.src64 = map_rec->addr64; else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "[Extended Source: Unknown]"); break; default: /* use the nwk extended source address for APS decryption */ if ( nwk_hints && (map_rec = nwk_hints->map_rec) ) packet.src64 = map_rec->addr64; else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "[Extended Source: Unknown]"); break; } } if (packet.key_id == ZBEE_SEC_KEY_NWK) { /* Get and display the key sequence number. */ packet.key_seqno = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_key_seqno, tvb, offset, 1, packet.key_seqno); } offset += 1; } /* Determine the length of the MIC. */ switch (packet.level) { case ZBEE_SEC_ENC: case ZBEE_SEC_NONE: default: mic_len=0; break; case ZBEE_SEC_ENC_MIC32: case ZBEE_SEC_MIC32: mic_len=4; break; case ZBEE_SEC_ENC_MIC64: case ZBEE_SEC_MIC64: mic_len=8; break; case ZBEE_SEC_ENC_MIC128: case ZBEE_SEC_MIC128: mic_len=16; break; } /* switch */ /* Get and display the MIC. */ if (mic_len) { /* Display the MIC. */ if (tree) { proto_tree_add_item(sec_tree, hf_zbee_sec_mic, tvb, (gint)(tvb_length(tvb)-mic_len), mic_len, ENC_NA); } } /* Check for null payload. */ if ( !(payload_len = tvb_reported_length_remaining(tvb, offset+mic_len)) ) { return NULL; } else if ( payload_len < 0 ) { THROW(ReportedBoundsError); } /********************************************** * Perform Security Operations on the Frame * ********************************************** */ if ((packet.level == ZBEE_SEC_NONE) || (packet.level == ZBEE_SEC_MIC32) || (packet.level == ZBEE_SEC_MIC64) || (packet.level == ZBEE_SEC_MIC128)) { /* Payload is only integrity protected. Just return the sub-tvbuff. */ return tvb_new_subset(tvb, offset, payload_len, payload_len); } #ifdef HAVE_LIBGCRYPT /* Allocate memory to decrypt the payload into. */ dec_buffer = (guint8 *)g_malloc(payload_len); decrypted = FALSE; if ( packet.src64 ) { if (pinfo->fd->flags.visited) { if ( nwk_hints ) { /* Use previously found key */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: if ( (key_rec = nwk_hints->nwk) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->nwk->key); } break; default: if ( (key_rec = nwk_hints->link) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->link->key); } break; } } } /* ( !pinfo->fd->flags.visited ) */ else { /* We only search for sniffed keys in the first pass, * to save time, and because decrypting with keys * transported in future packets is cheating */ /* Lookup NWK and link key in hash for this pan. */ /* This overkill approach is a placeholder for a hash that looks up * a key ring for a link key associated with a pair of devices. */ if ( nwk_hints ) { nwk_keyring = (GSList **)g_hash_table_lookup(zbee_table_nwk_keyring, &nwk_hints->src_pan); if ( nwk_keyring ) { GSList_i = *nwk_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } /* Loop through user's password table for preconfigured keys, our last resort */ GSList_i = zbee_pc_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } } /* ( ! pinfo->fd->flags.visited ) */ } /* ( packet.src64 ) */ if ( decrypted ) { if ( tree && key_rec ) { if ( key_rec->frame_num == ZBEE_SEC_PC_KEY ) { ti = proto_tree_add_text(sec_tree, tvb, 0, 0, "Decryption Key: %s", key_rec->label); } else { ti = proto_tree_add_uint(sec_tree, hf_zbee_sec_key_origin, tvb, 0, 0, key_rec->frame_num); } PROTO_ITEM_SET_GENERATED(ti); } /* Found a key that worked, setup the new tvbuff_t and return */ payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); tvb_set_free_cb(payload_tvb, g_free); /* set up callback to free dec_buffer */ add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); /* Done! */ return payload_tvb; } g_free(dec_buffer); #endif /* HAVE_LIBGCRYPT */ /* Add expert info. */ expert_add_info_format(pinfo, sec_tree, PI_UNDECODED, PI_WARN, "Encrypted Payload"); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset(tvb, offset, payload_len, -1); /* Dump the payload to the data dissector. */ call_dissector(data_handle, payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* dissect_zbee_secure */
/*FUNCTION:------------------------------------------------------ * NAME * dissect_zbee_secure * DESCRIPTION * Dissects and decrypts secured ZigBee frames. * * Will return a valid tvbuff only if security processing was * successful. If processing fails, then this function will * handle internally and return NULL. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_into *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * guint offset - pointer to the start of the auxilliary security header. * guint64 src - extended source address, or 0 if unknown. * RETURNS * tvbuff_t * *--------------------------------------------------------------- */ tvbuff_t * dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset, guint64 src) { proto_tree * sec_tree = NULL; proto_item * sec_root; proto_tree * field_tree; proto_item * ti; zbee_security_packet packet; guint mic_len; guint payload_len; tvbuff_t * payload_tvb; #ifdef HAVE_LIBGCRYPT const guint8 * enc_buffer; guint8 * dec_buffer; guint8 * key_buffer; guint8 nonce[ZBEE_SEC_CONST_NONCE_LEN]; #endif /* Create a substree for the security information. */ if (tree) { sec_root = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "ZigBee Security Header"); sec_tree = proto_item_add_subtree(sec_root, ett_zbee_sec); } /* Get and display the Security control field */ packet.control = tvb_get_guint8(tvb, offset); /* Patch the security level. */ packet.control &= ~ZBEE_SEC_CONTROL_LEVEL; packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level); /* * Eww, I think I just threw up a little... ZigBee requires this field * to be patched before computing the MIC, but we don't have write-access * to the tvbuff. So we need to allocate a copy of the whole thing just * so we can fix these 3 bits. */ #ifdef HAVE_LIBGCRYPT enc_buffer = ep_tvb_memdup(tvb, 0, tvb_length(tvb)); /* * Override the const qualifiers and patch the security level field, we * know it is safe to overide the const qualifiers because we just * allocated this memory via ep_tvb_memdup(). */ ((guint8 *)(enc_buffer))[offset] = packet.control; #endif /* HAVE_LIBGCRYPT */ packet.level = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL); packet.key = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); packet.nonce = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE); if (tree) { ti = proto_tree_add_text(sec_tree, tvb, offset, sizeof(guint8), "Security Control Field"); field_tree = proto_item_add_subtree(ti, ett_zbee_sec_control); proto_tree_add_uint(field_tree, hf_zbee_sec_key, tvb, offset, sizeof(guint8), packet.control & ZBEE_SEC_CONTROL_KEY); proto_tree_add_boolean(field_tree, hf_zbee_sec_nonce, tvb, offset, sizeof(guint8), packet.control & ZBEE_SEC_CONTROL_NONCE); } offset += sizeof(guint8); /* Get and display the frame counter field. */ packet.counter = tvb_get_letohl(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_counter, tvb, offset, sizeof(guint32), packet.counter); } offset += sizeof(guint32); if (packet.nonce) { /* Get and display the source address. */ packet.src = tvb_get_letoh64(tvb, offset); if (tree) { proto_tree_add_eui64(sec_tree, hf_zbee_sec_src, tvb, offset, sizeof(guint64), packet.src); } offset += sizeof(guint64); } else { /* This field is required in the security decryption process, so * fill it in in case the higher layer provided it. */ packet.src = src; } if (packet.key == ZBEE_SEC_KEY_NWK) { /* Get and display the key sequence number. */ packet.key_seqno = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_key_seqno, tvb, offset, sizeof(guint8), packet.key_seqno); } offset += sizeof(guint8); } /* Determine the length of the MIC. */ switch (packet.level){ case ZBEE_SEC_ENC: case ZBEE_SEC_NONE: default: mic_len=0; break; case ZBEE_SEC_ENC_MIC32: case ZBEE_SEC_MIC32: mic_len=4; break; case ZBEE_SEC_ENC_MIC64: case ZBEE_SEC_MIC64: mic_len=8; break; case ZBEE_SEC_ENC_MIC128: case ZBEE_SEC_MIC128: mic_len=16; break; } /* switch */ /* Ensure that the payload exists (length >= 1) for this length. */ payload_len = tvb_ensure_length_remaining(tvb, offset+mic_len+1)+1; /* Get and display the MIC. */ if (mic_len) { /* Display the MIC. */ if (tree) { ti = proto_tree_add_bytes(sec_tree, hf_zbee_sec_mic, tvb, tvb_length(tvb)-mic_len, mic_len, ep_tvb_memdup(tvb, tvb_length(tvb)-mic_len, mic_len)); } } /********************************************** * Perform Security Operations on the Frame * ********************************************** */ if ((packet.level == ZBEE_SEC_NONE) || (packet.level == ZBEE_SEC_MIC32) || (packet.level == ZBEE_SEC_MIC64) || (packet.level == ZBEE_SEC_MIC128)) { /* Payload is only integrity protected. Just return the sub-tvbuff. */ return tvb_new_subset(tvb, offset, payload_len, payload_len); } #ifdef HAVE_LIBGCRYPT /* Ensure we have enough security material to decrypt this payload. */ switch (packet.key) { /* Network Keys use the shared network key. */ case ZBEE_SEC_KEY_NWK: if (!zbee_sec_have_nwk_key) { /* Without a key we can't decrypt (if we could what good would security be?)*/ goto decrypt_failed; } if (packet.src == 0) { /* Without the extended source address, we can't create the nonce. */ goto decrypt_failed; } /* The key, is the network key. */ key_buffer = zbee_sec_nwk_key; break; /* Link Key might use the trust center link key. */ case ZBEE_SEC_KEY_LINK: if (!zbee_sec_have_tclink_key) { /* Without a key we can't decrypt. */ goto decrypt_failed; } if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){ /* Without the extended source address, we can't create the nonce. */ goto decrypt_failed; } else if (packet.src == 0) { packet.src = zbee_sec_tcaddr; } key_buffer = zbee_sec_tclink_key; break; /* Key-Transport Key should use the trust center link key. */ case ZBEE_SEC_KEY_TRANSPORT: if (!zbee_sec_have_tclink_key) { /* Without a key we can't decrypt. */ goto decrypt_failed; } if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){ /* Without the extended source address, we can't create the nonce. */ goto decrypt_failed; } else if (packet.src == 0) { packet.src = zbee_sec_tcaddr; } key_buffer = zbee_sec_key_hash(zbee_sec_tclink_key, 0x00, pinfo); break; /* Key-Load Key should use the trust center link key. */ case ZBEE_SEC_KEY_LOAD: if (!zbee_sec_have_tclink_key) { /* Without a key we can't decrypt. */ goto decrypt_failed; } if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){ /* Without the extended source address, we can't create the nonce. */ goto decrypt_failed; } else if (packet.src == 0) { packet.src = zbee_sec_tcaddr; } key_buffer = zbee_sec_key_hash(zbee_sec_tclink_key, 0x02, pinfo); break; default: goto decrypt_failed; } /* switch */ /* Create the nonce. */ zbee_sec_make_nonce(nonce, &packet); /* Allocate memory to decrypt the payload into. */ dec_buffer = g_malloc(payload_len); /* Perform Decryption. */ if (!zbee_sec_ccm_decrypt(key_buffer, /* key */ nonce, /* Nonce */ enc_buffer, /* a, length l(a) */ enc_buffer+offset, /* c, length l(c) = l(m) + M */ dec_buffer, /* m, length l(m) */ offset, /* l(a) */ payload_len, /* l(m) */ mic_len)) { /* M */ /* Decryption Failed! */ g_free(dec_buffer); goto decrypt_failed; } /* Setup the new tvbuff_t and return */ payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); /* Done! */ return payload_tvb; decrypt_failed: #endif /* HAVE_LIBGCRYPT */ /* Add expert info. */ expert_add_info_format(pinfo, sec_tree, PI_UNDECODED, PI_WARN, "Encrypted Payload"); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset(tvb, offset, payload_len, -1); /* Dump the payload to the data dissector. */ call_dissector(data_handle, payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* dissect_zbee_secure */
WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { /* Obtain the Value of the field */ FieldInfo fi = checkFieldInfo(L,1); switch(fi->hfinfo->type) { case FT_NONE: lua_pushnil(L); return 1; case FT_BOOLEAN: lua_pushboolean(L,(int)fvalue_get_uinteger(&(fi->value))); return 1; case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: case FT_FRAMENUM: lua_pushnumber(L,(lua_Number)fvalue_get_uinteger(&(fi->value))); return 1; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: lua_pushnumber(L,(lua_Number)fvalue_get_sinteger(&(fi->value))); return 1; case FT_FLOAT: case FT_DOUBLE: lua_pushnumber(L,(lua_Number)fvalue_get_floating(&(fi->value))); return 1; case FT_INT64: { Int64 num = (Int64)g_malloc(sizeof(gint64)); *num = fvalue_get_integer64(&(fi->value)); pushInt64(L,num); return 1; } case FT_UINT64: { UInt64 num = (UInt64)g_malloc(sizeof(guint64)); *num = fvalue_get_integer64(&(fi->value)); pushUInt64(L,num); return 1; } case FT_ETHER: { Address eth = (Address)g_malloc(sizeof(address)); eth->type = AT_ETHER; eth->len = fi->length; eth->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,eth); return 1; } case FT_IPv4: { Address ipv4 = (Address)g_malloc(sizeof(address)); ipv4->type = AT_IPv4; ipv4->len = fi->length; ipv4->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv4); return 1; } case FT_IPv6: { Address ipv6 = (Address)g_malloc(sizeof(address)); ipv6->type = AT_IPv6; ipv6->len = fi->length; ipv6->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv6); return 1; } case FT_IPXNET: { Address ipx = (Address)g_malloc(sizeof(address)); ipx->type = AT_IPX; ipx->len = fi->length; ipx->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipx); return 1; } case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: { NSTime nstime = (NSTime)g_malloc(sizeof(nstime_t)); *nstime = *(NSTime)fvalue_get(&(fi->value)); pushNSTime(L,nstime); return 1; } case FT_STRING: case FT_STRINGZ: { gchar* repr = fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL); if (repr) lua_pushstring(L,repr); else luaL_error(L,"field cannot be represented as string because it may contain invalid characters"); return 1; } case FT_BYTES: case FT_UINT_BYTES: case FT_GUID: case FT_PROTOCOL: case FT_OID: { ByteArray ba = g_byte_array_new(); g_byte_array_append(ba, (const guint8 *)ep_tvb_memdup(fi->ds_tvb,fi->start,fi->length),fi->length); pushByteArray(L,ba); return 1; } default: luaL_error(L,"FT_ not yet supported"); return 1; } }