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