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