If a PrincipalName has at least one name-string, put the first of the
[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.10 2000/12/25 06:59:33 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 #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   10    /* AS-REQ type */
61 #define KRB5_MSG_AS_REP   11    /* AS-REP type */
62 #define KRB5_MSG_TGS_REQ  12    /* TGS-REQ type */
63 #define KRB5_MSG_TGS_REP  13    /* TGS-REP type */
64 #define KRB5_MSG_AP_REQ   14    /* AP-REQ type */
65 #define KRB5_MSG_AP_REP   15    /* AP-REP type */
66
67 #define KRB5_MSG_SAFE     20    /* KRB-SAFE type */
68 #define KRB5_MSG_PRIV     21    /* KRB-PRIV type */
69 #define KRB5_MSG_CRED     22    /* KRB-CRED type */
70 #define KRB5_MSG_ERROR    30    /* KRB-ERROR type */
71
72 /* Type tags within KDC-REQ */
73 #define KRB5_KDC_REQ_PVNO     1
74 #define KRB5_KDC_REQ_MSG_TYPE 2
75 #define KRB5_KDC_REQ_PADATA   3
76 #define KRB5_KDC_REQ_REQBODY  4
77
78 /* Type tags within KDC-REP */
79 #define KRB5_KDC_REP_PVNO     0
80 #define KRB5_KDC_REP_MSG_TYPE 1
81 #define KRB5_KDC_REP_PADATA   2
82 #define KRB5_KDC_REP_CREALM   3
83 #define KRB5_KDC_REP_CNAME    4
84 #define KRB5_KDC_REP_TICKET   5
85 #define KRB5_KDC_REP_ENC_PART 6
86
87 /* Type tags within KDC-REQ-BODY */
88 #define KRB5_BODY_KDC_OPTIONS            0
89 #define KRB5_BODY_CNAME                  1
90 #define KRB5_BODY_REALM                  2
91 #define KRB5_BODY_SNAME                  3
92 #define KRB5_BODY_FROM                   4
93 #define KRB5_BODY_TILL                   5
94 #define KRB5_BODY_RTIME                  6
95 #define KRB5_BODY_NONCE                  7
96 #define KRB5_BODY_ENCTYPE                  8
97 #define KRB5_BODY_ADDRESSES              9
98 #define KRB5_BODY_ENC_AUTHORIZATION_DATA 10
99 #define KRB5_BODY_ADDITIONAL_TICKETS     11
100
101 #define KRB5_ADDR_IPv4       0x02
102 #define KRB5_ADDR_CHAOS      0x05
103 #define KRB5_ADDR_XEROX      0x06
104 #define KRB5_ADDR_ISO        0x07
105 #define KRB5_ADDR_DECNET     0x0c
106 #define KRB5_ADDR_APPLETALK  0x10
107
108 #define KRB5_ENCTYPE_NULL                0
109 #define KRB5_ENCTYPE_DES_CBC_CRC         1
110 #define KRB5_ENCTYPE_DES_CBC_MD4         2
111 #define KRB5_ENCTYPE_DES_CBC_MD5         3
112 #define KRB5_ENCTYPE_DES_CBC_RAW         4
113 #define KRB5_ENCTYPE_DES3_CBC_SHA        5
114 #define KRB5_ENCTYPE_DES3_CBC_RAW        6
115 #define KRB5_ENCTYPE_DES_HMAC_SHA1       8
116 #define KRB5_ENCTYPE_DES3_CBC_SHA1          0x10 
117 #define KRB5_ENCTYPE_UNKNOWN                0x1ff
118 #define KRB5_ENCTYPE_LOCAL_DES3_HMAC_SHA1   0x7007
119
120 #define KRB5_PA_TGS_REQ                1
121 #define KRB5_PA_ENC_TIMESTAMP          2
122 #define KRB5_PA_PW_SALT                3
123 #define KRB5_PA_ENC_ENCKEY             4
124 #define KRB5_PA_ENC_UNIX_TIME          5
125 #define KRB5_PA_ENC_SANDIA_SECURID     6
126 #define KRB5_PA_SESAME                 7
127 #define KRB5_PA_OSF_DCE                8
128 #define KRB5_PA_CYBERSAFE_SECUREID     9
129 #define KRB5_PA_AFS3_SALT              10
130 #define KRB5_PA_ENCTYPE_INFO             11
131 #define KRB5_PA_SAM_CHALLENGE          12
132 #define KRB5_PA_SAM_RESPONSE           13
133 #define KRB5_PA_DASS                   16
134
135 /* Type tags within Ticket */
136 #define KRB5_TKT_TKT_VNO  0
137 #define KRB5_TKT_REALM    1
138 #define KRB5_TKT_SNAME    2
139 #define KRB5_TKT_ENC_PART 3
140
141 /* Principal name-type */
142 #define KRB5_NT_UNKNOWN     0
143 #define KRB5_NT_PRINCIPAL   1
144 #define KRB5_NT_SRV_INST    2
145 #define KRB5_NT_SRV_HST     3
146 #define KRB5_NT_SRV_XHST    4
147 #define KRB5_NT_UID     5
148
149 static const value_string krb5_princ_types[] = {
150     { KRB5_NT_UNKNOWN              , "Unknown" },
151     { KRB5_NT_PRINCIPAL            , "Principal" },
152     { KRB5_NT_SRV_INST             , "Service and Instance" },
153     { KRB5_NT_SRV_HST              , "Service and Host" },
154     { KRB5_NT_SRV_XHST             , "Service and Host Components" },
155     { KRB5_NT_UID                  , "Unique ID" },
156 };
157
158 static const value_string krb5_preauthentication_types[] = {
159     { KRB5_PA_TGS_REQ              , "PA-TGS-REQ" },
160     { KRB5_PA_ENC_TIMESTAMP        , "PA-ENC-TIMESTAMP" },
161     { KRB5_PA_PW_SALT              , "PA-PW-SALT" },
162     { KRB5_PA_ENC_ENCKEY           , "PA-ENC-ENCKEY" },
163     { KRB5_PA_ENC_UNIX_TIME        , "PA-ENC-UNIX-TIME" },
164     { KRB5_PA_ENC_SANDIA_SECURID   , "PA-PW-SALT" },
165     { KRB5_PA_SESAME               , "PA-SESAME" },
166     { KRB5_PA_OSF_DCE              , "PA-OSF-DCE" },
167     { KRB5_PA_CYBERSAFE_SECUREID   , "PA-CYBERSAFE-SECURID" },
168     { KRB5_PA_AFS3_SALT            , "PA-AFS3-SALT" },
169     { KRB5_PA_ENCTYPE_INFO         , "PA-ENCTYPE-INFO" },
170     { KRB5_PA_SAM_CHALLENGE        , "PA-SAM-CHALLENGE" },
171     { KRB5_PA_SAM_RESPONSE         , "PA-SAM-RESPONSE" },
172     { KRB5_PA_DASS                 , "PA-DASS" },
173 };
174
175 static const value_string krb5_encryption_types[] = {
176     { KRB5_ENCTYPE_NULL           , "NULL" },
177     { KRB5_ENCTYPE_DES_CBC_CRC    , "des-cbc-crc" },
178     { KRB5_ENCTYPE_DES_CBC_MD4    , "des-cbc-md4" },
179     { KRB5_ENCTYPE_DES_CBC_MD5    , "des-cbc-md5" },
180     { KRB5_ENCTYPE_DES_CBC_RAW    , "des-cbc-raw" },
181     { KRB5_ENCTYPE_DES3_CBC_SHA   , "des3-cbc-sha" },
182     { KRB5_ENCTYPE_DES3_CBC_RAW   , "des3-cbc-raw" },
183     { KRB5_ENCTYPE_DES_HMAC_SHA1  , "des-hmac-sha1" },
184     { KRB5_ENCTYPE_DES3_CBC_SHA1  , "des3-cbc-sha1" },
185     { KRB5_ENCTYPE_UNKNOWN        , "unknown" },
186     { KRB5_ENCTYPE_LOCAL_DES3_HMAC_SHA1    , "local-des3-hmac-sha1" },
187 };
188
189 static const value_string krb5_address_types[] = {
190     { KRB5_ADDR_IPv4,           "IPv4"},
191     { KRB5_ADDR_CHAOS,          "CHAOS"},
192     { KRB5_ADDR_XEROX,          "XEROX"},
193     { KRB5_ADDR_ISO,            "ISO"},
194     { KRB5_ADDR_DECNET,         "DECNET"},
195     { KRB5_ADDR_APPLETALK,      "APPLETALK"}
196 };
197
198 static const value_string krb5_msg_types[] = {
199         { KRB5_MSG_TGS_REQ,     "TGS-REQ" },
200         { KRB5_MSG_TGS_REP,     "TGS-REP" },
201         { KRB5_MSG_AS_REQ,      "AS-REQ" },
202         { KRB5_MSG_AS_REP,      "AS-REP" },
203         { KRB5_MSG_AP_REQ,      "AP-REQ" },
204         { KRB5_MSG_AP_REP,      "AP-REP" },
205         { KRB5_MSG_SAFE,        "KRB-SAFE" },
206         { KRB5_MSG_PRIV,        "KRB-PRIV" },
207         { KRB5_MSG_CRED,        "KRB-CRED" },
208         { KRB5_MSG_ERROR,       "KRB-ERROR" }
209 };
210
211 static int dissect_PrincipalName(char *title, ASN1_SCK *asn1p,
212                                  frame_data *fd, proto_tree *tree,
213                                  int start_offset);
214 static int dissect_Ticket(char *title, ASN1_SCK *asn1p, frame_data *fd,
215                           proto_tree *tree, int start_offset);
216 static int dissect_EncryptedData(char *title, ASN1_SCK *asn1p, frame_data *fd,
217                                  proto_tree *tree, int start_offset);
218 static int dissect_Addresses(char *title, ASN1_SCK *asn1p, frame_data *fd,
219                              proto_tree *tree, int start_offset);
220
221 static const char *
222 to_error_str(int ret) {
223     switch (ret) {
224
225         case ASN1_ERR_EMPTY:
226             return("Ran out of data");
227
228         case ASN1_ERR_EOC_MISMATCH:
229             return("EOC mismatch");
230
231         case ASN1_ERR_WRONG_TYPE:
232             return("Wrong type for that item");
233
234         case ASN1_ERR_LENGTH_NOT_DEFINITE:
235             return("Length was indefinite");
236
237         case ASN1_ERR_LENGTH_MISMATCH:
238             return("Length mismatch");
239
240         case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
241             return("Wrong length for that item's type");
242
243     }
244     return("Unknown error");
245 }
246
247 static void
248 krb_proto_tree_add_time(proto_tree *tree, int offset, int str_len,
249                         char *name, guchar *str) {
250     if (tree)
251         proto_tree_add_text(tree, NullTVB, offset, str_len,
252                             "%s: %.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s)",
253                             name, str, str+4, str+6,
254                             str+8, str+10, str+12,
255                             str+14);
256 }
257
258
259 /*
260  * You must be kidding.  I'm going to actually use a macro to do something?
261  *   bad me.  Bad me.
262  */
263
264 #define KRB_HEAD_DECODE_OR_DIE(token) \
265    start = asn1p->pointer; \
266    ret = asn1_header_decode (asn1p, &cls, &con, &tag, &def, &item_len); \
267    if (ret != ASN1_ERR_NOERROR && ret != ASN1_ERR_EMPTY) {\
268        if (check_col(fd, COL_INFO)) \
269            col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
270                     token, to_error_str(ret)); \
271        return -1; \
272    } \
273    if (!def) {\
274        if (check_col(fd, COL_INFO)) \
275            col_add_fstr(fd, COL_INFO, "not definite: %s", token); \
276        fprintf(stderr,"not definite: %s\n", token); \
277        return -1; \
278    } \
279    offset += (asn1p->pointer - start);
280
281 #define CHECK_APPLICATION_TYPE(expected_tag) \
282     (cls == ASN1_APL && con == ASN1_CON && tag == expected_tag)
283
284 #define DIE_IF_NOT_APPLICATION_TYPE(token, expected_tag) \
285     if (!CHECK_APPLICATION_TYPE(expected_tag)) \
286         DIE_WITH_BAD_TYPE(token);
287
288 #define CHECK_CONTEXT_TYPE(expected_tag) \
289     (cls == ASN1_CTX && con == ASN1_CON && tag == expected_tag)
290
291 #define DIE_IF_NOT_CONTEXT_TYPE(token, expected_tag) \
292     if (!CHECK_CONTEXT_TYPE(expected_tag)) \
293         DIE_WITH_BAD_TYPE(token);
294
295 #define DIE_WITH_BAD_TYPE(token) \
296     { \
297       if (check_col(fd, COL_INFO)) \
298          col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
299                       token, to_error_str(ASN1_ERR_WRONG_TYPE)); \
300       return -1; \
301     }
302
303 #define KRB_DECODE_APPLICATION_TAGGED_HEAD_OR_DIE(token, expected_tag) \
304     KRB_HEAD_DECODE_OR_DIE(token); \
305     DIE_IF_NOT_APPLICATION_TYPE(token, expected_tag);
306
307 #define KRB_DECODE_CONTEXT_HEAD_OR_DIE(token, expected_tag) \
308     KRB_HEAD_DECODE_OR_DIE(token); \
309     DIE_IF_NOT_CONTEXT_TYPE(token, expected_tag);
310
311 #define KRB_SEQ_HEAD_DECODE_OR_DIE(token) \
312    ret = asn1_sequence_decode (asn1p, &item_len, &header_len); \
313    if (ret != ASN1_ERR_NOERROR && ret != ASN1_ERR_EMPTY) {\
314        if (check_col(fd, COL_INFO)) \
315            col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
316                     token, to_error_str(ret)); \
317        return -1; \
318    } \
319    offset += header_len;
320
321 #define KRB_DECODE_OR_DIE(token, fn, val) \
322     ret = fn (asn1p, &val, &length); \
323     if (ret != ASN1_ERR_NOERROR) { \
324        if (check_col(fd, COL_INFO)) \
325          col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
326                      token, to_error_str(ret)); \
327         return -1; \
328     } \
329
330 #define KRB_DECODE_UINT32_OR_DIE(token, val) \
331     KRB_DECODE_OR_DIE(token, asn1_uint32_decode, val);
332
333 #define KRB_DECODE_STRING_OR_DIE(token, expected_tag, val, val_len, item_len) \
334     ret = asn1_string_decode (asn1p, &val, &val_len, &item_len, expected_tag); \
335     if (ret != ASN1_ERR_NOERROR) { \
336        if (check_col(fd, COL_INFO)) \
337          col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
338                      token, to_error_str(ret)); \
339         return -1; \
340     }
341
342 #define KRB_DECODE_OCTET_STRING_OR_DIE(token, val, val_len, item_len) \
343     KRB_DECODE_STRING_OR_DIE(token, ASN1_OTS, val, val_len, item_len)
344
345 #define KRB_DECODE_GENERAL_STRING_OR_DIE(token, val, val_len, item_len) \
346     KRB_DECODE_STRING_OR_DIE(token, ASN1_GENSTR, val, val_len, item_len)
347
348 #define KRB_DECODE_GENERAL_TIME_OR_DIE(token, val, val_len, item_len) \
349     KRB_DECODE_STRING_OR_DIE(token, ASN1_GENTIM, val, val_len, item_len)
350
351 /* dissect_type_value_pair decodes (roughly) this:
352
353     SEQUENCE  {
354                         INTEGER,
355                         OCTET STRING
356     }
357
358     which is all over the place in krb5 */
359
360 static void
361 dissect_type_value_pair(ASN1_SCK *asn1p, int *inoff,
362                         guint32 *type, int *type_len, int *type_off,
363                         guchar **val, int *val_len, int *val_off) {
364     int offset = *inoff;
365     guint cls, con, tag;
366     gboolean def;
367     const guchar *start;
368     guint tmp_len;
369     int ret;
370
371     /* SEQUENCE */
372     start = asn1p->pointer;
373     asn1_header_decode (asn1p, &cls, &con, &tag, &def, &tmp_len);
374     offset += (asn1p->pointer - start);
375
376     /* INT */
377     /* wrapper */
378     start = asn1p->pointer;
379     asn1_header_decode (asn1p, &cls, &con, &tag, &def, &tmp_len);
380     offset += (asn1p->pointer - start);
381
382     if (type_off)
383         *type_off = offset;
384
385     /* value */
386     ret =  asn1_uint32_decode(asn1p, type, type_len);
387     if (ret != ASN1_ERR_NOERROR) {
388         fprintf(stderr,"die: type_value_pair: type, %s\n", to_error_str(ret));
389         return;
390     }
391     offset += tmp_len;
392
393     /* OCTET STRING (or generic data) */
394     /* wrapper */
395     start = asn1p->pointer;
396     asn1_header_decode (asn1p, &cls, &con, &tag, &def, val_len);
397     asn1_header_decode (asn1p, &cls, &con, &tag, &def, val_len);
398     offset += asn1p->pointer - start;
399     
400     if (val_off)
401         *val_off = offset;
402
403     /* value */
404     asn1_string_value_decode (asn1p, *val_len, val);
405
406     *inoff = offset + *val_len;
407 }
408
409 static gboolean
410 dissect_kerberos_main(const u_char *pd, int offset, frame_data *fd,
411                       proto_tree *tree)
412 {
413     proto_tree *kerberos_tree = NULL;
414     proto_tree *etype_tree = NULL;
415     proto_tree *preauth_tree = NULL;
416     proto_tree *request_tree = NULL;
417     ASN1_SCK asn1, *asn1p = &asn1;
418     proto_item *item = NULL;
419
420     guint length;
421     guint cls, con, tag;
422     gboolean def;
423     guint item_len, total_len;
424     const guchar *start;
425
426     int ret;
427
428     guint protocol_message_type;
429     
430     guint32 version;
431     guint32 msg_type;
432     guint32 preauth_type;
433     guint32 tmp_int;
434
435     /* simple holders */
436     int str_len;
437     guchar *str;
438     int tmp_pos1, tmp_pos2;
439
440     if (tree) {
441         item = proto_tree_add_item(tree, proto_kerberos, NullTVB, offset,
442                                    END_OF_FRAME, FALSE);
443         kerberos_tree = proto_item_add_subtree(item, ett_kerberos);
444     }
445
446     asn1_open(&asn1, &pd[offset], END_OF_FRAME);
447
448     /* top header */
449     KRB_HEAD_DECODE_OR_DIE("top");
450     protocol_message_type = tag;
451     
452     /* second header */
453     KRB_HEAD_DECODE_OR_DIE("top2");
454
455     /* version number */
456     KRB_HEAD_DECODE_OR_DIE("version-wrap");
457     KRB_DECODE_UINT32_OR_DIE("version", version);
458
459     if (kerberos_tree) {
460         proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
461                             "Version: %d",
462                             version);
463     }
464     offset += length;
465
466     /* message type */
467     KRB_HEAD_DECODE_OR_DIE("message-type-wrap");
468     KRB_DECODE_UINT32_OR_DIE("message-type", msg_type);
469
470     if (kerberos_tree) {
471         proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
472                             "MSG Type: %s",
473                             val_to_str(msg_type, krb5_msg_types,
474                                        "Unknown msg type %#x"));
475     }
476     offset += length;
477
478     if (check_col(fd, COL_INFO))
479         col_add_str(fd, COL_INFO, val_to_str(msg_type, krb5_msg_types,
480                                              "Unknown msg type %#x"));
481
482         /* is preauthentication present? */
483     KRB_HEAD_DECODE_OR_DIE("padata-or-body");
484     if (((protocol_message_type == KRB5_MSG_AS_REQ ||
485           protocol_message_type == KRB5_MSG_TGS_REQ) &&
486          tag == KRB5_KDC_REQ_PADATA) ||
487         ((protocol_message_type == KRB5_MSG_AS_REP ||
488           protocol_message_type == KRB5_MSG_TGS_REP) &&
489          tag == KRB5_KDC_REP_PADATA)) {
490         /* pre-authentication supplied */
491
492         if (tree) {
493             item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
494                                        item_len, "Pre-Authentication");
495             preauth_tree = proto_item_add_subtree(item, ett_preauth);
496         }
497
498         KRB_HEAD_DECODE_OR_DIE("sequence of pa-data");
499         start = asn1p->pointer + item_len;
500
501         while(start > asn1p->pointer) {
502             dissect_type_value_pair(asn1p, &offset,
503                                     &preauth_type, &item_len, &tmp_pos1,
504                                     &str, &str_len, &tmp_pos2);
505
506             if (preauth_tree) {
507                 proto_tree_add_text(preauth_tree, NullTVB, tmp_pos1,
508                                     item_len, "Type: %s",
509                                     val_to_str(preauth_type,
510                                                krb5_preauthentication_types,
511                                                "Unknown preauth type %#x"));
512                 proto_tree_add_text(preauth_tree, NullTVB, tmp_pos2,
513                                     str_len, "Value: %s",
514                                     bytes_to_str(str, str_len));
515             }
516         }
517         KRB_HEAD_DECODE_OR_DIE("message-body");
518     }
519
520     switch (protocol_message_type) {
521
522     case KRB5_MSG_AS_REQ:
523     case KRB5_MSG_TGS_REQ:
524 /*
525   AS-REQ ::=         [APPLICATION 10] KDC-REQ
526   TGS-REQ ::=        [APPLICATION 12] KDC-REQ
527     
528   KDC-REQ ::=        SEQUENCE {
529            pvno[1]               INTEGER,
530            msg-type[2]           INTEGER,
531            padata[3]             SEQUENCE OF PA-DATA OPTIONAL,
532            req-body[4]           KDC-REQ-BODY
533   }
534
535   KDC-REQ-BODY ::=   SEQUENCE {
536             kdc-options[0]       KDCOptions,
537             cname[1]             PrincipalName OPTIONAL,
538                          -- Used only in AS-REQ
539             realm[2]             Realm, -- Server's realm
540                          -- Also client's in AS-REQ
541             sname[3]             PrincipalName OPTIONAL,
542             from[4]              KerberosTime OPTIONAL,
543             till[5]              KerberosTime,
544             rtime[6]             KerberosTime OPTIONAL,
545             nonce[7]             INTEGER,
546             etype[8]             SEQUENCE OF INTEGER, -- EncryptionType,
547                          -- in preference order
548             addresses[9]         HostAddresses OPTIONAL,
549             enc-authorization-data[10]   EncryptedData OPTIONAL,
550                          -- Encrypted AuthorizationData encoding
551             additional-tickets[11]       SEQUENCE OF Ticket OPTIONAL
552   }
553
554 */
555         /* request body */
556         KRB_HEAD_DECODE_OR_DIE("body-sequence");
557         if (tree) {
558             item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
559                                        item_len, "Request");
560             request_tree = proto_item_add_subtree(item, ett_request);
561         }
562
563         /* kdc options */
564         KRB_HEAD_DECODE_OR_DIE("kdc options");
565
566         KRB_HEAD_DECODE_OR_DIE("kdc options:bits");
567
568         if (request_tree) {
569                 proto_tree_add_text(request_tree, NullTVB, offset, item_len,
570                                     "Options: %s",
571                                     bytes_to_str(asn1.pointer, item_len));
572         }
573         offset += item_len;
574         asn1.pointer += item_len;
575
576         KRB_HEAD_DECODE_OR_DIE("Client Name or Realm");
577
578         if (CHECK_CONTEXT_TYPE(KRB5_BODY_CNAME)) {
579             item_len = dissect_PrincipalName("Client Name", asn1p, fd,
580                                              request_tree, offset);
581             if (item_len == -1)
582                 return -1;
583             offset += item_len;
584             KRB_HEAD_DECODE_OR_DIE("Realm");
585         }
586
587         DIE_IF_NOT_CONTEXT_TYPE("Realm", KRB5_BODY_REALM);
588         KRB_DECODE_GENERAL_STRING_OR_DIE("Realm", str, str_len, item_len);
589         if (request_tree) {
590             proto_tree_add_text(request_tree, NullTVB, offset, item_len,
591                                 "Realm: %.*s", str_len, str);
592         }
593         offset += item_len;
594
595         KRB_HEAD_DECODE_OR_DIE("Server Name");
596         if (CHECK_CONTEXT_TYPE(KRB5_BODY_SNAME)) {
597             item_len = dissect_PrincipalName("Server Name", asn1p, fd,
598                                              request_tree, offset);
599             if (item_len == -1)
600                 return -1;
601             offset += item_len;
602             KRB_HEAD_DECODE_OR_DIE("From or Till");
603         }
604
605         if (CHECK_CONTEXT_TYPE(KRB5_BODY_FROM)) {
606             KRB_DECODE_GENERAL_TIME_OR_DIE("From", str, str_len, item_len);
607             krb_proto_tree_add_time(request_tree, offset, item_len,
608                                     "Start Time", str);
609             offset += item_len;
610             KRB_HEAD_DECODE_OR_DIE("Till");
611         }
612
613         DIE_IF_NOT_CONTEXT_TYPE("Till", KRB5_BODY_TILL);
614         KRB_DECODE_GENERAL_TIME_OR_DIE("Till", str, str_len, item_len);
615         krb_proto_tree_add_time(request_tree, offset, item_len,
616                                 "End Time", str);
617         offset += item_len;
618
619         KRB_HEAD_DECODE_OR_DIE("Renewable Until or Nonce");
620         if (CHECK_CONTEXT_TYPE(KRB5_BODY_RTIME)) {
621             KRB_DECODE_GENERAL_TIME_OR_DIE("Renewable Until", str, str_len, item_len);
622             krb_proto_tree_add_time(request_tree, offset, item_len,
623                                     "Renewable Until", str);
624             offset += item_len;
625             KRB_HEAD_DECODE_OR_DIE("Nonce");
626         }
627             
628         DIE_IF_NOT_CONTEXT_TYPE("Nonce", KRB5_BODY_NONCE);
629         KRB_DECODE_UINT32_OR_DIE("Nonce", tmp_int);
630         if (request_tree) {
631             proto_tree_add_text(request_tree, NullTVB, offset, length,
632                                 "Random Number: %u",
633                                 tmp_int);
634         }
635         offset += length;
636         
637         KRB_DECODE_CONTEXT_HEAD_OR_DIE("encryption type spot",
638                                               KRB5_BODY_ENCTYPE);
639         KRB_HEAD_DECODE_OR_DIE("encryption type list");
640         if (kerberos_tree) {
641             item = proto_tree_add_text(request_tree, NullTVB, offset,
642                                        item_len, "Encryption Types");
643             etype_tree = proto_item_add_subtree(item, ett_etype);
644         }
645         total_len = item_len;
646         while(total_len > 0) {
647             KRB_DECODE_UINT32_OR_DIE("encryption type", tmp_int);
648             if (etype_tree) {
649                 proto_tree_add_text(etype_tree, NullTVB, offset, length,
650                                     "Type: %s",
651                                     val_to_str(tmp_int,
652                                                krb5_encryption_types,
653                                                "Unknown encryption type %#x"));
654             }
655             offset += length;
656             total_len -= length;
657         }
658
659         KRB_HEAD_DECODE_OR_DIE("addresses");
660         if (CHECK_CONTEXT_TYPE(KRB5_BODY_ADDRESSES)) {
661             /* pre-authentication supplied */
662
663             offset = dissect_Addresses("Addresses", asn1p, fd, kerberos_tree,
664                                        offset);
665             if (offset == -1)
666                 return -1;
667             KRB_HEAD_DECODE_OR_DIE("auth-data");
668         }
669         break;
670
671     case KRB5_MSG_AS_REP:
672     case KRB5_MSG_TGS_REP:
673 /*
674    AS-REP ::=    [APPLICATION 11] KDC-REP
675    TGS-REP ::=   [APPLICATION 13] KDC-REP
676
677    KDC-REP ::=   SEQUENCE {
678                  pvno[0]                    INTEGER,
679                  msg-type[1]                INTEGER,
680                  padata[2]                  SEQUENCE OF PA-DATA OPTIONAL,
681                  crealm[3]                  Realm,
682                  cname[4]                   PrincipalName,
683                  ticket[5]                  Ticket,
684                  enc-part[6]                EncryptedData
685    }
686 */
687
688         if (tag == KRB5_KDC_REP_CREALM) {
689             KRB_DECODE_GENERAL_STRING_OR_DIE("realm name", str, str_len, item_len);
690             if (kerberos_tree) {
691                 proto_tree_add_text(kerberos_tree, NullTVB, offset, item_len,
692                                     "Realm: %.*s", str_len, str);
693             }
694             offset += item_len;
695         } else {
696             DIE_WITH_BAD_TYPE("crealm");
697         }
698
699         KRB_DECODE_CONTEXT_HEAD_OR_DIE("cname", KRB5_KDC_REP_CNAME);
700         item_len = dissect_PrincipalName("Client Name", asn1p, fd,
701                                          kerberos_tree, offset);
702         if (item_len == -1)
703             return -1;
704         offset += item_len;
705         
706         KRB_DECODE_CONTEXT_HEAD_OR_DIE("ticket", KRB5_KDC_REP_TICKET);
707         offset = dissect_Ticket("ticket", asn1p, fd, kerberos_tree, offset);
708         if (offset == -1)
709             return -1;
710
711         KRB_DECODE_CONTEXT_HEAD_OR_DIE("enc-msg-part",
712                                               KRB5_KDC_REP_ENC_PART);
713         offset = dissect_EncryptedData("Encrypted Payload", asn1p, fd,
714                                        kerberos_tree, offset);
715         if (offset == -1)
716             return -1;
717         break;
718     }
719     return offset;
720 }
721
722 static void
723 dissect_kerberos(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
724 {
725     OLD_CHECK_DISPLAY_AS_DATA(proto_kerberos, pd, offset, fd, tree);
726
727     if (check_col(fd, COL_PROTOCOL))
728         col_set_str(fd, COL_PROTOCOL, "KRB5");
729
730     dissect_kerberos_main(pd, offset, fd, tree);
731 }
732
733 static int
734 dissect_PrincipalName(char *title, ASN1_SCK *asn1p, frame_data *fd,
735                        proto_tree *tree, int start_offset)
736 {
737 /*
738    PrincipalName ::=   SEQUENCE {
739                        name-type[0]     INTEGER,
740                        name-string[1]   SEQUENCE OF GeneralString
741    }
742 */
743     proto_tree *princ_tree = NULL;
744     int offset = start_offset;
745
746     guint32 princ_type;
747
748     const guchar *start;
749     guint cls, con, tag;
750     guint header_len, item_len, total_len, type_len;
751     int ret;
752
753     proto_item *item = NULL;
754     guint length;
755     gboolean def;
756
757     int type_offset;
758
759     guchar *name;
760     guint name_len;
761
762     /* principal name */
763     KRB_SEQ_HEAD_DECODE_OR_DIE("principal section");
764
765     if (tree) {
766       item = proto_tree_add_text(tree, NullTVB, start_offset,
767                                  (offset - start_offset) + item_len, "%s",
768                                  title);
769       princ_tree = proto_item_add_subtree(item, ett_princ);
770     } else {
771       item = NULL;
772       princ_tree = NULL;
773     }
774
775     KRB_DECODE_CONTEXT_HEAD_OR_DIE("principal type", 0);
776     KRB_DECODE_UINT32_OR_DIE("princ-type", princ_type);
777     type_offset = offset;
778     type_len = item_len;
779     offset += length;
780
781     if (princ_tree) {
782       proto_tree_add_text(princ_tree, NullTVB, type_offset, type_len,
783                                                 "Type: %s",
784                                                 val_to_str(princ_type, krb5_princ_types,
785                                            "Unknown name type %#x"));
786     }
787
788     KRB_DECODE_CONTEXT_HEAD_OR_DIE("principal name-string", 1);
789     KRB_SEQ_HEAD_DECODE_OR_DIE("principal name-string sequence-of");
790     total_len = item_len;
791     if (total_len == 0) {
792       /* There are no name strings in this PrincipalName, so we can't
793          put any in the top-level item. */
794       return offset - start_offset;
795     }
796
797     /* Put the first name string in the top-level item. */
798     KRB_DECODE_GENERAL_STRING_OR_DIE("principal name", name, name_len, item_len);
799     if (princ_tree) {
800         proto_item_set_text(item, "%s: %.*s", title, (int) name_len, name);
801         proto_tree_add_text(princ_tree, NullTVB, offset, item_len,
802                             "Name: %.*s", (int) name_len, name);
803     }
804     total_len -= item_len;
805     offset += item_len;
806
807     /* Now process the rest of the strings.
808        XXX - put them in the item as well? */
809     while (total_len > 0) {
810         KRB_DECODE_GENERAL_STRING_OR_DIE("principal name", name, name_len, item_len);
811         if (princ_tree) {
812             proto_tree_add_text(princ_tree, NullTVB, offset, item_len,
813                                 "Name: %.*s", (int) name_len, name);
814         }
815         total_len -= item_len;
816         offset += item_len;
817     }
818     return offset - start_offset;
819 }
820
821 static int
822 dissect_Addresses(char *title, ASN1_SCK *asn1p, frame_data *fd,
823                   proto_tree *tree, int start_offset) {
824     proto_tree *address_tree = NULL;
825     int offset = start_offset;
826
827     const guchar *start;
828     guint cls, con, tag;
829     guint item_len;
830     int ret;
831
832     proto_item *item = NULL;
833     gboolean def;
834
835     int tmp_pos1, tmp_pos2;
836     guint32 address_type;
837
838     int str_len;
839     guchar *str;
840
841     KRB_HEAD_DECODE_OR_DIE("sequence of addresses");
842     if (tree) {
843         item = proto_tree_add_text(tree, NullTVB, offset,
844                                    item_len, "Addresses");
845         address_tree = proto_item_add_subtree(item, ett_addresses);
846     }
847
848     start = asn1p->pointer + item_len;
849
850     while(start > asn1p->pointer) {
851         dissect_type_value_pair(asn1p, &offset,
852                                 &address_type, &item_len, &tmp_pos1,
853                                 &str, &str_len, &tmp_pos2);
854
855         if (address_tree) {
856             proto_tree_add_text(address_tree, NullTVB, tmp_pos1,
857                                 item_len, "Type: %s",
858                                 val_to_str(address_type, krb5_address_types,
859                                            "Unknown address type %#x"));
860             switch(address_type) {
861                 case KRB5_ADDR_IPv4:
862                     proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
863                                         str_len, "Value: %d.%d.%d.%d",
864                                         str[0], str[1], str[2], str[3]);
865                     break;
866                     
867                 default:
868                     proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
869                                         str_len, "Value: %s",
870                                         bytes_to_str(str, str_len));
871             }
872         }
873     }
874     
875     return offset;
876 }
877
878 static int
879 dissect_EncryptedData(char *title, ASN1_SCK *asn1p, frame_data *fd,
880                       proto_tree *tree, int start_offset)
881 {
882 /*
883    EncryptedData ::=   SEQUENCE {
884                        etype[0]     INTEGER, -- EncryptionType
885                        kvno[1]      INTEGER OPTIONAL,
886                        cipher[2]    OCTET STRING -- ciphertext
887    }
888 */
889     proto_tree *encr_tree = NULL;
890     int offset = start_offset;
891
892     const guchar *start;
893     guint cls, con, tag;
894     guint header_len, item_len, data_len;
895     int ret;
896
897     proto_item *item = NULL;
898     guint length;
899     gboolean def;
900     guint32 val;
901
902     guchar *data;
903
904     KRB_SEQ_HEAD_DECODE_OR_DIE("encrypted data section");
905
906     if (tree) {
907         item = proto_tree_add_text(tree, NullTVB, start_offset,
908                                    (offset - start_offset) + item_len,
909                                    "Encrypted Data: %s", title);
910         encr_tree = proto_item_add_subtree(item, ett_princ);
911     }
912
913     /* type */
914     KRB_DECODE_CONTEXT_HEAD_OR_DIE("encryption type", 0);
915     KRB_DECODE_UINT32_OR_DIE("encr-type", val);
916     if (encr_tree) {
917         proto_tree_add_text(encr_tree, NullTVB, offset, length,
918                             "Type: %s",
919                             val_to_str(val, krb5_encryption_types,
920                                        "Unknown encryption type %#x"));
921     }
922     offset += length;
923
924     /* kvno */
925     KRB_HEAD_DECODE_OR_DIE("kvno-wrap or cipher-wrap");
926     if (CHECK_CONTEXT_TYPE(1)) {
927       KRB_DECODE_UINT32_OR_DIE("kvno", val);
928       if (encr_tree) {
929           proto_tree_add_text(encr_tree, NullTVB, offset, length,
930                               "KVNO: %d", val);
931       }
932       offset += length;
933       KRB_HEAD_DECODE_OR_DIE("cipher-wrap");
934     }
935
936     DIE_IF_NOT_CONTEXT_TYPE("cipher-wrap", 2);
937     KRB_DECODE_OCTET_STRING_OR_DIE("cipher", data, data_len, item_len);
938
939     if (encr_tree) {
940         proto_tree_add_text(encr_tree, NullTVB, offset, data_len,
941                             "CipherText: %s", bytes_to_str(data, item_len));
942     }
943     offset += data_len;
944     
945     return offset;
946 }
947
948 static int
949 dissect_Ticket(char *title, ASN1_SCK *asn1p, frame_data *fd, proto_tree *tree,
950                int start_offset)
951 {
952 /*
953    Ticket ::=                    [APPLICATION 1] SEQUENCE {
954                                  tkt-vno[0]                   INTEGER,
955                                  realm[1]                     Realm,
956                                  sname[2]                     PrincipalName,
957                                  enc-part[3]                  EncryptedData
958    }
959 */
960     proto_tree *ticket_tree = NULL;
961     int offset = start_offset;
962
963     const guchar *start;
964     guint cls, con, tag;
965     guint header_len, item_len, total_len;
966     int ret;
967
968     proto_item *item = NULL;
969     guint length;
970     gboolean def;
971     guint32 val;
972
973     int str_len;
974     guchar *str;
975
976     KRB_DECODE_APPLICATION_TAGGED_HEAD_OR_DIE("Ticket section", 1);
977     KRB_SEQ_HEAD_DECODE_OR_DIE("Ticket sequence");
978     total_len = item_len;
979
980     if (tree) {
981         item = proto_tree_add_text(tree, NullTVB, start_offset,
982                                    (offset - start_offset) + item_len,
983                                    "Ticket");
984         ticket_tree = proto_item_add_subtree(item, ett_ticket);
985     }
986
987     /* type */
988     KRB_DECODE_CONTEXT_HEAD_OR_DIE("Ticket tkt-vno", KRB5_TKT_TKT_VNO);
989     KRB_DECODE_UINT32_OR_DIE("Ticket tkt-vno", val);
990     if (ticket_tree) {
991         proto_tree_add_text(ticket_tree, NullTVB, offset, length,
992                             "Version: %u", val);
993     }
994     offset += length;
995     total_len -= length;
996
997     /* realm name */
998     KRB_DECODE_CONTEXT_HEAD_OR_DIE("Ticket realm", KRB5_TKT_REALM);
999     KRB_DECODE_GENERAL_STRING_OR_DIE("Ticket realm string", str, str_len, item_len);
1000     if (ticket_tree) {
1001         proto_tree_add_text(ticket_tree, NullTVB, offset, item_len,
1002                             "Realm: %.*s", str_len, str);
1003     }
1004     offset += item_len;
1005     total_len -= item_len;
1006
1007     /* server name (sname) */
1008     KRB_DECODE_CONTEXT_HEAD_OR_DIE("Ticket sname", KRB5_TKT_SNAME);
1009     item_len = dissect_PrincipalName("Service Name", asn1p, fd, ticket_tree,
1010                                      offset);
1011     if (item_len == -1)
1012         return -1;
1013     offset += item_len;
1014
1015     /* encrypted part */
1016     KRB_DECODE_CONTEXT_HEAD_OR_DIE("enc-part", KRB5_TKT_ENC_PART);
1017     offset = dissect_EncryptedData("Ticket data", asn1p, fd, ticket_tree,
1018                                    offset);
1019     if (offset == -1)
1020         return -1;
1021
1022     return offset;
1023 }
1024
1025
1026 void
1027 proto_register_kerberos(void) {
1028 /*
1029     static hf_register_info hf[] = {
1030     };
1031 */
1032     static gint *ett[] = {
1033         &ett_kerberos,
1034         &ett_preauth,
1035         &ett_request,
1036         &ett_princ,
1037         &ett_encrypted,
1038         &ett_ticket,
1039         &ett_addresses,
1040         &ett_etype,
1041     };
1042     proto_kerberos = proto_register_protocol("Kerberos", "kerberos");
1043 /*
1044     proto_register_field_array(proto_kerberos, hf, array_length(hf));
1045 */
1046     proto_register_subtree_array(ett, array_length(ett));
1047 }
1048
1049 void
1050 proto_reg_handoff_kerberos(void)
1051 {
1052         old_dissector_add("udp.port", UDP_PORT_KERBEROS, dissect_kerberos);
1053         old_dissector_add("tcp.port", TCP_PORT_KERBEROS, dissect_kerberos);
1054 }
1055
1056 /*
1057
1058   MISC definitions from RFC1510:
1059   
1060    Realm ::=           GeneralString
1061
1062    KerberosTime ::=   GeneralizedTime
1063
1064    HostAddress ::=    SEQUENCE  {
1065                       addr-type[0]             INTEGER,
1066                       address[1]               OCTET STRING
1067    }
1068
1069    HostAddresses ::=   SEQUENCE OF SEQUENCE {
1070                        addr-type[0]             INTEGER,
1071                        address[1]               OCTET STRING
1072    }
1073
1074    AuthorizationData ::=   SEQUENCE OF SEQUENCE {
1075                            ad-type[0]               INTEGER,
1076                            ad-data[1]               OCTET STRING
1077    }
1078                    APOptions ::=   BIT STRING {
1079                                    reserved(0),
1080                                    use-session-key(1),
1081                                    mutual-required(2)
1082                    }
1083
1084
1085                    TicketFlags ::=   BIT STRING {
1086                                      reserved(0),
1087                                      forwardable(1),
1088                                      forwarded(2),
1089                                      proxiable(3),
1090                                      proxy(4),
1091                                      may-postdate(5),
1092                                      postdated(6),
1093                                      invalid(7),
1094                                      renewable(8),
1095                                      initial(9),
1096                                      pre-authent(10),
1097                                      hw-authent(11)
1098                    }
1099
1100                   KDCOptions ::=   BIT STRING {
1101                                    reserved(0),
1102                                    forwardable(1),
1103                                    forwarded(2),
1104                                    proxiable(3),
1105                                    proxy(4),
1106                                    allow-postdate(5),
1107                                    postdated(6),
1108                                    unused7(7),
1109                                    renewable(8),
1110                                    unused9(9),
1111                                    unused10(10),
1112                                    unused11(11),
1113                                    renewable-ok(27),
1114                                    enc-tkt-in-skey(28),
1115                                    renew(30),
1116                                    validate(31)
1117                   }
1118
1119
1120             LastReq ::=   SEQUENCE OF SEQUENCE {
1121                           lr-type[0]               INTEGER,
1122                           lr-value[1]              KerberosTime
1123             }
1124
1125    Ticket ::=                    [APPLICATION 1] SEQUENCE {
1126                                  tkt-vno[0]                   INTEGER,
1127                                  realm[1]                     Realm,
1128                                  sname[2]                     PrincipalName,
1129                                  enc-part[3]                  EncryptedData
1130    }
1131
1132   -- Encrypted part of ticket
1133   EncTicketPart ::=     [APPLICATION 3] SEQUENCE {
1134                         flags[0]             TicketFlags,
1135                         key[1]               EncryptionKey,
1136                         crealm[2]            Realm,
1137                         cname[3]             PrincipalName,
1138                         transited[4]         TransitedEncoding,
1139                         authtime[5]          KerberosTime,
1140                         starttime[6]         KerberosTime OPTIONAL,
1141                         endtime[7]           KerberosTime,
1142                         renew-till[8]        KerberosTime OPTIONAL,
1143                         caddr[9]             HostAddresses OPTIONAL,
1144                         authorization-data[10]   AuthorizationData OPTIONAL
1145   }
1146
1147   -- encoded Transited field
1148   TransitedEncoding ::=         SEQUENCE {
1149                                 tr-type[0]  INTEGER, -- must be registered
1150                                 contents[1]          OCTET STRING
1151   }
1152
1153   -- Unencrypted authenticator
1154   Authenticator ::=    [APPLICATION 2] SEQUENCE    {
1155                  authenticator-vno[0]          INTEGER,
1156                  crealm[1]                     Realm,
1157                  cname[2]                      PrincipalName,
1158                  cksum[3]                      Checksum OPTIONAL,
1159                  cusec[4]                      INTEGER,
1160                  ctime[5]                      KerberosTime,
1161                  subkey[6]                     EncryptionKey OPTIONAL,
1162                  seq-number[7]                 INTEGER OPTIONAL,
1163                  authorization-data[8]         AuthorizationData OPTIONAL
1164   }
1165
1166   PA-DATA ::=        SEQUENCE {
1167            padata-type[1]        INTEGER,
1168            padata-value[2]       OCTET STRING,
1169                          -- might be encoded AP-REQ
1170   }
1171
1172    padata-type     ::= PA-ENC-TIMESTAMP
1173    padata-value    ::= EncryptedData -- PA-ENC-TS-ENC
1174
1175    PA-ENC-TS-ENC   ::= SEQUENCE {
1176            patimestamp[0]               KerberosTime, -- client's time
1177            pausec[1]                    INTEGER OPTIONAL
1178    }
1179
1180    EncASRepPart ::=    [APPLICATION 25[25]] EncKDCRepPart
1181    EncTGSRepPart ::=   [APPLICATION 26] EncKDCRepPart
1182
1183    EncKDCRepPart ::=   SEQUENCE {
1184                key[0]                       EncryptionKey,
1185                last-req[1]                  LastReq,
1186                nonce[2]                     INTEGER,
1187                key-expiration[3]            KerberosTime OPTIONAL,
1188                flags[4]                     TicketFlags,
1189                authtime[5]                  KerberosTime,
1190                starttime[6]                 KerberosTime OPTIONAL,
1191                endtime[7]                   KerberosTime,
1192                renew-till[8]                KerberosTime OPTIONAL,
1193                srealm[9]                    Realm,
1194                sname[10]                    PrincipalName,
1195                caddr[11]                    HostAddresses OPTIONAL
1196    }
1197
1198    AP-REQ ::=      [APPLICATION 14] SEQUENCE {
1199                    pvno[0]                       INTEGER,
1200                    msg-type[1]                   INTEGER,
1201                    ap-options[2]                 APOptions,
1202                    ticket[3]                     Ticket,
1203                    authenticator[4]              EncryptedData
1204    }
1205
1206    APOptions ::=   BIT STRING {
1207                    reserved(0),
1208                    use-session-key(1),
1209                    mutual-required(2)
1210    }
1211
1212    AP-REP ::=         [APPLICATION 15] SEQUENCE {
1213               pvno[0]                   INTEGER,
1214               msg-type[1]               INTEGER,
1215               enc-part[2]               EncryptedData
1216    }
1217
1218    EncAPRepPart ::=   [APPLICATION 27]     SEQUENCE {
1219               ctime[0]                  KerberosTime,
1220               cusec[1]                  INTEGER,
1221               subkey[2]                 EncryptionKey OPTIONAL,
1222               seq-number[3]             INTEGER OPTIONAL
1223    }
1224
1225    KRB-SAFE ::=        [APPLICATION 20] SEQUENCE {
1226                pvno[0]               INTEGER,
1227                msg-type[1]           INTEGER,
1228                safe-body[2]          KRB-SAFE-BODY,
1229                cksum[3]              Checksum
1230    }
1231
1232    KRB-SAFE-BODY ::=   SEQUENCE {
1233                user-data[0]          OCTET STRING,
1234                timestamp[1]          KerberosTime OPTIONAL,
1235                usec[2]               INTEGER OPTIONAL,
1236                seq-number[3]         INTEGER OPTIONAL,
1237                s-address[4]          HostAddress,
1238                r-address[5]          HostAddress OPTIONAL
1239    }
1240
1241    KRB-PRIV ::=         [APPLICATION 21] SEQUENCE {
1242                 pvno[0]                   INTEGER,
1243                 msg-type[1]               INTEGER,
1244                 enc-part[3]               EncryptedData
1245    }
1246
1247    EncKrbPrivPart ::=   [APPLICATION 28] SEQUENCE {
1248                 user-data[0]              OCTET STRING,
1249                 timestamp[1]              KerberosTime OPTIONAL,
1250                 usec[2]                   INTEGER OPTIONAL,
1251                 seq-number[3]             INTEGER OPTIONAL,
1252                 s-address[4]              HostAddress, -- sender's addr
1253                 r-address[5]              HostAddress OPTIONAL
1254                                                       -- recip's addr
1255    }
1256
1257    KRB-CRED         ::= [APPLICATION 22]   SEQUENCE {
1258                     pvno[0]                INTEGER,
1259                     msg-type[1]            INTEGER, -- KRB_CRED
1260                     tickets[2]             SEQUENCE OF Ticket,
1261                     enc-part[3]            EncryptedData
1262    }
1263
1264    EncKrbCredPart   ::= [APPLICATION 29]   SEQUENCE {
1265                     ticket-info[0]         SEQUENCE OF KrbCredInfo,
1266                     nonce[1]               INTEGER OPTIONAL,
1267                     timestamp[2]           KerberosTime OPTIONAL,
1268                     usec[3]                INTEGER OPTIONAL,
1269                     s-address[4]           HostAddress OPTIONAL,
1270                     r-address[5]           HostAddress OPTIONAL
1271    }
1272
1273    KrbCredInfo      ::=                    SEQUENCE {
1274                     key[0]                 EncryptionKey,
1275                     prealm[1]              Realm OPTIONAL,
1276                     pname[2]               PrincipalName OPTIONAL,
1277                     flags[3]               TicketFlags OPTIONAL,
1278                     authtime[4]            KerberosTime OPTIONAL,
1279                     starttime[5]           KerberosTime OPTIONAL,
1280                     endtime[6]             KerberosTime OPTIONAL
1281                     renew-till[7]          KerberosTime OPTIONAL,
1282                     srealm[8]              Realm OPTIONAL,
1283                     sname[9]               PrincipalName OPTIONAL,
1284                     caddr[10]              HostAddresses OPTIONAL
1285    }
1286
1287    KRB-ERROR ::=   [APPLICATION 30] SEQUENCE {
1288                    pvno[0]               INTEGER,
1289                    msg-type[1]           INTEGER,
1290                    ctime[2]              KerberosTime OPTIONAL,
1291                    cusec[3]              INTEGER OPTIONAL,
1292                    stime[4]              KerberosTime,
1293                    susec[5]              INTEGER,
1294                    error-code[6]         INTEGER,
1295                    crealm[7]             Realm OPTIONAL,
1296                    cname[8]              PrincipalName OPTIONAL,
1297                    realm[9]              Realm, -- Correct realm
1298                    sname[10]             PrincipalName, -- Correct name
1299                    e-text[11]            GeneralString OPTIONAL,
1300                    e-data[12]            OCTET STRING OPTIONAL
1301    }
1302
1303    e-data    This field contains additional data about the error for use
1304              by the application to help it recover from or handle the
1305              error.  If the errorcode is KDC_ERR_PREAUTH_REQUIRED, then
1306              the e-data field will contain an encoding of a sequence of
1307              padata fields, each corresponding to an acceptable pre-
1308              authentication method and optionally containing data for
1309              the method:
1310
1311       METHOD-DATA ::=    SEQUENCE of PA-DATA
1312
1313    If the error-code is KRB_AP_ERR_METHOD, then the e-data field will
1314    contain an encoding of the following sequence:
1315
1316       METHOD-DATA ::=    SEQUENCE {
1317                          method-type[0]   INTEGER,
1318                          method-data[1]   OCTET STRING OPTIONAL
1319        }
1320
1321           EncryptionKey ::=   SEQUENCE {
1322                               keytype[0]    INTEGER,
1323                               keyvalue[1]   OCTET STRING
1324           }
1325
1326             Checksum ::=   SEQUENCE {
1327                            cksumtype[0]   INTEGER,
1328                            checksum[1]    OCTET STRING
1329             }
1330
1331 */