/* * Removes any Markers from this FPDU by using memcpy or throws an out of memory * exception. */ static tvbuff_t * remove_markers(tvbuff_t *tvb, packet_info *pinfo, guint32 marker_offset, guint32 num_markers, guint32 orig_length) { guint8 *mfree_buff = NULL; guint32 mfree_buff_length, tot_copy, cur_copy; guint32 source_offset; tvbuff_t *mfree_tvb = NULL; DISSECTOR_ASSERT(num_markers > 0); DISSECTOR_ASSERT(orig_length > MPA_MARKER_LEN * num_markers); DISSECTOR_ASSERT(tvb_length(tvb) == orig_length); /* allocate memory for the marker-free buffer */ mfree_buff_length = orig_length - (MPA_MARKER_LEN * num_markers); mfree_buff = (guint8 *)wmem_alloc(pinfo->pool, mfree_buff_length); tot_copy = 0; source_offset = 0; cur_copy = marker_offset; while (tot_copy < mfree_buff_length) { tvb_memcpy(tvb, mfree_buff+tot_copy, source_offset, cur_copy); tot_copy += cur_copy; source_offset += cur_copy + MPA_MARKER_LEN; cur_copy = MIN(MPA_MARKER_INTERVAL, (mfree_buff_length - tot_copy)); } mfree_tvb = tvb_new_child_real_data(tvb, mfree_buff, mfree_buff_length, mfree_buff_length); add_new_data_source(pinfo, mfree_tvb, "FPDU without Markers"); return mfree_tvb; }
/* obtain an (aligned) EGPRS data block with given bit-offset and * bit-length from the parent TVB */ static tvbuff_t *get_egprs_data_block(tvbuff_t *tvb, guint offset_bits, guint length_bits, packet_info *pinfo) { tvbuff_t *aligned_tvb; const guint initial_spare_bits = 6; guint8 *aligned_buf; guint min_src_length_bytes = (offset_bits + length_bits + 7) / 8; guint length_bytes = (initial_spare_bits + length_bits + 7) / 8; tvb_ensure_bytes_exist(tvb, 0, min_src_length_bytes); aligned_buf = (guint8 *) wmem_alloc(pinfo->pool, length_bytes); /* Copy the data out of the tvb to an aligned buffer */ clone_aligned_buffer_lsbf( offset_bits - initial_spare_bits, length_bytes, tvb_get_ptr(tvb, 0, min_src_length_bytes), aligned_buf); /* clear spare bits and move block header bits to the right */ aligned_buf[0] = aligned_buf[0] >> initial_spare_bits; aligned_tvb = tvb_new_child_real_data(tvb, aligned_buf, length_bytes, length_bytes); add_new_data_source(pinfo, aligned_tvb, "Aligned EGPRS data bits"); return aligned_tvb; }
/** Unescapes the data. */ static tvbuff_t * unescape_data(tvbuff_t *tvb, packet_info *pinfo) { if (tvb_find_guint8(tvb, 0, -1, SIR_CE) == -1) { return tvb; } else { guint length = tvb_length(tvb); guint offset; guint8 *data = (guint8 *)g_malloc(length); guint8 *dst = data; tvbuff_t *next_tvb; for (offset = 0; offset < length; ) { guint8 c = tvb_get_guint8(tvb, offset++); if ((c == SIR_CE) && (offset < length)) c = SIR_ESCAPE(tvb_get_guint8(tvb, offset++)); *dst++ = c; } next_tvb = tvb_new_child_real_data(tvb, data, (guint) (dst-data), (guint) (dst-data)); tvb_set_free_cb(next_tvb, g_free); add_new_data_source(pinfo, next_tvb, "Unescaped SIR"); return next_tvb; } }
static gint tacplus_decrypted_tvb_setup( tvbuff_t *tvb, tvbuff_t **dst_tvb, packet_info *pinfo, guint32 len, guint8 version, const char *key ) { guint8 *buff; guint8 session_id[4]; /* TODO Check the possibility to use pinfo->decrypted_data */ /* session_id is in NETWORK Byte Order, and is used as byte array in the md5_xor */ tvb_memcpy(tvb, session_id, 4,4); buff = tvb_memdup(tvb, TAC_PLUS_HDR_SIZE, len); md5_xor( buff, key, len, session_id,version, tvb_get_guint8(tvb,2) ); /* Allocate a new tvbuff, referring to the decrypted data. */ *dst_tvb = tvb_new_child_real_data(tvb, buff, len, len ); /* Arrange that the allocated packet data copy be freed when the tvbuff is freed. */ tvb_set_free_cb( *dst_tvb, g_free ); /* Add the decrypted data to the data source list. */ add_new_data_source(pinfo, *dst_tvb, "TACACS+ Decrypted"); return 0; }
tvbuff_t * dissect_cbs_data(guint8 sms_encoding, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, guint offset ) { tvbuff_t * tvb_out = NULL; int length = tvb_length(tvb) - offset; gchar *utf8_text = NULL, *utf8_out; switch(sms_encoding){ case SMS_ENCODING_7BIT: case SMS_ENCODING_7BIT_LANG: utf8_text = tvb_get_ts_23_038_7bits_string(wmem_packet_scope(), tvb, offset<<3, (length*8)/7); utf8_out = g_strdup(utf8_text); tvb_out = tvb_new_child_real_data(tvb, utf8_out, (guint)strlen(utf8_out), (guint)strlen(utf8_out)); tvb_set_free_cb(tvb_out, g_free); add_new_data_source(pinfo, tvb_out, "unpacked 7 bit data"); break; case SMS_ENCODING_8BIT: /* * XXX - encoding is "user-defined". Have a preference? */ utf8_text = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, length, ENC_ASCII|ENC_NA); utf8_out = g_strdup(utf8_text); tvb_out = tvb_new_child_real_data(tvb, utf8_out, (guint)strlen(utf8_out), (guint)strlen(utf8_out)); tvb_set_free_cb(tvb_out, g_free); add_new_data_source(pinfo, tvb_out, "unpacked 7 bit data"); break; case SMS_ENCODING_UCS2: case SMS_ENCODING_UCS2_LANG: utf8_text = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, length, ENC_UCS_2|ENC_BIG_ENDIAN); utf8_out = g_strdup(utf8_text); tvb_out = tvb_new_child_real_data(tvb, utf8_out, (guint)strlen(utf8_out), (guint)strlen(utf8_out)); tvb_set_free_cb(tvb_out, g_free); add_new_data_source(pinfo, tvb_out, "unpacked UCS-2 data"); break; default: proto_tree_add_expert_format(tree, pinfo, &ei_gsm_cbs_unhandled_encoding, tvb, offset, length, "Unhandled encoding %d of CBS String", sms_encoding); break; } return tvb_out; }
static tvbuff_t * dissect_cbs_data(guint8 sms_encoding, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, guint16 offset ) { tvbuff_t * tvb_out = NULL; guint8 out_len; int length = tvb_length(tvb) - offset; gchar *utf8_text = NULL; static unsigned char msgbuf[1024]; guint8 * input_string = tvb_get_ephemeral_string(tvb, offset, length); GIConv cd; GError *l_conv_error = NULL; switch(sms_encoding){ case SMS_ENCODING_7BIT: case SMS_ENCODING_7BIT_LANG: out_len = gsm_sms_char_7bit_unpack(0, length, sizeof(msgbuf), input_string, msgbuf); msgbuf[out_len] = '\0'; utf8_text = gsm_sms_chars_to_utf8(msgbuf, out_len); tvb_out = tvb_new_child_real_data(tvb, utf8_text, out_len, out_len); add_new_data_source(pinfo, tvb_out, "unpacked 7 bit data"); break; case SMS_ENCODING_8BIT: tvb_out = tvb_new_subset(tvb, offset, length, length); break; case SMS_ENCODING_UCS2: case SMS_ENCODING_UCS2_LANG: if ((cd = g_iconv_open("UTF-8","UCS-2BE")) != (GIConv) -1) { utf8_text = g_convert_with_iconv(input_string, length, cd, NULL, NULL, &l_conv_error); if(!l_conv_error) { tvb_out = tvb_new_subset(tvb, offset, length, length); } else proto_tree_add_text(tree, tvb, offset, length, "CBS String: g_convert_with_iconv FAILED"); g_free(utf8_text); g_iconv_close(cd); } else { proto_tree_add_text(tree, tvb, offset, length, "CBS String: g_iconv_open FAILED contact wireshark"); } break; default: proto_tree_add_text(tree, tvb, offset, length, "Unhandled encoding %d of CBS String", sms_encoding); break; } return tvb_out; }
/* Decode and display the PDU Burst */ static void pdu_burst_decoder(proto_tree *tree, tvbuff_t *tvb, gint offset, gint length, packet_info *pinfo, gint burst_number, gint frag_type, gint frag_number) { fragment_data *pdu_frag; tvbuff_t *pdu_tvb = NULL; /* update the info column */ switch (frag_type) { case TLV_FIRST_FRAG: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "First TLV Fragment (%d)", frag_number); break; case TLV_LAST_FRAG: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Last TLV Fragment (%d)", frag_number); break; case TLV_MIDDLE_FRAG: col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Middle TLV Fragment %d", frag_number); break; } if(frag_type == TLV_NO_FRAG) { /* not fragmented PDU */ pdu_tvb = tvb_new_subset(tvb, offset, length, length); } else /* fragmented PDU */ { /* add the frag */ pdu_frag = fragment_add_seq(tvb, offset, pinfo, burst_number, pdu_frag_table, frag_number - 1, length, ((frag_type==TLV_LAST_FRAG)?0:1)); if(pdu_frag && frag_type == TLV_LAST_FRAG) { /* create the new tvb for defraged frame */ pdu_tvb = tvb_new_child_real_data(tvb, pdu_frag->data, pdu_frag->len, pdu_frag->len); /* add the defragmented data to the data source list */ add_new_data_source(pinfo, pdu_tvb, "Reassembled WiMax PDU Frame"); } else { pdu_tvb = NULL; if(frag_type == TLV_LAST_FRAG) { /* update the info column */ col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Incomplete PDU frame"); } } } /* process the defragmented PDU burst */ if(pdu_tvb) { if(wimax_pdu_burst_handle) {/* decode and display PDU Burst */ call_dissector(wimax_pdu_burst_handle, pdu_tvb, pinfo, tree); } else /* display PDU Burst info */ { /* update the info column */ col_append_str(pinfo->cinfo, COL_INFO, "PDU Burst"); } } }
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; }
tvbuff_t * dissect_cbs_data(guint8 sms_encoding, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, guint16 offset ) { tvbuff_t * tvb_out = NULL; int length = tvb_length(tvb) - offset; gchar *utf8_text = NULL, *utf8_out; guint8 * input_string; GIConv cd; GError *l_conv_error = NULL; switch(sms_encoding){ case SMS_ENCODING_7BIT: case SMS_ENCODING_7BIT_LANG: utf8_text = tvb_get_ts_23_038_7bits_string(wmem_packet_scope(), tvb, offset<<3, (length*8)/7); utf8_out = g_strdup(utf8_text); tvb_out = tvb_new_child_real_data(tvb, utf8_out, (guint)strlen(utf8_out), (guint)strlen(utf8_out)); tvb_set_free_cb(tvb_out, g_free); add_new_data_source(pinfo, tvb_out, "unpacked 7 bit data"); break; case SMS_ENCODING_8BIT: tvb_out = tvb_new_subset(tvb, offset, length, length); break; case SMS_ENCODING_UCS2: case SMS_ENCODING_UCS2_LANG: input_string = tvb_get_string(wmem_packet_scope(), tvb, offset, length); if ((cd = g_iconv_open("UTF-8","UCS-2BE")) != (GIConv) -1) { utf8_text = g_convert_with_iconv(input_string, length, cd, NULL, NULL, &l_conv_error); if(!l_conv_error) { tvb_out = tvb_new_subset(tvb, offset, length, length); } else proto_tree_add_text(tree, tvb, offset, length, "CBS String: g_convert_with_iconv FAILED"); g_free(utf8_text); g_iconv_close(cd); } else { proto_tree_add_text(tree, tvb, offset, length, "CBS String: g_iconv_open FAILED contact wireshark"); } break; default: proto_tree_add_text(tree, tvb, offset, length, "Unhandled encoding %d of CBS String", sms_encoding); break; } return tvb_out; }
static int mapi_dissect_element_EcDoRpc_response_(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, dcerpc_info* di, guint8 *drep) { guint32 size; int start_offset = offset; guint8 *decrypted_data; tvbuff_t *decrypted_tvb; const guint8 *ptr; gint reported_len; guint16 pdu_len; guint32 i; proto_tree *tr = NULL; offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, hf_mapi_EcDoRpc_mapi_response, &size); proto_tree_add_uint(tree, hf_mapi_EcDoRpc_subcontext_size, tvb, start_offset, offset - start_offset + size, size); reported_len = tvb_reported_length_remaining(tvb, offset); if ((guint32) reported_len > size) { reported_len = size; } if (size > (guint32) reported_len) { size = reported_len; } ptr = tvb_get_ptr(tvb, offset, size); decrypted_data = (guint8 *)g_malloc(size); for (i = 0; i < size; i++) { decrypted_data[i] = ptr[i] ^ 0xA5; } decrypted_tvb = tvb_new_child_real_data(tvb, decrypted_data, size, reported_len); tvb_set_free_cb(decrypted_tvb, g_free); add_new_data_source(pinfo, decrypted_tvb, "Decrypted MAPI"); tr = proto_tree_add_subtree(tree, decrypted_tvb, 0, size, ett_mapi_mapi_response, NULL, "Decrypted MAPI PDU"); pdu_len = tvb_get_letohs(decrypted_tvb, 0); proto_tree_add_uint(tr, hf_mapi_pdu_len, decrypted_tvb, 0, 2, pdu_len); proto_tree_add_item(tr, hf_mapi_decrypted_data, decrypted_tvb, 2, pdu_len - 2, ENC_NA); /* Analyze contents */ offset = mapi_dissect_element_EcDoRpc_response__(decrypted_tvb, 0, pinfo, tr, di, drep); /* Analyze mapi handles */ offset = mapi_dissect_element_request_handles_cnf(decrypted_tvb, offset, pinfo, tr, di, drep); return start_offset + offset + 4; }
/* The Cisco ITP's packet logging facility allows selected (SS7) MSUs to be * to be encapsulated in syslog UDP datagrams and sent to a monitoring tool. * However, no actual tool to monitor/decode the MSUs is provided. The aim * of this routine is to extract the hex dump of the MSU from the syslog * packet so that it can be passed on to the mtp3 dissector for decoding. */ static tvbuff_t * mtp3_msu_present(tvbuff_t *tvb, packet_info *pinfo, gint fac, gint level, const char *msg_str, gint chars_truncated) { size_t nbytes; size_t len; gchar **split_string, *msu_hex_dump; tvbuff_t *mtp3_tvb = NULL; guint8 *byte_array; /* In the sample capture I have, all MSUs are LOCAL0.DEBUG. * Try to optimize this routine for most syslog users by short-cutting * out here. */ if (!(fac == FAC_LOCAL0 && level == LEVEL_DEBUG)) return NULL; if (strstr(msg_str, "msu=") == NULL) return NULL; split_string = g_strsplit(msg_str, "msu=", 2); msu_hex_dump = split_string[1]; if (msu_hex_dump && (len = strlen(msu_hex_dump))) { /* convert_string_to_hex() will return NULL if it gets an incomplete * byte. If we have an odd string length then chop off the remaining * nibble so we can get at least a partial MSU (chances are the * subdissector will except out, of course). */ if (len % 2) msu_hex_dump[len - 1] = '\0'; byte_array = convert_string_to_hex(msu_hex_dump, &nbytes); if (byte_array) { mtp3_tvb = tvb_new_child_real_data(tvb, byte_array, (guint)nbytes, (guint)nbytes + chars_truncated / 2); tvb_set_free_cb(mtp3_tvb, g_free); /* ...and add the encapsulated MSU as a new data source so that it gets * its own tab in the packet bytes pane. */ add_new_data_source(pinfo, mtp3_tvb, "Encapsulated MSU"); } } g_strfreev(split_string); return(mtp3_tvb); }
static void dissect_kerberos_encrypted_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gssapi_encrypt_info_t* encrypt) { tvbuff_t *kerberos_tvb; gint offset = 0, len; guint8 *data; proto_tree_add_item(tree, hf_multipart_sec_token_len, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; len = tvb_reported_length_remaining(tvb, offset); DISSECTOR_ASSERT(tvb_bytes_exist(tvb, offset, len)); data = (guint8 *) g_malloc(len); tvb_memcpy(tvb, data, offset, len); kerberos_tvb = tvb_new_child_real_data(tvb, data, len, len); tvb_set_free_cb(kerberos_tvb, g_free); add_new_data_source(pinfo, kerberos_tvb, "Kerberos Data"); call_dissector_with_data(gssapi_handle, kerberos_tvb, pinfo, tree, encrypt); }
static void dissect_mime_encap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item* item; guint len; /* XXX, COL_INFO */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MIME_FILE"); item = proto_tree_add_item(tree, proto_mime_encap, tvb, 0, -1, ENC_NA); /* frames with nsec >= 1000000000 means errors :) */ if (pinfo->fd->abs_ts.nsecs >= 1000000000) { proto_item_append_text(item, " (Error)"); /* return; */ /* dissect what we have */ } if (!whole_file) whole_file = g_string_new(""); /* eof? */ if (!(len = tvb_length(tvb))) { tvbuff_t *comp_tvb; proto_item_append_text(item, " (Final)"); comp_tvb = tvb_new_child_real_data(tvb, whole_file->str, (guint) whole_file->len, (gint) whole_file->len); add_new_data_source(pinfo, comp_tvb, "Whole file"); if (!dissector_try_heuristic(heur_subdissector_list, comp_tvb, pinfo, tree)) { proto_item_append_text(item, " (Unhandled)"); call_dissector(data_handle, comp_tvb, pinfo, tree); } } else { if (!pinfo->fd->flags.visited) { g_string_set_size(whole_file, (gsize) pinfo->fd->file_off + len); tvb_memcpy(tvb, whole_file->str + pinfo->fd->file_off, 0, len); } } }
/* * Removes any Markers from this FPDU by using memcpy or throws an out of memory * exception. */ static tvbuff_t * remove_markers(tvbuff_t *tvb, packet_info *pinfo, guint32 marker_offset, guint32 num_markers, guint32 orig_length) { guint8 *mfree_buff = NULL; const guint8 *raw_data_ptr = NULL; guint32 mfree_buff_length, tot_copy, cur_copy; tvbuff_t *mfree_tvb = NULL; DISSECTOR_ASSERT(num_markers > 0); DISSECTOR_ASSERT(orig_length > MPA_MARKER_LEN * num_markers); DISSECTOR_ASSERT(tvb_length(tvb) == orig_length); /* allocate memory for the marker-free buffer */ mfree_buff_length = orig_length - (MPA_MARKER_LEN * num_markers); mfree_buff = g_malloc(mfree_buff_length); if (!mfree_buff) THROW(OutOfMemoryError); raw_data_ptr = tvb_get_ptr(tvb, 0, -1); tot_copy = 0; cur_copy = marker_offset; while (tot_copy < mfree_buff_length) { memcpy(mfree_buff+tot_copy, raw_data_ptr, cur_copy); tot_copy += cur_copy; raw_data_ptr += cur_copy + MPA_MARKER_LEN; cur_copy = MIN(MPA_MARKER_INTERVAL, (mfree_buff_length - tot_copy)); } mfree_tvb = tvb_new_child_real_data(tvb, mfree_buff, mfree_buff_length, mfree_buff_length); tvb_set_free_cb(mfree_tvb, g_free); add_new_data_source(pinfo, mfree_tvb, "FPDU without Markers"); return mfree_tvb; }
static gint dissect_adb_service(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *sub_item; proto_tree *sub_tree; gint offset = 0; adb_service_data_t *adb_service_data = (adb_service_data_t *) data; const guint8 *service; wmem_tree_key_t key[5]; wmem_tree_t *subtree; guint32 i_key; main_item = proto_tree_add_item(tree, proto_adb_service, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_adb_service); DISSECTOR_ASSERT(adb_service_data); service = adb_service_data->service; sub_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service); PROTO_ITEM_SET_GENERATED(sub_item); if (g_strcmp0(service, "host:version") == 0) { guint32 version; guint32 data_length; continuation_data_t *continuation_data; DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 0; key[i_key].key = NULL; subtree = (wmem_tree_t *) wmem_tree_lookup32_array(continuation_infos, key); continuation_data = (subtree) ? (continuation_data_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL; if (continuation_data && continuation_data->completed_in_frame < pinfo->num) continuation_data = NULL; if (!continuation_data || (continuation_data && continuation_data->length_in_frame == pinfo->num)) offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); if (!pinfo->fd->flags.visited && !continuation_data && tvb_reported_length_remaining(tvb, offset) < 4) { key[i_key].length = 1; key[i_key++].key = &pinfo->num; key[i_key].length = 0; key[i_key].key = NULL; continuation_data = wmem_new(wmem_file_scope(), continuation_data_t); continuation_data->length_in_frame = pinfo->num; continuation_data->completed_in_frame = G_MAXUINT32; continuation_data->length = data_length; wmem_tree_insert32_array(continuation_infos, key, continuation_data); continuation_data = NULL; } if (tvb_reported_length_remaining(tvb, offset) >= 4 || (continuation_data && continuation_data->completed_in_frame == pinfo->num)) { if (!pinfo->fd->flags.visited && continuation_data) { continuation_data->completed_in_frame = pinfo->num; } offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_version, ett_version, hf_version, tvb, offset, &version); col_append_fstr(pinfo->cinfo, COL_INFO, " Version=%u", version); } } else if (g_strcmp0(service, "host:devices") == 0 || g_strcmp0(service, "host:devices-l") == 0 || g_strcmp0(service, "host:track-devices") == 0) { guint32 data_length; offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); sub_item = proto_tree_add_item(main_tree, hf_devices, tvb, offset, -1, ENC_NA | ENC_ASCII); if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) { expert_add_info(pinfo, sub_item, &ei_incomplete_message); } } else if (g_strcmp0(service, "host:get-state") == 0 || g_strcmp0(service, "host:get-serialno") == 0 || g_strcmp0(service, "host:get-devpath") == 0 || g_str_has_prefix(service, "connect:") || g_str_has_prefix(service, "disconnect:")) { guint32 data_length; offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); sub_item = proto_tree_add_item(main_tree, hf_result, tvb, offset, -1, ENC_NA | ENC_ASCII); if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) { expert_add_info(pinfo, sub_item, &ei_incomplete_message); } } else if (g_str_has_prefix(service, "framebuffer:")) { framebuffer_data_t *framebuffer_data = NULL; DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 0; key[i_key].key = NULL; subtree = (wmem_tree_t *) wmem_tree_lookup32_array(framebuffer_infos, key); framebuffer_data = (subtree) ? (framebuffer_data_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL; if (framebuffer_data && framebuffer_data->completed_in_frame < pinfo->num) framebuffer_data = NULL; if (!pinfo->fd->flags.visited && !framebuffer_data) { key[i_key].length = 1; key[i_key++].key = &pinfo->num; key[i_key].length = 0; key[i_key].key = NULL; framebuffer_data = wmem_new(wmem_file_scope(), framebuffer_data_t); framebuffer_data->data_in = pinfo->num; framebuffer_data->current_size = 0; framebuffer_data->completed_in_frame = G_MAXUINT32; framebuffer_data->size = tvb_get_letohl(tvb, offset + 4 * 2); framebuffer_data->red_offset = tvb_get_letohl(tvb, offset + 4 * 5); framebuffer_data->red_length = tvb_get_letohl(tvb, offset + 4 * 6); framebuffer_data->green_offset = tvb_get_letohl(tvb, offset + 4 * 7); framebuffer_data->green_length = tvb_get_letohl(tvb, offset + 4 * 8); framebuffer_data->blue_offset = tvb_get_letohl(tvb, offset + 4 * 9); framebuffer_data->blue_length = tvb_get_letohl(tvb, offset + 4 * 10); framebuffer_data->alpha_offset = tvb_get_letohl(tvb, offset + 4 * 11); framebuffer_data->alpha_length = tvb_get_letohl(tvb, offset + 4 * 12); wmem_tree_insert32_array(framebuffer_infos, key, framebuffer_data); } if (framebuffer_data && framebuffer_data->data_in == pinfo->num) { proto_tree_add_item(main_tree, hf_framebuffer_version, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_depth, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_width, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_height, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_red_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_red_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_blue_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_blue_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_green_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_green_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_alpha_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_alpha_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; } if (tvb_reported_length_remaining(tvb, offset) > 0) { sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); sub_tree = proto_item_add_subtree(sub_item, ett_data); if (!pinfo->fd->flags.visited && framebuffer_data) { framebuffer_data->current_size += tvb_captured_length_remaining(tvb, offset); if (framebuffer_data->current_size >= framebuffer_data->size) framebuffer_data->completed_in_frame = pinfo->num; } if (pref_dissect_more_detail_framebuffer) { proto_item *pixel_item; proto_tree *pixel_tree; if (framebuffer_data && framebuffer_data->red_length == 5 && framebuffer_data->green_length == 6 && framebuffer_data->blue_length == 5 && framebuffer_data->red_offset == 11 && framebuffer_data->green_offset == 5 && framebuffer_data->blue_offset == 0) { while (tvb_reported_length_remaining(tvb, offset) > 0) { if (tvb_reported_length_remaining(tvb, offset) < 2) { proto_tree_add_item(main_tree, hf_fragment, tvb, offset, -1, ENC_NA); offset += 1; } pixel_item = proto_tree_add_item(sub_tree, hf_framebuffer_pixel, tvb, offset, 2, ENC_NA); pixel_tree = proto_item_add_subtree(pixel_item, ett_pixel); proto_tree_add_item(pixel_tree, hf_framebuffer_blue_5, tvb, offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_green_6, tvb, offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_red_5, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; } } else if (framebuffer_data && framebuffer_data->red_length == 8 && framebuffer_data->green_length == 8 && framebuffer_data->blue_length == 8 && (framebuffer_data->alpha_length == 0 || framebuffer_data->alpha_length == 8)) { while (tvb_reported_length_remaining(tvb, offset) > 0) { if (tvb_reported_length_remaining(tvb, offset) < 3 || (tvb_reported_length_remaining(tvb, offset) < 4 && framebuffer_data->alpha_offset > 0)) { proto_tree_add_item(main_tree, hf_fragment, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); break; } pixel_item = proto_tree_add_item(sub_tree, hf_framebuffer_pixel, tvb, offset, 3, ENC_NA); pixel_tree = proto_item_add_subtree(pixel_item, ett_pixel); proto_tree_add_item(pixel_tree, hf_framebuffer_red, tvb, offset + framebuffer_data->red_offset / 8, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_green, tvb, offset + framebuffer_data->green_offset / 8, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_blue, tvb, offset + framebuffer_data->blue_offset / 8, 1, ENC_LITTLE_ENDIAN); if (framebuffer_data->alpha_offset > 0) { if (framebuffer_data->alpha_length == 0) proto_tree_add_item(pixel_tree, hf_framebuffer_unused, tvb, offset + framebuffer_data->alpha_offset / 8, 1, ENC_LITTLE_ENDIAN); else proto_tree_add_item(pixel_tree, hf_framebuffer_alpha, tvb, offset + framebuffer_data->alpha_offset / 8, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_item_set_len(pixel_item, 4); } offset += 3; } } else { offset = tvb_captured_length(tvb); } } else { offset = tvb_captured_length(tvb); } } } else if (g_strcmp0(service, "track-jdwp") == 0) { guint32 data_length; offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); if (tvb_reported_length_remaining(tvb, offset) > 0) { sub_item = proto_tree_add_item(main_tree, hf_pids, tvb, offset, -1, ENC_NA | ENC_ASCII); if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) { expert_add_info(pinfo, sub_item, &ei_incomplete_message); } } offset = tvb_captured_length(tvb); } else if ((g_strcmp0(service, "shell:export ANDROID_LOG_TAGS=\"\" ; exec logcat -B") == 0) || (g_strcmp0(service, "shell:logcat -B") == 0)) { tvbuff_t *next_tvb; tvbuff_t *new_tvb; guint8 *buffer = NULL; gint size = 0; gint i_offset = offset; gint old_offset; gint i_char = 0; guint8 c1; guint8 c2 = '\0'; guint16 payload_length; guint16 try_header_size; gint logcat_length = 0; fragment_t *fragment; DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 0; key[i_key].key = NULL; subtree = (wmem_tree_t *) wmem_tree_lookup32_array(fragments, key); fragment = (subtree) ? (fragment_t *) wmem_tree_lookup32_le(subtree, pinfo->num - 1) : NULL; if (fragment) { if (!pinfo->fd->flags.visited && fragment->reassembled_in_frame == -1) fragment->reassembled_in_frame = pinfo->num; if (fragment->reassembled_in_frame == pinfo->num) { size += fragment->length; i_char += fragment->length; } } size += tvb_reported_length_remaining(tvb, i_offset); if (size > 0) { buffer = (guint8 *) wmem_alloc(pinfo->pool, size); if (fragment && i_char > 0) memcpy(buffer, fragment->data, i_char); if (i_char >= 1 && buffer[i_char - 1] == '\r' && tvb_get_guint8(tvb, i_offset) == '\n') { buffer[i_char - 1] = '\n'; i_offset += 1; } c1 = tvb_get_guint8(tvb, i_offset); i_offset += 1; old_offset = i_offset; while (tvb_reported_length_remaining(tvb, i_offset) > 0) { c2 = tvb_get_guint8(tvb, i_offset); if (c1 == '\r' && c2 == '\n') { buffer[i_char] = c2; if (tvb_reported_length_remaining(tvb, i_offset) > 1) { c1 = tvb_get_guint8(tvb, i_offset + 1); i_offset += 2; i_char += 1; } else { i_offset += 1; } continue; } buffer[i_char] = c1; c1 = c2; i_char += 1; i_offset += 1; } if (tvb_reported_length_remaining(tvb, old_offset) == 0) { buffer[i_char] = c1; i_char += 1; } else if (tvb_reported_length_remaining(tvb, old_offset) > 0) { buffer[i_char] = c2; i_char += 1; } next_tvb = tvb_new_child_real_data(tvb, buffer, i_char, i_char); add_new_data_source(pinfo, next_tvb, "Logcat"); i_offset = 0; while (tvb_reported_length_remaining(next_tvb, i_offset) > 0) { if (tvb_reported_length_remaining(next_tvb, i_offset) >= 4) { payload_length = tvb_get_letohs(next_tvb, i_offset); try_header_size = tvb_get_letohs(next_tvb, i_offset + 2); if (try_header_size != 24) logcat_length = payload_length + 20; else logcat_length = payload_length + 24; } if (tvb_reported_length_remaining(next_tvb, i_offset) >= 4 && tvb_reported_length_remaining(next_tvb, i_offset) >= logcat_length) { new_tvb = tvb_new_subset_length(next_tvb, i_offset, logcat_length); call_dissector(logcat_handle, new_tvb, pinfo, main_tree); i_offset += logcat_length; } else { if (!pinfo->fd->flags.visited) { DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 2 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 1; key[i_key++].key = &pinfo->num; key[i_key].length = 0; key[i_key].key = NULL; fragment = wmem_new(wmem_file_scope(), fragment_t); fragment->length = tvb_captured_length_remaining(next_tvb, i_offset); fragment->data = (guint8 *) wmem_alloc(wmem_file_scope(), fragment->length); tvb_memcpy(next_tvb, fragment->data, i_offset, fragment->length); fragment->reassembled_in_frame = -1; wmem_tree_insert32_array(fragments, key, fragment); } proto_tree_add_item(main_tree, hf_fragment, next_tvb, i_offset, -1, ENC_NA); i_offset = tvb_captured_length(next_tvb); } } } offset = tvb_captured_length(tvb); } else if (g_str_has_prefix(service, "shell:")) { if (adb_service_data->direction == P2P_DIR_SENT) { proto_tree_add_item(main_tree, hf_stdin, tvb, offset, -1, ENC_NA | ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " Stdin=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset))); } else { proto_tree_add_item(main_tree, hf_stdout, tvb, offset, -1, ENC_NA | ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " Stdout=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset))); } offset = tvb_captured_length(tvb); } else if (g_str_has_prefix(service, "jdwp:")) { /* TODO */ proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); } else if (g_str_has_prefix(service, "sync:")) { /* TODO */ proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); } else if (g_strcmp0(service, "host:list-forward") == 0 || g_str_has_prefix(service, "root:") || g_str_has_prefix(service, "remount:") || g_str_has_prefix(service, "tcpip:") || g_str_has_prefix(service, "usb:")) { if (tvb_reported_length_remaining(tvb, offset)) { proto_tree_add_item(main_tree, hf_result, tvb, offset, -1, ENC_NA | ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " Result=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset))); offset = tvb_captured_length(tvb); } } else { proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); } return offset; }
int PBE_decrypt_data(const char *object_identifier_id_param, tvbuff_t *encrypted_tvb, asn1_ctx_t *actx, proto_item *item) { #ifdef HAVE_LIBGCRYPT const char *encryption_algorithm; gcry_cipher_hd_t cipher; gcry_error_t err; int algo; int mode; int ivlen = 0; int keylen = 0; int datalen = 0; char *key = NULL; char *iv = NULL; char *clear_data = NULL; tvbuff_t *clear_tvb = NULL; const gchar *oidname; GString *name; proto_tree *tree; char byte; gboolean decrypt_ok = TRUE; if(((password == NULL) || (*password == '\0')) && (try_null_password == FALSE)) { /* we are not configured to decrypt */ return FALSE; } encryption_algorithm = x509af_get_last_algorithm_id(); /* these are the only encryption schemes we understand for now */ if(!strcmp(encryption_algorithm, PKCS12_PBE_3DES_SHA1_OID)) { ivlen = 8; keylen = 24; algo = GCRY_CIPHER_3DES; mode = GCRY_CIPHER_MODE_CBC; } else if(!strcmp(encryption_algorithm, PKCS12_PBE_ARCFOUR_SHA1_OID)) { ivlen = 0; keylen = 16; algo = GCRY_CIPHER_ARCFOUR; mode = GCRY_CIPHER_MODE_NONE; } else if(!strcmp(encryption_algorithm, PKCS12_PBE_RC2_40_SHA1_OID)) { ivlen = 8; keylen = 5; algo = GCRY_CIPHER_RFC2268_40; mode = GCRY_CIPHER_MODE_CBC; } else { /* we don't know how to decrypt this */ proto_item_append_text(item, " [Unsupported encryption algorithm]"); return FALSE; } if((iteration_count == 0) || (salt == NULL)) { proto_item_append_text(item, " [Insufficient parameters]"); return FALSE; } /* allocate buffers */ key = ep_alloc(keylen); if(!generate_key_or_iv(1 /*LEY */, salt, iteration_count, password, keylen, key)) return FALSE; if(ivlen) { iv = ep_alloc(ivlen); if(!generate_key_or_iv(2 /* IV */, salt, iteration_count, password, ivlen, iv)) return FALSE; } /* now try an internal function */ err = gcry_cipher_open(&cipher, algo, mode, 0); if (gcry_err_code (err)) return FALSE; err = gcry_cipher_setkey (cipher, key, keylen); if (gcry_err_code (err)) { gcry_cipher_close (cipher); return FALSE; } if(ivlen) { err = gcry_cipher_setiv (cipher, iv, ivlen); if (gcry_err_code (err)) { gcry_cipher_close (cipher); return FALSE; } } datalen = tvb_length(encrypted_tvb); clear_data = g_malloc(datalen); err = gcry_cipher_decrypt (cipher, clear_data, datalen, tvb_get_ephemeral_string(encrypted_tvb, 0, datalen), datalen); if (gcry_err_code (err)) { proto_item_append_text(item, " [Failed to decrypt with password preference]"); gcry_cipher_close (cipher); g_free(clear_data); return FALSE; } gcry_cipher_close (cipher); /* We don't know if we have successfully decrypted the data or not so we: a) check the trailing bytes b) see if we start with a sequence or a set (is this too constraining? */ /* first the trailing bytes */ byte = clear_data[datalen-1]; if(byte <= 0x08) { int i; for(i = (int)byte; i > 0 ; i--) { if(clear_data[datalen - i] != byte) { decrypt_ok = FALSE; break; } } } else { /* XXX: is this a failure? */ } /* we assume the result is ASN.1 - check it is a SET or SEQUENCE */ byte = clear_data[0]; if((byte != 0x30) && (byte != 0x31)) { /* do we need more here? OCTET STRING? */ decrypt_ok = FALSE; } if(!decrypt_ok) { g_free(clear_data); proto_item_append_text(item, " [Failed to decrypt with supplied password]"); return FALSE; } proto_item_append_text(item, " [Decrypted successfully]"); tree = proto_item_add_subtree(item, ett_decrypted_pbe); /* OK - so now clear_data contains the decrypted data */ clear_tvb = tvb_new_child_real_data(encrypted_tvb,(const guint8 *)clear_data, datalen, datalen); tvb_set_free_cb(clear_tvb, g_free); name = g_string_new(""); oidname = oid_resolved_from_string(object_identifier_id_param); g_string_printf(name, "Decrypted %s", oidname ? oidname : object_identifier_id_param); /* add it as a new source */ add_new_data_source(actx->pinfo, clear_tvb, name->str); g_string_free(name, TRUE); /* now try and decode it */ call_ber_oid_callback(object_identifier_id_param, clear_tvb, 0, actx->pinfo, tree); return TRUE; #else /* we cannot decrypt */ return FALSE; #endif }
static void dissect_payload_kink_encrypt(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_encrypt_tree; proto_item *ti; guint8 next_payload; guint8 reserved; guint payload_length; gint encrypt_length; guint8 inner_next_pload; guint32 reserved2; guint16 inner_payload_length; int start_payload_offset = 0; /* Keep the begining of the payload offset */ payload_length = tvb_get_ntohs(tvb,offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; encrypt_length = payload_length - FROM_NP_TO_PL; /* Make the subtree */ ti = proto_tree_add_text(tree, tvb, offset, payload_length,"KINK_ENCRYPT"); payload_kink_encrypt_tree = proto_item_add_subtree(ti, ett_payload_kink_encrypt); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_encrypt_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; reserved = tvb_get_guint8(tvb, offset); proto_tree_add_text(payload_kink_encrypt_tree, tvb, offset, 1, "RESERVED: %u", reserved); offset ++; if(payload_length <= PAYLOAD_HEADER){ proto_tree_add_text(payload_kink_encrypt_tree, tvb, offset, 2, "This Payload Length is too small.: %u", payload_length); } else{ proto_tree_add_text(payload_kink_encrypt_tree, tvb, offset, 2, "Payload Length: %u", payload_length); } offset += 2; /* decrypt kink encrypt */ if(keytype != 0){ #ifdef HAVE_KERBEROS tvbuff_t *next_tvb; guint8 *plaintext=NULL; next_tvb=tvb_new_subset(tvb, offset, MIN(tvb_length_remaining(tvb, offset), encrypt_length), encrypt_length); plaintext=decrypt_krb5_data(tree, pinfo, 0, next_tvb, keytype, NULL); if(plaintext){ next_tvb=tvb_new_child_real_data(tvb, plaintext, encrypt_length, encrypt_length); add_new_data_source(pinfo, next_tvb, "decrypted kink encrypt"); dissect_decrypt_kink_encrypt(pinfo, next_tvb, tree, encrypt_length); } #endif } else{ inner_next_pload = tvb_get_guint8(tvb, offset); proto_tree_add_text(payload_kink_encrypt_tree, tvb, offset, 1, "InnerNextPload: %u", inner_next_pload); offset += 1; reserved2 = 65536*tvb_get_guint8(tvb, offset) + 256*tvb_get_guint8(tvb, offset+1) + tvb_get_guint8(tvb, offset+2); proto_tree_add_text(payload_kink_encrypt_tree, tvb, offset, 3, "RESERVED: %u", reserved2); offset += 3; if(payload_length > PAYLOAD_HEADER){ inner_payload_length = payload_length - PAYLOAD_HEADER; proto_tree_add_text(payload_kink_encrypt_tree, tvb, offset, inner_payload_length, "Payload"); offset += inner_payload_length; } } /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING !=0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } }
static gint dissect_adb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *arg0_item; proto_tree *arg0_tree; proto_item *arg1_item; proto_tree *arg1_tree; proto_item *magic_item; proto_item *crc_item; proto_tree *crc_tree = NULL; proto_item *sub_item; gint offset = 0; guint32 command; guint32 arg0; guint32 arg1; guint32 data_length = 0; guint32 crc32 = 0; usb_conv_info_t *usb_conv_info = NULL; wmem_tree_key_t key[5]; guint32 interface_id; guint32 bus_id; guint32 device_address; guint32 side_id; guint32 frame_number; gboolean is_command = TRUE; gboolean is_next_fragment = FALSE; gboolean is_service = FALSE; gint proto; gint direction = P2P_DIR_UNKNOWN; wmem_tree_t *wmem_tree; command_data_t *command_data = NULL; service_data_t *service_data = NULL; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ADB"); col_clear(pinfo->cinfo, COL_INFO); main_item = proto_tree_add_item(tree, proto_adb, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_adb); frame_number = pinfo->fd->num; /* XXX: Why? If interface is USB only first try is correct * (and seems strange...), in other cases standard check for * previous protocol is correct */ proto = (gint) GPOINTER_TO_INT(wmem_list_frame_data(/*wmem_list_frame_prev*/(wmem_list_tail(pinfo->layers)))); if (proto != proto_usb) { proto = (gint) GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo->layers)))); } if (proto == proto_usb) { usb_conv_info = (usb_conv_info_t *) data; DISSECTOR_ASSERT(usb_conv_info); direction = usb_conv_info->direction; } else if (proto == proto_tcp) { if (pinfo->destport == ADB_TCP_PORT) direction = P2P_DIR_SENT; else direction = P2P_DIR_RECV; } else { return offset; } if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID) interface_id = pinfo->phdr->interface_id; else interface_id = 0; if (proto == proto_usb) { bus_id = usb_conv_info->bus_id; device_address = usb_conv_info->device_address; key[0].length = 1; key[0].key = &interface_id; key[1].length = 1; key[1].key = &bus_id; key[2].length = 1; key[2].key = &device_address; key[3].length = 0; key[3].key = NULL; } else { /* tcp */ key[0].length = 1; key[0].key = &interface_id; key[1].length = 1; key[2].length = 1; if (direction == P2P_DIR_SENT) { key[1].key = &pinfo->srcport; key[2].key = &pinfo->destport; } else { key[1].key = &pinfo->destport; key[2].key = &pinfo->srcport; } key[3].length = 0; key[3].key = NULL; } wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key); if (wmem_tree) { command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number); if (command_data && command_data->completed_in_frame >= frame_number && command_data->command_in_frame <= frame_number) { if (command_data->command_in_frame != frame_number) { is_command = FALSE; is_next_fragment = TRUE; } data_length = command_data->data_length; crc32 = command_data->crc32; if (direction == P2P_DIR_SENT) if (command_data->command == A_CLSE) side_id = command_data->arg1; /* OUT: local id */ else side_id = command_data->arg0; /* OUT: local id */ else if (command_data->command == A_OKAY) { side_id = command_data->arg1; /* IN: remote id */ } else side_id = command_data->arg1; /* IN: remote id */ key[3].length = 1; key[3].key = &side_id; key[4].length = 0; key[4].key = NULL; wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(service_info, key); if (wmem_tree) { service_data = (service_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number); if (service_data && command_data->command == A_OPEN) { is_service = TRUE; } } } } /* Simple heuristics to check if packet is command or data */ if ((command_data && command_data->completed_in_frame <= frame_number) || !command_data) { if (tvb_reported_length(tvb) < 24) { is_command = FALSE; } else if (tvb_reported_length(tvb) >= 24) { command = tvb_get_letohl(tvb, offset); if (command != A_SYNC && command != A_CLSE && command != A_WRTE && command != A_AUTH && command != A_CNXN && command != A_OPEN && command != A_OKAY) is_command = FALSE; else if (command != (0xFFFFFFFF ^ tvb_get_letohl(tvb, offset + 20))) is_command = FALSE; if (is_command) { data_length = tvb_get_letohl(tvb, offset + 12); crc32 = tvb_get_letohl(tvb, offset + 16); } if (command == A_OPEN) is_service = TRUE; } } if (service_data && !(command_data->command == A_OPEN && is_next_fragment)) { sub_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service_data->service); PROTO_ITEM_SET_GENERATED(sub_item); } if (service_data) { sub_item = proto_tree_add_uint(main_tree, hf_service_start_in_frame, tvb, offset, 0, service_data->start_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); if (service_data->close_local_in_frame < max_in_frame) { sub_item = proto_tree_add_uint(main_tree, hf_close_local_in_frame, tvb, offset, 0, service_data->close_local_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } if (service_data->close_remote_in_frame < max_in_frame) { sub_item = proto_tree_add_uint(main_tree, hf_close_remote_in_frame, tvb, offset, 0, service_data->close_remote_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } } if (is_command) { proto_tree_add_item(main_tree, hf_command, tvb, offset, 4, ENC_LITTLE_ENDIAN); command = tvb_get_letohl(tvb, offset); offset += 4; col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(command, command_vals, "Unknown command")); arg0_item = proto_tree_add_item(main_tree, hf_argument_0, tvb, offset, 4, ENC_LITTLE_ENDIAN); arg0_tree = proto_item_add_subtree(arg0_item, ett_adb_arg0); arg0 = tvb_get_letohl(tvb, offset); offset += 4; arg1_item = proto_tree_add_item(main_tree, hf_argument_1, tvb, offset, 4, ENC_LITTLE_ENDIAN); arg1_tree = proto_item_add_subtree(arg1_item, ett_adb_arg1); arg1 = tvb_get_letohl(tvb, offset); offset += 4; switch (command) { case A_CNXN: proto_tree_add_item(arg0_tree, hf_version, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_max_data, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(version=%u.%u.%u, max_data=%u)", tvb_get_guint8(tvb, offset - 5), tvb_get_guint8(tvb, offset - 6), tvb_get_letohs(tvb, offset - 7), tvb_get_letohl(tvb, offset - 4)); break; case A_AUTH: proto_tree_add_item(arg0_tree, hf_auth_type, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_zero, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(type=%s, 0)", val_to_str_const(tvb_get_letohl(tvb, offset - 8), auth_type_vals, "Unknown")); break; case A_OPEN: proto_tree_add_item(arg0_tree, hf_local_id, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_zero, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(local=%u, 0)", tvb_get_letohl(tvb, offset - 8)); break; case A_WRTE: proto_tree_add_item(arg0_tree, hf_zero, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_remote_id, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(0, remote=%u)", tvb_get_letohl(tvb, offset - 4)); break; case A_CLSE: case A_OKAY: proto_tree_add_item(arg0_tree, hf_local_id, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_remote_id, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(local=%u, remote=%u)", tvb_get_letohl(tvb, offset - 8), tvb_get_letohl(tvb, offset - 4)); break; case A_SYNC: proto_tree_add_item(arg0_tree, hf_online, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_sequence, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(online=%s, sequence=%u)", tvb_get_letohl(tvb, offset - 8) ? "Yes": "No", tvb_get_letohl(tvb, offset - 4)); break; } proto_tree_add_item(main_tree, hf_data_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; if (data_length > 0) col_append_fstr(pinfo->cinfo, COL_INFO, " length=%u ", data_length); crc_item = proto_tree_add_item(main_tree, hf_data_crc32, tvb, offset, 4, ENC_LITTLE_ENDIAN); crc_tree = proto_item_add_subtree(crc_item, ett_adb_crc); crc32 = tvb_get_letohl(tvb, offset); offset += 4; magic_item = proto_tree_add_item(main_tree, hf_magic, tvb, offset, 4, ENC_LITTLE_ENDIAN); if ((tvb_get_letohl(tvb, offset) ^ 0xFFFFFFFF) != command) { proto_tree *expert_tree; expert_tree = proto_item_add_subtree(magic_item, ett_adb_magic); proto_tree_add_expert(expert_tree, pinfo, &ei_invalid_magic, tvb, offset, 4); } if (!pinfo->fd->flags.visited) save_command(command, arg0, arg1, data_length, crc32, service_data, proto, data, pinfo, &service_data, &command_data); offset += 4; } if (!pinfo->fd->flags.visited && command_data) { if (command_data->command_in_frame != frame_number) { is_command = FALSE; is_next_fragment = TRUE; } data_length = command_data->data_length; crc32 = command_data->crc32; if ((command_data->command_in_frame != frame_number && tvb_captured_length(tvb) == data_length) || (command_data->command_in_frame == frame_number && tvb_captured_length(tvb) == data_length + 24) ) { command_data->reassemble_data_length = command_data->data_length; command_data->completed_in_frame = frame_number; } } if (is_next_fragment && command_data) { sub_item = proto_tree_add_uint(main_tree, hf_command_in_frame, tvb, offset, 0, command_data->command_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); sub_item = proto_tree_add_uint(main_tree, hf_command, tvb, offset, 0, command_data->command); PROTO_ITEM_SET_GENERATED(sub_item); sub_item = proto_tree_add_uint(main_tree, hf_data_length, tvb, offset, 0, command_data->data_length); PROTO_ITEM_SET_GENERATED(sub_item); crc_item = proto_tree_add_uint(main_tree, hf_data_crc32, tvb, offset, 0, command_data->crc32); crc_tree = proto_item_add_subtree(crc_item, ett_adb_crc); PROTO_ITEM_SET_GENERATED(crc_item); } if (command_data && command_data->completed_in_frame != frame_number) { sub_item = proto_tree_add_uint(main_tree, hf_completed_in_frame, tvb, offset, 0, command_data->completed_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } if (tvb_captured_length_remaining(tvb, offset) > 0 && (!is_command || data_length > 0)) { guint32 crc = 0; guint32 i_offset; if ((!pinfo->fd->flags.visited && command_data && command_data->reassemble_data_length < command_data->data_length) || data_length > (guint32) tvb_captured_length_remaining(tvb, offset)) { /* need reassemble */ if (!pinfo->fd->flags.visited && command_data && command_data->reassemble_data_length < command_data->data_length) { tvb_memcpy(tvb, command_data->reassemble_data + command_data->reassemble_data_length, offset, tvb_captured_length_remaining(tvb, offset)); command_data->reassemble_data_length += tvb_captured_length_remaining(tvb, offset); if (command_data->reassemble_data_length >= command_data->data_length) command_data->completed_in_frame = frame_number; } proto_tree_add_item(main_tree, hf_data_fragment, tvb, offset, -1, ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Data Fragment"); offset = tvb_captured_length(tvb); if (service_data && command_data && command_data->reassemble_data_length >= command_data->data_length && frame_number == command_data->completed_in_frame) { tvbuff_t *next_tvb; adb_service_data_t adb_service_data; next_tvb = tvb_new_child_real_data(tvb, command_data->reassemble_data, command_data->reassemble_data_length, command_data->reassemble_data_length); add_new_data_source(pinfo, next_tvb, "ADB Reassembled Data"); adb_service_data.service = service_data->service; adb_service_data.direction = direction; adb_service_data.session_key_length = 3; adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32)); adb_service_data.session_key[0] = interface_id; if (proto == proto_usb) { adb_service_data.session_key[1] = usb_conv_info->bus_id; adb_service_data.session_key[2] = usb_conv_info->device_address; } else { /* tcp */ if (direction == P2P_DIR_SENT) { adb_service_data.session_key[1] = pinfo->srcport; adb_service_data.session_key[2] = pinfo->destport; } else { adb_service_data.session_key[1] = pinfo->destport; adb_service_data.session_key[2] = pinfo->srcport; } } call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data); } } else { /* full message */ for (i_offset = 0; i_offset < data_length; ++i_offset) crc += tvb_get_guint8(tvb, offset + i_offset); if (crc32 > 0 && crc32 != crc) proto_tree_add_expert(crc_tree, pinfo, &ei_invalid_crc, tvb, offset, -1); if (is_service) { proto_tree_add_item(main_tree, hf_service, tvb, offset, -1, ENC_ASCII | ENC_NA); if (!pinfo->fd->flags.visited && service_data) { service_data->service = tvb_get_stringz_enc(wmem_file_scope(), tvb, offset, NULL, ENC_ASCII); } col_append_fstr(pinfo->cinfo, COL_INFO, "Service: %s", tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, NULL, ENC_ASCII)); offset = tvb_captured_length(tvb); } else if (command_data && command_data->command == A_CNXN) { gchar *info; gint len; info = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &len, ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, "Connection Info: %s", info); proto_tree_add_item(main_tree, hf_connection_info, tvb, offset, len, ENC_ASCII | ENC_NA); offset += len; } else { col_append_str(pinfo->cinfo, COL_INFO, "Data"); /* Decode service payload */ if (service_data) { tvbuff_t *next_tvb; adb_service_data_t adb_service_data; adb_service_data.service = service_data->service; adb_service_data.direction = direction; adb_service_data.session_key_length = 3; adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32)); adb_service_data.session_key[0] = interface_id; if (proto == proto_usb) { adb_service_data.session_key[1] = usb_conv_info->bus_id; adb_service_data.session_key[2] = usb_conv_info->device_address; } else { /* tcp */ if (direction == P2P_DIR_SENT) { adb_service_data.session_key[1] = pinfo->srcport; adb_service_data.session_key[2] = pinfo->destport; } else { adb_service_data.session_key[1] = pinfo->destport; adb_service_data.session_key[2] = pinfo->srcport; } } next_tvb = tvb_new_subset(tvb, offset, tvb_captured_length_remaining(tvb, offset), tvb_captured_length_remaining(tvb, offset)); call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data); } else { proto_item *data_item; gchar *data_str; data_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, data_length, ENC_NA); data_str = tvb_format_text(tvb, offset, data_length); proto_item_append_text(data_item, ": %s", data_str); col_append_fstr(pinfo->cinfo, COL_INFO, " Raw: %s", data_str); } offset = tvb_captured_length(tvb); } } } return offset; }
/*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 */
static tvbuff_t * dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint32 findex, guint32 fcount, guint16 seq, gint offset, guint16 plen, gboolean fec _U_, guint16 rsk, guint16 rsz, fragment_data *fdx ) { guint16 decoded_size; guint32 c_max; guint32 rx_min; gboolean first, last; tvbuff_t *new_tvb=NULL; if (fcount > MAX_FRAGMENTS) { if (tree) proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", fcount); return NULL; } first = findex == 0; last = fcount == (findex+1); decoded_size = fcount*plen; c_max = fcount*plen/(rsk+PFT_RS_P); /* rounded down */ rx_min = c_max*rsk/plen; if(rx_min*plen<c_max*rsk) rx_min++; if (fdx) new_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled DCP (ETSI)", fdx, &dcp_frag_items, NULL, tree); else { guint fragments=0; guint32 *got; fragment_data *fd; fragment_data *fd_head; if(tree) proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d", fcount, fragments, rx_min ); got = ep_alloc(fcount*sizeof(guint32)); /* make a list of the findex (offset) numbers of the fragments we have */ fd = fragment_get(pinfo, seq, dcp_fragment_table); for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) { if(fd_head->data) { got[fragments++] = fd_head->offset; /* this is the findex of the fragment */ } } /* put a sentinel at the end */ got[fragments++] = fcount; /* have we got enough for Reed Solomon to try to correct ? */ if(fragments>=rx_min) { /* yes, in theory */ guint i,current_findex; fragment_data *frag=NULL; guint8 *dummy_data = (guint8*) ep_alloc0 (plen); tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen); /* try and decode with missing fragments */ if(tree) proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d", fcount, fragments, rx_min ); /* fill the fragment table with empty fragments */ current_findex = 0; for(i=0; i<fragments; i++) { guint next_fragment_we_have = got[i]; if (next_fragment_we_have > MAX_FRAGMENTS) { if (tree) proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", next_fragment_we_have); return NULL; } for(; current_findex<next_fragment_we_have; current_findex++) { frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq, dcp_fragment_table, dcp_reassembled_table, current_findex, plen, (current_findex+1!=fcount)); } current_findex++; /* skip over the fragment we have */ } if(frag) new_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled DCP (ETSI)", frag, &dcp_frag_items, NULL, tree); } } if(new_tvb) { gboolean decoded = TRUE; tvbuff_t *dtvb = NULL; const guint8 *input = tvb_get_ptr(new_tvb, 0, -1); guint16 reassembled_size = tvb_length(new_tvb); guint8 *deinterleaved = (guint8*) g_malloc (reassembled_size); guint8 *output = (guint8*) g_malloc (decoded_size); rs_deinterleave(input, deinterleaved, plen, fcount); dtvb = tvb_new_child_real_data(tvb, deinterleaved, reassembled_size, reassembled_size); add_new_data_source(pinfo, dtvb, "Deinterleaved"); tvb_set_free_cb(dtvb, g_free); decoded = rs_correct_data(deinterleaved, output, c_max, rsk, rsz); if(tree) proto_tree_add_boolean (tree, hf_edcp_rs_ok, tvb, offset, 2, decoded); new_tvb = tvb_new_child_real_data(dtvb, output, decoded_size, decoded_size); add_new_data_source(pinfo, new_tvb, "RS Error Corrected Data"); tvb_set_free_cb(new_tvb, g_free); } return new_tvb; }
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_reported_length(tvb); reversing_buffer = (guint8 *)tvb_memdup(NULL, tvb, offset, len); bitswap_buf_inplace(reversing_buffer, len); /* 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); tvb_set_free_cb(bit_reversed_tvb, g_free); 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);
static int dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_verifier) { proto_item *volatile item; proto_tree *volatile subtree; volatile int return_offset = 0; gssapi_conv_info_t *volatile gss_info; gssapi_oid_value *oidvalue; dissector_handle_t handle; conversation_t *conversation; tvbuff_t *oid_tvb; int len, start_offset, oid_start_offset; volatile int offset; gint8 appclass; gboolean pc, ind_field; gint32 tag; guint32 len1; const char *oid; fragment_data *fd_head=NULL; gssapi_frag_info_t *fi; tvbuff_t *volatile gss_tvb=NULL; asn1_ctx_t asn1_ctx; void *pd_save; start_offset=0; offset=0; asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo); /* * We don't know whether the data is encrypted, so say it's * not, for now. The subdissector must set gssapi_data_encrypted * if it is. */ pinfo->gssapi_data_encrypted = FALSE; /* * We need a conversation for later */ conversation = find_or_create_conversation(pinfo); gss_info = (gssapi_conv_info_t *)conversation_get_proto_data(conversation, proto_gssapi); if (!gss_info) { gss_info = se_new(gssapi_conv_info_t); gss_info->oid=NULL; gss_info->do_reassembly=FALSE; gss_info->frags=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "gssapi_frags"); conversation_add_proto_data(conversation, proto_gssapi, gss_info); } item = proto_tree_add_item( tree, proto_gssapi, tvb, offset, -1, ENC_NA); subtree = proto_item_add_subtree(item, ett_gssapi); /* * Catch the ReportedBoundsError exception; the stuff we've been * handed doesn't necessarily run to the end of the packet, it's * an item inside a packet, so if it happens to be malformed (or * we, or a dissector we call, has a bug), so that an exception * is thrown, we want to report the error, but return and let * our caller dissect the rest of the packet. * * If it gets a BoundsError, we can stop, as there's nothing more * in the packet after our blob to see, so we just re-throw the * exception. */ pd_save = pinfo->private_data; TRY { gss_tvb=tvb; /* First of all, if it's the first time we see this packet * then check whether we are in the middle of reassembly or not */ if( (!pinfo->fd->flags.visited) && (gss_info->do_reassembly) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, gss_info->first_frame); if(!fi){ goto done; } se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fd_head=fragment_add(&gssapi_reassembly_table, tvb, 0, pinfo, fi->first_frame, NULL, gss_info->frag_offset, tvb_length(tvb), TRUE); gss_info->frag_offset+=tvb_length(tvb); /* we need more fragments */ if(!fd_head){ goto done; } /* this blob is now fully reassembled */ gss_info->do_reassembly=FALSE; fi->reassembled_in=pinfo->fd->num; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); } /* We have seen this packet before. * Is this blob part of reassembly or a normal blob ? */ if( (pinfo->fd->flags.visited) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, pinfo->fd->num); if(fi){ fd_head=fragment_get(&gssapi_reassembly_table, pinfo, fi->first_frame, NULL); if(fd_head && (fd_head->flags&FD_DEFRAGMENTED)){ if(pinfo->fd->num==fi->reassembled_in){ proto_item *frag_tree_item; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); show_fragment_tree(fd_head, &gssapi_frag_items, tree, pinfo, tvb, &frag_tree_item); } else { proto_item *it; it=proto_tree_add_uint(tree, hf_gssapi_reassembled_in, tvb, 0, 0, fi->reassembled_in); PROTO_ITEM_SET_GENERATED(it); goto done; } } } } /* Read header */ offset = get_ber_identifier(gss_tvb, offset, &appclass, &pc, &tag); offset = get_ber_length(gss_tvb, offset, &len1, &ind_field); if (!(appclass == BER_CLASS_APP && pc && tag == 0)) { /* It could be NTLMSSP, with no OID. This can happen for anything that microsoft calls 'Negotiate' or GSS-SPNEGO */ if ((tvb_length_remaining(gss_tvb, start_offset)>7) && (tvb_strneql(gss_tvb, start_offset, "NTLMSSP", 7) == 0)) { return_offset = call_dissector(ntlmssp_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* Maybe it's new NTLMSSP payload */ if ((tvb_length_remaining(gss_tvb, start_offset)>16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { return_offset = call_dissector(ntlmssp_payload_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; goto done; } if ((tvb_length_remaining(gss_tvb, start_offset)==16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { if( is_verifier ) { return_offset = call_dissector(ntlmssp_verf_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); } else if( pinfo->gssapi_encrypted_tvb ) { return_offset = call_dissector(ntlmssp_data_only_handle, tvb_new_subset_remaining(pinfo->gssapi_encrypted_tvb, 0), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; } goto done; } /* Maybe it's new GSSKRB5 CFX Wrapping */ if ((tvb_length_remaining(gss_tvb, start_offset)>2) && ((tvb_memeql(gss_tvb, start_offset, "\04\x04", 2) == 0) || (tvb_memeql(gss_tvb, start_offset, "\05\x04", 2) == 0))) { return_offset = call_dissector(spnego_krb5_wrap_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* * If we do not recognise an Application class, * then we are probably dealing with an inner context * token or a wrap token, and we should retrieve the * gssapi_oid_value pointer from the per-frame data or, * if there is no per-frame data (as would be the case * the first time we dissect this frame), from the * conversation that exists or that we created from * pinfo (and then make it per-frame data). * We need to make it per-frame data as there can be * more than one GSS-API negotiation in a conversation. * * Note! We "cheat". Since we only need the pointer, * we store that as the data. (That's not really * "cheating" - the per-frame data and per-conversation * data code doesn't care what you supply as a data * pointer; it just treats it as an opaque pointer, it * doesn't dereference it or free what it points to.) */ oidvalue = (gssapi_oid_value *)p_get_proto_data(pinfo->fd, proto_gssapi, 0); if (!oidvalue && !pinfo->fd->flags.visited) { /* No handle attached to this frame, but it's the first */ /* pass, so it'd be attached to the conversation. */ oidvalue = gss_info->oid; if (gss_info->oid) p_add_proto_data(pinfo->fd, proto_gssapi, 0, gss_info->oid); } if (!oidvalue) { proto_tree_add_text(subtree, gss_tvb, start_offset, 0, "Unknown header (class=%d, pc=%d, tag=%d)", appclass, pc, tag); return_offset = tvb_length(gss_tvb); goto done; } else { tvbuff_t *oid_tvb_local; oid_tvb_local = tvb_new_subset_remaining(gss_tvb, start_offset); if (is_verifier) handle = oidvalue->wrap_handle; else handle = oidvalue->handle; len = call_dissector(handle, oid_tvb_local, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = start_offset + len; goto done; /* We are finished here */ } } /* Read oid */ oid_start_offset=offset; offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, gss_tvb, offset, hf_gssapi_oid, &oid); oidvalue = gssapi_lookup_oid_str(oid); /* Check if we need reassembly of this blob. * Only try reassembly for OIDs we recognize * and when we have the entire tvb * * SMB will sometimes split one large GSSAPI blob * across multiple SMB/SessionSetup commands. * While we should look at the uid returned in the response * to the first SessionSetup and use that as a key * instead for simplicity we assume there will not be several * such authentication at once on a single tcp session */ if( (!pinfo->fd->flags.visited) && (oidvalue) && (tvb_length(gss_tvb)==tvb_reported_length(gss_tvb)) && (len1>(guint32)tvb_length_remaining(gss_tvb, oid_start_offset)) && (gssapi_reassembly) ){ fi=se_new(gssapi_frag_info_t); fi->first_frame=pinfo->fd->num; fi->reassembled_in=0; se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fragment_add(&gssapi_reassembly_table, gss_tvb, 0, pinfo, pinfo->fd->num, NULL, 0, tvb_length(gss_tvb), TRUE); fragment_set_tot_len(&gssapi_reassembly_table, pinfo, pinfo->fd->num, NULL, len1+oid_start_offset); gss_info->do_reassembly=TRUE; gss_info->first_frame=pinfo->fd->num; gss_info->frag_offset=tvb_length(gss_tvb); goto done; } /* * Hand off to subdissector. */ if ((oidvalue == NULL) || !proto_is_protocol_enabled(oidvalue->proto)) { /* No dissector for this oid */ proto_tree_add_text(subtree, gss_tvb, oid_start_offset, -1, "Token object"); return_offset = tvb_length(gss_tvb); goto done; } /* Save a pointer to the data for the OID for the * GSSAPI protocol for this conversation. */ /* * Now add the proto data ... * but only if it is not already there. */ if(!gss_info->oid){ gss_info->oid=oidvalue; } if (is_verifier) { handle = oidvalue->wrap_handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication verifier"); return_offset = tvb_length(gss_tvb); } } else { handle = oidvalue->handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication credentials"); return_offset = tvb_length(gss_tvb); } } done: ; } CATCH_NONFATAL_ERRORS { /* * Somebody threw an exception that means that there * was a problem dissecting the payload; that means * that a dissector was found, so we don't need to * dissect the payload as data or update the protocol * or info columns. * * Just show the exception and then drive on to show * the trailer, after noting that a dissector was found * and restoring the protocol value that was in effect * before we called the subdissector. * * Restore the private_data structure in case one of the * called dissectors modified it (and, due to the exception, * was unable to restore it). */ pinfo->private_data = pd_save; show_exception(gss_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); } ENDTRY; proto_item_set_len(item, return_offset); return return_offset; }
/*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 */
static void dissect_payload_kink_encrypt(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree){ proto_tree *payload_kink_encrypt_tree; proto_item *ti; guint8 next_payload; guint payload_length; #ifdef HAVE_KERBEROS gint encrypt_length; #endif guint8 inner_next_pload; guint16 inner_payload_length; int start_payload_offset = 0; /* Keep the beginning of the payload offset */ payload_length = tvb_get_ntohs(tvb,offset + TO_PAYLOAD_LENGTH); start_payload_offset = offset; #ifdef HAVE_KERBEROS encrypt_length = payload_length - FROM_NP_TO_PL; #endif /* Make the subtree */ ti = proto_tree_add_text(tree, tvb, offset, payload_length,"KINK_ENCRYPT"); payload_kink_encrypt_tree = proto_item_add_subtree(ti, ett_payload_kink_encrypt); next_payload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_encrypt_tree, hf_kink_next_payload, tvb, offset, 1, next_payload); offset ++; proto_tree_add_item(payload_kink_encrypt_tree, hf_kink_reserved8, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; ti = proto_tree_add_uint(payload_kink_encrypt_tree, hf_kink_payload_length, tvb, offset, 2, payload_length); if(payload_length <= PAYLOAD_HEADER){ expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "This Payload Length is too small"); } offset += 2; /* decrypt kink encrypt */ if(keytype != 0){ #ifdef HAVE_KERBEROS tvbuff_t *next_tvb; guint8 *plaintext=NULL; next_tvb=tvb_new_subset(tvb, offset, MIN(tvb_length_remaining(tvb, offset), encrypt_length), encrypt_length); plaintext=decrypt_krb5_data(tree, pinfo, 0, next_tvb, keytype, NULL); if(plaintext){ next_tvb=tvb_new_child_real_data(tvb, plaintext, encrypt_length, encrypt_length); tvb_set_free_cb(next_tvb, g_free); add_new_data_source(pinfo, next_tvb, "decrypted kink encrypt"); dissect_decrypt_kink_encrypt(pinfo, next_tvb, tree, encrypt_length); } #endif } else{ inner_next_pload = tvb_get_guint8(tvb, offset); proto_tree_add_uint(payload_kink_encrypt_tree, hf_kink_inner_next_pload, tvb, offset, 1, inner_next_pload); offset += 1; proto_tree_add_item(payload_kink_encrypt_tree, hf_kink_reserved24, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; if(payload_length > PAYLOAD_HEADER){ inner_payload_length = payload_length - PAYLOAD_HEADER; proto_tree_add_text(payload_kink_encrypt_tree, tvb, offset, inner_payload_length, "Payload"); offset += inner_payload_length; } } /* This part consider the padding. Payload_length don't contain the padding. */ if(payload_length % PADDING !=0){ payload_length += (PADDING - (payload_length % PADDING)); } offset = start_payload_offset + payload_length; if(payload_length > 0) { control_payload(pinfo, tvb, offset, next_payload, tree); /* Recur control_payload() */ } }