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>
7 * $Id: packet-spnego.c,v 1.37 2002/10/25 04:22:26 guy Exp $
9 * Ethereal - Network traffic analyzer
10 * By Gerald Combs <gerald@ethereal.com>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
37 #include <epan/packet.h>
40 #include "format-oid.h"
41 #include "packet-gssapi.h"
42 #include "packet-kerberos.h"
43 #include <epan/conversation.h>
45 #define SPNEGO_negTokenInit 0
46 #define SPNEGO_negTokenTarg 1
47 #define SPNEGO_mechTypes 0
48 #define SPNEGO_reqFlags 1
49 #define SPNEGO_mechToken 2
50 #define SPNEGO_mechListMIC 3
51 #define SPNEGO_negResult 0
52 #define SPNEGO_supportedMech 1
53 #define SPNEGO_responseToken 2
54 #define SPNEGO_negResult_accept_completed 0
55 #define SPNEGO_negResult_accept_incomplete 1
56 #define SPNEGO_negResult_accept_reject 2
58 static int proto_spnego = -1;
59 static int proto_spnego_krb5 = -1;
61 static int hf_spnego = -1;
62 static int hf_spnego_negtokeninit = -1;
63 static int hf_spnego_negtokentarg = -1;
64 static int hf_spnego_mechtype = -1;
65 static int hf_spnego_mechtoken = -1;
66 static int hf_spnego_negtokentarg_negresult = -1;
67 static int hf_spnego_mechlistmic = -1;
68 static int hf_spnego_responsetoken = -1;
69 static int hf_spnego_reqflags = -1;
70 static int hf_spnego_krb5 = -1;
71 static int hf_spnego_krb5_tok_id = -1;
73 static gint ett_spnego = -1;
74 static gint ett_spnego_negtokeninit = -1;
75 static gint ett_spnego_negtokentarg = -1;
76 static gint ett_spnego_mechtype = -1;
77 static gint ett_spnego_mechtoken = -1;
78 static gint ett_spnego_mechlistmic = -1;
79 static gint ett_spnego_responsetoken = -1;
80 static gint ett_spnego_krb5 = -1;
82 static const value_string spnego_negResult_vals[] = {
83 { SPNEGO_negResult_accept_completed, "Accept Completed" },
84 { SPNEGO_negResult_accept_incomplete, "Accept Incomplete" },
85 { SPNEGO_negResult_accept_reject, "Accept Reject"},
89 /* Display an ASN1 parse error. Taken from packet-snmp.c */
91 static dissector_handle_t data_handle;
94 dissect_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
95 proto_tree *tree, const char *field_name, int ret)
99 errstr = asn1_err_to_str(ret);
102 proto_tree_add_text(tree, tvb, offset, 0,
103 "ERROR: Couldn't parse %s: %s", field_name, errstr);
104 call_dissector(data_handle,
105 tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
110 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
111 * wrapped blob with an OID, Boolean, and a Ticket, that is also ASN.1 wrapped
112 * by the looks of it.
115 #define KRB_TOKEN_AP_REQ 0x0001
116 #define KRB_TOKEN_AP_REP 0x0002
117 #define KRB_TOKEN_AP_ERR 0x0003
119 static const value_string spnego_krb5_tok_id_vals[] = {
120 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
121 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
122 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
127 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
134 guint len1, cls, con, tag, oid_len, nbytes;
137 gssapi_oid_value *value;
140 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
143 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
146 * The KRB5 blob conforms to RFC1964:
149 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR,
152 * However, for some protocols, the KRB5 blob stars at the SHORT
153 * and has no DER encoded header etc.
155 * It appears that for some other protocols the KRB5 blob is just
156 * a Kerberos message, with no [APPLICATION 0] header, no OID,
161 * If we see an [APPLICATION 0] HEADER, we show the OID and
162 * the USHORT, and then dissect the rest as a Kerberos message.
164 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
165 * we assume it's an AP-REQ or AP-REP message, and dissect
166 * it all as a Kerberos message.
168 * Otherwise, we show the USHORT, and then dissect the rest
169 * as a Kerberos message.
172 asn1_open(&hnd, tvb, offset);
175 * Get the first header ...
178 ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
180 if (ret != ASN1_ERR_NOERROR) {
181 dissect_parse_error(tvb, offset, pinfo, subtree,
182 "SPNEGO KRB5 Header", ret);
186 if (cls == ASN1_APL && con == ASN1_CON) {
188 * [APPLICATION <tag>]
201 ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
203 if (ret != ASN1_ERR_NOERROR) {
204 dissect_parse_error(tvb, offset, pinfo, subtree,
205 "SPNEGO supportedMech token", ret);
209 oid_string = format_oid(oid, oid_len);
211 value = gssapi_lookup_oid(oid, oid_len);
214 proto_tree_add_text(subtree, tvb, offset, nbytes,
216 oid_string, value->comment);
218 proto_tree_add_text(subtree, tvb, offset, nbytes,
226 /* Next, the token ID ... */
228 proto_tree_add_item(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
237 case 14: /* [APPLICATION 14] */
238 case 15: /* [APPLICATION 15] */
242 proto_tree_add_text(subtree, tvb, offset, 0,
243 "Unknown header (cls=%d, con=%d, tag=%d)",
248 /* Next, the token ID ... */
250 proto_tree_add_item(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
258 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
260 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE);
266 /* Spnego stuff from here */
269 dissect_spnego_mechTypes(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
270 proto_tree *tree, ASN1_SCK *hnd,
271 dissector_handle_t *next_level_dissector_p)
273 proto_item *item = NULL;
274 proto_tree *subtree = NULL;
276 guint len1, len, cls, con, tag, nbytes;
280 gboolean saw_mechanism = FALSE;
283 * MechTypeList ::= SEQUENCE OF MechType
286 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
288 if (ret != ASN1_ERR_NOERROR) {
289 dissect_parse_error(tvb, offset, pinfo, subtree,
290 "SPNEGO last sequence header", ret);
294 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
296 subtree, tvb, offset, 0,
297 "Unknown header (cls=%d, con=%d, tag=%d)",
302 offset = hnd->offset;
304 item = proto_tree_add_item(tree, hf_spnego_mechtype, tvb, offset,
306 subtree = proto_item_add_subtree(item, ett_spnego_mechtype);
309 * Now, the object IDs ... We should translate them: FIXME
313 gssapi_oid_value *value;
315 ret = asn1_oid_decode(hnd, &oid, &len, &nbytes);
317 if (ret != ASN1_ERR_NOERROR) {
318 dissect_parse_error(tvb, offset, pinfo, subtree,
319 "SPNEGO mechTypes token", ret);
323 oid_string = format_oid(oid, len);
324 value = gssapi_lookup_oid(oid, len);
326 proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s (%s)",
327 oid_string, value->comment);
329 proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s",
335 * Tell our caller the first mechanism we see, so that if
336 * this is a negTokenInit with a mechToken, it can interpret
337 * the mechToken according to the first mechType. (There
338 * might not have been any indication of the mechType
339 * in prior frames, so we can't necessarily use the
340 * mechanism from the conversation; i.e., a negTokenInit
341 * can contain the initial security token for the desired
342 * mechanism of the initiator - that's the first mechanism
345 if (!saw_mechanism) {
347 *next_level_dissector_p = value->handle;
348 saw_mechanism = TRUE;
363 dissect_spnego_reqFlags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
364 proto_tree *tree, ASN1_SCK *hnd)
367 guint len1, cls, con, tag;
370 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
372 if (ret != ASN1_ERR_NOERROR) {
373 dissect_parse_error(tvb, offset, pinfo, tree,
374 "SPNEGO reqFlags header", ret);
378 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_BTS)) {
380 tree, tvb, offset, 0,
381 "Unknown header (cls=%d, con=%d, tag=%d)",
386 /* We must have a Bit String ... insert it */
388 offset = hnd->offset;
390 proto_tree_add_item(tree, hf_spnego_reqflags, tvb, offset, len1,
396 return offset + len1;
401 dissect_spnego_mechToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
402 proto_tree *tree, ASN1_SCK *hnd,
403 dissector_handle_t next_level_dissector)
409 guint cls, con, tag, nbytes;
413 * This appears to be a simple octet string ...
416 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
418 if (ret != ASN1_ERR_NOERROR) {
419 dissect_parse_error(tvb, offset, pinfo, tree,
420 "SPNEGO sequence header", ret);
424 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
426 tree, tvb, offset, 0,
427 "Unknown header (cls=%d, con=%d, tag=%d)",
432 offset = hnd->offset;
434 item = proto_tree_add_item(tree, hf_spnego_mechtoken, tvb, offset,
436 subtree = proto_item_add_subtree(item, ett_spnego_mechtoken);
439 * Now, we should be able to dispatch after creating a new TVB.
442 token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
443 if (next_level_dissector)
444 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
446 hnd->offset += nbytes; /* Update this ... */
450 return offset + nbytes;
455 dissect_spnego_mechListMIC(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
456 proto_tree *tree, ASN1_SCK *hnd,
457 dissector_handle_t next_level_dissector)
459 guint len1, cls, con, tag;
462 proto_tree *subtree = NULL;
465 * Add the mechListMIC [3] Octet String or General String ...
467 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
469 if (ret != ASN1_ERR_NOERROR) {
470 dissect_parse_error(tvb, offset, pinfo, subtree,
471 "SPNEGO sequence header", ret);
475 offset = hnd->offset;
477 if (cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ) {
480 * There seems to be two different forms this can take
481 * One as an Octet string, and one as a general string in a
482 * sequence ... We will have to dissect this later
485 proto_tree_add_text(tree, tvb, offset + 4, len1 - 4,
487 tvb_format_text(tvb, offset + 4, len1 - 4));
489 /* Naughty ... but we have to adjust for what we never took */
495 else if (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS) {
500 item = proto_tree_add_item(tree, hf_spnego_mechlistmic, tvb, offset,
502 subtree = proto_item_add_subtree(item, ett_spnego_mechlistmic);
505 * Now, we should be able to dispatch after creating a new TVB.
508 token_tvb = tvb_new_subset(tvb, offset, len1, -1);
509 if (next_level_dissector)
510 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
512 hnd->offset += len1; /* Update this ... */
518 proto_tree_add_text(subtree, tvb, offset, 0,
519 "Unknown header (cls=%d, con=%d, tag=%d)",
531 dissect_spnego_negTokenInit(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
532 proto_tree *tree, ASN1_SCK *hnd,
533 dissector_handle_t *next_level_dissector_p)
538 guint len1, len, cls, con, tag;
541 item = proto_tree_add_item( tree, hf_spnego_negtokeninit, tvb, offset,
543 subtree = proto_item_add_subtree(item, ett_spnego_negtokeninit);
546 * Here is what we need to get ...
547 * NegTokenInit ::= SEQUENCE {
548 * mechTypes [0] MechTypeList OPTIONAL,
549 * reqFlags [1] ContextFlags OPTIONAL,
550 * mechToken [2] OCTET STRING OPTIONAL,
551 * mechListMIC [3] OCTET STRING OPTIONAL }
555 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
557 if (ret != ASN1_ERR_NOERROR) {
558 dissect_parse_error(tvb, offset, pinfo, subtree,
559 "SPNEGO sequence header", ret);
563 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
565 subtree, tvb, offset, 0,
566 "Unknown header (cls=%d, con=%d, tag=%d)",
571 offset = hnd->offset;
576 hdr_ofs = hnd->offset;
578 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
580 if (ret != ASN1_ERR_NOERROR) {
581 dissect_parse_error(tvb, offset, pinfo, subtree,
582 "SPNEGO context header", ret);
586 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
587 proto_tree_add_text(subtree, tvb, offset, 0,
588 "Unknown header (cls=%d, con=%d, tag=%d)",
593 /* Adjust for the length of the header */
595 len1 -= (hnd->offset - hdr_ofs);
597 /* Should be one of the fields */
601 case SPNEGO_mechTypes:
603 offset = dissect_spnego_mechTypes(tvb, offset, pinfo,
605 next_level_dissector_p);
609 case SPNEGO_reqFlags:
611 offset = dissect_spnego_reqFlags(tvb, offset, pinfo, subtree, hnd);
615 case SPNEGO_mechToken:
617 offset = dissect_spnego_mechToken(tvb, offset, pinfo, subtree,
618 hnd, *next_level_dissector_p);
621 case SPNEGO_mechListMIC:
623 offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
624 hnd, *next_level_dissector_p);
638 return offset; /* Not sure this is right */
642 dissect_spnego_negResult(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
643 proto_tree *tree, ASN1_SCK *hnd)
647 guint len, cls, con, tag, val;
649 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
651 if (ret != ASN1_ERR_NOERROR) {
652 dissect_parse_error(tvb, offset, pinfo, tree,
653 "SPNEGO context header", ret);
657 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_ENUM)) {
659 tree, tvb, offset, 0,
660 "Unknown header (cls=%d, con=%d, tag=%d) xxx",
665 offset = hnd->offset;
667 /* Now, get the value */
669 ret = asn1_uint32_value_decode(hnd, len, &val);
671 if (ret != ASN1_ERR_NOERROR) {
672 dissect_parse_error(tvb, offset, pinfo, tree,
673 "SPNEGO negResult value", ret);
677 proto_tree_add_item(tree, hf_spnego_negtokentarg_negresult, tvb,
680 offset = hnd->offset;
687 dissect_spnego_supportedMech(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
688 proto_tree *tree, ASN1_SCK *hnd,
689 dissector_handle_t *next_level_dissector_p)
692 guint oid_len, nbytes;
695 gssapi_oid_value *value;
696 conversation_t *conversation;
699 * Now, get the OID, and find the handle, if any
702 offset = hnd->offset;
704 ret = asn1_oid_decode(hnd, &oid, &oid_len, &nbytes);
706 if (ret != ASN1_ERR_NOERROR) {
707 dissect_parse_error(tvb, offset, pinfo, tree,
708 "SPNEGO supportedMech token", ret);
712 oid_string = format_oid(oid, oid_len);
713 value = gssapi_lookup_oid(oid, oid_len);
716 proto_tree_add_text(tree, tvb, offset, nbytes,
717 "supportedMech: %s (%s)",
718 oid_string, value->comment);
720 proto_tree_add_text(tree, tvb, offset, nbytes, "supportedMech: %s",
727 /* Should check for an unrecognized OID ... */
730 *next_level_dissector_p = value->handle;
733 * Now, we need to save this in per proto info in the
734 * conversation if it exists. We also should create a
735 * conversation if one does not exist. FIXME!
736 * Hmmm, might need to be smarter, because there can be
737 * multiple mechTypes in a negTokenInit with one being the
738 * default used in the Token if present. Then the negTokenTarg
739 * could override that. :-(
742 if ((conversation = find_conversation(&pinfo->src, &pinfo->dst,
743 pinfo->ptype, pinfo->srcport,
744 pinfo->destport, 0))) {
747 conversation_add_proto_data(conversation, proto_spnego,
748 *next_level_dissector_p);
759 dissect_spnego_responseToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
760 proto_tree *tree, ASN1_SCK *hnd,
761 dissector_handle_t next_level_dissector)
765 guint cls, con, tag, nbytes;
770 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
772 if (ret != ASN1_ERR_NOERROR) {
773 dissect_parse_error(tvb, offset, pinfo, tree,
774 "SPNEGO sequence header", ret);
778 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
780 tree, tvb, offset, 0,
781 "Unknown header (cls=%d, con=%d, tag=%d)",
786 offset = hnd->offset;
788 item = proto_tree_add_item(tree, hf_spnego_responsetoken, tvb, offset,
791 subtree = proto_item_add_subtree(item, ett_spnego_responsetoken);
794 * Now, we should be able to dispatch after creating a new TVB.
797 token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
798 if (next_level_dissector)
799 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
801 hnd->offset += nbytes; /* Update this ... */
804 return offset + nbytes;
808 dissect_spnego_negTokenTarg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
809 proto_tree *tree, ASN1_SCK *hnd,
810 dissector_handle_t *next_level_dissector_p)
817 guint len1, len, cls, con, tag;
819 item = proto_tree_add_item( tree, hf_spnego_negtokentarg, tvb, offset,
821 subtree = proto_item_add_subtree(item, ett_spnego_negtokentarg);
824 * Here is what we need to get ...
825 * NegTokenTarg ::= SEQUENCE {
826 * negResult [0] ENUMERATED {
827 * accept_completed (0),
828 * accept_incomplete (1),
829 * reject (2) } OPTIONAL,
830 * supportedMech [1] MechType OPTIONAL,
831 * responseToken [2] OCTET STRING OPTIONAL,
832 * mechListMIC [3] OCTET STRING OPTIONAL }
835 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
837 if (ret != ASN1_ERR_NOERROR) {
838 dissect_parse_error(tvb, offset, pinfo, subtree,
839 "SPNEGO sequence header", ret);
843 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
845 subtree, tvb, offset, 0,
846 "Unknown header (cls=%d, con=%d, tag=%d)",
851 offset = hnd->offset;
856 hdr_ofs = hnd->offset;
858 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
860 if (ret != ASN1_ERR_NOERROR) {
861 dissect_parse_error(tvb, offset, pinfo, subtree,
862 "SPNEGO context header", ret);
866 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
868 subtree, tvb, offset, 0,
869 "Unknown header (cls=%d, con=%d, tag=%d)",
874 /* Adjust for the length of the header */
876 len1 -= (hnd->offset - hdr_ofs);
878 /* Should be one of the fields */
882 case SPNEGO_negResult:
884 offset = dissect_spnego_negResult(tvb, offset, pinfo, subtree,
888 case SPNEGO_supportedMech:
890 offset = dissect_spnego_supportedMech(tvb, offset, pinfo, subtree,
891 hnd, next_level_dissector_p);
895 case SPNEGO_responseToken:
897 offset = dissect_spnego_responseToken(tvb, offset, pinfo, subtree,
898 hnd, *next_level_dissector_p);
901 case SPNEGO_mechListMIC:
903 offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
904 hnd, *next_level_dissector_p);
922 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
929 guint len1, cls, con, tag;
930 conversation_t *conversation;
931 dissector_handle_t next_level_dissector = NULL;
934 * We need this later, so lets get it now ...
937 conversation = find_conversation(&pinfo->src, &pinfo->dst,
938 pinfo->ptype, pinfo->srcport,
942 next_level_dissector = conversation_get_proto_data(conversation,
945 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
948 subtree = proto_item_add_subtree(item, ett_spnego);
951 * The TVB contains a [0] header and a sequence that consists of an
952 * object ID and a blob containing the data ...
953 * Actually, it contains, according to RFC2478:
954 * NegotiationToken ::= CHOICE {
955 * negTokenInit [0] NegTokenInit,
956 * negTokenTarg [1] NegTokenTarg }
957 * NegTokenInit ::= SEQUENCE {
958 * mechTypes [0] MechTypeList OPTIONAL,
959 * reqFlags [1] ContextFlags OPTIONAL,
960 * mechToken [2] OCTET STRING OPTIONAL,
961 * mechListMIC [3] OCTET STRING OPTIONAL }
962 * NegTokenTarg ::= SEQUENCE {
963 * negResult [0] ENUMERATED {
964 * accept_completed (0),
965 * accept_incomplete (1),
966 * reject (2) } OPTIONAL,
967 * supportedMech [1] MechType OPTIONAL,
968 * responseToken [2] OCTET STRING OPTIONAL,
969 * mechListMIC [3] OCTET STRING OPTIONAL }
971 * Windows typically includes mechTypes and mechListMic ('NONE'
972 * in the case of NTLMSSP only).
973 * It seems to duplicate the responseToken into the mechListMic field
974 * as well. Naughty, naughty.
978 asn1_open(&hnd, tvb, offset);
981 * Get the first header ...
984 ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
986 if (ret != ASN1_ERR_NOERROR) {
987 dissect_parse_error(tvb, offset, pinfo, subtree,
988 "SPNEGO context header", ret);
992 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
994 subtree, tvb, offset, 0,
995 "Unknown header (cls=%d, con=%d, tag=%d)",
1000 offset = hnd.offset;
1003 * The Tag is one of negTokenInit or negTokenTarg
1008 case SPNEGO_negTokenInit:
1010 offset = dissect_spnego_negTokenInit(tvb, offset, pinfo,
1012 &next_level_dissector);
1016 case SPNEGO_negTokenTarg:
1018 offset = dissect_spnego_negTokenTarg(tvb, offset, pinfo,
1020 &next_level_dissector);
1023 default: /* Broken, what to do? */
1030 asn1_close(&hnd, &offset);
1035 proto_register_spnego(void)
1037 static hf_register_info hf[] = {
1039 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1041 { &hf_spnego_negtokeninit,
1042 { "negTokenInit", "spnego.negtokeninit", FT_NONE, BASE_NONE,
1043 NULL, 0x0, "SPNEGO negTokenInit", HFILL}},
1044 { &hf_spnego_negtokentarg,
1045 { "negTokenTarg", "spnego.negtokentarg", FT_NONE, BASE_NONE,
1046 NULL, 0x0, "SPNEGO negTokenTarg", HFILL}},
1047 { &hf_spnego_mechtype,
1048 { "mechType", "spnego.negtokeninit.mechtype", FT_NONE,
1049 BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechTypes", HFILL}},
1050 { &hf_spnego_mechtoken,
1051 { "mechToken", "spnego.negtokeninit.mechtoken", FT_NONE,
1052 BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechToken", HFILL}},
1053 { &hf_spnego_mechlistmic,
1054 { "mechListMIC", "spnego.mechlistmic", FT_NONE,
1055 BASE_NONE, NULL, 0x0, "SPNEGO mechListMIC", HFILL}},
1056 { &hf_spnego_responsetoken,
1057 { "responseToken", "spnego.negtokentarg.responsetoken",
1058 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO responseToken",
1060 { &hf_spnego_negtokentarg_negresult,
1061 { "negResult", "spnego.negtokeninit.negresult", FT_UINT16,
1062 BASE_HEX, VALS(spnego_negResult_vals), 0, "negResult", HFILL}},
1063 { &hf_spnego_reqflags,
1064 { "reqFlags", "spnego.negtokeninit.reqflags", FT_BYTES,
1065 BASE_HEX, NULL, 0, "reqFlags", HFILL }},
1067 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1068 BASE_HEX, NULL, 0, "krb5_blob", HFILL }},
1069 { &hf_spnego_krb5_tok_id,
1070 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1071 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Ids", HFILL}},
1074 static gint *ett[] = {
1076 &ett_spnego_negtokeninit,
1077 &ett_spnego_negtokentarg,
1078 &ett_spnego_mechtype,
1079 &ett_spnego_mechtoken,
1080 &ett_spnego_mechlistmic,
1081 &ett_spnego_responsetoken,
1085 proto_spnego = proto_register_protocol(
1086 "Spnego", "Spnego", "spnego");
1087 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1091 proto_register_field_array(proto_spnego, hf, array_length(hf));
1092 proto_register_subtree_array(ett, array_length(ett));
1096 proto_reg_handoff_spnego(void)
1098 dissector_handle_t spnego_handle, spnego_krb5_handle;
1100 /* Register protocol with GSS-API module */
1102 spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
1103 spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
1105 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1106 spnego_handle, "SPNEGO - Simple Protected Negotiation");
1108 /* Register both the one MS created and the real one */
1109 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1110 spnego_krb5_handle, "MS KRB5 - Microsoft Kerberos 5");
1111 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1112 spnego_krb5_handle, "KRB5 - Kerberos 5");