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