Move the GSM SMS dissection to a dedicated subdissector (currently still within
[obnox/wireshark/wip.git] / packet-spnego.c
1 /* packet-spnego.c
2  * Routines for the simple and protected GSS-API negotiation mechanism
3  * as described in RFC 2478.
4  * Copyright 2002, Tim Potter <tpot@samba.org>
5  * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
6  * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
7  *
8  * $Id: packet-spnego.c,v 1.51 2003/07/17 22:17:01 sharpe Exp $
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <glib.h>
38 #include <epan/packet.h>
39
40 #include "asn1.h"
41 #include "format-oid.h"
42 #include "packet-gssapi.h"
43 #include "packet-kerberos.h"
44 #include <epan/conversation.h>
45
46 #define SPNEGO_negTokenInit 0
47 #define SPNEGO_negTokenTarg 1
48 #define SPNEGO_mechTypes 0
49 #define SPNEGO_reqFlags 1
50 #define SPNEGO_mechToken 2
51 #define SPNEGO_mechListMIC 3
52 #define SPNEGO_negResult 0
53 #define SPNEGO_supportedMech 1
54 #define SPNEGO_responseToken 2
55 #define SPNEGO_negResult_accept_completed 0
56 #define SPNEGO_negResult_accept_incomplete 1
57 #define SPNEGO_negResult_accept_reject 2
58
59 static int proto_spnego = -1;
60 static int proto_spnego_krb5 = -1;
61
62 static int hf_spnego = -1;
63 static int hf_spnego_negtokeninit = -1;
64 static int hf_spnego_negtokentarg = -1;
65 static int hf_spnego_mechtype = -1;
66 static int hf_spnego_mechtoken = -1;
67 static int hf_spnego_negtokentarg_negresult = -1;
68 static int hf_spnego_mechlistmic = -1;
69 static int hf_spnego_responsetoken = -1;
70 static int hf_spnego_reqflags = -1;
71 static int hf_spnego_wraptoken = -1;
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 static int hf_gssapi_reqflags_deleg = -1;
80 static int hf_gssapi_reqflags_mutual = -1;
81 static int hf_gssapi_reqflags_replay = -1;
82 static int hf_gssapi_reqflags_sequence = -1;
83 static int hf_gssapi_reqflags_anon = -1;
84 static int hf_gssapi_reqflags_conf = -1;
85 static int hf_gssapi_reqflags_integ = -1;
86
87 static gint ett_spnego = -1;
88 static gint ett_spnego_negtokeninit = -1;
89 static gint ett_spnego_negtokentarg = -1;
90 static gint ett_spnego_mechtype = -1;
91 static gint ett_spnego_mechtoken = -1;
92 static gint ett_spnego_mechlistmic = -1;
93 static gint ett_spnego_responsetoken = -1;
94 static gint ett_spnego_wraptoken = -1;
95 static gint ett_spnego_krb5 = -1;
96 static gint ett_spnego_reqflags = -1;
97
98 static const value_string spnego_negResult_vals[] = {
99   { SPNEGO_negResult_accept_completed,   "Accept Completed" },
100   { SPNEGO_negResult_accept_incomplete,  "Accept Incomplete" },
101   { SPNEGO_negResult_accept_reject,      "Accept Reject"},
102   { 0, NULL}
103 };
104
105 /*
106  * These should be in the GSSAPI dissector ... XXX
107  */
108
109 static const true_false_string tfs_reqflags_deleg = {
110   "Delegation Requested",
111   "Delegation NOT Requested"
112 };
113
114 static const true_false_string tfs_reqflags_mutual = {
115   "Mutual Authentication Requested",
116   "Mutual Authentication NOT Requested"
117 };
118
119 static const true_false_string tfs_reqflags_replay = {
120   "Replay Detection Requested",
121   "Replay Detection NOT Requested"
122 };
123
124 static const true_false_string tfs_reqflags_sequence = {
125   "Out-of-sequence Detection Requested",
126   "Out-of-sequence Detection NOT Requested"
127 };
128
129 static const true_false_string tfs_reqflags_anon = {
130   "Anonymous Authentication Requested",
131   "Anonymous Authentication NOT Requested"
132 };
133
134 static const true_false_string tfs_reqflags_conf = {
135   "Per-message Confidentiality Requested",
136   "Per-message Confidentiality NOT Requested"
137 };
138
139 static const true_false_string tfs_reqflags_integ = {
140   "Per-message Integrity Requested",
141   "Per-message Integrity NOT Requested"
142 };
143
144 /* Display an ASN1 parse error.  Taken from packet-snmp.c */
145
146 static dissector_handle_t data_handle;
147
148 static void
149 dissect_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
150                     proto_tree *tree, const char *field_name, int ret)
151 {
152         char *errstr;
153
154         errstr = asn1_err_to_str(ret);
155
156         if (tree != NULL) {
157                 proto_tree_add_text(tree, tvb, offset, 0,
158                     "ERROR: Couldn't parse %s: %s", field_name, errstr);
159                 call_dissector(data_handle,
160                     tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
161         }
162 }
163
164 /*
165  * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
166  * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also 
167  * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
168  */ 
169
170 #define KRB_TOKEN_AP_REQ                0x0001
171 #define KRB_TOKEN_AP_REP                0x0002
172 #define KRB_TOKEN_AP_ERR                0x0003
173 #define KRB_TOKEN_GETMIC                0x0101
174 #define KRB_TOKEN_WRAP                  0x0102
175 #define KRB_TOKEN_DELETE_SEC_CONTEXT    0x0201
176
177 static const value_string spnego_krb5_tok_id_vals[] = {
178   { KRB_TOKEN_AP_REQ,             "KRB5_AP_REQ"},
179   { KRB_TOKEN_AP_REP,             "KRB5_AP_REP"},
180   { KRB_TOKEN_AP_ERR,             "KRB5_ERROR"},
181   { KRB_TOKEN_GETMIC,             "KRB5_GSS_GetMIC" },
182   { KRB_TOKEN_WRAP,               "KRB5_GSS_Wrap" },
183   { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
184   { 0, NULL}
185 };
186
187 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
188 #define KRB_SGN_ALG_MD2_5       0x0001
189 #define KRB_SGN_ALG_DES_MAC     0x0002
190 #define KRB_SGN_ALG_HMAC        0x0011
191
192 static const value_string spnego_krb5_sgn_alg_vals[] = {
193   { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
194   { KRB_SGN_ALG_MD2_5,       "MD2.5"},
195   { KRB_SGN_ALG_DES_MAC,     "DES MAC"},
196   { KRB_SGN_ALG_HMAC,        "HMAC"},
197   { 0, NULL}
198 };
199
200 #define KRB_SEAL_ALG_DES_CBC    0x0000
201 #define KRB_SEAL_ALG_RC4        0x0010
202 #define KRB_SEAL_ALG_NONE       0xffff
203
204 static const value_string spnego_krb5_seal_alg_vals[] = {
205   { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
206   { KRB_SEAL_ALG_RC4,     "RC4"},
207   { KRB_SEAL_ALG_NONE,    "None"},
208   { 0, NULL}
209 };
210
211 /*
212  * XXX - is this for SPNEGO or just GSS-API?
213  * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
214  * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
215  * than designating SPNEGO as the mechanism, offering Kerberos V5, and
216  * getting it accepted.
217  */
218 static int
219 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
220 static int
221 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
222
223 static void
224 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
225 {
226         proto_item *item;
227         proto_tree *subtree;
228         int ret, offset = 0;
229         ASN1_SCK hnd;
230         gboolean def;
231         guint len1, cls, con, tag, oid_len, nbytes;
232         guint16 token_id;
233         subid_t *oid;
234         gchar *oid_string;
235         gssapi_oid_value *value;
236         tvbuff_t *krb5_tvb;
237
238         item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset, 
239                                    -1, FALSE);
240
241         subtree = proto_item_add_subtree(item, ett_spnego_krb5);
242
243         /*
244          * The KRB5 blob conforms to RFC1964:
245          * [APPLICATION 0] {
246          *   OID,
247          *   USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
248          *   OCTET STRING } 
249          *
250          * However, for some protocols, the KRB5 blob starts at the SHORT
251          * and has no DER encoded header etc.
252          *
253          * It appears that for some other protocols the KRB5 blob is just
254          * a Kerberos message, with no [APPLICATION 0] header, no OID,
255          * and no USHORT.
256          *
257          * So:
258          *
259          *      If we see an [APPLICATION 0] HEADER, we show the OID and
260          *      the USHORT, and then dissect the rest as a Kerberos message.
261          *
262          *      If we see an [APPLICATION 14] or [APPLICATION 15] header,
263          *      we assume it's an AP-REQ or AP-REP message, and dissect
264          *      it all as a Kerberos message.
265          *
266          *      Otherwise, we show the USHORT, and then dissect the rest
267          *      as a Kerberos message.
268          */
269
270         asn1_open(&hnd, tvb, offset);
271
272         /*
273          * Get the first header ...
274          */
275
276         ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
277
278         if (ret != ASN1_ERR_NOERROR) {
279                 dissect_parse_error(tvb, offset, pinfo, subtree,
280                                     "SPNEGO KRB5 Header", ret);
281                 goto done;
282         }
283
284         if (cls == ASN1_APL && con == ASN1_CON) {
285             /*
286              * [APPLICATION <tag>]
287              */
288             switch (tag) {
289
290             case 0:
291                 /*
292                  * [APPLICATION 0]
293                  */
294
295                 offset = hnd.offset;
296
297                 /* Next, the OID */
298
299                 ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
300
301                 if (ret != ASN1_ERR_NOERROR) {
302                     dissect_parse_error(tvb, offset, pinfo, subtree,
303                                         "SPNEGO supportedMech token", ret);
304                     goto done;
305                 }
306
307                 oid_string = format_oid(oid, oid_len);
308
309                 value = gssapi_lookup_oid(oid, oid_len);
310
311                 if (value) 
312                     proto_tree_add_text(subtree, tvb, offset, nbytes, 
313                                         "OID: %s (%s)",
314                                         oid_string, value->comment);
315                 else
316                     proto_tree_add_text(subtree, tvb, offset, nbytes,
317                                         "OID: %s",
318                                         oid_string);
319           
320                 g_free(oid_string);
321
322                 offset += nbytes;
323
324                 /* Next, the token ID ... */
325
326                 token_id = tvb_get_letohs(tvb, offset);
327                 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
328                                     token_id);
329
330                 hnd.offset += 2;
331
332                 offset += 2;
333
334                 break;
335
336             case 14:    /* [APPLICATION 14] */
337             case 15:    /* [APPLICATION 15] */
338                 /*
339                  * No token ID - just dissect as a Kerberos message and
340                  * return.
341                  */
342                 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1); 
343                 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE);
344                 return;
345
346             default:
347                 proto_tree_add_text(subtree, tvb, offset, 0,
348                         "Unknown header (cls=%d, con=%d, tag=%d)",
349                         cls, con, tag);
350                 goto done;
351             }
352         } else {
353             /* Next, the token ID ... */
354
355             token_id = tvb_get_letohs(tvb, offset);
356             proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
357                                 token_id);
358
359             hnd.offset += 2;
360
361             offset += 2;
362         }
363
364         switch (token_id) {
365
366         case KRB_TOKEN_AP_REQ:
367         case KRB_TOKEN_AP_REP:
368         case KRB_TOKEN_AP_ERR:
369           krb5_tvb = tvb_new_subset(tvb, offset, -1, -1); 
370           offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE);
371           break;
372
373         case KRB_TOKEN_GETMIC:
374           offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree); 
375           break;
376
377         case KRB_TOKEN_WRAP:
378           offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree);
379           break;
380
381         case KRB_TOKEN_DELETE_SEC_CONTEXT:
382
383           break;
384
385         default:
386
387           break;
388         }
389
390  done:
391         return;
392 }
393
394 /*
395  * XXX - This is for GSSAPI Wrap tokens ...
396  */
397 static int
398 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
399 {
400         guint16 sgn_alg;
401
402         /*
403          * The KRB5 blob conforms to RFC1964:
404          *   USHORT (0x0102 == GSS_Wrap)
405          *   and so on } 
406          */
407
408         /* Now, the sign and seal algorithms ... */
409
410         sgn_alg = tvb_get_letohs(tvb, offset);
411         proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
412                             sgn_alg);
413
414         offset += 2;
415
416         proto_tree_add_item(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
417                             TRUE);
418
419         offset += 2;
420
421         /* Skip the filler */
422
423         offset += 2;
424
425         /* Encrypted sequence number */
426
427         proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
428                             TRUE);
429
430         offset += 8;
431
432         /* Checksum of plaintext padded data */
433
434         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
435                             TRUE);
436
437         offset += 8;
438
439         /*
440          * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
441          * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
442          * extra 8 bytes of "Random confounder" after the checksum.
443          * It certainly confounds code expecting all Kerberos 5
444          * GSS_Wrap() tokens to look the same....
445          */
446         if (sgn_alg == KRB_SGN_ALG_HMAC) {
447           proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
448                               TRUE);
449
450           offset += 8;
451         }
452
453         /*
454          * Return the offset past the checksum, so that we know where
455          * the data we're wrapped around starts.  Also, set the length
456          * of our top-level item to that offset, so it doesn't cover
457          * the data we're wrapped around.
458          */
459         return offset;
460 }
461
462 /*
463  * XXX - This is for GSSAPI GetMIC tokens ...
464  */
465 static int
466 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
467 {
468         guint16 sgn_alg;
469
470         /*
471          * The KRB5 blob conforms to RFC1964:
472          *   USHORT (0x0101 == GSS_GetMIC)
473          *   and so on } 
474          */
475
476         /* Now, the sign algorithm ... */
477
478         sgn_alg = tvb_get_letohs(tvb, offset);
479         proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
480                             sgn_alg);
481
482         offset += 2;
483
484         /* Skip the filler */
485
486         offset += 4;
487
488         /* Encrypted sequence number */
489
490         proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
491                             TRUE);
492
493         offset += 8;
494
495         /* Checksum of plaintext padded data */
496
497         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
498                             TRUE);
499
500         offset += 8;
501
502         /*
503          * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
504          * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
505          * extra 8 bytes of "Random confounder" after the checksum.
506          * It certainly confounds code expecting all Kerberos 5
507          * GSS_Wrap() tokens to look the same....
508          */
509         if (sgn_alg == KRB_SGN_ALG_HMAC) {
510           proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
511                               TRUE);
512
513           offset += 8;
514         }
515
516         /*
517          * Return the offset past the checksum, so that we know where
518          * the data we're wrapped around starts.  Also, set the length
519          * of our top-level item to that offset, so it doesn't cover
520          * the data we're wrapped around.
521          */
522
523         return offset;
524 }
525
526 /*
527  * XXX - is this for SPNEGO or just GSS-API?
528  * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
529  * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
530  * than designating SPNEGO as the mechanism, offering Kerberos V5, and
531  * getting it accepted.
532  */
533 static int
534 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
535 {
536         proto_item *item;
537         proto_tree *subtree;
538         int offset = 0;
539
540         item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
541
542         subtree = proto_item_add_subtree(item, ett_spnego_krb5);
543
544         /*
545          * The KRB5 blob conforms to RFC1964:
546          *   USHORT (0x0102 == GSS_Wrap)
547          *   and so on } 
548          */
549
550         /* First, the token ID ... */
551
552         proto_tree_add_item(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
553                             TRUE);
554
555         offset += 2;
556
557         offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree);
558
559         /*
560          * Return the offset past the checksum, so that we know where
561          * the data we're wrapped around starts.  Also, set the length
562          * of our top-level item to that offset, so it doesn't cover
563          * the data we're wrapped around.
564          */
565         proto_item_set_len(item, offset);
566         return offset;
567 }
568
569 /* Spnego stuff from here */
570
571 static int
572 dissect_spnego_mechTypes(tvbuff_t *tvb, int offset, packet_info *pinfo,
573                          proto_tree *tree, ASN1_SCK *hnd,
574                          gssapi_oid_value **next_level_value_p)
575 {
576         proto_item *item = NULL;
577         proto_tree *subtree = NULL;
578         gboolean def;
579         guint len1, len, cls, con, tag, nbytes;
580         subid_t *oid;
581         gchar *oid_string;
582         int ret;
583         gboolean saw_mechanism = FALSE;
584
585         /*
586          * MechTypeList ::= SEQUENCE OF MechType
587          */
588
589         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
590
591         if (ret != ASN1_ERR_NOERROR) {
592           dissect_parse_error(tvb, offset, pinfo, subtree,
593                               "SPNEGO last sequence header", ret);
594           goto done;
595         }
596
597         if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
598           proto_tree_add_text(
599                               subtree, tvb, offset, 0,
600                               "Unknown header (cls=%d, con=%d, tag=%d)",
601                               cls, con, tag);
602           goto done;
603         }
604
605         offset = hnd->offset;
606
607         item = proto_tree_add_item(tree, hf_spnego_mechtype, tvb, offset, 
608                                    len1, FALSE);
609         subtree = proto_item_add_subtree(item, ett_spnego_mechtype);
610
611         /*
612          * Now, the object IDs ... We should translate them: FIXME
613          */
614
615         while (len1) {
616           gssapi_oid_value *value;
617
618           ret = asn1_oid_decode(hnd, &oid, &len, &nbytes);
619
620           if (ret != ASN1_ERR_NOERROR) {
621             dissect_parse_error(tvb, offset, pinfo, subtree,
622                                 "SPNEGO mechTypes token", ret);
623             goto done;
624           }
625
626           oid_string = format_oid(oid, len);
627           value = gssapi_lookup_oid(oid, len);
628           if (value)
629             proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s (%s)",
630                                 oid_string, value->comment);
631           else
632             proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s",
633                                 oid_string);
634
635           g_free(oid_string);
636
637           /*
638            * Tell our caller the first mechanism we see, so that if
639            * this is a negTokenInit with a mechToken, it can interpret
640            * the mechToken according to the first mechType.  (There
641            * might not have been any indication of the mechType
642            * in prior frames, so we can't necessarily use the
643            * mechanism from the conversation; i.e., a negTokenInit
644            * can contain the initial security token for the desired
645            * mechanism of the initiator - that's the first mechanism
646            * in the list.)
647            */
648           if (!saw_mechanism) {
649             if (value)
650               *next_level_value_p = value;
651             saw_mechanism = TRUE;
652           }
653
654           offset += nbytes;
655           len1 -= nbytes;
656
657         }
658
659  done:
660
661         return offset;
662
663 }
664
665 static int
666 dissect_spnego_reqFlags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
667                         proto_tree *tree, ASN1_SCK *hnd)
668 {
669         gboolean def;
670         guint len1, cls, con, tag, flags;
671         int ret;
672         proto_item *item;
673         proto_tree *subtree;
674
675         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
676
677         if (ret != ASN1_ERR_NOERROR) {
678                 dissect_parse_error(tvb, offset, pinfo, tree,
679                                     "SPNEGO reqFlags header", ret);
680                 goto done;
681         }
682
683         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_BTS)) {
684                 proto_tree_add_text(
685                         tree, tvb, offset, 0,
686                         "Unknown header (cls=%d, con=%d, tag=%d)",
687                         cls, con, tag);
688                 goto done;
689         }
690
691         /* We must have a Bit String ... insert it */ 
692
693         offset = hnd->offset;
694
695         flags = tvb_get_guint8(tvb, offset);
696
697         item = proto_tree_add_item(tree, hf_spnego_reqflags, tvb, offset, len1,
698             FALSE);
699
700         subtree = proto_item_add_subtree(item, ett_spnego_reqflags);
701
702         /*
703          * Now, the bits. XXX: Assume 8 bits. FIXME.
704          */
705
706         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_deleg, tvb, offset, len1, flags);
707         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_mutual, tvb, offset, len1, flags);
708         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_replay, tvb, offset, len1, flags);
709         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_sequence, tvb, offset, len1, flags);
710         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_anon, tvb, offset, len1, flags);
711         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_conf, tvb, offset, len1, flags);
712         proto_tree_add_boolean(subtree, hf_gssapi_reqflags_integ, tvb, offset, len1, flags);
713
714         hnd->offset += len1;
715
716  done:
717         return offset + len1;
718
719 }
720
721 static int
722 dissect_spnego_mechToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
723                          proto_tree *tree, ASN1_SCK *hnd,
724                          dissector_handle_t next_level_dissector)
725 {
726         proto_item *item;
727         proto_tree *subtree;
728         gboolean def;
729         int ret;
730         guint cls, con, tag, nbytes;
731         tvbuff_t *token_tvb;
732
733         /*
734          * This appears to be a simple octet string ...
735          */
736
737         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
738
739         if (ret != ASN1_ERR_NOERROR) {
740                 dissect_parse_error(tvb, offset, pinfo, tree,
741                                     "SPNEGO sequence header", ret);
742                 goto done;
743         }
744
745         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
746                 proto_tree_add_text(
747                         tree, tvb, offset, 0,
748                         "Unknown header (cls=%d, con=%d, tag=%d)",
749                         cls, con, tag);
750                 goto done;
751         }
752
753         offset = hnd->offset;
754
755         item = proto_tree_add_item(tree, hf_spnego_mechtoken, tvb, offset, 
756                                    nbytes, FALSE);
757         subtree = proto_item_add_subtree(item, ett_spnego_mechtoken);
758
759         /*
760          * Now, we should be able to dispatch after creating a new TVB.
761          */
762
763         token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
764         if (next_level_dissector)
765           call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
766
767         hnd->offset += nbytes; /* Update this ... */
768
769  done:
770
771   return offset + nbytes;
772
773 }
774
775 static int
776 dissect_spnego_mechListMIC(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
777                            proto_tree *tree, ASN1_SCK *hnd,
778                            dissector_handle_t next_level_dissector)
779 {
780         guint len1, cls, con, tag;
781         int ret;
782         gboolean def;
783         proto_tree *subtree = NULL;
784
785         /*
786          * Add the mechListMIC [3] Octet String or General String ...
787          */
788         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
789
790         if (ret != ASN1_ERR_NOERROR) {
791                 dissect_parse_error(tvb, offset, pinfo, subtree,
792                                     "SPNEGO sequence header", ret);
793                 goto done;
794         }
795
796         offset = hnd->offset;
797
798         if (cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ) {
799
800           /*
801            * There seems to be two different forms this can take
802            * One as an Octet string, and one as a general string in a 
803            * sequence ... We will have to dissect this later
804            */
805          
806           proto_tree_add_text(tree, tvb, offset + 4, len1 - 4,
807                               "mechListMIC: %s",
808                               tvb_format_text(tvb, offset + 4, len1 - 4));
809
810           /* Naughty ... but we have to adjust for what we never took */
811
812           hnd->offset += len1;
813           offset += len1;
814
815         }
816         else if (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS) {
817           tvbuff_t *token_tvb;
818           proto_item *item;
819           proto_tree *subtree;
820
821           item = proto_tree_add_item(tree, hf_spnego_mechlistmic, tvb, offset, 
822                               len1, FALSE); 
823           subtree = proto_item_add_subtree(item, ett_spnego_mechlistmic);
824           
825         /*
826          * Now, we should be able to dispatch after creating a new TVB.
827          */
828
829           token_tvb = tvb_new_subset(tvb, offset, len1, -1);
830           if (next_level_dissector)
831             call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
832
833           hnd->offset += len1; /* Update this ... */
834           offset += len1;
835
836         }
837         else {
838
839           proto_tree_add_text(subtree, tvb, offset, 0,
840                               "Unknown header (cls=%d, con=%d, tag=%d)",
841                               cls, con, tag);
842           goto done;
843         }
844
845  done:
846
847         return offset;
848
849 }
850
851 static int
852 dissect_spnego_negTokenInit(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
853                             proto_tree *tree, ASN1_SCK *hnd,
854                             gssapi_oid_value **next_level_value_p)
855 {
856         proto_item *item;
857         proto_tree *subtree;
858         gboolean def;
859         guint len1, len, cls, con, tag;
860         int ret;
861
862         item = proto_tree_add_item( tree, hf_spnego_negtokeninit, tvb, offset,
863                                     -1, FALSE);
864         subtree = proto_item_add_subtree(item, ett_spnego_negtokeninit);
865
866         /*
867          * Here is what we need to get ...
868          * NegTokenInit ::= SEQUENCE {
869          *          mechTypes [0] MechTypeList OPTIONAL,
870          *          reqFlags [1] ContextFlags OPTIONAL,
871          *          mechToken [2] OCTET STRING OPTIONAL,
872          *          mechListMIC [3] OCTET STRING OPTIONAL }
873
874          */
875
876         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
877
878         if (ret != ASN1_ERR_NOERROR) {
879                 dissect_parse_error(tvb, offset, pinfo, subtree,
880                                     "SPNEGO sequence header", ret);
881                 goto done;
882         }
883
884         if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
885                 proto_tree_add_text(
886                         subtree, tvb, offset, 0,
887                         "Unknown header (cls=%d, con=%d, tag=%d)",
888                         cls, con, tag);
889                 goto done;
890         }
891
892         offset = hnd->offset;
893
894         while (len1) {
895           int hdr_ofs;
896
897           hdr_ofs = hnd->offset;
898
899           ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
900
901           if (ret != ASN1_ERR_NOERROR) {
902             dissect_parse_error(tvb, offset, pinfo, subtree,
903                                 "SPNEGO context header", ret);
904             goto done;
905           }
906
907           if (!(cls == ASN1_CTX && con == ASN1_CON)) {
908             proto_tree_add_text(subtree, tvb, offset, 0,
909                                 "Unknown header (cls=%d, con=%d, tag=%d)",
910                                 cls, con, tag);
911             goto done;
912           }
913
914           /* Adjust for the length of the header */
915
916           len1 -= (hnd->offset - hdr_ofs);
917
918           /* Should be one of the fields */
919
920           switch (tag) {
921
922           case SPNEGO_mechTypes:
923
924             offset = dissect_spnego_mechTypes(tvb, offset, pinfo,
925                                               subtree, hnd,
926                                               next_level_value_p);
927
928             break;
929
930           case SPNEGO_reqFlags:
931
932             offset = dissect_spnego_reqFlags(tvb, offset, pinfo, subtree, hnd);
933
934             break;
935
936           case SPNEGO_mechToken:
937
938             offset = dissect_spnego_mechToken(tvb, offset, pinfo, subtree, 
939                                               hnd, (*next_level_value_p)->handle);
940             break;
941
942           case SPNEGO_mechListMIC:
943
944             offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
945                                                 hnd, (*next_level_value_p)->handle);
946             break;
947
948           default:
949
950             break;
951           }
952
953           len1 -= len;
954
955         }
956
957  done:
958
959         return offset; /* Not sure this is right */
960 }
961
962 static int
963 dissect_spnego_negResult(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
964                             proto_tree *tree, ASN1_SCK *hnd)
965 {
966         gboolean def;
967         int ret;
968         guint len, cls, con, tag, val;
969
970         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
971
972         if (ret != ASN1_ERR_NOERROR) {
973           dissect_parse_error(tvb, offset, pinfo, tree,
974                               "SPNEGO context header", ret);
975           goto done;
976         }
977
978         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_ENUM)) {
979           proto_tree_add_text(
980                               tree, tvb, offset, 0,
981                               "Unknown header (cls=%d, con=%d, tag=%d) xxx",
982                               cls, con, tag);
983           goto done;
984         }
985
986         offset = hnd->offset;
987
988         /* Now, get the value */
989
990         ret = asn1_uint32_value_decode(hnd, len, &val);
991
992         if (ret != ASN1_ERR_NOERROR) {
993           dissect_parse_error(tvb, offset, pinfo, tree,
994                               "SPNEGO negResult value", ret);
995           goto done;
996         }
997         
998         proto_tree_add_item(tree, hf_spnego_negtokentarg_negresult, tvb, 
999                             offset, 1, FALSE);
1000
1001         offset = hnd->offset;
1002
1003  done:
1004         return offset;
1005 }
1006
1007 static int
1008 dissect_spnego_supportedMech(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1009                              proto_tree *tree, ASN1_SCK *hnd,
1010                              gssapi_oid_value **next_level_value_p)
1011 {
1012         int ret;
1013         guint oid_len, nbytes;
1014         subid_t *oid;
1015         gchar *oid_string;
1016         gssapi_oid_value *value;
1017         conversation_t *conversation;
1018
1019         /*
1020          * Now, get the OID, and find the handle, if any
1021          */
1022
1023         offset = hnd->offset;
1024
1025         ret = asn1_oid_decode(hnd, &oid, &oid_len, &nbytes);
1026
1027         if (ret != ASN1_ERR_NOERROR) {
1028                 dissect_parse_error(tvb, offset, pinfo, tree,
1029                                     "SPNEGO supportedMech token", ret);
1030                 goto done;
1031         }
1032
1033         oid_string = format_oid(oid, oid_len);
1034         value = gssapi_lookup_oid(oid, oid_len);
1035
1036         if (value)
1037           proto_tree_add_text(tree, tvb, offset, nbytes, 
1038                               "supportedMech: %s (%s)",
1039                               oid_string, value->comment);
1040         else
1041           proto_tree_add_text(tree, tvb, offset, nbytes, "supportedMech: %s",
1042                               oid_string);
1043
1044         g_free(oid_string);
1045
1046         offset += nbytes;
1047
1048         /* Should check for an unrecognized OID ... */
1049
1050         if (value)
1051           *next_level_value_p = value;
1052
1053         /*
1054          * Now, we need to save this in per proto info in the
1055          * conversation if it exists. We also should create a 
1056          * conversation if one does not exist. FIXME!
1057          * Hmmm, might need to be smarter, because there can be
1058          * multiple mechTypes in a negTokenInit with one being the
1059          * default used in the Token if present. Then the negTokenTarg
1060          * could override that. :-(
1061          */
1062
1063         if ((conversation = find_conversation(&pinfo->src, &pinfo->dst,
1064                                              pinfo->ptype, pinfo->srcport,
1065                                              pinfo->destport, 0))) {
1066
1067
1068           conversation_add_proto_data(conversation, proto_spnego, 
1069                                       *next_level_value_p);
1070         }
1071         else {
1072
1073         }
1074
1075  done:
1076         return offset;
1077 }
1078
1079 static int
1080 dissect_spnego_responseToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1081                              proto_tree *tree, ASN1_SCK *hnd,
1082                              dissector_handle_t next_level_dissector)
1083 {
1084         gboolean def;
1085         int ret;
1086         guint cls, con, tag, nbytes;
1087         tvbuff_t *token_tvb;
1088         proto_item *item;
1089         proto_tree *subtree;
1090
1091         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
1092
1093         if (ret != ASN1_ERR_NOERROR) {
1094                 dissect_parse_error(tvb, offset, pinfo, tree,
1095                                     "SPNEGO sequence header", ret);
1096                 goto done;
1097         }
1098
1099         if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
1100                 proto_tree_add_text(
1101                         tree, tvb, offset, 0,
1102                         "Unknown header (cls=%d, con=%d, tag=%d)",
1103                         cls, con, tag);
1104                 goto done;
1105         }
1106
1107         offset = hnd->offset;
1108
1109         item = proto_tree_add_item(tree, hf_spnego_responsetoken, tvb, offset -2 , 
1110                                    nbytes + 2, FALSE); 
1111
1112         subtree = proto_item_add_subtree(item, ett_spnego_responsetoken);
1113
1114
1115         /*
1116          * Now, we should be able to dispatch after creating a new TVB.
1117          * However, we should make sure that there is something in the 
1118          * response token ...
1119          */
1120
1121         if (nbytes) {
1122           token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
1123           if (next_level_dissector)
1124             call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1125         }
1126         else {
1127           proto_tree_add_text(subtree, tvb, offset-2, 2, "<Empty String>");
1128         }
1129         hnd->offset += nbytes; /* Update this ... */
1130
1131  done:
1132         return offset + nbytes;
1133 }
1134
1135 static int
1136 dissect_spnego_negTokenTarg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1137                             proto_tree *tree, ASN1_SCK *hnd,
1138                             gssapi_oid_value **next_level_value_p)
1139
1140 {
1141         proto_item *item;
1142         proto_tree *subtree;
1143         gboolean def;
1144         int ret;
1145         guint len1, len, cls, con, tag;
1146
1147         item = proto_tree_add_item( tree, hf_spnego_negtokentarg, tvb, offset,
1148                                     -1, FALSE);
1149         subtree = proto_item_add_subtree(item, ett_spnego_negtokentarg);
1150
1151         /* 
1152          * Here is what we need to get ...
1153          * NegTokenTarg ::= SEQUENCE {
1154          *          negResult [0] ENUMERATED {
1155          *              accept_completed (0),
1156          *              accept_incomplete (1),
1157          *              reject (2) } OPTIONAL,
1158          *          supportedMech [1] MechType OPTIONAL,
1159          *          responseToken [2] OCTET STRING OPTIONAL,
1160          *          mechListMIC [3] OCTET STRING OPTIONAL }
1161          */
1162
1163         ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1164
1165         if (ret != ASN1_ERR_NOERROR) {
1166                 dissect_parse_error(tvb, offset, pinfo, subtree,
1167                                     "SPNEGO sequence header", ret);
1168                 goto done;
1169         }
1170
1171         if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
1172                 proto_tree_add_text(
1173                         subtree, tvb, offset, 0,
1174                         "Unknown header (cls=%d, con=%d, tag=%d)",
1175                         cls, con, tag);
1176                 goto done;
1177         }
1178
1179         offset = hnd->offset;
1180
1181         while (len1) {
1182           int hdr_ofs;
1183
1184           hdr_ofs = hnd->offset; 
1185
1186           ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1187
1188           if (ret != ASN1_ERR_NOERROR) {
1189             dissect_parse_error(tvb, offset, pinfo, subtree,
1190                                 "SPNEGO context header", ret);
1191             goto done;
1192           }
1193
1194           if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1195             proto_tree_add_text(
1196                                 subtree, tvb, offset, 0,
1197                                 "Unknown header (cls=%d, con=%d, tag=%d)",
1198                                 cls, con, tag);
1199             goto done;
1200           }
1201
1202           /* Adjust for the length of the header */
1203
1204           len1 -= (hnd->offset - hdr_ofs);
1205
1206           /* Should be one of the fields */
1207
1208           switch (tag) {
1209
1210           case SPNEGO_negResult:
1211
1212             offset = dissect_spnego_negResult(tvb, offset, pinfo, subtree, 
1213                                               hnd);
1214             break;
1215
1216           case SPNEGO_supportedMech:
1217
1218             offset = dissect_spnego_supportedMech(tvb, offset, pinfo, subtree,
1219                                                   hnd, next_level_value_p);
1220
1221             break;
1222
1223           case SPNEGO_responseToken:
1224
1225             offset = dissect_spnego_responseToken(tvb, offset, pinfo, subtree,
1226                                                   hnd,
1227                                                   (*next_level_value_p != NULL) ?
1228                                                       (*next_level_value_p)->handle :
1229                                                       NULL);
1230             break;
1231
1232           case SPNEGO_mechListMIC:
1233
1234             offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree, 
1235                                                 hnd,
1236                                                 (*next_level_value_p != NULL) ?
1237                                                     (*next_level_value_p)->handle :
1238                                                     NULL);
1239             break;
1240
1241           default:
1242
1243             break;
1244           }
1245
1246           len1 -= len;
1247
1248         }
1249
1250  done:
1251         return offset;
1252
1253 }
1254
1255 static void
1256 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1257 {
1258         proto_item *item;
1259         proto_tree *subtree;
1260         int ret, offset = 0;
1261         ASN1_SCK hnd;
1262         gboolean def;
1263         guint len1, cls, con, tag;
1264         conversation_t *conversation;
1265         gssapi_oid_value *next_level_value;
1266
1267         /*
1268          * We need this later, so lets get it now ...
1269          * It has to be per-frame as there can be more than one GSS-API
1270          * negotiation in a conversation.
1271          */
1272
1273         next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1274         if (!next_level_value && !pinfo->fd->flags.visited) {
1275             /*
1276              * No handle attached to this frame, but it's the first
1277              * pass, so it'd be attached to the conversation.
1278              * If we have a conversation, try to get the handle,
1279              * and if we get one, attach it to the frame.
1280              */
1281             conversation = find_conversation(&pinfo->src, &pinfo->dst,
1282                                              pinfo->ptype, pinfo->srcport,
1283                                              pinfo->destport, 0);
1284
1285             if (conversation) {
1286                 next_level_value = conversation_get_proto_data(conversation, 
1287                                                                proto_spnego);
1288                 if (next_level_value)
1289                     p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1290             }
1291         }
1292
1293         item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
1294                                    -1, FALSE);
1295
1296         subtree = proto_item_add_subtree(item, ett_spnego);
1297
1298         /*
1299          * The TVB contains a [0] header and a sequence that consists of an
1300          * object ID and a blob containing the data ...
1301          * Actually, it contains, according to RFC2478:
1302          * NegotiationToken ::= CHOICE {
1303          *          negTokenInit [0] NegTokenInit,
1304          *          negTokenTarg [1] NegTokenTarg }
1305          * NegTokenInit ::= SEQUENCE {
1306          *          mechTypes [0] MechTypeList OPTIONAL,
1307          *          reqFlags [1] ContextFlags OPTIONAL,
1308          *          mechToken [2] OCTET STRING OPTIONAL,
1309          *          mechListMIC [3] OCTET STRING OPTIONAL }
1310          * NegTokenTarg ::= SEQUENCE {
1311          *          negResult [0] ENUMERATED {
1312          *              accept_completed (0),
1313          *              accept_incomplete (1),
1314          *              reject (2) } OPTIONAL,
1315          *          supportedMech [1] MechType OPTIONAL,
1316          *          responseToken [2] OCTET STRING OPTIONAL,
1317          *          mechListMIC [3] OCTET STRING OPTIONAL }
1318          *
1319          * Windows typically includes mechTypes and mechListMic ('NONE'
1320          * in the case of NTLMSSP only).
1321          * It seems to duplicate the responseToken into the mechListMic field
1322          * as well. Naughty, naughty.
1323          *
1324          */
1325
1326         asn1_open(&hnd, tvb, offset);
1327
1328         /*
1329          * Get the first header ...
1330          */
1331
1332         ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
1333
1334         if (ret != ASN1_ERR_NOERROR) {
1335                 dissect_parse_error(tvb, offset, pinfo, subtree,
1336                                     "SPNEGO context header", ret);
1337                 goto done;
1338         }
1339
1340         if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1341                 proto_tree_add_text(
1342                         subtree, tvb, offset, 0,
1343                         "Unknown header (cls=%d, con=%d, tag=%d)",
1344                         cls, con, tag);
1345                 goto done;
1346         }
1347
1348         offset = hnd.offset;
1349
1350         /*
1351          * The Tag is one of negTokenInit or negTokenTarg
1352          */
1353
1354         switch (tag) {
1355
1356         case SPNEGO_negTokenInit:
1357
1358           offset = dissect_spnego_negTokenInit(tvb, offset, pinfo,
1359                                                subtree, &hnd,
1360                                                &next_level_value);
1361
1362           break;
1363
1364         case SPNEGO_negTokenTarg:
1365
1366           offset = dissect_spnego_negTokenTarg(tvb, offset, pinfo,
1367                                                subtree, &hnd,
1368                                                &next_level_value);
1369           break;
1370
1371         default: /* Broken, what to do? */
1372
1373           break;
1374         }
1375
1376
1377  done:
1378         asn1_close(&hnd, &offset);
1379
1380 }
1381
1382 static int
1383 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1384 {
1385         proto_item *item;
1386         proto_tree *subtree;
1387         int ret, offset = 0;
1388         int return_offset;
1389         ASN1_SCK hnd;
1390         gboolean def;
1391         guint len1, cls, con, tag, nbytes;
1392         guint oid_len;
1393         subid_t *oid;
1394         gchar *oid_string;
1395         conversation_t *conversation;
1396         gssapi_oid_value *next_level_value;
1397         tvbuff_t *token_tvb;
1398         int len;
1399
1400         /*
1401          * We need this later, so lets get it now ...
1402          * It has to be per-frame as there can be more than one GSS-API
1403          * negotiation in a conversation.
1404          */
1405
1406         next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1407         if (!next_level_value && !pinfo->fd->flags.visited) {
1408             /*
1409              * No handle attached to this frame, but it's the first
1410              * pass, so it'd be attached to the conversation.
1411              * If we have a conversation, try to get the handle,
1412              * and if we get one, attach it to the frame.
1413              */
1414             conversation = find_conversation(&pinfo->src, &pinfo->dst,
1415                                              pinfo->ptype, pinfo->srcport,
1416                                              pinfo->destport, 0);
1417
1418             if (conversation) {
1419                 next_level_value = conversation_get_proto_data(conversation, 
1420                                                                proto_spnego);
1421                 if (next_level_value)
1422                     p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1423             }
1424         }
1425
1426         item = proto_tree_add_item(tree, hf_spnego, tvb, offset, 
1427                                    -1, FALSE);
1428
1429         subtree = proto_item_add_subtree(item, ett_spnego);
1430
1431         /*
1432          * The TVB contains a [0] header and a sequence that consists of an
1433          * object ID and a blob containing the data ...
1434          * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1435          * with the "optional" "use in non-initial tokens" being chosen.
1436          */
1437
1438         asn1_open(&hnd, tvb, offset);
1439
1440         /*
1441          * Get the first header ...
1442          */
1443
1444         ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
1445
1446         if (ret != ASN1_ERR_NOERROR) {
1447                 dissect_parse_error(tvb, offset, pinfo, subtree,
1448                                     "SPNEGO context header", ret);
1449                 return_offset = tvb_length(tvb);
1450                 goto done;
1451         }
1452
1453         if (!(cls == ASN1_APL && con == ASN1_CON && tag == 0)) {
1454                 proto_tree_add_text(
1455                         subtree, tvb, offset, 0,
1456                         "Unknown header (cls=%d, con=%d, tag=%d)",
1457                         cls, con, tag);
1458                 return_offset = tvb_length(tvb);
1459                 goto done;
1460         }
1461
1462         offset = hnd.offset;
1463
1464         /*
1465          * Get the OID, and find the handle, if any
1466          */
1467
1468         ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
1469
1470         if (ret != ASN1_ERR_NOERROR) {
1471                 dissect_parse_error(tvb, offset, pinfo, tree,
1472                                     "SPNEGO wrap token", ret);
1473                 return_offset = tvb_length(tvb);
1474                 goto done;
1475         }
1476
1477         oid_string = format_oid(oid, oid_len);
1478         next_level_value = gssapi_lookup_oid(oid, oid_len);
1479
1480         /*
1481          * XXX - what should we do if this doesn't match the value
1482          * attached to the frame or conversation?  (That would be
1483          * bogus, but that's not impossible - some broken implementation
1484          * might negotiate some security mechanism but put the OID
1485          * for some other security mechanism in GSS_Wrap tokens.)
1486          */
1487         if (next_level_value)
1488           proto_tree_add_text(tree, tvb, offset, nbytes, 
1489                               "thisMech: %s (%s)",
1490                               oid_string, next_level_value->comment);
1491         else
1492           proto_tree_add_text(tree, tvb, offset, nbytes, "thisMech: %s",
1493                               oid_string);
1494
1495         g_free(oid_string);
1496
1497         offset += nbytes;
1498
1499         /*
1500          * Now dissect the GSS_Wrap token; it's assumed to be in the
1501          * rest of the tvbuff.
1502          */
1503         item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, 
1504                                    -1, FALSE); 
1505
1506         subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
1507
1508         /*
1509          * Now, we should be able to dispatch after creating a new TVB.
1510          * The subdissector must return the length of the part of the
1511          * token it dissected, so we can return the length of the part
1512          * we (and it) dissected.
1513          */
1514
1515         token_tvb = tvb_new_subset(tvb, offset, -1, -1);
1516         if (next_level_value->wrap_handle) {
1517           len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
1518           if (len == 0)
1519             return_offset = tvb_length(tvb);
1520           else
1521             return_offset = offset + len;
1522         } else
1523           return_offset = tvb_length(tvb);
1524  done:
1525         asn1_close(&hnd, &offset);
1526
1527         return return_offset;
1528 }
1529
1530 void
1531 proto_register_spnego(void)
1532 {
1533         static hf_register_info hf[] = {
1534                 { &hf_spnego,
1535                   { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1536                     "SPNEGO", HFILL }},
1537                 { &hf_spnego_negtokeninit,
1538                   { "negTokenInit", "spnego.negtokeninit", FT_NONE, BASE_NONE,
1539                     NULL, 0x0, "SPNEGO negTokenInit", HFILL}},
1540                 { &hf_spnego_negtokentarg,
1541                   { "negTokenTarg", "spnego.negtokentarg", FT_NONE, BASE_NONE,
1542                     NULL, 0x0, "SPNEGO negTokenTarg", HFILL}},
1543                 { &hf_spnego_mechtype,
1544                   { "mechType", "spnego.negtokeninit.mechtype", FT_NONE,
1545                     BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechTypes", HFILL}},
1546                 { &hf_spnego_mechtoken,
1547                   { "mechToken", "spnego.negtokeninit.mechtoken", FT_NONE,
1548                     BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechToken", HFILL}},
1549                 { &hf_spnego_mechlistmic,
1550                   { "mechListMIC", "spnego.mechlistmic", FT_NONE,
1551                     BASE_NONE, NULL, 0x0, "SPNEGO mechListMIC", HFILL}}, 
1552                 { &hf_spnego_responsetoken,
1553                   { "responseToken", "spnego.negtokentarg.responsetoken",
1554                     FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO responseToken",
1555                     HFILL}},
1556                 { &hf_spnego_negtokentarg_negresult,
1557                   { "negResult", "spnego.negtokeninit.negresult", FT_UINT16,
1558                     BASE_HEX, VALS(spnego_negResult_vals), 0, "negResult", HFILL}},
1559                 { &hf_spnego_reqflags, 
1560                   { "reqFlags", "spnego.negtokeninit.reqflags", FT_BYTES,
1561                     BASE_HEX, NULL, 0, "reqFlags", HFILL }},
1562                 { &hf_gssapi_reqflags_deleg,
1563                   { "Delegation", "gssapi.reqflags.deleg", FT_BOOLEAN, 8,
1564                     TFS(&tfs_reqflags_deleg), 0x01, "Delegation", HFILL }},
1565                 { &hf_gssapi_reqflags_mutual,
1566                   { "Mutual Authentication", "gssapi.reqflags.mutual", FT_BOOLEAN,
1567                     8, TFS(&tfs_reqflags_mutual), 0x02, "Mutual Authentication", HFILL}},
1568                 { &hf_gssapi_reqflags_replay,
1569                   { "Replay Detection", "gssapi.reqflags.replay", FT_BOOLEAN,
1570                     8, TFS(&tfs_reqflags_replay), 0x04, "Replay Detection", HFILL}},
1571                 { &hf_gssapi_reqflags_sequence,
1572                   { "Out-of-sequence Detection", "gssapi.reqflags.sequence",
1573                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_sequence), 0x08, 
1574                     "Out-of-sequence Detection", HFILL}},
1575                 { &hf_gssapi_reqflags_anon,
1576                   { "Anonymous Authentication", "gssapi.reqflags.anon", 
1577                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_anon), 0x10,
1578                     "Anonymous Authentication", HFILL}},
1579                 { &hf_gssapi_reqflags_conf,
1580                   { "Per-message Confidentiality", "gssapi.reqflags.conf",
1581                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_conf), 0x20, 
1582                     "Per-message Confidentiality", HFILL}},
1583                 { &hf_gssapi_reqflags_integ,
1584                   { "Per-message Integrity", "gssapi.reqflags.integ", 
1585                     FT_BOOLEAN, 8, TFS(&tfs_reqflags_integ), 0x40,
1586                     "Per-message Integrity", HFILL}},
1587                 { &hf_spnego_wraptoken,
1588                   { "wrapToken", "spnego.wraptoken",
1589                     FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1590                     HFILL}},
1591                 { &hf_spnego_krb5,
1592                   { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1593                     BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1594                 { &hf_spnego_krb5_tok_id,
1595                   { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1596                     VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1597                 { &hf_spnego_krb5_sgn_alg,
1598                   { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1599                     VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1600                 { &hf_spnego_krb5_seal_alg,
1601                   { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1602                     VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1603                 { &hf_spnego_krb5_snd_seq,
1604                   { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1605                     NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1606                 { &hf_spnego_krb5_sgn_cksum,
1607                   { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1608                     NULL, 0, "KRB5 Data Checksum", HFILL}},
1609                 { &hf_spnego_krb5_confounder,
1610                   { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1611                     NULL, 0, "KRB5 Confounder", HFILL}},
1612         };
1613
1614         static gint *ett[] = {
1615                 &ett_spnego,
1616                 &ett_spnego_negtokeninit,
1617                 &ett_spnego_negtokentarg,
1618                 &ett_spnego_mechtype,
1619                 &ett_spnego_mechtoken,
1620                 &ett_spnego_mechlistmic,
1621                 &ett_spnego_responsetoken,
1622                 &ett_spnego_wraptoken,
1623                 &ett_spnego_krb5,
1624         };
1625
1626         proto_spnego = proto_register_protocol(
1627                 "Spnego", "Spnego", "spnego");
1628         proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1629                                                     "SPNEGO-KRB5",
1630                                                     "spnego-krb5");
1631
1632         proto_register_field_array(proto_spnego, hf, array_length(hf));
1633         proto_register_subtree_array(ett, array_length(ett));
1634 }
1635
1636 void
1637 proto_reg_handoff_spnego(void)
1638 {
1639         dissector_handle_t spnego_handle, spnego_wrap_handle;
1640         dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1641
1642         /* Register protocol with GSS-API module */
1643
1644         spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
1645         spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
1646                                                          proto_spnego);
1647         gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1648             spnego_handle, spnego_wrap_handle,
1649             "SPNEGO - Simple Protected Negotiation");
1650
1651         /* Register both the one MS created and the real one */
1652         /*
1653          * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1654          * mystery of the MS KRB5 OID is cleared up. It was due to a library
1655          * that did not handle OID components greater than 16 bits, and was
1656          * fixed in Win2K SP2 as well as WinXP.
1657          * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1658          * SPNEGO implementation issues. 3-Dec-2002.
1659          */
1660         spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
1661                                                      proto_spnego_krb5);
1662         spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
1663                                                               proto_spnego_krb5);
1664         gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1665                         spnego_krb5_handle, spnego_krb5_wrap_handle,
1666                         "MS KRB5 - Microsoft Kerberos 5");
1667         gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1668                         spnego_krb5_handle, spnego_krb5_wrap_handle,
1669                         "KRB5 - Kerberos 5");
1670         gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1671                         spnego_krb5_handle, spnego_krb5_wrap_handle,
1672                         "KRB5 - Kerberos 5 - User to User");
1673
1674         /*
1675          * Find the data handle for some calls
1676          */
1677         data_handle = find_dissector("data");
1678 }