Fix up a bunch of arguments to "dissect_ber_identifier()" to match its
[obnox/wireshark/wip.git] / epan / dissectors / packet-spnego.c
1 /* packet-spnego.c
2  * Routines for the simple and protected GSS-API negotiation mechanism
3  * as described in RFC 2478.
4  * Copyright 2002, Tim Potter <tpot@samba.org>
5  * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
6  * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
7  * Copyright 2005, Ronnie Sahlberg (krb decryption)
8  *
9  * $Id$
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  */
29 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
30    Heimdal 1.6 and has been modified for ethereal's requirements.
31 */
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #include <string.h>
41 #include <glib.h>
42 #include <epan/packet.h>
43
44 #include <epan/asn1.h>
45 #include "format-oid.h"
46 #include "packet-ber.h"
47 #include "packet-dcerpc.h"
48 #include "packet-gssapi.h"
49 #include "packet-kerberos.h"
50 #include <epan/crypt-rc4.h>
51 #include <epan/conversation.h>
52
53 #define SPNEGO_negTokenInit 0
54 #define SPNEGO_negTokenTarg 1
55 #define SPNEGO_mechTypes 0
56 #define SPNEGO_reqFlags 1
57 #define SPNEGO_mechToken 2
58 #define SPNEGO_mechListMIC 3
59 #define SPNEGO_negResult 0
60 #define SPNEGO_supportedMech 1
61 #define SPNEGO_responseToken 2
62 #define SPNEGO_negResult_accept_completed 0
63 #define SPNEGO_negResult_accept_incomplete 1
64 #define SPNEGO_negResult_accept_reject 2
65
66 static int proto_spnego = -1;
67 static int proto_spnego_krb5 = -1;
68
69 static int hf_spnego = -1;
70 static int hf_spnego_mech = -1;
71 static int hf_spnego_this_mech = -1;
72 static int hf_spnego_negtokeninit = -1;
73 static int hf_spnego_negtokentarg = -1;
74 static int hf_spnego_mechtype = -1;
75 static int hf_spnego_mechtoken = -1;
76 static int hf_spnego_negtokentarg_negresult = -1;
77 static int hf_spnego_mechlistmic = -1;
78 static int hf_spnego_responsetoken = -1;
79 static int hf_spnego_reqflags = -1;
80 static int hf_spnego_wraptoken = -1;
81 static int hf_spnego_krb5 = -1;
82 static int hf_spnego_krb5_tok_id = -1;
83 static int hf_spnego_krb5_sgn_alg = -1;
84 static int hf_spnego_krb5_seal_alg = -1;
85 static int hf_spnego_krb5_snd_seq = -1;
86 static int hf_spnego_krb5_sgn_cksum = -1;
87 static int hf_spnego_krb5_confounder = -1;
88 static int hf_gssapi_reqflags_deleg = -1;
89 static int hf_gssapi_reqflags_mutual = -1;
90 static int hf_gssapi_reqflags_replay = -1;
91 static int hf_gssapi_reqflags_sequence = -1;
92 static int hf_gssapi_reqflags_anon = -1;
93 static int hf_gssapi_reqflags_conf = -1;
94 static int hf_gssapi_reqflags_integ = -1;
95
96 static gint ett_spnego = -1;
97 static gint ett_spnego_negtokeninit = -1;
98 static gint ett_spnego_negtokentarg = -1;
99 static gint ett_spnego_mechtype = -1;
100 static gint ett_spnego_mechtoken = -1;
101 static gint ett_spnego_mechlistmic = -1;
102 static gint ett_spnego_responsetoken = -1;
103 static gint ett_spnego_wraptoken = -1;
104 static gint ett_spnego_krb5 = -1;
105 static gint ett_spnego_reqflags = -1;
106
107 static const value_string spnego_negResult_vals[] = {
108   { SPNEGO_negResult_accept_completed,   "Accept Completed" },
109   { SPNEGO_negResult_accept_incomplete,  "Accept Incomplete" },
110   { SPNEGO_negResult_accept_reject,      "Accept Reject"},
111   { 0, NULL}
112 };
113
114 /*
115  * These should be in the GSSAPI dissector ... XXX
116  */
117
118 static const true_false_string tfs_reqflags_deleg = {
119   "Delegation Requested",
120   "Delegation NOT Requested"
121 };
122
123 static const true_false_string tfs_reqflags_mutual = {
124   "Mutual Authentication Requested",
125   "Mutual Authentication NOT Requested"
126 };
127
128 static const true_false_string tfs_reqflags_replay = {
129   "Replay Detection Requested",
130   "Replay Detection NOT Requested"
131 };
132
133 static const true_false_string tfs_reqflags_sequence = {
134   "Out-of-sequence Detection Requested",
135   "Out-of-sequence Detection NOT Requested"
136 };
137
138 static const true_false_string tfs_reqflags_anon = {
139   "Anonymous Authentication Requested",
140   "Anonymous Authentication NOT Requested"
141 };
142
143 static const true_false_string tfs_reqflags_conf = {
144   "Per-message Confidentiality Requested",
145   "Per-message Confidentiality NOT Requested"
146 };
147
148 static const true_false_string tfs_reqflags_integ = {
149   "Per-message Integrity Requested",
150   "Per-message Integrity NOT Requested"
151 };
152
153 /*
154  * This takes an OID in binary form, not an OID as a text string, as
155  * an argument.
156  */
157 static gssapi_oid_value *
158 gssapi_lookup_oid(subid_t *oid, guint oid_len)
159 {
160         gchar *oid_key;
161         gchar *p;
162         unsigned int i;
163         int len;
164         gssapi_oid_value *value;
165
166         /*
167          * Convert the OID to a string, as text strings are used as
168          * keys in the OID hash table.
169          */
170         oid_key = g_malloc(oid_len * 22 + 1);
171         p = oid_key;
172         len = sprintf(p, "%lu", (unsigned long)oid[0]);
173         p += len;
174         for (i = 1; i < oid_len;i++) {
175                 len = sprintf(p, ".%lu", (unsigned long)oid[i]);
176                 p += len;
177         }
178
179         value = gssapi_lookup_oid_str(oid_key);
180         g_free(oid_key);
181         return value;
182 }
183
184
185 /* Display an ASN1 parse error.  Taken from packet-snmp.c */
186
187 static dissector_handle_t data_handle;
188
189 static dissector_handle_t
190 gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
191         if (next_level_value == NULL) {
192                 return NULL;
193         }
194         return next_level_value->handle;
195 }
196
197 static void
198 dissect_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
199                     proto_tree *tree, const char *field_name, int ret)
200 {
201         char *errstr;
202
203         errstr = asn1_err_to_str(ret);
204
205         if (tree != NULL) {
206                 proto_tree_add_text(tree, tvb, offset, 0,
207                     "ERROR: Couldn't parse %s: %s", field_name, errstr);
208                 call_dissector(data_handle,
209                     tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
210         }
211 }
212
213 /*
214  * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
215  * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also 
216  * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
217  */ 
218
219 #define KRB_TOKEN_AP_REQ                0x0001
220 #define KRB_TOKEN_AP_REP                0x0002
221 #define KRB_TOKEN_AP_ERR                0x0003
222 #define KRB_TOKEN_GETMIC                0x0101
223 #define KRB_TOKEN_WRAP                  0x0102
224 #define KRB_TOKEN_DELETE_SEC_CONTEXT    0x0201
225
226 static const value_string spnego_krb5_tok_id_vals[] = {
227   { KRB_TOKEN_AP_REQ,             "KRB5_AP_REQ"},
228   { KRB_TOKEN_AP_REP,             "KRB5_AP_REP"},
229   { KRB_TOKEN_AP_ERR,             "KRB5_ERROR"},
230   { KRB_TOKEN_GETMIC,             "KRB5_GSS_GetMIC" },
231   { KRB_TOKEN_WRAP,               "KRB5_GSS_Wrap" },
232   { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
233   { 0, NULL}
234 };
235
236 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
237 #define KRB_SGN_ALG_MD2_5       0x0001
238 #define KRB_SGN_ALG_DES_MAC     0x0002
239 #define KRB_SGN_ALG_HMAC        0x0011
240
241 static const value_string spnego_krb5_sgn_alg_vals[] = {
242   { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
243   { KRB_SGN_ALG_MD2_5,       "MD2.5"},
244   { KRB_SGN_ALG_DES_MAC,     "DES MAC"},
245   { KRB_SGN_ALG_HMAC,        "HMAC"},
246   { 0, NULL}
247 };
248
249 #define KRB_SEAL_ALG_DES_CBC    0x0000
250 #define KRB_SEAL_ALG_RC4        0x0010
251 #define KRB_SEAL_ALG_NONE       0xffff
252
253 static const value_string spnego_krb5_seal_alg_vals[] = {
254   { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
255   { KRB_SEAL_ALG_RC4,     "RC4"},
256   { KRB_SEAL_ALG_NONE,    "None"},
257   { 0, NULL}
258 };
259
260 /*
261  * XXX - is this for SPNEGO or just GSS-API?
262  * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
263  * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
264  * than designating SPNEGO as the mechanism, offering Kerberos V5, and
265  * getting it accepted.
266  */
267 static int
268 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
269 static int
270 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
271
272 static void
273 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
274 {
275         proto_item *item;
276         proto_tree *subtree;
277         int ret, offset = 0;
278         ASN1_SCK hnd;
279         gboolean def;
280         guint len1, cls, con, tag, oid_len, nbytes;
281         guint16 token_id;
282         subid_t *oid;
283         gchar *oid_string;
284         gssapi_oid_value *value;
285         tvbuff_t *krb5_tvb;
286
287         item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset, 
288                                    -1, FALSE);
289
290         subtree = proto_item_add_subtree(item, ett_spnego_krb5);
291
292         /*
293          * The KRB5 blob conforms to RFC1964:
294          * [APPLICATION 0] {
295          *   OID,
296          *   USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
297          *   OCTET STRING } 
298          *
299          * However, for some protocols, the KRB5 blob starts at the SHORT
300          * and has no DER encoded header etc.
301          *
302          * It appears that for some other protocols the KRB5 blob is just
303          * a Kerberos message, with no [APPLICATION 0] header, no OID,
304          * and no USHORT.
305          *
306          * So:
307          *
308          *      If we see an [APPLICATION 0] HEADER, we show the OID and
309          *      the USHORT, and then dissect the rest as a Kerberos message.
310          *
311          *      If we see an [APPLICATION 14] or [APPLICATION 15] header,
312          *      we assume it's an AP-REQ or AP-REP message, and dissect
313          *      it all as a Kerberos message.
314          *
315          *      Otherwise, we show the USHORT, and then dissect the rest
316          *      as a Kerberos message.
317          */
318
319         asn1_open(&hnd, tvb, offset);
320
321         /*
322          * Get the first header ...
323          */
324
325         ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
326
327         if (ret != ASN1_ERR_NOERROR) {
328                 dissect_parse_error(tvb, offset, pinfo, subtree,
329                                     "SPNEGO KRB5 Header", ret);
330                 goto done;
331         }
332
333         if (cls == ASN1_APL && con == ASN1_CON) {
334             /*
335              * [APPLICATION <tag>]
336              */
337             switch (tag) {
338
339             case 0:
340                 /*
341                  * [APPLICATION 0]
342                  */
343
344                 offset = hnd.offset;
345
346                 /* Next, the OID */
347
348                 ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
349
350                 if (ret != ASN1_ERR_NOERROR) {
351                     dissect_parse_error(tvb, offset, pinfo, subtree,
352                                         "SPNEGO supportedMech token", ret);
353                     goto done;
354                 }
355
356                 oid_string = format_oid(oid, oid_len);
357
358                 value = gssapi_lookup_oid(oid, oid_len);
359
360                 if (value) 
361                     proto_tree_add_text(subtree, tvb, offset, nbytes, 
362                                         "OID: %s (%s)",
363                                         oid_string, value->comment);
364                 else
365                     proto_tree_add_text(subtree, tvb, offset, nbytes,
366                                         "OID: %s",
367                                         oid_string);
368           
369                 g_free(oid_string);
370
371                 offset += nbytes;
372
373                 /* Next, the token ID ... */
374
375                 token_id = tvb_get_letohs(tvb, offset);
376                 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
377                                     token_id);
378
379                 hnd.offset += 2;
380
381                 offset += 2;
382
383                 break;
384
385             case 14:    /* [APPLICATION 14] */
386             case 15:    /* [APPLICATION 15] */
387                 /*
388                  * No token ID - just dissect as a Kerberos message and
389                  * return.
390                  */
391                 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1); 
392                 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
393                 return;
394
395             default:
396                 proto_tree_add_text(subtree, tvb, offset, 0,
397                         "Unknown header (cls=%d, con=%d, tag=%d)",
398                         cls, con, tag);
399                 goto done;
400             }
401         } else {
402             /* Next, the token ID ... */
403
404             token_id = tvb_get_letohs(tvb, offset);
405             proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
406                                 token_id);
407
408             hnd.offset += 2;
409
410             offset += 2;
411         }
412
413         switch (token_id) {
414
415         case KRB_TOKEN_AP_REQ:
416         case KRB_TOKEN_AP_REP:
417         case KRB_TOKEN_AP_ERR:
418           krb5_tvb = tvb_new_subset(tvb, offset, -1, -1); 
419           offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
420           break;
421
422         case KRB_TOKEN_GETMIC:
423           offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree); 
424           break;
425
426         case KRB_TOKEN_WRAP:
427           offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
428           break;
429
430         case KRB_TOKEN_DELETE_SEC_CONTEXT:
431
432           break;
433
434         default:
435
436           break;
437         }
438
439  done:
440         return;
441 }
442
443 #ifdef HAVE_KERBEROS
444 #include <epan/crypt-md5.h>
445
446 #ifndef KEYTYPE_ARCFOUR_56
447 # define KEYTYPE_ARCFOUR_56 24
448 #endif
449 /* XXX - We should probably do a configure-time check for this instead */
450 #ifndef KRB5_KU_USAGE_SEAL
451 # define KRB5_KU_USAGE_SEAL 22
452 #endif
453
454 static int
455 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
456                 void *cksum_data, size_t cksum_size,
457                 void *key6_data)
458 {
459     char k5_data[16];
460     char T[4];
461
462     memset(T, 0, 4);
463
464     if (key_type == KEYTYPE_ARCFOUR_56) {
465         char L40[14] = "fortybits";
466
467         memcpy(L40 + 10, T, sizeof(T));
468         md5_hmac(
469                 L40, 14,  
470                 key_data,
471                 key_size, 
472                 k5_data);
473         memset(&k5_data[7], 0xAB, 9);
474     } else {
475         md5_hmac(
476                 T, 4,  
477                 key_data,
478                 key_size,
479                 k5_data);
480     }
481
482     md5_hmac(
483         cksum_data, cksum_size,  
484         k5_data,
485         16, 
486         key6_data);
487
488     return 0;
489 }
490
491 static int
492 usage2arcfour(int usage)
493 {
494     switch (usage) {
495     case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
496     case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
497         return 8;
498     case 22: /*KRB5_KU_USAGE_SEAL 22 */
499         return 13;
500     case 23: /*KRB5_KU_USAGE_SIGN 23 */
501         return 15;
502     case 24: /*KRB5_KU_USAGE_SEQ 24 */
503         return 0;
504     default :
505         return 0;
506     }
507 }
508
509 static int
510 arcfour_mic_cksum(char *key_data, int key_length,
511                   unsigned usage,
512                   u_char sgn_cksum[8],
513                   const char *v1, size_t l1,
514                   const void *v2, size_t l2,
515                   const void *v3, size_t l3)
516 {
517     const char signature[] = "signaturekey";
518     char ksign_c[16];
519     unsigned char t[4];
520     md5_state_t ms;
521     unsigned char digest[16];
522     int rc4_usage;
523     char cksum[16];
524     
525     rc4_usage=usage2arcfour(usage);
526     md5_hmac(signature, sizeof(signature), 
527                 key_data, key_length, 
528                 ksign_c);
529     md5_init(&ms);
530     t[0] = (rc4_usage >>  0) & 0xFF;
531     t[1] = (rc4_usage >>  8) & 0xFF;
532     t[2] = (rc4_usage >> 16) & 0xFF;
533     t[3] = (rc4_usage >> 24) & 0xFF;
534     md5_append(&ms, t, 4);
535     md5_append(&ms, v1, l1);
536     md5_append(&ms, v2, l2);
537     md5_append(&ms, v3, l3);
538     md5_finish(&ms, digest);
539     md5_hmac(digest, 16, ksign_c, 16, cksum);
540
541     memcpy(sgn_cksum, cksum, 8);
542
543     return 0;
544 }
545
546 /*
547  * Verify padding of a gss wrapped message and return its length.
548  */
549 static int
550 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length, 
551                    size_t datalen,
552                    size_t *padlen)
553 {
554     unsigned char *pad;
555     size_t padlength;
556     int i;
557
558     pad = wrapped_data + wrapped_length - 1;
559     padlength = *pad;
560
561     if (padlength > datalen)
562         return 1;
563
564     for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
565         ;
566     if (i != 0)
567         return 2;
568
569     *padlen = padlength;
570
571     return 0;
572 }
573
574 static int
575 decrypt_arcfour(packet_info *pinfo,
576          char *input_message_buffer,
577          char *output_message_buffer,
578          char *key_value, int key_size, int key_type)
579 {
580     unsigned char Klocaldata[16];
581     int ret;
582     int32_t seq_number;
583     size_t datalen;
584     char k6_data[16], SND_SEQ[8], Confounder[8];
585     char cksum_data[8];
586     int cmp;
587     int conf_flag;
588     size_t padlen = 0;
589
590     datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
591
592     if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
593         conf_flag=1;
594     } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
595         conf_flag=0;
596     } else {
597         return -3;
598     }
599
600     if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
601         return -4;
602     }
603
604     ret = arcfour_mic_key(key_value, key_size, key_type,
605                           (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
606                           8, /* SGN_CKSUM */
607                           k6_data);
608     if (ret) {
609         return -5;
610     }
611
612     {
613         rc4_state_struct rc4_state;
614         
615         crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
616         memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
617         crypt_rc4(&rc4_state, SND_SEQ, 8);
618
619         memset(k6_data, 0, sizeof(k6_data));
620     }
621
622     seq_number=g_ntohl(*((guint32 *)SND_SEQ));
623
624     cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
625     if(cmp){
626         cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
627     }
628
629     if (cmp != 0) {
630         return -6;
631     }
632
633     {
634         int i;
635
636         for (i = 0; i < 16; i++)
637             Klocaldata[i] = ((u_char *)key_value)[i] ^ 0xF0;
638     }
639     ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
640                           SND_SEQ, 4,
641                           k6_data);
642     memset(Klocaldata, 0, sizeof(Klocaldata));
643     if (ret) {
644         return -7;
645     }
646
647     if(conf_flag) {
648         rc4_state_struct rc4_state;
649
650         crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
651         memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
652         crypt_rc4(&rc4_state, Confounder, 8);
653         memcpy(output_message_buffer, input_message_buffer, datalen);
654         crypt_rc4(&rc4_state, output_message_buffer, datalen);
655     } else {
656         memcpy(Confounder, 
657                 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 
658                 8); /* Confounder */
659         memcpy(output_message_buffer, 
660                 input_message_buffer, 
661                 datalen);
662     }
663     memset(k6_data, 0, sizeof(k6_data));
664
665     /* only normal (i.e. non DCE style  wrapping use padding ? */
666     if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
667         ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
668         if (ret) {
669             return -9;
670         }
671         datalen -= padlen;
672     }
673
674     /* dont know what the checksum looks like for dce style gssapi */
675     if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
676         ret = arcfour_mic_cksum(key_value, key_size,
677                             KRB5_KU_USAGE_SEAL,
678                             cksum_data, 
679                             tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
680                             Confounder, sizeof(Confounder),
681                             output_message_buffer, 
682                             datalen + padlen);
683         if (ret) {
684             return -10;
685         }
686
687         cmp = memcmp(cksum_data, 
688             tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
689             8); /* SGN_CKSUM */
690         if (cmp) {
691             return -11;
692         }
693     }
694
695     return datalen;
696 }
697
698
699
700 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
701
702 static void
703 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
704 {
705         int ret;
706         enc_key_t *ek;
707         int length;
708         const guint8 *original_data;
709
710         static int omb_index=0;
711         static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
712         static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
713         guint8 *output_message_buffer;
714
715         omb_index++;
716         if(omb_index>=4){
717                 omb_index=0;
718         }
719         output_message_buffer=omb_arr[omb_index];
720
721
722         length=tvb_length(pinfo->gssapi_encrypted_tvb);
723         original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
724
725         /* dont do anything if we are not attempting to decrypt data */
726 /*
727         if(!krb_decrypt){
728                 return;
729         }
730 */
731         /* XXX we should only do this for first time, then store somewhere */
732         /* XXX We also need to re-read the keytab when the preference changes */
733
734         if(cryptocopy){
735                 g_free(cryptocopy);
736                 cryptocopy=NULL;
737         }               
738         cryptocopy=g_malloc(length);
739         if(output_message_buffer){
740                 g_free(output_message_buffer);
741                 output_message_buffer=NULL;
742         }
743         output_message_buffer=g_malloc(length);
744
745         for(ek=enc_key_list;ek;ek=ek->next){
746                 /* shortcircuit and bail out if enctypes are not matching */
747                 if(ek->keytype!=keytype){
748                         continue;
749                 }
750
751                 /* pre-0.6.1 versions of Heimdal would sometimes change
752                   the cryptotext data even when the decryption failed.
753                   This would obviously not work since we iterate over the
754                   keys. So just give it a copy of the crypto data instead.
755                   This has been seen for RC4-HMAC blobs.
756                 */
757                 memcpy(cryptocopy, original_data, length);
758                 ret=decrypt_arcfour(pinfo,
759                                 cryptocopy,
760                                 output_message_buffer,
761                                 ek->keyvalue,
762                                 ek->keylength,
763                                 ek->keytype
764                                             );
765                 if (ret >= 0) {
766                         proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
767                         pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
768                                 output_message_buffer,
769                                 ret, ret);
770                         tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
771                         add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
772                         return;
773                 }
774         }
775         return;
776 }
777 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
778
779
780 #endif
781
782 /*
783  * XXX - This is for GSSAPI Wrap tokens ...
784  */
785 static int
786 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
787 #ifndef HAVE_KERBEROS
788         _U_
789 #endif
790     , proto_tree *tree, guint16 token_id
791 #ifndef HAVE_KERBEROS
792         _U_
793 #endif
794     )
795 {
796         guint16 sgn_alg, seal_alg;
797 #ifdef HAVE_KERBEROS
798         int start_offset=offset;
799 #endif
800
801         /*
802          * The KRB5 blob conforms to RFC1964:
803          *   USHORT (0x0102 == GSS_Wrap)
804          *   and so on } 
805          */
806
807         /* Now, the sign and seal algorithms ... */
808
809         sgn_alg = tvb_get_letohs(tvb, offset);
810         proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
811                             sgn_alg);
812
813         offset += 2;
814
815         seal_alg = tvb_get_letohs(tvb, offset);
816         proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
817                             seal_alg);
818
819         offset += 2;
820
821         /* Skip the filler */
822
823         offset += 2;
824
825         /* Encrypted sequence number */
826
827         proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
828                             TRUE);
829
830         offset += 8;
831
832         /* Checksum of plaintext padded data */
833
834         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
835                             TRUE);
836
837         offset += 8;
838
839         /*
840          * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
841          * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
842          * extra 8 bytes of "Random confounder" after the checksum.
843          * It certainly confounds code expecting all Kerberos 5
844          * GSS_Wrap() tokens to look the same....
845          */
846         if (sgn_alg == KRB_SGN_ALG_HMAC) {
847           proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
848                               TRUE);
849           offset += 8;
850         }
851
852         /* Is the data encrypted? */
853         pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
854
855 #ifdef HAVE_KERBEROS
856 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
857         if(pinfo->decrypt_gssapi_tvb){
858                 /* if the caller did not provide a tvb, then we just use
859                    whatever is left of our current tvb.
860                 */
861                 if(!pinfo->gssapi_encrypted_tvb){
862                         int len;
863                         len=tvb_reported_length_remaining(tvb,offset);
864                         if(len>tvb_length_remaining(tvb, offset)){
865                                 /* no point in trying to decrypt, 
866                                    we dont have the full pdu.
867                                 */
868                                 return offset;
869                         }
870                         pinfo->gssapi_encrypted_tvb = tvb_new_subset(
871                                         tvb, offset, len, len);
872                 }
873                         
874                 /* if this is KRB5 wrapped rc4-hmac */
875                 if((token_id==KRB_TOKEN_WRAP)
876                  &&(sgn_alg==KRB_SGN_ALG_HMAC)
877                  &&(seal_alg==KRB_SEAL_ALG_RC4)){
878                         /* do we need to create a tvb for the wrapper
879                            as well ?
880                         */
881                         if(!pinfo->gssapi_wrap_tvb){
882                                 pinfo->gssapi_wrap_tvb = tvb_new_subset(
883                                         tvb, start_offset-2,
884                                         GSS_ARCFOUR_WRAP_TOKEN_SIZE,
885                                         GSS_ARCFOUR_WRAP_TOKEN_SIZE);
886                         }
887 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
888                         decrypt_gssapi_krb_arcfour_wrap(tree,
889                                 pinfo,
890                                 tvb,
891                                 23 /* rc4-hmac */);
892 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
893                 }
894         }       
895 #endif
896         /*
897          * Return the offset past the checksum, so that we know where
898          * the data we're wrapped around starts.  Also, set the length
899          * of our top-level item to that offset, so it doesn't cover
900          * the data we're wrapped around.
901          * 
902          * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
903          * not before.
904          */
905         return offset;
906 }
907
908 /*
909  * XXX - This is for GSSAPI GetMIC tokens ...
910  */
911 static int
912 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
913 {
914         guint16 sgn_alg;
915
916         /*
917          * The KRB5 blob conforms to RFC1964:
918          *   USHORT (0x0101 == GSS_GetMIC)
919          *   and so on } 
920          */
921
922         /* Now, the sign algorithm ... */
923
924         sgn_alg = tvb_get_letohs(tvb, offset);
925         proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
926                             sgn_alg);
927
928         offset += 2;
929
930         /* Skip the filler */
931
932         offset += 4;
933
934         /* Encrypted sequence number */
935
936         proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
937                             TRUE);
938
939         offset += 8;
940
941         /* Checksum of plaintext padded data */
942
943         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
944                             TRUE);
945
946         offset += 8;
947
948         /*
949          * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
950          * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
951          * extra 8 bytes of "Random confounder" after the checksum.
952          * It certainly confounds code expecting all Kerberos 5
953          * GSS_Wrap() tokens to look the same....
954          */
955         if (sgn_alg == KRB_SGN_ALG_HMAC) {
956           proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
957                               TRUE);
958
959           offset += 8;
960         }
961
962         /*
963          * Return the offset past the checksum, so that we know where
964          * the data we're wrapped around starts.  Also, set the length
965          * of our top-level item to that offset, so it doesn't cover
966          * the data we're wrapped around.
967          */
968
969         return offset;
970 }
971
972 /*
973  * XXX - is this for SPNEGO or just GSS-API?
974  * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
975  * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
976  * than designating SPNEGO as the mechanism, offering Kerberos V5, and
977  * getting it accepted.
978  */
979 static int
980 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
981 {
982         proto_item *item;
983         proto_tree *subtree;
984         int offset = 0;
985         guint16 token_id;
986
987         item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
988
989         subtree = proto_item_add_subtree(item, ett_spnego_krb5);
990
991         /*
992          * The KRB5 blob conforms to RFC1964:
993          *   USHORT (0x0102 == GSS_Wrap)
994          *   and so on } 
995          */
996
997         /* First, the token ID ... */
998
999         token_id = tvb_get_letohs(tvb, offset);
1000         proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1001                             token_id);
1002
1003         offset += 2;
1004
1005         offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1006
1007         /*
1008          * Return the offset past the checksum, so that we know where
1009          * the data we're wrapped around starts.  Also, set the length
1010          * of our top-level item to that offset, so it doesn't cover
1011          * the data we're wrapped around.
1012          */
1013         proto_item_set_len(item, offset);
1014         return offset;
1015 }
1016
1017 /* Spnego stuff from here */
1018
1019 static int
1020 dissect_spnego_mechTypes(tvbuff_t *tvb, int offset, packet_info *pinfo,
1021                          proto_tree *tree,
1022                          gssapi_oid_value **next_level_value_p)
1023 {
1024         proto_item *item = NULL;
1025         proto_tree *subtree = NULL;
1026         gboolean saw_mechanism = FALSE;
1027         int start_offset, start_oid_offset;
1028         gint8 class;
1029         gboolean pc, ind_field;
1030         gint32 tag;
1031         gint32 len1;
1032         gchar oid[MAX_OID_STR_LEN];
1033
1034         start_offset=offset;
1035         /*
1036          * MechTypeList ::= SEQUENCE OF MechType
1037          */
1038         offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1039         offset = get_ber_length(tree, tvb, offset, &len1, &ind_field);
1040
1041         if (!(class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE)) {
1042           proto_tree_add_text(
1043                               tree, tvb, offset, 0,
1044                               "Unknown header (class=%d, pc=%d, tag=%d)",
1045                               class, pc, tag);
1046           goto done;
1047         }
1048
1049         item = proto_tree_add_item(tree, hf_spnego_mechtype, tvb, 
1050                                 start_offset, len1, FALSE);
1051         subtree = proto_item_add_subtree(item, ett_spnego_mechtype);
1052
1053         /*
1054          * Now, the object IDs ...
1055          */
1056         start_oid_offset=offset;
1057         while (offset<(start_oid_offset+len1)) {
1058           gssapi_oid_value *value;
1059
1060           offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_mech, oid);
1061           value = gssapi_lookup_oid_str(oid);
1062
1063           /*
1064            * Tell our caller the first mechanism we see, so that if
1065            * this is a negTokenInit with a mechToken, it can interpret
1066            * the mechToken according to the first mechType.  (There
1067            * might not have been any indication of the mechType
1068            * in prior frames, so we can't necessarily use the
1069            * mechanism from the conversation; i.e., a negTokenInit
1070            * can contain the initial security token for the desired
1071            * mechanism of the initiator - that's the first mechanism
1072            * in the list.)
1073            */
1074           if (!saw_mechanism) {
1075             if (value)
1076               *next_level_value_p = value;
1077             saw_mechanism = TRUE;
1078           }
1079         }
1080
1081  done:
1082
1083         return offset;
1084
1085 }
1086
1087 static int
1088 dissect_spnego_reqFlags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1089                         proto_tree *tree, ASN1_SCK *hnd)
1090 {
1091         gboolean def;
1092         guint len1, cls, con, tag, flags;
1093         int ret;
1094         proto_item *item;
1095         proto_tree *subtree;
1096
1097         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1098
1099         if (ret != ASN1_ERR_NOERROR) {
1100                 dissect_parse_error(tvb, offset, pinfo, tree,
1101                                     "SPNEGO reqFlags header", ret);
1102                 goto done;
1103         }
1104
1105         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_BTS)) {
1106                 proto_tree_add_text(
1107                         tree, tvb, offset, 0,
1108                         "Unknown header (cls=%d, con=%d, tag=%d)",
1109                         cls, con, tag);
1110                 goto done;
1111         }
1112
1113         /* We must have a Bit String ... insert it */ 
1114
1115         offset = hnd->offset;
1116
1117         flags = tvb_get_guint8(tvb, offset);
1118
1119         item = proto_tree_add_item(tree, hf_spnego_reqflags, tvb, offset, len1,
1120             FALSE);
1121
1122         subtree = proto_item_add_subtree(item, ett_spnego_reqflags);
1123
1124         /*
1125          * Now, the bits. XXX: Assume 8 bits. FIXME.
1126          */
1127
1128         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_deleg, tvb, offset, len1, flags);
1129         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_mutual, tvb, offset, len1, flags);
1130         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_replay, tvb, offset, len1, flags);
1131         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_sequence, tvb, offset, len1, flags);
1132         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_anon, tvb, offset, len1, flags);
1133         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_conf, tvb, offset, len1, flags);
1134         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_integ, tvb, offset, len1, flags);
1135
1136         hnd->offset += len1;
1137
1138  done:
1139         return offset + len1;
1140
1141 }
1142
1143 static int
1144 dissect_spnego_mechToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1145                          proto_tree *tree, ASN1_SCK *hnd,
1146                          dissector_handle_t next_level_dissector)
1147 {
1148         proto_item *item;
1149         proto_tree *subtree;
1150         gboolean def;
1151         int ret;
1152         guint cls, con, tag, nbytes;
1153         gint length_remaining, reported_length_remaining;
1154         tvbuff_t *token_tvb;
1155
1156         /*
1157          * This appears to be a simple octet string ...
1158          */
1159
1160         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
1161
1162         if (ret != ASN1_ERR_NOERROR) {
1163                 dissect_parse_error(tvb, offset, pinfo, tree,
1164                                     "SPNEGO sequence header", ret);
1165                 goto done;
1166         }
1167
1168         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
1169                 proto_tree_add_text(
1170                         tree, tvb, offset, 0,
1171                         "Unknown header (cls=%d, con=%d, tag=%d)",
1172                         cls, con, tag);
1173                 goto done;
1174         }
1175
1176         offset = hnd->offset;
1177
1178
1179         /* Dont try to create an item with more bytes than remains in the
1180          * frame or we will not even attempt to dissect those bytes we
1181          * do have. (since there will be an exception)
1182          *
1183          * We use "tvb_ensure_length_remaining()" so that we throw
1184          * an exception if there's nothing to dissect.
1185          */
1186         length_remaining = tvb_ensure_length_remaining(tvb,offset);
1187         reported_length_remaining = tvb_reported_length_remaining(tvb,offset);
1188         if ((guint)length_remaining > nbytes)
1189                 length_remaining = nbytes;
1190         if ((guint)reported_length_remaining > nbytes)
1191                 reported_length_remaining = nbytes;
1192         item = proto_tree_add_item(tree, hf_spnego_mechtoken, tvb, offset, 
1193                                    length_remaining, FALSE);
1194         subtree = proto_item_add_subtree(item, ett_spnego_mechtoken);
1195
1196         /*
1197          * Now, we should be able to dispatch after creating a new TVB.
1198          */
1199
1200         token_tvb = tvb_new_subset(tvb, offset, length_remaining,
1201             reported_length_remaining);
1202         if (next_level_dissector)
1203           call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1204
1205         hnd->offset += nbytes; /* Update this ... */
1206
1207 done:
1208         return offset + nbytes;
1209 }
1210
1211 static int
1212 dissect_spnego_mechListMIC(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1213                            proto_tree *tree, ASN1_SCK *hnd,
1214                            dissector_handle_t next_level_dissector)
1215 {
1216         guint len1, cls, con, tag;
1217         int ret;
1218         gboolean def;
1219         proto_tree *subtree = NULL;
1220
1221         /*
1222          * Add the mechListMIC [3] Octet String or General String ...
1223          */
1224         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1225
1226         if (ret != ASN1_ERR_NOERROR) {
1227                 dissect_parse_error(tvb, offset, pinfo, subtree,
1228                                     "SPNEGO sequence header", ret);
1229                 goto done;
1230         }
1231
1232         offset = hnd->offset;
1233
1234         if (cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ) {
1235
1236           /*
1237            * There seems to be two different forms this can take
1238            * One as an Octet string, and one as a general string in a 
1239            * sequence ... We will have to dissect this later
1240            */
1241          
1242           proto_tree_add_text(tree, tvb, offset + 4, len1 - 4,
1243                               "mechListMIC: %s",
1244                               tvb_format_text(tvb, offset + 4, len1 - 4));
1245
1246           /* Naughty ... but we have to adjust for what we never took */
1247
1248           hnd->offset += len1;
1249           offset += len1;
1250
1251         }
1252         else if (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS) {
1253           tvbuff_t *token_tvb;
1254           proto_item *item;
1255           proto_tree *subtree;
1256
1257           item = proto_tree_add_item(tree, hf_spnego_mechlistmic, tvb, offset, 
1258                               len1, FALSE); 
1259           subtree = proto_item_add_subtree(item, ett_spnego_mechlistmic);
1260           
1261         /*
1262          * Now, we should be able to dispatch after creating a new TVB.
1263          */
1264
1265           token_tvb = tvb_new_subset(tvb, offset, len1, -1);
1266           if (next_level_dissector)
1267             call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1268
1269           hnd->offset += len1; /* Update this ... */
1270           offset += len1;
1271
1272         }
1273         else {
1274
1275           proto_tree_add_text(subtree, tvb, offset, 0,
1276                               "Unknown header (cls=%d, con=%d, tag=%d)",
1277                               cls, con, tag);
1278           goto done;
1279         }
1280
1281  done:
1282
1283         return offset;
1284
1285 }
1286
1287 static int
1288 dissect_spnego_negTokenInit(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1289                             proto_tree *tree, ASN1_SCK *hnd,
1290                             gssapi_oid_value **next_level_value_p)
1291 {
1292         proto_item *item;
1293         proto_tree *subtree;
1294         gboolean def;
1295         guint len1, len, cls, con, tag;
1296         int ret;
1297
1298         item = proto_tree_add_item( tree, hf_spnego_negtokeninit, tvb, offset,
1299                                     -1, FALSE);
1300         subtree = proto_item_add_subtree(item, ett_spnego_negtokeninit);
1301
1302         /*
1303          * Here is what we need to get ...
1304          * NegTokenInit ::= SEQUENCE {
1305          *          mechTypes [0] MechTypeList OPTIONAL,
1306          *          reqFlags [1] ContextFlags OPTIONAL,
1307          *          mechToken [2] OCTET STRING OPTIONAL,
1308          *          mechListMIC [3] OCTET STRING OPTIONAL }
1309
1310          */
1311
1312         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1313
1314         if (ret != ASN1_ERR_NOERROR) {
1315                 dissect_parse_error(tvb, offset, pinfo, subtree,
1316                                     "SPNEGO sequence header", ret);
1317                 goto done;
1318         }
1319
1320         if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
1321                 proto_tree_add_text(
1322                         subtree, tvb, offset, 0,
1323                         "Unknown header (cls=%d, con=%d, tag=%d)",
1324                         cls, con, tag);
1325                 goto done;
1326         }
1327
1328         offset = hnd->offset;
1329
1330         while (len1) {
1331           int hdr_ofs;
1332
1333           hdr_ofs = hnd->offset;
1334
1335           ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1336
1337           if (ret != ASN1_ERR_NOERROR) {
1338             dissect_parse_error(tvb, offset, pinfo, subtree,
1339                                 "SPNEGO context header", ret);
1340             goto done;
1341           }
1342
1343           if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1344             proto_tree_add_text(subtree, tvb, offset, 0,
1345                                 "Unknown header (cls=%d, con=%d, tag=%d)",
1346                                 cls, con, tag);
1347             goto done;
1348           }
1349
1350           /* Adjust for the length of the header */
1351
1352           len1 -= (hnd->offset - hdr_ofs);
1353
1354           /* Should be one of the fields */
1355
1356           switch (tag) {
1357
1358           case SPNEGO_mechTypes:
1359
1360             offset = dissect_spnego_mechTypes(tvb, hnd->offset, pinfo,
1361                                               subtree,
1362                                               next_level_value_p);
1363             hnd->offset=offset;
1364
1365             break;
1366
1367           case SPNEGO_reqFlags:
1368
1369             offset = dissect_spnego_reqFlags(tvb, offset, pinfo, subtree, hnd);
1370
1371             break;
1372
1373           case SPNEGO_mechToken:
1374
1375             offset = dissect_spnego_mechToken(tvb, offset, pinfo, subtree, 
1376                                               hnd, gssapi_dissector_handle(*next_level_value_p));
1377             break;
1378
1379           case SPNEGO_mechListMIC:
1380
1381             offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
1382                                                 hnd, gssapi_dissector_handle(*next_level_value_p));
1383             break;
1384
1385           default:
1386
1387             break;
1388           }
1389
1390           len1 -= len;
1391
1392         }
1393
1394  done:
1395
1396         return offset; /* Not sure this is right */
1397 }
1398
1399 static int
1400 dissect_spnego_negResult(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1401                             proto_tree *tree, ASN1_SCK *hnd)
1402 {
1403         gboolean def;
1404         int ret;
1405         guint len, cls, con, tag, val;
1406
1407         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1408
1409         if (ret != ASN1_ERR_NOERROR) {
1410           dissect_parse_error(tvb, offset, pinfo, tree,
1411                               "SPNEGO context header", ret);
1412           goto done;
1413         }
1414
1415         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_ENUM)) {
1416           proto_tree_add_text(
1417                               tree, tvb, offset, 0,
1418                               "Unknown header (cls=%d, con=%d, tag=%d) xxx",
1419                               cls, con, tag);
1420           goto done;
1421         }
1422
1423         offset = hnd->offset;
1424
1425         /* Now, get the value */
1426
1427         ret = asn1_uint32_value_decode(hnd, len, &val);
1428
1429         if (ret != ASN1_ERR_NOERROR) {
1430           dissect_parse_error(tvb, offset, pinfo, tree,
1431                               "SPNEGO negResult value", ret);
1432           goto done;
1433         }
1434         
1435         proto_tree_add_item(tree, hf_spnego_negtokentarg_negresult, tvb, 
1436                             offset, 1, FALSE);
1437
1438         offset = hnd->offset;
1439
1440  done:
1441         return offset;
1442 }
1443
1444 static int
1445 dissect_spnego_supportedMech(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1446                              proto_tree *tree, ASN1_SCK *hnd,
1447                              gssapi_oid_value **next_level_value_p)
1448 {
1449         int ret;
1450         guint oid_len, nbytes;
1451         subid_t *oid;
1452         gchar *oid_string;
1453         gssapi_oid_value *value;
1454         conversation_t *conversation;
1455
1456         /*
1457          * Now, get the OID, and find the handle, if any
1458          */
1459
1460         offset = hnd->offset;
1461
1462         ret = asn1_oid_decode(hnd, &oid, &oid_len, &nbytes);
1463
1464         if (ret != ASN1_ERR_NOERROR) {
1465                 dissect_parse_error(tvb, offset, pinfo, tree,
1466                                     "SPNEGO supportedMech token", ret);
1467                 goto done;
1468         }
1469
1470         oid_string = format_oid(oid, oid_len);
1471         value = gssapi_lookup_oid(oid, oid_len);
1472
1473         if (value)
1474           proto_tree_add_text(tree, tvb, offset, nbytes, 
1475                               "supportedMech: %s (%s)",
1476                               oid_string, value->comment);
1477         else
1478           proto_tree_add_text(tree, tvb, offset, nbytes, "supportedMech: %s",
1479                               oid_string);
1480
1481         g_free(oid_string);
1482
1483         offset += nbytes;
1484
1485         /* Should check for an unrecognized OID ... */
1486
1487         if (value)
1488           *next_level_value_p = value;
1489
1490         /*
1491          * Now, we need to save this in per proto info in the
1492          * conversation if it exists. We also should create a 
1493          * conversation if one does not exist. FIXME!
1494          * Hmmm, might need to be smarter, because there can be
1495          * multiple mechTypes in a negTokenInit with one being the
1496          * default used in the Token if present. Then the negTokenTarg
1497          * could override that. :-(
1498          */
1499
1500         if ((conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1501                                              pinfo->ptype, pinfo->srcport,
1502                                              pinfo->destport, 0))) {
1503
1504
1505           conversation_add_proto_data(conversation, proto_spnego, 
1506                                       *next_level_value_p);
1507         }
1508         else {
1509
1510         }
1511
1512  done:
1513         return offset;
1514 }
1515
1516 static int
1517 dissect_spnego_responseToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1518                              proto_tree *tree, ASN1_SCK *hnd,
1519                              dissector_handle_t next_level_dissector)
1520 {
1521         gboolean def;
1522         int ret;
1523         guint cls, con, tag, nbytes;
1524         tvbuff_t *token_tvb;
1525         proto_item *item;
1526         proto_tree *subtree;
1527
1528         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
1529
1530         if (ret != ASN1_ERR_NOERROR) {
1531                 dissect_parse_error(tvb, offset, pinfo, tree,
1532                                     "SPNEGO sequence header", ret);
1533                 goto done;
1534         }
1535
1536         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
1537                 proto_tree_add_text(
1538                         tree, tvb, offset, 0,
1539                         "Unknown header (cls=%d, con=%d, tag=%d)",
1540                         cls, con, tag);
1541                 goto done;
1542         }
1543
1544         offset = hnd->offset;
1545
1546         item = proto_tree_add_item(tree, hf_spnego_responsetoken, tvb, offset -2 , 
1547                                    nbytes + 2, FALSE); 
1548
1549         subtree = proto_item_add_subtree(item, ett_spnego_responsetoken);
1550
1551
1552         /*
1553          * Now, we should be able to dispatch after creating a new TVB.
1554          * However, we should make sure that there is something in the 
1555          * response token ...
1556          */
1557
1558         if (nbytes) {
1559           token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
1560           if (next_level_dissector)
1561             call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1562         }
1563         else {
1564           proto_tree_add_text(subtree, tvb, offset-2, 2, "<Empty String>");
1565         }
1566         hnd->offset += nbytes; /* Update this ... */
1567
1568  done:
1569         return offset + nbytes;
1570 }
1571
1572 static int
1573 dissect_spnego_negTokenTarg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1574                             proto_tree *tree, ASN1_SCK *hnd,
1575                             gssapi_oid_value **next_level_value_p)
1576
1577 {
1578         proto_item *item;
1579         proto_tree *subtree;
1580         gboolean def;
1581         int ret;
1582         guint len1, len, cls, con, tag;
1583
1584         item = proto_tree_add_item( tree, hf_spnego_negtokentarg, tvb, offset,
1585                                     -1, FALSE);
1586         subtree = proto_item_add_subtree(item, ett_spnego_negtokentarg);
1587
1588         /* 
1589          * Here is what we need to get ...
1590          * NegTokenTarg ::= SEQUENCE {
1591          *          negResult [0] ENUMERATED {
1592          *              accept_completed (0),
1593          *              accept_incomplete (1),
1594          *              reject (2) } OPTIONAL,
1595          *          supportedMech [1] MechType OPTIONAL,
1596          *          responseToken [2] OCTET STRING OPTIONAL,
1597          *          mechListMIC [3] OCTET STRING OPTIONAL }
1598          */
1599
1600         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1601
1602         if (ret != ASN1_ERR_NOERROR) {
1603                 dissect_parse_error(tvb, offset, pinfo, subtree,
1604                                     "SPNEGO sequence header", ret);
1605                 goto done;
1606         }
1607
1608         if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
1609                 proto_tree_add_text(
1610                         subtree, tvb, offset, 0,
1611                         "Unknown header (cls=%d, con=%d, tag=%d)",
1612                         cls, con, tag);
1613                 goto done;
1614         }
1615
1616         offset = hnd->offset;
1617
1618         while (len1) {
1619           int hdr_ofs;
1620
1621           hdr_ofs = hnd->offset; 
1622
1623           ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1624
1625           if (ret != ASN1_ERR_NOERROR) {
1626             dissect_parse_error(tvb, offset, pinfo, subtree,
1627                                 "SPNEGO context header", ret);
1628             goto done;
1629           }
1630
1631           if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1632             proto_tree_add_text(
1633                                 subtree, tvb, offset, 0,
1634                                 "Unknown header (cls=%d, con=%d, tag=%d)",
1635                                 cls, con, tag);
1636             goto done;
1637           }
1638
1639           /* Adjust for the length of the header */
1640
1641           len1 -= (hnd->offset - hdr_ofs);
1642
1643           /* Should be one of the fields */
1644
1645           switch (tag) {
1646
1647           case SPNEGO_negResult:
1648
1649             offset = dissect_spnego_negResult(tvb, offset, pinfo, subtree, 
1650                                               hnd);
1651             break;
1652
1653           case SPNEGO_supportedMech:
1654
1655             offset = dissect_spnego_supportedMech(tvb, offset, pinfo, subtree,
1656                                                   hnd, next_level_value_p);
1657
1658             break;
1659
1660           case SPNEGO_responseToken:
1661
1662             offset = dissect_spnego_responseToken(tvb, offset, pinfo, subtree,
1663                                                   hnd, gssapi_dissector_handle(*next_level_value_p));
1664             break;
1665
1666           case SPNEGO_mechListMIC:
1667
1668             offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree, 
1669                                                 hnd, gssapi_dissector_handle(*next_level_value_p));
1670             break;
1671
1672           default:
1673
1674             break;
1675           }
1676
1677           len1 -= len;
1678
1679         }
1680
1681  done:
1682         return offset;
1683
1684 }
1685
1686 static void
1687 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1688 {
1689         proto_item *item;
1690         proto_tree *subtree;
1691         int ret, offset = 0;
1692         ASN1_SCK hnd;
1693         gboolean def;
1694         guint len1, cls, con, tag;
1695         conversation_t *conversation;
1696         gssapi_oid_value *next_level_value;
1697
1698         /*
1699          * We need this later, so lets get it now ...
1700          * It has to be per-frame as there can be more than one GSS-API
1701          * negotiation in a conversation.
1702          */
1703
1704         next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1705         if (!next_level_value && !pinfo->fd->flags.visited) {
1706             /*
1707              * No handle attached to this frame, but it's the first
1708              * pass, so it'd be attached to the conversation.
1709              * If we have a conversation, try to get the handle,
1710              * and if we get one, attach it to the frame.
1711              */
1712             conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1713                                              pinfo->ptype, pinfo->srcport,
1714                                              pinfo->destport, 0);
1715
1716             if (conversation) {
1717                 next_level_value = conversation_get_proto_data(conversation, 
1718                                                                proto_spnego);
1719                 if (next_level_value)
1720                     p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1721             }
1722         }
1723
1724         item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
1725                                    -1, FALSE);
1726
1727         subtree = proto_item_add_subtree(item, ett_spnego);
1728
1729         /*
1730          * The TVB contains a [0] header and a sequence that consists of an
1731          * object ID and a blob containing the data ...
1732          * Actually, it contains, according to RFC2478:
1733          * NegotiationToken ::= CHOICE {
1734          *          negTokenInit [0] NegTokenInit,
1735          *          negTokenTarg [1] NegTokenTarg }
1736          * NegTokenInit ::= SEQUENCE {
1737          *          mechTypes [0] MechTypeList OPTIONAL,
1738          *          reqFlags [1] ContextFlags OPTIONAL,
1739          *          mechToken [2] OCTET STRING OPTIONAL,
1740          *          mechListMIC [3] OCTET STRING OPTIONAL }
1741          * NegTokenTarg ::= SEQUENCE {
1742          *          negResult [0] ENUMERATED {
1743          *              accept_completed (0),
1744          *              accept_incomplete (1),
1745          *              reject (2) } OPTIONAL,
1746          *          supportedMech [1] MechType OPTIONAL,
1747          *          responseToken [2] OCTET STRING OPTIONAL,
1748          *          mechListMIC [3] OCTET STRING OPTIONAL }
1749          *
1750          * Windows typically includes mechTypes and mechListMic ('NONE'
1751          * in the case of NTLMSSP only).
1752          * It seems to duplicate the responseToken into the mechListMic field
1753          * as well. Naughty, naughty.
1754          *
1755          */
1756
1757         asn1_open(&hnd, tvb, offset);
1758
1759         /*
1760          * Get the first header ...
1761          */
1762
1763         ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
1764
1765         if (ret != ASN1_ERR_NOERROR) {
1766                 dissect_parse_error(tvb, offset, pinfo, subtree,
1767                                     "SPNEGO context header", ret);
1768                 goto done;
1769         }
1770
1771         if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1772                 proto_tree_add_text(
1773                         subtree, tvb, offset, 0,
1774                         "Unknown header (cls=%d, con=%d, tag=%d)",
1775                         cls, con, tag);
1776                 goto done;
1777         }
1778
1779         offset = hnd.offset;
1780
1781         /*
1782          * The Tag is one of negTokenInit or negTokenTarg
1783          */
1784
1785         switch (tag) {
1786
1787         case SPNEGO_negTokenInit:
1788
1789           offset = dissect_spnego_negTokenInit(tvb, offset, pinfo,
1790                                                subtree, &hnd,
1791                                                &next_level_value);
1792
1793           break;
1794
1795         case SPNEGO_negTokenTarg:
1796
1797           offset = dissect_spnego_negTokenTarg(tvb, offset, pinfo,
1798                                                subtree, &hnd,
1799                                                &next_level_value);
1800           break;
1801
1802         default: /* Broken, what to do? */
1803
1804           break;
1805         }
1806
1807
1808  done:
1809         asn1_close(&hnd, &offset);
1810
1811 }
1812
1813 static int
1814 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1815 {
1816         proto_item *item;
1817         proto_tree *subtree;
1818         int return_offset;
1819         conversation_t *conversation;
1820         gssapi_oid_value *next_level_value;
1821         tvbuff_t *token_tvb;
1822         int len, offset, start_offset;
1823         gint8 class;
1824         gboolean pc, ind_field;
1825         gint32 tag;
1826         guint32 len1;
1827         gchar oid[MAX_OID_STR_LEN];
1828
1829         start_offset=0;
1830         offset=start_offset;
1831
1832         /*
1833          * We need this later, so lets get it now ...
1834          * It has to be per-frame as there can be more than one GSS-API
1835          * negotiation in a conversation.
1836          */
1837
1838         next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1839         if (!next_level_value && !pinfo->fd->flags.visited) {
1840             /*
1841              * No handle attached to this frame, but it's the first
1842              * pass, so it'd be attached to the conversation.
1843              * If we have a conversation, try to get the handle,
1844              * and if we get one, attach it to the frame.
1845              */
1846             conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1847                                              pinfo->ptype, pinfo->srcport,
1848                                              pinfo->destport, 0);
1849
1850             if (conversation) {
1851                 next_level_value = conversation_get_proto_data(conversation, 
1852                                                                proto_spnego);
1853                 if (next_level_value)
1854                     p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1855             }
1856         }
1857
1858         item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
1859                                    -1, FALSE);
1860
1861         subtree = proto_item_add_subtree(item, ett_spnego);
1862
1863         /*
1864          * The TVB contains a [0] header and a sequence that consists of an
1865          * object ID and a blob containing the data ...
1866          * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1867          * with the "optional" "use in non-initial tokens" being chosen.
1868          */
1869
1870         /*
1871          * Get the first header ...
1872          */
1873         offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1874         offset = get_ber_length(tree, tvb, offset, &len1, &ind_field);
1875
1876         if (!(class == BER_CLASS_APP && pc && tag == 0)) {
1877                 proto_tree_add_text(
1878                         subtree, tvb, start_offset, 0,
1879                         "Unknown header (class=%d, pc=%d, tag=%d)",
1880                         class, pc, tag);
1881                 return_offset = tvb_length(tvb);
1882                 goto done;
1883         }
1884
1885         /*
1886          * Get the OID, and find the handle, if any
1887          *
1888          * XXX - what should we do if this OID doesn't match the value
1889          * attached to the frame or conversation?  (That would be
1890          * bogus, but that's not impossible - some broken implementation
1891          * might negotiate some security mechanism but put the OID
1892          * for some other security mechanism in GSS_Wrap tokens.)
1893          */
1894         offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_this_mech, oid);
1895         next_level_value = gssapi_lookup_oid_str(oid);
1896
1897         /*
1898          * Now dissect the GSS_Wrap token; it's assumed to be in the
1899          * rest of the tvbuff.
1900          */
1901         item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, 
1902                                    -1, FALSE); 
1903
1904         subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
1905
1906         /*
1907          * Now, we should be able to dispatch after creating a new TVB.
1908          * The subdissector must return the length of the part of the
1909          * token it dissected, so we can return the length of the part
1910          * we (and it) dissected.
1911          */
1912
1913         token_tvb = tvb_new_subset(tvb, offset, -1, -1);
1914         if (next_level_value->wrap_handle) {
1915           len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
1916           if (len == 0)
1917             return_offset = tvb_length(tvb);
1918           else
1919             return_offset = offset + len;
1920         } else
1921           return_offset = tvb_length(tvb);
1922  done:
1923
1924         return return_offset;
1925 }
1926
1927 void
1928 proto_register_spnego(void)
1929 {
1930         static hf_register_info hf[] = {
1931                 { &hf_spnego,
1932                   { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1933                     "SPNEGO", HFILL }},
1934                 { &hf_spnego_mech, {
1935                     "Mech", "spnego.mech", FT_STRING, BASE_NONE,
1936                     NULL, 0, "This is a SPNEGO Object Identifier", HFILL }},
1937                 { &hf_spnego_this_mech, {
1938                     "thisMech", "spnego.this_mech", FT_STRING, BASE_NONE,
1939                     NULL, 0, "This is a SPNEGO Object Identifier", HFILL }},
1940                 { &hf_spnego_negtokeninit,
1941                   { "negTokenInit", "spnego.negtokeninit", FT_NONE, BASE_NONE,
1942                     NULL, 0x0, "SPNEGO negTokenInit", HFILL}},
1943                 { &hf_spnego_negtokentarg,
1944                   { "negTokenTarg", "spnego.negtokentarg", FT_NONE, BASE_NONE,
1945                     NULL, 0x0, "SPNEGO negTokenTarg", HFILL}},
1946                 { &hf_spnego_mechtype,
1947                   { "mechType", "spnego.negtokeninit.mechtype", FT_NONE,
1948                     BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechTypes", HFILL}},
1949                 { &hf_spnego_mechtoken,
1950                   { "mechToken", "spnego.negtokeninit.mechtoken", FT_NONE,
1951                     BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechToken", HFILL}},
1952                 { &hf_spnego_mechlistmic,
1953                   { "mechListMIC", "spnego.mechlistmic", FT_NONE,
1954                     BASE_NONE, NULL, 0x0, "SPNEGO mechListMIC", HFILL}}, 
1955                 { &hf_spnego_responsetoken,
1956                   { "responseToken", "spnego.negtokentarg.responsetoken",
1957                     FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO responseToken",
1958                     HFILL}},
1959                 { &hf_spnego_negtokentarg_negresult,
1960                   { "negResult", "spnego.negtokeninit.negresult", FT_UINT16,
1961                     BASE_HEX, VALS(spnego_negResult_vals), 0, "negResult", HFILL}},
1962                 { &hf_spnego_reqflags, 
1963                   { "reqFlags", "spnego.negtokeninit.reqflags", FT_BYTES,
1964                     BASE_HEX, NULL, 0, "reqFlags", HFILL }},
1965                 { &hf_gssapi_reqflags_deleg,
1966                   { "Delegation", "gssapi.reqflags.deleg", FT_BOOLEAN, 8,
1967                     TFS(&tfs_reqflags_deleg), 0x01, "Delegation", HFILL }},
1968                 { &hf_gssapi_reqflags_mutual,
1969                   { "Mutual Authentication", "gssapi.reqflags.mutual", FT_BOOLEAN,
1970                     8, TFS(&tfs_reqflags_mutual), 0x02, "Mutual Authentication", HFILL}},
1971                 { &hf_gssapi_reqflags_replay,
1972                   { "Replay Detection", "gssapi.reqflags.replay", FT_BOOLEAN,
1973                     8, TFS(&tfs_reqflags_replay), 0x04, "Replay Detection", HFILL}},
1974                 { &hf_gssapi_reqflags_sequence,
1975                   { "Out-of-sequence Detection", "gssapi.reqflags.sequence",
1976                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_sequence), 0x08, 
1977                     "Out-of-sequence Detection", HFILL}},
1978                 { &hf_gssapi_reqflags_anon,
1979                   { "Anonymous Authentication", "gssapi.reqflags.anon", 
1980                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_anon), 0x10,
1981                     "Anonymous Authentication", HFILL}},
1982                 { &hf_gssapi_reqflags_conf,
1983                   { "Per-message Confidentiality", "gssapi.reqflags.conf",
1984                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_conf), 0x20, 
1985                     "Per-message Confidentiality", HFILL}},
1986                 { &hf_gssapi_reqflags_integ,
1987                   { "Per-message Integrity", "gssapi.reqflags.integ", 
1988                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_integ), 0x40,
1989                     "Per-message Integrity", HFILL}},
1990                 { &hf_spnego_wraptoken,
1991                   { "wrapToken", "spnego.wraptoken",
1992                     FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1993                     HFILL}},
1994                 { &hf_spnego_krb5,
1995                   { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1996                     BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1997                 { &hf_spnego_krb5_tok_id,
1998                   { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1999                     VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
2000                 { &hf_spnego_krb5_sgn_alg,
2001                   { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
2002                     VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
2003                 { &hf_spnego_krb5_seal_alg,
2004                   { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
2005                     VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
2006                 { &hf_spnego_krb5_snd_seq,
2007                   { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
2008                     NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
2009                 { &hf_spnego_krb5_sgn_cksum,
2010                   { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
2011                     NULL, 0, "KRB5 Data Checksum", HFILL}},
2012                 { &hf_spnego_krb5_confounder,
2013                   { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
2014                     NULL, 0, "KRB5 Confounder", HFILL}},
2015         };
2016
2017         static gint *ett[] = {
2018                 &ett_spnego,
2019                 &ett_spnego_negtokeninit,
2020                 &ett_spnego_negtokentarg,
2021                 &ett_spnego_mechtype,
2022                 &ett_spnego_mechtoken,
2023                 &ett_spnego_mechlistmic,
2024                 &ett_spnego_responsetoken,
2025                 &ett_spnego_wraptoken,
2026                 &ett_spnego_krb5,
2027         };
2028
2029         proto_spnego = proto_register_protocol(
2030                 "Spnego", "Spnego", "spnego");
2031         proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
2032                                                     "SPNEGO-KRB5",
2033                                                     "spnego-krb5");
2034
2035         proto_register_field_array(proto_spnego, hf, array_length(hf));
2036         proto_register_subtree_array(ett, array_length(ett));
2037 }
2038
2039 void
2040 proto_reg_handoff_spnego(void)
2041 {
2042         dissector_handle_t spnego_handle, spnego_wrap_handle;
2043         dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
2044
2045         /* Register protocol with GSS-API module */
2046
2047         spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
2048         spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
2049                                                          proto_spnego);
2050         gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
2051             spnego_handle, spnego_wrap_handle,
2052             "SPNEGO - Simple Protected Negotiation");
2053
2054         /* Register both the one MS created and the real one */
2055         /*
2056          * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
2057          * mystery of the MS KRB5 OID is cleared up. It was due to a library
2058          * that did not handle OID components greater than 16 bits, and was
2059          * fixed in Win2K SP2 as well as WinXP.
2060          * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
2061          * SPNEGO implementation issues. 3-Dec-2002.
2062          */
2063         spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
2064                                                      proto_spnego_krb5);
2065         spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
2066                                                               proto_spnego_krb5);
2067         gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2068                         spnego_krb5_handle, spnego_krb5_wrap_handle,
2069                         "MS KRB5 - Microsoft Kerberos 5");
2070         gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2071                         spnego_krb5_handle, spnego_krb5_wrap_handle,
2072                         "KRB5 - Kerberos 5");
2073         gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
2074                         spnego_krb5_handle, spnego_krb5_wrap_handle,
2075                         "KRB5 - Kerberos 5 - User to User");
2076
2077         /*
2078          * Find the data handle for some calls
2079          */
2080         data_handle = find_dissector("data");
2081 }