diff options
author | Guy Harris <guy@alum.mit.edu> | 2004-03-25 09:18:03 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2004-03-25 09:18:03 +0000 |
commit | a6ed2d499af391480d9853833e22f153c502dc4b (patch) | |
tree | 84080b769cb16a9533d179fc4a231192c7c83b20 /packet-ber.c | |
parent | 7b109873f4263b97155419bb1f07111bb8adecb3 (diff) |
From Tomas Kukosa: BER dissector enhancements and proto.c updates to
support them.
From Ronnie Sahlberg: Kerberos updates with new constants from the
current draft, decryption and dissection of Kerberos blobs, and changes
to work with the changed BER dissector.
svn path=/trunk/; revision=10479
Diffstat (limited to 'packet-ber.c')
-rw-r--r-- | packet-ber.c | 710 |
1 files changed, 501 insertions, 209 deletions
diff --git a/packet-ber.c b/packet-ber.c index b396af4032..e255c3df24 100644 --- a/packet-ber.c +++ b/packet-ber.c @@ -2,7 +2,7 @@ * Helpers for ASN.1/BER dissection * Ronnie Sahlberg (C) 2004 * - * $Id: packet-ber.c,v 1.3 2004/03/01 09:11:23 sahlberg Exp $ + * $Id: packet-ber.c,v 1.4 2004/03/25 09:17:07 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -23,6 +23,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* + * 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) + * + */ + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -40,7 +47,6 @@ #include "packet-ber.h" - static gint proto_ber = -1; static gint hf_ber_id_class = -1; static gint hf_ber_id_pc = -1; @@ -81,85 +87,145 @@ static const value_string ber_uni_tag_codes[] = { }; -/* this function dissects the identifier octer of the BER TLV. - * We only handle TAGs (and LENGTHs) that fit inside 32 bit integers. - */ -int -dissect_ber_identifier(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint8 *class, gboolean *pc, guint32 *tag) -{ - guint8 id; - int old_offset=offset; +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); - id=tvb_get_guint8(tvb, offset); - offset+=1; +/* 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; - *class=(id>>6)&0x03; - *pc=(id>>5)&0x01; - *tag=id&0x1f; -/*XXX handle case when TAG==0x1f */ + /* 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; +} +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); + if(show_internal_ber_fields){ - proto_tree_add_uint(tree, hf_ber_id_class, tvb, old_offset, 1, id); - proto_tree_add_boolean(tree, hf_ber_id_pc, tvb, old_offset, 1, id); - if(*class==BER_CLASS_UNI){ - proto_tree_add_uint(tree, hf_ber_id_uni_tag, tvb, old_offset, 1, *tag); + 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); } else { - proto_tree_add_uint(tree, hf_ber_id_tag, tvb, old_offset, 1, *tag); + proto_tree_add_uint(tree, hf_ber_id_tag, tvb, old_offset, offset - old_offset, tmp_tag); } - } + if (class) + *class = tmp_class; + if (pc) + *pc = tmp_pc; + if (tag) + *tag = tmp_tag; + return offset; } -/* this function dissects the identifier octer of the BER TLV. +/* this function gets the length octets of the BER TLV. * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers. */ +/* 8.1.3 Length octets */ int -dissect_ber_length(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length) -{ - guint8 id; - int old_offset=offset; +get_ber_length(tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind) { + guint8 oct, len; + guint32 tmp_length; + gboolean tmp_ind; - *length=0; + tmp_length = 0; + tmp_ind = FALSE; - id=tvb_get_guint8(tvb, offset); - offset+=1; + oct = tvb_get_guint8(tvb, offset); + offset += 1; - if(!(id&0x80)){ - *length=id; - if(show_internal_ber_fields){ - proto_tree_add_uint(tree, hf_ber_length, tvb, old_offset, 1, *length); + 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 */ } - return offset; } - /* length byte has bit 8 set ! */ - id&=0x7f; - while(id--){ - guint tmpl; - tmpl=tvb_get_guint8(tvb, offset); - offset++; - *length=((*length)<<8)+tmpl; - } - if(show_internal_ber_fields){ -/*XXX show the len byte */ - proto_tree_add_uint(tree, hf_ber_length, tvb, old_offset+1, offset-old_offset+1, *length); - } + if (length) + *length = tmp_length; + if (ind) + *ind = tmp_ind; return offset; } - -/* func is NULL normally but - * if the octet string contains an ber encode struct we provide func as the - * dissector for that struct +/* this function dissects the length octets of the BER TLV. + * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers. */ -int -dissect_ber_octet_string(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, ber_callback func) +int +dissect_ber_length(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind) { + 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) { guint8 class; - gboolean pc; + gboolean pc, ind; guint32 tag; guint32 len; int end_offset; @@ -167,35 +233,48 @@ dissect_ber_octet_string(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, in /* 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); + offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind); end_offset=offset+len; - if(!len){ - return end_offset; - } - /* sanity check: we only handle Constructed Universal Sequences */ - 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; + 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; + } } - - if(hf_id!=-1){ - it=proto_tree_add_item(tree, hf_id, tvb, offset, len, FALSE); - tree=proto_item_add_subtree(it, ett_ber_octet_string); - } - if(func){ - tvbuff_t *next_tvb; - next_tvb=tvb_new_subset(tvb, offset, len, len); - func(pinfo, tree, next_tvb, 0); + 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); + } } -/*qqq*/ - return end_offset; } +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; +} + int dissect_ber_integer(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, guint32 *value) @@ -204,16 +283,21 @@ dissect_ber_integer(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int off gboolean pc; guint32 tag; guint32 len; - guint32 val; + gint32 val; guint32 i; offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag); - offset=dissect_ber_length(pinfo, tree, tvb, offset, &len); + offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL); /* if(class!=BER_CLASS_UNI)*/ val=0; - for(i=0;i<len;i++){ + if (len > 0) { + /* extend sign bit */ + val = (gint8)tvb_get_guint8(tvb, offset); + offset++; + } + for(i=1;i<len;i++){ val=(val<<8)|tvb_get_guint8(tvb, offset); offset++; } @@ -221,7 +305,7 @@ dissect_ber_integer(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int off ber_last_created_item=NULL; if(hf_id!=-1){ - ber_last_created_item=proto_tree_add_uint(tree, hf_id, tvb, offset-len, len, val); + ber_last_created_item=proto_tree_add_item(tree, hf_id, tvb, offset-len, len, FALSE); } if(value){ *value=val; @@ -242,9 +326,10 @@ dissect_ber_boolean(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int off guint32 tag; guint32 len; guint8 val; + header_field_info *hfi; offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag); - offset=dissect_ber_length(pinfo, tree, tvb, offset, &len); + offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL); /* if(class!=BER_CLASS_UNI)*/ @@ -253,8 +338,12 @@ dissect_ber_boolean(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int off ber_last_created_item=NULL; - if(hf_id!=-1){ - ber_last_created_item=proto_tree_add_uint(tree, hf_id, tvb, offset-1, 1, val?1:0); + 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); } return offset; @@ -266,60 +355,56 @@ dissect_ber_boolean(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int off /* this function dissects a BER sequence */ -int -dissect_ber_sequence(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, ber_sequence *seq, gint hf_id, gint ett_id) -{ +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) { guint8 class; - gboolean pc; + gboolean pc, ind; guint32 tag; guint32 len; - proto_tree *tree=parent_tree; - proto_item *item=NULL; + proto_tree *tree = parent_tree; + proto_item *item = NULL; int end_offset; /* 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); - end_offset=offset+len; - + 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 */ - if( (class!=BER_CLASS_UNI) - ||(!pc) - ||(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); + 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); return end_offset; } /* create subtree */ - if(hf_id!=-1){ + if (hf_id != -1) { 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 */ - while(offset<end_offset){ + while (offset < end_offset){ guint8 class; gboolean pc; guint32 tag; guint32 len; - int eoffset; + int hoffset, eoffset; + hoffset = offset; /* read header and len for next field */ - offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag); - offset=dissect_ber_length(pinfo, tree, tvb, offset, &len); - eoffset=offset+len; + offset = get_ber_identifier(tvb, offset, &class, &pc, &tag); + offset = get_ber_length(tvb, offset, &len, NULL); + eoffset = offset + len; - ber_sequence_try_again: /* have we run out of known entries in the sequence ?*/ - if(!seq->func){ + if (!seq->func) { /* it was not, move to the enxt one and try again */ - proto_tree_add_text(tree, tvb, offset, len, "BER Error: This field lies beyond the end of the known sequence definition."); - offset=eoffset; + proto_tree_add_text(tree, tvb, offset, len, "BER Error: This field lies beyond the end of the known sequence definition."); + offset = eoffset; continue; } @@ -332,23 +417,30 @@ ber_sequence_try_again: seq++; goto ber_sequence_try_again; } - proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field"); - seq++; - offset=eoffset; - continue; + if (!(seq->flags & BER_FLAGS_NOTCHKTAG)) { + proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field"); + seq++; + 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); + } + /* call the dissector for this field */ - seq->func(pinfo, tree, tvb, offset); - + seq->func(pinfo, tree, tvb, hoffset); seq++; - offset=eoffset; + offset = eoffset; } /* if we didnt end up at exactly offset, then we ate too many bytes */ - if(offset!=end_offset){ - proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Sequence ate %d too many bytes", offset-end_offset); + if (offset != end_offset) { + proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Sequence ate %d too many bytes", offset-end_offset); } return end_offset; @@ -359,37 +451,42 @@ ber_sequence_try_again: /* this function dissects a BER choice */ int -dissect_ber_choice(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_choice *ch, gint hf_id, gint ett_id) +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) { guint8 class; gboolean pc; guint32 tag; guint32 len; + const ber_choice *ch; proto_tree *tree=parent_tree; proto_item *item=NULL; int end_offset; + int hoffset = offset; - /* 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); + /* read header and len for choice field */ + offset=get_ber_identifier(tvb, offset, &class, &pc, &tag); + offset=get_ber_length(tvb, offset, &len, NULL); end_offset=offset+len; - - /* create subtree */ - if(hf_id!=-1){ - 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 find the right choice or run out of entries */ + ch = choice; while(ch->func){ if( (ch->class==class) &&(ch->tag==tag) ){ - offset=ch->func(pinfo, tree, tvb, offset); + 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); return end_offset; break; } @@ -398,12 +495,12 @@ dissect_ber_choice(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, i /* oops no more entries and we still havent found * our guy :-( */ - proto_tree_add_text(tree, tvb, offset, len, "BER Error: This choice field was not found."); + proto_tree_add_text(tree, tvb, offset, len, "BER Error: This choice field was not found."); return end_offset; } - +#if 0 /* this function dissects a BER GeneralString */ int @@ -427,7 +524,7 @@ dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, i /* first we must read the GeneralString header */ offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag); - offset=dissect_ber_length(pinfo, tree, tvb, offset, &len); + offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL); end_offset=offset+len; /* sanity check: we only handle Universal GeneralString*/ @@ -450,55 +547,222 @@ dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, i return end_offset; } +#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); +} -/* this function dissects a BER sequence of - */ int -dissect_ber_sequence_of(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, ber_callback func, gint hf_id, gint ett_id) +dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, guint name_len) { + tvbuff_t *out_tvb; + + offset = dissect_ber_restricted_string(FALSE, BER_UNI_TAG_GENSTR, pinfo, tree, tvb, offset, hf_id, (name_string)?&out_tvb:NULL); + + 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) { guint8 class; gboolean pc; guint32 tag; + guint32 i, len; + int eoffset; + guint8 byte; + guint32 value; + char str[256],*strp; + + 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) { + proto_tree_add_string(tree, hf_id, tvb, offset - len, len, str); + } + + 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; guint32 len; - proto_tree *tree=parent_tree; - proto_item *item=NULL; - int end_offset; + proto_tree *tree = parent_tree; + proto_item *item = NULL; + int cnt, hoffset, end_offset; + header_field_info *hfi; /* 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); - end_offset=offset+len; + 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 */ - if( (class!=BER_CLASS_UNI) - ||(!pc) - ||(tag!=BER_UNI_TAG_SEQUENCE) ){ - proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: SequenceOf expected but Class:%d PC:%d Tag:%d was unexpected", class, pc, tag); + 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); return end_offset; } + /* 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; + /* create subtree */ - if(hf_id!=-1){ + if (hf_id != -1) { + hfi = proto_registrar_get_nth(hf_id); if(parent_tree){ - item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE); + if (hfi->type == FT_NONE) + item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE); + else { + item = proto_tree_add_uint(parent_tree, hf_id, tvb, offset, len, cnt); + proto_item_append_text(item, (cnt==1)?" item":" items"); + } tree = proto_item_add_subtree(item, ett_id); } } /* loop over all entries until we reach the end of the sequence */ - while(offset<end_offset){ + 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)) { + proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field"); + 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); + } + /* call the dissector for this field */ - offset=func(pinfo, tree, tvb, offset); + seq->func(pinfo, tree, tvb, hoffset); + cnt++; + offset = eoffset; } /* if we didnt end up at exactly offset, then we ate too many bytes */ - if(offset!=end_offset){ - proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: SequenceOf ate %d too many bytes", offset-end_offset); + 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); } return end_offset; } +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); +} int dissect_ber_generalized_time(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id) @@ -512,7 +776,7 @@ dissect_ber_generalized_time(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb int end_offset; offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag); - offset=dissect_ber_length(pinfo, tree, tvb, offset, &len); + offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL); end_offset=offset+len; /* sanity check. we only handle universal/generalized time */ @@ -537,86 +801,112 @@ dissect_ber_generalized_time(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb return offset; } - - -/* this function dissects a BER BIT-STRING - */ -int -dissect_ber_bitstring(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, gint hf_id, gint ett_id, unsigned char *bitstring, int bitstring_len, proto_item **it, proto_tree **tr) +/* 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) { guint8 class; - gboolean pc; + gboolean pc, ind; guint32 tag; guint32 len; - proto_tree *tree=parent_tree; - proto_item *item=NULL; + guint8 pad, b0, b1, val; int end_offset; - guint8 pad; - gboolean first_time=TRUE; + proto_item *item = NULL; + proto_tree *tree = NULL; + asn_namedbit *nb; - /* 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); - end_offset=offset+len; + /* 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; /* sanity check: we only handle Universal BitSrings */ - if( (class!=BER_CLASS_UNI) - ||(tag!=BER_UNI_TAG_BITSTRING) ){ - proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: BitString expected but Class:%d PC:%d Tag:%d was unexpected", class, pc, tag); - return end_offset; - } - - - /* create subtree */ - if(hf_id!=-1){ - if(parent_tree){ - item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE); - tree = proto_item_add_subtree(item, ett_id); + 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; } } - if(tr){ - *tr=tree; - } - if(it){ - *it=item; - } + ber_last_created_item = NULL; - /* padding */ - pad=tvb_get_guint8(tvb, offset); - proto_tree_add_item(tree, hf_ber_bitstring_padding, tvb, offset, 1, FALSE); - offset+=1; - len--; - - - /* XXX we should handle segmented bitstrings */ - - while(len--){ - guint8 tmp; - - tmp=tvb_get_guint8(tvb, offset); + 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); offset++; - - if(item){ - if(first_time){ - proto_item_append_text(item, " 0x"); + 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); } - proto_item_append_text(item, "%02x",tmp); - first_time=FALSE; } + if (out_tvb) { + *out_tvb = tvb_new_subset(tvb, offset, len, 8*len-pad); + } + } - if(bitstring){ - *(bitstring++)=tmp; - if(--bitstring_len<=0){ - bitstring=NULL; + if (named_bits) { + 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); + b0 = (nb->gb0 == -1) ? nb->bit/8 : nb->gb0/8; + b1 = (nb->gb1 == -1) ? nb->bit/8 : nb->gb1/8; + 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); } + if (val) { + if (item && nb->tstr) + proto_item_append_text(item, " %s", nb->tstr); + } else { + if (item && nb->fstr) + proto_item_append_text(item, " %s", nb->fstr); + } + nb++; } } return end_offset; } +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; + 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) { + val = tvb_get_ntohl(tmp_tvb, 0); + bf = bit_fields; + while (*bf) { + proto_tree_add_item(tree, **bf, tmp_tvb, 0, 4, FALSE); + hfi = proto_registrar_get_nth(**bf); + if (val & hfi->bitmask) + proto_item_append_text(ber_last_created_item, " %s", hfi->name); + bf++; + } + } + + if (out_tvb) + *out_tvb = tmp_tvb; + + return offset; +} void proto_register_ber(void) @@ -652,6 +942,8 @@ proto_register_ber(void) proto_register_field_array(proto_ber, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + proto_set_cant_toggle(proto_ber); + /* Register preferences */ ber_module = prefs_register_protocol(proto_ber, NULL); prefs_register_bool_preference(ber_module, "show_internals", |