For each column, have both a buffer into which strings for that column
[obnox/wireshark/wip.git] / packet-kerberos.c
1 /* packet-kerberos.c
2  * Routines for Kerberos
3  * Wes Hardaker (c) 2000
4  * wjhardaker@ucdavis.edu
5  *
6  * $Id: packet-kerberos.c,v 1.6 2000/11/19 08:53:58 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Didier Jorand
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38
39 #include <glib.h>
40
41 #include "packet.h"
42
43 #include "strutil.h"
44
45 #include "asn1.h"
46
47 #include "packet-kerberos.h"
48
49 #define UDP_PORT_KERBEROS               88
50 #define TCP_PORT_KERBEROS               88
51
52 static gint ett_kerberos   = -1;
53 static gint ett_preauth    = -1;
54 static gint ett_addresses  = -1;
55 static gint ett_request    = -1;
56 static gint ett_princ      = -1;
57 static gint ett_ticket     = -1;
58 static gint ett_encrypted  = -1;
59 static gint ett_etype      = -1;
60 static gint proto_kerberos = -1;
61
62 #define KRB5_MSG_AS_REQ   0x0a
63 #define KRB5_MSG_AS_RESP  0x0b
64 #define KRB5_MSG_TGS_REQ  0x0c
65 #define KRB5_MSG_TGS_RESP 0x0d
66
67 #define KRB5_KDC_REQ_PVNO     0x01
68 #define KRB5_KDC_REQ_MSG_TYPE 0x02
69 #define KRB5_KDC_REQ_PADATA   0x03
70 #define KRB5_KDC_REQ_REQBODY  0x04
71
72 #define KRB5_KDC_RESP_PVNO     0x00
73 #define KRB5_KDC_RESP_MSG_TYPE 0x01
74 #define KRB5_KDC_RESP_PADATA   0x02
75 #define KRB5_KDC_RESP_CREALM   0x03
76 #define KRB5_KDC_RESP_CNAME    0x04
77 #define KRB5_KDC_RESP_TICKET   0x05
78 #define KRB5_KDC_RESP_ENC_PART 0x06
79
80 #define KRB5_BODY_KDC_OPTIONS            0x00
81 #define KRB5_BODY_CNAME                  0x01
82 #define KRB5_BODY_REALM                  0x02
83 #define KRB5_BODY_SNAME                  0x03
84 #define KRB5_BODY_FROM                   0x04
85 #define KRB5_BODY_TILL                   0x05
86 #define KRB5_BODY_RTIME                  0x06
87 #define KRB5_BODY_NONCE                  0x07
88 #define KRB5_BODY_ETYPE                  0x08
89 #define KRB5_BODY_ADDRESSES              0x09
90 #define KRB5_BODY_ENC_AUTHORIZATION_DATA 0x0a
91 #define KRB5_BODY_ADDITIONAL_TICKETS     0x0b
92
93 #define KRB5_ADDR_IPv4       0x02
94 #define KRB5_ADDR_CHAOS      0x05
95 #define KRB5_ADDR_XEROX      0x06
96 #define KRB5_ADDR_ISO        0x07
97 #define KRB5_ADDR_DECNET     0x0c
98 #define KRB5_ADDR_APPLETALK  0x10
99
100 #define KRB5_ETYPE_NULL                0
101 #define KRB5_ETYPE_DES_CBC_CRC         1
102 #define KRB5_ETYPE_DES_CBC_MD4         2
103 #define KRB5_ETYPE_DES_CBC_MD5         3
104
105 #define KRB5_PA_TGS_REQ       0x01
106 #define KRB5_PA_ENC_TIMESTAMP 0x02
107 #define KRB5_PA_PW_SALT       0x03
108
109 static const value_string krb5_preauthentication_types[] = {
110     { KRB5_PA_TGS_REQ      , "PA-TGS-REQ" },
111     { KRB5_PA_ENC_TIMESTAMP, "PA-ENC-TIMESTAMP" },
112     { KRB5_PA_PW_SALT      , "PA-PW-SALT" },
113 };
114
115 static const value_string krb5_encryption_types[] = {
116     { KRB5_ETYPE_NULL           , "NULL" },
117     { KRB5_ETYPE_DES_CBC_CRC    , "des-cbc-crc" },
118     { KRB5_ETYPE_DES_CBC_MD4    , "des-cbc-md4" },
119     { KRB5_ETYPE_DES_CBC_MD5    , "des-cbc-md5" },
120 };
121
122 static const value_string krb5_address_types[] = {
123     { KRB5_ADDR_IPv4,   "IPv4"},
124     { KRB5_ADDR_CHAOS,  "CHAOS"},
125     { KRB5_ADDR_XEROX,  "XEROX"},
126     { KRB5_ADDR_ISO,    "ISO"},
127     { KRB5_ADDR_DECNET, "DECNET"},
128     { KRB5_ADDR_APPLETALK,      "APPLETALK"}
129 };
130
131 static const value_string krb5_msg_types[] = {
132         { KRB5_MSG_TGS_REQ,     "TGS-REQ" },
133         { KRB5_MSG_TGS_RESP,    "TGS-RESP" },
134         { KRB5_MSG_AS_REQ,      "AS-REQ" },
135         { KRB5_MSG_AS_RESP,     "AS-RESP" }
136 };
137
138 const char *
139 to_error_str(int ret) {
140     switch (ret) {
141
142         case ASN1_ERR_EMPTY:
143             return("Ran out of data");
144
145         case ASN1_ERR_EOC_MISMATCH:
146             return("EOC mismatch");
147
148         case ASN1_ERR_WRONG_TYPE:
149             return("Wrong type for that item");
150
151         case ASN1_ERR_LENGTH_NOT_DEFINITE:
152             return("Length was indefinite");
153
154         case ASN1_ERR_LENGTH_MISMATCH:
155             return("Length mismatch");
156
157         case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
158             return("Wrong length for that item's type");
159
160     }
161     return("Unknown error");
162 }
163
164 void
165 krb_proto_tree_add_time(proto_tree *tree, int offset, int str_len,
166                         char *name, guchar *str) {
167     if (tree)
168         proto_tree_add_text(tree, NullTVB, offset, str_len,
169                             "%s: %.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s)",
170                             name, str, str+4, str+6,
171                             str+8, str+10, str+12,
172                             str+14);
173 }
174
175
176 /*
177  * You must be kidding.  I'm going to actually use a macro to do something?
178  *   bad me.  Bad me.
179  */
180
181 #define KRB_HEAD_DECODE_OR_DIE(token) \
182    start = asn1p->pointer; \
183    ret = asn1_header_decode (asn1p, &cls, &con, &tag, &def, &item_len); \
184    if (ret != ASN1_ERR_NOERROR && ret != ASN1_ERR_EMPTY) {\
185        if (check_col(fd, COL_INFO)) \
186            col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
187                     token, to_error_str(ret)); \
188        return; \
189    } \
190    if (!def) {\
191        if (check_col(fd, COL_INFO)) \
192            col_add_fstr(fd, COL_INFO, "not definite: %s", token); \
193        fprintf(stderr,"not definite: %s\n", token); \
194        return; \
195    } \
196    offset += (asn1p->pointer - start);
197
198
199 #define KRB_DECODE_OR_DIE(token, fn, val) \
200     ret = fn (asn1p, &val, &length); \
201     if (ret != ASN1_ERR_NOERROR) { \
202        if (check_col(fd, COL_INFO)) \
203          col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
204                      token, to_error_str(ret)); \
205         return; \
206     } \
207
208 /* dissect_type_value_pair decodes (roughly) this:
209
210     SEQUENCE  {
211                         INTEGER,
212                         OCTET STRING
213     }
214
215     which is all over the place in krb5 */
216
217 void
218 dissect_type_value_pair(ASN1_SCK *asn1p, int *inoff,
219                         int *type, int *type_len, int *type_off,
220                         guchar **val, int *val_len, int *val_off) {
221     int offset = *inoff;
222     guint cls, con, tag;
223     gboolean def;
224     const guchar *start;
225     guint tmp_len;
226     int ret;
227
228     /* SEQUENCE */
229     start = asn1p->pointer;
230     asn1_header_decode (asn1p, &cls, &con, &tag, &def, &tmp_len);
231     offset += (asn1p->pointer - start);
232
233     /* INT */
234     /* wrapper */
235     start = asn1p->pointer;
236     asn1_header_decode (asn1p, &cls, &con, &tag, &def, &tmp_len);
237     offset += (asn1p->pointer - start);
238
239     if (type_off)
240         *type_off = offset;
241
242     /* value */
243     ret =  asn1_int32_decode(asn1p, type, type_len);
244     if (ret != ASN1_ERR_NOERROR) {
245         fprintf(stderr,"die: type_value_pair: type, %s\n", to_error_str(ret));
246         return;
247     }
248     offset += tmp_len;
249
250     /* OCTET STRING (or generic data) */
251     /* wrapper */
252     start = asn1p->pointer;
253     asn1_header_decode (asn1p, &cls, &con, &tag, &def, val_len);
254     asn1_header_decode (asn1p, &cls, &con, &tag, &def, val_len);
255     offset += asn1p->pointer - start;
256     
257     if (val_off)
258         *val_off = offset;
259
260     /* value */
261     asn1_octet_string_value_decode (asn1p, *val_len, val);
262
263     *inoff = offset + *val_len;
264 }
265
266
267 void
268 dissect_kerberos(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
269 {
270     proto_tree *kerberos_tree = NULL;
271     proto_tree *etype_tree = NULL;
272     proto_tree *preauth_tree = NULL;
273     proto_tree *request_tree = NULL;
274     ASN1_SCK asn1, *asn1p = &asn1;
275     proto_item *item = NULL;
276
277     guint length;
278     guint cls, con, tag;
279     gboolean def;
280     guint item_len, total_len;
281     const guchar *start;
282
283     int ret;
284
285     guint protocol_message_type;
286     
287     gint32 version;
288     gint32 msg_type;
289     gint32 preauth_type;
290     gint32 tmp_int;
291
292     /* simple holders */
293     int str_len;
294     guchar *str;
295     int tmp_pos1, tmp_pos2;
296
297     OLD_CHECK_DISPLAY_AS_DATA(proto_kerberos, pd, offset, fd, tree);
298
299     if (check_col(fd, COL_PROTOCOL))
300         col_set_str(fd, COL_PROTOCOL, "KRB5");
301
302     if (tree) {
303         item = proto_tree_add_item(tree, proto_kerberos, NullTVB, offset,
304                                    END_OF_FRAME, FALSE);
305         kerberos_tree = proto_item_add_subtree(item, ett_kerberos);
306     }
307
308     asn1_open(&asn1, &pd[offset], END_OF_FRAME);
309
310     /* top header */
311     KRB_HEAD_DECODE_OR_DIE("top");
312     protocol_message_type = tag;
313     
314     /* second header */
315     KRB_HEAD_DECODE_OR_DIE("top2");
316
317     /* version number */
318     KRB_HEAD_DECODE_OR_DIE("version-wrap");
319     KRB_DECODE_OR_DIE("version", asn1_int32_decode, version);
320
321     if (kerberos_tree) {
322         proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
323                             "Version: %d",
324                             version);
325     }
326     offset += length;
327
328     /* message type */
329     KRB_HEAD_DECODE_OR_DIE("message-type-wrap");
330     KRB_DECODE_OR_DIE("message-type", asn1_int32_decode, msg_type);
331
332     if (kerberos_tree) {
333         proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
334                             "MSG Type: %s",
335                             val_to_str(msg_type, krb5_msg_types,
336                                        "Unknown msg type %#x"));
337     }
338     offset += length;
339
340     if (check_col(fd, COL_INFO))
341         col_add_str(fd, COL_INFO, val_to_str(msg_type, krb5_msg_types,
342                                              "Unknown msg type %#x"));
343
344         /* is preauthentication present? */
345     KRB_HEAD_DECODE_OR_DIE("padata-or-body");
346     if (((protocol_message_type == KRB5_MSG_AS_REQ ||
347           protocol_message_type == KRB5_MSG_TGS_REQ) &&
348          tag == KRB5_KDC_REQ_PADATA) ||
349         ((protocol_message_type == KRB5_MSG_AS_RESP ||
350           protocol_message_type == KRB5_MSG_TGS_RESP) &&
351          tag == KRB5_KDC_RESP_PADATA)) {
352         /* pre-authentication supplied */
353
354         if (tree) {
355             item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
356                                        item_len, "Pre-Authentication");
357             preauth_tree = proto_item_add_subtree(item, ett_preauth);
358         }
359
360         KRB_HEAD_DECODE_OR_DIE("sequence of pa-data");
361         start = asn1p->pointer + item_len;
362
363         while(start > asn1p->pointer) {
364             dissect_type_value_pair(asn1p, &offset,
365                                     &preauth_type, &item_len, &tmp_pos1,
366                                     &str, &str_len, &tmp_pos2);
367
368             if (preauth_tree) {
369                 proto_tree_add_text(preauth_tree, NullTVB, tmp_pos1,
370                                     item_len, "Type: %s",
371                                     val_to_str(preauth_type,
372                                                krb5_preauthentication_types,
373                                                "Unknown preauth type %#x"));
374                 proto_tree_add_text(preauth_tree, NullTVB, tmp_pos2,
375                                     str_len, "Value: %s",
376                                     bytes_to_str(str, str_len));
377             }
378         }
379         KRB_HEAD_DECODE_OR_DIE("message-body");
380     }
381
382     if (protocol_message_type == KRB5_MSG_AS_REQ ||
383         protocol_message_type == KRB5_MSG_TGS_REQ) {
384     
385         /* request body */
386         KRB_HEAD_DECODE_OR_DIE("body-sequence");
387         if (tree) {
388             item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
389                                        item_len, "Request");
390             request_tree = proto_item_add_subtree(item, ett_request);
391         }
392
393         /* kdc options */
394         KRB_HEAD_DECODE_OR_DIE("kdc options");
395
396         KRB_HEAD_DECODE_OR_DIE("kdc options:bits");
397
398         if (request_tree) {
399                 proto_tree_add_text(request_tree, NullTVB, offset, item_len,
400                                     "Options: %s",
401                                     bytes_to_str(asn1.pointer, item_len));
402         }
403         offset += item_len;
404         asn1.pointer += item_len;
405
406         KRB_HEAD_DECODE_OR_DIE("Principal Name");
407
408         if (tag == KRB5_BODY_CNAME) {
409             dissect_PrincipalName("Client Name", asn1p, fd, request_tree,
410                                    &offset);
411             KRB_HEAD_DECODE_OR_DIE("realm name");
412         }
413
414         if (tag == KRB5_BODY_REALM) {
415             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
416             offset += item_len - str_len;
417             if (request_tree) {
418                 proto_tree_add_text(request_tree, NullTVB, offset, str_len,
419                                     "Realm: %.*s", str_len, str);
420             }
421             offset += str_len;
422             KRB_HEAD_DECODE_OR_DIE("realm name");
423         } else {
424             return;
425         }
426
427         if (tag == KRB5_BODY_SNAME) {
428             dissect_PrincipalName("Server Name", asn1p, fd, request_tree, &offset);
429             KRB_HEAD_DECODE_OR_DIE("realm name");
430         }
431
432         if (tag == KRB5_BODY_FROM) {
433             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
434             offset += item_len - str_len;
435             krb_proto_tree_add_time(request_tree, offset, str_len,
436                                     "Start Time", str);
437             offset += str_len;
438             KRB_HEAD_DECODE_OR_DIE("realm name");
439         }
440
441         if (tag == KRB5_BODY_TILL) {
442             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
443             offset += item_len - str_len;
444             krb_proto_tree_add_time(request_tree, offset, str_len,
445                                     "End Time", str);
446             offset += str_len;
447             KRB_HEAD_DECODE_OR_DIE("realm name");
448         } else {
449             return;
450         }
451         
452         if (tag == KRB5_BODY_RTIME) {
453             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
454             offset += item_len - str_len;
455             krb_proto_tree_add_time(request_tree, offset, str_len,
456                                     "Renewable Until", str);
457             offset += str_len;
458             KRB_HEAD_DECODE_OR_DIE("realm name");
459         }
460             
461         if (tag == KRB5_BODY_NONCE) {
462             ret =  asn1_int32_decode(asn1p, &tmp_int, &length);
463             if (ret != ASN1_ERR_NOERROR) {
464                 fprintf(stderr,"die: nonce, %s\n", to_error_str(ret));
465                 return;
466             }
467             if (request_tree) {
468                 proto_tree_add_text(request_tree, NullTVB, offset, length,
469                                     "Random Number: %d",
470                                     tmp_int);
471             }
472             offset += length;
473         } else {
474             return;
475         }
476         
477         KRB_HEAD_DECODE_OR_DIE("encryption type spot");
478         if (tag == KRB5_BODY_ETYPE) {
479             KRB_HEAD_DECODE_OR_DIE("encryption type list");
480             if (kerberos_tree) {
481                 item = proto_tree_add_text(request_tree, NullTVB, offset,
482                                            item_len, "Encryption Types");
483                 etype_tree = proto_item_add_subtree(item, ett_etype);
484             }
485             total_len = item_len;
486             while(total_len > 0) {
487                 ret =  asn1_int32_decode(asn1p, &tmp_int, &length);
488                 if (ret != ASN1_ERR_NOERROR) {
489                     fprintf(stderr,"die: etype, %s\n", to_error_str(ret));
490                     return;
491                 }
492                 if (etype_tree) {
493                     proto_tree_add_text(etype_tree, NullTVB, offset, length,
494                                         "Type: %s",
495                                         val_to_str(tmp_int,
496                                                    krb5_encryption_types,
497                                                    "Unknown encryption type %#x"));
498                 }
499                 offset += length;
500                 total_len -= length;
501             }
502         } else {
503             return;
504         }
505
506         KRB_HEAD_DECODE_OR_DIE("addresses");
507         if (tag == KRB5_BODY_ADDRESSES) {
508             /* pre-authentication supplied */
509
510             dissect_Addresses("Addresses", asn1p, fd, kerberos_tree, &offset);
511             KRB_HEAD_DECODE_OR_DIE("auth-data");
512         }
513     } else if (protocol_message_type == KRB5_MSG_AS_RESP ||
514                protocol_message_type == KRB5_MSG_TGS_RESP) {
515         if (tag == KRB5_KDC_RESP_CREALM) {
516             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
517             offset += item_len - str_len;
518             if (kerberos_tree) {
519                 proto_tree_add_text(kerberos_tree, NullTVB, offset, str_len,
520                                     "Realm: %.*s", str_len, str);
521             }
522             offset += str_len;
523         } else {
524             return;
525         }
526
527         KRB_HEAD_DECODE_OR_DIE("cname");
528         if (tag == KRB5_KDC_RESP_CNAME) {
529             dissect_PrincipalName("Client Name", asn1p, fd, kerberos_tree,
530                                    &offset);
531         } else {
532             return;
533         }
534         
535         KRB_HEAD_DECODE_OR_DIE("ticket");
536         if (tag == KRB5_KDC_RESP_TICKET) {
537             dissect_ticket("ticket", asn1p, fd, kerberos_tree, &offset);
538         } else {
539             return;
540         }
541
542         KRB_HEAD_DECODE_OR_DIE("enc-msg-part");
543         if (tag == KRB5_KDC_RESP_TICKET) {
544             dissect_EncryptedData("Encrypted Payload", asn1p, fd, kerberos_tree,
545                                   &offset);
546         } else {
547             return;
548         }
549     }
550 }
551
552 void
553 dissect_GeneralString(ASN1_SCK *asn1p, guchar **where,
554                       guint *item_len, guint *pkt_len)
555 {
556     guint cls, con, tag;
557     gboolean def;
558     const guchar *start = asn1p->pointer;
559
560     asn1_header_decode (asn1p, &cls, &con, &tag, &def, item_len);
561     asn1_octet_string_value_decode (asn1p, *item_len, where);
562     *pkt_len = asn1p->pointer - start;
563 }
564
565 void
566 dissect_PrincipalName(char *title, ASN1_SCK *asn1p, frame_data *fd,
567                        proto_tree *tree, int *inoff) {
568     proto_tree *princ_tree = NULL;
569     int offset = 0;
570
571     gint32 princ_type;
572
573     const guchar *start;
574     guint cls, con, tag;
575     guint item_len, total_len, type_len;
576     int ret;
577
578     proto_item *item = NULL;
579     guint length;
580     gboolean def;
581
582     int type_offset;
583
584     guchar *name;
585     guint name_len;
586
587     if (inoff)
588         offset = *inoff;
589     
590     /* principal name */
591     KRB_HEAD_DECODE_OR_DIE("principal section");
592
593     KRB_HEAD_DECODE_OR_DIE("principal type");
594     KRB_DECODE_OR_DIE("princ-type", asn1_int32_decode, princ_type);
595     type_offset = offset;
596     type_len = item_len;
597     offset += length;
598
599     KRB_HEAD_DECODE_OR_DIE("cname header");
600     total_len = item_len;
601
602     dissect_GeneralString(asn1p, &name, &name_len, &item_len);
603     offset += item_len - name_len;
604     
605     if (tree) {
606         item = proto_tree_add_text(tree, NullTVB, *inoff, total_len,
607                                    "%s: %.*s", title, (int) name_len, name);
608         princ_tree = proto_item_add_subtree(item, ett_princ);
609
610         proto_tree_add_text(princ_tree, NullTVB, type_offset, type_len,
611                             "Type: %d", princ_type);
612         proto_tree_add_text(princ_tree, NullTVB, offset, name_len,
613                             "Name: %.*s", (int) name_len, name);
614     }
615
616     total_len -= item_len;
617     offset += name_len;
618     
619     while(total_len > 0) {
620         dissect_GeneralString(asn1p, &name, &name_len, &item_len);
621         offset += item_len - name_len;
622         if (princ_tree) {
623             proto_tree_add_text(princ_tree, NullTVB, offset, name_len,
624                                 "Name: %.*s", (int) name_len, name);
625         }
626         total_len -= item_len;
627         offset += name_len;
628     }
629     if (inoff)
630         *inoff = offset;
631 }
632
633 void
634 dissect_Addresses(char *title, ASN1_SCK *asn1p, frame_data *fd,
635                   proto_tree *tree, int *inoff) {
636     proto_tree *address_tree = NULL;
637     int offset = 0;
638
639     const guchar *start;
640     guint cls, con, tag;
641     guint item_len;
642     int ret;
643
644     proto_item *item = NULL;
645     gboolean def;
646
647     int tmp_pos1, tmp_pos2;
648     gint32 address_type;
649
650     int str_len;
651     guchar *str;
652
653     if (inoff)
654         offset = *inoff;
655
656     KRB_HEAD_DECODE_OR_DIE("sequence of addresses");
657     if (tree) {
658         item = proto_tree_add_text(tree, NullTVB, offset,
659                                    item_len, "Addresses");
660         address_tree = proto_item_add_subtree(item, ett_addresses);
661     }
662
663     start = asn1p->pointer + item_len;
664
665     while(start > asn1p->pointer) {
666         dissect_type_value_pair(asn1p, &offset,
667                                 &address_type, &item_len, &tmp_pos1,
668                                 &str, &str_len, &tmp_pos2);
669
670         if (address_tree) {
671             proto_tree_add_text(address_tree, NullTVB, tmp_pos1,
672                                 item_len, "Type: %s",
673                                 val_to_str(address_type, krb5_address_types,
674                                            "Unknown address type %#x"));
675             switch(address_type) {
676                 case KRB5_ADDR_IPv4:
677                     proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
678                                         str_len, "Value: %d.%d.%d.%d",
679                                         str[0], str[1], str[2], str[3]);
680                     break;
681                     
682                 default:
683                     proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
684                                         str_len, "Value: %s",
685                                         bytes_to_str(str, str_len));
686             }
687         }
688     }
689     
690     if (inoff)
691         *inoff = offset;
692 }
693
694 void
695 dissect_EncryptedData(char *title, ASN1_SCK *asn1p, frame_data *fd,
696                       proto_tree *tree, int *inoff) {
697     proto_tree *encr_tree = NULL;
698     int offset = 0;
699
700     const guchar *start;
701     guint cls, con, tag;
702     guint item_len;
703     int ret;
704
705     proto_item *item = NULL;
706     guint length;
707     gboolean def;
708     int val;
709
710     guchar *data;
711
712     if (inoff)
713         offset = *inoff;
714     
715     KRB_HEAD_DECODE_OR_DIE("encrypted data section");
716
717     if (tree) {
718         item = proto_tree_add_text(tree, NullTVB, *inoff, item_len,
719                                    "Encrypted Data: %s", title);
720         encr_tree = proto_item_add_subtree(item, ett_princ);
721     }
722
723     /* type */
724     KRB_HEAD_DECODE_OR_DIE("encryption type");
725     KRB_DECODE_OR_DIE("encr-type", asn1_int32_decode, val);
726
727     if (encr_tree) {
728         proto_tree_add_text(encr_tree, NullTVB, offset, length,
729                             "Type: %s",
730                             val_to_str(val, krb5_encryption_types,
731                                        "Unknown encryption type %#x"));
732     }
733     offset += length;
734
735     /* kvno */
736     KRB_HEAD_DECODE_OR_DIE("kvno-wrap");
737     KRB_DECODE_OR_DIE("kvno", asn1_int32_decode, val);
738
739     if (encr_tree) {
740         proto_tree_add_text(encr_tree, NullTVB, offset, length,
741                             "KVNO: %d", val);
742     }
743     offset += length;
744
745     KRB_HEAD_DECODE_OR_DIE("cipher-wrap");
746     KRB_HEAD_DECODE_OR_DIE("cipher");
747     asn1_octet_string_value_decode (asn1p, item_len, &data);
748
749     if (encr_tree) {
750         proto_tree_add_text(encr_tree, NullTVB, offset, length,
751                             "Cipher: %s", bytes_to_str(data, item_len));
752     }
753     offset += item_len;
754     
755     if (inoff)
756         *inoff = offset;
757 }
758
759 void
760 dissect_ticket(char *title, ASN1_SCK *asn1p, frame_data *fd, proto_tree *tree,
761                int *inoff) {
762 /*
763    Ticket ::=                    [APPLICATION 1] SEQUENCE {
764                                  tkt-vno[0]                   INTEGER,
765                                  realm[1]                     Realm,
766                                  sname[2]                     PrincipalName,
767                                  enc-part[3]                  EncryptedData
768    }
769 */
770     proto_tree *ticket_tree = NULL;
771     int offset = 0;
772
773     const guchar *start;
774     guint cls, con, tag;
775     guint item_len;
776     int ret;
777
778     proto_item *item = NULL;
779     guint length;
780     gboolean def;
781     int val;
782
783     int str_len;
784     guchar *str;
785
786     if (inoff)
787         offset = *inoff;
788     
789     KRB_HEAD_DECODE_OR_DIE("ticket section");
790     KRB_HEAD_DECODE_OR_DIE("ticket sequence");
791
792     if (tree) {
793         item = proto_tree_add_text(tree, NullTVB, *inoff, item_len,
794                                    "Ticket");
795         ticket_tree = proto_item_add_subtree(item, ett_ticket);
796     }
797
798     /* type */
799     KRB_HEAD_DECODE_OR_DIE("ticket type");
800     KRB_DECODE_OR_DIE("ticket-type", asn1_int32_decode, val);
801
802     if (ticket_tree) {
803         proto_tree_add_text(ticket_tree, NullTVB, offset, length,
804                             "Version: %d", val);
805     }
806     offset += length;
807
808     /* realm name */
809     KRB_HEAD_DECODE_OR_DIE("realm");
810     dissect_GeneralString(asn1p, &str, &str_len, &item_len);
811     offset += item_len - str_len;
812     if (ticket_tree) {
813         proto_tree_add_text(ticket_tree, NullTVB, offset, str_len,
814                             "Realm: %.*s", str_len, str);
815     }
816     offset += str_len;
817
818     /* server name (sname) */
819     KRB_HEAD_DECODE_OR_DIE("sname");
820     dissect_PrincipalName("Service Name", asn1p, fd, ticket_tree, &offset);
821
822     /* ticket */
823     KRB_HEAD_DECODE_OR_DIE("enc-part");
824     dissect_EncryptedData("ticket data", asn1p, fd, ticket_tree, &offset);
825
826     if (inoff)
827         *inoff = offset;
828 }
829
830
831 void
832 proto_register_kerberos(void) {
833 /*
834     static hf_register_info hf[] = {
835     };
836 */
837     static gint *ett[] = {
838         &ett_kerberos,
839         &ett_preauth,
840         &ett_request,
841         &ett_princ,
842         &ett_encrypted,
843         &ett_ticket,
844         &ett_addresses,
845         &ett_etype,
846     };
847     proto_kerberos = proto_register_protocol("Kerberos", "kerberos");
848 /*
849     proto_register_field_array(proto_kerberos, hf, array_length(hf));
850 */
851     proto_register_subtree_array(ett, array_length(ett));
852 }
853
854 void
855 proto_reg_handoff_kerberos(void)
856 {
857         old_dissector_add("udp.port", UDP_PORT_KERBEROS, dissect_kerberos);
858         old_dissector_add("tcp.port", TCP_PORT_KERBEROS, dissect_kerberos);
859 }
860
861 /*
862
863   MISC definitions from RFC1510:
864   
865    KerberosTime ::=   GeneralizedTime
866    Realm ::=           GeneralString
867    PrincipalName ::=   SEQUENCE {
868                        name-type[0]     INTEGER,
869                        name-string[1]   SEQUENCE OF GeneralString
870    }
871     HostAddress ::=     SEQUENCE  {
872                         addr-type[0]             INTEGER,
873                         address[1]               OCTET STRING
874     }
875
876     HostAddresses ::=   SEQUENCE OF SEQUENCE {
877                         addr-type[0]             INTEGER,
878                         address[1]               OCTET STRING
879     }
880
881     AS-REQ ::=         [APPLICATION 10] KDC-REQ
882     TGS-REQ ::=        [APPLICATION 12] KDC-REQ
883     
884     KDC-REQ ::=        SEQUENCE {
885            pvno[1]               INTEGER,
886            msg-type[2]           INTEGER,
887            padata[3]             SEQUENCE OF PA-DATA OPTIONAL,
888            req-body[4]           KDC-REQ-BODY
889     }
890
891     PA-DATA ::=        SEQUENCE {
892            padata-type[1]        INTEGER,
893            padata-value[2]       OCTET STRING,
894                          -- might be encoded AP-REQ
895     }
896
897 KDC-REQ-BODY ::=   SEQUENCE {
898             kdc-options[0]       KDCOptions,
899             cname[1]             PrincipalName OPTIONAL,
900                          -- Used only in AS-REQ
901             realm[2]             Realm, -- Server's realm
902                          -- Also client's in AS-REQ
903             sname[3]             PrincipalName OPTIONAL,
904             from[4]              KerberosTime OPTIONAL,
905             till[5]              KerberosTime,
906             rtime[6]             KerberosTime OPTIONAL,
907             nonce[7]             INTEGER,
908             etype[8]             SEQUENCE OF INTEGER, -- EncryptionType,
909                          -- in preference order
910             addresses[9]         HostAddresses OPTIONAL,
911             enc-authorization-data[10]   EncryptedData OPTIONAL,
912                          -- Encrypted AuthorizationData encoding
913             additional-tickets[11]       SEQUENCE OF Ticket OPTIONAL
914 }
915
916    AS-REP ::=    [APPLICATION 11] KDC-REP
917    TGS-REP ::=   [APPLICATION 13] KDC-REP
918
919    KDC-REP ::=   SEQUENCE {
920                  pvno[0]                    INTEGER,
921                  msg-type[1]                INTEGER,
922                  padata[2]                  SEQUENCE OF PA-DATA OPTIONAL,
923                  crealm[3]                  Realm,
924                  cname[4]                   PrincipalName,
925                  ticket[5]                  Ticket,
926                  enc-part[6]                EncryptedData
927    }
928
929    EncASRepPart ::=    [APPLICATION 25[25]] EncKDCRepPart
930    EncTGSRepPart ::=   [APPLICATION 26] EncKDCRepPart
931
932    EncKDCRepPart ::=   SEQUENCE {
933                key[0]                       EncryptionKey,
934                last-req[1]                  LastReq,
935                nonce[2]                     INTEGER,
936                key-expiration[3]            KerberosTime OPTIONAL,
937                flags[4]                     TicketFlags,
938                authtime[5]                  KerberosTime,
939                starttime[6]                 KerberosTime OPTIONAL,
940                endtime[7]                   KerberosTime,
941                renew-till[8]                KerberosTime OPTIONAL,
942                srealm[9]                    Realm,
943                sname[10]                    PrincipalName,
944                caddr[11]                    HostAddresses OPTIONAL
945    }
946
947    Ticket ::=                    [APPLICATION 1] SEQUENCE {
948                                  tkt-vno[0]                   INTEGER,
949                                  realm[1]                     Realm,
950                                  sname[2]                     PrincipalName,
951                                  enc-part[3]                  EncryptedData
952    }
953
954
955 */