1 /*#define DEBUG_BER 1 */
2 /* TODO: change #.REGISTER signature to new_dissector_t and
3 * update call_ber_oid_callback() accordingly.
5 * Since we dont pass the TAG/LENGTH from the CHOICE/SEQUENCE/SEQUENCE OF/
6 * SET OF helpers through the callbacks to the next pabket-ber helper
7 * when the tags are IMPLICIT, this causes a problem when we also have
8 * indefinite length at the same time as the tags are implicit.
9 * While the proper fix is to change the signatures for packet-ber.c helpers
10 * as well as the signatures for the callbacks to include the indefinite length
11 * indication that would be a major job.
12 * For the time being, kludge, set a global variable in the
13 * CHOICE/SEQUENCE [OF]/SET [OF] helpers to indicate to the next helper
14 * whether the length is indefinite or not.
15 * This has currently only been implemented for {SEQUENCE|SET} [OF] but not yet
18 * This version attacks the problem(s) in a different way, if we see indefinit length
19 * the get_ber_length traverses the tags within the compound value and then we return the
20 * true length of the compound value including the EOC. Thus the tvb length is now always correct
21 * even for indefinite length, then if we get implicit tags they can be handled as if they were definite
26 * Helpers for ASN.1/BER dissection
27 * Ronnie Sahlberg (C) 2004
31 * Ethereal - Network traffic analyzer
32 * By Gerald Combs <gerald@ethereal.com>
33 * Copyright 1998 Gerald Combs
35 * This program is free software; you can redistribute it and/or
36 * modify it under the terms of the GNU General Public License
37 * as published by the Free Software Foundation; either version 2
38 * of the License, or (at your option) any later version.
40 * This program is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 * GNU General Public License for more details.
45 * You should have received a copy of the GNU General Public License
46 * along with this program; if not, write to the Free Software
47 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
51 * ITU-T Recommendation X.690 (07/2002),
52 * Information technology ASN.1 encoding rules:
53 * Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)
67 #include <epan/packet.h>
69 #include <epan/strutil.h>
70 #include <epan/to_str.h>
71 #include <epan/prefs.h>
72 #include <epan/reassemble.h>
73 #include <epan/emem.h>
74 #include "packet-ber.h"
77 #define MIN(x,y) ((x)<(y))?(x):(y)
80 static gint proto_ber = -1;
81 static gint hf_ber_id_class = -1;
82 static gint hf_ber_id_pc = -1;
83 static gint hf_ber_id_uni_tag = -1;
84 static gint hf_ber_id_uni_tag_ext = -1;
85 static gint hf_ber_id_tag = -1;
86 static gint hf_ber_id_tag_ext = -1;
87 static gint hf_ber_length = -1;
88 static gint hf_ber_bitstring_padding = -1;
89 static gint hf_ber_unknown_OID = -1;
90 static gint hf_ber_unknown_OCTETSTRING = -1;
91 static gint hf_ber_unknown_GraphicString = -1;
92 static gint hf_ber_unknown_NumericString = -1;
93 static gint hf_ber_unknown_PrintableString = -1;
94 static gint hf_ber_unknown_IA5String = -1;
95 static gint hf_ber_unknown_INTEGER = -1;
96 static gint hf_ber_unknown_ENUMERATED = -1;
98 static gint ett_ber_octet_string = -1;
99 static gint ett_ber_unknown = -1;
100 static gint ett_ber_SEQUENCE = -1;
102 static gboolean show_internal_ber_fields = FALSE;
104 proto_item *ber_last_created_item=NULL;
106 /* kludge to pass indefinite length indications from structure helpers
107 to the next helper. Or else implicite tag + indefinite length wont work.
109 static gboolean length_is_indefinite=FALSE;
110 not used anymore as the length from get_ber_length should be correct for indefinite length also.
112 static dissector_table_t ber_oid_dissector_table=NULL;
114 static const value_string ber_class_codes[] = {
115 { BER_CLASS_UNI, "Universal" },
116 { BER_CLASS_APP, "Application" },
117 { BER_CLASS_CON, "Context Specific" },
118 { BER_CLASS_PRI, "Private" },
122 static const true_false_string ber_pc_codes = {
123 "Constructed Encoding",
127 static const value_string ber_uni_tag_codes[] = {
128 { BER_UNI_TAG_EOC , "'end-of-content'" },
129 { BER_UNI_TAG_BOOLEAN , "BOOLEAN" },
130 { BER_UNI_TAG_INTEGER , "INTEGER" },
131 { BER_UNI_TAG_BITSTRING , "BIT STRING" },
132 { BER_UNI_TAG_OCTETSTRING , "OCTET STRING" },
133 { BER_UNI_TAG_NULL , "NULL" },
134 { BER_UNI_TAG_OID , "OBJECT IDENTIFIER" },
135 { BER_UNI_TAG_ObjectDescriptor, "ObjectDescriptor" },
136 { BER_UNI_TAG_REAL , "REAL" },
137 { BER_UNI_TAG_ENUMERATED , "ENUMERATED" },
138 { BER_UNI_TAG_EMBEDDED_PDV , "EMBEDDED PDV" },
139 { BER_UNI_TAG_UTF8String , "UTF8String" },
140 { BER_UNI_TAG_RELATIVE_OID , "RELATIVE-OID" },
141 { BER_UNI_TAG_SEQUENCE , "SEQUENCE, SEQUENCE OF" },
142 { BER_UNI_TAG_SET , "SET, SET OF" },
143 { BER_UNI_TAG_NumericString , "NumericString" },
144 { BER_UNI_TAG_PrintableString , "PrintableString" },
145 { BER_UNI_TAG_TeletexString , "TeletexString, T61String" },
146 { BER_UNI_TAG_VideotexString , "VideotexString" },
147 { BER_UNI_TAG_IA5String , "IA5String" },
148 { BER_UNI_TAG_UTCTime , "UTCTime" },
149 { BER_UNI_TAG_GeneralizedTime , "GeneralizedTime" },
150 { BER_UNI_TAG_GraphicString , "GraphicString" },
151 { BER_UNI_TAG_VisibleString , "VisibleString, ISO64String" },
152 { BER_UNI_TAG_GeneralString , "GeneralString" },
153 { BER_UNI_TAG_UniversalString , "UniversalString" },
154 { BER_UNI_TAG_CHARACTERSTRING , "CHARACTER STRING" },
155 { BER_UNI_TAG_BMPString , "BMPString" },
156 { 31 , "Continued" },
161 proto_item *get_ber_last_created_item(void) {
162 return ber_last_created_item;
166 static GHashTable *oid_table=NULL;
169 dissect_ber_oid_NULL_callback(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_)
176 register_ber_oid_dissector_handle(const char *oid, dissector_handle_t dissector, int proto _U_, const char *name)
178 dissector_add_string("ber.oid", oid, dissector);
179 g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
183 register_ber_oid_dissector(const char *oid, dissector_t dissector, int proto, const char *name)
185 dissector_handle_t dissector_handle;
187 dissector_handle=create_dissector_handle(dissector, proto);
188 dissector_add_string("ber.oid", oid, dissector_handle);
189 g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
192 /* Register the oid name to get translation in proto dissection */
194 register_ber_oid_name(const char *oid, const char *name)
196 g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
199 /* Get oid name from hash table to get translation in proto dissection(packet-per.c) */
201 get_ber_oid_name(char *oid)
203 return g_hash_table_lookup(oid_table, oid);
207 /* this function tries to dissect an unknown blob as much as possible.
208 * everytime this function is called it is a failure to implement a proper
209 * dissector in ethereal.
210 * something is missing, so dont become too comfy with this one,
211 * when it is called it is a BAD thing not a good thing.
212 * It can not handle IMPLICIT tags nor indefinite length.
214 int dissect_unknown_ber(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree)
221 proto_item *item=NULL;
222 proto_tree *next_tree=NULL;
226 offset=dissect_ber_identifier(pinfo, NULL, tvb, offset, &class, &pc, &tag);
227 offset=dissect_ber_length(pinfo, NULL, tvb, offset, &len, &ind);
229 if(len>(guint32)tvb_length_remaining(tvb, offset)){
230 /* hmm maybe something bad happened or the frame is short,
231 since these are not vital outputs just return instead of
232 throwing en exception.
234 proto_tree_add_text(tree, tvb, offset, len, "BER: Error length:%u longer than tvb_length_ramaining:%d",len, tvb_length_remaining(tvb, offset));
235 return tvb_length(tvb);
237 /* we dont care about the class only on the constructor flag */
241 case BER_UNI_TAG_INTEGER:
242 offset = dissect_ber_integer(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_INTEGER, NULL);
244 case BER_UNI_TAG_ENUMERATED:
245 offset = dissect_ber_integer(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_ENUMERATED, NULL);
247 case BER_UNI_TAG_GraphicString:
248 offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_GraphicString, NULL);
250 case BER_UNI_TAG_OCTETSTRING:
251 offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_OCTETSTRING, NULL);
253 case BER_UNI_TAG_OID:
254 offset=dissect_ber_object_identifier(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_OID, NULL);
256 case BER_UNI_TAG_SEQUENCE:
257 item=proto_tree_add_text(tree, tvb, offset, len, "SEQUENCE (len:%d bytes) tvb_remaining:%d", len, tvb_length_remaining(tvb, offset));
259 next_tree=proto_item_add_subtree(item, ett_ber_SEQUENCE);
261 offset=dissect_unknown_ber(pinfo, tvb, offset, next_tree);
263 case BER_UNI_TAG_NumericString:
264 offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_NumericString, NULL);
266 case BER_UNI_TAG_PrintableString:
267 offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_PrintableString, NULL);
269 case BER_UNI_TAG_IA5String:
270 offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_IA5String, NULL);
273 proto_tree_add_text(tree, tvb, offset, len, "BER: Error can not handle universal tag:%d",tag);
278 item=proto_tree_add_text(tree, tvb, offset, len, "[%d] (len:%d bytes) ",tag,len);
280 next_tree=proto_item_add_subtree(item, ett_ber_SEQUENCE);
282 offset=dissect_unknown_ber(pinfo, tvb, offset, next_tree);
285 proto_tree_add_text(tree, tvb, offset, len, "BER: Error can not handle class:%d (0x%02x)",class,tvb_get_guint8(tvb, start_offset));
286 /* some printout here? aborting dissection */
287 return tvb_length(tvb);
290 /* were there more data to eat? */
291 if(offset<(int)tvb_length(tvb)){
292 offset=dissect_unknown_ber(pinfo, tvb, offset, tree);
300 call_ber_oid_callback(const char *oid, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
304 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
305 if(!dissector_try_string(ber_oid_dissector_table, oid, next_tvb, pinfo, tree)){
306 proto_item *item=NULL;
307 proto_tree *next_tree=NULL;
309 item=proto_tree_add_text(tree, next_tvb, 0, tvb_length_remaining(tvb, offset), "BER: Dissector for OID:%s not implemented. Contact Ethereal developers if you want this supported", oid);
311 next_tree=proto_item_add_subtree(item, ett_ber_unknown);
313 dissect_unknown_ber(pinfo, next_tvb, 0, next_tree);
316 /*XXX until we change the #.REGISTER signature for _PDU()s
317 * into new_dissector_t we have to do this kludge with
318 * manually step past the content in the ANY type.
320 offset+=tvb_length_remaining(tvb, offset);
326 static int dissect_ber_sq_of(gboolean implicit_tag, gint32 type, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id);
328 /* 8.1 General rules for encoding */
330 /* 8.1.2 Identifier octets */
331 int get_ber_identifier(tvbuff_t *tvb, int offset, gint8 *class, gboolean *pc, gint32 *tag) {
337 id = tvb_get_guint8(tvb, offset);
340 printf ("BER ID=%02x", id);
343 tmp_class = (id>>6) & 0x03;
344 tmp_pc = (id>>5) & 0x01;
347 if (tmp_tag == 0x1F) {
349 while (tvb_length_remaining(tvb, offset) > 0) {
350 t = tvb_get_guint8(tvb, offset);
357 if (!(t & 0x80)) break;
374 int dissect_ber_identifier(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gint8 *class, gboolean *pc, gint32 *tag)
376 int old_offset = offset;
381 offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
383 if(show_internal_ber_fields){
384 proto_tree_add_uint(tree, hf_ber_id_class, tvb, old_offset, 1, tmp_class<<6);
385 proto_tree_add_boolean(tree, hf_ber_id_pc, tvb, old_offset, 1, (tmp_pc)?0x20:0x00);
387 proto_tree_add_uint(tree, hf_ber_id_uni_tag, tvb, old_offset, 1, tmp_tag);
388 if(tmp_class==BER_CLASS_UNI){
389 proto_tree_add_uint(tree, hf_ber_id_uni_tag_ext, tvb, old_offset + 1, offset - (old_offset + 1), tmp_tag);
391 proto_tree_add_uint(tree, hf_ber_id_tag_ext, tvb, old_offset + 1, offset - (old_offset + 1), tmp_tag);
394 if(tmp_class==BER_CLASS_UNI){
395 proto_tree_add_uint(tree, hf_ber_id_uni_tag, tvb, old_offset, 1, tmp_tag);
397 proto_tree_add_uint(tree, hf_ber_id_tag, tvb, old_offset, 1, tmp_tag);
412 /* this function gets the length octets of the BER TLV.
413 * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
415 /* 8.1.3 Length octets */
417 get_ber_length(proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind) {
422 int old_offset=offset;
423 int tmp_offset,s_offset;
430 oct = tvb_get_guint8(tvb, offset);
441 oct = tvb_get_guint8(tvb, offset);
443 tmp_length = (tmp_length<<8) + oct;
449 /* ok in here we can traverse the BER to find the length, this will fix most indefinite length issues */
450 /* Assumption here is that indefinite length is always used on constructed types*/
452 while ((tvb_reported_length_remaining(tvb,offset)>0) && ( tvb_get_guint8(tvb, offset) || tvb_get_guint8(tvb,offset+1)))
454 /* not an EOC at offset */
456 offset= get_ber_identifier(tvb, offset, &tclass, &tpc, &ttag);
457 offset= get_ber_length(tree,tvb,offset, &tmp_len, NULL);
458 tmp_length += tmp_len+(offset-s_offset); /* length + tag and length */
467 /* check that the length is sane */
468 if(tmp_length>(guint32)tvb_reported_length_remaining(tvb,offset)){
469 proto_tree_add_text(tree, tvb, old_offset, offset-old_offset, "BER: Error length:%u longer than tvb_reported_length_remaining:%d",tmp_length, tvb_reported_length_remaining(tvb, offset));
470 /* force the appropriate exception */
471 tvb_ensure_bytes_exist(tvb, offset, tmp_length);
472 /*tmp_length = (guint32)tvb_reported_length_remaining(tvb,offset);*/
476 *length = tmp_length;
483 /* this function dissects the length octets of the BER TLV.
484 * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
487 dissect_ber_length(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind)
489 int old_offset = offset;
493 offset = get_ber_length(tree, tvb, offset, &tmp_length, &tmp_ind);
495 if(show_internal_ber_fields){
497 proto_tree_add_text(tree, tvb, old_offset, 1, "Length: Indefinite length %d", tmp_length);
499 proto_tree_add_uint(tree, hf_ber_length, tvb, old_offset, offset - old_offset, tmp_length);
503 *length = tmp_length;
509 reassemble_octet_string(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 con_len, gboolean ind, tvbuff_t **out_tvb)
511 static GHashTable *octet_segment_table = NULL;
512 static GHashTable *octet_reassembled_table = NULL;
513 fragment_data *fd_head = NULL;
514 tvbuff_t *next_tvb = NULL;
515 tvbuff_t *reassembled_tvb = NULL;
517 int start_offset = offset;
518 gboolean fragment = TRUE;
519 gboolean firstFragment = TRUE;
521 if(octet_segment_table == NULL) {
522 /* I assume I can take this late binding approach */
523 fragment_table_init(&octet_segment_table);
524 reassembled_table_init(&octet_reassembled_table);
528 /* so we need to consume octet strings for the given length */
530 /* not sure we need this */
531 pinfo->fragmented = TRUE;
535 offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, offset, hf_ber_unknown_OCTETSTRING, &next_tvb);
537 if (next_tvb == NULL) {
538 /* Assume that we have a malformed packet. */
539 THROW(ReportedBoundsError);
543 /* this was indefinite length - so check for EOC */
545 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)) {
552 if((guint32)(offset - start_offset) >= con_len)
556 if(!fragment && firstFragment) {
557 /* there is only one fragment (I'm sure there's a reason it was constructed) */
558 /* anyway, we can get out of here */
559 reassembled_tvb = next_tvb;
564 if (tvb_length(next_tvb) < 1) {
565 /* Don't cause an assertion in the reassembly code. */
566 THROW(ReportedBoundsError);
568 fd_head = fragment_add_seq_next(next_tvb, 0, pinfo, dst_ref,
570 octet_reassembled_table,
571 tvb_length(next_tvb),
574 firstFragment = FALSE;
579 reassembled_tvb = tvb_new_real_data(fd_head->data,
583 tvb_set_child_real_data_tvbuff(next_tvb, reassembled_tvb);
585 /* not sure I really want to do this here - should be nearer the application where we can give it a better name*/
586 add_new_data_source(pinfo, reassembled_tvb, "Reassembled OCTET STRING");
592 *out_tvb = reassembled_tvb;
594 /* again - not sure we need this */
595 pinfo->fragmented = FALSE;
601 /* 8.7 Encoding of an octetstring value */
603 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) {
615 header_field_info *hfinfo;
617 hfinfo = proto_registrar_get_nth(hf_id);
622 if(tvb_length_remaining(tvb,offset)>3){
623 printf("OCTET STRING dissect_ber_octet string(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
625 printf("OCTET STRING dissect_ber_octet_string(%s) entered\n",name);
631 /* read header and len for the octet string */
632 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
633 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
634 end_offset=offset+len;
636 /* sanity check: we only handle Constructed Universal Sequences */
637 if ((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
639 if( (class!=BER_CLASS_UNI)
640 ||((tag<BER_UNI_TAG_NumericString)&&(tag!=BER_UNI_TAG_OCTETSTRING)&&(tag!=BER_UNI_TAG_UTF8String)) ){
641 tvb_ensure_bytes_exist(tvb, offset-2, 2);
642 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);
648 /* implicit tag so just trust the length of the tvb */
650 len=tvb_length_remaining(tvb,offset);
651 end_offset=offset+len;
654 ber_last_created_item = NULL;
657 end_offset = reassemble_octet_string(pinfo, tree, tvb, offset, len, ind, out_tvb);
660 gint length_remaining = tvb_length_remaining(tvb, offset);
662 if(len<=(guint32)length_remaining){
663 length_remaining=len;
666 it = proto_tree_add_item(tree, hf_id, tvb, offset, length_remaining, FALSE);
667 ber_last_created_item = it;
671 pi=proto_tree_add_text(tree, tvb, offset, len, "Unknown OctetString: Length: 0x%02x, Value: 0x", len);
674 proto_item_append_text(pi,"%02x",tvb_get_guint8(tvb, offset));
681 *out_tvb = tvb_new_subset(tvb, offset, length_remaining, len);
687 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)
689 tvbuff_t *out_tvb = NULL;
691 offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_id, (func)?&out_tvb:NULL);
692 if (func && out_tvb && (tvb_length(out_tvb)>0)) {
694 tree = proto_item_add_subtree(ber_last_created_item, ett_ber_octet_string);
695 func(pinfo, tree, out_tvb, 0);
700 /* 8.8 Encoding of a null value */
702 dissect_ber_null(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id) {
711 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
713 (!implicit_tag && ((class != BER_CLASS_UNI) || (tag != BER_UNI_TAG_NULL)))) {
714 proto_tree_add_text(tree, tvb, offset_old, offset - offset_old, "BER Error: NULL expected but Class:%d(%s) PC:%d Tag:%d was unexpected", class,val_to_str(class,ber_class_codes,"Unknown"), pc, tag);
718 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
720 proto_tree_add_text(tree, tvb, offset_old, offset - offset_old, "BER Error: NULL expect zero length but Length=%d", len);
721 proto_tree_add_text(tree, tvb, offset, len, "BER Error: unexpected data in NULL type");
726 proto_tree_add_item(tree, hf_id, tvb, offset, 0, FALSE);
731 dissect_ber_integer(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, guint32 *value)
744 header_field_info *hfinfo;
746 hfinfo = proto_registrar_get_nth(hf_id);
751 if(tvb_length_remaining(tvb,offset)>3){
752 printf("INTEGERnew dissect_ber_integer(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
754 printf("INTEGERnew dissect_ber_integer(%s) entered implicit_tag:%d \n",name,implicit_tag);
761 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
762 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
764 len=tvb_length_remaining(tvb, offset);
767 /* ok, we cant handle >4 byte integers so lets fake them */
769 * XXX - should we handle large integers with a bignum type,
770 * and an FT_BIGNUM field type? This code currently has trouble
771 * with, for example, INTEGER (0..4294967295), as a value in the
772 * range 2147483648 to 0..4294967295 is represented as 5 bytes.
774 * There should at least be a way to indicate that the value we
775 * returned didn't fit in a 32-bit signed integer, so our caller
776 * can, if they didn't supply an hf_id, indicate that the value
780 header_field_info *hfinfo;
781 proto_item *pi = NULL;
784 hfinfo = proto_registrar_get_nth(hf_id);
785 pi=proto_tree_add_text(tree, tvb, offset, len, "%s : 0x", hfinfo->name);
789 proto_item_append_text(pi,"%02x",tvb_get_guint8(tvb, offset));
798 header_field_info *hfinfo;
802 /* extend sign bit */
803 val64 = (gint8)tvb_get_guint8(tvb, offset);
807 val64=(val64<<8)|tvb_get_guint8(tvb, offset);
811 hfinfo = proto_registrar_get_nth(hf_id);
812 proto_tree_add_text(tree, tvb, offset-len, len, "%s: %" PRIu64, hfinfo->name, val64);
819 /* extend sign bit */
820 val = (gint8)tvb_get_guint8(tvb, offset);
824 val=(val<<8)|tvb_get_guint8(tvb, offset);
828 ber_last_created_item=NULL;
832 if(len < 1 || len > 4) {
833 proto_tree_add_text(tree, tvb, offset-len, len, "Can't handle integer length: %u", len);
835 ber_last_created_item=proto_tree_add_item(tree, hf_id, tvb, offset-len, len, FALSE);
847 dissect_ber_boolean(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
854 header_field_info *hfi;
857 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
858 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
859 /*if(class!=BER_CLASS_UNI)*/
861 /* nothing to do here, yet */
864 val=tvb_get_guint8(tvb, offset);
867 ber_last_created_item=NULL;
870 hfi = proto_registrar_get_nth(hf_id);
871 if(hfi->type == FT_BOOLEAN)
872 ber_last_created_item=proto_tree_add_boolean(tree, hf_id, tvb, offset-1, 1, val);
874 ber_last_created_item=proto_tree_add_uint(tree, hf_id, tvb, offset-1, 1, val?1:0);
884 /* this function dissects a BER sequence
886 int dissect_ber_sequence(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
888 gboolean pc, ind = 0, ind_field;
891 proto_tree *tree = parent_tree;
892 proto_item *item = NULL;
893 int end_offset, s_offset;
894 gint length_remaining;
900 header_field_info *hfinfo;
902 hfinfo = proto_registrar_get_nth(hf_id);
907 if(tvb_length_remaining(tvb,offset)>3){
908 printf("SEQUENCE dissect_ber_sequence(%s) entered offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
910 printf("SEQUENCE dissect_ber_sequence(%s) entered\n",name);
915 /* first we must read the sequence header */
916 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
917 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
919 /* Fixed the length is correctly returned from dissect ber_length
920 end_offset = tvb_length(tvb);*/
921 end_offset = offset + len -2;
923 end_offset = offset + len;
926 /* sanity check: we only handle Constructed Universal Sequences */
927 if((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
929 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
930 ||(tag!=BER_UNI_TAG_SEQUENCE)))) {
931 tvb_ensure_bytes_exist(tvb, offset-2, 2);
932 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Sequence expected but Class:%d(%s) PC:%d Tag:%d was unexpected", class,val_to_str(class,ber_class_codes,"Unknown"), pc, tag);
936 /* was implicit tag so just use the length of the tvb */
937 len=tvb_length_remaining(tvb,offset);
938 end_offset=offset+len;
944 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
945 tree = proto_item_add_subtree(item, ett_id);
949 /* loop over all entries until we reach the end of the sequence */
950 while (offset < end_offset){
955 int hoffset, eoffset, count;
957 /*if(ind){ this sequence was of indefinite length, if this is implicit indefinite impossible maybe
958 but tcap dissector uses this to eat the tag length then pass into here... EOC still on there...*/
959 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){
960 if(show_internal_ber_fields){
961 proto_tree_add_text(tree, tvb, s_offset, offset+2, "ERROR WRONG SEQ EOC");
967 /* read header and len for next field */
968 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
969 offset = get_ber_length(tree, tvb, offset, &len, &ind_field);
970 eoffset = offset + len;
972 ber_sequence_try_again:
973 /* have we run out of known entries in the sequence ?*/
975 /* it was not, move to the enxt one and try again */
976 proto_tree_add_text(tree, tvb, offset, len, "BER Error: This field lies beyond the end of the known sequence definition.");
981 /* Verify that this one is the one we want.
982 * Skip check completely if class==ANY
983 * of if NOCHKTAG is set
985 /* XXX Bug in asn2eth,
986 * for scope [7] Scope OPTIONAL,
988 * { BER_CLASS_CON, 7, BER_FLAGS_OPTIONAL|BER_FLAGS_NOTCHKTAG, dissect_scope },
989 * and there should not be a NOTCHKTAG here
991 if( ((seq->class==BER_CLASS_CON)||(seq->class==BER_CLASS_APP)||(seq->class==BER_CLASS_PRI)) && (!(seq->flags&BER_FLAGS_NOOWNTAG)) ){
992 if( (seq->class!=BER_CLASS_ANY)
994 &&( (seq->class!=class)
995 ||(seq->tag!=tag) ) ){
996 /* it was not, move to the next one and try again */
997 if(seq->flags&BER_FLAGS_OPTIONAL){
998 /* well this one was optional so just skip to the next one and try again. */
1000 goto ber_sequence_try_again;
1002 if( seq->class == BER_CLASS_UNI){
1003 proto_tree_add_text(tree, tvb, offset, len,
1004 "BER Error: Wrong field in SEQUENCE expected class:%d (%s) tag:%d (%s) but found class:%d tag:%d",
1005 seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),
1006 seq->tag,val_to_str(seq->tag,ber_uni_tag_codes,"Unknown"),
1009 proto_tree_add_text(tree, tvb, offset, len,
1010 "BER Error: Wrong field in SEQUENCE expected class:%d (%s) tag:%d but found class:%d tag:%d",
1011 seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),
1012 seq->tag,class,tag);
1018 } else if(!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
1019 if( (seq->class!=BER_CLASS_ANY)
1021 &&( (seq->class!=class)
1022 ||(seq->tag!=tag) ) ){
1023 /* it was not, move to the enxt one and try again */
1024 if(seq->flags&BER_FLAGS_OPTIONAL){
1025 /* well this one was optional so just skip to the next one and try again. */
1027 goto ber_sequence_try_again;
1030 if( seq->class == BER_CLASS_UNI){
1031 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field in sequence expected class:%d (%s) tag:%d(%s) but found class:%d(%s) tag:%d",seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),seq->tag,val_to_str(seq->tag,ber_uni_tag_codes,"Unknown"),class,val_to_str(class,ber_class_codes,"Unknown"),tag);
1033 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field in sequence expected class:%d (%s) tag:%d but found class:%d(%s) tag:%d",seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),seq->tag,class,val_to_str(class,ber_class_codes,"Unknown"),tag);
1041 if(!(seq->flags & BER_FLAGS_NOOWNTAG) ) {
1042 /* dissect header and len for field */
1043 hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
1044 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1045 length_remaining=tvb_length_remaining(tvb, hoffset);
1046 if (length_remaining>eoffset-hoffset-(2*ind_field))
1047 length_remaining=eoffset-hoffset-(2*ind_field);
1048 next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset-(2*ind_field));
1051 length_remaining=tvb_length_remaining(tvb, hoffset);
1052 if (length_remaining>eoffset-hoffset)
1053 length_remaining=eoffset-hoffset;
1054 next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset);
1057 /* call the dissector for this field */
1058 /*if ((eoffset-hoffset)>length_remaining) {*/
1059 /* If the field is indefinite (i.e. we dont know the
1060 * length) of if the tvb is short, then just
1061 * give it all of the tvb and hope for the best.
1063 /*next_tvb = tvb_new_subset(tvb, hoffset, -1, -1);*/
1071 header_field_info *hfinfo;
1073 hfinfo = proto_registrar_get_nth(hf_id);
1078 if(tvb_length_remaining(next_tvb,0)>3){
1079 printf("SEQUENCE dissect_ber_sequence(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(next_tvb,0),tvb_get_guint8(next_tvb,0),tvb_get_guint8(next_tvb,1),tvb_get_guint8(next_tvb,2));
1081 printf("SEQUENCE dissect_ber_sequence(%s) calling subdissector\n",name);
1085 if (next_tvb == NULL) {
1086 /* Assume that we have a malformed packet. */
1087 THROW(ReportedBoundsError);
1089 count=seq->func(pinfo, tree, next_tvb, 0);
1094 header_field_info *hfinfo;
1096 hfinfo = proto_registrar_get_nth(hf_id);
1101 printf("SEQUENCE dissect_ber_sequence(%s) subdissector ate %d bytes\n",name,count);
1104 /* if it was optional and no bytes were eaten and it was */
1105 /* supposed to (len<>0), just try again. */
1106 if((len!=0)&&(count==0)&&(seq->flags&BER_FLAGS_OPTIONAL)){
1108 goto ber_sequence_try_again;
1109 /* move the offset to the beginning of the next sequenced item */
1113 if(!(seq->flags & BER_FLAGS_NOOWNTAG) ) {
1114 /* if we stripped the tag and length we should also strip the EOC is ind_len */
1118 if(show_internal_ber_fields){
1119 proto_tree_add_text(tree, tvb, offset, count, "SEQ FIELD EOC");
1126 /* if we didnt end up at exactly offset, then we ate too many bytes */
1127 if(offset != end_offset) {
1128 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1129 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Sequence ate %d too many bytes", offset-end_offset);
1132 /* need to eat this EOC
1133 end_offset = tvb_length(tvb);*/
1135 if(show_internal_ber_fields){
1136 proto_tree_add_text(tree, tvb, end_offset-2,2 , "SEQ EOC");
1142 /* This function dissects a BER set
1144 int dissect_ber_set(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *set, gint hf_id, gint ett_id) {
1146 gboolean pc, ind = 0, ind_field;
1149 proto_tree *tree = parent_tree;
1150 proto_item *item = NULL;
1151 int end_offset, s_offset;
1152 gint length_remaining;
1154 const ber_sequence_t *cset = NULL;
1155 # define MAX_SET_ELEMENTS 32
1156 guint32 mandatory_fields = 0;
1158 gboolean first_pass;
1163 header_field_info *hfinfo;
1165 hfinfo = proto_registrar_get_nth(hf_id);
1170 if(tvb_length_remaining(tvb,offset)>3){
1171 printf("SET dissect_ber_set(%s) entered offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1173 printf("SET dissect_ber_set(%s) entered\n",name);
1179 /* first we must read the sequence header */
1180 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1181 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
1183 /* Fixed the length is correctly returned from dissect ber_length
1184 end_offset = tvb_length(tvb);*/
1185 end_offset = offset + len -2;
1187 end_offset = offset + len;
1190 /* sanity check: we only handle Constructed Universal Sets */
1191 if ((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
1193 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
1194 ||(tag!=BER_UNI_TAG_SET)))) {
1195 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1196 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: SET expected but Class:%d(%s) PC:%d Tag:%d was found", class,val_to_str(class,ber_class_codes,"Unknown"), pc, tag);
1200 /* was implicit tag so just use the length of the tvb */
1201 len=tvb_length_remaining(tvb,offset);
1202 end_offset=offset+len;
1205 /* create subtree */
1208 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
1209 tree = proto_item_add_subtree(item, ett_id);
1213 /* record the mandatory elements of the set so we can check we founf everything at the end
1214 we can only record 32 elements for now ... */
1215 for(set_idx = 0; (cset=&set[set_idx])->func && (set_idx < MAX_SET_ELEMENTS); set_idx++) {
1217 if(!(cset->flags & BER_FLAGS_OPTIONAL))
1218 mandatory_fields |= 1 << set_idx;
1222 /* loop over all entries until we reach the end of the set */
1223 while (offset < end_offset){
1228 int hoffset, eoffset, count;
1230 /*if(ind){ this sequence was of indefinite length, if this is implicit indefinite impossible maybe
1231 but tcap dissector uses this to eat the tag length then pass into here... EOC still on there...*/
1233 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){
1234 if(show_internal_ber_fields){
1235 proto_tree_add_text(tree, tvb, s_offset, offset+2, "SEQ EOC");
1241 /* read header and len for next field */
1242 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1243 offset = get_ber_length(tree, tvb, offset, &len, &ind_field);
1244 eoffset = offset + len;
1246 /* Look through the Set to see if this class/id exists and
1247 * hasn't been seen before
1248 * Skip check completely if class==ANY
1249 * of if NOCHKTAG is set
1253 for(first_pass=TRUE, cset = set, set_idx = 0; cset->func || first_pass; cset++, set_idx++) {
1255 /* we reset for a second pass when we will look for choices */
1259 cset=set; /* reset to the beginning */
1263 if((first_pass && ((cset->class==class) && (cset->tag==tag))) ||
1264 (!first_pass && ((cset->class== BER_CLASS_ANY) && (cset->tag == -1))) ) /* choices */
1267 if (!(cset->flags & BER_FLAGS_NOOWNTAG) ) {
1268 /* dissect header and len for field */
1269 hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
1270 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1271 length_remaining=tvb_length_remaining(tvb, hoffset);
1272 if (length_remaining>eoffset-hoffset-(2*ind_field))
1273 length_remaining=eoffset-hoffset-(2*ind_field);
1274 next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset-(2*ind_field));
1277 length_remaining=tvb_length_remaining(tvb, hoffset);
1278 if (length_remaining>eoffset-hoffset)
1279 length_remaining=eoffset-hoffset;
1280 next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset);
1284 /* call the dissector for this field */
1285 /*if ((eoffset-hoffset)>length_remaining) {*/
1286 /* If the field is indefinite (i.e. we dont know the
1287 * length) of if the tvb is short, then just
1288 * give it all of the tvb and hope for the best.
1290 /*next_tvb = tvb_new_subset(tvb, hoffset, -1, -1);*/
1298 header_field_info *hfinfo;
1300 hfinfo = proto_registrar_get_nth(hf_id);
1305 if(tvb_length_remaining(next_tvb,0)>3){
1306 printf("SET dissect_ber_set(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(next_tvb,0),tvb_get_guint8(next_tvb,0),tvb_get_guint8(next_tvb,1),tvb_get_guint8(next_tvb,2));
1308 printf("SET dissect_ber_set(%s) calling subdissector\n",name);
1312 if (next_tvb == NULL) {
1313 /* Assume that we have a malformed packet. */
1314 THROW(ReportedBoundsError);
1316 count=cset->func(pinfo, tree, next_tvb, 0);
1320 if(set_idx < MAX_SET_ELEMENTS)
1321 mandatory_fields &= ~(1 << set_idx);
1325 if(!(cset->flags & BER_FLAGS_NOOWNTAG) ) {
1326 /* if we stripped the tag and length we should also strip the EOC is ind_len */
1329 if(show_internal_ber_fields){
1330 proto_tree_add_text(tree, tvb, offset, count, "SET FIELD EOC");
1340 /* we didn't find a match */
1341 proto_tree_add_text(tree, tvb, hoffset, len, "BER Error: Unknown field in SET class:%d(%s) tag:%d",class,val_to_str(class,ber_class_codes,"Unknown"),tag);
1346 if(mandatory_fields) {
1348 /* OK - we didn't find some of the elements we expected */
1350 for(set_idx = 0; (cset = &set[set_idx])->func && (set_idx < MAX_SET_ELEMENTS); set_idx++) {
1352 if(mandatory_fields & (1 << set_idx)) {
1354 /* here is something we should have seen - but didn't! */
1355 proto_tree_add_text(tree, tvb, offset, len,
1356 "BER Error: Missing field in SET class:%d (%s) tag:%d expected",
1357 cset->class,val_to_str(cset->class,ber_class_codes,"Unknown"),
1365 /* if we didnt end up at exactly offset, then we ate too many bytes */
1366 if (offset != end_offset) {
1367 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1368 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: SET ate %d too many bytes", offset-end_offset);
1372 /* need to eat this EOC
1373 end_offset = tvb_length(tvb);*/
1375 if(show_internal_ber_fields){
1376 proto_tree_add_text(tree, tvb, end_offset-2,2 , "SET EOC");
1385 /* this function dissects a BER choice
1386 * If we did not find a matching choice, just return offset unchanged
1387 * in case it was a CHOICE { } OPTIONAL
1390 dissect_ber_choice(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_choice_t *choice, gint hf_id, gint ett_id, gint *branch_taken)
1396 const ber_choice_t *ch;
1397 proto_tree *tree=parent_tree;
1398 proto_item *item=NULL;
1399 int end_offset, start_offset, count;
1400 int hoffset = offset;
1401 header_field_info *hfinfo;
1402 gint length, length_remaining;
1404 gboolean first_pass;
1409 header_field_info *hfinfo;
1411 hfinfo = proto_registrar_get_nth(hf_id);
1416 if(tvb_length_remaining(tvb,offset)>3){
1417 printf("CHOICE dissect_ber_choice(%s) entered offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1419 printf("CHOICE dissect_ber_choice(%s) entered len:%d\n",name,tvb_length_remaining(tvb,offset));
1423 start_offset=offset;
1425 /* read header and len for choice field */
1426 offset=get_ber_identifier(tvb, offset, &class, &pc, &tag);
1427 offset=get_ber_length(parent_tree, tvb, offset, &len, &ind);
1428 end_offset = offset + len ;
1430 /* Some sanity checks.
1431 * The hf field passed to us MUST be an integer type
1434 hfinfo=proto_registrar_get_nth(hf_id);
1435 switch(hfinfo->type) {
1442 proto_tree_add_text(tree, tvb, offset, len,"dissect_ber_choice(): Was passed a HF field that was not integer type : %s",hfinfo->abbrev);
1443 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);
1450 /* loop over all entries until we find the right choice or
1451 run out of entries */
1457 while(ch->func || first_pass){
1461 /* we reset for a second pass when we will look for choices */
1464 ch = choice; /* reset to the beginning */
1472 printf("CHOICE testing potential subdissector class:%d:(expected)%d tag:%d:(expected)%d flags:%d\n",class,ch->class,tag,ch->tag,ch->flags);
1474 if( (first_pass && (((ch->class==class)&&(ch->tag==tag))
1475 || ((ch->class==class)&&(ch->tag==-1)&&(ch->flags&BER_FLAGS_NOOWNTAG)))) ||
1476 (!first_pass && (((ch->class == BER_CLASS_ANY) && (ch->tag == -1)))) /* we failed on the first pass so now try any choices */
1478 if(!(ch->flags & BER_FLAGS_NOOWNTAG)){
1479 /* dissect header and len for field */
1480 hoffset = dissect_ber_identifier(pinfo, tree, tvb, start_offset, NULL, NULL, NULL);
1481 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1482 start_offset=hoffset;
1494 length = end_offset- hoffset;
1495 /* create subtree */
1498 item = proto_tree_add_uint(parent_tree, hf_id, tvb, hoffset, end_offset - hoffset, ch->value);
1499 tree = proto_item_add_subtree(item, ett_id);
1502 length_remaining=tvb_length_remaining(tvb, hoffset);
1503 if(length_remaining>length)
1504 length_remaining=length;
1507 next_tvb=tvb_new_subset(tvb, hoffset, length_remaining, length);
1509 next_tvb = tvb; /* we didn't make selection on this class/tag so pass it on */
1514 header_field_info *hfinfo;
1516 hfinfo = proto_registrar_get_nth(hf_id);
1521 if(tvb_length_remaining(next_tvb,0)>3){
1522 printf("CHOICE dissect_ber_choice(%s) calling subdissector start_offset:%d offset:%d len:%d %02x:%02x:%02x\n",name,start_offset,offset,tvb_length_remaining(next_tvb,0),tvb_get_guint8(next_tvb,0),tvb_get_guint8(next_tvb,1),tvb_get_guint8(next_tvb,2));
1524 printf("CHOICE dissect_ber_choice(%s) calling subdissector len:%d\n",name,tvb_length(next_tvb));
1528 if (next_tvb == NULL) {
1529 /* Assume that we have a malformed packet. */
1530 THROW(ReportedBoundsError);
1532 count=ch->func(pinfo, tree, next_tvb, 0);
1536 header_field_info *hfinfo;
1538 hfinfo = proto_registrar_get_nth(hf_id);
1543 printf("CHOICE dissect_ber_choice(%s) subdissector ate %d bytes\n",name,count);
1546 if((count==0)&&(((ch->class==class)&&(ch->tag==-1)&&(ch->flags&BER_FLAGS_NOOWNTAG)) || !first_pass)){
1547 /* wrong one, break and try again */
1549 goto choice_try_again;
1551 if(!(ch->flags & BER_FLAGS_NOOWNTAG)){
1554 /* we are traversing a indfinite length choice where we did not pass the tag length */
1555 /* we need to eat the EOC */
1556 if(show_internal_ber_fields){
1557 proto_tree_add_text(tree, tvb, start_offset, count+2, "CHOICE EOC");
1567 /* none of the branches were taken so set the param
1573 /*XXX here we should have another flag to the CHOICE to distinguish
1574 * between teh case when we know it is a mandatory or if the CHOICE is optional == no arm matched */
1576 /* oops no more entries and we still havent found
1579 proto_tree_add_text(tree, tvb, offset, len, "BER Error: This choice field was not found.");
1584 return start_offset;
1588 /* this function dissects a BER GeneralString
1591 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, int name_len)
1609 /* first we must read the GeneralString header */
1610 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1611 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
1612 end_offset=offset+len;
1614 /* sanity check: we only handle Universal GeneralString*/
1615 if( (class!=BER_CLASS_UNI)
1616 ||(tag!=BER_UNI_TAG_GENSTR) ){
1617 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1618 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);
1622 if(len>=(max_len-1)){
1626 tvb_memcpy(tvb, str, offset, len);
1630 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
1636 int dissect_ber_restricted_string(gboolean implicit_tag, gint32 type, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, tvbuff_t **out_tvb) {
1642 int hoffset = offset;
1647 header_field_info *hfinfo;
1649 hfinfo = proto_registrar_get_nth(hf_id);
1654 if(tvb_length_remaining(tvb,offset)>3){
1655 printf("RESTRICTED STRING dissect_ber_octet string(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1657 printf("RESTRICTED STRING dissect_ber_octet_string(%s) entered\n",name);
1663 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1664 offset = get_ber_length(tree, tvb, offset, &len, NULL);
1665 eoffset = offset + len;
1668 if( (class!=BER_CLASS_UNI)
1670 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1671 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);
1677 return dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, hoffset, hf_id, out_tvb);
1681 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, guint name_len)
1683 tvbuff_t *out_tvb = NULL;
1685 offset = dissect_ber_restricted_string(FALSE, BER_UNI_TAG_GeneralString, pinfo, tree, tvb, offset, hf_id, (name_string)?&out_tvb:NULL);
1688 if(out_tvb && tvb_length(out_tvb) >= name_len) {
1689 tvb_memcpy(out_tvb, name_string, 0, name_len-1);
1690 name_string[name_len-1] = '\0';
1691 } else if(out_tvb) {
1692 tvb_memcpy(out_tvb, name_string, 0, -1);
1693 name_string[tvb_length(out_tvb)] = '\0';
1700 /* 8.19 Encoding of an object identifier value */
1701 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) {
1710 str=ep_alloc(MAX_OID_STR_LEN);
1714 header_field_info *hfinfo;
1716 hfinfo = proto_registrar_get_nth(hf_id);
1721 if(tvb_length_remaining(tvb,offset)>3){
1722 printf("OBJECT IDENTIFIER dissect_ber_object_identifier(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1724 printf("OBJECT IDENTIFIER dissect_ber_object_identifier(%s) entered\n",name);
1730 value_string[0] = '\0';
1735 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1736 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
1737 eoffset = offset + len;
1738 if( (class!=BER_CLASS_UNI)
1739 ||(tag != BER_UNI_TAG_OID) ){
1740 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1741 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);
1745 len=tvb_length_remaining(tvb,offset);
1749 oid_to_str_buf(tvb_get_ptr(tvb, offset, len), len, str, MAX_OID_STR_LEN);
1753 item=proto_tree_add_string(tree, hf_id, tvb, offset - len, len, str);
1754 /* see if we know the name of this oid */
1756 name=g_hash_table_lookup(oid_table, str);
1758 proto_item_append_text(item, " (%s)", name);
1764 strcpy(value_string, str);
1770 static int dissect_ber_sq_of(gboolean implicit_tag, gint32 type, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
1772 gboolean pc, ind = FALSE, ind_field;
1776 proto_tree *tree = parent_tree;
1777 proto_item *item = NULL;
1778 int cnt, hoffset, end_offset;
1779 header_field_info *hfi;
1784 header_field_info *hfinfo;
1786 hfinfo = proto_registrar_get_nth(hf_id);
1791 if(tvb_length_remaining(tvb,offset)>3){
1792 printf("SQ OF dissect_ber_sq_of(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1794 printf("SQ OF dissect_ber_sq_of(%s) entered\n",name);
1800 /* first we must read the sequence header */
1801 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1802 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
1804 /* if the length is indefinite we dont really know (yet) where the
1805 * object ends so assume it spans the rest of the tvb for now.
1807 end_offset = offset + len;
1809 end_offset = offset + len;
1812 /* sanity check: we only handle Constructed Universal Sequences */
1813 if((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
1815 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
1817 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1818 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: %s Of expected but Class:%d PC:%d Tag:%d was unexpected",
1819 (type==BER_UNI_TAG_SEQUENCE)?"Set":"Sequence", class, pc, tag);
1823 /* the tvb length should be correct now nope we could be comming from an implicit choice or sequence, thus we
1824 read the items we match and return the length*/
1825 len=tvb_length_remaining(tvb,offset);
1826 end_offset = offset + len;
1829 /* count number of items */
1832 /* only count the number of items IFF we have the full blob,
1833 * else this will just generate a [short frame] before we even start
1834 * dissecting a single item.
1836 /* XXX Do we really need to count them at all ? ronnie */
1837 if(tvb_length_remaining(tvb, offset)==tvb_reported_length_remaining(tvb, offset)){
1838 while (offset < end_offset){
1841 if(ind){ /* this sequence of was of indefinite length, so check for EOC */
1842 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){
1847 /* read header and len for next field */
1848 offset = get_ber_identifier(tvb, offset, NULL, NULL, NULL);
1849 offset = get_ber_length(tree, tvb, offset, &len, NULL);
1850 /* best place to get real length of implicit sequence of or set of is here... */
1851 /* adjust end_offset if we find somthing that doesnt match */
1858 /* create subtree */
1860 hfi = proto_registrar_get_nth(hf_id);
1862 if(hfi->type == FT_NONE) {
1863 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
1864 proto_item_append_text(item, ":");
1866 item = proto_tree_add_uint(parent_tree, hf_id, tvb, offset, len, cnt);
1867 proto_item_append_text(item, (cnt==1)?" item":" items");
1869 tree = proto_item_add_subtree(item, ett_id);
1873 /* loop over all entries until we reach the end of the sequence */
1874 while (offset < end_offset){
1883 if(ind){ /*this sequence of was of indefinite length, so check for EOC */
1884 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){
1885 if(show_internal_ber_fields){
1886 proto_tree_add_text(tree, tvb, hoffset, end_offset-hoffset, "SEQ OF EOC");
1891 /* read header and len for next field */
1892 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1893 offset = get_ber_length(tree, tvb, offset, &len, &ind_field);
1895 /* if the length is indefinite we dont really know (yet) where the
1896 * object ends so assume it spans the rest of the tvb for now.
1898 eoffset = offset + len;
1900 eoffset = offset + len;
1903 /* verify that this one is the one we want */
1904 /* ahup if we are implicit then we return to the uper layer how much we have used */
1905 if(seq->class!=BER_CLASS_ANY){
1906 if((seq->class!=class)
1907 ||(seq->tag!=tag) ){
1908 if(!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
1909 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field in SQ OF");
1917 if(!(seq->flags & BER_FLAGS_NOOWNTAG) && !(seq->flags & BER_FLAGS_IMPLTAG)) {
1918 /* dissect header and len for field */
1919 hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
1920 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1923 /* call the dissector for this field */
1924 count=seq->func(pinfo, tree, tvb, hoffset)-hoffset;
1925 /* hold on if we are implicit and the result is zero, i.e. the item in the sequence of
1926 doesnt match the next item, thus this implicit sequence is over, return the number of bytes
1927 we have eaten to allow the possible upper sequence continue... */
1930 /* previous field was of indefinite length so we have
1931 * no choice but use whatever the subdissector told us
1932 * as size for the field.
1933 * not any more the length should be correct
1941 /* if we didnt end up at exactly offset, then we ate too many bytes */
1942 if(offset != end_offset) {
1943 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1944 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: %s Of ate %d too many bytes",
1945 (type==BER_UNI_TAG_SEQUENCE)?"Set":"Sequence", offset-end_offset);
1951 int dissect_ber_sequence_of(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
1952 return dissect_ber_sq_of(implicit_tag, BER_UNI_TAG_SEQUENCE, pinfo, parent_tree, tvb, offset, seq, hf_id, ett_id);
1955 int dissect_ber_set_of(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
1956 return dissect_ber_sq_of(implicit_tag, BER_UNI_TAG_SET, pinfo, parent_tree, tvb, offset, seq, hf_id, ett_id);
1960 dissect_ber_GeneralizedTime(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
1963 const guint8 *tmpstr;
1971 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1972 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
1973 end_offset=offset+len;
1975 /* sanity check. we only handle universal/generalized time */
1976 if( (class!=BER_CLASS_UNI)
1977 ||(tag!=BER_UNI_TAG_GeneralizedTime)){
1978 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1979 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);
1981 end_offset=offset+len;
1984 len=tvb_length_remaining(tvb,offset);
1985 end_offset=offset+len;
1989 tmpstr=tvb_get_ptr(tvb, offset, len);
1990 snprintf(str, 31, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s)",
1991 tmpstr, tmpstr+4, tmpstr+6, tmpstr+8,
1992 tmpstr+10, tmpstr+12, tmpstr+14);
1993 str[31]=0; /* just in case ... */
1996 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
2003 /* 8.6 Encoding of a bitstring value */
2004 int dissect_ber_bitstring(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const asn_namedbit *named_bits, gint hf_id, gint ett_id, tvbuff_t **out_tvb)
2010 guint8 pad=0, b0, b1, val;
2012 proto_item *item = NULL;
2013 proto_tree *tree = NULL;
2014 const asn_namedbit *nb;
2019 /* read header and len for the octet string */
2020 offset = dissect_ber_identifier(pinfo, parent_tree, tvb, offset, &class, &pc, &tag);
2021 offset = dissect_ber_length(pinfo, parent_tree, tvb, offset, &len, &ind);
2022 end_offset = offset + len;
2024 /* sanity check: we only handle Universal BitSrings */
2026 if( (class!=BER_CLASS_UNI)
2027 ||(tag!=BER_UNI_TAG_BITSTRING) ){
2028 tvb_ensure_bytes_exist(tvb, offset-2, 2);
2029 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);
2035 len=tvb_length_remaining(tvb,offset);
2036 end_offset=offset+len;
2039 ber_last_created_item = NULL;
2047 pad = tvb_get_guint8(tvb, offset);
2048 proto_tree_add_item(parent_tree, hf_ber_bitstring_padding, tvb, offset, 1, FALSE);
2052 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
2053 ber_last_created_item = item;
2055 tree = proto_item_add_subtree(item, ett_id);
2059 if(len<=(guint32)tvb_length_remaining(tvb, offset)){
2060 *out_tvb = tvb_new_subset(tvb, offset, len, len);
2062 *out_tvb = tvb_new_subset(tvb, offset, -1, -1);
2072 if(nb->bit < (8*len-pad)) {
2073 val = tvb_get_guint8(tvb, offset + nb->bit/8);
2074 val &= 0x80 >> (nb->bit%8);
2075 b0 = (nb->gb0 == -1) ? nb->bit/8 :
2076 ((guint32)nb->gb0)/8;
2077 b1 = (nb->gb1 == -1) ? nb->bit/8 :
2078 ((guint32)nb->gb1)/8;
2079 proto_tree_add_item(tree, *(nb->p_id), tvb, offset + b0, b1 - b0 + 1, FALSE);
2080 } else { /* 8.6.2.4 */
2082 proto_tree_add_boolean(tree, *(nb->p_id), tvb, offset + len, 0, 0x00);
2085 if(item && nb->tstr) {
2086 proto_item_append_text(item, "%s%s", sep, nb->tstr);
2091 if(item && nb->fstr) {
2092 proto_item_append_text(item, "%s%s", sep, nb->fstr);
2100 proto_item_append_text(item, ")");
2106 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)
2108 tvbuff_t *tmp_tvb = NULL;
2112 header_field_info *hfi;
2115 unsigned int i, tvb_len;
2117 offset = dissect_ber_bitstring(implicit_tag, pinfo, parent_tree, tvb, offset, NULL, hf_id, ett_id, &tmp_tvb);
2119 tree = proto_item_get_subtree(ber_last_created_item);
2120 if(bit_fields && tree && tmp_tvb) {
2121 /* tmp_tvb points to the actual bitstring (including any pad bits at the end.
2122 * note that this bitstring is not neccessarily always encoded as 4 bytes
2123 * so we have to read it byte by byte.
2126 tvb_len=tvb_length(tmp_tvb);
2130 val|=tvb_get_guint8(tmp_tvb,i);
2137 proto_tree_add_boolean(tree, **bf, tmp_tvb, 0, tvb_len, val);
2139 hfi = proto_registrar_get_nth(**bf);
2140 if(val & hfi->bitmask) {
2141 proto_item_append_text(ber_last_created_item, "%s%s", sep, hfi->name);
2149 proto_item_append_text(ber_last_created_item, ")");
2159 proto_register_ber(void)
2161 static hf_register_info hf[] = {
2162 { &hf_ber_id_class, {
2163 "Class", "ber.id.class", FT_UINT8, BASE_DEC,
2164 VALS(ber_class_codes), 0xc0, "Class of BER TLV Identifier", HFILL }},
2165 { &hf_ber_bitstring_padding, {
2166 "Padding", "ber.bitstring.padding", FT_UINT8, BASE_DEC,
2167 NULL, 0x0, "Number of unsused bits in the last octet of the bitstring", HFILL }},
2169 "P/C", "ber.id.pc", FT_BOOLEAN, 8,
2170 TFS(&ber_pc_codes), 0x20, "Primitive or Constructed BER encoding", HFILL }},
2171 { &hf_ber_id_uni_tag, {
2172 "Tag", "ber.id.uni_tag", FT_UINT8, BASE_DEC,
2173 VALS(ber_uni_tag_codes), 0x1f, "Universal tag type", HFILL }},
2174 { &hf_ber_id_uni_tag_ext, {
2175 "Tag", "ber.id.uni_tag", FT_UINT32, BASE_DEC,
2176 NULL, 0, "Universal tag type", HFILL }},
2178 "Tag", "ber.id.tag", FT_UINT8, BASE_DEC,
2179 NULL, 0x1f, "Tag value for non-Universal classes", HFILL }},
2180 { &hf_ber_id_tag_ext, {
2181 "Tag", "ber.id.tag", FT_UINT32, BASE_DEC,
2182 NULL, 0, "Tag value for non-Universal classes", HFILL }},
2184 "Length", "ber.length", FT_UINT32, BASE_DEC,
2185 NULL, 0, "Length of contents", HFILL }},
2186 { &hf_ber_unknown_OCTETSTRING, {
2187 "OCTETSTRING", "ber.unknown.OCTETSTRING", FT_BYTES, BASE_HEX,
2188 NULL, 0, "This is an unknown OCTETSTRING", HFILL }},
2189 { &hf_ber_unknown_OID, {
2190 "OID", "ber.unknown.OID", FT_STRING, BASE_NONE,
2191 NULL, 0, "This is an unknown Object Identifier", HFILL }},
2192 { &hf_ber_unknown_GraphicString, {
2193 "GRAPHICSTRING", "ber.unknown.GRAPHICSTRING", FT_STRING, BASE_HEX,
2194 NULL, 0, "This is an unknown GRAPHICSTRING", HFILL }},
2196 { &hf_ber_unknown_NumericString, {
2197 "NumericString", "ber.unknown.NumericString", FT_STRING, BASE_NONE,
2198 NULL, 0, "This is an unknown NumericString", HFILL }},
2199 { &hf_ber_unknown_PrintableString, {
2200 "PrintableString", "ber.unknown.PrintableString", FT_STRING, BASE_NONE,
2201 NULL, 0, "This is an unknown PrintableString", HFILL }},
2202 { &hf_ber_unknown_IA5String, {
2203 "IA5String", "ber.unknown.IA5String", FT_STRING, BASE_NONE,
2204 NULL, 0, "This is an unknown IA5String", HFILL }},
2205 { &hf_ber_unknown_INTEGER, {
2206 "INTEGER", "ber.unknown.INTEGER", FT_UINT32, BASE_DEC,
2207 NULL, 0, "This is an unknown INTEGER", HFILL }},
2208 { &hf_ber_unknown_ENUMERATED, {
2209 "ENUMERATED", "ber.unknown.ENUMERATED", FT_UINT32, BASE_DEC,
2210 NULL, 0, "This is an unknown ENUMERATED", HFILL }},
2214 static gint *ett[] = {
2215 &ett_ber_octet_string,
2219 module_t *ber_module;
2221 proto_ber = proto_register_protocol("Basic Encoding Rules (ASN.1 X.690)", "BER", "ber");
2222 proto_register_field_array(proto_ber, hf, array_length(hf));
2223 proto_register_subtree_array(ett, array_length(ett));
2225 proto_set_cant_toggle(proto_ber);
2227 /* Register preferences */
2228 ber_module = prefs_register_protocol(proto_ber, NULL);
2229 prefs_register_bool_preference(ber_module, "show_internals",
2230 "Show internal BER encapsulation tokens",
2231 "Whether the dissector should also display internal"
2232 " ASN.1 BER details such as Identifier and Length fields", &show_internal_ber_fields);
2234 ber_oid_dissector_table = register_dissector_table("ber.oid", "BER OID Dissectors", FT_STRING, BASE_NONE);
2235 oid_table=g_hash_table_new(g_str_hash, g_str_equal);
2239 proto_reg_handoff_ber(void)
2241 register_ber_oid_name("2.1.1","joint-iso-itu-t(2) asn1(1) basic-encoding(1)");