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>
# include "prefs.h"
# 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 ;
static gint ett_ber_octet_string = - 1 ;
static gboolean show_internal_ber_fields = FALSE ;
proto_item * ber_last_created_item = NULL ;
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 " } ,
{ BER_UNI_TAG_TeletextString , " TeletextString, T61String " } ,
{ 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 ;
}
2004-07-23 07:08:14 +00:00
void
2004-07-29 09:32:13 +00:00
register_ber_oid_dissector ( char * oid , dissector_t dissector , int proto , 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 ) ;
2004-07-29 09:32:13 +00:00
g_hash_table_insert ( oid_table , oid , name ) ;
2004-07-23 07:08:14 +00:00
}
2004-07-20 09:11:40 +00:00
int
2004-07-21 11:13:03 +00:00
call_ber_oid_callback ( 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 ;
next_tvb = tvb_new_subset ( tvb , offset , tvb_length_remaining ( tvb , offset ) , tvb_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 ) ) {
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 ) ;
}
2004-07-20 09:11:40 +00:00
return offset ;
}
2004-03-25 09:18:03 +00:00
static int dissect_ber_sq_of ( gboolean implicit_tag , guint32 type , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , ber_sequence * 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 */
int get_ber_identifier ( tvbuff_t * tvb , int offset , guint8 * class , gboolean * pc , guint32 * tag ) {
guint8 id , t ;
guint8 tmp_class ;
gboolean tmp_pc ;
guint32 tmp_tag ;
id = tvb_get_guint8 ( tvb , offset ) ;
offset + = 1 ;
2004-02-20 10:04:10 +00:00
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 ) ;
offset + = 1 ;
tmp_tag < < = 7 ;
tmp_tag | = t & 0x7F ;
if ( t & 0x80 ) break ;
}
}
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-03-25 09:18:03 +00:00
int dissect_ber_identifier ( packet_info * pinfo _U_ , proto_tree * tree , tvbuff_t * tvb , int offset , guint8 * class , gboolean * pc , guint32 * tag )
{
int old_offset = offset ;
guint8 tmp_class ;
gboolean tmp_pc ;
guint32 tmp_tag ;
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
2004-03-25 09:18:03 +00:00
get_ber_length ( tvbuff_t * tvb , int offset , guint32 * length , gboolean * ind ) {
guint8 oct , len ;
guint32 tmp_length ;
gboolean tmp_ind ;
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
}
}
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 ;
offset = get_ber_length ( tvb , offset , & tmp_length , & tmp_ind ) ;
if ( show_internal_ber_fields ) {
proto_tree_add_uint ( tree , hf_ber_length , tvb , old_offset , offset - old_offset , tmp_length ) ;
}
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 ) {
2004-02-20 10:04:10 +00:00
guint8 class ;
2004-03-25 09:18:03 +00:00
gboolean pc , ind ;
2004-02-20 10:04:10 +00:00
guint32 tag ;
guint32 len ;
int end_offset ;
proto_item * it ;
/* read header and len for the octet string */
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 , & ind ) ;
2004-02-20 10:04:10 +00:00
end_offset = offset + len ;
/* sanity check: we only handle Constructed Universal Sequences */
2004-03-25 09:18:03 +00:00
if ( ! implicit_tag ) {
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_OCTETSTRING ) ) {
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 ) ;
return end_offset ;
}
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 */
} else {
/* primitive */
if ( hf_id ! = - 1 ) {
it = proto_tree_add_item ( tree , hf_id , tvb , offset , len , FALSE ) ;
ber_last_created_item = it ;
}
if ( out_tvb ) {
* out_tvb = tvb_new_subset ( tvb , offset , len , len ) ;
}
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 )
{
tvbuff_t * out_tvb ;
offset = dissect_ber_octet_string ( implicit_tag , pinfo , tree , tvb , offset , hf_id , ( func ) ? & out_tvb : NULL ) ;
if ( func & & ( tvb_length ( out_tvb ) > 0 ) ) {
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 ;
}
2004-02-20 10:04:10 +00:00
int
dissect_ber_integer ( packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , guint32 * value )
{
guint8 class ;
gboolean pc ;
guint32 tag ;
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 ;
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
/* if(class!=BER_CLASS_UNI)*/
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 + + ) {
proto_item_append_text ( pi , " %02x " , tvb_get_guint8 ( tvb , offset + i ) ) ;
}
}
2004-06-24 05:31:21 +00:00
return 0xdeadbeef ;
}
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-08-22 00:31:58 +00:00
proto_tree_add_text ( tree , tvb , offset , len , " %s: % " PRIu64 , hfinfo - > name , val64 ) ;
2004-06-24 05:31:21 +00:00
return 0xdeadbeef ;
}
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 ) {
2004-05-11 07:26:45 +00:00
/* XXX - what if "len" is not 1, 2, 3, or 4? */
2004-03-25 09:18:03 +00:00
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
dissect_ber_boolean ( packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id )
{
guint8 class ;
gboolean pc ;
guint32 tag ;
guint32 len ;
guint8 val ;
2004-03-25 09:18:03 +00:00
header_field_info * hfi ;
2004-02-20 10:04:10 +00:00
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
/* if(class!=BER_CLASS_UNI)*/
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-03-25 09:18:03 +00:00
int dissect_ber_sequence ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , ber_sequence * seq , gint hf_id , gint ett_id ) {
2004-02-20 10:04:10 +00:00
guint8 class ;
2004-03-25 09:18:03 +00:00
gboolean pc , ind ;
2004-02-20 10:04:10 +00:00
guint32 tag ;
guint32 len ;
2004-03-25 09:18:03 +00:00
proto_tree * tree = parent_tree ;
proto_item * item = NULL ;
2004-02-20 10:04:10 +00:00
int end_offset ;
2004-07-23 23:06:38 +00:00
tvbuff_t * next_tvb ;
2004-02-20 10:04:10 +00:00
/* first we must read the sequence header */
2004-03-25 09:18:03 +00:00
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 ;
2004-02-20 10:04:10 +00:00
/* sanity check: we only handle Constructed Universal Sequences */
2004-03-25 09:18:03 +00:00
if ( ( ! pc )
| | ( ! implicit_tag & & ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_SEQUENCE ) ) ) ) {
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: Sequence expected but Class:%d PC:%d Tag:%d was unexpected " , class , pc , tag ) ;
2004-02-20 10:04:10 +00:00
return end_offset ;
}
/* 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-02-20 10:04:10 +00:00
guint8 class ;
gboolean pc ;
guint32 tag ;
guint32 len ;
2004-03-25 09:18:03 +00:00
int hoffset , eoffset ;
2004-02-20 10:04:10 +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 ) ;
offset = get_ber_length ( tvb , offset , & len , NULL ) ;
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 */
2004-03-25 09:18:03 +00:00
proto_tree_add_text ( tree , tvb , offset , len , " BER Error: This field lies beyond the end of the known sequence definition. " ) ;
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
*/
if ( ( seq - > class ! = BER_CLASS_ANY )
& & ( ( 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 ;
}
2004-03-25 09:18:03 +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 SEQUENCE " ) ;
2004-03-25 09:18:03 +00:00
seq + + ;
offset = eoffset ;
continue ;
}
2004-02-20 10:04:10 +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 ) ;
}
2004-02-20 10:04:10 +00:00
/* call the dissector for this field */
2004-07-23 23:06:38 +00:00
next_tvb = tvb_new_subset ( tvb , hoffset , eoffset - hoffset , eoffset - hoffset ) ;
seq - > func ( pinfo , tree , next_tvb , 0 ) ;
2004-02-20 10:04:10 +00:00
seq + + ;
2004-03-25 09:18:03 +00:00
offset = eoffset ;
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 ) {
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
*/
int
2004-03-25 09:18:03 +00:00
dissect_ber_choice ( packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , const ber_choice * choice , gint hf_id , gint ett_id )
2004-02-20 10:04:10 +00:00
{
guint8 class ;
gboolean pc ;
guint32 tag ;
guint32 len ;
2004-03-25 09:18:03 +00:00
const ber_choice * ch ;
2004-02-20 10:04:10 +00:00
proto_tree * tree = parent_tree ;
proto_item * item = NULL ;
int end_offset ;
2004-03-25 09:18:03 +00:00
int hoffset = offset ;
2004-06-25 09:24:17 +00:00
header_field_info * hfinfo ;
2004-03-25 09:18:03 +00:00
/* read header and len for choice field */
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
offset = get_ber_length ( tvb , offset , & len , NULL ) ;
2004-02-20 10:04:10 +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 :
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 ) ;
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 ;
2004-02-20 10:04:10 +00:00
while ( ch - > func ) {
if ( ( ch - > class = = class )
& & ( ch - > tag = = tag ) ) {
2004-03-25 09:18:03 +00:00
if ( ! ( ch - > flags & BER_FLAGS_NOOWNTAG ) & & ! ( ch - > 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 ) ;
}
/* 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 ) ;
}
}
offset = ch - > func ( pinfo , tree , tvb , hoffset ) ;
2004-02-20 10:04:10 +00:00
return end_offset ;
break ;
}
ch + + ;
}
/* 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-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 )
{
guint8 class ;
gboolean pc ;
guint32 tag ;
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 ) ) {
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
dissect_ber_restricted_string ( gboolean implicit_tag , guint32 type , packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id , tvbuff_t * * out_tvb ) {
guint8 class ;
gboolean pc ;
guint32 tag ;
guint32 len ;
int eoffset ;
int hoffset = offset ;
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
offset = get_ber_length ( tvb , offset , & len , NULL ) ;
eoffset = offset + len ;
/* sanity check */
if ( ! implicit_tag ) {
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = type ) ) {
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 */
return dissect_ber_octet_string ( TRUE , pinfo , tree , tvb , hoffset , hf_id , out_tvb ) ;
}
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
{
2004-03-25 09:18:03 +00:00
tvbuff_t * out_tvb ;
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 ) {
if ( tvb_length ( out_tvb ) > = name_len ) {
tvb_memcpy ( out_tvb , name_string , 0 , name_len - 1 ) ;
name_string [ name_len - 1 ] = ' \0 ' ;
} else {
tvb_memcpy ( out_tvb , name_string , 0 , - 1 ) ;
name_string [ tvb_length ( out_tvb ) ] = ' \0 ' ;
}
}
return offset ;
}
/* 8.19 Encoding of an object identifier value */
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-02-20 10:04:10 +00:00
guint8 class ;
gboolean pc ;
guint32 tag ;
2004-03-25 09:18:03 +00:00
guint32 i , len ;
int eoffset ;
guint8 byte ;
guint32 value ;
2004-07-29 09:32:13 +00:00
char str [ 256 ] , * strp , * name ;
proto_item * item ;
2004-03-25 09:18:03 +00:00
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
offset = dissect_ber_length ( pinfo , tree , tvb , offset , & len , NULL ) ;
eoffset = offset + len ;
if ( value_string ) {
value_string [ 0 ] = ' \0 ' ;
}
/* sanity check */
if ( ! implicit_tag ) {
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_OID ) ) {
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 ;
}
}
value = 0 ;
for ( i = 0 , strp = str ; i < len ; i + + ) {
byte = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
if ( ( strp - str ) > 200 ) {
proto_tree_add_text ( tree , tvb , offset , eoffset - offset , " BER Error: too long Object Identifier " ) ;
return offset ;
}
/* 8.19.4 */
if ( i = = 0 ) {
strp + = sprintf ( strp , " %d.%d " , byte / 40 , byte % 40 ) ;
continue ;
}
value = ( value < < 7 ) | ( byte & 0x7F ) ;
if ( byte & 0x80 ) {
continue ;
}
strp + = sprintf ( strp , " .%d " , value ) ;
value = 0 ;
}
* strp = ' \0 ' ;
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 ;
}
static int dissect_ber_sq_of ( gboolean implicit_tag , guint32 type , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , ber_sequence * seq , gint hf_id , gint ett_id ) {
guint8 class ;
gboolean pc , ind ;
guint32 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
/* first we must read the sequence header */
2004-03-25 09:18:03 +00:00
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 ;
2004-02-20 10:04:10 +00:00
/* sanity check: we only handle Constructed Universal Sequences */
2004-03-25 09:18:03 +00:00
if ( ! pc
| | ( ! implicit_tag & & ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = type ) ) ) ) {
proto_tree_add_text ( tree , tvb , offset - 2 , 2 , " BER Error: %s Of expected but Class:%d PC:%d Tag:%d was unexpected " ,
( type = = BER_UNI_TAG_SEQUENCE ) ? " Set " : " Sequence " , class , pc , tag ) ;
2004-02-20 10:04:10 +00:00
return end_offset ;
}
2004-03-25 09:18:03 +00:00
/* count number of items */
cnt = 0 ;
hoffset = offset ;
while ( offset < end_offset ) {
guint32 len ;
/* read header and len for next field */
offset = get_ber_identifier ( tvb , offset , NULL , NULL , NULL ) ;
offset = get_ber_length ( tvb , offset , & len , NULL ) ;
offset + = len ;
cnt + + ;
}
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 ) {
guint8 class ;
gboolean pc ;
guint32 tag ;
guint32 len ;
int eoffset ;
int hoffset ;
hoffset = offset ;
/* read header and len for next field */
offset = get_ber_identifier ( tvb , offset , & class , & pc , & tag ) ;
offset = get_ber_length ( tvb , offset , & len , NULL ) ;
eoffset = offset + len ;
/* verify that this one is the one we want */
if ( ( seq - > class ! = class )
| | ( 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 ;
}
}
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 ) ;
}
2004-02-20 10:04:10 +00:00
/* call the dissector for this field */
2004-03-25 09:18:03 +00:00
seq - > func ( pinfo , tree , tvb , hoffset ) ;
cnt + + ;
offset = eoffset ;
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 ) {
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-03-25 09:18:03 +00:00
int dissect_ber_sequence_of ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , ber_sequence * seq , gint hf_id , gint ett_id ) {
return dissect_ber_sq_of ( implicit_tag , BER_UNI_TAG_SEQUENCE , pinfo , parent_tree , tvb , offset , seq , hf_id , ett_id ) ;
}
int dissect_ber_set_of ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , ber_sequence * seq , gint hf_id , gint ett_id ) {
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
dissect_ber_generalized_time ( packet_info * pinfo , proto_tree * tree , tvbuff_t * tvb , int offset , gint hf_id )
{
char str [ 32 ] ;
const guint8 * tmpstr ;
guint8 class ;
gboolean pc ;
guint32 tag ;
guint32 len ;
int end_offset ;
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/generalized time */
if ( ( class ! = BER_CLASS_UNI )
2004-03-25 23:57:10 +00:00
| | ( tag ! = BER_UNI_TAG_GeneralizedTime ) ) {
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 ;
}
tmpstr = tvb_get_ptr ( tvb , offset , len ) ;
snprintf ( str , 31 , " %.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s) " ,
tmpstr , tmpstr + 4 , tmpstr + 6 , tmpstr + 8 ,
tmpstr + 10 , tmpstr + 12 , tmpstr + 14 ) ;
str [ 31 ] = 0 ; /* just in case ... */
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 */
int dissect_ber_bitstring ( gboolean implicit_tag , packet_info * pinfo , proto_tree * parent_tree , tvbuff_t * tvb , int offset , asn_namedbit * named_bits , gint hf_id , gint ett_id , tvbuff_t * * out_tvb )
2004-02-20 10:04:10 +00:00
{
guint8 class ;
2004-03-25 09:18:03 +00:00
gboolean pc , ind ;
2004-02-20 10:04:10 +00:00
guint32 tag ;
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 ;
asn_namedbit * nb ;
2004-05-11 07:26:45 +00:00
char * sep ;
gboolean term ;
2004-02-20 10:04:10 +00:00
2004-03-25 09:18:03 +00:00
/* 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
/* sanity check: we only handle Universal BitSrings */
2004-03-25 09:18:03 +00:00
if ( ! implicit_tag ) {
if ( ( class ! = BER_CLASS_UNI )
| | ( tag ! = BER_UNI_TAG_BITSTRING ) ) {
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-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 ) {
* out_tvb = tvb_new_subset ( tvb , offset , len , 8 * len - pad ) ;
}
}
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 ) {
if ( item & & nb - > tstr )
2004-05-11 07:26:45 +00:00
proto_item_append_text ( item , " %s%s " , sep , nb - > tstr ) ;
2004-03-25 09:18:03 +00:00
} else {
if ( item & & nb - > fstr )
2004-05-11 07:26:45 +00:00
proto_item_append_text ( item , " %s%s " , sep , nb - > fstr ) ;
2004-03-25 09:18:03 +00:00
}
nb + + ;
2004-05-11 07:26:45 +00:00
sep = " , " ;
term = TRUE ;
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 )
{
tvbuff_t * tmp_tvb ;
proto_tree * tree ;
guint32 val ;
int * * bf ;
header_field_info * hfi ;
2004-05-11 07:26:45 +00:00
char * sep ;
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 ) ;
if ( bit_fields & & tree ) {
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 } } ,
} ;
static gint * ett [ ] = {
& ett_ber_octet_string ,
} ;
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 )
{
}