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