1 /* Do not modify this file. */
2 /* It is created automatically by the ASN.1 to Ethereal dissector compiler */
3 /* .\packet-spnego.c */
4 /* ../../tools/asn2eth.py -X -b -e -p spnego -c spnego.cnf -s packet-spnego-template spnego.asn */
6 /* Input file: packet-spnego-template.c */
9 * Routines for the simple and protected GSS-API negotiation mechanism
10 * as described in RFC 2478.
11 * Copyright 2002, Tim Potter <tpot@samba.org>
12 * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
13 * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
14 * Copyright 2005, Ronnie Sahlberg (krb decryption)
15 * Copyright 2005, Anders Broman (converted to asn2eth generated dissector)
19 * Ethereal - Network traffic analyzer
20 * By Gerald Combs <gerald@ethereal.com>
21 * Copyright 1998 Gerald Combs
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
38 Heimdal 1.6 and has been modified for ethereal's requirements.
46 #include <epan/packet.h>
47 #include "packet-dcerpc.h"
48 #include "packet-gssapi.h"
49 #include "packet-kerberos.h"
50 #include <epan/crypt-rc4.h>
51 #include <epan/conversation.h>
52 #include <epan/emem.h>
57 #include "packet-ber.h"
60 #define PNAME "Simple Protected Negotiation"
61 #define PSNAME "SPNEGO"
62 #define PFNAME "spnego"
64 /* Initialize the protocol and registered fields */
65 static int proto_spnego = -1;
66 static int proto_spnego_krb5 = -1;
69 static int hf_spnego = -1;
70 static int hf_spnego_wraptoken = -1;
71 static int hf_spnego_krb5_oid;
72 static int hf_spnego_krb5 = -1;
73 static int hf_spnego_krb5_tok_id = -1;
74 static int hf_spnego_krb5_sgn_alg = -1;
75 static int hf_spnego_krb5_seal_alg = -1;
76 static int hf_spnego_krb5_snd_seq = -1;
77 static int hf_spnego_krb5_sgn_cksum = -1;
78 static int hf_spnego_krb5_confounder = -1;
81 /*--- Included file: packet-spnego-hf.c ---*/
83 static int hf_spnego_negTokenInit = -1; /* NegTokenInit */
84 static int hf_spnego_negTokenTarg = -1; /* NegTokenTarg */
85 static int hf_spnego_MechTypeList_item = -1; /* MechType */
86 static int hf_spnego_principal = -1; /* GeneralString */
87 static int hf_spnego_mechTypes = -1; /* MechTypeList */
88 static int hf_spnego_reqFlags = -1; /* ContextFlags */
89 static int hf_spnego_mechToken = -1; /* T_mechToken */
90 static int hf_spnego_negTokenInit_mechListMIC = -1; /* T_NegTokenInit_mechListMIC */
91 static int hf_spnego_negResult = -1; /* T_negResult */
92 static int hf_spnego_supportedMech = -1; /* T_supportedMech */
93 static int hf_spnego_responseToken = -1; /* T_responseToken */
94 static int hf_spnego_mechListMIC = -1; /* T_mechListMIC */
95 static int hf_spnego_thisMech = -1; /* MechType */
96 static int hf_spnego_innerContextToken = -1; /* InnerContextToken */
98 static int hf_spnego_ContextFlags_delegFlag = -1;
99 static int hf_spnego_ContextFlags_mutualFlag = -1;
100 static int hf_spnego_ContextFlags_replayFlag = -1;
101 static int hf_spnego_ContextFlags_sequenceFlag = -1;
102 static int hf_spnego_ContextFlags_anonFlag = -1;
103 static int hf_spnego_ContextFlags_confFlag = -1;
104 static int hf_spnego_ContextFlags_integFlag = -1;
106 /*--- End of included file: packet-spnego-hf.c ---*/
109 /* Global variables */
110 static const char *MechType_oid;
111 gssapi_oid_value *next_level_value;
112 gboolean saw_mechanism = FALSE;
115 /* Initialize the subtree pointers */
116 static gint ett_spnego;
117 static gint ett_spnego_wraptoken;
118 static gint ett_spnego_krb5 = -1;
121 /*--- Included file: packet-spnego-ett.c ---*/
123 static gint ett_spnego_NegotiationToken = -1;
124 static gint ett_spnego_MechTypeList = -1;
125 static gint ett_spnego_PrincipalSeq = -1;
126 static gint ett_spnego_NegTokenInit = -1;
127 static gint ett_spnego_ContextFlags = -1;
128 static gint ett_spnego_NegTokenTarg = -1;
129 static gint ett_spnego_InitialContextToken = -1;
131 /*--- End of included file: packet-spnego-ett.c ---*/
134 static dissector_handle_t data_handle;
137 * Unfortunately, we have to have a forward declaration of this,
138 * as the code generated by asn2eth includes a call before the
141 static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
142 int offset, packet_info *pinfo,
143 proto_tree *tree, int hf_index);
146 /*--- Included file: packet-spnego-fn.c ---*/
148 /*--- Fields for imported types ---*/
154 dissect_spnego_MechType(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
156 gssapi_oid_value *value;
158 offset = dissect_ber_object_identifier_str(implicit_tag, pinfo, tree, tvb, offset, hf_index, &MechType_oid);
161 value = gssapi_lookup_oid_str(MechType_oid);
164 * Tell our caller the first mechanism we see, so that if
165 * this is a negTokenInit with a mechToken, it can interpret
166 * the mechToken according to the first mechType. (There
167 * might not have been any indication of the mechType
168 * in prior frames, so we can't necessarily use the
169 * mechanism from the conversation; i.e., a negTokenInit
170 * can contain the initial security token for the desired
171 * mechanism of the initiator - that's the first mechanism
174 if (!saw_mechanism) {
176 next_level_value = value;
177 saw_mechanism = TRUE;
183 static int dissect_MechTypeList_item(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
184 return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_MechTypeList_item);
186 static int dissect_thisMech(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
187 return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_thisMech);
191 static const ber_sequence_t MechTypeList_sequence_of[1] = {
192 { BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_MechTypeList_item },
196 dissect_spnego_MechTypeList(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
198 saw_mechanism = FALSE;
200 offset = dissect_ber_sequence_of(implicit_tag, pinfo, tree, tvb, offset,
201 MechTypeList_sequence_of, hf_index, ett_spnego_MechTypeList);
205 static int dissect_mechTypes(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
206 return dissect_spnego_MechTypeList(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechTypes);
210 static const asn_namedbit ContextFlags_bits[] = {
211 { 0, &hf_spnego_ContextFlags_delegFlag, -1, -1, "delegFlag", NULL },
212 { 1, &hf_spnego_ContextFlags_mutualFlag, -1, -1, "mutualFlag", NULL },
213 { 2, &hf_spnego_ContextFlags_replayFlag, -1, -1, "replayFlag", NULL },
214 { 3, &hf_spnego_ContextFlags_sequenceFlag, -1, -1, "sequenceFlag", NULL },
215 { 4, &hf_spnego_ContextFlags_anonFlag, -1, -1, "anonFlag", NULL },
216 { 5, &hf_spnego_ContextFlags_confFlag, -1, -1, "confFlag", NULL },
217 { 6, &hf_spnego_ContextFlags_integFlag, -1, -1, "integFlag", NULL },
218 { 0, NULL, 0, 0, NULL, NULL }
222 dissect_spnego_ContextFlags(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
223 offset = dissect_ber_bitstring(implicit_tag, pinfo, tree, tvb, offset,
224 ContextFlags_bits, hf_index, ett_spnego_ContextFlags,
229 static int dissect_reqFlags(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
230 return dissect_spnego_ContextFlags(FALSE, tvb, offset, pinfo, tree, hf_spnego_reqFlags);
236 dissect_spnego_T_mechToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
238 tvbuff_t *mechToken_tvb = NULL;
240 offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index,
245 * Now, we should be able to dispatch, if we've gotten a tvbuff for
246 * the token and we have information on how to dissect its contents.
248 if (mechToken_tvb && next_level_value)
249 call_dissector(next_level_value->handle, mechToken_tvb, pinfo, tree);
255 static int dissect_mechToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
256 return dissect_spnego_T_mechToken(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechToken);
262 dissect_spnego_T_NegTokenInit_mechListMIC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
267 tvbuff_t *mechListMIC_tvb;
270 * There seems to be two different forms this can take,
271 * one as an octet string, and one as a general string in a
274 * Peek at the header, and then decide which it is we're seeing.
276 get_ber_identifier(tvb, offset, &class, &pc, &tag);
277 if (class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE) {
281 return dissect_spnego_PrincipalSeq(FALSE, tvb, offset, pinfo, tree,
282 hf_spnego_mechListMIC);
285 * It's not a sequence, so dissect it as an octet string,
286 * which is what it's supposed to be; that'll cause the
287 * right error report if it's not an octet string, either.
289 offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, offset,
290 hf_spnego_mechListMIC, &mechListMIC_tvb);
293 * Now, we should be able to dispatch with that tvbuff.
295 if (mechListMIC_tvb && next_level_value)
296 call_dissector(next_level_value->handle, mechListMIC_tvb, pinfo, tree);
303 static int dissect_negTokenInit_mechListMIC(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
304 return dissect_spnego_T_NegTokenInit_mechListMIC(FALSE, tvb, offset, pinfo, tree, hf_spnego_negTokenInit_mechListMIC);
308 static const ber_sequence_t NegTokenInit_sequence[] = {
309 { BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_mechTypes },
310 { BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_reqFlags },
311 { BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_mechToken },
312 { BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_negTokenInit_mechListMIC },
317 dissect_spnego_NegTokenInit(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
318 offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
319 NegTokenInit_sequence, hf_index, ett_spnego_NegTokenInit);
323 static int dissect_negTokenInit(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
324 return dissect_spnego_NegTokenInit(FALSE, tvb, offset, pinfo, tree, hf_spnego_negTokenInit);
328 static const value_string spnego_T_negResult_vals[] = {
329 { 0, "accept-completed" },
330 { 1, "accept-incomplete" },
337 dissect_spnego_T_negResult(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
338 offset = dissect_ber_integer(implicit_tag, pinfo, tree, tvb, offset, hf_index,
343 static int dissect_negResult(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
344 return dissect_spnego_T_negResult(FALSE, tvb, offset, pinfo, tree, hf_spnego_negResult);
350 dissect_spnego_T_supportedMech(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
352 conversation_t *conversation;
354 saw_mechanism = FALSE;
356 offset = dissect_spnego_MechType(implicit_tag, tvb, offset, pinfo, tree, hf_index);
360 * Now, we need to save this in per-proto info in the
361 * conversation if it exists. We also should create a
362 * conversation if one does not exist. FIXME!
363 * Hmmm, might need to be smarter, because there can be
364 * multiple mechTypes in a negTokenInit with one being the
365 * default used in the Token if present. Then the negTokenTarg
366 * could override that. :-(
368 if ((conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
369 pinfo->ptype, pinfo->srcport,
370 pinfo->destport, 0))) {
371 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
378 static int dissect_supportedMech(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
379 return dissect_spnego_T_supportedMech(FALSE, tvb, offset, pinfo, tree, hf_spnego_supportedMech);
385 dissect_spnego_T_responseToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
387 tvbuff_t *responseToken_tvb;
390 offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index,
396 * Now, we should be able to dispatch, if we've gotten a tvbuff for
397 * the token and we have information on how to dissect its contents.
398 * However, we should make sure that there is something in the
401 if (responseToken_tvb && next_level_value) {
402 if (tvb_reported_length(responseToken_tvb) > 0)
403 call_dissector(next_level_value->handle, responseToken_tvb, pinfo, tree);
410 static int dissect_responseToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
411 return dissect_spnego_T_responseToken(FALSE, tvb, offset, pinfo, tree, hf_spnego_responseToken);
417 dissect_spnego_T_mechListMIC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
419 tvbuff_t *mechListMIC_tvb;
422 offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index,
428 * Now, we should be able to dispatch, if we've gotten a tvbuff for
429 * the MIC and we have information on how to dissect its contents.
431 if (mechListMIC_tvb && next_level_value)
432 call_dissector(next_level_value->handle, mechListMIC_tvb, pinfo, tree);
438 static int dissect_mechListMIC(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
439 return dissect_spnego_T_mechListMIC(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechListMIC);
443 static const ber_sequence_t NegTokenTarg_sequence[] = {
444 { BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_negResult },
445 { BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_supportedMech },
446 { BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_responseToken },
447 { BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_mechListMIC },
452 dissect_spnego_NegTokenTarg(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
453 offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
454 NegTokenTarg_sequence, hf_index, ett_spnego_NegTokenTarg);
458 static int dissect_negTokenTarg(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
459 return dissect_spnego_NegTokenTarg(FALSE, tvb, offset, pinfo, tree, hf_spnego_negTokenTarg);
463 static const value_string spnego_NegotiationToken_vals[] = {
464 { 0, "negTokenInit" },
465 { 1, "negTokenTarg" },
469 static const ber_choice_t NegotiationToken_choice[] = {
470 { 0, BER_CLASS_CON, 0, 0, dissect_negTokenInit },
471 { 1, BER_CLASS_CON, 1, 0, dissect_negTokenTarg },
476 dissect_spnego_NegotiationToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
477 offset = dissect_ber_choice(pinfo, tree, tvb, offset,
478 NegotiationToken_choice, hf_index, ett_spnego_NegotiationToken,
487 dissect_spnego_GeneralString(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
488 offset = dissect_ber_restricted_string(implicit_tag, BER_UNI_TAG_GeneralString,
489 pinfo, tree, tvb, offset, hf_index,
494 static int dissect_principal(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
495 return dissect_spnego_GeneralString(FALSE, tvb, offset, pinfo, tree, hf_spnego_principal);
499 static const ber_sequence_t PrincipalSeq_sequence[] = {
500 { BER_CLASS_CON, 0, 0, dissect_principal },
505 dissect_spnego_PrincipalSeq(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
506 offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
507 PrincipalSeq_sequence, hf_index, ett_spnego_PrincipalSeq);
515 dissect_spnego_InnerContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
517 gssapi_oid_value *next_level_value;
524 * XXX - what should we do if this OID doesn't match the value
525 * attached to the frame or conversation? (That would be
526 * bogus, but that's not impossible - some broken implementation
527 * might negotiate some security mechanism but put the OID
528 * for some other security mechanism in GSS_Wrap tokens.)
531 next_level_value = gssapi_lookup_oid_str(MechType_oid);
534 * Now dissect the GSS_Wrap token; it's assumed to be in the
535 * rest of the tvbuff.
537 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, -1, FALSE);
539 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
542 * Now, we should be able to dispatch after creating a new TVB.
543 * The subdissector must return the length of the part of the
544 * token it dissected, so we can return the length of the part
545 * we (and it) dissected.
547 token_tvb = tvb_new_subset(tvb, offset, -1, -1);
548 if (next_level_value && next_level_value->wrap_handle) {
549 len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo,
552 offset = tvb_length(tvb);
554 offset = offset + len;
556 offset = tvb_length(tvb);
561 static int dissect_innerContextToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
562 return dissect_spnego_InnerContextToken(FALSE, tvb, offset, pinfo, tree, hf_spnego_innerContextToken);
566 static const ber_sequence_t InitialContextToken_sequence[] = {
567 { BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_thisMech },
568 { BER_CLASS_ANY, 0, BER_FLAGS_NOOWNTAG, dissect_innerContextToken },
573 dissect_spnego_InitialContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
574 offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
575 InitialContextToken_sequence, hf_index, ett_spnego_InitialContextToken);
581 /*--- End of included file: packet-spnego-fn.c ---*/
584 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
585 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
586 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
589 #define KRB_TOKEN_AP_REQ 0x0001
590 #define KRB_TOKEN_AP_REP 0x0002
591 #define KRB_TOKEN_AP_ERR 0x0003
592 #define KRB_TOKEN_GETMIC 0x0101
593 #define KRB_TOKEN_WRAP 0x0102
594 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
596 static const value_string spnego_krb5_tok_id_vals[] = {
597 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
598 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
599 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
600 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
601 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
602 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
606 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
607 #define KRB_SGN_ALG_MD2_5 0x0001
608 #define KRB_SGN_ALG_DES_MAC 0x0002
609 #define KRB_SGN_ALG_HMAC 0x0011
611 static const value_string spnego_krb5_sgn_alg_vals[] = {
612 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
613 { KRB_SGN_ALG_MD2_5, "MD2.5"},
614 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
615 { KRB_SGN_ALG_HMAC, "HMAC"},
619 #define KRB_SEAL_ALG_DES_CBC 0x0000
620 #define KRB_SEAL_ALG_RC4 0x0010
621 #define KRB_SEAL_ALG_NONE 0xffff
623 static const value_string spnego_krb5_seal_alg_vals[] = {
624 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
625 { KRB_SEAL_ALG_RC4, "RC4"},
626 { KRB_SEAL_ALG_NONE, "None"},
631 * XXX - is this for SPNEGO or just GSS-API?
632 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
633 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
634 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
635 * getting it accepted.
638 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
640 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
643 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
650 gssapi_oid_value *value;
653 gboolean pc, ind = 0;
657 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
660 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
663 * The KRB5 blob conforms to RFC1964:
666 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
669 * However, for some protocols, the KRB5 blob starts at the SHORT
670 * and has no DER encoded header etc.
672 * It appears that for some other protocols the KRB5 blob is just
673 * a Kerberos message, with no [APPLICATION 0] header, no OID,
678 * If we see an [APPLICATION 0] HEADER, we show the OID and
679 * the USHORT, and then dissect the rest as a Kerberos message.
681 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
682 * we assume it's an AP-REQ or AP-REP message, and dissect
683 * it all as a Kerberos message.
685 * Otherwise, we show the USHORT, and then dissect the rest
686 * as a Kerberos message.
690 * Get the first header ...
692 get_ber_identifier(tvb, offset, &class, &pc, &tag);
693 if (class == BER_CLASS_APP && pc) {
695 * [APPLICATION <tag>]
697 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
698 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
708 offset=dissect_ber_object_identifier_str(FALSE, pinfo, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
710 value = gssapi_lookup_oid_str(oid);
712 token_id = tvb_get_letohs(tvb, offset);
713 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
720 case 14: /* [APPLICATION 14] */
721 case 15: /* [APPLICATION 15] */
723 * No token ID - just dissect as a Kerberos message and
726 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
730 proto_tree_add_text(subtree, tvb, offset, 0,
731 "Unknown header (class=%d, pc=%d, tag=%d)",
736 /* Next, the token ID ... */
738 token_id = tvb_get_letohs(tvb, offset);
739 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
747 case KRB_TOKEN_AP_REQ:
748 case KRB_TOKEN_AP_REP:
749 case KRB_TOKEN_AP_ERR:
750 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
751 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
754 case KRB_TOKEN_GETMIC:
755 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
759 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
762 case KRB_TOKEN_DELETE_SEC_CONTEXT:
776 #include <epan/crypt-md5.h>
778 #ifndef KEYTYPE_ARCFOUR_56
779 # define KEYTYPE_ARCFOUR_56 24
781 /* XXX - We should probably do a configure-time check for this instead */
782 #ifndef KRB5_KU_USAGE_SEAL
783 # define KRB5_KU_USAGE_SEAL 22
787 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
788 void *cksum_data, size_t cksum_size,
796 if (key_type == KEYTYPE_ARCFOUR_56) {
797 guint8 L40[14] = "fortybits";
799 memcpy(L40 + 10, T, sizeof(T));
805 memset(&k5_data[7], 0xAB, 9);
815 cksum_data, cksum_size,
824 usage2arcfour(int usage)
827 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
828 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
830 case 22: /*KRB5_KU_USAGE_SEAL 22 */
832 case 23: /*KRB5_KU_USAGE_SIGN 23 */
834 case 24: /*KRB5_KU_USAGE_SEQ 24 */
842 arcfour_mic_cksum(guint8 *key_data, int key_length,
845 const void *v1, size_t l1,
846 const void *v2, size_t l2,
847 const void *v3, size_t l3)
849 const guint8 signature[] = "signaturekey";
853 unsigned char digest[16];
857 rc4_usage=usage2arcfour(usage);
858 md5_hmac(signature, sizeof(signature),
859 key_data, key_length,
862 t[0] = (rc4_usage >> 0) & 0xFF;
863 t[1] = (rc4_usage >> 8) & 0xFF;
864 t[2] = (rc4_usage >> 16) & 0xFF;
865 t[3] = (rc4_usage >> 24) & 0xFF;
866 md5_append(&ms, t, 4);
867 md5_append(&ms, v1, l1);
868 md5_append(&ms, v2, l2);
869 md5_append(&ms, v3, l3);
870 md5_finish(&ms, digest);
871 md5_hmac(digest, 16, ksign_c, 16, cksum);
873 memcpy(sgn_cksum, cksum, 8);
879 * Verify padding of a gss wrapped message and return its length.
882 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
890 pad = wrapped_data + wrapped_length - 1;
893 if (padlength > datalen)
896 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
907 decrypt_arcfour(packet_info *pinfo,
908 guint8 *input_message_buffer,
909 guint8 *output_message_buffer,
910 guint8 *key_value, int key_size, int key_type)
912 guint8 Klocaldata[16];
916 guint8 k6_data[16], SND_SEQ[8], Confounder[8];
917 guint8 cksum_data[8];
922 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
924 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
926 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
932 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
936 ret = arcfour_mic_key(key_value, key_size, key_type,
937 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
945 rc4_state_struct rc4_state;
947 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
948 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
949 crypt_rc4(&rc4_state, SND_SEQ, 8);
951 memset(k6_data, 0, sizeof(k6_data));
954 seq_number=g_ntohl(*((guint32 *)SND_SEQ));
956 cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
958 cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
968 for (i = 0; i < 16; i++)
969 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
971 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
974 memset(Klocaldata, 0, sizeof(Klocaldata));
980 rc4_state_struct rc4_state;
982 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
983 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
984 crypt_rc4(&rc4_state, Confounder, 8);
985 memcpy(output_message_buffer, input_message_buffer, datalen);
986 crypt_rc4(&rc4_state, output_message_buffer, datalen);
989 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
991 memcpy(output_message_buffer,
992 input_message_buffer,
995 memset(k6_data, 0, sizeof(k6_data));
997 /* only normal (i.e. non DCE style wrapping use padding ? */
998 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
999 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
1006 /* dont know what the checksum looks like for dce style gssapi */
1007 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1008 ret = arcfour_mic_cksum(key_value, key_size,
1011 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
1012 Confounder, sizeof(Confounder),
1013 output_message_buffer,
1019 cmp = memcmp(cksum_data,
1020 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
1032 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1035 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
1040 const guint8 *original_data;
1042 static int omb_index=0;
1043 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
1044 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
1045 guint8 *output_message_buffer;
1051 output_message_buffer=omb_arr[omb_index];
1054 length=tvb_length(pinfo->gssapi_encrypted_tvb);
1055 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
1057 /* dont do anything if we are not attempting to decrypt data */
1063 /* XXX we should only do this for first time, then store somewhere */
1064 /* XXX We also need to re-read the keytab when the preference changes */
1066 cryptocopy=ep_alloc(length);
1067 if(output_message_buffer){
1068 g_free(output_message_buffer);
1069 output_message_buffer=NULL;
1071 output_message_buffer=g_malloc(length);
1073 for(ek=enc_key_list;ek;ek=ek->next){
1074 /* shortcircuit and bail out if enctypes are not matching */
1075 if(ek->keytype!=keytype){
1079 /* pre-0.6.1 versions of Heimdal would sometimes change
1080 the cryptotext data even when the decryption failed.
1081 This would obviously not work since we iterate over the
1082 keys. So just give it a copy of the crypto data instead.
1083 This has been seen for RC4-HMAC blobs.
1085 memcpy(cryptocopy, original_data, length);
1086 ret=decrypt_arcfour(pinfo,
1088 output_message_buffer,
1094 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
1095 pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
1096 output_message_buffer,
1098 tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
1099 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1105 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1111 * XXX - This is for GSSAPI Wrap tokens ...
1114 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1115 #ifndef HAVE_KERBEROS
1118 , proto_tree *tree, guint16 token_id
1119 #ifndef HAVE_KERBEROS
1124 guint16 sgn_alg, seal_alg;
1125 #ifdef HAVE_KERBEROS
1126 int start_offset=offset;
1130 * The KRB5 blob conforms to RFC1964:
1131 * USHORT (0x0102 == GSS_Wrap)
1135 /* Now, the sign and seal algorithms ... */
1137 sgn_alg = tvb_get_letohs(tvb, offset);
1138 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1143 seal_alg = tvb_get_letohs(tvb, offset);
1144 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
1149 /* Skip the filler */
1153 /* Encrypted sequence number */
1155 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1160 /* Checksum of plaintext padded data */
1162 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1168 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1169 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1170 * extra 8 bytes of "Random confounder" after the checksum.
1171 * It certainly confounds code expecting all Kerberos 5
1172 * GSS_Wrap() tokens to look the same....
1174 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1175 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1180 /* Is the data encrypted? */
1181 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
1183 #ifdef HAVE_KERBEROS
1184 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
1185 if(pinfo->decrypt_gssapi_tvb){
1186 /* if the caller did not provide a tvb, then we just use
1187 whatever is left of our current tvb.
1189 if(!pinfo->gssapi_encrypted_tvb){
1191 len=tvb_reported_length_remaining(tvb,offset);
1192 if(len>tvb_length_remaining(tvb, offset)){
1193 /* no point in trying to decrypt,
1194 we dont have the full pdu.
1198 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1199 tvb, offset, len, len);
1202 /* if this is KRB5 wrapped rc4-hmac */
1203 if((token_id==KRB_TOKEN_WRAP)
1204 &&(sgn_alg==KRB_SGN_ALG_HMAC)
1205 &&(seal_alg==KRB_SEAL_ALG_RC4)){
1206 /* do we need to create a tvb for the wrapper
1209 if(!pinfo->gssapi_wrap_tvb){
1210 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1211 tvb, start_offset-2,
1212 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
1213 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
1215 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1216 decrypt_gssapi_krb_arcfour_wrap(tree,
1220 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1225 * Return the offset past the checksum, so that we know where
1226 * the data we're wrapped around starts. Also, set the length
1227 * of our top-level item to that offset, so it doesn't cover
1228 * the data we're wrapped around.
1230 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1237 * XXX - This is for GSSAPI GetMIC tokens ...
1240 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1245 * The KRB5 blob conforms to RFC1964:
1246 * USHORT (0x0101 == GSS_GetMIC)
1250 /* Now, the sign algorithm ... */
1252 sgn_alg = tvb_get_letohs(tvb, offset);
1253 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1258 /* Skip the filler */
1262 /* Encrypted sequence number */
1264 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1269 /* Checksum of plaintext padded data */
1271 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1277 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1278 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1279 * extra 8 bytes of "Random confounder" after the checksum.
1280 * It certainly confounds code expecting all Kerberos 5
1281 * GSS_Wrap() tokens to look the same....
1283 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1284 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1291 * Return the offset past the checksum, so that we know where
1292 * the data we're wrapped around starts. Also, set the length
1293 * of our top-level item to that offset, so it doesn't cover
1294 * the data we're wrapped around.
1301 * XXX - is this for SPNEGO or just GSS-API?
1302 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1303 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1304 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1305 * getting it accepted.
1308 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1311 proto_tree *subtree;
1315 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
1317 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1320 * The KRB5 blob conforms to RFC1964:
1321 * USHORT (0x0102 == GSS_Wrap)
1325 /* First, the token ID ... */
1327 token_id = tvb_get_letohs(tvb, offset);
1328 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1333 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1336 * Return the offset past the checksum, so that we know where
1337 * the data we're wrapped around starts. Also, set the length
1338 * of our top-level item to that offset, so it doesn't cover
1339 * the data we're wrapped around.
1341 proto_item_set_len(item, offset);
1345 /* Spnego stuff from here */
1348 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1351 proto_tree *subtree;
1357 * We need this later, so lets get it now ...
1358 * It has to be per-frame as there can be more than one GSS-API
1359 * negotiation in a conversation.
1363 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1366 subtree = proto_item_add_subtree(item, ett_spnego);
1368 * The TVB contains a [0] header and a sequence that consists of an
1369 * object ID and a blob containing the data ...
1370 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1371 * with the "optional" "use in non-initial tokens" being chosen.
1372 * ASN1 code addet to spnego.asn to handle this.
1375 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, pinfo , subtree, -1);
1382 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1385 proto_tree *subtree;
1387 conversation_t *conversation;
1390 * We need this later, so lets get it now ...
1391 * It has to be per-frame as there can be more than one GSS-API
1392 * negotiation in a conversation.
1394 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1395 if (!next_level_value && !pinfo->fd->flags.visited) {
1397 * No handle attached to this frame, but it's the first
1398 * pass, so it'd be attached to the conversation.
1399 * If we have a conversation, try to get the handle,
1400 * and if we get one, attach it to the frame.
1402 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1403 pinfo->ptype, pinfo->srcport,
1404 pinfo->destport, 0);
1407 next_level_value = conversation_get_proto_data(conversation,
1409 if (next_level_value)
1410 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1414 item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset,
1417 subtree = proto_item_add_subtree(item, ett_spnego);
1420 * The TVB contains a [0] header and a sequence that consists of an
1421 * object ID and a blob containing the data ...
1422 * Actually, it contains, according to RFC2478:
1423 * NegotiationToken ::= CHOICE {
1424 * negTokenInit [0] NegTokenInit,
1425 * negTokenTarg [1] NegTokenTarg }
1426 * NegTokenInit ::= SEQUENCE {
1427 * mechTypes [0] MechTypeList OPTIONAL,
1428 * reqFlags [1] ContextFlags OPTIONAL,
1429 * mechToken [2] OCTET STRING OPTIONAL,
1430 * mechListMIC [3] OCTET STRING OPTIONAL }
1431 * NegTokenTarg ::= SEQUENCE {
1432 * negResult [0] ENUMERATED {
1433 * accept_completed (0),
1434 * accept_incomplete (1),
1435 * reject (2) } OPTIONAL,
1436 * supportedMech [1] MechType OPTIONAL,
1437 * responseToken [2] OCTET STRING OPTIONAL,
1438 * mechListMIC [3] OCTET STRING OPTIONAL }
1440 * Windows typically includes mechTypes and mechListMic ('NONE'
1441 * in the case of NTLMSSP only).
1442 * It seems to duplicate the responseToken into the mechListMic field
1443 * as well. Naughty, naughty.
1446 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, pinfo, subtree, -1);
1450 /*--- proto_register_spnego -------------------------------------------*/
1451 void proto_register_spnego(void) {
1453 /* List of fields */
1454 static hf_register_info hf[] = {
1456 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1458 { &hf_spnego_wraptoken,
1459 { "wrapToken", "spnego.wraptoken",
1460 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1463 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1464 BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1465 { &hf_spnego_krb5_oid,
1466 { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
1467 BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
1468 { &hf_spnego_krb5_tok_id,
1469 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1470 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1471 { &hf_spnego_krb5_sgn_alg,
1472 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1473 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1474 { &hf_spnego_krb5_seal_alg,
1475 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1476 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1477 { &hf_spnego_krb5_snd_seq,
1478 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1479 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1480 { &hf_spnego_krb5_sgn_cksum,
1481 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1482 NULL, 0, "KRB5 Data Checksum", HFILL}},
1483 { &hf_spnego_krb5_confounder,
1484 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1485 NULL, 0, "KRB5 Confounder", HFILL}},
1488 /*--- Included file: packet-spnego-hfarr.c ---*/
1490 { &hf_spnego_negTokenInit,
1491 { "negTokenInit", "spnego.negTokenInit",
1492 FT_NONE, BASE_NONE, NULL, 0,
1493 "NegotiationToken/negTokenInit", HFILL }},
1494 { &hf_spnego_negTokenTarg,
1495 { "negTokenTarg", "spnego.negTokenTarg",
1496 FT_NONE, BASE_NONE, NULL, 0,
1497 "NegotiationToken/negTokenTarg", HFILL }},
1498 { &hf_spnego_MechTypeList_item,
1499 { "Item", "spnego.MechTypeList_item",
1500 FT_STRING, BASE_NONE, NULL, 0,
1501 "MechTypeList/_item", HFILL }},
1502 { &hf_spnego_principal,
1503 { "principal", "spnego.principal",
1504 FT_STRING, BASE_NONE, NULL, 0,
1505 "PrincipalSeq/principal", HFILL }},
1506 { &hf_spnego_mechTypes,
1507 { "mechTypes", "spnego.mechTypes",
1508 FT_UINT32, BASE_DEC, NULL, 0,
1509 "NegTokenInit/mechTypes", HFILL }},
1510 { &hf_spnego_reqFlags,
1511 { "reqFlags", "spnego.reqFlags",
1512 FT_BYTES, BASE_HEX, NULL, 0,
1513 "NegTokenInit/reqFlags", HFILL }},
1514 { &hf_spnego_mechToken,
1515 { "mechToken", "spnego.mechToken",
1516 FT_BYTES, BASE_HEX, NULL, 0,
1517 "NegTokenInit/mechToken", HFILL }},
1518 { &hf_spnego_negTokenInit_mechListMIC,
1519 { "mechListMIC", "spnego.mechListMIC",
1520 FT_BYTES, BASE_HEX, NULL, 0,
1521 "NegTokenInit/mechListMIC", HFILL }},
1522 { &hf_spnego_negResult,
1523 { "negResult", "spnego.negResult",
1524 FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
1525 "NegTokenTarg/negResult", HFILL }},
1526 { &hf_spnego_supportedMech,
1527 { "supportedMech", "spnego.supportedMech",
1528 FT_STRING, BASE_NONE, NULL, 0,
1529 "NegTokenTarg/supportedMech", HFILL }},
1530 { &hf_spnego_responseToken,
1531 { "responseToken", "spnego.responseToken",
1532 FT_BYTES, BASE_HEX, NULL, 0,
1533 "NegTokenTarg/responseToken", HFILL }},
1534 { &hf_spnego_mechListMIC,
1535 { "mechListMIC", "spnego.mechListMIC",
1536 FT_BYTES, BASE_HEX, NULL, 0,
1537 "NegTokenTarg/mechListMIC", HFILL }},
1538 { &hf_spnego_thisMech,
1539 { "thisMech", "spnego.thisMech",
1540 FT_STRING, BASE_NONE, NULL, 0,
1541 "InitialContextToken/thisMech", HFILL }},
1542 { &hf_spnego_innerContextToken,
1543 { "innerContextToken", "spnego.innerContextToken",
1544 FT_NONE, BASE_NONE, NULL, 0,
1545 "InitialContextToken/innerContextToken", HFILL }},
1546 { &hf_spnego_ContextFlags_delegFlag,
1547 { "delegFlag", "spnego.delegFlag",
1548 FT_BOOLEAN, 8, NULL, 0x80,
1550 { &hf_spnego_ContextFlags_mutualFlag,
1551 { "mutualFlag", "spnego.mutualFlag",
1552 FT_BOOLEAN, 8, NULL, 0x40,
1554 { &hf_spnego_ContextFlags_replayFlag,
1555 { "replayFlag", "spnego.replayFlag",
1556 FT_BOOLEAN, 8, NULL, 0x20,
1558 { &hf_spnego_ContextFlags_sequenceFlag,
1559 { "sequenceFlag", "spnego.sequenceFlag",
1560 FT_BOOLEAN, 8, NULL, 0x10,
1562 { &hf_spnego_ContextFlags_anonFlag,
1563 { "anonFlag", "spnego.anonFlag",
1564 FT_BOOLEAN, 8, NULL, 0x08,
1566 { &hf_spnego_ContextFlags_confFlag,
1567 { "confFlag", "spnego.confFlag",
1568 FT_BOOLEAN, 8, NULL, 0x04,
1570 { &hf_spnego_ContextFlags_integFlag,
1571 { "integFlag", "spnego.integFlag",
1572 FT_BOOLEAN, 8, NULL, 0x02,
1575 /*--- End of included file: packet-spnego-hfarr.c ---*/
1579 /* List of subtrees */
1580 static gint *ett[] = {
1582 &ett_spnego_wraptoken,
1586 /*--- Included file: packet-spnego-ettarr.c ---*/
1588 &ett_spnego_NegotiationToken,
1589 &ett_spnego_MechTypeList,
1590 &ett_spnego_PrincipalSeq,
1591 &ett_spnego_NegTokenInit,
1592 &ett_spnego_ContextFlags,
1593 &ett_spnego_NegTokenTarg,
1594 &ett_spnego_InitialContextToken,
1596 /*--- End of included file: packet-spnego-ettarr.c ---*/
1600 /* Register protocol */
1601 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1603 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1606 /* Register fields and subtrees */
1607 proto_register_field_array(proto_spnego, hf, array_length(hf));
1608 proto_register_subtree_array(ett, array_length(ett));
1612 /*--- proto_reg_handoff_spnego ---------------------------------------*/
1613 void proto_reg_handoff_spnego(void) {
1615 dissector_handle_t spnego_handle, spnego_wrap_handle;
1616 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1618 /* Register protocol with GSS-API module */
1620 spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
1621 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
1623 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1624 spnego_handle, spnego_wrap_handle,
1625 "SPNEGO - Simple Protected Negotiation");
1627 /* Register both the one MS created and the real one */
1629 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1630 * mystery of the MS KRB5 OID is cleared up. It was due to a library
1631 * that did not handle OID components greater than 16 bits, and was
1632 * fixed in Win2K SP2 as well as WinXP.
1633 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1634 * SPNEGO implementation issues. 3-Dec-2002.
1636 spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
1638 spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
1640 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1641 spnego_krb5_handle, spnego_krb5_wrap_handle,
1642 "MS KRB5 - Microsoft Kerberos 5");
1643 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1644 spnego_krb5_handle, spnego_krb5_wrap_handle,
1645 "KRB5 - Kerberos 5");
1646 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1647 spnego_krb5_handle, spnego_krb5_wrap_handle,
1648 "KRB5 - Kerberos 5 - User to User");
1651 * Find the data handle for some calls
1653 data_handle = find_dissector("data");