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 .
2004-10-30 01:54:40 +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>
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-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 .
*/
static gboolean length_is_indefinite = FALSE ;
2004-02-20 10:04:10 +00:00
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
2005-06-22 09:58:46 +00:00
/* This function is only used by dissect_unknown_ber()
* It is essentially the get_ber_length ( ) function but we dont
* deliberately generate a [ malformed packet ] if the length field looks
* like garbage .
* For unknown ber encodings we can just do as much as we can but sometimes it
* is impossible to do it right .
* For example :
* If there are implicit tags , then the length will not be valid when we
* try to read the tag / len but we DONT want to generate a malformed packet
* here , the packet is not malformed we just can not parse the ber encoding .
*/
static int
get_ber_length_dont_check_len ( proto_tree * tree , tvbuff_t * tvb , int offset , guint32 * length , gboolean * ind ) {
guint8 oct , len ;
guint32 tmp_length ;
gboolean tmp_ind ;
int old_offset = offset ;
tmp_length = 0 ;
tmp_ind = FALSE ;
2005-06-29 08:00:55 +00:00
/* dont read beyond the end of the tvb */
2005-07-26 09:52:06 +00:00
if ( tvb_length ( tvb ) < = ( unsigned ) offset ) {
2005-06-29 08:00:55 +00:00
* length = tvb_length ( tvb ) + 99 ;
return offset ;
}
2005-06-22 09:58:46 +00:00
oct = tvb_get_guint8 ( tvb , offset ) ;
offset + = 1 ;
if ( ! ( oct & 0x80 ) ) {
/* 8.1.3.4 */
tmp_length = oct ;
} else {
len = oct & 0x7F ;
if ( len ) {
/* 8.1.3.5 */
while ( len - - ) {
2005-07-26 09:52:06 +00:00
if ( ( unsigned ) offset > = tvb_length ( tvb ) ) {
2005-06-22 09:58:46 +00:00
if ( length )
* length = 999999999 ;
if ( ind )
* ind = tmp_ind ;
return offset ;
}
oct = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
tmp_length = ( tmp_length < < 8 ) + oct ;
}
} else {
/* 8.1.3.6 */
tmp_ind = TRUE ;
/* TO DO */
}
}
/* 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 ) ) ;
/* the ignorant mans way to generate [malformed packet] */
}
if ( length )
* length = tmp_length ;
if ( ind )
* ind = tmp_ind ;
return offset ;
}
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 ;
2005-06-22 09:58:46 +00:00
tvbuff_t * next_tvb ;
2004-11-18 10:46:27 +00:00
start_offset = offset ;
2005-06-22 09:58:46 +00:00
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
offset = get_ber_length_dont_check_len ( 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,
2005-06-22 09:58:46 +00:00
or the ASN1 definition contains implicit tags making
decoding impossible ?
2004-11-25 21:30:38 +00:00
since these are not vital outputs just return instead of
throwing en exception .
*/
2005-06-22 09:58:46 +00:00
proto_tree_add_text ( tree , tvb , offset , 0 , " BER Failure decoding unknown BER structure. I tried but sometimes decoding unknown BER structures is just impossible " ) ;
2004-11-25 21:30:38 +00:00
return tvb_length ( tvb ) ;
}
2004-11-25 22:27:52 +00:00
switch ( class ) {
case BER_CLASS_UNI :
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-06-22 09:58:46 +00:00
next_tvb = tvb_new_subset ( tvb , offset , len , len ) ;
2005-06-27 11:43:18 +00:00
offset + = dissect_unknown_ber ( pinfo , next_tvb , 0 , 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 ;
case BER_CLASS_CON :
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-06-22 09:58:46 +00:00
next_tvb = tvb_new_subset ( tvb , offset , len , len ) ;
2005-06-27 11:43:18 +00:00
offset + = dissect_unknown_ber ( pinfo , next_tvb , 0 , 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-07-28 08:18:18 +00:00
next_tvb = tvb_new_subset ( tvb , offset , tvb_length_remaining ( tvb , offset ) , tvb_reported_length_remaining ( tvb , offset ) ) ;
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 ) ;
}
dissect_unknown_ber ( pinfo , next_tvb , offset , 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
}
}
2004-03-25 09:18:03 +00:00
if ( class )
* class = tmp_class ;
if ( pc )
* pc = tmp_pc ;
if ( tag )
* 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 ;
guint32 tmp_length ;
gboolean tmp_ind ;
2005-04-20 08:35:47 +00:00
int old_offset = offset ;
2004-02-20 10:04:10 +00:00
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
2004-03-25 09:18:03 +00:00
if ( ! ( oct & 0x80 ) ) {
/* 8.1.3.4 */
tmp_length = oct ;
} else {
len = oct & 0x7F ;
if ( len ) {
/* 8.1.3.5 */
while ( len - - ) {
oct = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
tmp_length = ( tmp_length < < 8 ) + oct ;
}
} else {
/* 8.1.3.6 */
tmp_ind = TRUE ;
/* TO DO */
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 ) ) ;
/* the ignorant mans way to generate [malformed packet] */
tvb_get_guint8 ( tvb , 99999999 ) ;
}
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 ) {
proto_tree_add_text ( tree , tvb , old_offset , 1 , " Length: Indefinite length " ) ;
} 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
}
if ( length )
* length = tmp_length ;
if ( ind )
* 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-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 */
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 + + ;
}
}
}
2004-03-25 09:18:03 +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-07-28 08:18:18 +00:00
* out_tvb = tvb_new_subset ( tvb , offset , tvb_length_remaining ( tvb , offset ) , tvb_reported_length_remaining ( tvb , offset ) ) ;
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-06-24 08:57:41 +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-06-24 08:57:41 +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-04-27 14:17:14 +00:00
}
2005-06-24 08:57:41 +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-07-09 02:58:07 +00:00
gint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2005-07-09 02:58:07 +00:00
gint32 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 ;
if ( len > 0 ) {
/* 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 ;
2004-03-25 09:18:03 +00:00
if ( len > 0 ) {
/* 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
/* */
if ( len < 1 | | len > 4 ) {
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-07-09 02:58:07 +00:00
gint8 class ;
2004-02-20 10:04:10 +00:00
gboolean pc ;
2005-07-09 02:58:07 +00:00
gint32 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 ) ;
if ( hfi - > type = = FT_BOOLEAN )
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-06-29 08:00:55 +00:00
int end_offset , tag_start_offset ;
2004-07-23 23:06:38 +00:00
tvbuff_t * next_tvb ;
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-06-22 09:58:46 +00:00
printf ( " SEQUENCE dissect_ber_sequence(%s) entered offset:%d len:%d %02x:%02x:%02x implicit_tag:%d length_is_indefinite:%d \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 ) , implicit_tag , length_is_indefinite ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-06-22 09:58:46 +00:00
printf ( " SEQUENCE dissect_ber_sequence(%s) entered length_is_indefinite:%d \n " , name , length_is_indefinite ) ;
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 ) {
/* 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 .
*/
end_offset = tvb_length ( tvb ) ;
} 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-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 ( ( ! 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 {
2005-06-22 09:58:46 +00:00
ind = length_is_indefinite ;
2004-11-14 05:10:44 +00:00
/* 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 */
2004-03-25 09:18:03 +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-11 15:35:17 +00:00
int orig_offset = offset , hoffset , eoffset , count ;
2004-10-16 12:53:09 +00:00
if ( ind ) { /* this sequence was of indefinite length, so check for EOC */
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 " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
printf ( " SEQUENCE dissect_ber_sequence(%s) TESTING FOR EOC implicit_tag:%d offset:%d len:%d %02x:%02x:%02x length_is_indefinite:%d \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 ) , length_is_indefinite ) ;
} else {
printf ( " SEQUENCE dissect_ber_sequence(%s) TESTING FOR EOC length_is_indefinite:%d \n " , name , length_is_indefinite ) ;
}
}
# endif
2004-10-16 12:53:09 +00:00
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 , offset , 2 , " EOC " ) ;
}
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 " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
printf ( " SEQUENCE dissect_ber_sq_of(%s) EOC FOUND implicit_tag:%d offset:%d len:%d %02x:%02x:%02x length_is_indefinite:%d \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 ) , length_is_indefinite ) ;
} else {
printf ( " SEQUENCE dissect_ber_sq_of(%s) EOC FOUND length_is_indefinite:%d \n " , name , length_is_indefinite ) ;
}
}
# endif
2004-10-16 12:53:09 +00:00
return offset + 2 ;
}
}
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 */
2005-06-29 08:00:55 +00:00
tag_start_offset = offset ;
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 ;
2004-02-20 10:04:10 +00:00
ber_sequence_try_again :
/* have we run out of known entries in the sequence ?*/
2004-03-25 09:18:03 +00:00
if ( ! seq - > func ) {
2004-02-20 10:04:10 +00:00
/* it was not, move to the enxt one and try again */
2005-06-29 08:00:55 +00:00
proto_tree_add_text ( tree , tvb , tag_start_offset , offset - tag_start_offset , " BER Error: This field lies beyond the end of the known sequence definition. class:%d pc:%d tag:%d len:%d " , class , pc , tag , len ) ;
2004-03-25 09:18:03 +00:00
offset = eoffset ;
2004-02-20 10:04:10 +00:00
continue ;
}
2004-07-20 10:45:11 +00:00
/* Verify that this one is the one we want.
* 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
/* 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
*/
2005-06-07 05:49:06 +00:00
if ( ( ( seq - > class = = BER_CLASS_CON ) | | ( seq - > class = = BER_CLASS_APP ) | | ( seq - > class = = BER_CLASS_PRI ) ) & & ( ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) ) {
2004-11-14 05:10:44 +00:00
if ( ( seq - > class ! = BER_CLASS_ANY )
2004-11-21 10:34:08 +00:00
& & ( seq - > tag ! = - 1 )
2004-07-20 10:45:11 +00:00
& & ( ( seq - > class ! = class )
| | ( seq - > tag ! = tag ) ) ) {
2004-02-20 10:04:10 +00:00
/* 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 ;
}
2005-03-30 19:09:48 +00:00
if ( seq - > class = = BER_CLASS_UNI ) {
2005-03-31 23:48:08 +00:00
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 ) ;
2005-03-30 19:09:48 +00:00
} else {
2005-03-31 23:48:08 +00:00
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 ) ;
2005-03-30 19:09:48 +00:00
}
2004-10-24 03:51:27 +00:00
seq + + ;
offset = eoffset ;
continue ;
2004-11-14 05:10:44 +00:00
}
} else if ( ! ( seq - > flags & BER_FLAGS_NOTCHKTAG ) ) {
if ( ( seq - > class ! = BER_CLASS_ANY )
2004-11-21 10:34:08 +00:00
& & ( seq - > tag ! = - 1 )
2004-11-14 05:10:44 +00:00
& & ( ( 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 ;
}
2005-03-30 19:09:48 +00:00
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 ) ;
}
2004-11-14 05:10:44 +00:00
seq + + ;
offset = eoffset ;
continue ;
}
2004-02-20 10:04:10 +00:00
}
2004-11-14 05:10:44 +00:00
if ( ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) {
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-11-30 03:39:34 +00:00
if ( ind_field
| | ( ( eoffset - hoffset ) > tvb_length_remaining ( tvb , hoffset ) ) ) {
/* If the field is indefinite (i.e. we dont know the
* length ) of if the tvb is short , then just
2004-10-16 12:53:09 +00:00
* give it all of the tvb and hope for the best .
*/
2005-07-28 08:18:18 +00:00
next_tvb = tvb_new_subset ( tvb , hoffset , tvb_length_remaining ( tvb , hoffset ) , tvb_reported_length_remaining ( tvb , hoffset ) ) ;
2004-10-16 12:53:09 +00:00
} else {
next_tvb = tvb_new_subset ( tvb , hoffset , eoffset - hoffset , eoffset - hoffset ) ;
}
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-06-22 09:58:46 +00:00
printf ( " SEQUENCE dissect_ber_sequence(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x indefinite_len:%d no_own_tag:%d \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 ) , ind_field , ! ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-06-22 09:58:46 +00:00
printf ( " SEQUENCE dissect_ber_sequence(%s) calling subdissector indefinite_len:%d no_own_tag:%d \n " , name , ind_field , ! ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) ;
2004-11-14 05:10:44 +00:00
}
}
# endif
2005-06-22 09:58:46 +00:00
length_is_indefinite = ind_field ;
2004-10-16 12:53:09 +00:00
count = seq - > func ( pinfo , tree , next_tvb , 0 ) ;
2005-06-22 09:58:46 +00:00
length_is_indefinite = FALSE ;
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 " ;
}
printf ( " SEQUENCE dissect_ber_sequence(%s) subdissector ate %d bytes \n " , name , count ) ;
}
# endif
2004-10-28 11:35:43 +00:00
seq + + ;
2005-06-22 09:58:46 +00:00
if ( ( len = = 0 ) & & ( ! ind_field ) ) {
2005-04-21 21:37:23 +00:00
offset = eoffset ;
} else {
offset = hoffset + count ;
}
/* 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 ) ) {
goto ber_sequence_try_again ;
2004-11-13 10:06:15 +00:00
}
2005-08-11 15:35:17 +00:00
/* Check for an infinite loop */
if ( offset < = orig_offset ) {
proto_tree_add_text ( tree , tvb , 0 , 0 , " BER Error: Invalid sequence length " ) ;
THROW ( ReportedBoundsError ) ;
}
2004-02-20 10:04:10 +00:00
}
/* if we didnt end up at exactly offset, then we ate too many bytes */
2004-03-25 09:18:03 +00:00
if ( offset ! = end_offset ) {
2005-04-13 20:59:39 +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: Sequence ate %d too many bytes " , offset - end_offset ) ;
2004-02-20 10:04:10 +00:00
}
return end_offset ;
}
/* 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 ;
2004-11-21 23:02:36 +00:00
gint reported_length , length ;
2004-11-14 05:10:44 +00:00
tvbuff_t * next_tvb ;
2004-06-25 09:24:17 +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-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 ) ;
2004-10-24 03:51:27 +00:00
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 .
2004-11-21 23:02:36 +00:00
* XXX - what if it runs past the end of the tvb because we
* need to do reassembly ?
2004-10-24 03:51:27 +00:00
*/
2004-11-14 05:10:44 +00:00
end_offset = tvb_length ( tvb ) ;
2004-10-24 03:51:27 +00:00
} else {
end_offset = offset + len ;
}
2004-02-20 10:04:10 +00:00
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-06-26 05:48:50 +00:00
if ( branch_taken ) {
2005-06-26 06:16:03 +00:00
* branch_taken = - 1 ;
2005-06-26 05:48:50 +00:00
}
2004-02-20 10:04:10 +00:00
while ( ch - > func ) {
2004-12-12 22:19:00 +00:00
choice_try_again :
2005-06-26 05:48:50 +00:00
if ( branch_taken ) {
2005-06-26 06:16:03 +00:00
( * branch_taken ) + + ;
2005-06-26 05:48:50 +00:00
}
2004-12-12 22:19:00 +00:00
# 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
if ( ( ( ch - > class = = class ) & & ( ch - > tag = = tag ) )
| | ( ( ch - > class = = class ) & & ( ch - > tag = = - 1 ) & & ( ch - > flags & BER_FLAGS_NOOWNTAG ) )
) {
2004-11-14 05:10:44 +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 ;
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 ) ;
}
}
2004-11-14 05:10:44 +00:00
2004-11-21 23:02:36 +00:00
reported_length = end_offset - start_offset ;
length = tvb_length_remaining ( tvb , hoffset ) ;
if ( length > reported_length )
length = reported_length ;
next_tvb = tvb_new_subset ( tvb , hoffset , length , reported_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 ;
}
2004-11-14 05:10:44 +00:00
offset = hoffset + count ;
2004-10-24 03:51:27 +00:00
if ( ind ) {
/* this choice was of indefinite length so we
* just have to trust what the subdissector
* told us about the length consumed .
*/
return offset ;
} else {
return end_offset ;
}
2004-02-20 10:04:10 +00:00
break ;
}
ch + + ;
}
2005-06-26 05:48:50 +00:00
if ( branch_taken ) {
/* none of the branches were taken so set the param
back to - 1 */
2005-06-26 06:16:03 +00:00
* branch_taken = - 1 ;
2005-06-26 05:48:50 +00:00
}
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
int
2004-12-13 08:15:34 +00:00
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 ) {
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
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
if ( name_string ) {
2005-04-13 21:20:23 +00:00
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-04-13 21:20:23 +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-04-28 09:54:03 +00:00
char str [ MAX_OID_STR_LEN ] , * name ;
2004-07-29 09:32:13 +00:00
proto_item * item ;
2004-03-25 09:18:03 +00:00
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
2004-03-25 09:18:03 +00:00
if ( value_string ) {
value_string [ 0 ] = ' \0 ' ;
}
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-04-28 09:54:03 +00:00
oid_to_str_buf ( tvb_get_ptr ( tvb , offset , len ) , len , str ) ;
offset + = len ;
2004-03-25 09:18:03 +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
}
if ( value_string ) {
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 ;
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-06-22 09:58:46 +00:00
printf ( " SQ OF dissect_ber_sq_of(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x length_is_indefinite:%d \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 ) , length_is_indefinite ) ;
2004-11-14 05:10:44 +00:00
} else {
2005-06-22 09:58:46 +00:00
printf ( " SQ OF dissect_ber_sq_of(%s) entered length_is_indefinite:%d \n " , name , length_is_indefinite ) ;
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-06-22 09:58:46 +00:00
/* first we must read the sequence of 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 .
*/
end_offset = tvb_length ( tvb ) ;
} 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-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 ( ! pc
| | ( ! 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-06-22 09:58:46 +00:00
ind = length_is_indefinite ;
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 ;
while ( offset < end_offset ) {
guint32 len ;
2005-08-11 15:35:17 +00:00
int orig_offset = offset ;
2004-10-24 03:51:27 +00:00
if ( ind ) { /* this sequence of was of indefinite length, so check for EOC */
2005-06-22 09:58:46 +00:00
2004-10-24 03:51:27 +00:00
if ( ( tvb_get_guint8 ( tvb , offset ) = = 0 ) & & ( tvb_get_guint8 ( tvb , offset + 1 ) = = 0 ) ) {
break ;
}
}
2004-03-25 09:18:03 +00:00
/* read header and len for next field */
offset = get_ber_identifier ( tvb , offset , NULL , NULL , NULL ) ;
2005-04-20 08:35:47 +00:00
offset = get_ber_length ( tree , tvb , offset , & len , NULL ) ;
2004-03-25 09:18:03 +00:00
offset + = len ;
cnt + + ;
2005-08-11 15:35:17 +00:00
/* Check for an infinite loop */
if ( offset < = orig_offset ) {
proto_tree_add_text ( tree , tvb , 0 , 0 , " BER Error: Invalid length " ) ;
THROW ( ReportedBoundsError ) ;
}
2004-03-25 09:18:03 +00:00
}
offset = hoffset ;
2004-02-20 10:04:10 +00:00
/* create subtree */
2004-03-25 09:18:03 +00:00
if ( hf_id ! = - 1 ) {
hfi = proto_registrar_get_nth ( hf_id ) ;
2004-02-20 10:04:10 +00:00
if ( parent_tree ) {
2004-05-11 10:57:14 +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-11 15:35:17 +00:00
int orig_offset = offset , hoffset , count ;
2004-03-25 09:18:03 +00:00
2004-10-24 03:51:27 +00:00
if ( ind ) { /* this sequence of was of indefinite length, so check for EOC */
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 " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
printf ( " SQ OF dissect_ber_sq_of(%s) TESTING FOR EOC implicit_tag:%d offset:%d len:%d %02x:%02x:%02x length_is_indefinite:%d \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 ) , length_is_indefinite ) ;
} else {
printf ( " SQ OF dissect_ber_sq_of(%s) TESTING FOR EOC length_is_indefinite:%d \n " , name , length_is_indefinite ) ;
}
}
# endif
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 ) {
proto_tree_add_text ( tree , tvb , offset , 2 , " EOC " ) ;
}
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 " ;
}
if ( tvb_length_remaining ( tvb , offset ) > 3 ) {
printf ( " SQ OF dissect_ber_sq_of(%s) EOC FOUND implicit_tag:%d offset:%d len:%d %02x:%02x:%02x length_is_indefinite:%d \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 ) , length_is_indefinite ) ;
} else {
printf ( " SQ OF dissect_ber_sq_of(%s) EOC FOUND length_is_indefinite:%d \n " , name , length_is_indefinite ) ;
}
}
# endif
2004-10-24 03:51:27 +00:00
return offset + 2 ;
}
}
2004-03-25 09:18:03 +00:00
hoffset = offset ;
/* 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 .
*/
eoffset = tvb_length ( tvb ) ;
} else {
eoffset = offset + len ;
}
2004-03-25 09:18:03 +00:00
/* verify that this one is the one we want */
2004-11-14 09:45:04 +00:00
if ( seq - > class ! = BER_CLASS_ANY ) {
if ( ( seq - > class ! = class )
2004-03-25 09:18:03 +00:00
| | ( seq - > tag ! = tag ) ) {
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 ;
}
2004-11-14 09:45:04 +00:00
}
2004-03-25 09:18:03 +00:00
}
if ( ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) & & ! ( seq - > flags & BER_FLAGS_IMPLTAG ) ) {
/* 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-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 " ;
}
if ( tvb_length_remaining ( tvb , 0 ) > 3 ) {
printf ( " SQ OF dissect_ber_sq_of(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x indefinite_len:%d no_own_tag:%d \n " , name , offset , tvb_length_remaining ( tvb , 0 ) , tvb_get_guint8 ( tvb , 0 ) , tvb_get_guint8 ( tvb , 1 ) , tvb_get_guint8 ( tvb , 2 ) , ind_field , ! ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) ;
} else {
printf ( " SQ OF dissect_ber_sq_of(%s) calling subdissector indefinite_len:%d no_own_tag:%d \n " , name , ind_field , ! ! ( seq - > flags & BER_FLAGS_NOOWNTAG ) ) ;
}
}
# endif
2004-02-20 10:04:10 +00:00
/* call the dissector for this field */
2005-06-22 09:58:46 +00:00
length_is_indefinite = ind_field ;
2004-10-24 03:51:27 +00:00
count = seq - > func ( pinfo , tree , tvb , hoffset ) - hoffset ;
2005-06-22 09:58:46 +00:00
length_is_indefinite = FALSE ;
# 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 ( " SQ OF dissect_ber_sq_of(%s) subdissector ate %d bytes \n " , name , count ) ;
}
# endif
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 .
*/
cnt + + ;
offset = hoffset + count ;
} else {
cnt + + ;
offset = eoffset ;
}
2005-08-11 15:35:17 +00:00
/* Check for an infinite loop */
if ( offset < = orig_offset ) {
proto_tree_add_text ( tree , tvb , 0 , 0 , " BER Error: Invalid length " ) ;
THROW ( ReportedBoundsError ) ;
}
2004-02-20 10:04:10 +00:00
}
/* if we didnt end up at exactly offset, then we ate too many bytes */
2004-03-25 09:18:03 +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-08 18:50:39 +00:00
g_snprintf ( str , 32 , " %.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 ) ;
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-07-28 07:53:38 +00:00
const 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 */
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
2004-03-25 09:18:03 +00:00
if ( pc ) {
/* 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 - - ;
if ( hf_id ! = - 1 ) {
item = proto_tree_add_item ( parent_tree , hf_id , tvb , offset , len , FALSE ) ;
ber_last_created_item = item ;
if ( ett_id ! = - 1 ) {
tree = proto_item_add_subtree ( item , ett_id ) ;
2004-02-20 10:04:10 +00:00
}
}
2004-03-25 09:18:03 +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-07-28 08:18:18 +00:00
* out_tvb = tvb_new_subset ( tvb , offset , tvb_length_remaining ( tvb , offset ) , tvb_reported_length_remaining ( tvb , offset ) ) ;
2004-11-30 03:39:34 +00:00
}
2004-03-25 09:18:03 +00:00
}
}
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +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 ) {
if ( nb - > bit < ( 8 * len - pad ) ) {
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
}
2004-03-25 09:18:03 +00:00
if ( val ) {
2005-07-01 13:48:52 +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-07-01 13:48:52 +00:00
term = TRUE ;
}
2004-03-25 09:18:03 +00:00
} else {
2005-07-01 13:48:52 +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-07-01 13:48:52 +00:00
term = TRUE ;
}
2004-03-25 09:18:03 +00:00
}
nb + + ;
2005-07-01 13:48:52 +00:00
if ( term ) sep = " , " ;
2004-02-20 10:04:10 +00:00
}
2004-05-11 07:26:45 +00:00
if ( term )
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-07-28 07:53:38 +00:00
const 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-04-15 14:18:08 +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 ) ;
2004-05-11 07:26:45 +00:00
if ( val & hfi - > bitmask ) {
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 + + ;
}
2004-05-11 07:26:45 +00:00
if ( term )
proto_item_append_text ( ber_last_created_item , " ) " ) ;
2004-03-25 09:18:03 +00:00
}
if ( out_tvb )
* 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 } } ,
2005-06-24 10:03:20 +00:00
{ & hf_ber_unknown_GraphicString , {
" GRAPHICSTRING " , " ber.unknown.GRAPHICSTRING " , FT_STRING , BASE_HEX ,
NULL , 0 , " This is an unknown GRAPHICSTRING " , HFILL } } ,
2004-11-25 22:27:52 +00:00
{ & hf_ber_unknown_OID , {
" OID " , " ber.unknown.OID " , FT_STRING , BASE_NONE ,
NULL , 0 , " This is an unknown Object Identifier " , 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 )
{
}