/** 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; } }
/* * ByteArray_tvb(name) */ WSLUA_CONSTRUCTOR ByteArray_tvb (lua_State *L) { /* Creates a new Tvb from a bytearray (it gets added to the current frame too) */ #define WSLUA_ARG_ByteArray_tvb_NAME 2 /* The name to be given to the new data-source. */ ByteArray ba = checkByteArray(L,1); const gchar* name = luaL_optstring(L,WSLUA_ARG_ByteArray_tvb_NAME,"Unnamed") ; guint8* data; Tvb tvb; if (!ba) return 0; if (!lua_tvb) { luaL_error(L,"Tvbs can only be created and used in dissectors"); return 0; } data = (guint8 *)g_memdup(ba->data, ba->len); tvb = (Tvb)g_malloc(sizeof(struct _wslua_tvb)); tvb->ws_tvb = tvb_new_real_data(data, ba->len,ba->len); tvb->expired = FALSE; tvb->need_free = TRUE; tvb_set_free_cb(tvb->ws_tvb, g_free); add_new_data_source(lua_pinfo, tvb->ws_tvb, name); PUSH_TVB(L,tvb); WSLUA_RETURN(1); /* The created Tvb. */ }
static gboolean val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { fvalue_t *fv_bytes; tvbuff_t *new_tvb; guint8 *private_data; /* Free up the old value, if we have one */ value_free(fv); /* Does this look like a byte string? */ fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL); if (fv_bytes) { /* Make a tvbuff from the bytes */ private_data = (guint8 *)g_memdup(fv_bytes->value.bytes->data, fv_bytes->value.bytes->len); new_tvb = tvb_new_real_data(private_data, fv_bytes->value.bytes->len, fv_bytes->value.bytes->len); /* Let the tvbuff know how to delete the data. */ tvb_set_free_cb(new_tvb, free_tvb_data); /* And let us know that we need to free the tvbuff */ fv->tvb_is_private = TRUE; fv->value.tvb = new_tvb; return TRUE; } /* Treat it as a string. */ return val_from_string(fv, s, logfunc); }
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; }
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); }
tvbuff_t * tvb_unmasked(tvbuff_t *tvb, const int offset, int payload_length, const guint8 *masking_key) { gchar *data_unmask; tvbuff_t *tvb_unmask = NULL; int i; const guint8 *data_mask; int unmasked_length = payload_length > MAX_UNMASKED_LEN ? MAX_UNMASKED_LEN : payload_length; data_unmask = g_malloc(unmasked_length); data_mask = tvb_get_ptr(tvb, offset, unmasked_length); /* Unmasked(XOR) Data... */ for(i=0; i < unmasked_length; i++){ data_unmask[i] = data_mask[i] ^ masking_key[i%4]; } tvb_unmask = tvb_new_real_data(data_unmask, unmasked_length, unmasked_length); tvb_set_free_cb(tvb_unmask, g_free); return tvb_unmask; }
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 gboolean val_from_string(fvalue_t *fv, char *s, LogFunc logfunc _U_) { tvbuff_t *new_tvb; guint8 *private_data; /* Free up the old value, if we have one */ value_free(fv); /* Make a tvbuff from the string. We can drop the * terminating NUL. */ private_data = (guint8 *)g_memdup(s, (guint)strlen(s)); new_tvb = tvb_new_real_data(private_data, (guint)strlen(s), (gint)strlen(s)); /* Let the tvbuff know how to delete the data. */ tvb_set_free_cb(new_tvb, free_tvb_data); /* And let us know that we need to free the tvbuff */ fv->tvb_is_private = TRUE; fv->value.tvb = new_tvb; return TRUE; }
/* * 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 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; }
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() */ } }
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 }
tvbuff_t * tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen) { gint err; guint bytes_out = 0; guint8 *compr; guint8 *uncompr = NULL; tvbuff_t *uncompr_tvb = NULL; z_streamp strm; Bytef *strmbuf; guint inits_done = 0; gint wbits = MAX_WBITS; guint8 *next; guint bufsiz; #ifdef TVB_Z_DEBUG guint inflate_passes = 0; guint bytes_in = tvb_captured_length_remaining(tvb, offset); #endif if (tvb == NULL || comprlen <= 0) { return NULL; } compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen); if (compr == NULL) { return NULL; } /* * Assume that the uncompressed data is at least twice as big as * the compressed size. */ bufsiz = tvb_captured_length_remaining(tvb, offset) * 2; bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ); #ifdef TVB_Z_DEBUG ws_debug_printf("bufsiz: %u bytes\n", bufsiz); #endif next = compr; strm = g_new0(z_stream, 1); strm->next_in = next; strm->avail_in = comprlen; strmbuf = (Bytef *)g_malloc0(bufsiz); strm->next_out = strmbuf; strm->avail_out = bufsiz; err = inflateInit2(strm, wbits); inits_done = 1; if (err != Z_OK) { inflateEnd(strm); g_free(strm); wmem_free(NULL, compr); g_free(strmbuf); return NULL; } while (1) { memset(strmbuf, '\0', bufsiz); strm->next_out = strmbuf; strm->avail_out = bufsiz; err = inflate(strm, Z_SYNC_FLUSH); if (err == Z_OK || err == Z_STREAM_END) { guint bytes_pass = bufsiz - strm->avail_out; #ifdef TVB_Z_DEBUG ++inflate_passes; #endif if (uncompr == NULL) { /* * This is ugly workaround for bug #6480 * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480) * * g_memdup(..., 0) returns NULL (g_malloc(0) also) * when uncompr is NULL logic below doesn't create tvb * which is later interpreted as decompression failed. */ uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ? g_memdup(strmbuf, bytes_pass) : g_strdup("")); } else { guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass); memcpy(new_data, uncompr, bytes_out); memcpy(new_data + bytes_out, strmbuf, bytes_pass); g_free(uncompr); uncompr = new_data; } bytes_out += bytes_pass; if (err == Z_STREAM_END) { inflateEnd(strm); g_free(strm); g_free(strmbuf); break; } } else if (err == Z_BUF_ERROR) { /* * It's possible that not enough frames were captured * to decompress this fully, so return what we've done * so far, if any. */ inflateEnd(strm); g_free(strm); g_free(strmbuf); if (uncompr != NULL) { break; } else { wmem_free(NULL, compr); return NULL; } } else if (err == Z_DATA_ERROR && inits_done == 1 && uncompr == NULL && comprlen >= 2 && (*compr == 0x1f) && (*(compr + 1) == 0x8b)) { /* * inflate() is supposed to handle both gzip and deflate * streams automatically, but in reality it doesn't * seem to handle either (at least not within the * context of an HTTP response.) We have to try * several tweaks, depending on the type of data and * version of the library installed. */ /* * Gzip file format. Skip past the header, since the * fix to make it work (setting windowBits to 31) * doesn't work with all versions of the library. */ Bytef *c = compr + 2; Bytef flags = 0; /* we read two bytes already (0x1f, 0x8b) and need at least Z_DEFLATED, 1 byte flags, 4 bytes MTIME, 1 byte XFL, 1 byte OS */ if (comprlen < 10 || *c != Z_DEFLATED) { inflateEnd(strm); g_free(strm); wmem_free(NULL, compr); g_free(strmbuf); return NULL; } c++; flags = *c; c++; /* Skip past the MTIME (4 bytes), XFL, and OS fields (1 byte each). */ c += 6; if (flags & (1 << 2)) { /* An Extra field is present. It consists of 2 bytes xsize and xsize bytes of data. Read byte-by-byte (least significant byte first) to make sure we abort cleanly when the xsize is truncated after the first byte. */ guint16 xsize = 0; if (c-compr < comprlen) { xsize += *c; c++; } if (c-compr < comprlen) { xsize += *c << 8; c++; } c += xsize; } if (flags & (1 << 3)) { /* A null terminated filename */ while ((c - compr) < comprlen && *c != '\0') { c++; } c++; } if (flags & (1 << 4)) { /* A null terminated comment */ while ((c - compr) < comprlen && *c != '\0') { c++; } c++; } if (c - compr > comprlen) { inflateEnd(strm); g_free(strm); wmem_free(NULL, compr); g_free(strmbuf); return NULL; } /* Drop gzip header */ comprlen -= (int) (c - compr); next = c; inflateReset(strm); strm->next_in = next; strm->avail_in = comprlen; inflateEnd(strm); inflateInit2(strm, wbits); inits_done++; } else if (err == Z_DATA_ERROR && uncompr == NULL && inits_done <= 3) { /* * Re-init the stream with a negative * MAX_WBITS. This is necessary due to * some servers (Apache) not sending * the deflate header with the * content-encoded response. */ wbits = -MAX_WBITS; inflateReset(strm); strm->next_in = next; strm->avail_in = comprlen; inflateEnd(strm); memset(strmbuf, '\0', bufsiz); strm->next_out = strmbuf; strm->avail_out = bufsiz; err = inflateInit2(strm, wbits); inits_done++; if (err != Z_OK) { g_free(strm); g_free(strmbuf); wmem_free(NULL, compr); g_free(uncompr); return NULL; } } else { inflateEnd(strm); g_free(strm); g_free(strmbuf); if (uncompr == NULL) { wmem_free(NULL, compr); return NULL; } break; } } #ifdef TVB_Z_DEBUG ws_debug_printf("inflate() total passes: %u\n", inflate_passes); ws_debug_printf("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out); #endif if (uncompr != NULL) { uncompr_tvb = tvb_new_real_data((guint8*) uncompr, bytes_out, bytes_out); tvb_set_free_cb(uncompr_tvb, g_free); } wmem_free(NULL, compr); return uncompr_tvb; }
/*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 */