2 * Helpers for ASN.1/BER dissection
3 * Ronnie Sahlberg (C) 2004
5 * $Id: packet-ber.c,v 1.9 2004/05/11 10:57:14 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 * ITU-T Recommendation X.690 (07/2002),
28 * Information technology ASN.1 encoding rules:
29 * Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)
43 #include <epan/packet.h>
45 #include <epan/strutil.h>
47 #include "packet-ber.h"
50 static gint proto_ber = -1;
51 static gint hf_ber_id_class = -1;
52 static gint hf_ber_id_pc = -1;
53 static gint hf_ber_id_uni_tag = -1;
54 static gint hf_ber_id_tag = -1;
55 static gint hf_ber_length = -1;
56 static gint hf_ber_bitstring_padding = -1;
58 static gint ett_ber_octet_string = -1;
60 static gboolean show_internal_ber_fields = FALSE;
62 proto_item *ber_last_created_item=NULL;
65 static const value_string ber_class_codes[] = {
66 { BER_CLASS_UNI, "Universal" },
67 { BER_CLASS_APP, "Application" },
68 { BER_CLASS_CON, "Context Specific" },
69 { BER_CLASS_PRI, "Private" },
73 static const true_false_string ber_pc_codes = {
74 "Constructed Encoding",
78 static const value_string ber_uni_tag_codes[] = {
79 { BER_UNI_TAG_EOC , "'end-of-content'" },
80 { BER_UNI_TAG_BOOLEAN , "BOOLEAN" },
81 { BER_UNI_TAG_INTEGER , "INTEGER" },
82 { BER_UNI_TAG_BITSTRING , "BIT STRING" },
83 { BER_UNI_TAG_OCTETSTRING , "OCTET STRING" },
84 { BER_UNI_TAG_NULL , "NULL" },
85 { BER_UNI_TAG_OID , "OBJECT IDENTIFIER" },
86 { BER_UNI_TAG_ObjectDescriptor, "ObjectDescriptor" },
87 { BER_UNI_TAG_REAL , "REAL" },
88 { BER_UNI_TAG_ENUMERATED , "ENUMERATED" },
89 { BER_UNI_TAG_EMBEDDED_PDV , "EMBEDDED PDV" },
90 { BER_UNI_TAG_UTF8String , "UTF8String" },
91 { BER_UNI_TAG_RELATIVE_OID , "RELATIVE-OID" },
92 { BER_UNI_TAG_SEQUENCE , "SEQUENCE, SEQUENCE OF" },
93 { BER_UNI_TAG_SET , "SET, SET OF" },
94 { BER_UNI_TAG_NumericString , "NumericString" },
95 { BER_UNI_TAG_PrintableString , "PrintableString" },
96 { BER_UNI_TAG_TeletextString , "TeletextString, T61String" },
97 { BER_UNI_TAG_VideotexString , "VideotexString" },
98 { BER_UNI_TAG_IA5String , "IA5String" },
99 { BER_UNI_TAG_UCTTime , "UCTTime" },
100 { BER_UNI_TAG_GeneralizedTime , "GeneralizedTime" },
101 { BER_UNI_TAG_GraphicString , "GraphicString" },
102 { BER_UNI_TAG_VisibleString , "VisibleString, ISO64String" },
103 { BER_UNI_TAG_GeneralString , "GeneralString" },
104 { BER_UNI_TAG_UniversalString , "UniversalString" },
105 { BER_UNI_TAG_CHARACTERSTRING , "CHARACTER STRING" },
106 { BER_UNI_TAG_BMPString , "BMPString" },
111 proto_item *get_ber_last_created_item(void) {
112 return ber_last_created_item;
115 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);
117 /* 8.1 General rules for encoding */
119 /* 8.1.2 Identifier octets */
120 int get_ber_identifier(tvbuff_t *tvb, int offset, guint8 *class, gboolean *pc, guint32 *tag) {
126 id = tvb_get_guint8(tvb, offset);
130 tmp_class = (id>>6) & 0x03;
131 tmp_pc = (id>>5) & 0x01;
134 if (tmp_tag == 0x1F) {
136 while (tvb_length_remaining(tvb, offset) > 0) {
137 t = tvb_get_guint8(tvb, offset);
155 int dissect_ber_identifier(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint8 *class, gboolean *pc, guint32 *tag)
157 int old_offset = offset;
162 offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
164 if(show_internal_ber_fields){
165 proto_tree_add_uint(tree, hf_ber_id_class, tvb, old_offset, 1, tmp_class<<6);
166 proto_tree_add_boolean(tree, hf_ber_id_pc, tvb, old_offset, 1, (tmp_pc)?0x20:0x00);
167 if(tmp_class==BER_CLASS_UNI){
168 proto_tree_add_uint(tree, hf_ber_id_uni_tag, tvb, old_offset, offset - old_offset, tmp_tag);
170 proto_tree_add_uint(tree, hf_ber_id_tag, tvb, old_offset, offset - old_offset, tmp_tag);
184 /* this function gets the length octets of the BER TLV.
185 * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
187 /* 8.1.3 Length octets */
189 get_ber_length(tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind) {
197 oct = tvb_get_guint8(tvb, offset);
208 oct = tvb_get_guint8(tvb, offset);
210 tmp_length = (tmp_length<<8) + oct;
220 *length = tmp_length;
227 /* this function dissects the length octets of the BER TLV.
228 * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
231 dissect_ber_length(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind)
233 int old_offset = offset;
237 offset = get_ber_length(tvb, offset, &tmp_length, &tmp_ind);
239 if(show_internal_ber_fields){
240 proto_tree_add_uint(tree, hf_ber_length, tvb, old_offset, offset - old_offset, tmp_length);
243 *length = tmp_length;
249 /* 8.7 Encoding of an octetstring value */
251 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) {
259 /* read header and len for the octet string */
260 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
261 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
262 end_offset=offset+len;
264 /* sanity check: we only handle Constructed Universal Sequences */
266 if( (class!=BER_CLASS_UNI)
267 ||(tag!=BER_UNI_TAG_OCTETSTRING) ){
268 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);
273 ber_last_created_item = NULL;
280 it = proto_tree_add_item(tree, hf_id, tvb, offset, len, FALSE);
281 ber_last_created_item = it;
284 *out_tvb = tvb_new_subset(tvb, offset, len, len);
290 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)
294 offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_id, (func)?&out_tvb:NULL);
295 if (func && (tvb_length(out_tvb)>0)) {
297 tree = proto_item_add_subtree(ber_last_created_item, ett_ber_octet_string);
298 func(pinfo, tree, out_tvb, 0);
305 dissect_ber_integer(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, guint32 *value)
314 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
315 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
317 /* if(class!=BER_CLASS_UNI)*/
321 /* extend sign bit */
322 val = (gint8)tvb_get_guint8(tvb, offset);
326 val=(val<<8)|tvb_get_guint8(tvb, offset);
330 ber_last_created_item=NULL;
333 /* XXX - what if "len" is not 1, 2, 3, or 4? */
334 ber_last_created_item=proto_tree_add_item(tree, hf_id, tvb, offset-len, len, FALSE);
348 dissect_ber_boolean(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
355 header_field_info *hfi;
357 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
358 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
360 /* if(class!=BER_CLASS_UNI)*/
362 val=tvb_get_guint8(tvb, offset);
365 ber_last_created_item=NULL;
368 hfi = proto_registrar_get_nth(hf_id);
369 if (hfi->type == FT_BOOLEAN)
370 ber_last_created_item=proto_tree_add_boolean(tree, hf_id, tvb, offset-1, 1, val);
372 ber_last_created_item=proto_tree_add_uint(tree, hf_id, tvb, offset-1, 1, val?1:0);
382 /* this function dissects a BER sequence
384 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) {
389 proto_tree *tree = parent_tree;
390 proto_item *item = NULL;
393 /* first we must read the sequence header */
394 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
395 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
396 end_offset = offset + len;
398 /* sanity check: we only handle Constructed Universal Sequences */
400 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
401 ||(tag!=BER_UNI_TAG_SEQUENCE)))) {
402 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);
409 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
410 tree = proto_item_add_subtree(item, ett_id);
414 /* loop over all entries until we reach the end of the sequence */
415 while (offset < end_offset){
420 int hoffset, eoffset;
423 /* read header and len for next field */
424 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
425 offset = get_ber_length(tvb, offset, &len, NULL);
426 eoffset = offset + len;
428 ber_sequence_try_again:
429 /* have we run out of known entries in the sequence ?*/
431 /* it was not, move to the enxt one and try again */
432 proto_tree_add_text(tree, tvb, offset, len, "BER Error: This field lies beyond the end of the known sequence definition.");
437 /* verify that this one is the one we want */
438 if( (seq->class!=class)
440 /* it was not, move to the enxt one and try again */
441 if(seq->flags&BER_FLAGS_OPTIONAL){
442 /* well this one was optional so just skip to the next one and try again. */
444 goto ber_sequence_try_again;
446 if (!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
447 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field");
454 if (!(seq->flags & BER_FLAGS_NOOWNTAG) && !(seq->flags & BER_FLAGS_IMPLTAG)) {
455 /* dissect header and len for field */
456 hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
457 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
460 /* call the dissector for this field */
461 seq->func(pinfo, tree, tvb, hoffset);
467 /* if we didnt end up at exactly offset, then we ate too many bytes */
468 if (offset != end_offset) {
469 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Sequence ate %d too many bytes", offset-end_offset);
477 /* this function dissects a BER choice
480 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)
486 const ber_choice *ch;
487 proto_tree *tree=parent_tree;
488 proto_item *item=NULL;
490 int hoffset = offset;
492 /* read header and len for choice field */
493 offset=get_ber_identifier(tvb, offset, &class, &pc, &tag);
494 offset=get_ber_length(tvb, offset, &len, NULL);
495 end_offset=offset+len;
497 /* loop over all entries until we find the right choice or
498 run out of entries */
501 if( (ch->class==class)
503 if (!(ch->flags & BER_FLAGS_NOOWNTAG) && !(ch->flags & BER_FLAGS_IMPLTAG)) {
504 /* dissect header and len for field */
505 hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
506 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
511 item = proto_tree_add_uint(parent_tree, hf_id, tvb, hoffset, end_offset - hoffset, ch->value);
512 tree = proto_item_add_subtree(item, ett_id);
515 offset=ch->func(pinfo, tree, tvb, hoffset);
521 /* oops no more entries and we still havent found
524 proto_tree_add_text(tree, tvb, offset, len, "BER Error: This choice field was not found.");
530 /* this function dissects a BER GeneralString
533 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, int name_len)
551 /* first we must read the GeneralString header */
552 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
553 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
554 end_offset=offset+len;
556 /* sanity check: we only handle Universal GeneralString*/
557 if( (class!=BER_CLASS_UNI)
558 ||(tag!=BER_UNI_TAG_GENSTR) ){
559 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);
563 if(len>=(max_len-1)){
567 tvb_memcpy(tvb, str, offset, len);
571 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
578 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) {
584 int hoffset = offset;
586 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
587 offset = get_ber_length(tvb, offset, &len, NULL);
588 eoffset = offset + len;
592 if( (class!=BER_CLASS_UNI)
594 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);
600 return dissect_ber_octet_string(TRUE, pinfo, tree, tvb, hoffset, hf_id, out_tvb);
604 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, guint name_len)
608 offset = dissect_ber_restricted_string(FALSE, BER_UNI_TAG_GeneralString, pinfo, tree, tvb, offset, hf_id, (name_string)?&out_tvb:NULL);
611 if (tvb_length(out_tvb) >= name_len) {
612 tvb_memcpy(out_tvb, name_string, 0, name_len-1);
613 name_string[name_len-1] = '\0';
615 tvb_memcpy(out_tvb, name_string, 0, -1);
616 name_string[tvb_length(out_tvb)] = '\0';
623 /* 8.19 Encoding of an object identifier value */
624 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) {
634 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
635 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
636 eoffset = offset + len;
639 value_string[0] = '\0';
644 if( (class!=BER_CLASS_UNI)
645 ||(tag != BER_UNI_TAG_OID) ){
646 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);
652 for (i=0,strp=str; i<len; i++){
653 byte = tvb_get_guint8(tvb, offset);
657 proto_tree_add_text(tree, tvb, offset, eoffset - offset, "BER Error: too long Object Identifier");
663 strp += sprintf(strp, "%d.%d", byte/40, byte%40);
667 value = (value << 7) | (byte & 0x7F);
672 strp += sprintf(strp, ".%d", value);
678 proto_tree_add_string(tree, hf_id, tvb, offset - len, len, str);
682 strcpy(value_string, str);
688 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) {
693 proto_tree *tree = parent_tree;
694 proto_item *item = NULL;
695 int cnt, hoffset, end_offset;
696 header_field_info *hfi;
698 /* first we must read the sequence header */
699 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
700 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
701 end_offset = offset + len;
703 /* sanity check: we only handle Constructed Universal Sequences */
705 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
707 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: %s Of expected but Class:%d PC:%d Tag:%d was unexpected",
708 (type==BER_UNI_TAG_SEQUENCE)?"Set":"Sequence", class, pc, tag);
712 /* count number of items */
715 while (offset < end_offset){
717 /* read header and len for next field */
718 offset = get_ber_identifier(tvb, offset, NULL, NULL, NULL);
719 offset = get_ber_length(tvb, offset, &len, NULL);
727 hfi = proto_registrar_get_nth(hf_id);
729 if (hfi->type == FT_NONE) {
730 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
731 proto_item_append_text(item, ":");
733 item = proto_tree_add_uint(parent_tree, hf_id, tvb, offset, len, cnt);
734 proto_item_append_text(item, (cnt==1)?" item":" items");
736 tree = proto_item_add_subtree(item, ett_id);
740 /* loop over all entries until we reach the end of the sequence */
741 while (offset < end_offset){
750 /* read header and len for next field */
751 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
752 offset = get_ber_length(tvb, offset, &len, NULL);
753 eoffset = offset + len;
755 /* verify that this one is the one we want */
756 if ((seq->class!=class)
758 if (!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
759 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field");
765 if (!(seq->flags & BER_FLAGS_NOOWNTAG) && !(seq->flags & BER_FLAGS_IMPLTAG)) {
766 /* dissect header and len for field */
767 hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
768 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
771 /* call the dissector for this field */
772 seq->func(pinfo, tree, tvb, hoffset);
777 /* if we didnt end up at exactly offset, then we ate too many bytes */
778 if (offset != end_offset) {
779 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: %s Of ate %d too many bytes",
780 (type==BER_UNI_TAG_SEQUENCE)?"Set":"Sequence", offset-end_offset);
786 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) {
787 return dissect_ber_sq_of(implicit_tag, BER_UNI_TAG_SEQUENCE, pinfo, parent_tree, tvb, offset, seq, hf_id, ett_id);
790 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) {
791 return dissect_ber_sq_of(implicit_tag, BER_UNI_TAG_SET, pinfo, parent_tree, tvb, offset, seq, hf_id, ett_id);
795 dissect_ber_generalized_time(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
798 const guint8 *tmpstr;
805 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
806 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
807 end_offset=offset+len;
809 /* sanity check. we only handle universal/generalized time */
810 if( (class!=BER_CLASS_UNI)
811 ||(tag!=BER_UNI_TAG_GeneralizedTime)){
812 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);
814 end_offset=offset+len;
817 tmpstr=tvb_get_ptr(tvb, offset, len);
818 snprintf(str, 31, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s)",
819 tmpstr, tmpstr+4, tmpstr+6, tmpstr+8,
820 tmpstr+10, tmpstr+12, tmpstr+14);
821 str[31]=0; /* just in case ... */
824 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
831 /* 8.6 Encoding of a bitstring value */
832 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)
838 guint8 pad, b0, b1, val;
840 proto_item *item = NULL;
841 proto_tree *tree = NULL;
846 /* read header and len for the octet string */
847 offset = dissect_ber_identifier(pinfo, parent_tree, tvb, offset, &class, &pc, &tag);
848 offset = dissect_ber_length(pinfo, parent_tree, tvb, offset, &len, &ind);
849 end_offset = offset + len;
851 /* sanity check: we only handle Universal BitSrings */
853 if( (class!=BER_CLASS_UNI)
854 ||(tag!=BER_UNI_TAG_BITSTRING) ){
855 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);
860 ber_last_created_item = NULL;
868 pad = tvb_get_guint8(tvb, offset);
869 proto_tree_add_item(parent_tree, hf_ber_bitstring_padding, tvb, offset, 1, FALSE);
873 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
874 ber_last_created_item = item;
876 tree = proto_item_add_subtree(item, ett_id);
880 *out_tvb = tvb_new_subset(tvb, offset, len, 8*len-pad);
889 if (nb->bit < (8*len-pad)) {
890 val = tvb_get_guint8(tvb, offset + nb->bit/8);
891 val &= 0x80 >> (nb->bit%8);
892 b0 = (nb->gb0 == -1) ? nb->bit/8 :
893 ((guint32)nb->gb0)/8;
894 b1 = (nb->gb1 == -1) ? nb->bit/8 :
895 ((guint32)nb->gb1)/8;
896 proto_tree_add_item(tree, *(nb->p_id), tvb, offset + b0, b1 - b0 + 1, FALSE);
897 } else { /* 8.6.2.4 */
899 proto_tree_add_boolean(tree, *(nb->p_id), tvb, offset + len, 0, 0x00);
902 if (item && nb->tstr)
903 proto_item_append_text(item, "%s%s", sep, nb->tstr);
905 if (item && nb->fstr)
906 proto_item_append_text(item, "%s%s", sep, nb->fstr);
913 proto_item_append_text(item, ")");
919 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)
925 header_field_info *hfi;
929 offset = dissect_ber_bitstring(implicit_tag, pinfo, parent_tree, tvb, offset, NULL, hf_id, ett_id, &tmp_tvb);
931 tree = proto_item_get_subtree(ber_last_created_item);
932 if (bit_fields && tree) {
933 val = tvb_get_ntohl(tmp_tvb, 0);
938 proto_tree_add_item(tree, **bf, tmp_tvb, 0, 4, FALSE);
939 hfi = proto_registrar_get_nth(**bf);
940 if (val & hfi->bitmask) {
941 proto_item_append_text(ber_last_created_item, "%s%s", sep, hfi->name);
948 proto_item_append_text(ber_last_created_item, ")");
958 proto_register_ber(void)
960 static hf_register_info hf[] = {
961 { &hf_ber_id_class, {
962 "Class", "ber.id.class", FT_UINT8, BASE_DEC,
963 VALS(ber_class_codes), 0xc0, "Class of BER TLV Identifier", HFILL }},
964 { &hf_ber_bitstring_padding, {
965 "Padding", "ber.bitstring.padding", FT_UINT8, BASE_DEC,
966 NULL, 0x0, "Number of unsused bits in the last octet of the bitstring", HFILL }},
968 "P/C", "ber.id.pc", FT_BOOLEAN, 8,
969 TFS(&ber_pc_codes), 0x20, "Primitive or Constructed BER encoding", HFILL }},
970 { &hf_ber_id_uni_tag, {
971 "Tag", "ber.id.uni_tag", FT_UINT8, BASE_DEC,
972 VALS(ber_uni_tag_codes), 0x1f, "Universal tag type", HFILL }},
974 "Tag", "ber.id.tag", FT_UINT32, BASE_DEC,
975 NULL, 0, "Tag value for non-Universal classes", HFILL }},
977 "Length", "ber.length", FT_UINT32, BASE_DEC,
978 NULL, 0, "Length of contents", HFILL }},
982 static gint *ett[] = {
983 &ett_ber_octet_string,
985 module_t *ber_module;
987 proto_ber = proto_register_protocol("Basic Encoding Rules (ASN.1 X.690)", "BER", "ber");
988 proto_register_field_array(proto_ber, hf, array_length(hf));
989 proto_register_subtree_array(ett, array_length(ett));
991 proto_set_cant_toggle(proto_ber);
993 /* Register preferences */
994 ber_module = prefs_register_protocol(proto_ber, NULL);
995 prefs_register_bool_preference(ber_module, "show_internals",
996 "Show internal BER encapsulation tokens",
997 "Whether the dissector should also display internal"
998 " ASN.1 BER details such as Identifier and Length fields", &show_internal_ber_fields);
1002 proto_reg_handoff_ber(void)