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