aboutsummaryrefslogtreecommitdiffstats
path: root/packet-ber.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2004-03-25 09:18:03 +0000
committerGuy Harris <guy@alum.mit.edu>2004-03-25 09:18:03 +0000
commita6ed2d499af391480d9853833e22f153c502dc4b (patch)
tree84080b769cb16a9533d179fc4a231192c7c83b20 /packet-ber.c
parent7b109873f4263b97155419bb1f07111bb8adecb3 (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.c710
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",