The function pointer in a "per_choice_t" or a "per_sequence_t" is to a
[obnox/wireshark/wip.git] / packet-ber.c
1 /* packet-ber.c
2  * Helpers for ASN.1/BER dissection
3  * Ronnie Sahlberg (C) 2004
4  *
5  * $Id: packet-ber.c,v 1.9 2004/05/11 10:57:14 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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.
24  */
25
26 /* 
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)
30  * 
31  */ 
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40
41 #include <glib.h>
42
43 #include <epan/packet.h>
44
45 #include <epan/strutil.h>
46 #include "prefs.h"
47 #include "packet-ber.h"
48
49
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;
57
58 static gint ett_ber_octet_string = -1;
59
60 static gboolean show_internal_ber_fields = FALSE;
61
62 proto_item *ber_last_created_item=NULL;
63
64
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" },
70         { 0, NULL }
71 };
72
73 static const true_false_string ber_pc_codes = {
74         "Constructed Encoding",
75         "Primitive Encoding"
76 };
77
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" },
107         { 0, NULL }
108 };
109
110
111 proto_item *get_ber_last_created_item(void) {
112   return ber_last_created_item;
113 }
114
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);
116
117 /* 8.1 General rules for encoding */
118
119 /*  8.1.2 Identifier octets */
120 int get_ber_identifier(tvbuff_t *tvb, int offset, guint8 *class, gboolean *pc, guint32 *tag) {
121         guint8 id, t;
122         guint8 tmp_class;
123         gboolean tmp_pc;
124         guint32 tmp_tag;
125
126         id = tvb_get_guint8(tvb, offset);
127         offset += 1;
128         
129         /* 8.1.2.2 */
130         tmp_class = (id>>6) & 0x03;
131         tmp_pc = (id>>5) & 0x01;
132         tmp_tag = id&0x1F;
133         /* 8.1.2.4 */
134         if (tmp_tag == 0x1F) {
135                 tmp_tag = 0;
136                 while (tvb_length_remaining(tvb, offset) > 0) {
137                         t = tvb_get_guint8(tvb, offset);
138                         offset += 1;
139                         tmp_tag <<= 7;       
140                         tmp_tag |= t & 0x7F;
141                         if (t & 0x80) break;
142                 }
143         }
144
145         if (class)
146                 *class = tmp_class;
147         if (pc)
148                 *pc = tmp_pc;
149         if (tag)
150                 *tag = tmp_tag;
151
152         return offset;
153 }
154
155 int dissect_ber_identifier(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint8 *class, gboolean *pc, guint32 *tag) 
156 {
157         int old_offset = offset;
158         guint8 tmp_class;
159         gboolean tmp_pc;
160         guint32 tmp_tag;
161
162         offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
163         
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);
169                 } else {
170                         proto_tree_add_uint(tree, hf_ber_id_tag, tvb, old_offset, offset - old_offset, tmp_tag);
171                 }
172         }
173
174         if (class)
175                 *class = tmp_class;
176         if (pc)
177                 *pc = tmp_pc;
178         if (tag)
179                 *tag = tmp_tag;
180
181         return offset;
182 }
183
184 /* this function gets the length octets of the BER TLV.
185  * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
186  */
187 /* 8.1.3 Length octets */
188 int
189 get_ber_length(tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind) {
190         guint8 oct, len;
191         guint32 tmp_length;
192         gboolean tmp_ind;
193
194         tmp_length = 0;
195         tmp_ind = FALSE;
196
197         oct = tvb_get_guint8(tvb, offset);
198         offset += 1;
199         
200         if (!(oct&0x80)) {
201                 /* 8.1.3.4 */
202                 tmp_length = oct;
203         } else {
204                 len = oct & 0x7F;
205                 if (len) {
206                         /* 8.1.3.5 */
207                         while (len--) {
208                                 oct = tvb_get_guint8(tvb, offset);
209                                 offset++;
210                                 tmp_length = (tmp_length<<8) + oct;
211                         }
212                 } else {
213                         /* 8.1.3.6 */
214                         tmp_ind = TRUE;
215                         /* TO DO */
216                 }
217         }
218
219         if (length)
220                 *length = tmp_length;
221         if (ind)
222                 *ind = tmp_ind;
223
224         return offset;
225 }
226
227 /* this function dissects the length octets of the BER TLV.
228  * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
229  */
230 int
231 dissect_ber_length(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind)
232 {
233         int old_offset = offset;
234         guint32 tmp_length;
235         gboolean tmp_ind;
236
237         offset = get_ber_length(tvb, offset, &tmp_length, &tmp_ind);
238         
239         if(show_internal_ber_fields){
240                 proto_tree_add_uint(tree, hf_ber_length, tvb, old_offset, offset - old_offset, tmp_length);
241         }
242         if (length)
243                 *length = tmp_length;
244         if (ind)
245                 *ind = tmp_ind;
246         return offset;
247 }
248
249 /* 8.7 Encoding of an octetstring value */
250 int 
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) {
252         guint8 class;
253         gboolean pc, ind;
254         guint32 tag;
255         guint32 len;
256         int end_offset;
257         proto_item *it;
258
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;
263
264         /* sanity check: we only handle Constructed Universal Sequences */
265         if (!implicit_tag) {
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);
269                         return end_offset;
270                 }
271         }
272
273         ber_last_created_item = NULL;
274         if (pc) {
275                 /* constructed */
276                 /* TO DO */
277         } else {
278                 /* primitive */
279                 if (hf_id != -1) {
280                         it = proto_tree_add_item(tree, hf_id, tvb, offset, len, FALSE);
281                         ber_last_created_item = it;
282                 }
283                 if (out_tvb) {
284                         *out_tvb = tvb_new_subset(tvb, offset, len, len);
285                 }
286         }
287         return end_offset;
288 }
289
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)
291 {
292         tvbuff_t *out_tvb;
293
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)) {
296                 if (hf_id != -1)
297                         tree = proto_item_add_subtree(ber_last_created_item, ett_ber_octet_string);
298                 func(pinfo, tree, out_tvb, 0);
299         }
300         return offset;
301 }
302
303
304 int
305 dissect_ber_integer(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, guint32 *value)
306 {
307         guint8 class;
308         gboolean pc;
309         guint32 tag;
310         guint32 len;
311         gint32 val;
312         guint32 i;
313
314         offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
315         offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
316
317 /*      if(class!=BER_CLASS_UNI)*/
318         
319         val=0;
320         if (len > 0) {
321                 /* extend sign bit */
322                 val = (gint8)tvb_get_guint8(tvb, offset);
323                 offset++;
324         }
325         for(i=1;i<len;i++){
326                 val=(val<<8)|tvb_get_guint8(tvb, offset);
327                 offset++;
328         }
329
330         ber_last_created_item=NULL;
331
332         if(hf_id!=-1){  
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);
335         }
336         if(value){
337                 *value=val;
338         }
339
340         return offset;
341 }
342
343
344
345
346
347 int
348 dissect_ber_boolean(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
349 {
350         guint8 class;
351         gboolean pc;
352         guint32 tag;
353         guint32 len;
354         guint8 val;
355         header_field_info *hfi;
356
357         offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
358         offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
359
360 /*      if(class!=BER_CLASS_UNI)*/
361         
362         val=tvb_get_guint8(tvb, offset);
363         offset+=1;
364
365         ber_last_created_item=NULL;
366
367         if(hf_id!=-1){
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);
371                 else
372                         ber_last_created_item=proto_tree_add_uint(tree, hf_id, tvb, offset-1, 1, val?1:0);
373         }
374
375         return offset;
376 }
377
378
379
380
381
382 /* this function dissects a BER sequence 
383  */
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) {
385         guint8 class;
386         gboolean pc, ind;
387         guint32 tag;
388         guint32 len;
389         proto_tree *tree = parent_tree;
390         proto_item *item = NULL;
391         int end_offset;
392
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;
397
398         /* sanity check: we only handle Constructed Universal Sequences */
399         if ((!pc)
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);
403                 return end_offset;
404         }
405
406         /* create subtree */
407         if (hf_id != -1) {
408                 if(parent_tree){
409                         item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
410                         tree = proto_item_add_subtree(item, ett_id);
411                 }
412         }
413
414         /* loop over all entries until we reach the end of the sequence */
415         while (offset < end_offset){
416                 guint8 class;
417                 gboolean pc;
418                 guint32 tag;
419                 guint32 len;
420                 int hoffset, eoffset;
421
422                 hoffset = offset;
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;
427
428 ber_sequence_try_again:
429                 /* have we run out of known entries in the sequence ?*/
430                 if (!seq->func) {
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.");
433                         offset = eoffset;
434                         continue;
435                 }
436
437                 /* verify that this one is the one we want */
438                 if( (seq->class!=class)
439                   ||(seq->tag!=tag) ){
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. */
443                                 seq++;
444                                 goto ber_sequence_try_again;
445                         }
446                         if (!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
447                                 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field");
448                                 seq++;
449                                 offset=eoffset;
450                                 continue;
451                         }
452                 }
453
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);
458                 }
459                 
460                 /* call the dissector for this field */
461                 seq->func(pinfo, tree, tvb, hoffset);
462
463                 seq++;
464                 offset = eoffset;
465         }
466
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);
470         }
471
472         return end_offset;
473 }
474
475
476
477 /* this function dissects a BER choice 
478  */
479 int
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)
481 {
482         guint8 class;
483         gboolean pc;
484         guint32 tag;
485         guint32 len;
486         const ber_choice *ch;
487         proto_tree *tree=parent_tree;
488         proto_item *item=NULL;
489         int end_offset;
490         int hoffset = offset;
491
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;
496
497         /* loop over all entries until we find the right choice or 
498            run out of entries */
499         ch = choice;
500         while(ch->func){
501                 if( (ch->class==class)
502                   &&(ch->tag==tag) ){
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);
507                         }
508                         /* create subtree */
509                         if(hf_id!=-1){
510                                 if(parent_tree){
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);
513                                 }
514                         }
515                         offset=ch->func(pinfo, tree, tvb, hoffset);
516                         return end_offset;
517                         break;
518                 }
519                 ch++;
520         }
521         /* oops no more entries and we still havent found
522          * our guy :-(
523          */
524         proto_tree_add_text(tree, tvb, offset, len, "BER Error: This choice field was not found.");
525
526         return end_offset;
527 }
528
529 #if 0
530 /* this function dissects a BER GeneralString
531  */
532 int
533 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, int name_len)
534 {
535         guint8 class;
536         gboolean pc;
537         guint32 tag;
538         guint32 len;
539         int end_offset;
540         char str_arr[256];
541         guint32 max_len;
542         char *str;
543
544         str=str_arr;
545         max_len=255;
546         if(name_string){
547                 str=name_string;
548                 max_len=name_len;
549         }
550
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;
555
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);
560                 return end_offset;
561         }
562
563         if(len>=(max_len-1)){
564                 len=max_len-1;
565         }
566         
567         tvb_memcpy(tvb, str, offset, len);
568         str[len]=0;
569
570         if(hf_id!=-1){
571                 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
572         }
573
574         return end_offset;
575 }
576 #endif
577 int
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) {
579         guint8 class;
580         gboolean pc;
581         guint32 tag;
582         guint32 len;
583         int eoffset;
584         int hoffset = offset;
585
586         offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
587         offset = get_ber_length(tvb, offset, &len, NULL);
588         eoffset = offset + len;
589
590         /* sanity check */
591         if (!implicit_tag) {
592                 if( (class!=BER_CLASS_UNI)
593                   ||(tag != type) ){
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);
595                         return eoffset;
596                 }
597         }
598
599         /* 8.21.3 */
600         return dissect_ber_octet_string(TRUE, pinfo, tree, tvb, hoffset, hf_id, out_tvb);
601 }
602
603 int
604 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, guint name_len)
605 {
606         tvbuff_t *out_tvb;
607
608         offset = dissect_ber_restricted_string(FALSE, BER_UNI_TAG_GeneralString, pinfo, tree, tvb, offset, hf_id, (name_string)?&out_tvb:NULL);
609
610         if (name_string) {
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';
614                 } else {
615                         tvb_memcpy(out_tvb, name_string, 0, -1);
616                         name_string[tvb_length(out_tvb)] = '\0';
617                 }
618         }
619
620         return offset;
621 }
622
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) {
625         guint8 class;
626         gboolean pc;
627         guint32 tag;
628         guint32 i, len;
629         int eoffset;
630         guint8 byte;
631         guint32 value;
632         char str[256],*strp;
633
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;
637
638         if (value_string) {
639                 value_string[0] = '\0';
640         }
641
642         /* sanity check */
643         if (!implicit_tag) {
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);
647                         return eoffset;
648                 }
649         }
650
651         value=0;
652         for (i=0,strp=str; i<len; i++){
653                 byte = tvb_get_guint8(tvb, offset);
654                 offset++;
655
656                 if((strp-str)>200){
657             proto_tree_add_text(tree, tvb, offset, eoffset - offset, "BER Error: too long Object Identifier");
658                         return offset;
659                 }
660
661                 /* 8.19.4 */
662                 if (i == 0) {
663                         strp += sprintf(strp, "%d.%d", byte/40, byte%40);
664                         continue;
665                 }
666
667                 value = (value << 7) | (byte & 0x7F);
668                 if (byte & 0x80) {
669                         continue;
670                 }
671
672                 strp += sprintf(strp, ".%d", value);
673                 value = 0;
674         }
675         *strp = '\0';
676
677         if (hf_id != -1) {
678                 proto_tree_add_string(tree, hf_id, tvb, offset - len, len, str);
679         }
680
681         if (value_string) {
682                 strcpy(value_string, str);
683         }
684
685         return eoffset;
686 }
687
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) {
689         guint8 class;
690         gboolean pc, ind;
691         guint32 tag;
692         guint32 len;
693         proto_tree *tree = parent_tree;
694         proto_item *item = NULL;
695         int cnt, hoffset, end_offset;
696         header_field_info *hfi;
697
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;
702
703         /* sanity check: we only handle Constructed Universal Sequences */
704         if (!pc
705                 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
706                                                         ||(tag!=type)))) {
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);
709                 return end_offset;
710         }
711
712         /* count number of items */
713         cnt = 0;
714         hoffset = offset;
715         while (offset < end_offset){
716                 guint32 len;
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);
720                 offset += len;
721                 cnt++;
722         }
723         offset = hoffset;
724
725         /* create subtree */
726         if (hf_id != -1) {
727                 hfi = proto_registrar_get_nth(hf_id);
728                 if(parent_tree){
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, ":");
732                         } else {
733                                 item = proto_tree_add_uint(parent_tree, hf_id, tvb, offset, len, cnt);
734                                 proto_item_append_text(item, (cnt==1)?" item":" items");
735                         }
736                         tree = proto_item_add_subtree(item, ett_id);
737                 }
738         }
739
740         /* loop over all entries until we reach the end of the sequence */
741         while (offset < end_offset){
742                 guint8 class;
743                 gboolean pc;
744                 guint32 tag;
745                 guint32 len;
746                 int eoffset;
747                 int hoffset;
748
749                 hoffset = 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;
754
755                 /* verify that this one is the one we want */
756                 if ((seq->class!=class)
757                         ||(seq->tag!=tag) ){
758                         if (!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
759                                 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field");
760                                 offset = eoffset;
761                                 continue;
762                         }
763                 }
764
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);
769                 }
770                 
771                 /* call the dissector for this field */
772                 seq->func(pinfo, tree, tvb, hoffset);
773                 cnt++;
774                 offset = eoffset;
775         }
776
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);
781         }
782
783         return end_offset;
784 }
785
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);
788 }
789
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);
792 }
793
794 int 
795 dissect_ber_generalized_time(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
796 {
797         char str[32];
798         const guint8 *tmpstr;
799         guint8 class;
800         gboolean pc;
801         guint32 tag;
802         guint32 len;
803         int end_offset;
804
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;
808
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);
813                 return end_offset;
814                 end_offset=offset+len;
815         }
816
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 ... */
822                 
823         if(hf_id!=-1){
824                 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
825         }
826
827         offset+=len;
828         return offset;
829 }
830
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) 
833 {
834         guint8 class;
835         gboolean pc, ind;
836         guint32 tag;
837         guint32 len;
838         guint8 pad, b0, b1, val;
839         int end_offset;
840         proto_item *item = NULL;
841         proto_tree *tree = NULL;
842         asn_namedbit *nb;
843         char *sep;
844         gboolean term;
845
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;
850
851         /* sanity check: we only handle Universal BitSrings */
852         if (!implicit_tag) {
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);
856                         return end_offset;
857                 }
858         }
859
860         ber_last_created_item = NULL;
861
862         if (pc) {
863                 /* constructed */
864                 /* TO DO */
865         } else {
866                 /* primitive */
867                 /* padding */
868                 pad = tvb_get_guint8(tvb, offset);
869                 proto_tree_add_item(parent_tree, hf_ber_bitstring_padding, tvb, offset, 1, FALSE);
870                 offset++;
871                 len--;
872                 if ( hf_id != -1) {
873                         item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
874                         ber_last_created_item = item;
875                         if (ett_id != -1) {
876                                 tree = proto_item_add_subtree(item, ett_id);
877                         }
878                 }
879                 if (out_tvb) {
880                         *out_tvb = tvb_new_subset(tvb, offset, len, 8*len-pad);
881                 }
882         }
883
884         if (named_bits) {
885                 sep = " (";
886                 term = FALSE;
887                 nb = named_bits;
888                 while (nb->p_id) {
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 */
898                                 val = 0;
899                                 proto_tree_add_boolean(tree, *(nb->p_id), tvb, offset + len, 0, 0x00);
900                         }
901                         if (val) {
902                                 if (item && nb->tstr)
903                                         proto_item_append_text(item, "%s%s", sep, nb->tstr);
904                         } else {
905                                 if (item && nb->fstr)
906                                         proto_item_append_text(item, "%s%s", sep, nb->fstr);
907                         }
908                         nb++;
909                         sep = ", ";
910                         term = TRUE;
911                 }
912                 if (term)
913                         proto_item_append_text(item, ")");
914         }
915
916         return end_offset;
917 }
918
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) 
920 {
921         tvbuff_t *tmp_tvb;
922         proto_tree *tree;
923         guint32 val;
924         int **bf;
925         header_field_info *hfi;
926         char *sep;
927         gboolean term;
928
929         offset = dissect_ber_bitstring(implicit_tag, pinfo, parent_tree, tvb, offset, NULL, hf_id, ett_id, &tmp_tvb);
930         
931         tree = proto_item_get_subtree(ber_last_created_item);
932         if (bit_fields && tree) {
933                 val = tvb_get_ntohl(tmp_tvb, 0);
934                 bf = bit_fields;
935                 sep = " (";
936                 term = FALSE;
937                 while (*bf) {
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);
942                                 sep = ", ";
943                                 term = TRUE;
944                         }
945                         bf++;
946                 }
947                 if (term)
948                         proto_item_append_text(ber_last_created_item, ")");
949         }
950
951         if (out_tvb)
952                 *out_tvb = tmp_tvb;
953
954         return offset;
955 }
956
957 void
958 proto_register_ber(void)
959 {
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 }},
967         { &hf_ber_id_pc, {
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 }},
973         { &hf_ber_id_tag, {
974             "Tag", "ber.id.tag", FT_UINT32, BASE_DEC,
975             NULL, 0, "Tag value for non-Universal classes", HFILL }},
976         { &hf_ber_length, {
977             "Length", "ber.length", FT_UINT32, BASE_DEC,
978             NULL, 0, "Length of contents", HFILL }},
979
980     };
981
982     static gint *ett[] = {
983         &ett_ber_octet_string,
984     };
985     module_t *ber_module;
986
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));
990
991         proto_set_cant_toggle(proto_ber);
992
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);
999 }
1000
1001 void
1002 proto_reg_handoff_ber(void)
1003 {
1004 }