Kerberos 5 dissector, from Wes Hardaker.
[metze/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.1 2000/08/11 03:32:43 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 "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     if (check_col(fd, COL_PROTOCOL))
293         col_add_str(fd, COL_PROTOCOL, "KRB5");
294
295     if (tree) {
296         item = proto_tree_add_item(tree, proto_kerberos, NullTVB, offset,
297                                    END_OF_FRAME, FALSE);
298         kerberos_tree = proto_item_add_subtree(item, ett_kerberos);
299     }
300
301     asn1_open(&asn1, &pd[offset], END_OF_FRAME);
302
303     /* top header */
304     KRB_HEAD_DECODE_OR_DIE("top");
305     protocol_message_type = tag;
306     
307     /* second header */
308     KRB_HEAD_DECODE_OR_DIE("top2");
309
310     /* version number */
311     KRB_HEAD_DECODE_OR_DIE("version-wrap");
312     KRB_DECODE_OR_DIE("version", asn1_int32_decode, version);
313
314     if (kerberos_tree) {
315         proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
316                             "Version: %d",
317                             version);
318     }
319     offset += length;
320
321     /* message type */
322     KRB_HEAD_DECODE_OR_DIE("message-type-wrap");
323     KRB_DECODE_OR_DIE("message-type", asn1_int32_decode, msg_type);
324
325     if (kerberos_tree) {
326         proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
327                             "MSG Type: %s",
328                             val_to_str(msg_type, krb5_msg_types,
329                                        "Unknown msg type %#x"));
330     }
331     offset += length;
332
333     if (check_col(fd, COL_INFO))
334         col_add_str(fd, COL_INFO, val_to_str(msg_type, krb5_msg_types,
335                                              "Unknown msg type %#x"));
336
337         /* is preauthentication present? */
338     KRB_HEAD_DECODE_OR_DIE("padata-or-body");
339     if (((protocol_message_type == KRB5_MSG_AS_REQ ||
340           protocol_message_type == KRB5_MSG_TGS_REQ) &&
341          tag == KRB5_KDC_REQ_PADATA) ||
342         ((protocol_message_type == KRB5_MSG_AS_RESP ||
343           protocol_message_type == KRB5_MSG_TGS_RESP) &&
344          tag == KRB5_KDC_RESP_PADATA)) {
345         /* pre-authentication supplied */
346
347         if (tree) {
348             item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
349                                        item_len, "Pre-Authentication");
350             preauth_tree = proto_item_add_subtree(item, ett_preauth);
351         }
352
353         KRB_HEAD_DECODE_OR_DIE("sequence of pa-data");
354         start = asn1p->pointer + item_len;
355
356         while(start > asn1p->pointer) {
357             dissect_type_value_pair(asn1p, &offset,
358                                     &preauth_type, &item_len, &tmp_pos1,
359                                     &str, &str_len, &tmp_pos2);
360
361             if (preauth_tree) {
362                 proto_tree_add_text(preauth_tree, NullTVB, tmp_pos1,
363                                     item_len, "Type: %s",
364                                     val_to_str(preauth_type,
365                                                krb5_preauthentication_types,
366                                                "Unknown preauth type %#x"));
367                 proto_tree_add_text(preauth_tree, NullTVB, tmp_pos2,
368                                     str_len, "Value: %s",
369                                     bytes_to_str(str, str_len));
370             }
371         }
372         KRB_HEAD_DECODE_OR_DIE("message-body");
373     }
374
375     if (protocol_message_type == KRB5_MSG_AS_REQ ||
376         protocol_message_type == KRB5_MSG_TGS_REQ) {
377     
378         /* request body */
379         KRB_HEAD_DECODE_OR_DIE("body-sequence");
380         if (tree) {
381             item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
382                                        item_len, "Request");
383             request_tree = proto_item_add_subtree(item, ett_request);
384         }
385
386         /* kdc options */
387         KRB_HEAD_DECODE_OR_DIE("kdc options");
388
389         KRB_HEAD_DECODE_OR_DIE("kdc options:bits");
390
391         if (request_tree) {
392                 proto_tree_add_text(request_tree, NullTVB, offset, item_len,
393                                     "Options: %s",
394                                     bytes_to_str(asn1.pointer, item_len));
395         }
396         offset += item_len;
397         asn1.pointer += item_len;
398
399         KRB_HEAD_DECODE_OR_DIE("Principal Name");
400
401         if (tag == KRB5_BODY_CNAME) {
402             dissect_PrincipalName("Client Name", asn1p, fd, request_tree,
403                                    &offset);
404             KRB_HEAD_DECODE_OR_DIE("realm name");
405         }
406
407         if (tag == KRB5_BODY_REALM) {
408             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
409             offset += item_len - str_len;
410             if (request_tree) {
411                 proto_tree_add_text(request_tree, NullTVB, offset, str_len,
412                                     "Realm: %.*s", str_len, str);
413             }
414             offset += str_len;
415             KRB_HEAD_DECODE_OR_DIE("realm name");
416         } else {
417             return;
418         }
419
420         if (tag == KRB5_BODY_SNAME) {
421             dissect_PrincipalName("Server Name", asn1p, fd, request_tree, &offset);
422             KRB_HEAD_DECODE_OR_DIE("realm name");
423         }
424
425         if (tag == KRB5_BODY_FROM) {
426             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
427             offset += item_len - str_len;
428             krb_proto_tree_add_time(request_tree, offset, str_len,
429                                     "Start Time", str);
430             offset += str_len;
431             KRB_HEAD_DECODE_OR_DIE("realm name");
432         }
433
434         if (tag == KRB5_BODY_TILL) {
435             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
436             offset += item_len - str_len;
437             krb_proto_tree_add_time(request_tree, offset, str_len,
438                                     "End Time", str);
439             offset += str_len;
440             KRB_HEAD_DECODE_OR_DIE("realm name");
441         } else {
442             return;
443         }
444         
445         if (tag == KRB5_BODY_RTIME) {
446             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
447             offset += item_len - str_len;
448             krb_proto_tree_add_time(request_tree, offset, str_len,
449                                     "Renewable Until", str);
450             offset += str_len;
451             KRB_HEAD_DECODE_OR_DIE("realm name");
452         }
453             
454         if (tag == KRB5_BODY_NONCE) {
455             ret =  asn1_int32_decode(asn1p, &tmp_int, &length);
456             if (ret != ASN1_ERR_NOERROR) {
457                 fprintf(stderr,"die: nonce, %s\n", to_error_str(ret));
458                 return;
459             }
460             if (request_tree) {
461                 proto_tree_add_text(request_tree, NullTVB, offset, length,
462                                     "Random Number: %d",
463                                     tmp_int);
464             }
465             offset += length;
466         } else {
467             return;
468         }
469         
470         KRB_HEAD_DECODE_OR_DIE("encryption type spot");
471         if (tag == KRB5_BODY_ETYPE) {
472             KRB_HEAD_DECODE_OR_DIE("encryption type list");
473             if (kerberos_tree) {
474                 item = proto_tree_add_text(request_tree, NullTVB, offset,
475                                            item_len, "Encryption Types");
476                 etype_tree = proto_item_add_subtree(item, ett_etype);
477             }
478             total_len = item_len;
479             while(total_len > 0) {
480                 ret =  asn1_int32_decode(asn1p, &tmp_int, &length);
481                 if (ret != ASN1_ERR_NOERROR) {
482                     fprintf(stderr,"die: etype, %s\n", to_error_str(ret));
483                     return;
484                 }
485                 if (etype_tree) {
486                     proto_tree_add_text(etype_tree, NullTVB, offset, length,
487                                         "Type: %s",
488                                         val_to_str(tmp_int,
489                                                    krb5_encryption_types,
490                                                    "Unknown encryption type %#x"));
491                 }
492                 offset += length;
493                 total_len -= length;
494             }
495         } else {
496             return;
497         }
498
499         KRB_HEAD_DECODE_OR_DIE("addresses");
500         if (tag == KRB5_BODY_ADDRESSES) {
501             /* pre-authentication supplied */
502
503             dissect_Addresses("Addresses", asn1p, fd, kerberos_tree, &offset);
504             KRB_HEAD_DECODE_OR_DIE("auth-data");
505         }
506     } else if (protocol_message_type == KRB5_MSG_AS_RESP ||
507                protocol_message_type == KRB5_MSG_TGS_RESP) {
508         if (tag == KRB5_KDC_RESP_CREALM) {
509             dissect_GeneralString(asn1p, &str, &str_len, &item_len);
510             offset += item_len - str_len;
511             if (kerberos_tree) {
512                 proto_tree_add_text(kerberos_tree, NullTVB, offset, str_len,
513                                     "Realm: %.*s", str_len, str);
514             }
515             offset += str_len;
516         } else {
517             return;
518         }
519
520         KRB_HEAD_DECODE_OR_DIE("cname");
521         if (tag == KRB5_KDC_RESP_CNAME) {
522             dissect_PrincipalName("Client Name", asn1p, fd, kerberos_tree,
523                                    &offset);
524         } else {
525             return;
526         }
527         
528         KRB_HEAD_DECODE_OR_DIE("ticket");
529         if (tag == KRB5_KDC_RESP_TICKET) {
530             dissect_ticket("ticket", asn1p, fd, kerberos_tree, &offset);
531         } else {
532             return;
533         }
534
535         KRB_HEAD_DECODE_OR_DIE("enc-msg-part");
536         if (tag == KRB5_KDC_RESP_TICKET) {
537             dissect_EncryptedData("Encrypted Payload", asn1p, fd, kerberos_tree,
538                                   &offset);
539         } else {
540             return;
541         }
542     }
543 }
544
545 void
546 dissect_GeneralString(ASN1_SCK *asn1p, guchar **where,
547                       guint *item_len, guint *pkt_len)
548 {
549     guint cls, con, tag;
550     gboolean def;
551     const guchar *start = asn1p->pointer;
552
553     asn1_header_decode (asn1p, &cls, &con, &tag, &def, item_len);
554     asn1_octet_string_value_decode (asn1p, *item_len, where);
555     *pkt_len = asn1p->pointer - start;
556 }
557
558 void
559 dissect_PrincipalName(char *title, ASN1_SCK *asn1p, frame_data *fd,
560                        proto_tree *tree, int *inoff) {
561     proto_tree *princ_tree = NULL;
562     int offset = 0;
563
564     gint32 princ_type;
565
566     const guchar *start;
567     guint cls, con, tag;
568     guint item_len, total_len, type_len;
569     int ret;
570
571     proto_item *item = NULL;
572     guint length;
573     gboolean def;
574
575     int type_offset;
576
577     guchar *name;
578     guint name_len;
579
580     if (inoff)
581         offset = *inoff;
582     
583     /* principal name */
584     KRB_HEAD_DECODE_OR_DIE("principal section");
585
586     KRB_HEAD_DECODE_OR_DIE("principal type");
587     KRB_DECODE_OR_DIE("princ-type", asn1_int32_decode, princ_type);
588     type_offset = offset;
589     type_len = item_len;
590     offset += length;
591
592     KRB_HEAD_DECODE_OR_DIE("cname header");
593     total_len = item_len;
594
595     dissect_GeneralString(asn1p, &name, &name_len, &item_len);
596     offset += item_len - name_len;
597     
598     if (tree) {
599         item = proto_tree_add_text(tree, NullTVB, *inoff, total_len,
600                                    "%s: %.*s", title, (int) name_len, name);
601         princ_tree = proto_item_add_subtree(item, ett_princ);
602
603         proto_tree_add_text(princ_tree, NullTVB, type_offset, type_len,
604                             "Type: %d", princ_type);
605         proto_tree_add_text(princ_tree, NullTVB, offset, name_len,
606                             "Name: %.*s", (int) name_len, name);
607     }
608
609     total_len -= item_len;
610     offset += name_len;
611     
612     while(total_len > 0) {
613         dissect_GeneralString(asn1p, &name, &name_len, &item_len);
614         offset += item_len - name_len;
615         if (princ_tree) {
616             proto_tree_add_text(princ_tree, NullTVB, offset, name_len,
617                                 "Name: %.*s", (int) name_len, name);
618         }
619         total_len -= item_len;
620         offset += name_len;
621     }
622     if (inoff)
623         *inoff = offset;
624 }
625
626 void
627 dissect_Addresses(char *title, ASN1_SCK *asn1p, frame_data *fd,
628                   proto_tree *tree, int *inoff) {
629     proto_tree *address_tree = NULL;
630     int offset = 0;
631
632     const guchar *start;
633     guint cls, con, tag;
634     guint item_len;
635     int ret;
636
637     proto_item *item = NULL;
638     gboolean def;
639
640     int tmp_pos1, tmp_pos2;
641     gint32 address_type;
642
643     int str_len;
644     guchar *str;
645
646     if (inoff)
647         offset = *inoff;
648
649     KRB_HEAD_DECODE_OR_DIE("sequence of addresses");
650     if (tree) {
651         item = proto_tree_add_text(tree, NullTVB, offset,
652                                    item_len, "Addresses");
653         address_tree = proto_item_add_subtree(item, ett_addresses);
654     }
655
656     start = asn1p->pointer + item_len;
657
658     while(start > asn1p->pointer) {
659         dissect_type_value_pair(asn1p, &offset,
660                                 &address_type, &item_len, &tmp_pos1,
661                                 &str, &str_len, &tmp_pos2);
662
663         if (address_tree) {
664             proto_tree_add_text(address_tree, NullTVB, tmp_pos1,
665                                 item_len, "Type: %s",
666                                 val_to_str(address_type, krb5_address_types,
667                                            "Unknown address type %#x"));
668             switch(address_type) {
669                 case KRB5_ADDR_IPv4:
670                     proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
671                                         str_len, "Value: %d.%d.%d.%d",
672                                         str[0], str[1], str[2], str[3]);
673                     break;
674                     
675                 default:
676                     proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
677                                         str_len, "Value: %s",
678                                         bytes_to_str(str, str_len));
679             }
680         }
681     }
682     
683     if (inoff)
684         *inoff = offset;
685 }
686
687 void
688 dissect_EncryptedData(char *title, ASN1_SCK *asn1p, frame_data *fd,
689                       proto_tree *tree, int *inoff) {
690     proto_tree *encr_tree = NULL;
691     int offset = 0;
692
693     const guchar *start;
694     guint cls, con, tag;
695     guint item_len;
696     int ret;
697
698     proto_item *item = NULL;
699     guint length;
700     gboolean def;
701     int val;
702
703     guchar *data;
704
705     if (inoff)
706         offset = *inoff;
707     
708     KRB_HEAD_DECODE_OR_DIE("encrypted data section");
709
710     if (tree) {
711         item = proto_tree_add_text(tree, NullTVB, *inoff, item_len,
712                                    "Encrypted Data: %s", title);
713         encr_tree = proto_item_add_subtree(item, ett_princ);
714     }
715
716     /* type */
717     KRB_HEAD_DECODE_OR_DIE("encryption type");
718     KRB_DECODE_OR_DIE("encr-type", asn1_int32_decode, val);
719
720     if (encr_tree) {
721         proto_tree_add_text(encr_tree, NullTVB, offset, length,
722                             "Type: %s",
723                             val_to_str(val, krb5_encryption_types,
724                                        "Unknown encryption type %#x"));
725     }
726     offset += length;
727
728     /* kvno */
729     KRB_HEAD_DECODE_OR_DIE("kvno-wrap");
730     KRB_DECODE_OR_DIE("kvno", asn1_int32_decode, val);
731
732     if (encr_tree) {
733         proto_tree_add_text(encr_tree, NullTVB, offset, length,
734                             "KVNO: %d", val);
735     }
736     offset += length;
737
738     KRB_HEAD_DECODE_OR_DIE("cipher-wrap");
739     KRB_HEAD_DECODE_OR_DIE("cipher");
740     asn1_octet_string_value_decode (asn1p, item_len, &data);
741
742     if (encr_tree) {
743         proto_tree_add_text(encr_tree, NullTVB, offset, length,
744                             "Cipher: %s", bytes_to_str(data, item_len));
745     }
746     offset += item_len;
747     
748     if (inoff)
749         *inoff = offset;
750 }
751
752 void
753 dissect_ticket(char *title, ASN1_SCK *asn1p, frame_data *fd, proto_tree *tree,
754                int *inoff) {
755 /*
756    Ticket ::=                    [APPLICATION 1] SEQUENCE {
757                                  tkt-vno[0]                   INTEGER,
758                                  realm[1]                     Realm,
759                                  sname[2]                     PrincipalName,
760                                  enc-part[3]                  EncryptedData
761    }
762 */
763     proto_tree *ticket_tree = NULL;
764     int offset = 0;
765
766     const guchar *start;
767     guint cls, con, tag;
768     guint item_len;
769     int ret;
770
771     proto_item *item = NULL;
772     guint length;
773     gboolean def;
774     int val;
775
776     int str_len;
777     guchar *str;
778
779     if (inoff)
780         offset = *inoff;
781     
782     KRB_HEAD_DECODE_OR_DIE("ticket section");
783     KRB_HEAD_DECODE_OR_DIE("ticket sequence");
784
785     if (tree) {
786         item = proto_tree_add_text(tree, NullTVB, *inoff, item_len,
787                                    "Ticket");
788         ticket_tree = proto_item_add_subtree(item, ett_ticket);
789     }
790
791     /* type */
792     KRB_HEAD_DECODE_OR_DIE("ticket type");
793     KRB_DECODE_OR_DIE("ticket-type", asn1_int32_decode, val);
794
795     if (ticket_tree) {
796         proto_tree_add_text(ticket_tree, NullTVB, offset, length,
797                             "Version: %d", val);
798     }
799     offset += length;
800
801     /* realm name */
802     KRB_HEAD_DECODE_OR_DIE("realm");
803     dissect_GeneralString(asn1p, &str, &str_len, &item_len);
804     offset += item_len - str_len;
805     if (ticket_tree) {
806         proto_tree_add_text(ticket_tree, NullTVB, offset, str_len,
807                             "Realm: %.*s", str_len, str);
808     }
809     offset += str_len;
810
811     /* server name (sname) */
812     KRB_HEAD_DECODE_OR_DIE("sname");
813     dissect_PrincipalName("Service Name", asn1p, fd, ticket_tree, &offset);
814
815     /* ticket */
816     KRB_HEAD_DECODE_OR_DIE("enc-part");
817     dissect_EncryptedData("ticket data", asn1p, fd, ticket_tree, &offset);
818
819     if (inoff)
820         *inoff = offset;
821 }
822
823
824 void
825 proto_register_kerberos(void) {
826     static hf_register_info hf[] = {
827     };
828     static gint *ett[] = {
829         &ett_kerberos,
830         &ett_preauth,
831         &ett_request,
832         &ett_princ,
833         &ett_encrypted,
834         &ett_ticket,
835         &ett_addresses,
836         &ett_etype,
837     };
838     proto_kerberos = proto_register_protocol("Kerberos", "kerberos");
839     proto_register_field_array(proto_kerberos, hf, array_length(hf));
840     proto_register_subtree_array(ett, array_length(ett));
841 }
842
843 void
844 proto_reg_handoff_kerberos(void)
845 {
846         old_dissector_add("udp.port", UDP_PORT_KERBEROS, dissect_kerberos);
847         old_dissector_add("tcp.port", TCP_PORT_KERBEROS, dissect_kerberos);
848 }
849
850 /*
851
852   MISC definitions from RFC1510:
853   
854    KerberosTime ::=   GeneralizedTime
855    Realm ::=           GeneralString
856    PrincipalName ::=   SEQUENCE {
857                        name-type[0]     INTEGER,
858                        name-string[1]   SEQUENCE OF GeneralString
859    }
860     HostAddress ::=     SEQUENCE  {
861                         addr-type[0]             INTEGER,
862                         address[1]               OCTET STRING
863     }
864
865     HostAddresses ::=   SEQUENCE OF SEQUENCE {
866                         addr-type[0]             INTEGER,
867                         address[1]               OCTET STRING
868     }
869
870     AS-REQ ::=         [APPLICATION 10] KDC-REQ
871     TGS-REQ ::=        [APPLICATION 12] KDC-REQ
872     
873     KDC-REQ ::=        SEQUENCE {
874            pvno[1]               INTEGER,
875            msg-type[2]           INTEGER,
876            padata[3]             SEQUENCE OF PA-DATA OPTIONAL,
877            req-body[4]           KDC-REQ-BODY
878     }
879
880     PA-DATA ::=        SEQUENCE {
881            padata-type[1]        INTEGER,
882            padata-value[2]       OCTET STRING,
883                          -- might be encoded AP-REQ
884     }
885
886 KDC-REQ-BODY ::=   SEQUENCE {
887             kdc-options[0]       KDCOptions,
888             cname[1]             PrincipalName OPTIONAL,
889                          -- Used only in AS-REQ
890             realm[2]             Realm, -- Server's realm
891                          -- Also client's in AS-REQ
892             sname[3]             PrincipalName OPTIONAL,
893             from[4]              KerberosTime OPTIONAL,
894             till[5]              KerberosTime,
895             rtime[6]             KerberosTime OPTIONAL,
896             nonce[7]             INTEGER,
897             etype[8]             SEQUENCE OF INTEGER, -- EncryptionType,
898                          -- in preference order
899             addresses[9]         HostAddresses OPTIONAL,
900             enc-authorization-data[10]   EncryptedData OPTIONAL,
901                          -- Encrypted AuthorizationData encoding
902             additional-tickets[11]       SEQUENCE OF Ticket OPTIONAL
903 }
904
905    AS-REP ::=    [APPLICATION 11] KDC-REP
906    TGS-REP ::=   [APPLICATION 13] KDC-REP
907
908    KDC-REP ::=   SEQUENCE {
909                  pvno[0]                    INTEGER,
910                  msg-type[1]                INTEGER,
911                  padata[2]                  SEQUENCE OF PA-DATA OPTIONAL,
912                  crealm[3]                  Realm,
913                  cname[4]                   PrincipalName,
914                  ticket[5]                  Ticket,
915                  enc-part[6]                EncryptedData
916    }
917
918    EncASRepPart ::=    [APPLICATION 25[25]] EncKDCRepPart
919    EncTGSRepPart ::=   [APPLICATION 26] EncKDCRepPart
920
921    EncKDCRepPart ::=   SEQUENCE {
922                key[0]                       EncryptionKey,
923                last-req[1]                  LastReq,
924                nonce[2]                     INTEGER,
925                key-expiration[3]            KerberosTime OPTIONAL,
926                flags[4]                     TicketFlags,
927                authtime[5]                  KerberosTime,
928                starttime[6]                 KerberosTime OPTIONAL,
929                endtime[7]                   KerberosTime,
930                renew-till[8]                KerberosTime OPTIONAL,
931                srealm[9]                    Realm,
932                sname[10]                    PrincipalName,
933                caddr[11]                    HostAddresses OPTIONAL
934    }
935
936    Ticket ::=                    [APPLICATION 1] SEQUENCE {
937                                  tkt-vno[0]                   INTEGER,
938                                  realm[1]                     Realm,
939                                  sname[2]                     PrincipalName,
940                                  enc-part[3]                  EncryptedData
941    }
942
943
944 */