2005-06-22 09:58:46 +00:00
/*#define DEBUG_BER 1 */
2004-10-30 01:54:40 +00:00
/* TODO: change #.REGISTER signature to new_dissector_t and
* update call_ber_oid_callback ( ) accordingly .
2005-06-22 09:58:46 +00:00
*
* Since we dont pass the TAG / LENGTH from the CHOICE / SEQUENCE / SEQUENCE OF /
* SET OF helpers through the callbacks to the next pabket - ber helper
* when the tags are IMPLICIT , this causes a problem when we also have
* indefinite length at the same time as the tags are implicit .
* While the proper fix is to change the signatures for packet - ber . c helpers
* as well as the signatures for the callbacks to include the indefinite length
* indication that would be a major job .
* For the time being , kludge , set a global variable in the
* CHOICE / SEQUENCE [ OF ] / SET [ OF ] helpers to indicate to the next helper
* whether the length is indefinite or not .
* This has currently only been implemented for { SEQUENCE | SET } [ OF ] but not yet
* CHOICE .
2005-08-18 08:37:31 +00:00
*
* This version attacks the problem ( s ) in a different way , if we see indefinit length
* the get_ber_length traverses the tags within the compound value and then we return the
* true length of the compound value including the EOC . Thus the tvb length is now always correct
* even for indefinite length , then if we get implicit tags they can be handled as if they were definite
* length .
2004-10-30 01:54:40 +00:00
*/
2005-08-18 08:37:31 +00:00
2004-02-20 10:04:10 +00:00
/* packet-ber.c
* Helpers for ASN .1 / BER dissection
* Ronnie Sahlberg ( C ) 2004
*
2004-07-18 00:24:25 +00:00
* $ Id $
2004-02-20 10:04:10 +00:00
*
* Ethereal - Network traffic analyzer
* By Gerald Combs < gerald @ ethereal . com >
* Copyright 1998 Gerald Combs
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2004-03-25 09:18:03 +00:00
/*
* ITU - T Recommendation X .690 ( 07 / 2002 ) ,
* Information technology ASN .1 encoding rules :
* Specification of Basic Encoding Rules ( BER ) , Canonical Encoding Rules ( CER ) and Distinguished Encoding Rules ( DER )
*
*/
2004-02-20 10:04:10 +00:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <glib.h>
# include <epan/packet.h>
# include <epan/strutil.h>
2005-04-28 09:54:03 +00:00
# include <epan/to_str.h>
2004-09-27 22:55:15 +00:00
# include <epan/prefs.h>
2005-08-20 02:33:33 +00:00
# include <epan/emem.h>
2004-02-20 10:04:10 +00:00
# include "packet-ber.h"
static gint proto_ber = - 1 ;
static gint hf_ber_id_class = - 1 ;
static gint hf_ber_id_pc = - 1 ;
static gint hf_ber_id_uni_tag = - 1 ;
static gint hf_ber_id_tag = - 1 ;
static gint hf_ber_length = - 1 ;
static gint hf_ber_bitstring_padding = - 1 ;
2004-11-25 22:27:52 +00:00
static gint hf_ber_unknown_OID = - 1 ;
static gint hf_ber_unknown_OCTETSTRING = - 1 ;
2005-06-24 10:03:20 +00:00
static gint hf_ber_unknown_GraphicString = - 1 ;
2004-12-12 22:59:43 +00:00
static gint hf_ber_unknown_NumericString = - 1 ;
2004-11-18 10:46:27 +00:00
static gint hf_ber_unknown_PrintableString = - 1 ;
2004-11-25 21:30:38 +00:00
static gint hf_ber_unknown_IA5String = - 1 ;
2004-11-18 10:46:27 +00:00
static gint hf_ber_unknown_INTEGER = - 1 ;
2004-12-12 22:59:43 +00:00
static gint hf_ber_unknown_ENUMERATED = - 1 ;
2004-02-20 10:04:10 +00:00
static gint ett_ber_octet_string = - 1 ;
2004-11-25 21:30:38 +00:00
static gint ett_ber_unknown = - 1 ;
2004-11-25 22:27:52 +00:00
static gint ett_ber_SEQUENCE = - 1 ;
2004-02-20 10:04:10 +00:00
static gboolean show_internal_ber_fields = FALSE ;
proto_item * ber_last_created_item = NULL ;
2005-08-18 08:37:31 +00:00
2005-06-22 09:58:46 +00:00
/* kludge to pass indefinite length indications from structure helpers
to the next helper . Or else implicite tag + indefinite length wont work .
2004-02-20 10:04:10 +00:00
2005-08-18 08:37:31 +00:00
static gboolean length_is_indefinite = FALSE ;
not used anymore as the length from get_ber_length should be correct for indefinite length also .
*/
2004-07-21 11:13:03 +00:00
static dissector_table_t ber_oid_dissector_table = NULL ;
2004-02-20 10:04:10 +00:00
static const value_string ber_class_codes [ ] = {
{ BER_CLASS_UNI , " Universal " } ,
{ BER_CLASS_APP , " Application " } ,
{ BER_CLASS_CON , " Context Specific " } ,
{ BER_CLASS_PRI , " Private " } ,
{ 0 , NULL }
} ;
static const true_false_string ber_pc_codes = {
" Constructed Encoding " ,
" Primitive Encoding "
} ;
static const value_string ber_uni_tag_codes [ ] = {
2004-03-25 23:57:10 +00:00
{ BER_UNI_TAG_EOC , " 'end-of-content' " } ,
{ BER_UNI_TAG_BOOLEAN , " BOOLEAN " } ,
{ BER_UNI_TAG_INTEGER , " INTEGER " } ,
{ BER_UNI_TAG_BITSTRING , " BIT STRING " } ,
{ BER_UNI_TAG_OCTETSTRING , " OCTET STRING " } ,
{ BER_UNI_TAG_NULL , " NULL " } ,
{ BER_UNI_TAG_OID , " OBJECT IDENTIFIER " } ,
{ BER_UNI_TAG_ObjectDescriptor , " ObjectDescriptor " } ,
{ BER_UNI_TAG_REAL , " REAL " } ,
{ BER_UNI_TAG_ENUMERATED , " ENUMERATED " } ,
{ BER_UNI_TAG_EMBEDDED_PDV , " EMBEDDED PDV " } ,
{ BER_UNI_TAG_UTF8String , " UTF8String " } ,
{ BER_UNI_TAG_RELATIVE_OID , " RELATIVE-OID " } ,
{ BER_UNI_TAG_SEQUENCE , " SEQUENCE, SEQUENCE OF " } ,
{ BER_UNI_TAG_SET , " SET, SET OF " } ,
{ BER_UNI_TAG_NumericString , " NumericString " } ,
{ BER_UNI_TAG_PrintableString , " PrintableString " } ,
2004-12-13 11:59:48 +00:00
{ BER_UNI_TAG_TeletexString , " TeletexString, T61String " } ,
2004-03-25 23:57:10 +00:00
{ BER_UNI_TAG_VideotexString , " VideotexString " } ,
{ BER_UNI_TAG_IA5String , " IA5String " } ,
2004-06-05 09:59:45 +00:00
{ BER_UNI_TAG_UTCTime , " UTCTime " } ,
2004-03-25 23:57:10 +00:00
{ BER_UNI_TAG_GeneralizedTime , " GeneralizedTime " } ,
{ BER_UNI_TAG_GraphicString , " GraphicString " } ,
{ BER_UNI_TAG_VisibleString , " VisibleString, ISO64String " } ,
2004-03-26 00:21:53 +00:00
{ BER_UNI_TAG_GeneralString , " GeneralString " } ,
2004-03-25 23:57:10 +00:00
{ BER_UNI_TAG_UniversalString , " UniversalString " } ,
{ BER_UNI_TAG_CHARACTERSTRING , " CHARACTER STRING " } ,
{ BER_UNI_TAG_BMPString , " BMPString " } ,
2004-02-20 10:04:10 +00:00
{ 0 , NULL }
} ;
2004-03-25 23:57:10 +00:00
proto_item * get_ber_last_created_item ( void ) {
return ber_last_created_item ;
}
2004-07-20 09:11:40 +00:00
2004-07-29 09:32:13 +00:00
static GHashTable * oid_table = NULL ;
2004-07-29 09:52:14 +00:00
void
dissect_ber_oid_NULL_callback ( tvbuff_t * tvb _U_ , packet_info * pinfo _U_ , proto_tree * tree _U_ )
{
return ;
}
2005-06-07 05:49:06 +00:00
void
2005-07-28 07:53:38 +00:00
register_ber_oid_dissector_handle ( const char * oid , dissector_handle_t dissector , int proto _U_ , const char * name )
2005-06-07 05:49:06 +00:00
{
dissector_add_string ( " ber.oid " , oid , dissector ) ;
2005-07-29 03:27:59 +00:00
g_hash_table_insert ( oid_table , ( gpointer ) oid , ( gpointer ) name ) ;
2005-06-07 05:49:06 +00:00
}
2004-07-23 07:08:14 +00:00
void
2005-07-28 07:53:38 +00:00
register_ber_oid_dissector ( const char * oid , dissector_t dissector , int proto , const char * name )
2004-07-23 07:08:14 +00:00
{
dissector_handle_t dissector_handle ;
dissector_handle = create_dissector_handle ( dissector , proto ) ;
dissector_add_string ( " ber.oid " , oid , dissector_handle ) ;
2005-07-29 03:27:59 +00:00
g_hash_table_insert ( oid_table , ( gpointer ) oid , ( gpointer ) name ) ;
2004-07-23 07:08:14 +00:00
}
2005-06-07 05:49:06 +00:00
2004-11-09 06:49:35 +00:00
/* Register the oid name to get translation in proto dissection */
2004-10-27 19:59:44 +00:00
void
2005-07-28 07:53:38 +00:00
register_ber_oid_name ( const char * oid , const char * name )
2004-10-27 19:59:44 +00:00
{
2005-07-29 03:27:59 +00:00
g_hash_table_insert ( oid_table , ( gpointer ) oid , ( gpointer ) name ) ;
2004-10-27 19:59:44 +00:00
}
2004-11-09 06:49:35 +00:00
2005-07-29 03:27:59 +00:00
/* Get oid name from hash table to get translation in proto dissection(packet-per.c) */
2004-11-09 06:49:35 +00:00
char *
get_ber_oid_name ( char * oid )
{
return g_hash_table_lookup ( oid_table , oid ) ;
}
2004-11-18 10:46:27 +00:00
/* this function tries to dissect an unknown blob as much as possible.
* everytime this function is called it is a failure to implement a proper
* dissector in ethereal .
* something is missing , so dont become too comfy with this one ,
* when it is called it is a BAD thing not a good thing .
2004-11-25 22:27:52 +00:00
* It can not handle IMPLICIT tags nor indefinite length .
2004-11-18 10:46:27 +00:00
*/
2005-06-07 05:49:06 +00:00
int dissect_unknown_ber ( packet_info * pinfo , tvbuff_t * tvb , int offset , proto_tree * tree )
2004-11-18 10:46:27 +00:00
{
int start_offset ;
2005-07-09 02:58:07 +00:00
gint8 class ;
2004-11-18 10:46:27 +00:00
gboolean pc , ind ;
2005-07-09 02:58:07 +00:00
gint32 tag ;
2004-11-18 10:46:27 +00:00
guint32 len ;
2004-11-25 22:27:52 +00:00
proto_item * item = NULL ;
proto_tree * next_tree = NULL ;
2004-11-18 10:46:27 +00:00
start_offset = offset ;
2005-08-18 08:37:31 +00:00
offset = dissect_ber_identifier ( pinfo , NULL , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , NULL , tvb , offset , & len , & ind ) ;
2004-11-18 10:46:27 +00:00
2004-12-13 08:15:34 +00:00
if ( len > ( guint32 ) tvb_length_remaining ( tvb , offset ) ) {
2004-11-25 21:30:38 +00:00
/* hmm maybe something bad happened or the frame is short,
since these are not vital outputs just return instead of
throwing en exception .
*/
2005-08-18 08:37:31 +00:00
proto_tree_add_text ( tree , tvb , offset , len , " BER: Error length:%d longer than tvb_length_ramaining:%d " , len , tvb_length_remaining ( tvb , offset ) ) ;
2004-11-25 21:30:38 +00:00
return tvb_length ( tvb ) ;
}
2005-08-18 08:37:31 +00:00
/* we dont care about the class only on the constructor flag */
switch ( pc ) {
case FALSE :
2004-11-25 22:27:52 +00:00
switch ( tag ) {
case BER_UNI_TAG_INTEGER :
2004-12-12 01:14:03 +00:00
offset = dissect_ber_integer ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_INTEGER , NULL ) ;
2004-11-25 22:27:52 +00:00
break ;
2004-12-12 22:59:43 +00:00
case BER_UNI_TAG_ENUMERATED :
offset = dissect_ber_integer ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_ENUMERATED , NULL ) ;
break ;
2005-06-24 10:03:20 +00:00
case BER_UNI_TAG_GraphicString :
offset = dissect_ber_octet_string ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_GraphicString , NULL ) ;
break ;
2004-11-25 22:27:52 +00:00
case BER_UNI_TAG_OCTETSTRING :
offset = dissect_ber_octet_string ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_OCTETSTRING , NULL ) ;
break ;
case BER_UNI_TAG_OID :
offset = dissect_ber_object_identifier ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_OID , NULL ) ;
break ;
case BER_UNI_TAG_SEQUENCE :
2005-06-22 09:58:46 +00:00
item = proto_tree_add_text ( tree , tvb , offset , len , " SEQUENCE (len:%d bytes) tvb_remaining:%d " , len , tvb_length_remaining ( tvb , offset ) ) ;
2004-11-25 22:27:52 +00:00
if ( item ) {
next_tree = proto_item_add_subtree ( item , ett_ber_SEQUENCE ) ;
}
2005-08-18 08:37:31 +00:00
offset = dissect_unknown_ber ( pinfo , tvb , offset , next_tree ) ;
2004-11-25 22:27:52 +00:00
break ;
2004-12-12 22:59:43 +00:00
case BER_UNI_TAG_NumericString :
offset = dissect_ber_octet_string ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_NumericString , NULL ) ;
break ;
2004-11-25 22:27:52 +00:00
case BER_UNI_TAG_PrintableString :
offset = dissect_ber_octet_string ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_PrintableString , NULL ) ;
break ;
case BER_UNI_TAG_IA5String :
offset = dissect_ber_octet_string ( FALSE , pinfo , tree , tvb , start_offset , hf_ber_unknown_IA5String , NULL ) ;
break ;
default :
proto_tree_add_text ( tree , tvb , offset , len , " BER: Error can not handle universal tag:%d " , tag ) ;
offset + = len ;
}
break ;
2005-08-18 08:37:31 +00:00
case TRUE :
2005-06-22 09:58:46 +00:00
item = proto_tree_add_text ( tree , tvb , offset , len , " [%d] (len:%d bytes) " , tag , len ) ;
2004-11-25 22:27:52 +00:00
if ( item ) {
next_tree = proto_item_add_subtree ( item , ett_ber_SEQUENCE ) ;
}
2005-08-18 08:37:31 +00:00
offset = dissect_unknown_ber ( pinfo , tvb , offset , next_tree ) ;
2004-11-25 22:27:52 +00:00
break ;
default :
proto_tree_add_text ( tree , tvb , offset , len , " BER: Error can not handle class:%d (0x%02x) " , class , tvb_get_guint8 ( tvb , start_offset ) ) ;
2004-11-18 10:46:27 +00:00
/* some printout here? aborting dissection */
return tvb_length ( tvb ) ;
}
2004-11-25 22:27:52 +00:00
/* were there more data to eat? */
2004-12-13 08:15:34 +00:00
if ( offset < ( int ) tvb_length ( tvb ) ) {
2004-11-25 22:27:52 +00:00
offset = dissect_unknown_ber ( pinfo , tvb , offset , tree ) ;
2004-11-18 10:46:27 +00:00
}
2004-11-25 22:27:52 +00:00
2004-11-18 10:46:27 +00:00
return offset ;
}
2004-07-20 09:11:40 +00:00
int
2005-08-05 13:10:58 +00:00
call_ber_oid_callback ( const char * oid , tvbuff_t * tvb , int offset , packet_info * pinfo , proto_tree * tree )
2004-07-20 09:11:40 +00:00
{
2004-07-21 11:13:03 +00:00
tvbuff_t * next_tvb ;
2005-08-28 17:57:30 +00:00
next_tvb = tvb_new_subset ( tvb , offset , - 1 , - 1 ) ;
2004-07-23 23:12:31 +00:00
if ( ! dissector_try_string ( ber_oid_dissector_table , oid , next_tvb , pinfo , tree ) ) {
2004-11-25 21:30:38 +00:00
proto_item * item = NULL ;
proto_tree * next_tree = NULL ;
item = proto_tree_add_text ( tree , next_tvb , 0 , tvb_length_remaining ( tvb , offset ) , " BER: Dissector for OID:%s not implemented. Contact Ethereal developers if you want this supported " , oid ) ;
if ( item ) {
next_tree = proto_item_add_subtree ( item , ett_ber_unknown ) ;
}
2005-08-28 17:57:30 +00:00
dissect_unknown_ber ( pinfo , next_tvb , 0 , next_tree ) ;
2004-07-23 23:12:31 +00:00
}
2004-07-20 09:11:40 +00:00
2004-10-30 01:54:40 +00:00
/*XXX until we change the #.REGISTER signature for _PDU()s
* into new_dissector_t we have to do this kludge with
* manually step past the content in the ANY type .
*/
offset + = tvb_length_remaining ( tvb , offset ) ;
2004-07-20 09:11:40 +00:00
return offset ;
}
2004-12-13 08:15:34 +00:00
static int dissect_ber_sq_of ( gboolean implicit_tag , gint32 type , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_sequence_t * seq , gint hf_id , gint ett_id ) ;
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +00:00
/* 8.1 General rules for encoding */
/* 8.1.2 Identifier octets */
2004-12-13 08:15:34 +00:00
int get_ber_identifier ( tvbuff_t * tvb , int offset , gint8 * class , gboolean * pc , gint32 * tag ) {
2004-03-25 09:18:03 +00:00
guint8 id , t ;
2004-12-13 08:15:34 +00:00
gint8 tmp_class ;
2004-03-25 09:18:03 +00:00
gboolean tmp_pc ;
2004-12-13 08:15:34 +00:00
gint32 tmp_tag ;
2004-03-25 09:18:03 +00:00
id = tvb_get_guint8 ( tvb , offset ) ;
offset + = 1 ;
2005-03-24 14:21:30 +00:00
# ifdef DEBUG_BER
printf ( " BER ID=%02x " , id ) ;
# endif
2004-03-25 09:18:03 +00:00
/* 8.1.2.2 */
tmp_class = ( id > > 6 ) & 0x03 ;
tmp_pc = ( id > > 5 ) & 0x01 ;
tmp_tag = id & 0x1F ;
/* 8.1.2.4 */
if ( tmp_tag = = 0x1F ) {
tmp_tag = 0 ;
while ( tvb_length_remaining ( tvb , offset ) > 0 ) {
t = tvb_get_guint8 ( tvb , offset ) ;
2005-03-24 14:21:30 +00:00
# ifdef DEBUG_BER
printf ( " %02x " , t ) ;
# endif
2004-03-25 09:18:03 +00:00
offset + = 1 ;
tmp_tag < < = 7 ;
tmp_tag | = t & 0x7F ;
2005-03-24 14:21:30 +00:00
if ( ! ( t & 0x80 ) ) break ;
2004-03-25 09:18:03 +00:00
}
}
2005-03-24 14:21:30 +00:00
# ifdef DEBUG_BER
printf ( " \n " ) ;
# endif
2004-03-25 09:18:03 +00:00
if ( class )
* class = tmp_class ;
if ( pc )
* pc = tmp_pc ;
if ( tag )
* tag = tmp_tag ;
return offset ;
}
2004-02-20 10:04:10 +00:00
2004-12-13 08:15:34 +00:00
int dissect_ber_identifier ( packet_info * pinfo _U_ , proto_tree * tree , tvbuff_t * tvb , int offset , gint8 * class , gboolean * pc , gint32 * tag )
2004-03-25 09:18:03 +00:00
{
int old_offset = offset ;
2004-12-13 08:15:34 +00:00
gint8 tmp_class ;
2004-03-25 09:18:03 +00:00
gboolean tmp_pc ;
2004-12-13 08:15:34 +00:00
gint32 tmp_tag ;
2004-03-25 09:18:03 +00:00
offset = get_ber_identifier ( tvb , offset , & tmp_class , & tmp_pc , & tmp_tag ) ;
2004-02-20 10:04:10 +00:00
if ( show_internal_ber_fields ) {
2004-03-25 09:18:03 +00:00
proto_tree_add_uint ( tree , hf_ber_id_class , tvb , old_offset , 1 , tmp_class < < 6 ) ;
proto_tree_add_boolean ( tree , hf_ber_id_pc , tvb , old_offset , 1 , ( tmp_pc ) ? 0x20 : 0x00 ) ;
if ( tmp_class = = BER_CLASS_UNI ) {
proto_tree_add_uint ( tree , hf_ber_id_uni_tag , tvb , old_offset , offset - old_offset , tmp_tag ) ;
2004-02-20 10:04:10 +00:00
} else {
2004-03-25 09:18:03 +00:00
proto_tree_add_uint ( tree , hf_ber_id_tag , tvb , old_offset , offset - old_offset , tmp_tag ) ;
2004-02-20 10:04:10 +00:00
}
}
2005-08-18 08:37:31 +00:00
if ( class )
2004-03-25 09:18:03 +00:00
* class = tmp_class ;
2005-08-18 08:37:31 +00:00
if ( pc )
2004-03-25 09:18:03 +00:00
* pc = tmp_pc ;
2005-08-18 08:37:31 +00:00
if ( tag )
2004-03-25 09:18:03 +00:00
* tag = tmp_tag ;
2004-02-20 10:04:10 +00:00
return offset ;
}
2004-03-25 09:18:03 +00:00
/* this function gets the length octets of the BER TLV.
2004-02-20 10:04:10 +00:00
* We only handle ( TAGs and ) LENGTHs that fit inside 32 bit integers .
*/
2004-03-25 09:18:03 +00:00
/* 8.1.3 Length octets */
2004-02-20 10:04:10 +00:00
int
2005-04-20 08:35:47 +00:00
get_ber_length ( proto_tree * tree , tvbuff_t * tvb , int offset , guint32 * length , gboolean * ind ) {
2004-03-25 09:18:03 +00:00
guint8 oct , len ;
2005-08-18 08:37:31 +00:00
guint32 tmp_len ;
2004-03-25 09:18:03 +00:00
guint32 tmp_length ;
gboolean tmp_ind ;
2005-04-20 08:35:47 +00:00
int old_offset = offset ;
2005-08-18 08:37:31 +00:00
int tmp_offset , s_offset ;
gint8 tclass ;
gboolean tpc ;
gint32 ttag ;
2004-03-25 09:18:03 +00:00
tmp_length = 0 ;
tmp_ind = FALSE ;
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +00:00
oct = tvb_get_guint8 ( tvb , offset ) ;
offset + = 1 ;
2004-02-20 10:04:10 +00:00
2005-08-18 08:37:31 +00:00
if ( ! ( oct & 0x80 ) ) {
2004-03-25 09:18:03 +00:00
/* 8.1.3.4 */
tmp_length = oct ;
} else {
len = oct & 0x7F ;
2005-08-18 08:37:31 +00:00
if ( len ) {
2004-03-25 09:18:03 +00:00
/* 8.1.3.5 */
while ( len - - ) {
oct = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
tmp_length = ( tmp_length < < 8 ) + oct ;
}
} else {
/* 8.1.3.6 */
2005-08-18 08:37:31 +00:00
tmp_offset = offset ;
/* ok in here we can traverse the BER to find the length, this will fix most indefinite length issues */
/* Assumption here is that indefinite length is always used on constructed types*/
/* check for EOC */
2005-08-23 08:01:46 +00:00
while ( ( tvb_reported_length_remaining ( tvb , offset ) > 0 ) & & ( tvb_get_guint8 ( tvb , offset ) | | tvb_get_guint8 ( tvb , offset + 1 ) ) )
2005-08-18 08:37:31 +00:00
{
2005-08-23 08:01:46 +00:00
/* not an EOC at offset */
2005-08-18 08:37:31 +00:00
s_offset = offset ;
offset = get_ber_identifier ( tvb , offset , & tclass , & tpc , & ttag ) ;
offset = get_ber_length ( tree , tvb , offset , & tmp_len , NULL ) ;
tmp_length + = tmp_len + ( offset - s_offset ) ; /* length + tag and length */
offset + = tmp_len ;
}
tmp_length + = 2 ;
2004-03-25 09:18:03 +00:00
tmp_ind = TRUE ;
2005-08-18 08:37:31 +00:00
offset = tmp_offset ;
2004-02-20 10:04:10 +00:00
}
}
2005-04-20 08:35:47 +00:00
/* check that the length is sane */
if ( tmp_length > ( guint32 ) tvb_reported_length_remaining ( tvb , offset ) ) {
proto_tree_add_text ( tree , tvb , old_offset , offset - old_offset , " BER: Error length:%d longer than tvb_reported_length_remaining:%d " , tmp_length , tvb_reported_length_remaining ( tvb , offset ) ) ;
2005-08-28 17:57:30 +00:00
/* force the appropriate exception */
tvb_ensure_bytes_exist ( tvb , offset , tmp_length ) ;
2005-08-18 08:37:31 +00:00
/*tmp_length = (guint32)tvb_reported_length_remaining(tvb,offset);*/
2005-04-20 08:35:47 +00:00
}
2004-03-25 09:18:03 +00:00
if ( length )
* length = tmp_length ;
if ( ind )
* ind = tmp_ind ;
2004-02-20 10:04:10 +00:00
return offset ;
}
2004-03-25 09:18:03 +00:00
/* this function dissects the length octets of the BER TLV.
* We only handle ( TAGs and ) LENGTHs that fit inside 32 bit integers .
2004-02-20 10:04:10 +00:00
*/
2004-03-25 09:18:03 +00:00
int
dissect_ber_length ( packet_info * pinfo _U_ , proto_tree * tree , tvbuff_t * tvb , int offset , guint32 * length , gboolean * ind )
2004-02-20 10:04:10 +00:00
{
2004-03-25 09:18:03 +00:00
int old_offset = offset ;
guint32 tmp_length ;
gboolean tmp_ind ;
2005-04-20 08:35:47 +00:00
offset = get_ber_length ( tree , tvb , offset , & tmp_length , & tmp_ind ) ;
2004-03-25 09:18:03 +00:00
if ( show_internal_ber_fields ) {
2004-10-16 12:53:09 +00:00
if ( tmp_ind ) {
2005-08-18 08:37:31 +00:00
proto_tree_add_text ( tree , tvb , old_offset , 1 , " Length: Indefinite length %d " , tmp_length ) ;
2004-10-16 12:53:09 +00:00
} else {
proto_tree_add_uint ( tree , hf_ber_length , tvb , old_offset , offset - old_offset , tmp_length ) ;
}
2004-03-25 09:18:03 +00:00
}
2005-08-18 08:37:31 +00:00
if ( length )
2004-03-25 09:18:03 +00:00
* length = tmp_length ;
2005-08-18 08:37:31 +00:00
if ( ind )
2004-03-25 09:18:03 +00:00
* ind = tmp_ind ;
return offset ;
}
/* 8.7 Encoding of an octetstring value */
int
dissect_ber_octet_string ( gboolean implicit_tag , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , tvbuff_t * * out_tvb ) {
2005-07-09 02:58:07 +00:00
gint8 class ;
2004-03-25 09:18:03 +00:00
gboolean pc , ind ;
2005-07-09 02:58:07 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
int end_offset ;
proto_item * it ;
2005-03-24 14:21:30 +00:00
guint32 i ;
2004-02-20 10:04:10 +00:00
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
printf ( " OCTET STRING dissect_ber_octet string(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x \n " , name , implicit_tag , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
} else {
printf ( " OCTET STRING dissect_ber_octet_string(%s) entered \n " , name ) ;
}
}
# endif
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +00:00
if ( ! implicit_tag ) {
2004-11-14 05:10:44 +00:00
/* read header and len for the octet string */
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , & ind ) ;
end_offset = offset + len ;
/* sanity check: we only handle Constructed Universal Sequences */
2005-06-07 05:49:06 +00:00
if ( ( class ! = BER_CLASS_APP ) & & ( class ! = BER_CLASS_PRI ) )
2004-11-14 05:10:44 +00:00
if ( ( class ! = BER_CLASS_UNI )
2004-11-14 08:50:37 +00:00
| | ( ( tag < BER_UNI_TAG_NumericString ) & & ( tag ! = BER_UNI_TAG_OCTETSTRING ) & & ( tag ! = BER_UNI_TAG_UTF8String ) ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-03-25 09:18:03 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: OctetString expected but Class:%d PC:%d Tag:%d was unexpected " , class , pc , tag ) ;
2005-03-30 09:18:25 +00:00
if ( out_tvb )
2005-01-30 17:48:18 +00:00
* out_tvb = NULL ;
2004-03-25 09:18:03 +00:00
return end_offset ;
}
2004-11-14 05:10:44 +00:00
} else {
/* implicit tag so just trust the length of the tvb */
pc = FALSE ;
len = tvb_length_remaining ( tvb , offset ) ;
end_offset = offset + len ;
}
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +00:00
ber_last_created_item = NULL ;
if ( pc ) {
/* constructed */
/* TO DO */
2005-06-09 04:28:13 +00:00
if ( out_tvb )
* out_tvb = NULL ;
2005-08-18 08:37:31 +00:00
2005-03-24 14:21:30 +00:00
printf ( " TODO: handle constructed type in packet-ber.c, dissect_ber_octet_string \n " ) ;
2004-03-25 09:18:03 +00:00
} else {
/* primitive */
2005-08-18 08:37:31 +00:00
if ( hf_id ! = - 1 ) {
2005-04-14 19:53:27 +00:00
tvb_ensure_bytes_exist ( tvb , offset , len ) ;
2004-03-25 09:18:03 +00:00
it = proto_tree_add_item ( tree , hf_id , tvb , offset , len , FALSE ) ;
ber_last_created_item = it ;
2005-03-24 14:21:30 +00:00
} else {
proto_item * pi ;
pi = proto_tree_add_text ( tree , tvb , offset , len , " Unknown OctetString: Length: 0x%02x, Value: 0x " , len ) ;
if ( pi ) {
for ( i = 0 ; i < len ; i + + ) {
proto_item_append_text ( pi , " %02x " , tvb_get_guint8 ( tvb , offset ) ) ;
offset + + ;
}
}
}
2005-08-18 08:37:31 +00:00
if ( out_tvb ) {
2004-12-13 08:15:34 +00:00
if ( len < = ( guint32 ) tvb_length_remaining ( tvb , offset ) ) {
2004-11-30 03:39:34 +00:00
* out_tvb = tvb_new_subset ( tvb , offset , len , len ) ;
} else {
2005-08-28 17:57:30 +00:00
* out_tvb = tvb_new_subset ( tvb , offset , - 1 , - 1 ) ;
2004-11-30 03:39:34 +00:00
}
2004-03-25 09:18:03 +00:00
}
2004-02-20 10:04:10 +00:00
}
return end_offset ;
}
2004-03-25 09:18:03 +00:00
int dissect_ber_octet_string_wcb ( gboolean implicit_tag , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , ber_callback func )
{
2005-04-13 21:20:23 +00:00
tvbuff_t * out_tvb = NULL ;
2004-03-25 09:18:03 +00:00
offset = dissect_ber_octet_string ( implicit_tag , pinfo , tree , tvb , offset , hf_id , ( func ) ? & out_tvb : NULL ) ;
2005-04-13 21:20:23 +00:00
if ( func & & out_tvb & & ( tvb_length ( out_tvb ) > 0 ) ) {
2004-03-25 09:18:03 +00:00
if ( hf_id ! = - 1 )
tree = proto_item_add_subtree ( ber_last_created_item , ett_ber_octet_string ) ;
func ( pinfo , tree , out_tvb , 0 ) ;
}
return offset ;
}
2005-04-27 14:17:14 +00:00
/* 8.8 Encoding of a null value */
int
dissect_ber_null ( gboolean implicit_tag , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id ) {
2005-07-09 02:58:07 +00:00
gint8 class ;
2005-04-27 14:17:14 +00:00
gboolean pc ;
2005-07-09 02:58:07 +00:00
gint32 tag ;
guint32 len ;
2005-04-27 14:17:14 +00:00
int offset_old ;
2005-08-18 08:37:31 +00:00
if ( ! implicit_tag )
{
offset_old = offset ;
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
if ( ( pc ) | |
( ! implicit_tag & & ( ( class ! = BER_CLASS_UNI ) | | ( tag ! = BER_UNI_TAG_NULL ) ) ) ) {
proto_tree_add_text ( tree , tvb , offset_old , offset - offset_old , " BER Error: NULL expected but Class:%d(%s) PC:%d Tag:%d was unexpected " , class , val_to_str ( class , ber_class_codes , " Unknown " ) , pc , tag ) ;
2005-04-27 14:17:14 +00:00
}
2005-08-18 08:37:31 +00:00
offset_old = offset ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , NULL ) ;
if ( len ) {
proto_tree_add_text ( tree , tvb , offset_old , offset - offset_old , " BER Error: NULL expect zero length but Length=%d " , len ) ;
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: unexpected data in NULL type " ) ;
offset + = len ;
}
}
2005-06-24 08:57:41 +00:00
2005-08-18 08:37:31 +00:00
proto_tree_add_item ( tree , hf_id , tvb , offset , 0 , FALSE ) ;
2005-04-27 14:17:14 +00:00
return offset ;
}
2004-02-20 10:04:10 +00:00
int
2004-12-12 01:14:03 +00:00
dissect_ber_integer ( gboolean implicit_tag , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , guint32 * value )
2004-02-20 10:04:10 +00:00
{
2005-08-18 08:37:31 +00:00
guint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2005-08-18 08:37:31 +00:00
guint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
2004-03-25 09:18:03 +00:00
gint32 val ;
2004-08-22 00:31:58 +00:00
gint64 val64 ;
2004-02-20 10:04:10 +00:00
guint32 i ;
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
2004-12-12 01:14:03 +00:00
printf ( " INTEGERnew dissect_ber_integer(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x \n " , name , implicit_tag , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-06-07 05:49:06 +00:00
printf ( " INTEGERnew dissect_ber_integer(%s) entered implicit_tag:%d \n " , name , implicit_tag ) ;
2004-11-14 05:10:44 +00:00
}
}
# endif
2004-11-13 14:16:06 +00:00
if ( ! implicit_tag ) {
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , NULL ) ;
} else {
len = tvb_length_remaining ( tvb , offset ) ;
}
2004-06-24 05:31:21 +00:00
/* ok, we cant handle >4 byte integers so lets fake them */
if ( len > 8 ) {
2004-07-29 08:41:51 +00:00
header_field_info * hfinfo ;
proto_item * pi ;
hfinfo = proto_registrar_get_nth ( hf_id ) ;
pi = proto_tree_add_text ( tree , tvb , offset , len , " %s : 0x " , hfinfo - > name ) ;
if ( pi ) {
for ( i = 0 ; i < len ; i + + ) {
2004-09-25 02:44:45 +00:00
proto_item_append_text ( pi , " %02x " , tvb_get_guint8 ( tvb , offset ) ) ;
offset + + ;
2004-07-29 08:41:51 +00:00
}
}
2004-09-25 02:44:45 +00:00
return offset ;
2004-06-24 05:31:21 +00:00
}
if ( len > 4 ) {
header_field_info * hfinfo ;
2004-08-22 00:31:58 +00:00
val64 = 0 ;
2005-08-18 08:37:31 +00:00
if ( len > 0 ) {
2004-08-22 00:31:58 +00:00
/* extend sign bit */
val64 = ( gint8 ) tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
}
for ( i = 1 ; i < len ; i + + ) {
val64 = ( val64 < < 8 ) | tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
}
2004-06-24 05:31:21 +00:00
hfinfo = proto_registrar_get_nth ( hf_id ) ;
2004-09-25 02:44:45 +00:00
proto_tree_add_text ( tree , tvb , offset - len , len , " %s: % " PRIu64 , hfinfo - > name , val64 ) ;
return offset ;
2004-06-24 05:31:21 +00:00
}
2004-02-20 10:04:10 +00:00
val = 0 ;
2005-08-18 08:37:31 +00:00
if ( len > 0 ) {
2004-03-25 09:18:03 +00:00
/* extend sign bit */
val = ( gint8 ) tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
}
for ( i = 1 ; i < len ; i + + ) {
2004-02-20 10:04:10 +00:00
val = ( val < < 8 ) | tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
}
ber_last_created_item = NULL ;
if ( hf_id ! = - 1 ) {
2005-04-14 20:16:35 +00:00
/* */
2005-08-18 08:37:31 +00:00
if ( len < 1 | | len > 4 ) {
2005-04-14 20:16:35 +00:00
proto_tree_add_text ( tree , tvb , offset - len , len , " Can't handle integer length: %u " , len ) ;
} else {
ber_last_created_item = proto_tree_add_item ( tree , hf_id , tvb , offset - len , len , FALSE ) ;
}
2004-02-20 10:04:10 +00:00
}
if ( value ) {
* value = val ;
}
return offset ;
}
int
2005-02-23 08:57:47 +00:00
dissect_ber_boolean ( gboolean implicit_tag , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id )
2004-02-20 10:04:10 +00:00
{
2005-08-18 08:37:31 +00:00
guint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2005-08-18 08:37:31 +00:00
guint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
guint8 val ;
2004-03-25 09:18:03 +00:00
header_field_info * hfi ;
2004-02-20 10:04:10 +00:00
2005-02-23 08:57:47 +00:00
if ( ! implicit_tag ) {
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , NULL ) ;
/*if(class!=BER_CLASS_UNI)*/
} else {
/* nothing to do here, yet */
}
2004-02-20 10:04:10 +00:00
val = tvb_get_guint8 ( tvb , offset ) ;
offset + = 1 ;
ber_last_created_item = NULL ;
2004-03-25 09:18:03 +00:00
if ( hf_id ! = - 1 ) {
hfi = proto_registrar_get_nth ( hf_id ) ;
2005-08-18 08:37:31 +00:00
if ( hfi - > type = = FT_BOOLEAN )
2004-03-25 09:18:03 +00:00
ber_last_created_item = proto_tree_add_boolean ( tree , hf_id , tvb , offset - 1 , 1 , val ) ;
else
ber_last_created_item = proto_tree_add_uint ( tree , hf_id , tvb , offset - 1 , 1 , val ? 1 : 0 ) ;
2004-02-20 10:04:10 +00:00
}
return offset ;
}
/* this function dissects a BER sequence
*/
2004-12-13 08:15:34 +00:00
int dissect_ber_sequence ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_sequence_t * seq , gint hf_id , gint ett_id ) {
gint8 class ;
2005-05-30 20:51:36 +00:00
gboolean pc , ind = 0 , ind_field ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
2004-03-25 09:18:03 +00:00
proto_tree * tree = parent_tree ;
proto_item * item = NULL ;
2005-08-18 08:37:31 +00:00
int end_offset , s_offset ;
2005-08-28 17:57:30 +00:00
gint length_remaining ;
2004-07-23 23:06:38 +00:00
tvbuff_t * next_tvb ;
2005-08-18 08:37:31 +00:00
s_offset = offset ;
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
2005-08-18 08:37:31 +00:00
printf ( " SEQUENCE dissect_ber_sequence(%s) entered offset:%d len:%d %02x:%02x:%02x \n " , name , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-08-18 08:37:31 +00:00
printf ( " SEQUENCE dissect_ber_sequence(%s) entered \n " , name ) ;
2004-11-14 05:10:44 +00:00
}
}
# endif
if ( ! implicit_tag ) {
/* first we must read the sequence header */
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , & ind ) ;
if ( ind ) {
2005-08-18 08:37:31 +00:00
/* Fixed the length is correctly returned from dissect ber_length
end_offset = tvb_length ( tvb ) ; */
end_offset = offset + len - 2 ;
2004-11-14 05:10:44 +00:00
} else {
end_offset = offset + len ;
}
2004-02-20 10:04:10 +00:00
2004-11-14 05:10:44 +00:00
/* sanity check: we only handle Constructed Universal Sequences */
2005-08-18 08:37:31 +00:00
if ( ( class ! = BER_CLASS_APP ) & & ( class ! = BER_CLASS_PRI ) )
if ( ( ! pc )
2004-03-25 09:18:03 +00:00
| | ( ! implicit_tag & & ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_SEQUENCE ) ) ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2005-03-30 19:09:48 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: Sequence expected but Class:%d(%s) PC:%d Tag:%d was unexpected " , class , val_to_str ( class , ber_class_codes , " Unknown " ) , pc , tag ) ;
2004-11-14 05:10:44 +00:00
return end_offset ;
}
} else {
/* was implicit tag so just use the length of the tvb */
len = tvb_length_remaining ( tvb , offset ) ;
end_offset = offset + len ;
2004-02-20 10:04:10 +00:00
}
/* create subtree */
2005-08-18 08:37:31 +00:00
if ( hf_id ! = - 1 ) {
2004-02-20 10:04:10 +00:00
if ( parent_tree ) {
item = proto_tree_add_item ( parent_tree , hf_id , tvb , offset , len , FALSE ) ;
tree = proto_item_add_subtree ( item , ett_id ) ;
}
}
/* loop over all entries until we reach the end of the sequence */
2004-03-25 09:18:03 +00:00
while ( offset < end_offset ) {
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
2005-08-18 08:37:31 +00:00
int hoffset , eoffset , count ;
/*if(ind){ this sequence was of indefinite length, if this is implicit indefinite impossible maybe
but tcap dissector uses this to eat the tag length then pass into here . . . EOC still on there . . . */
if ( ( tvb_get_guint8 ( tvb , offset ) = = 0 ) & & ( tvb_get_guint8 ( tvb , offset + 1 ) = = 0 ) ) {
if ( show_internal_ber_fields ) {
proto_tree_add_text ( tree , tvb , s_offset , offset + 2 , " ERROR WRONG SEQ EOC " ) ;
}
return end_offset ;
}
/*}*/
hoffset = offset ;
/* read header and len for next field */
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
offset = get_ber_length ( tree , tvb , offset , & len , & ind_field ) ;
eoffset = offset + len ;
ber_sequence_try_again :
/* have we run out of known entries in the sequence ?*/
if ( ! seq - > func ) {
/* it was not, move to the enxt one and try again */
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: This field lies beyond the end of the known sequence definition. " ) ;
offset = eoffset ;
continue ;
}
/* Verify that this one is the one we want.
* Skip check completely if class = = ANY
* of if NOCHKTAG is set
*/
/* XXX Bug in asn2eth,
* for scope [ 7 ] Scope OPTIONAL ,
* it generates
* { BER_CLASS_CON , 7 , BER_FLAGS_OPTIONAL | BER_FLAGS_NOTCHKTAG , dissect_scope } ,
* and there should not be a NOTCHKTAG here
*/
if ( ( ( seq - > class = = BER_CLASS_CON ) | | ( seq - > class = = BER_CLASS_APP ) | | ( seq - > class = = BER_CLASS_PRI ) ) & & ( ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) ) {
if ( ( seq - > class ! = BER_CLASS_ANY )
& & ( seq - > tag ! = - 1 )
& & ( ( seq - > class ! = class )
| | ( seq - > tag ! = tag ) ) ) {
2005-08-22 05:49:09 +00:00
/* it was not, move to the next one and try again */
2005-08-18 08:37:31 +00:00
if ( seq - > flags & BER_FLAGS_OPTIONAL ) {
/* well this one was optional so just skip to the next one and try again. */
seq + + ;
goto ber_sequence_try_again ;
}
if ( seq - > class = = BER_CLASS_UNI ) {
proto_tree_add_text ( tree , tvb , offset , len ,
" BER Error: Wrong field in SEQUENCE expected class:%d (%s) tag:%d (%s) but found class:%d tag:%d " ,
seq - > class , val_to_str ( seq - > class , ber_class_codes , " Unknown " ) ,
seq - > tag , val_to_str ( seq - > tag , ber_uni_tag_codes , " Unknown " ) ,
class , tag ) ;
} else {
proto_tree_add_text ( tree , tvb , offset , len ,
" BER Error: Wrong field in SEQUENCE expected class:%d (%s) tag:%d but found class:%d tag:%d " ,
seq - > class , val_to_str ( seq - > class , ber_class_codes , " Unknown " ) ,
seq - > tag , class , tag ) ;
}
seq + + ;
offset = eoffset ;
continue ;
}
} else if ( ! ( seq - > flags & BER_FLAGS_NOTCHKTAG ) ) {
if ( ( seq - > class ! = BER_CLASS_ANY )
& & ( seq - > tag ! = - 1 )
& & ( ( seq - > class ! = class )
| | ( seq - > tag ! = tag ) ) ) {
/* it was not, move to the enxt one and try again */
if ( seq - > flags & BER_FLAGS_OPTIONAL ) {
/* well this one was optional so just skip to the next one and try again. */
seq + + ;
goto ber_sequence_try_again ;
}
if ( seq - > class = = BER_CLASS_UNI ) {
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: Wrong field in sequence expected class:%d (%s) tag:%d(%s) but found class:%d(%s) tag:%d " , seq - > class , val_to_str ( seq - > class , ber_class_codes , " Unknown " ) , seq - > tag , val_to_str ( seq - > tag , ber_uni_tag_codes , " Unknown " ) , class , val_to_str ( class , ber_class_codes , " Unknown " ) , tag ) ;
} else {
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: Wrong field in sequence expected class:%d (%s) tag:%d but found class:%d(%s) tag:%d " , seq - > class , val_to_str ( seq - > class , ber_class_codes , " Unknown " ) , seq - > tag , class , val_to_str ( class , ber_class_codes , " Unknown " ) , tag ) ;
}
seq + + ;
offset = eoffset ;
continue ;
}
}
if ( ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) {
/* dissect header and len for field */
hoffset = dissect_ber_identifier ( pinfo , tree , tvb , hoffset , NULL , NULL , NULL ) ;
hoffset = dissect_ber_length ( pinfo , tree , tvb , hoffset , NULL , NULL ) ;
2005-08-28 17:57:30 +00:00
length_remaining = tvb_length_remaining ( tvb , hoffset ) ;
if ( length_remaining > eoffset - hoffset - ( 2 * ind_field ) )
length_remaining = eoffset - hoffset - ( 2 * ind_field ) ;
next_tvb = tvb_new_subset ( tvb , hoffset , length_remaining , eoffset - hoffset - ( 2 * ind_field ) ) ;
}
else {
length_remaining = tvb_length_remaining ( tvb , hoffset ) ;
if ( length_remaining > eoffset - hoffset )
length_remaining = eoffset - hoffset ;
next_tvb = tvb_new_subset ( tvb , hoffset , length_remaining , eoffset - hoffset ) ;
2005-08-18 08:37:31 +00:00
}
/* call the dissector for this field */
2005-08-28 17:57:30 +00:00
/*if ((eoffset-hoffset)>length_remaining) {*/
2005-08-18 08:37:31 +00:00
/* If the field is indefinite (i.e. we dont know the
* length ) of if the tvb is short , then just
* give it all of the tvb and hope for the best .
*/
2005-08-28 17:57:30 +00:00
/*next_tvb = tvb_new_subset(tvb, hoffset, -1, -1);*/
2005-08-18 08:37:31 +00:00
/*} else {*/
/*}*/
2004-10-16 12:53:09 +00:00
2005-06-22 09:58:46 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
2005-08-18 08:37:31 +00:00
if ( tvb_length_remaining ( next_tvb , 0 ) > 3 ) {
printf ( " SEQUENCE dissect_ber_sequence(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x \n " , name , offset , tvb_length_remaining ( next_tvb , 0 ) , tvb_get_guint8 ( next_tvb , 0 ) , tvb_get_guint8 ( next_tvb , 1 ) , tvb_get_guint8 ( next_tvb , 2 ) ) ;
2005-06-22 09:58:46 +00:00
} else {
2005-08-18 08:37:31 +00:00
printf ( " SEQUENCE dissect_ber_sequence(%s) calling subdissector \n " , name ) ;
2005-06-22 09:58:46 +00:00
}
}
# endif
2005-08-18 08:37:31 +00:00
count = seq - > func ( pinfo , tree , next_tvb , 0 ) ;
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
printf ( " SEQUENCE dissect_ber_sequence(%s) subdissector ate %d bytes \n " , name , count ) ;
}
# endif
/* if it was optional and no bytes were eaten and it was */
/* supposed to (len<>0), just try again. */
if ( ( len ! = 0 ) & & ( count = = 0 ) & & ( seq - > flags & BER_FLAGS_OPTIONAL ) ) {
seq + + ;
goto ber_sequence_try_again ;
/* move the offset to the beginning of the next sequenced item */
}
offset = eoffset ;
seq + + ;
2005-08-18 21:36:59 +00:00
if ( ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) {
/* if we stripped the tag and length we should also strip the EOC is ind_len */
if ( ind_field = = 1 )
{
/* skip over EOC */
if ( show_internal_ber_fields ) {
proto_tree_add_text ( tree , tvb , offset , count , " SEQ FIELD EOC " ) ;
}
}
}
2005-08-18 08:37:31 +00:00
}
/* if we didnt end up at exactly offset, then we ate too many bytes */
if ( offset ! = end_offset ) {
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: Sequence ate %d too many bytes " , offset - end_offset ) ;
}
if ( ind ) {
/* need to eat this EOC
end_offset = tvb_length ( tvb ) ; */
end_offset + = 2 ;
if ( show_internal_ber_fields ) {
proto_tree_add_text ( tree , tvb , end_offset - 2 , 2 , " SEQ EOC " ) ;
}
}
return end_offset ;
}
2005-08-28 19:50:36 +00:00
/* This function dissects a BER set
*/
int dissect_ber_set ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_sequence_t * set , gint hf_id , gint ett_id ) {
2005-08-18 08:37:31 +00:00
gint8 class ;
gboolean pc , ind = 0 , ind_field ;
gint32 tag ;
guint32 len ;
proto_tree * tree = parent_tree ;
proto_item * item = NULL ;
int end_offset , s_offset ;
2005-08-28 17:57:30 +00:00
gint length_remaining ;
2005-08-18 08:37:31 +00:00
tvbuff_t * next_tvb ;
2005-08-28 19:50:36 +00:00
const ber_sequence_t * cset = NULL ;
# define MAX_SET_ELEMENTS 32
guint32 mandatory_fields = 0 ;
guint8 set_idx ;
gboolean first_pass ;
2005-08-18 08:37:31 +00:00
s_offset = offset ;
2005-06-22 09:58:46 +00:00
# ifdef DEBUG_BER
2005-08-28 19:50:36 +00:00
{
2005-06-22 09:58:46 +00:00
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
2005-08-22 05:49:09 +00:00
printf ( " SET dissect_ber_set(%s) entered offset:%d len:%d %02x:%02x:%02x \n " , name , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
2005-06-22 09:58:46 +00:00
} else {
2005-08-22 05:49:09 +00:00
printf ( " SET dissect_ber_set(%s) entered \n " , name ) ;
2005-06-22 09:58:46 +00:00
}
}
# endif
2005-08-28 19:50:36 +00:00
2005-08-18 08:37:31 +00:00
if ( ! implicit_tag ) {
/* first we must read the sequence header */
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , & ind ) ;
if ( ind ) {
/* Fixed the length is correctly returned from dissect ber_length
end_offset = tvb_length ( tvb ) ; */
end_offset = offset + len - 2 ;
} else {
end_offset = offset + len ;
2004-10-16 12:53:09 +00:00
}
2005-08-18 08:37:31 +00:00
2005-08-28 19:50:36 +00:00
/* sanity check: we only handle Constructed Universal Sets */
if ( ( class ! = BER_CLASS_APP ) & & ( class ! = BER_CLASS_PRI ) )
if ( ( ! pc )
2005-08-18 08:37:31 +00:00
| | ( ! implicit_tag & & ( ( class ! = BER_CLASS_UNI )
2005-08-28 19:50:36 +00:00
| | ( tag ! = BER_UNI_TAG_SET ) ) ) ) {
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: SET expected but Class:%d(%s) PC:%d Tag:%d was found " , class , val_to_str ( class , ber_class_codes , " Unknown " ) , pc , tag ) ;
return end_offset ;
2005-08-18 08:37:31 +00:00
}
} else {
/* was implicit tag so just use the length of the tvb */
len = tvb_length_remaining ( tvb , offset ) ;
end_offset = offset + len ;
}
/* create subtree */
2005-08-28 19:50:36 +00:00
if ( hf_id ! = - 1 ) {
2005-08-18 08:37:31 +00:00
if ( parent_tree ) {
item = proto_tree_add_item ( parent_tree , hf_id , tvb , offset , len , FALSE ) ;
tree = proto_item_add_subtree ( item , ett_id ) ;
}
}
2005-08-28 19:50:36 +00:00
/* record the mandatory elements of the set so we can check we founf everything at the end
we can only record 32 elements for now . . . */
for ( set_idx = 0 ; ( cset = & set [ set_idx ] ) - > func & & ( set_idx < MAX_SET_ELEMENTS ) ; set_idx + + ) {
if ( ! ( cset - > flags & BER_FLAGS_OPTIONAL ) )
mandatory_fields | = 1 < < set_idx ;
}
/* loop over all entries until we reach the end of the set */
2005-08-18 08:37:31 +00:00
while ( offset < end_offset ) {
gint8 class ;
gboolean pc ;
gint32 tag ;
guint32 len ;
int hoffset , eoffset , count ;
/*if(ind){ this sequence was of indefinite length, if this is implicit indefinite impossible maybe
2005-08-28 19:50:36 +00:00
but tcap dissector uses this to eat the tag length then pass into here . . . EOC still on there . . . */
2005-08-18 08:37:31 +00:00
if ( ( tvb_get_guint8 ( tvb , offset ) = = 0 ) & & ( tvb_get_guint8 ( tvb , offset + 1 ) = = 0 ) ) {
if ( show_internal_ber_fields ) {
2005-08-28 19:50:36 +00:00
proto_tree_add_text ( tree , tvb , s_offset , offset + 2 , " SEQ EOC " ) ;
2005-08-18 08:37:31 +00:00
}
return end_offset ;
}
2005-08-28 19:50:36 +00:00
/* } */
2004-03-25 09:18:03 +00:00
hoffset = offset ;
2004-02-20 10:04:10 +00:00
/* read header and len for next field */
2004-03-25 09:18:03 +00:00
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
2005-04-20 08:35:47 +00:00
offset = get_ber_length ( tree , tvb , offset , & len , & ind_field ) ;
2004-03-25 09:18:03 +00:00
eoffset = offset + len ;
2005-08-18 08:37:31 +00:00
2005-08-28 19:50:36 +00:00
/* Look through the Set to see if this class/id exists and
* hasn ' t been seen before
2004-07-20 10:45:11 +00:00
* Skip check completely if class = = ANY
2004-10-24 03:51:27 +00:00
* of if NOCHKTAG is set
2004-07-20 10:45:11 +00:00
*/
2004-11-14 05:10:44 +00:00
2005-08-28 19:50:36 +00:00
for ( first_pass = TRUE , cset = set , set_idx = 0 ; cset - > func | | first_pass ; cset + + , set_idx + + ) {
/* we reset for a second pass when we will look for choices */
if ( ! cset - > func ) {
first_pass = FALSE ;
cset = set ; /* reset to the beginning */
set_idx = 0 ;
2004-11-14 05:10:44 +00:00
}
2005-08-28 19:50:36 +00:00
if ( ( first_pass & & ( ( cset - > class = = class ) & & ( cset - > tag = = tag ) ) ) | |
( ! first_pass & & ( ( cset - > class = = BER_CLASS_ANY ) & & ( cset - > tag = = - 1 ) ) ) ) /* choices */
{
if ( ! ( cset - > flags & BER_FLAGS_NOOWNTAG ) ) {
/* dissect header and len for field */
hoffset = dissect_ber_identifier ( pinfo , tree , tvb , hoffset , NULL , NULL , NULL ) ;
hoffset = dissect_ber_length ( pinfo , tree , tvb , hoffset , NULL , NULL ) ;
length_remaining = tvb_length_remaining ( tvb , hoffset ) ;
if ( length_remaining > eoffset - hoffset - ( 2 * ind_field ) )
length_remaining = eoffset - hoffset - ( 2 * ind_field ) ;
next_tvb = tvb_new_subset ( tvb , hoffset , length_remaining , eoffset - hoffset - ( 2 * ind_field ) ) ;
}
else {
length_remaining = tvb_length_remaining ( tvb , hoffset ) ;
if ( length_remaining > eoffset - hoffset )
length_remaining = eoffset - hoffset ;
next_tvb = tvb_new_subset ( tvb , hoffset , length_remaining , eoffset - hoffset ) ;
}
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +00:00
2005-08-28 19:50:36 +00:00
/* call the dissector for this field */
/*if ((eoffset-hoffset)>length_remaining) {*/
/* If the field is indefinite (i.e. we dont know the
* length ) of if the tvb is short , then just
* give it all of the tvb and hope for the best .
*/
/*next_tvb = tvb_new_subset(tvb, hoffset, -1, -1);*/
/*} else {*/
2005-08-18 08:37:31 +00:00
2005-08-28 19:50:36 +00:00
/*}*/
2004-02-20 10:04:10 +00:00
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( next_tvb , 0 ) > 3 ) {
2005-08-22 05:49:09 +00:00
printf ( " SET dissect_ber_set(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x \n " , name , offset , tvb_length_remaining ( next_tvb , 0 ) , tvb_get_guint8 ( next_tvb , 0 ) , tvb_get_guint8 ( next_tvb , 1 ) , tvb_get_guint8 ( next_tvb , 2 ) ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-08-22 05:49:09 +00:00
printf ( " SET dissect_ber_set(%s) calling subdissector \n " , name ) ;
2004-11-14 05:10:44 +00:00
}
}
# endif
2005-08-28 19:50:36 +00:00
count = cset - > func ( pinfo , tree , next_tvb , 0 ) ;
if ( count ) {
/* we found it! */
if ( set_idx < MAX_SET_ELEMENTS )
mandatory_fields & = ~ ( 1 < < set_idx ) ;
offset = eoffset ;
if ( ! ( cset - > flags & BER_FLAGS_NOOWNTAG ) ) {
/* if we stripped the tag and length we should also strip the EOC is ind_len */
if ( ind_field = = 1 )
2005-08-18 21:36:59 +00:00
{
2005-08-28 19:50:36 +00:00
/* skip over EOC */
if ( show_internal_ber_fields ) {
proto_tree_add_text ( tree , tvb , offset , count , " SET FIELD EOC " ) ;
}
2005-08-18 21:36:59 +00:00
}
2005-08-28 19:50:36 +00:00
}
break ;
}
}
}
if ( ! cset - > func ) {
/* we didn't find a match */
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: Unknown field in SET class:%d(%s) tag:%d " , class , val_to_str ( class , ber_class_codes , " Unknown " ) , tag ) ;
2005-08-18 21:36:59 +00:00
2005-08-28 19:50:36 +00:00
}
}
if ( mandatory_fields ) {
/* OK - we didn't find some of the elements we expected */
for ( set_idx = 0 ; ( cset = & set [ set_idx ] ) - > func & & ( set_idx < MAX_SET_ELEMENTS ) ; set_idx + + ) {
if ( mandatory_fields & ( 1 < < set_idx ) ) {
/* here is something we should have seen - but didn't! */
proto_tree_add_text ( tree , tvb , offset , len ,
" BER Error: Missing field in SET class:%d (%s) tag:%d expected " ,
cset - > class , val_to_str ( cset - > class , ber_class_codes , " Unknown " ) ,
cset - > tag ) ;
}
}
2004-02-20 10:04:10 +00:00
}
/* if we didnt end up at exactly offset, then we ate too many bytes */
2005-08-28 19:50:36 +00:00
if ( offset ! = end_offset ) {
2005-04-13 20:59:39 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2005-08-28 19:50:36 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: SET ate %d too many bytes " , offset - end_offset ) ;
2004-02-20 10:04:10 +00:00
}
2005-08-28 19:50:36 +00:00
2005-08-18 08:37:31 +00:00
if ( ind ) {
/* need to eat this EOC
end_offset = tvb_length ( tvb ) ; */
end_offset + = 2 ;
if ( show_internal_ber_fields ) {
2005-08-28 19:50:36 +00:00
proto_tree_add_text ( tree , tvb , end_offset - 2 , 2 , " SET EOC " ) ;
}
}
2004-02-20 10:04:10 +00:00
return end_offset ;
2005-08-28 19:50:36 +00:00
2004-02-20 10:04:10 +00:00
}
/* this function dissects a BER choice
2004-10-28 11:35:43 +00:00
* If we did not find a matching choice , just return offset unchanged
* in case it was a CHOICE { } OPTIONAL
2004-02-20 10:04:10 +00:00
*/
int
2005-07-21 21:12:09 +00:00
dissect_ber_choice ( packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_choice_t * choice , gint hf_id , gint ett_id , gint * branch_taken )
2004-02-20 10:04:10 +00:00
{
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-10-24 03:51:27 +00:00
gboolean pc , ind ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
2004-12-13 08:15:34 +00:00
const ber_choice_t * ch ;
2004-02-20 10:04:10 +00:00
proto_tree * tree = parent_tree ;
proto_item * item = NULL ;
2004-11-14 05:10:44 +00:00
int end_offset , start_offset , count ;
2004-03-25 09:18:03 +00:00
int hoffset = offset ;
2004-06-25 09:24:17 +00:00
header_field_info * hfinfo ;
2005-08-28 17:57:30 +00:00
gint length , length_remaining ;
2004-11-14 05:10:44 +00:00
tvbuff_t * next_tvb ;
2005-08-28 19:50:36 +00:00
gboolean first_pass ;
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
2005-07-21 21:12:09 +00:00
printf ( " CHOICE dissect_ber_choice(%s) entered offset:%d len:%d %02x:%02x:%02x \n " , name , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-07-21 21:12:09 +00:00
printf ( " CHOICE dissect_ber_choice(%s) entered len:%d \n " , name , tvb_length_remaining ( tvb , offset ) ) ;
2004-11-14 05:10:44 +00:00
}
}
# endif
2004-10-28 11:35:43 +00:00
start_offset = offset ;
2004-03-25 09:18:03 +00:00
/* read header and len for choice field */
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
2005-04-20 08:35:47 +00:00
offset = get_ber_length ( parent_tree , tvb , offset , & len , & ind ) ;
2005-08-18 08:37:31 +00:00
end_offset = offset + len ;
2004-06-25 09:24:17 +00:00
/* Some sanity checks.
* The hf field passed to us MUST be an integer type
*/
if ( hf_id ! = - 1 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
switch ( hfinfo - > type ) {
case FT_UINT8 :
case FT_UINT16 :
case FT_UINT24 :
case FT_UINT32 :
break ;
default :
2005-07-21 21:12:09 +00:00
proto_tree_add_text ( tree , tvb , offset , len , " dissect_ber_choice(): Was passed a HF field that was not integer type : %s " , hfinfo - > abbrev ) ;
fprintf ( stderr , " dissect_ber_choice(): frame:%d offset:%d Was passed a HF field that was not integer type : %s \n " , pinfo - > fd - > num , offset , hfinfo - > abbrev ) ;
2004-06-25 09:24:17 +00:00
return end_offset ;
}
}
2004-02-20 10:04:10 +00:00
/* loop over all entries until we find the right choice or
run out of entries */
2004-03-25 09:18:03 +00:00
ch = choice ;
2005-08-28 19:50:36 +00:00
first_pass = TRUE ;
while ( ch - > func | | first_pass ) {
/* we reset for a second pass when we will look for choices */
if ( ! ch - > func ) {
first_pass = FALSE ;
ch = choice ; /* reset to the beginning */
}
2004-12-12 22:19:00 +00:00
choice_try_again :
# ifdef DEBUG_BER
printf ( " CHOICE testing potential subdissector class:%d:(expected)%d tag:%d:(expected)%d flags:%d \n " , class , ch - > class , tag , ch - > tag , ch - > flags ) ;
# endif
2005-08-28 19:50:36 +00:00
if ( ( first_pass & & ( ( ( ch - > class = = class ) & & ( ch - > tag = = tag ) )
| | ( ( ch - > class = = class ) & & ( ch - > tag = = - 1 ) & & ( ch - > flags & BER_FLAGS_NOOWNTAG ) ) ) ) | |
( ! first_pass & & ( ( ( ch - > class = = BER_CLASS_ANY ) & & ( ch - > tag = = - 1 ) ) ) ) /* we failed on the first pass so now try any choices */
2004-12-12 22:19:00 +00:00
) {
2005-08-18 08:37:31 +00:00
if ( ! ( ch - > flags & BER_FLAGS_NOOWNTAG ) ) {
2004-03-25 09:18:03 +00:00
/* dissect header and len for field */
2004-11-14 05:10:44 +00:00
hoffset = dissect_ber_identifier ( pinfo , tree , tvb , start_offset , NULL , NULL , NULL ) ;
2004-03-25 09:18:03 +00:00
hoffset = dissect_ber_length ( pinfo , tree , tvb , hoffset , NULL , NULL ) ;
2004-11-14 05:10:44 +00:00
start_offset = hoffset ;
2005-08-18 08:37:31 +00:00
if ( ind )
{
length = len - 2 ;
}
else
{
length = len ;
}
2004-03-25 09:18:03 +00:00
}
2005-08-18 08:37:31 +00:00
else
length = end_offset - hoffset ;
2004-03-25 09:18:03 +00:00
/* create subtree */
if ( hf_id ! = - 1 ) {
if ( parent_tree ) {
item = proto_tree_add_uint ( parent_tree , hf_id , tvb , hoffset , end_offset - hoffset , ch - > value ) ;
tree = proto_item_add_subtree ( item , ett_id ) ;
}
}
2005-08-28 17:57:30 +00:00
length_remaining = tvb_length_remaining ( tvb , hoffset ) ;
if ( length_remaining > length )
length_remaining = length ;
next_tvb = tvb_new_subset ( tvb , hoffset , length_remaining , length ) ;
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( next_tvb , 0 ) > 3 ) {
2005-07-21 21:12:09 +00:00
printf ( " CHOICE dissect_ber_choice(%s) calling subdissector start_offset:%d offset:%d len:%d %02x:%02x:%02x \n " , name , start_offset , offset , tvb_length_remaining ( next_tvb , 0 ) , tvb_get_guint8 ( next_tvb , 0 ) , tvb_get_guint8 ( next_tvb , 1 ) , tvb_get_guint8 ( next_tvb , 2 ) ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-07-21 21:12:09 +00:00
printf ( " CHOICE dissect_ber_choice(%s) calling subdissector len:%d \n " , name , tvb_length ( next_tvb ) ) ;
2004-11-14 05:10:44 +00:00
}
}
# endif
count = ch - > func ( pinfo , tree , next_tvb , 0 ) ;
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
2005-07-21 21:12:09 +00:00
printf ( " CHOICE dissect_ber_choice(%s) subdissector ate %d bytes \n " , name , count ) ;
2004-11-14 05:10:44 +00:00
}
# endif
2004-12-12 22:19:00 +00:00
if ( ( count = = 0 ) & & ( ch - > class = = class ) & & ( ch - > tag = = - 1 ) & & ( ch - > flags & BER_FLAGS_NOOWNTAG ) ) {
/* wrong one, break and try again */
ch + + ;
goto choice_try_again ;
}
2005-08-18 08:37:31 +00:00
if ( ! ( ch - > flags & BER_FLAGS_NOOWNTAG ) ) {
if ( ind )
{
/* we are traversing a indfinite length choice where we did not pass the tag length */
/* we need to eat the EOC */
if ( show_internal_ber_fields ) {
proto_tree_add_text ( tree , tvb , start_offset , count + 2 , " CHOICE EOC " ) ;
}
}
2004-10-24 03:51:27 +00:00
}
2005-08-18 08:37:31 +00:00
return end_offset ;
2004-02-20 10:04:10 +00:00
break ;
}
ch + + ;
}
2004-10-28 11:35:43 +00:00
# ifdef REMOVED
/*XXX here we should have another flag to the CHOICE to distinguish
* between teh case when we know it is a mandatory or if the CHOICE is optional = = no arm matched */
2004-02-20 10:04:10 +00:00
/* oops no more entries and we still havent found
* our guy : - (
*/
2004-03-25 09:18:03 +00:00
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: This choice field was not found. " ) ;
2004-02-20 10:04:10 +00:00
return end_offset ;
2004-10-28 11:35:43 +00:00
# endif
return start_offset ;
2004-02-20 10:04:10 +00:00
}
2004-03-25 09:18:03 +00:00
#if 0
2004-02-20 10:04:10 +00:00
/* this function dissects a BER GeneralString
*/
int
dissect_ber_GeneralString ( packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , char * name_string , int name_len )
{
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
int end_offset ;
char str_arr [ 256 ] ;
guint32 max_len ;
char * str ;
str = str_arr ;
max_len = 255 ;
if ( name_string ) {
str = name_string ;
max_len = name_len ;
}
/* first we must read the GeneralString header */
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
2004-03-25 09:18:03 +00:00
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , NULL ) ;
2004-02-20 10:04:10 +00:00
end_offset = offset + len ;
/* sanity check: we only handle Universal GeneralString*/
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_GENSTR ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-02-20 10:04:10 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: GeneralString expected but Class:%d PC:%d Tag:%d was unexpected " , class , pc , tag ) ;
return end_offset ;
}
if ( len > = ( max_len - 1 ) ) {
len = max_len - 1 ;
}
tvb_memcpy ( tvb , str , offset , len ) ;
str [ len ] = 0 ;
if ( hf_id ! = - 1 ) {
proto_tree_add_string ( tree , hf_id , tvb , offset , len , str ) ;
}
return end_offset ;
}
2004-03-25 09:18:03 +00:00
# endif
2005-08-18 08:37:31 +00:00
int dissect_ber_restricted_string ( gboolean implicit_tag , gint32 type , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , tvbuff_t * * out_tvb ) {
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-03-25 09:18:03 +00:00
gboolean pc ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-03-25 09:18:03 +00:00
guint32 len ;
int eoffset ;
int hoffset = offset ;
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
printf ( " RESTRICTED STRING dissect_ber_octet string(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x \n " , name , implicit_tag , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
} else {
printf ( " RESTRICTED STRING dissect_ber_octet_string(%s) entered \n " , name ) ;
}
}
# endif
2004-03-25 09:18:03 +00:00
2005-08-18 08:37:31 +00:00
if ( ! implicit_tag ) {
2004-11-14 05:10:44 +00:00
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
2005-04-20 08:35:47 +00:00
offset = get_ber_length ( tree , tvb , offset , & len , NULL ) ;
2004-11-14 05:10:44 +00:00
eoffset = offset + len ;
/* sanity check */
2004-03-25 09:18:03 +00:00
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = type ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-03-25 09:18:03 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: String with tag=%d expected but Class:%d PC:%d Tag:%d was unexpected " , type , class , pc , tag ) ;
return eoffset ;
}
}
/* 8.21.3 */
2004-11-14 05:10:44 +00:00
return dissect_ber_octet_string ( implicit_tag , pinfo , tree , tvb , hoffset , hf_id , out_tvb ) ;
2004-03-25 09:18:03 +00:00
}
2004-02-20 10:04:10 +00:00
int
2004-03-25 09:18:03 +00:00
dissect_ber_GeneralString ( packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , char * name_string , guint name_len )
2004-02-20 10:04:10 +00:00
{
2005-04-13 21:20:23 +00:00
tvbuff_t * out_tvb = NULL ;
2004-03-25 09:18:03 +00:00
2004-03-26 00:21:53 +00:00
offset = dissect_ber_restricted_string ( FALSE , BER_UNI_TAG_GeneralString , pinfo , tree , tvb , offset , hf_id , ( name_string ) ? & out_tvb : NULL ) ;
2004-03-25 09:18:03 +00:00
2005-08-18 08:37:31 +00:00
if ( name_string ) {
if ( out_tvb & & tvb_length ( out_tvb ) > = name_len ) {
2004-03-25 09:18:03 +00:00
tvb_memcpy ( out_tvb , name_string , 0 , name_len - 1 ) ;
name_string [ name_len - 1 ] = ' \0 ' ;
2005-08-18 08:37:31 +00:00
} else if ( out_tvb ) {
2004-03-25 09:18:03 +00:00
tvb_memcpy ( out_tvb , name_string , 0 , - 1 ) ;
name_string [ tvb_length ( out_tvb ) ] = ' \0 ' ;
}
}
return offset ;
}
2005-06-22 09:58:46 +00:00
/* 8.19 Encoding of an object identifier value */
2004-03-25 09:18:03 +00:00
int dissect_ber_object_identifier ( gboolean implicit_tag , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , char * value_string ) {
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2005-04-28 09:54:03 +00:00
guint32 len ;
2004-03-25 09:18:03 +00:00
int eoffset ;
2005-08-20 02:33:33 +00:00
char * str , * name ;
2004-07-29 09:32:13 +00:00
proto_item * item ;
2004-03-25 09:18:03 +00:00
2005-08-20 02:33:33 +00:00
str = ep_alloc ( MAX_OID_STR_LEN ) ;
2004-11-14 09:45:04 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
printf ( " OBJECT IDENTIFIER dissect_ber_object_identifier(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x \n " , name , implicit_tag , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
} else {
printf ( " OBJECT IDENTIFIER dissect_ber_object_identifier(%s) entered \n " , name ) ;
}
}
# endif
2005-08-18 08:37:31 +00:00
if ( value_string ) {
2004-03-25 09:18:03 +00:00
value_string [ 0 ] = ' \0 ' ;
}
2005-08-18 08:37:31 +00:00
if ( ! implicit_tag ) {
2004-11-14 05:10:44 +00:00
/* sanity check */
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , NULL ) ;
eoffset = offset + len ;
2004-03-25 09:18:03 +00:00
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_OID ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-03-25 09:18:03 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: Object Identifier expected but Class:%d PC:%d Tag:%d was unexpected " , class , pc , tag ) ;
return eoffset ;
}
2004-11-14 05:10:44 +00:00
} else {
len = tvb_length_remaining ( tvb , offset ) ;
eoffset = offset + len ;
2004-03-25 09:18:03 +00:00
}
2005-08-20 02:33:33 +00:00
oid_to_str_buf ( tvb_get_ptr ( tvb , offset , len ) , len , str , MAX_OID_STR_LEN ) ;
2005-04-28 09:54:03 +00:00
offset + = len ;
2004-03-25 09:18:03 +00:00
2005-08-18 08:37:31 +00:00
if ( hf_id ! = - 1 ) {
2004-07-29 09:32:13 +00:00
item = proto_tree_add_string ( tree , hf_id , tvb , offset - len , len , str ) ;
/* see if we know the name of this oid */
if ( item ) {
name = g_hash_table_lookup ( oid_table , str ) ;
if ( name ) {
proto_item_append_text ( item , " (%s) " , name ) ;
}
}
2004-03-25 09:18:03 +00:00
}
2005-08-18 08:37:31 +00:00
if ( value_string ) {
2004-03-25 09:18:03 +00:00
strcpy ( value_string , str ) ;
}
return eoffset ;
}
2004-12-13 08:15:34 +00:00
static int dissect_ber_sq_of ( gboolean implicit_tag , gint32 type , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_sequence_t * seq , gint hf_id , gint ett_id ) {
gint8 class ;
2005-04-22 04:10:44 +00:00
gboolean pc , ind = FALSE , ind_field ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
2005-08-18 08:37:31 +00:00
2004-03-25 09:18:03 +00:00
proto_tree * tree = parent_tree ;
proto_item * item = NULL ;
int cnt , hoffset , end_offset ;
header_field_info * hfi ;
2004-02-20 10:04:10 +00:00
2004-11-14 05:10:44 +00:00
# ifdef DEBUG_BER
{
char * name ;
header_field_info * hfinfo ;
if ( hf_id > 0 ) {
hfinfo = proto_registrar_get_nth ( hf_id ) ;
name = hfinfo - > name ;
} else {
name = " unnamed " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
2005-08-18 08:37:31 +00:00
printf ( " SQ OF dissect_ber_sq_of(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x \n " , name , implicit_tag , offset , tvb_length_remaining ( tvb , offset ) , tvb_get_guint8 ( tvb , offset ) , tvb_get_guint8 ( tvb , offset + 1 ) , tvb_get_guint8 ( tvb , offset + 2 ) ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-08-18 08:37:31 +00:00
printf ( " SQ OF dissect_ber_sq_of(%s) entered \n " , name ) ;
2004-11-14 05:10:44 +00:00
}
}
# endif
2004-10-24 03:51:27 +00:00
2004-11-14 05:10:44 +00:00
if ( ! implicit_tag ) {
2005-08-18 08:37:31 +00:00
/* first we must read the sequence header */
2004-11-14 05:10:44 +00:00
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , & ind ) ;
if ( ind ) {
/* if the length is indefinite we dont really know (yet) where the
* object ends so assume it spans the rest of the tvb for now .
*/
2005-08-18 08:37:31 +00:00
end_offset = offset + len ;
2004-11-14 05:10:44 +00:00
} else {
end_offset = offset + len ;
}
2004-02-20 10:04:10 +00:00
2004-11-14 05:10:44 +00:00
/* sanity check: we only handle Constructed Universal Sequences */
2005-08-18 08:37:31 +00:00
if ( ( class ! = BER_CLASS_APP ) & & ( class ! = BER_CLASS_PRI ) )
if ( ! pc
2004-11-14 05:10:44 +00:00
| | ( ! implicit_tag & & ( ( class ! = BER_CLASS_UNI )
2004-03-25 09:18:03 +00:00
| | ( tag ! = type ) ) ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-11-14 05:10:44 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: %s Of expected but Class:%d PC:%d Tag:%d was unexpected " ,
2004-03-25 09:18:03 +00:00
( type = = BER_UNI_TAG_SEQUENCE ) ? " Set " : " Sequence " , class , pc , tag ) ;
2004-11-14 05:10:44 +00:00
return end_offset ;
}
} else {
2005-08-18 08:37:31 +00:00
/* the tvb length should be correct now nope we could be comming from an implicit choice or sequence, thus we
read the items we match and return the length */
2004-11-14 05:10:44 +00:00
len = tvb_length_remaining ( tvb , offset ) ;
end_offset = offset + len ;
2004-02-20 10:04:10 +00:00
}
2004-03-25 09:18:03 +00:00
/* count number of items */
cnt = 0 ;
hoffset = offset ;
2005-08-29 08:24:15 +00:00
/* only count the number of items IFF we have the full blob,
* else this will just generate a [ short frame ] before we even start
* dissecting a single item .
*/
/* XXX Do we really need to count them at all ? ronnie */
if ( tvb_length_remaining ( tvb , offset ) = = tvb_reported_length_remaining ( tvb , offset ) ) {
while ( offset < end_offset ) {
guint32 len ;
if ( ind ) { /* this sequence of was of indefinite length, so check for EOC */
if ( ( tvb_get_guint8 ( tvb , offset ) = = 0 ) & & ( tvb_get_guint8 ( tvb , offset + 1 ) = = 0 ) ) {
break ;
}
2004-10-24 03:51:27 +00:00
}
2005-08-29 08:24:15 +00:00
/* read header and len for next field */
offset = get_ber_identifier ( tvb , offset , NULL , NULL , NULL ) ;
offset = get_ber_length ( tree , tvb , offset , & len , NULL ) ;
/* best place to get real length of implicit sequence of or set of is here... */
/* adjust end_offset if we find somthing that doesnt match */
offset + = len ;
cnt + + ;
}
2004-03-25 09:18:03 +00:00
}
offset = hoffset ;
2004-02-20 10:04:10 +00:00
/* create subtree */
2005-08-18 08:37:31 +00:00
if ( hf_id ! = - 1 ) {
2004-03-25 09:18:03 +00:00
hfi = proto_registrar_get_nth ( hf_id ) ;
2004-02-20 10:04:10 +00:00
if ( parent_tree ) {
2005-08-18 08:37:31 +00:00
if ( hfi - > type = = FT_NONE ) {
2004-03-25 09:18:03 +00:00
item = proto_tree_add_item ( parent_tree , hf_id , tvb , offset , len , FALSE ) ;
2004-05-11 10:57:14 +00:00
proto_item_append_text ( item , " : " ) ;
} else {
2004-03-25 09:18:03 +00:00
item = proto_tree_add_uint ( parent_tree , hf_id , tvb , offset , len , cnt ) ;
proto_item_append_text ( item , ( cnt = = 1 ) ? " item " : " items " ) ;
}
2004-02-20 10:04:10 +00:00
tree = proto_item_add_subtree ( item , ett_id ) ;
}
}
/* loop over all entries until we reach the end of the sequence */
2004-03-25 09:18:03 +00:00
while ( offset < end_offset ) {
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-03-25 09:18:03 +00:00
gboolean pc ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-03-25 09:18:03 +00:00
guint32 len ;
int eoffset ;
2005-08-18 08:37:31 +00:00
int hoffset , count ;
2004-03-25 09:18:03 +00:00
2005-08-19 01:56:14 +00:00
hoffset = offset ;
2005-08-18 08:37:31 +00:00
if ( ind ) { /*this sequence of was of indefinite length, so check for EOC */
2004-10-24 03:51:27 +00:00
if ( ( tvb_get_guint8 ( tvb , offset ) = = 0 ) & & ( tvb_get_guint8 ( tvb , offset + 1 ) = = 0 ) ) {
if ( show_internal_ber_fields ) {
2005-08-18 08:37:31 +00:00
proto_tree_add_text ( tree , tvb , hoffset , end_offset - hoffset , " SEQ OF EOC " ) ;
2004-10-24 03:51:27 +00:00
}
return offset + 2 ;
}
}
2004-03-25 09:18:03 +00:00
/* read header and len for next field */
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
2005-04-20 08:35:47 +00:00
offset = get_ber_length ( tree , tvb , offset , & len , & ind_field ) ;
2004-10-24 03:51:27 +00:00
if ( ind_field ) {
/* if the length is indefinite we dont really know (yet) where the
* object ends so assume it spans the rest of the tvb for now .
*/
2005-08-18 08:37:31 +00:00
eoffset = offset + len ;
2004-10-24 03:51:27 +00:00
} else {
eoffset = offset + len ;
}
2004-03-25 09:18:03 +00:00
/* verify that this one is the one we want */
2005-08-18 08:37:31 +00:00
/* ahup if we are implicit then we return to the uper layer how much we have used */
2004-11-14 09:45:04 +00:00
if ( seq - > class ! = BER_CLASS_ANY ) {
2005-08-18 08:37:31 +00:00
if ( ( seq - > class ! = class )
2004-03-25 09:18:03 +00:00
| | ( seq - > tag ! = tag ) ) {
2005-08-18 08:37:31 +00:00
if ( ! ( seq - > flags & BER_FLAGS_NOTCHKTAG ) ) {
2004-07-22 10:05:59 +00:00
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: Wrong field in SQ OF " ) ;
2004-03-25 09:18:03 +00:00
offset = eoffset ;
continue ;
2005-08-18 08:37:31 +00:00
/* wrong.... */
2004-03-25 09:18:03 +00:00
}
2004-11-14 09:45:04 +00:00
}
2004-03-25 09:18:03 +00:00
}
2005-08-18 08:37:31 +00:00
if ( ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) & & ! ( seq - > flags & BER_FLAGS_IMPLTAG ) ) {
2004-03-25 09:18:03 +00:00
/* dissect header and len for field */
hoffset = dissect_ber_identifier ( pinfo , tree , tvb , hoffset , NULL , NULL , NULL ) ;
hoffset = dissect_ber_length ( pinfo , tree , tvb , hoffset , NULL , NULL ) ;
}
2004-02-20 10:04:10 +00:00
/* call the dissector for this field */
2004-10-24 03:51:27 +00:00
count = seq - > func ( pinfo , tree , tvb , hoffset ) - hoffset ;
2005-08-18 08:37:31 +00:00
/* hold on if we are implicit and the result is zero, i.e. the item in the sequence of
doesnt match the next item , thus this implicit sequence is over , return the number of bytes
we have eaten to allow the possible upper sequence continue . . . */
2005-08-29 08:24:15 +00:00
cnt + + ; /* rubbish*/
2004-10-24 03:51:27 +00:00
if ( ind_field ) {
/* previous field was of indefinite length so we have
* no choice but use whatever the subdissector told us
* as size for the field .
2005-08-18 08:37:31 +00:00
* not any more the length should be correct
2004-10-24 03:51:27 +00:00
*/
2005-08-18 08:37:31 +00:00
offset = eoffset ;
2004-10-24 03:51:27 +00:00
} else {
offset = eoffset ;
}
2004-02-20 10:04:10 +00:00
}
/* if we didnt end up at exactly offset, then we ate too many bytes */
2005-08-18 08:37:31 +00:00
if ( offset ! = end_offset ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-03-25 09:18:03 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: %s Of ate %d too many bytes " ,
( type = = BER_UNI_TAG_SEQUENCE ) ? " Set " : " Sequence " , offset - end_offset ) ;
2004-02-20 10:04:10 +00:00
}
return end_offset ;
}
2004-12-13 08:15:34 +00:00
int dissect_ber_sequence_of ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_sequence_t * seq , gint hf_id , gint ett_id ) {
2004-03-25 09:18:03 +00:00
return dissect_ber_sq_of ( implicit_tag , BER_UNI_TAG_SEQUENCE , pinfo , parent_tree , tvb , offset , seq , hf_id , ett_id ) ;
}
2004-12-13 08:15:34 +00:00
int dissect_ber_set_of ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_sequence_t * seq , gint hf_id , gint ett_id ) {
2004-03-25 09:18:03 +00:00
return dissect_ber_sq_of ( implicit_tag , BER_UNI_TAG_SET , pinfo , parent_tree , tvb , offset , seq , hf_id , ett_id ) ;
}
2004-02-20 10:04:10 +00:00
int
2004-12-12 22:47:24 +00:00
dissect_ber_GeneralizedTime ( gboolean implicit_tag , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id )
2004-02-20 10:04:10 +00:00
{
char str [ 32 ] ;
const guint8 * tmpstr ;
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
int end_offset ;
2004-12-12 22:47:24 +00:00
if ( ! implicit_tag ) {
offset = dissect_ber_identifier ( pinfo , tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , NULL ) ;
end_offset = offset + len ;
2004-02-20 10:04:10 +00:00
2004-12-12 22:47:24 +00:00
/* sanity check. we only handle universal/generalized time */
if ( ( class ! = BER_CLASS_UNI )
2004-03-25 23:57:10 +00:00
| | ( tag ! = BER_UNI_TAG_GeneralizedTime ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-02-20 10:04:10 +00:00
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: GeneralizedTime expected but Class:%d PC:%d Tag:%d was unexpected " , class , pc , tag ) ;
return end_offset ;
end_offset = offset + len ;
2004-12-12 22:47:24 +00:00
}
} else {
len = tvb_length_remaining ( tvb , offset ) ;
end_offset = offset + len ;
2004-02-20 10:04:10 +00:00
}
2004-12-12 22:47:24 +00:00
2004-02-20 10:04:10 +00:00
tmpstr = tvb_get_ptr ( tvb , offset , len ) ;
2005-08-18 08:37:31 +00:00
snprintf ( str , 31 , " %.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s) " ,
2004-02-20 10:04:10 +00:00
tmpstr , tmpstr + 4 , tmpstr + 6 , tmpstr + 8 ,
tmpstr + 10 , tmpstr + 12 , tmpstr + 14 ) ;
2005-08-18 08:37:31 +00:00
str [ 31 ] = 0 ; /* just in case ... */
2004-02-20 10:04:10 +00:00
if ( hf_id ! = - 1 ) {
proto_tree_add_string ( tree , hf_id , tvb , offset , len , str ) ;
}
offset + = len ;
return offset ;
}
2004-03-25 09:18:03 +00:00
/* 8.6 Encoding of a bitstring value */
2004-10-08 21:14:33 +00:00
int dissect_ber_bitstring ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const asn_namedbit * named_bits , gint hf_id , gint ett_id , tvbuff_t * * out_tvb )
2004-02-20 10:04:10 +00:00
{
2004-12-13 08:15:34 +00:00
gint8 class ;
2004-03-25 09:18:03 +00:00
gboolean pc , ind ;
2004-12-13 08:15:34 +00:00
gint32 tag ;
2004-02-20 10:04:10 +00:00
guint32 len ;
2004-06-05 09:59:45 +00:00
guint8 pad = 0 , b0 , b1 , val ;
2004-02-20 10:04:10 +00:00
int end_offset ;
2004-03-25 09:18:03 +00:00
proto_item * item = NULL ;
proto_tree * tree = NULL ;
2004-10-08 21:14:33 +00:00
const asn_namedbit * nb ;
2005-08-18 08:37:31 +00:00
char * sep ;
2004-05-11 07:26:45 +00:00
gboolean term ;
2004-02-20 10:04:10 +00:00
2004-11-14 05:10:44 +00:00
if ( ! implicit_tag ) {
/* read header and len for the octet string */
offset = dissect_ber_identifier ( pinfo , parent_tree , tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , parent_tree , tvb , offset , & len , & ind ) ;
end_offset = offset + len ;
2004-02-20 10:04:10 +00:00
2004-11-14 05:10:44 +00:00
/* sanity check: we only handle Universal BitSrings */
2005-08-18 08:37:31 +00:00
if ( ! implicit_tag ) {
2004-03-25 09:18:03 +00:00
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_BITSTRING ) ) {
2005-04-14 20:01:14 +00:00
tvb_ensure_bytes_exist ( tvb , offset - 2 , 2 ) ;
2004-03-25 09:18:03 +00:00
proto_tree_add_text ( parent_tree , tvb , offset - 2 , 2 , " BER Error: BitString expected but Class:%d PC:%d Tag:%d was unexpected " , class , pc , tag ) ;
return end_offset ;
2004-02-20 10:04:10 +00:00
}
2004-11-14 05:10:44 +00:00
}
} else {
pc = 0 ;
len = tvb_length_remaining ( tvb , offset ) ;
end_offset = offset + len ;
2004-02-20 10:04:10 +00:00
}
2004-03-25 09:18:03 +00:00
ber_last_created_item = NULL ;
2004-02-20 10:04:10 +00:00
2005-08-18 08:37:31 +00:00
if ( pc ) {
2004-03-25 09:18:03 +00:00
/* constructed */
/* TO DO */
} else {
/* primitive */
/* padding */
pad = tvb_get_guint8 ( tvb , offset ) ;
proto_tree_add_item ( parent_tree , hf_ber_bitstring_padding , tvb , offset , 1 , FALSE ) ;
2004-02-20 10:04:10 +00:00
offset + + ;
2004-03-25 09:18:03 +00:00
len - - ;
2005-08-18 08:37:31 +00:00
if ( hf_id ! = - 1 ) {
2004-03-25 09:18:03 +00:00
item = proto_tree_add_item ( parent_tree , hf_id , tvb , offset , len , FALSE ) ;
ber_last_created_item = item ;
2005-08-18 08:37:31 +00:00
if ( ett_id ! = - 1 ) {
2004-03-25 09:18:03 +00:00
tree = proto_item_add_subtree ( item , ett_id ) ;
2004-02-20 10:04:10 +00:00
}
}
2005-08-18 08:37:31 +00:00
if ( out_tvb ) {
2004-12-13 08:15:34 +00:00
if ( len < = ( guint32 ) tvb_length_remaining ( tvb , offset ) ) {
2004-11-30 03:39:34 +00:00
* out_tvb = tvb_new_subset ( tvb , offset , len , len ) ;
} else {
2005-08-28 17:57:30 +00:00
* out_tvb = tvb_new_subset ( tvb , offset , - 1 , - 1 ) ;
2004-11-30 03:39:34 +00:00
}
2004-03-25 09:18:03 +00:00
}
}
2004-02-20 10:04:10 +00:00
2005-08-18 08:37:31 +00:00
if ( named_bits ) {
2004-05-11 07:26:45 +00:00
sep = " ( " ;
term = FALSE ;
2004-03-25 09:18:03 +00:00
nb = named_bits ;
while ( nb - > p_id ) {
2005-08-18 08:37:31 +00:00
if ( nb - > bit < ( 8 * len - pad ) ) {
2004-03-25 09:18:03 +00:00
val = tvb_get_guint8 ( tvb , offset + nb - > bit / 8 ) ;
val & = 0x80 > > ( nb - > bit % 8 ) ;
2004-05-03 22:55:36 +00:00
b0 = ( nb - > gb0 = = - 1 ) ? nb - > bit / 8 :
( ( guint32 ) nb - > gb0 ) / 8 ;
b1 = ( nb - > gb1 = = - 1 ) ? nb - > bit / 8 :
( ( guint32 ) nb - > gb1 ) / 8 ;
2004-03-25 09:18:03 +00:00
proto_tree_add_item ( tree , * ( nb - > p_id ) , tvb , offset + b0 , b1 - b0 + 1 , FALSE ) ;
} else { /* 8.6.2.4 */
val = 0 ;
proto_tree_add_boolean ( tree , * ( nb - > p_id ) , tvb , offset + len , 0 , 0x00 ) ;
2004-02-20 10:04:10 +00:00
}
2005-08-18 08:37:31 +00:00
if ( val ) {
2005-08-27 18:16:35 +00:00
if ( item & & nb - > tstr ) {
2004-05-11 07:26:45 +00:00
proto_item_append_text ( item , " %s%s " , sep , nb - > tstr ) ;
2005-08-27 18:44:57 +00:00
sep = " , " ;
2005-08-27 18:16:35 +00:00
term = TRUE ;
}
2004-03-25 09:18:03 +00:00
} else {
2005-08-27 18:16:35 +00:00
if ( item & & nb - > fstr ) {
2004-05-11 07:26:45 +00:00
proto_item_append_text ( item , " %s%s " , sep , nb - > fstr ) ;
2005-08-27 18:44:57 +00:00
sep = " , " ;
2005-08-27 18:16:35 +00:00
term = TRUE ;
}
2004-03-25 09:18:03 +00:00
}
nb + + ;
2004-02-20 10:04:10 +00:00
}
2005-08-18 08:37:31 +00:00
if ( term )
2004-05-11 07:26:45 +00:00
proto_item_append_text ( item , " ) " ) ;
2004-02-20 10:04:10 +00:00
}
return end_offset ;
}
2004-03-25 09:18:03 +00:00
int dissect_ber_bitstring32 ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , int * * bit_fields , gint hf_id , gint ett_id , tvbuff_t * * out_tvb )
{
2005-04-15 14:18:08 +00:00
tvbuff_t * tmp_tvb = NULL ;
2004-03-25 09:18:03 +00:00
proto_tree * tree ;
guint32 val ;
int * * bf ;
header_field_info * hfi ;
2005-08-18 08:37:31 +00:00
char * sep ;
2004-05-11 07:26:45 +00:00
gboolean term ;
2004-05-26 11:25:20 +00:00
unsigned int i , tvb_len ;
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +00:00
offset = dissect_ber_bitstring ( implicit_tag , pinfo , parent_tree , tvb , offset , NULL , hf_id , ett_id , & tmp_tvb ) ;
tree = proto_item_get_subtree ( ber_last_created_item ) ;
2005-08-18 08:37:31 +00:00
if ( bit_fields & & tree & & tmp_tvb ) {
2004-05-26 11:25:20 +00:00
/* tmp_tvb points to the actual bitstring (including any pad bits at the end.
* note that this bitstring is not neccessarily always encoded as 4 bytes
* so we have to read it byte by byte .
*/
val = 0 ;
tvb_len = tvb_length ( tmp_tvb ) ;
for ( i = 0 ; i < 4 ; i + + ) {
val < < = 8 ;
if ( i < tvb_len ) {
val | = tvb_get_guint8 ( tmp_tvb , i ) ;
}
}
2004-03-25 09:18:03 +00:00
bf = bit_fields ;
2004-05-11 07:26:45 +00:00
sep = " ( " ;
term = FALSE ;
2004-03-25 09:18:03 +00:00
while ( * bf ) {
2004-05-26 11:25:20 +00:00
proto_tree_add_boolean ( tree , * * bf , tmp_tvb , 0 , tvb_len , val ) ;
2004-03-25 09:18:03 +00:00
hfi = proto_registrar_get_nth ( * * bf ) ;
2005-08-18 08:37:31 +00:00
if ( val & hfi - > bitmask ) {
2004-05-11 07:26:45 +00:00
proto_item_append_text ( ber_last_created_item , " %s%s " , sep , hfi - > name ) ;
sep = " , " ;
term = TRUE ;
}
2004-03-25 09:18:03 +00:00
bf + + ;
}
2005-08-18 08:37:31 +00:00
if ( term )
2004-05-11 07:26:45 +00:00
proto_item_append_text ( ber_last_created_item , " ) " ) ;
2004-03-25 09:18:03 +00:00
}
2005-08-18 08:37:31 +00:00
if ( out_tvb )
2004-03-25 09:18:03 +00:00
* out_tvb = tmp_tvb ;
return offset ;
}
2004-02-20 10:04:10 +00:00
void
proto_register_ber ( void )
{
static hf_register_info hf [ ] = {
{ & hf_ber_id_class , {
" Class " , " ber.id.class " , FT_UINT8 , BASE_DEC ,
VALS ( ber_class_codes ) , 0xc0 , " Class of BER TLV Identifier " , HFILL } } ,
{ & hf_ber_bitstring_padding , {
" Padding " , " ber.bitstring.padding " , FT_UINT8 , BASE_DEC ,
NULL , 0x0 , " Number of unsused bits in the last octet of the bitstring " , HFILL } } ,
{ & hf_ber_id_pc , {
" P/C " , " ber.id.pc " , FT_BOOLEAN , 8 ,
TFS ( & ber_pc_codes ) , 0x20 , " Primitive or Constructed BER encoding " , HFILL } } ,
{ & hf_ber_id_uni_tag , {
" Tag " , " ber.id.uni_tag " , FT_UINT8 , BASE_DEC ,
VALS ( ber_uni_tag_codes ) , 0x1f , " Universal tag type " , HFILL } } ,
{ & hf_ber_id_tag , {
" Tag " , " ber.id.tag " , FT_UINT32 , BASE_DEC ,
NULL , 0 , " Tag value for non-Universal classes " , HFILL } } ,
{ & hf_ber_length , {
" Length " , " ber.length " , FT_UINT32 , BASE_DEC ,
NULL , 0 , " Length of contents " , HFILL } } ,
2004-11-25 22:27:52 +00:00
{ & hf_ber_unknown_OCTETSTRING , {
" OCTETSTRING " , " ber.unknown.OCTETSTRING " , FT_BYTES , BASE_HEX ,
NULL , 0 , " This is an unknown OCTETSTRING " , HFILL } } ,
{ & hf_ber_unknown_OID , {
" OID " , " ber.unknown.OID " , FT_STRING , BASE_NONE ,
NULL , 0 , " This is an unknown Object Identifier " , HFILL } } ,
2005-08-18 08:37:31 +00:00
{ & hf_ber_unknown_GraphicString , {
" GRAPHICSTRING " , " ber.unknown.GRAPHICSTRING " , FT_STRING , BASE_HEX ,
NULL , 0 , " This is an unknown GRAPHICSTRING " , HFILL } } ,
2004-12-12 22:59:43 +00:00
{ & hf_ber_unknown_NumericString , {
" NumericString " , " ber.unknown.NumericString " , FT_STRING , BASE_NONE ,
NULL , 0 , " This is an unknown NumericString " , HFILL } } ,
2004-11-18 10:46:27 +00:00
{ & hf_ber_unknown_PrintableString , {
2004-11-25 21:30:38 +00:00
" PrintableString " , " ber.unknown.PrintableString " , FT_STRING , BASE_NONE ,
2004-11-18 10:46:27 +00:00
NULL , 0 , " This is an unknown PrintableString " , HFILL } } ,
2004-11-25 21:30:38 +00:00
{ & hf_ber_unknown_IA5String , {
" IA5String " , " ber.unknown.IA5String " , FT_STRING , BASE_NONE ,
NULL , 0 , " This is an unknown IA5String " , HFILL } } ,
2004-11-18 10:46:27 +00:00
{ & hf_ber_unknown_INTEGER , {
2004-11-25 21:30:38 +00:00
" INTEGER " , " ber.unknown.INTEGER " , FT_UINT32 , BASE_DEC ,
2004-11-18 10:46:27 +00:00
NULL , 0 , " This is an unknown INTEGER " , HFILL } } ,
2004-12-12 22:59:43 +00:00
{ & hf_ber_unknown_ENUMERATED , {
" ENUMERATED " , " ber.unknown.ENUMERATED " , FT_UINT32 , BASE_DEC ,
NULL , 0 , " This is an unknown ENUMERATED " , HFILL } } ,
2004-02-20 10:04:10 +00:00
} ;
static gint * ett [ ] = {
& ett_ber_octet_string ,
2004-11-25 21:30:38 +00:00
& ett_ber_unknown ,
2004-11-25 22:27:52 +00:00
& ett_ber_SEQUENCE ,
2004-02-20 10:04:10 +00:00
} ;
module_t * ber_module ;
2004-03-25 23:57:10 +00:00
proto_ber = proto_register_protocol ( " Basic Encoding Rules (ASN.1 X.690) " , " BER " , " ber " ) ;
2004-02-20 10:04:10 +00:00
proto_register_field_array ( proto_ber , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2004-03-25 09:18:03 +00:00
proto_set_cant_toggle ( proto_ber ) ;
2004-02-20 10:04:10 +00:00
/* Register preferences */
ber_module = prefs_register_protocol ( proto_ber , NULL ) ;
prefs_register_bool_preference ( ber_module , " show_internals " ,
" Show internal BER encapsulation tokens " ,
" Whether the dissector should also display internal "
" ASN.1 BER details such as Identifier and Length fields " , & show_internal_ber_fields ) ;
2004-07-21 11:13:03 +00:00
ber_oid_dissector_table = register_dissector_table ( " ber.oid " , " BER OID Dissectors " , FT_STRING , BASE_NONE ) ;
2004-07-29 09:32:13 +00:00
oid_table = g_hash_table_new ( g_str_hash , g_str_equal ) ;
2004-02-20 10:04:10 +00:00
}
void
proto_reg_handoff_ber ( void )
{
}
2005-08-18 08:37:31 +00:00