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>
8 * $Id: packet-spnego.c,v 1.55 2004/05/11 02:02:44 gerald Exp $
10 * Ethereal - Network traffic analyzer
11 * By Gerald Combs <gerald@ethereal.com>
12 * Copyright 1998 Gerald Combs
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.
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.
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.
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
38 #include <epan/packet.h>
41 #include "format-oid.h"
42 #include "packet-gssapi.h"
43 #include "packet-kerberos.h"
44 #include <epan/conversation.h>
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
59 static int proto_spnego = -1;
60 static int proto_spnego_krb5 = -1;
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;
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;
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"},
106 * These should be in the GSSAPI dissector ... XXX
109 static const true_false_string tfs_reqflags_deleg = {
110 "Delegation Requested",
111 "Delegation NOT Requested"
114 static const true_false_string tfs_reqflags_mutual = {
115 "Mutual Authentication Requested",
116 "Mutual Authentication NOT Requested"
119 static const true_false_string tfs_reqflags_replay = {
120 "Replay Detection Requested",
121 "Replay Detection NOT Requested"
124 static const true_false_string tfs_reqflags_sequence = {
125 "Out-of-sequence Detection Requested",
126 "Out-of-sequence Detection NOT Requested"
129 static const true_false_string tfs_reqflags_anon = {
130 "Anonymous Authentication Requested",
131 "Anonymous Authentication NOT Requested"
134 static const true_false_string tfs_reqflags_conf = {
135 "Per-message Confidentiality Requested",
136 "Per-message Confidentiality NOT Requested"
139 static const true_false_string tfs_reqflags_integ = {
140 "Per-message Integrity Requested",
141 "Per-message Integrity NOT Requested"
144 /* Display an ASN1 parse error. Taken from packet-snmp.c */
146 static dissector_handle_t data_handle;
148 static dissector_handle_t
149 gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
150 if (next_level_value == NULL) {
153 return next_level_value->handle;
157 dissect_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
158 proto_tree *tree, const char *field_name, int ret)
162 errstr = asn1_err_to_str(ret);
165 proto_tree_add_text(tree, tvb, offset, 0,
166 "ERROR: Couldn't parse %s: %s", field_name, errstr);
167 call_dissector(data_handle,
168 tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
173 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
174 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
175 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
178 #define KRB_TOKEN_AP_REQ 0x0001
179 #define KRB_TOKEN_AP_REP 0x0002
180 #define KRB_TOKEN_AP_ERR 0x0003
181 #define KRB_TOKEN_GETMIC 0x0101
182 #define KRB_TOKEN_WRAP 0x0102
183 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
185 static const value_string spnego_krb5_tok_id_vals[] = {
186 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
187 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
188 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
189 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
190 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
191 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
195 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
196 #define KRB_SGN_ALG_MD2_5 0x0001
197 #define KRB_SGN_ALG_DES_MAC 0x0002
198 #define KRB_SGN_ALG_HMAC 0x0011
200 static const value_string spnego_krb5_sgn_alg_vals[] = {
201 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
202 { KRB_SGN_ALG_MD2_5, "MD2.5"},
203 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
204 { KRB_SGN_ALG_HMAC, "HMAC"},
208 #define KRB_SEAL_ALG_DES_CBC 0x0000
209 #define KRB_SEAL_ALG_RC4 0x0010
210 #define KRB_SEAL_ALG_NONE 0xffff
212 static const value_string spnego_krb5_seal_alg_vals[] = {
213 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
214 { KRB_SEAL_ALG_RC4, "RC4"},
215 { KRB_SEAL_ALG_NONE, "None"},
220 * XXX - is this for SPNEGO or just GSS-API?
221 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
222 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
223 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
224 * getting it accepted.
227 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
229 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
232 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
239 guint len1, cls, con, tag, oid_len, nbytes;
243 gssapi_oid_value *value;
246 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
249 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
252 * The KRB5 blob conforms to RFC1964:
255 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
258 * However, for some protocols, the KRB5 blob starts at the SHORT
259 * and has no DER encoded header etc.
261 * It appears that for some other protocols the KRB5 blob is just
262 * a Kerberos message, with no [APPLICATION 0] header, no OID,
267 * If we see an [APPLICATION 0] HEADER, we show the OID and
268 * the USHORT, and then dissect the rest as a Kerberos message.
270 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
271 * we assume it's an AP-REQ or AP-REP message, and dissect
272 * it all as a Kerberos message.
274 * Otherwise, we show the USHORT, and then dissect the rest
275 * as a Kerberos message.
278 asn1_open(&hnd, tvb, offset);
281 * Get the first header ...
284 ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
286 if (ret != ASN1_ERR_NOERROR) {
287 dissect_parse_error(tvb, offset, pinfo, subtree,
288 "SPNEGO KRB5 Header", ret);
292 if (cls == ASN1_APL && con == ASN1_CON) {
294 * [APPLICATION <tag>]
307 ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
309 if (ret != ASN1_ERR_NOERROR) {
310 dissect_parse_error(tvb, offset, pinfo, subtree,
311 "SPNEGO supportedMech token", ret);
315 oid_string = format_oid(oid, oid_len);
317 value = gssapi_lookup_oid(oid, oid_len);
320 proto_tree_add_text(subtree, tvb, offset, nbytes,
322 oid_string, value->comment);
324 proto_tree_add_text(subtree, tvb, offset, nbytes,
332 /* Next, the token ID ... */
334 token_id = tvb_get_letohs(tvb, offset);
335 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
344 case 14: /* [APPLICATION 14] */
345 case 15: /* [APPLICATION 15] */
347 * No token ID - just dissect as a Kerberos message and
350 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
351 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE);
355 proto_tree_add_text(subtree, tvb, offset, 0,
356 "Unknown header (cls=%d, con=%d, tag=%d)",
361 /* Next, the token ID ... */
363 token_id = tvb_get_letohs(tvb, offset);
364 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
374 case KRB_TOKEN_AP_REQ:
375 case KRB_TOKEN_AP_REP:
376 case KRB_TOKEN_AP_ERR:
377 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
378 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE);
381 case KRB_TOKEN_GETMIC:
382 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
386 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree);
389 case KRB_TOKEN_DELETE_SEC_CONTEXT:
403 * XXX - This is for GSSAPI Wrap tokens ...
406 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
411 * The KRB5 blob conforms to RFC1964:
412 * USHORT (0x0102 == GSS_Wrap)
416 /* Now, the sign and seal algorithms ... */
418 sgn_alg = tvb_get_letohs(tvb, offset);
419 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
424 proto_tree_add_item(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
429 /* Skip the filler */
433 /* Encrypted sequence number */
435 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
440 /* Checksum of plaintext padded data */
442 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
448 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
449 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
450 * extra 8 bytes of "Random confounder" after the checksum.
451 * It certainly confounds code expecting all Kerberos 5
452 * GSS_Wrap() tokens to look the same....
454 if (sgn_alg == KRB_SGN_ALG_HMAC) {
455 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
462 * Return the offset past the checksum, so that we know where
463 * the data we're wrapped around starts. Also, set the length
464 * of our top-level item to that offset, so it doesn't cover
465 * the data we're wrapped around.
471 * XXX - This is for GSSAPI GetMIC tokens ...
474 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
479 * The KRB5 blob conforms to RFC1964:
480 * USHORT (0x0101 == GSS_GetMIC)
484 /* Now, the sign algorithm ... */
486 sgn_alg = tvb_get_letohs(tvb, offset);
487 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
492 /* Skip the filler */
496 /* Encrypted sequence number */
498 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
503 /* Checksum of plaintext padded data */
505 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
511 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
512 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
513 * extra 8 bytes of "Random confounder" after the checksum.
514 * It certainly confounds code expecting all Kerberos 5
515 * GSS_Wrap() tokens to look the same....
517 if (sgn_alg == KRB_SGN_ALG_HMAC) {
518 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
525 * Return the offset past the checksum, so that we know where
526 * the data we're wrapped around starts. Also, set the length
527 * of our top-level item to that offset, so it doesn't cover
528 * the data we're wrapped around.
535 * XXX - is this for SPNEGO or just GSS-API?
536 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
537 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
538 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
539 * getting it accepted.
542 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
548 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
550 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
553 * The KRB5 blob conforms to RFC1964:
554 * USHORT (0x0102 == GSS_Wrap)
558 /* First, the token ID ... */
560 proto_tree_add_item(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
565 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree);
568 * Return the offset past the checksum, so that we know where
569 * the data we're wrapped around starts. Also, set the length
570 * of our top-level item to that offset, so it doesn't cover
571 * the data we're wrapped around.
573 proto_item_set_len(item, offset);
577 /* Spnego stuff from here */
580 dissect_spnego_mechTypes(tvbuff_t *tvb, int offset, packet_info *pinfo,
581 proto_tree *tree, ASN1_SCK *hnd,
582 gssapi_oid_value **next_level_value_p)
584 proto_item *item = NULL;
585 proto_tree *subtree = NULL;
587 guint len1, len, cls, con, tag, nbytes;
591 gboolean saw_mechanism = FALSE;
594 * MechTypeList ::= SEQUENCE OF MechType
597 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
599 if (ret != ASN1_ERR_NOERROR) {
600 dissect_parse_error(tvb, offset, pinfo, subtree,
601 "SPNEGO last sequence header", ret);
605 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
607 subtree, tvb, offset, 0,
608 "Unknown header (cls=%d, con=%d, tag=%d)",
613 offset = hnd->offset;
615 item = proto_tree_add_item(tree, hf_spnego_mechtype, tvb, offset,
617 subtree = proto_item_add_subtree(item, ett_spnego_mechtype);
620 * Now, the object IDs ... We should translate them: FIXME
624 gssapi_oid_value *value;
626 ret = asn1_oid_decode(hnd, &oid, &len, &nbytes);
628 if (ret != ASN1_ERR_NOERROR) {
629 dissect_parse_error(tvb, offset, pinfo, subtree,
630 "SPNEGO mechTypes token", ret);
634 oid_string = format_oid(oid, len);
635 value = gssapi_lookup_oid(oid, len);
637 proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s (%s)",
638 oid_string, value->comment);
640 proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s",
646 * Tell our caller the first mechanism we see, so that if
647 * this is a negTokenInit with a mechToken, it can interpret
648 * the mechToken according to the first mechType. (There
649 * might not have been any indication of the mechType
650 * in prior frames, so we can't necessarily use the
651 * mechanism from the conversation; i.e., a negTokenInit
652 * can contain the initial security token for the desired
653 * mechanism of the initiator - that's the first mechanism
656 if (!saw_mechanism) {
658 *next_level_value_p = value;
659 saw_mechanism = TRUE;
674 dissect_spnego_reqFlags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
675 proto_tree *tree, ASN1_SCK *hnd)
678 guint len1, cls, con, tag, flags;
683 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
685 if (ret != ASN1_ERR_NOERROR) {
686 dissect_parse_error(tvb, offset, pinfo, tree,
687 "SPNEGO reqFlags header", ret);
691 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_BTS)) {
693 tree, tvb, offset, 0,
694 "Unknown header (cls=%d, con=%d, tag=%d)",
699 /* We must have a Bit String ... insert it */
701 offset = hnd->offset;
703 flags = tvb_get_guint8(tvb, offset);
705 item = proto_tree_add_item(tree, hf_spnego_reqflags, tvb, offset, len1,
708 subtree = proto_item_add_subtree(item, ett_spnego_reqflags);
711 * Now, the bits. XXX: Assume 8 bits. FIXME.
714 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_deleg, tvb, offset, len1, flags);
715 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_mutual, tvb, offset, len1, flags);
716 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_replay, tvb, offset, len1, flags);
717 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_sequence, tvb, offset, len1, flags);
718 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_anon, tvb, offset, len1, flags);
719 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_conf, tvb, offset, len1, flags);
720 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_integ, tvb, offset, len1, flags);
725 return offset + len1;
730 dissect_spnego_mechToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
731 proto_tree *tree, ASN1_SCK *hnd,
732 dissector_handle_t next_level_dissector)
738 guint cls, con, tag, nbytes;
739 gint length_remaining, reported_length_remaining;
743 * This appears to be a simple octet string ...
746 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
748 if (ret != ASN1_ERR_NOERROR) {
749 dissect_parse_error(tvb, offset, pinfo, tree,
750 "SPNEGO sequence header", ret);
754 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
756 tree, tvb, offset, 0,
757 "Unknown header (cls=%d, con=%d, tag=%d)",
762 offset = hnd->offset;
765 /* Dont try to create an item with more bytes than remains in the
766 * frame or we will not even attempt to dissect those bytes we
767 * do have. (since there will be an exception)
769 * We use "tvb_ensure_length_remaining()" so that we throw
770 * an exception if there's nothing to dissect.
772 length_remaining = tvb_ensure_length_remaining(tvb,offset);
773 reported_length_remaining = tvb_reported_length_remaining(tvb,offset);
774 if ((guint)length_remaining > nbytes)
775 length_remaining = nbytes;
776 if ((guint)reported_length_remaining > nbytes)
777 reported_length_remaining = nbytes;
778 item = proto_tree_add_item(tree, hf_spnego_mechtoken, tvb, offset,
779 length_remaining, FALSE);
780 subtree = proto_item_add_subtree(item, ett_spnego_mechtoken);
783 * Now, we should be able to dispatch after creating a new TVB.
786 token_tvb = tvb_new_subset(tvb, offset, length_remaining,
787 reported_length_remaining);
788 if (next_level_dissector)
789 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
791 hnd->offset += nbytes; /* Update this ... */
794 return offset + nbytes;
798 dissect_spnego_mechListMIC(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
799 proto_tree *tree, ASN1_SCK *hnd,
800 dissector_handle_t next_level_dissector)
802 guint len1, cls, con, tag;
805 proto_tree *subtree = NULL;
808 * Add the mechListMIC [3] Octet String or General String ...
810 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
812 if (ret != ASN1_ERR_NOERROR) {
813 dissect_parse_error(tvb, offset, pinfo, subtree,
814 "SPNEGO sequence header", ret);
818 offset = hnd->offset;
820 if (cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ) {
823 * There seems to be two different forms this can take
824 * One as an Octet string, and one as a general string in a
825 * sequence ... We will have to dissect this later
828 proto_tree_add_text(tree, tvb, offset + 4, len1 - 4,
830 tvb_format_text(tvb, offset + 4, len1 - 4));
832 /* Naughty ... but we have to adjust for what we never took */
838 else if (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS) {
843 item = proto_tree_add_item(tree, hf_spnego_mechlistmic, tvb, offset,
845 subtree = proto_item_add_subtree(item, ett_spnego_mechlistmic);
848 * Now, we should be able to dispatch after creating a new TVB.
851 token_tvb = tvb_new_subset(tvb, offset, len1, -1);
852 if (next_level_dissector)
853 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
855 hnd->offset += len1; /* Update this ... */
861 proto_tree_add_text(subtree, tvb, offset, 0,
862 "Unknown header (cls=%d, con=%d, tag=%d)",
874 dissect_spnego_negTokenInit(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
875 proto_tree *tree, ASN1_SCK *hnd,
876 gssapi_oid_value **next_level_value_p)
881 guint len1, len, cls, con, tag;
884 item = proto_tree_add_item( tree, hf_spnego_negtokeninit, tvb, offset,
886 subtree = proto_item_add_subtree(item, ett_spnego_negtokeninit);
889 * Here is what we need to get ...
890 * NegTokenInit ::= SEQUENCE {
891 * mechTypes [0] MechTypeList OPTIONAL,
892 * reqFlags [1] ContextFlags OPTIONAL,
893 * mechToken [2] OCTET STRING OPTIONAL,
894 * mechListMIC [3] OCTET STRING OPTIONAL }
898 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
900 if (ret != ASN1_ERR_NOERROR) {
901 dissect_parse_error(tvb, offset, pinfo, subtree,
902 "SPNEGO sequence header", ret);
906 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
908 subtree, tvb, offset, 0,
909 "Unknown header (cls=%d, con=%d, tag=%d)",
914 offset = hnd->offset;
919 hdr_ofs = hnd->offset;
921 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
923 if (ret != ASN1_ERR_NOERROR) {
924 dissect_parse_error(tvb, offset, pinfo, subtree,
925 "SPNEGO context header", ret);
929 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
930 proto_tree_add_text(subtree, tvb, offset, 0,
931 "Unknown header (cls=%d, con=%d, tag=%d)",
936 /* Adjust for the length of the header */
938 len1 -= (hnd->offset - hdr_ofs);
940 /* Should be one of the fields */
944 case SPNEGO_mechTypes:
946 offset = dissect_spnego_mechTypes(tvb, offset, pinfo,
952 case SPNEGO_reqFlags:
954 offset = dissect_spnego_reqFlags(tvb, offset, pinfo, subtree, hnd);
958 case SPNEGO_mechToken:
960 offset = dissect_spnego_mechToken(tvb, offset, pinfo, subtree,
961 hnd, gssapi_dissector_handle(*next_level_value_p));
964 case SPNEGO_mechListMIC:
966 offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
967 hnd, gssapi_dissector_handle(*next_level_value_p));
981 return offset; /* Not sure this is right */
985 dissect_spnego_negResult(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
986 proto_tree *tree, ASN1_SCK *hnd)
990 guint len, cls, con, tag, val;
992 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
994 if (ret != ASN1_ERR_NOERROR) {
995 dissect_parse_error(tvb, offset, pinfo, tree,
996 "SPNEGO context header", ret);
1000 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_ENUM)) {
1001 proto_tree_add_text(
1002 tree, tvb, offset, 0,
1003 "Unknown header (cls=%d, con=%d, tag=%d) xxx",
1008 offset = hnd->offset;
1010 /* Now, get the value */
1012 ret = asn1_uint32_value_decode(hnd, len, &val);
1014 if (ret != ASN1_ERR_NOERROR) {
1015 dissect_parse_error(tvb, offset, pinfo, tree,
1016 "SPNEGO negResult value", ret);
1020 proto_tree_add_item(tree, hf_spnego_negtokentarg_negresult, tvb,
1023 offset = hnd->offset;
1030 dissect_spnego_supportedMech(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1031 proto_tree *tree, ASN1_SCK *hnd,
1032 gssapi_oid_value **next_level_value_p)
1035 guint oid_len, nbytes;
1038 gssapi_oid_value *value;
1039 conversation_t *conversation;
1042 * Now, get the OID, and find the handle, if any
1045 offset = hnd->offset;
1047 ret = asn1_oid_decode(hnd, &oid, &oid_len, &nbytes);
1049 if (ret != ASN1_ERR_NOERROR) {
1050 dissect_parse_error(tvb, offset, pinfo, tree,
1051 "SPNEGO supportedMech token", ret);
1055 oid_string = format_oid(oid, oid_len);
1056 value = gssapi_lookup_oid(oid, oid_len);
1059 proto_tree_add_text(tree, tvb, offset, nbytes,
1060 "supportedMech: %s (%s)",
1061 oid_string, value->comment);
1063 proto_tree_add_text(tree, tvb, offset, nbytes, "supportedMech: %s",
1070 /* Should check for an unrecognized OID ... */
1073 *next_level_value_p = value;
1076 * Now, we need to save this in per proto info in the
1077 * conversation if it exists. We also should create a
1078 * conversation if one does not exist. FIXME!
1079 * Hmmm, might need to be smarter, because there can be
1080 * multiple mechTypes in a negTokenInit with one being the
1081 * default used in the Token if present. Then the negTokenTarg
1082 * could override that. :-(
1085 if ((conversation = find_conversation(&pinfo->src, &pinfo->dst,
1086 pinfo->ptype, pinfo->srcport,
1087 pinfo->destport, 0))) {
1090 conversation_add_proto_data(conversation, proto_spnego,
1091 *next_level_value_p);
1102 dissect_spnego_responseToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1103 proto_tree *tree, ASN1_SCK *hnd,
1104 dissector_handle_t next_level_dissector)
1108 guint cls, con, tag, nbytes;
1109 tvbuff_t *token_tvb;
1111 proto_tree *subtree;
1113 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
1115 if (ret != ASN1_ERR_NOERROR) {
1116 dissect_parse_error(tvb, offset, pinfo, tree,
1117 "SPNEGO sequence header", ret);
1121 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
1122 proto_tree_add_text(
1123 tree, tvb, offset, 0,
1124 "Unknown header (cls=%d, con=%d, tag=%d)",
1129 offset = hnd->offset;
1131 item = proto_tree_add_item(tree, hf_spnego_responsetoken, tvb, offset -2 ,
1134 subtree = proto_item_add_subtree(item, ett_spnego_responsetoken);
1138 * Now, we should be able to dispatch after creating a new TVB.
1139 * However, we should make sure that there is something in the
1140 * response token ...
1144 token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
1145 if (next_level_dissector)
1146 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1149 proto_tree_add_text(subtree, tvb, offset-2, 2, "<Empty String>");
1151 hnd->offset += nbytes; /* Update this ... */
1154 return offset + nbytes;
1158 dissect_spnego_negTokenTarg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1159 proto_tree *tree, ASN1_SCK *hnd,
1160 gssapi_oid_value **next_level_value_p)
1164 proto_tree *subtree;
1167 guint len1, len, cls, con, tag;
1169 item = proto_tree_add_item( tree, hf_spnego_negtokentarg, tvb, offset,
1171 subtree = proto_item_add_subtree(item, ett_spnego_negtokentarg);
1174 * Here is what we need to get ...
1175 * NegTokenTarg ::= SEQUENCE {
1176 * negResult [0] ENUMERATED {
1177 * accept_completed (0),
1178 * accept_incomplete (1),
1179 * reject (2) } OPTIONAL,
1180 * supportedMech [1] MechType OPTIONAL,
1181 * responseToken [2] OCTET STRING OPTIONAL,
1182 * mechListMIC [3] OCTET STRING OPTIONAL }
1185 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1187 if (ret != ASN1_ERR_NOERROR) {
1188 dissect_parse_error(tvb, offset, pinfo, subtree,
1189 "SPNEGO sequence header", ret);
1193 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
1194 proto_tree_add_text(
1195 subtree, tvb, offset, 0,
1196 "Unknown header (cls=%d, con=%d, tag=%d)",
1201 offset = hnd->offset;
1206 hdr_ofs = hnd->offset;
1208 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1210 if (ret != ASN1_ERR_NOERROR) {
1211 dissect_parse_error(tvb, offset, pinfo, subtree,
1212 "SPNEGO context header", ret);
1216 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1217 proto_tree_add_text(
1218 subtree, tvb, offset, 0,
1219 "Unknown header (cls=%d, con=%d, tag=%d)",
1224 /* Adjust for the length of the header */
1226 len1 -= (hnd->offset - hdr_ofs);
1228 /* Should be one of the fields */
1232 case SPNEGO_negResult:
1234 offset = dissect_spnego_negResult(tvb, offset, pinfo, subtree,
1238 case SPNEGO_supportedMech:
1240 offset = dissect_spnego_supportedMech(tvb, offset, pinfo, subtree,
1241 hnd, next_level_value_p);
1245 case SPNEGO_responseToken:
1247 offset = dissect_spnego_responseToken(tvb, offset, pinfo, subtree,
1248 hnd, gssapi_dissector_handle(*next_level_value_p));
1251 case SPNEGO_mechListMIC:
1253 offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
1254 hnd, gssapi_dissector_handle(*next_level_value_p));
1272 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1275 proto_tree *subtree;
1276 int ret, offset = 0;
1279 guint len1, cls, con, tag;
1280 conversation_t *conversation;
1281 gssapi_oid_value *next_level_value;
1284 * We need this later, so lets get it now ...
1285 * It has to be per-frame as there can be more than one GSS-API
1286 * negotiation in a conversation.
1289 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1290 if (!next_level_value && !pinfo->fd->flags.visited) {
1292 * No handle attached to this frame, but it's the first
1293 * pass, so it'd be attached to the conversation.
1294 * If we have a conversation, try to get the handle,
1295 * and if we get one, attach it to the frame.
1297 conversation = find_conversation(&pinfo->src, &pinfo->dst,
1298 pinfo->ptype, pinfo->srcport,
1299 pinfo->destport, 0);
1302 next_level_value = conversation_get_proto_data(conversation,
1304 if (next_level_value)
1305 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1309 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1312 subtree = proto_item_add_subtree(item, ett_spnego);
1315 * The TVB contains a [0] header and a sequence that consists of an
1316 * object ID and a blob containing the data ...
1317 * Actually, it contains, according to RFC2478:
1318 * NegotiationToken ::= CHOICE {
1319 * negTokenInit [0] NegTokenInit,
1320 * negTokenTarg [1] NegTokenTarg }
1321 * NegTokenInit ::= SEQUENCE {
1322 * mechTypes [0] MechTypeList OPTIONAL,
1323 * reqFlags [1] ContextFlags OPTIONAL,
1324 * mechToken [2] OCTET STRING OPTIONAL,
1325 * mechListMIC [3] OCTET STRING OPTIONAL }
1326 * NegTokenTarg ::= SEQUENCE {
1327 * negResult [0] ENUMERATED {
1328 * accept_completed (0),
1329 * accept_incomplete (1),
1330 * reject (2) } OPTIONAL,
1331 * supportedMech [1] MechType OPTIONAL,
1332 * responseToken [2] OCTET STRING OPTIONAL,
1333 * mechListMIC [3] OCTET STRING OPTIONAL }
1335 * Windows typically includes mechTypes and mechListMic ('NONE'
1336 * in the case of NTLMSSP only).
1337 * It seems to duplicate the responseToken into the mechListMic field
1338 * as well. Naughty, naughty.
1342 asn1_open(&hnd, tvb, offset);
1345 * Get the first header ...
1348 ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
1350 if (ret != ASN1_ERR_NOERROR) {
1351 dissect_parse_error(tvb, offset, pinfo, subtree,
1352 "SPNEGO context header", ret);
1356 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1357 proto_tree_add_text(
1358 subtree, tvb, offset, 0,
1359 "Unknown header (cls=%d, con=%d, tag=%d)",
1364 offset = hnd.offset;
1367 * The Tag is one of negTokenInit or negTokenTarg
1372 case SPNEGO_negTokenInit:
1374 offset = dissect_spnego_negTokenInit(tvb, offset, pinfo,
1380 case SPNEGO_negTokenTarg:
1382 offset = dissect_spnego_negTokenTarg(tvb, offset, pinfo,
1387 default: /* Broken, what to do? */
1394 asn1_close(&hnd, &offset);
1399 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1402 proto_tree *subtree;
1403 int ret, offset = 0;
1407 guint len1, cls, con, tag, nbytes;
1411 conversation_t *conversation;
1412 gssapi_oid_value *next_level_value;
1413 tvbuff_t *token_tvb;
1417 * We need this later, so lets get it now ...
1418 * It has to be per-frame as there can be more than one GSS-API
1419 * negotiation in a conversation.
1422 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1423 if (!next_level_value && !pinfo->fd->flags.visited) {
1425 * No handle attached to this frame, but it's the first
1426 * pass, so it'd be attached to the conversation.
1427 * If we have a conversation, try to get the handle,
1428 * and if we get one, attach it to the frame.
1430 conversation = find_conversation(&pinfo->src, &pinfo->dst,
1431 pinfo->ptype, pinfo->srcport,
1432 pinfo->destport, 0);
1435 next_level_value = conversation_get_proto_data(conversation,
1437 if (next_level_value)
1438 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1442 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1445 subtree = proto_item_add_subtree(item, ett_spnego);
1448 * The TVB contains a [0] header and a sequence that consists of an
1449 * object ID and a blob containing the data ...
1450 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1451 * with the "optional" "use in non-initial tokens" being chosen.
1454 asn1_open(&hnd, tvb, offset);
1457 * Get the first header ...
1460 ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
1462 if (ret != ASN1_ERR_NOERROR) {
1463 dissect_parse_error(tvb, offset, pinfo, subtree,
1464 "SPNEGO context header", ret);
1465 return_offset = tvb_length(tvb);
1469 if (!(cls == ASN1_APL && con == ASN1_CON && tag == 0)) {
1470 proto_tree_add_text(
1471 subtree, tvb, offset, 0,
1472 "Unknown header (cls=%d, con=%d, tag=%d)",
1474 return_offset = tvb_length(tvb);
1478 offset = hnd.offset;
1481 * Get the OID, and find the handle, if any
1484 ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
1486 if (ret != ASN1_ERR_NOERROR) {
1487 dissect_parse_error(tvb, offset, pinfo, tree,
1488 "SPNEGO wrap token", ret);
1489 return_offset = tvb_length(tvb);
1493 oid_string = format_oid(oid, oid_len);
1494 next_level_value = gssapi_lookup_oid(oid, oid_len);
1497 * XXX - what should we do if this doesn't match the value
1498 * attached to the frame or conversation? (That would be
1499 * bogus, but that's not impossible - some broken implementation
1500 * might negotiate some security mechanism but put the OID
1501 * for some other security mechanism in GSS_Wrap tokens.)
1503 if (next_level_value)
1504 proto_tree_add_text(tree, tvb, offset, nbytes,
1505 "thisMech: %s (%s)",
1506 oid_string, next_level_value->comment);
1508 proto_tree_add_text(tree, tvb, offset, nbytes, "thisMech: %s",
1516 * Now dissect the GSS_Wrap token; it's assumed to be in the
1517 * rest of the tvbuff.
1519 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset,
1522 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
1525 * Now, we should be able to dispatch after creating a new TVB.
1526 * The subdissector must return the length of the part of the
1527 * token it dissected, so we can return the length of the part
1528 * we (and it) dissected.
1531 token_tvb = tvb_new_subset(tvb, offset, -1, -1);
1532 if (next_level_value->wrap_handle) {
1533 len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
1535 return_offset = tvb_length(tvb);
1537 return_offset = offset + len;
1539 return_offset = tvb_length(tvb);
1541 asn1_close(&hnd, &offset);
1543 return return_offset;
1547 proto_register_spnego(void)
1549 static hf_register_info hf[] = {
1551 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1553 { &hf_spnego_negtokeninit,
1554 { "negTokenInit", "spnego.negtokeninit", FT_NONE, BASE_NONE,
1555 NULL, 0x0, "SPNEGO negTokenInit", HFILL}},
1556 { &hf_spnego_negtokentarg,
1557 { "negTokenTarg", "spnego.negtokentarg", FT_NONE, BASE_NONE,
1558 NULL, 0x0, "SPNEGO negTokenTarg", HFILL}},
1559 { &hf_spnego_mechtype,
1560 { "mechType", "spnego.negtokeninit.mechtype", FT_NONE,
1561 BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechTypes", HFILL}},
1562 { &hf_spnego_mechtoken,
1563 { "mechToken", "spnego.negtokeninit.mechtoken", FT_NONE,
1564 BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechToken", HFILL}},
1565 { &hf_spnego_mechlistmic,
1566 { "mechListMIC", "spnego.mechlistmic", FT_NONE,
1567 BASE_NONE, NULL, 0x0, "SPNEGO mechListMIC", HFILL}},
1568 { &hf_spnego_responsetoken,
1569 { "responseToken", "spnego.negtokentarg.responsetoken",
1570 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO responseToken",
1572 { &hf_spnego_negtokentarg_negresult,
1573 { "negResult", "spnego.negtokeninit.negresult", FT_UINT16,
1574 BASE_HEX, VALS(spnego_negResult_vals), 0, "negResult", HFILL}},
1575 { &hf_spnego_reqflags,
1576 { "reqFlags", "spnego.negtokeninit.reqflags", FT_BYTES,
1577 BASE_HEX, NULL, 0, "reqFlags", HFILL }},
1578 { &hf_gssapi_reqflags_deleg,
1579 { "Delegation", "gssapi.reqflags.deleg", FT_BOOLEAN, 8,
1580 TFS(&tfs_reqflags_deleg), 0x01, "Delegation", HFILL }},
1581 { &hf_gssapi_reqflags_mutual,
1582 { "Mutual Authentication", "gssapi.reqflags.mutual", FT_BOOLEAN,
1583 8, TFS(&tfs_reqflags_mutual), 0x02, "Mutual Authentication", HFILL}},
1584 { &hf_gssapi_reqflags_replay,
1585 { "Replay Detection", "gssapi.reqflags.replay", FT_BOOLEAN,
1586 8, TFS(&tfs_reqflags_replay), 0x04, "Replay Detection", HFILL}},
1587 { &hf_gssapi_reqflags_sequence,
1588 { "Out-of-sequence Detection", "gssapi.reqflags.sequence",
1589 FT_BOOLEAN, 8, TFS(&tfs_reqflags_sequence), 0x08,
1590 "Out-of-sequence Detection", HFILL}},
1591 { &hf_gssapi_reqflags_anon,
1592 { "Anonymous Authentication", "gssapi.reqflags.anon",
1593 FT_BOOLEAN, 8, TFS(&tfs_reqflags_anon), 0x10,
1594 "Anonymous Authentication", HFILL}},
1595 { &hf_gssapi_reqflags_conf,
1596 { "Per-message Confidentiality", "gssapi.reqflags.conf",
1597 FT_BOOLEAN, 8, TFS(&tfs_reqflags_conf), 0x20,
1598 "Per-message Confidentiality", HFILL}},
1599 { &hf_gssapi_reqflags_integ,
1600 { "Per-message Integrity", "gssapi.reqflags.integ",
1601 FT_BOOLEAN, 8, TFS(&tfs_reqflags_integ), 0x40,
1602 "Per-message Integrity", HFILL}},
1603 { &hf_spnego_wraptoken,
1604 { "wrapToken", "spnego.wraptoken",
1605 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1608 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1609 BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1610 { &hf_spnego_krb5_tok_id,
1611 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1612 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1613 { &hf_spnego_krb5_sgn_alg,
1614 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1615 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1616 { &hf_spnego_krb5_seal_alg,
1617 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1618 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1619 { &hf_spnego_krb5_snd_seq,
1620 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1621 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1622 { &hf_spnego_krb5_sgn_cksum,
1623 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1624 NULL, 0, "KRB5 Data Checksum", HFILL}},
1625 { &hf_spnego_krb5_confounder,
1626 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1627 NULL, 0, "KRB5 Confounder", HFILL}},
1630 static gint *ett[] = {
1632 &ett_spnego_negtokeninit,
1633 &ett_spnego_negtokentarg,
1634 &ett_spnego_mechtype,
1635 &ett_spnego_mechtoken,
1636 &ett_spnego_mechlistmic,
1637 &ett_spnego_responsetoken,
1638 &ett_spnego_wraptoken,
1642 proto_spnego = proto_register_protocol(
1643 "Spnego", "Spnego", "spnego");
1644 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1648 proto_register_field_array(proto_spnego, hf, array_length(hf));
1649 proto_register_subtree_array(ett, array_length(ett));
1653 proto_reg_handoff_spnego(void)
1655 dissector_handle_t spnego_handle, spnego_wrap_handle;
1656 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1658 /* Register protocol with GSS-API module */
1660 spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
1661 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
1663 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1664 spnego_handle, spnego_wrap_handle,
1665 "SPNEGO - Simple Protected Negotiation");
1667 /* Register both the one MS created and the real one */
1669 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1670 * mystery of the MS KRB5 OID is cleared up. It was due to a library
1671 * that did not handle OID components greater than 16 bits, and was
1672 * fixed in Win2K SP2 as well as WinXP.
1673 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1674 * SPNEGO implementation issues. 3-Dec-2002.
1676 spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
1678 spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
1680 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1681 spnego_krb5_handle, spnego_krb5_wrap_handle,
1682 "MS KRB5 - Microsoft Kerberos 5");
1683 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1684 spnego_krb5_handle, spnego_krb5_wrap_handle,
1685 "KRB5 - Kerberos 5");
1686 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1687 spnego_krb5_handle, spnego_krb5_wrap_handle,
1688 "KRB5 - Kerberos 5 - User to User");
1691 * Find the data handle for some calls
1693 data_handle = find_dissector("data");