1 /* Do not modify this file. */
2 /* It is created automatically by the ASN.1 to Wireshark dissector compiler */
4 /* ../../tools/asn2wrs.py -b -p spnego -c ./spnego.cnf -s ./packet-spnego-template -D . spnego.asn */
6 /* Input file: packet-spnego-template.c */
8 #line 1 "packet-spnego-template.c"
10 * Routines for the simple and protected GSS-API negotiation mechanism
11 * as described in RFC 2478.
12 * Copyright 2002, Tim Potter <tpot@samba.org>
13 * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
14 * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
15 * Copyright 2005, Ronnie Sahlberg (krb decryption)
16 * Copyright 2005, Anders Broman (converted to asn2wrs generated dissector)
20 * Wireshark - Network traffic analyzer
21 * By Gerald Combs <gerald@wireshark.org>
22 * Copyright 1998 Gerald Combs
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * as published by the Free Software Foundation; either version 2
27 * of the License, or (at your option) any later version.
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
34 * You should have received a copy of the GNU General Public License
35 * along with this program; if not, write to the Free Software
36 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
39 Heimdal 1.6 and has been modified for wireshark's requirements.
47 #include <epan/packet.h>
48 #include <epan/asn1.h>
49 #include "packet-dcerpc.h"
50 #include "packet-gssapi.h"
51 #include "packet-kerberos.h"
52 #include <epan/crypt/crypt-rc4.h>
53 #include <epan/conversation.h>
54 #include <epan/emem.h>
55 #include <epan/asn1.h>
60 #include "packet-ber.h"
63 #define PNAME "Simple Protected Negotiation"
64 #define PSNAME "SPNEGO"
65 #define PFNAME "spnego"
67 /* Initialize the protocol and registered fields */
68 static int proto_spnego = -1;
69 static int proto_spnego_krb5 = -1;
72 static int hf_spnego = -1;
73 static int hf_spnego_wraptoken = -1;
74 static int hf_spnego_krb5_oid;
75 static int hf_spnego_krb5 = -1;
76 static int hf_spnego_krb5_tok_id = -1;
77 static int hf_spnego_krb5_sgn_alg = -1;
78 static int hf_spnego_krb5_seal_alg = -1;
79 static int hf_spnego_krb5_snd_seq = -1;
80 static int hf_spnego_krb5_sgn_cksum = -1;
81 static int hf_spnego_krb5_confounder = -1;
82 static int hf_spnego_krb5_filler = -1;
83 static int hf_spnego_krb5_cfx_flags = -1;
84 static int hf_spnego_krb5_cfx_flags_01 = -1;
85 static int hf_spnego_krb5_cfx_flags_02 = -1;
86 static int hf_spnego_krb5_cfx_flags_04 = -1;
87 static int hf_spnego_krb5_cfx_ec = -1;
88 static int hf_spnego_krb5_cfx_rrc = -1;
89 static int hf_spnego_krb5_cfx_seq = -1;
92 /*--- Included file: packet-spnego-hf.c ---*/
93 #line 1 "packet-spnego-hf.c"
94 static int hf_spnego_negTokenInit = -1; /* NegTokenInit */
95 static int hf_spnego_negTokenTarg = -1; /* NegTokenTarg */
96 static int hf_spnego_MechTypeList_item = -1; /* MechType */
97 static int hf_spnego_principal = -1; /* GeneralString */
98 static int hf_spnego_mechTypes = -1; /* MechTypeList */
99 static int hf_spnego_reqFlags = -1; /* ContextFlags */
100 static int hf_spnego_mechToken = -1; /* T_mechToken */
101 static int hf_spnego_negTokenInit_mechListMIC = -1; /* T_NegTokenInit_mechListMIC */
102 static int hf_spnego_negResult = -1; /* T_negResult */
103 static int hf_spnego_supportedMech = -1; /* T_supportedMech */
104 static int hf_spnego_responseToken = -1; /* T_responseToken */
105 static int hf_spnego_mechListMIC = -1; /* T_mechListMIC */
106 static int hf_spnego_thisMech = -1; /* MechType */
107 static int hf_spnego_innerContextToken = -1; /* InnerContextToken */
109 static int hf_spnego_ContextFlags_delegFlag = -1;
110 static int hf_spnego_ContextFlags_mutualFlag = -1;
111 static int hf_spnego_ContextFlags_replayFlag = -1;
112 static int hf_spnego_ContextFlags_sequenceFlag = -1;
113 static int hf_spnego_ContextFlags_anonFlag = -1;
114 static int hf_spnego_ContextFlags_confFlag = -1;
115 static int hf_spnego_ContextFlags_integFlag = -1;
117 /*--- End of included file: packet-spnego-hf.c ---*/
118 #line 84 "packet-spnego-template.c"
120 /* Global variables */
121 static const char *MechType_oid;
122 gssapi_oid_value *next_level_value;
123 gboolean saw_mechanism = FALSE;
126 /* Initialize the subtree pointers */
127 static gint ett_spnego;
128 static gint ett_spnego_wraptoken;
129 static gint ett_spnego_krb5 = -1;
130 static gint ett_spnego_krb5_cfx_flags = -1;
133 /*--- Included file: packet-spnego-ett.c ---*/
134 #line 1 "packet-spnego-ett.c"
135 static gint ett_spnego_NegotiationToken = -1;
136 static gint ett_spnego_MechTypeList = -1;
137 static gint ett_spnego_PrincipalSeq = -1;
138 static gint ett_spnego_NegTokenInit = -1;
139 static gint ett_spnego_ContextFlags = -1;
140 static gint ett_spnego_NegTokenTarg = -1;
141 static gint ett_spnego_InitialContextToken_U = -1;
143 /*--- End of included file: packet-spnego-ett.c ---*/
144 #line 98 "packet-spnego-template.c"
146 static dissector_handle_t data_handle;
149 * Unfortunately, we have to have a forward declaration of this,
150 * as the code generated by asn2wrs includes a call before the
153 static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
154 int offset, asn1_ctx_t *actx _U_,
155 proto_tree *tree, int hf_index);
158 /*--- Included file: packet-spnego-fn.c ---*/
159 #line 1 "packet-spnego-fn.c"
163 dissect_spnego_MechType(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
164 #line 23 "spnego.cnf"
166 gssapi_oid_value *value;
168 offset = dissect_ber_object_identifier_str(implicit_tag, actx, tree, tvb, offset, hf_index, &MechType_oid);
171 value = gssapi_lookup_oid_str(MechType_oid);
174 * Tell our caller the first mechanism we see, so that if
175 * this is a negTokenInit with a mechToken, it can interpret
176 * the mechToken according to the first mechType. (There
177 * might not have been any indication of the mechType
178 * in prior frames, so we can't necessarily use the
179 * mechanism from the conversation; i.e., a negTokenInit
180 * can contain the initial security token for the desired
181 * mechanism of the initiator - that's the first mechanism
184 if (!saw_mechanism) {
186 next_level_value = value;
187 saw_mechanism = TRUE;
196 static const ber_sequence_t MechTypeList_sequence_of[1] = {
197 { &hf_spnego_MechTypeList_item, BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_spnego_MechType },
201 dissect_spnego_MechTypeList(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
202 #line 91 "spnego.cnf"
204 conversation_t *conversation;
206 saw_mechanism = FALSE;
208 offset = dissect_ber_sequence_of(implicit_tag, actx, tree, tvb, offset,
209 MechTypeList_sequence_of, hf_index, ett_spnego_MechTypeList);
213 * If we saw a mechType we need to store it in case the negTokenTarg
214 * does not provide a supportedMech.
217 conversation = find_conversation(actx->pinfo->fd->num,
218 &actx->pinfo->src, &actx->pinfo->dst,
220 actx->pinfo->srcport, actx->pinfo->destport, 0);
222 conversation = conversation_new(actx->pinfo->fd->num,
223 &actx->pinfo->src, &actx->pinfo->dst,
225 actx->pinfo->srcport, actx->pinfo->destport, 0);
227 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
236 static const asn_namedbit ContextFlags_bits[] = {
237 { 0, &hf_spnego_ContextFlags_delegFlag, -1, -1, "delegFlag", NULL },
238 { 1, &hf_spnego_ContextFlags_mutualFlag, -1, -1, "mutualFlag", NULL },
239 { 2, &hf_spnego_ContextFlags_replayFlag, -1, -1, "replayFlag", NULL },
240 { 3, &hf_spnego_ContextFlags_sequenceFlag, -1, -1, "sequenceFlag", NULL },
241 { 4, &hf_spnego_ContextFlags_anonFlag, -1, -1, "anonFlag", NULL },
242 { 5, &hf_spnego_ContextFlags_confFlag, -1, -1, "confFlag", NULL },
243 { 6, &hf_spnego_ContextFlags_integFlag, -1, -1, "integFlag", NULL },
244 { 0, NULL, 0, 0, NULL, NULL }
248 dissect_spnego_ContextFlags(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
249 offset = dissect_ber_bitstring(implicit_tag, actx, tree, tvb, offset,
250 ContextFlags_bits, hf_index, ett_spnego_ContextFlags,
259 dissect_spnego_T_mechToken(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
260 #line 121 "spnego.cnf"
262 tvbuff_t *mechToken_tvb = NULL;
264 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
269 * Now, we should be able to dispatch, if we've gotten a tvbuff for
270 * the token and we have information on how to dissect its contents.
272 if (mechToken_tvb && next_level_value)
273 call_dissector(next_level_value->handle, mechToken_tvb, actx->pinfo, tree);
284 dissect_spnego_T_NegTokenInit_mechListMIC(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
285 #line 135 "spnego.cnf"
290 tvbuff_t *mechListMIC_tvb;
293 * There seems to be two different forms this can take,
294 * one as an octet string, and one as a general string in a
297 * Peek at the header, and then decide which it is we're seeing.
299 get_ber_identifier(tvb, offset, &class, &pc, &tag);
300 if (class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE) {
304 return dissect_spnego_PrincipalSeq(FALSE, tvb, offset, actx, tree,
305 hf_spnego_mechListMIC);
308 * It's not a sequence, so dissect it as an octet string,
309 * which is what it's supposed to be; that'll cause the
310 * right error report if it's not an octet string, either.
312 offset = dissect_ber_octet_string(FALSE, actx, tree, tvb, offset,
313 hf_spnego_mechListMIC, &mechListMIC_tvb);
316 * Now, we should be able to dispatch with that tvbuff.
318 if (mechListMIC_tvb && next_level_value)
319 call_dissector(next_level_value->handle, mechListMIC_tvb, actx->pinfo, tree);
329 static const ber_sequence_t NegTokenInit_sequence[] = {
330 { &hf_spnego_mechTypes , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_MechTypeList },
331 { &hf_spnego_reqFlags , BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_ContextFlags },
332 { &hf_spnego_mechToken , BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechToken },
333 { &hf_spnego_negTokenInit_mechListMIC, BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_NegTokenInit_mechListMIC },
334 { NULL, 0, 0, 0, NULL }
338 dissect_spnego_NegTokenInit(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
339 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
340 NegTokenInit_sequence, hf_index, ett_spnego_NegTokenInit);
346 static const value_string spnego_T_negResult_vals[] = {
347 { 0, "accept-completed" },
348 { 1, "accept-incomplete" },
355 dissect_spnego_T_negResult(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
356 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
365 dissect_spnego_T_supportedMech(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
366 #line 173 "spnego.cnf"
368 conversation_t *conversation;
370 saw_mechanism = FALSE;
372 offset = dissect_spnego_MechType(implicit_tag, tvb, offset, actx, tree, hf_index);
376 * If we saw an explicit mechType we store this in the conversation so that
377 * it will override any mechType we might have picked up from the
381 conversation = find_conversation(actx->pinfo->fd->num,
382 &actx->pinfo->src, &actx->pinfo->dst,
384 actx->pinfo->srcport, actx->pinfo->destport, 0);
386 conversation = conversation_new(actx->pinfo->fd->num,
387 &actx->pinfo->src, &actx->pinfo->dst,
389 actx->pinfo->srcport, actx->pinfo->destport, 0);
391 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
403 dissect_spnego_T_responseToken(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
404 #line 205 "spnego.cnf"
406 tvbuff_t *responseToken_tvb;
409 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
415 * Now, we should be able to dispatch, if we've gotten a tvbuff for
416 * the token and we have information on how to dissect its contents.
417 * However, we should make sure that there is something in the
420 if (responseToken_tvb && (tvb_reported_length(responseToken_tvb) > 0) ){
421 gssapi_oid_value *value=next_level_value;
424 call_dissector(value->handle, responseToken_tvb, actx->pinfo, tree);
437 dissect_spnego_T_mechListMIC(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
438 #line 232 "spnego.cnf"
440 tvbuff_t *mechListMIC_tvb;
443 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
449 * Now, we should be able to dispatch, if we've gotten a tvbuff for
450 * the MIC and we have information on how to dissect its contents.
452 if (mechListMIC_tvb && (tvb_reported_length(mechListMIC_tvb) > 0) ){
453 gssapi_oid_value *value=next_level_value;
456 call_dissector(value->handle, mechListMIC_tvb, actx->pinfo, tree);
467 static const ber_sequence_t NegTokenTarg_sequence[] = {
468 { &hf_spnego_negResult , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_T_negResult },
469 { &hf_spnego_supportedMech, BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_T_supportedMech },
470 { &hf_spnego_responseToken, BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_responseToken },
471 { &hf_spnego_mechListMIC , BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechListMIC },
472 { NULL, 0, 0, 0, NULL }
476 dissect_spnego_NegTokenTarg(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
477 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
478 NegTokenTarg_sequence, hf_index, ett_spnego_NegTokenTarg);
484 static const value_string spnego_NegotiationToken_vals[] = {
485 { 0, "negTokenInit" },
486 { 1, "negTokenTarg" },
490 static const ber_choice_t NegotiationToken_choice[] = {
491 { 0, &hf_spnego_negTokenInit , BER_CLASS_CON, 0, 0, dissect_spnego_NegTokenInit },
492 { 1, &hf_spnego_negTokenTarg , BER_CLASS_CON, 1, 0, dissect_spnego_NegTokenTarg },
493 { 0, NULL, 0, 0, 0, NULL }
497 dissect_spnego_NegotiationToken(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
498 offset = dissect_ber_choice(actx, tree, tvb, offset,
499 NegotiationToken_choice, hf_index, ett_spnego_NegotiationToken,
508 dissect_spnego_GeneralString(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
509 offset = dissect_ber_restricted_string(implicit_tag, BER_UNI_TAG_GeneralString,
510 actx, tree, tvb, offset, hf_index,
517 static const ber_sequence_t PrincipalSeq_sequence[] = {
518 { &hf_spnego_principal , BER_CLASS_CON, 0, 0, dissect_spnego_GeneralString },
519 { NULL, 0, 0, 0, NULL }
523 dissect_spnego_PrincipalSeq(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
524 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
525 PrincipalSeq_sequence, hf_index, ett_spnego_PrincipalSeq);
533 dissect_spnego_InnerContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
534 #line 48 "spnego.cnf"
536 gssapi_oid_value *next_level_value;
543 * XXX - what should we do if this OID doesn't match the value
544 * attached to the frame or conversation? (That would be
545 * bogus, but that's not impossible - some broken implementation
546 * might negotiate some security mechanism but put the OID
547 * for some other security mechanism in GSS_Wrap tokens.)
550 next_level_value = gssapi_lookup_oid_str(MechType_oid);
553 * Now dissect the GSS_Wrap token; it's assumed to be in the
554 * rest of the tvbuff.
556 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, -1, FALSE);
558 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
561 * Now, we should be able to dispatch after creating a new TVB.
562 * The subdissector must return the length of the part of the
563 * token it dissected, so we can return the length of the part
564 * we (and it) dissected.
566 token_tvb = tvb_new_subset(tvb, offset, -1, -1);
567 if (next_level_value && next_level_value->wrap_handle) {
568 len = call_dissector(next_level_value->wrap_handle, token_tvb, actx->pinfo,
571 offset = tvb_length(tvb);
573 offset = offset + len;
575 offset = tvb_length(tvb);
583 static const ber_sequence_t InitialContextToken_U_sequence[] = {
584 { &hf_spnego_thisMech , BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_spnego_MechType },
585 { &hf_spnego_innerContextToken, BER_CLASS_ANY, 0, BER_FLAGS_NOOWNTAG, dissect_spnego_InnerContextToken },
586 { NULL, 0, 0, 0, NULL }
590 dissect_spnego_InitialContextToken_U(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
591 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
592 InitialContextToken_U_sequence, hf_index, ett_spnego_InitialContextToken_U);
600 dissect_spnego_InitialContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
601 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
602 hf_index, BER_CLASS_APP, 0, TRUE, dissect_spnego_InitialContextToken_U);
608 /*--- End of included file: packet-spnego-fn.c ---*/
609 #line 111 "packet-spnego-template.c"
611 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
612 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
613 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
616 #define KRB_TOKEN_AP_REQ 0x0001
617 #define KRB_TOKEN_AP_REP 0x0002
618 #define KRB_TOKEN_AP_ERR 0x0003
619 #define KRB_TOKEN_GETMIC 0x0101
620 #define KRB_TOKEN_WRAP 0x0102
621 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
622 #define KRB_TOKEN_CFX_GETMIC 0x0404
623 #define KRB_TOKEN_CFX_WRAP 0x0405
625 static const value_string spnego_krb5_tok_id_vals[] = {
626 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
627 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
628 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
629 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
630 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
631 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
632 { KRB_TOKEN_CFX_GETMIC, "KRB_TOKEN_CFX_GetMic" },
633 { KRB_TOKEN_CFX_WRAP, "KRB_TOKEN_CFX_WRAP" },
637 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
638 #define KRB_SGN_ALG_MD2_5 0x0001
639 #define KRB_SGN_ALG_DES_MAC 0x0002
640 #define KRB_SGN_ALG_HMAC 0x0011
642 static const value_string spnego_krb5_sgn_alg_vals[] = {
643 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
644 { KRB_SGN_ALG_MD2_5, "MD2.5"},
645 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
646 { KRB_SGN_ALG_HMAC, "HMAC"},
650 #define KRB_SEAL_ALG_DES_CBC 0x0000
651 #define KRB_SEAL_ALG_RC4 0x0010
652 #define KRB_SEAL_ALG_NONE 0xffff
654 static const value_string spnego_krb5_seal_alg_vals[] = {
655 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
656 { KRB_SEAL_ALG_RC4, "RC4"},
657 { KRB_SEAL_ALG_NONE, "None"},
662 * XXX - is this for SPNEGO or just GSS-API?
663 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
664 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
665 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
666 * getting it accepted.
669 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
671 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
673 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
675 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
678 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
685 gssapi_oid_value *value;
688 gboolean pc, ind = 0;
692 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
694 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
697 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
700 * The KRB5 blob conforms to RFC1964:
703 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
706 * However, for some protocols, the KRB5 blob starts at the SHORT
707 * and has no DER encoded header etc.
709 * It appears that for some other protocols the KRB5 blob is just
710 * a Kerberos message, with no [APPLICATION 0] header, no OID,
715 * If we see an [APPLICATION 0] HEADER, we show the OID and
716 * the USHORT, and then dissect the rest as a Kerberos message.
718 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
719 * we assume it's an AP-REQ or AP-REP message, and dissect
720 * it all as a Kerberos message.
722 * Otherwise, we show the USHORT, and then dissect the rest
723 * as a Kerberos message.
727 * Get the first header ...
729 get_ber_identifier(tvb, offset, &class, &pc, &tag);
730 if (class == BER_CLASS_APP && pc) {
732 * [APPLICATION <tag>]
734 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
735 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
745 offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
747 value = gssapi_lookup_oid_str(oid);
749 token_id = tvb_get_letohs(tvb, offset);
750 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
757 case 14: /* [APPLICATION 14] */
758 case 15: /* [APPLICATION 15] */
760 * No token ID - just dissect as a Kerberos message and
763 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
767 proto_tree_add_text(subtree, tvb, offset, 0,
768 "Unknown header (class=%d, pc=%d, tag=%d)",
773 /* Next, the token ID ... */
775 token_id = tvb_get_letohs(tvb, offset);
776 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
784 case KRB_TOKEN_AP_REQ:
785 case KRB_TOKEN_AP_REP:
786 case KRB_TOKEN_AP_ERR:
787 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
788 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
791 case KRB_TOKEN_GETMIC:
792 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
796 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
799 case KRB_TOKEN_DELETE_SEC_CONTEXT:
803 case KRB_TOKEN_CFX_GETMIC:
804 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
807 case KRB_TOKEN_CFX_WRAP:
808 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
817 proto_item_set_len(item, offset);
822 #include <epan/crypt/crypt-md5.h>
824 #ifndef KEYTYPE_ARCFOUR_56
825 # define KEYTYPE_ARCFOUR_56 24
827 /* XXX - We should probably do a configure-time check for this instead */
828 #ifndef KRB5_KU_USAGE_SEAL
829 # define KRB5_KU_USAGE_SEAL 22
833 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
834 void *cksum_data, size_t cksum_size,
842 if (key_type == KEYTYPE_ARCFOUR_56) {
843 guint8 L40[14] = "fortybits";
845 memcpy(L40 + 10, T, sizeof(T));
851 memset(&k5_data[7], 0xAB, 9);
861 cksum_data, cksum_size,
870 usage2arcfour(int usage)
873 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
874 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
876 case 22: /*KRB5_KU_USAGE_SEAL 22 */
878 case 23: /*KRB5_KU_USAGE_SIGN 23 */
880 case 24: /*KRB5_KU_USAGE_SEQ 24 */
888 arcfour_mic_cksum(guint8 *key_data, int key_length,
891 const void *v1, size_t l1,
892 const void *v2, size_t l2,
893 const void *v3, size_t l3)
895 const guint8 signature[] = "signaturekey";
899 unsigned char digest[16];
903 rc4_usage=usage2arcfour(usage);
904 md5_hmac(signature, sizeof(signature),
905 key_data, key_length,
908 t[0] = (rc4_usage >> 0) & 0xFF;
909 t[1] = (rc4_usage >> 8) & 0xFF;
910 t[2] = (rc4_usage >> 16) & 0xFF;
911 t[3] = (rc4_usage >> 24) & 0xFF;
912 md5_append(&ms, t, 4);
913 md5_append(&ms, v1, l1);
914 md5_append(&ms, v2, l2);
915 md5_append(&ms, v3, l3);
916 md5_finish(&ms, digest);
917 md5_hmac(digest, 16, ksign_c, 16, cksum);
919 memcpy(sgn_cksum, cksum, 8);
925 * Verify padding of a gss wrapped message and return its length.
928 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
936 pad = wrapped_data + wrapped_length - 1;
939 if (padlength > datalen)
942 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
953 decrypt_arcfour(packet_info *pinfo,
954 guint8 *input_message_buffer,
955 guint8 *output_message_buffer,
956 guint8 *key_value, int key_size, int key_type)
958 guint8 Klocaldata[16];
964 guint8 Confounder[8];
965 guint8 cksum_data[8];
970 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
972 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
974 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
980 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
984 ret = arcfour_mic_key(key_value, key_size, key_type,
985 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
993 rc4_state_struct rc4_state;
995 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
996 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
997 crypt_rc4(&rc4_state, (unsigned char *)SND_SEQ, 8);
999 memset(k6_data, 0, sizeof(k6_data));
1002 seq_number=g_ntohl(SND_SEQ[0]);
1004 if (SND_SEQ[1] != 0xFFFFFFFF && SND_SEQ[1] != 0x00000000) {
1011 for (i = 0; i < 16; i++)
1012 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
1014 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
1015 (unsigned char *)SND_SEQ, 4,
1017 memset(Klocaldata, 0, sizeof(Klocaldata));
1023 rc4_state_struct rc4_state;
1025 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
1026 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
1027 crypt_rc4(&rc4_state, Confounder, 8);
1028 memcpy(output_message_buffer, input_message_buffer, datalen);
1029 crypt_rc4(&rc4_state, output_message_buffer, datalen);
1032 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
1033 8); /* Confounder */
1034 memcpy(output_message_buffer,
1035 input_message_buffer,
1038 memset(k6_data, 0, sizeof(k6_data));
1040 /* only normal (i.e. non DCE style wrapping use padding ? */
1041 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1042 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
1049 /* dont know what the checksum looks like for dce style gssapi */
1050 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1051 ret = arcfour_mic_cksum(key_value, key_size,
1054 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
1055 Confounder, sizeof(Confounder),
1056 output_message_buffer,
1062 cmp = memcmp(cksum_data,
1063 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
1075 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1078 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
1083 const guint8 *original_data;
1085 static int omb_index=0;
1086 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
1087 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
1088 guint8 *output_message_buffer;
1094 output_message_buffer=omb_arr[omb_index];
1097 length=tvb_length(pinfo->gssapi_encrypted_tvb);
1098 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
1100 /* dont do anything if we are not attempting to decrypt data */
1106 /* XXX we should only do this for first time, then store somewhere */
1107 /* XXX We also need to re-read the keytab when the preference changes */
1109 cryptocopy=ep_alloc(length);
1110 if(output_message_buffer){
1111 g_free(output_message_buffer);
1112 output_message_buffer=NULL;
1114 output_message_buffer=g_malloc(length);
1116 for(ek=enc_key_list;ek;ek=ek->next){
1117 /* shortcircuit and bail out if enctypes are not matching */
1118 if(ek->keytype!=keytype){
1122 /* pre-0.6.1 versions of Heimdal would sometimes change
1123 the cryptotext data even when the decryption failed.
1124 This would obviously not work since we iterate over the
1125 keys. So just give it a copy of the crypto data instead.
1126 This has been seen for RC4-HMAC blobs.
1128 memcpy(cryptocopy, original_data, length);
1129 ret=decrypt_arcfour(pinfo,
1131 output_message_buffer,
1137 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
1138 pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
1139 output_message_buffer,
1141 tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
1142 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1148 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1154 * XXX - This is for GSSAPI Wrap tokens ...
1157 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1158 #ifndef HAVE_KERBEROS
1161 , proto_tree *tree, guint16 token_id
1162 #ifndef HAVE_KERBEROS
1167 guint16 sgn_alg, seal_alg;
1168 #ifdef HAVE_KERBEROS
1169 int start_offset=offset;
1173 * The KRB5 blob conforms to RFC1964:
1174 * USHORT (0x0102 == GSS_Wrap)
1178 /* Now, the sign and seal algorithms ... */
1180 sgn_alg = tvb_get_letohs(tvb, offset);
1181 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1186 seal_alg = tvb_get_letohs(tvb, offset);
1187 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
1192 /* Skip the filler */
1196 /* Encrypted sequence number */
1198 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1203 /* Checksum of plaintext padded data */
1205 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1211 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1212 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1213 * extra 8 bytes of "Random confounder" after the checksum.
1214 * It certainly confounds code expecting all Kerberos 5
1215 * GSS_Wrap() tokens to look the same....
1217 if ((sgn_alg == KRB_SGN_ALG_HMAC) ||
1218 /* there also seems to be a confounder for DES MAC MD5 - certainly seen when using with
1219 SASL with LDAP between a Java client and Active Directory. If this breaks other things
1220 we may need to make this an option. gal 17/2/06 */
1221 (sgn_alg == KRB_SGN_ALG_DES_MAC_MD5)) {
1222 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1227 /* Is the data encrypted? */
1228 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
1230 #ifdef HAVE_KERBEROS
1231 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
1232 if(pinfo->decrypt_gssapi_tvb){
1233 /* if the caller did not provide a tvb, then we just use
1234 whatever is left of our current tvb.
1236 if(!pinfo->gssapi_encrypted_tvb){
1238 len=tvb_reported_length_remaining(tvb,offset);
1239 if(len>tvb_length_remaining(tvb, offset)){
1240 /* no point in trying to decrypt,
1241 we dont have the full pdu.
1245 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1246 tvb, offset, len, len);
1249 /* if this is KRB5 wrapped rc4-hmac */
1250 if((token_id==KRB_TOKEN_WRAP)
1251 &&(sgn_alg==KRB_SGN_ALG_HMAC)
1252 &&(seal_alg==KRB_SEAL_ALG_RC4)){
1253 /* do we need to create a tvb for the wrapper
1256 if(!pinfo->gssapi_wrap_tvb){
1257 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1258 tvb, start_offset-2,
1259 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
1260 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
1262 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1263 decrypt_gssapi_krb_arcfour_wrap(tree,
1267 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1272 * Return the offset past the checksum, so that we know where
1273 * the data we're wrapped around starts. Also, set the length
1274 * of our top-level item to that offset, so it doesn't cover
1275 * the data we're wrapped around.
1277 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1284 * XXX - This is for GSSAPI GetMIC tokens ...
1287 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1292 * The KRB5 blob conforms to RFC1964:
1293 * USHORT (0x0101 == GSS_GetMIC)
1297 /* Now, the sign algorithm ... */
1299 sgn_alg = tvb_get_letohs(tvb, offset);
1300 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1305 /* Skip the filler */
1309 /* Encrypted sequence number */
1311 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1316 /* Checksum of plaintext padded data */
1318 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1324 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1325 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1326 * extra 8 bytes of "Random confounder" after the checksum.
1327 * It certainly confounds code expecting all Kerberos 5
1328 * GSS_Wrap() tokens to look the same....
1330 * The exception is DNS/TSIG where there is no such confounder
1331 * so we need to test here if there are more bytes in our tvb or not.
1334 if (tvb_length_remaining(tvb, offset)) {
1335 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1336 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1344 * Return the offset past the checksum, so that we know where
1345 * the data we're wrapped around starts. Also, set the length
1346 * of our top-level item to that offset, so it doesn't cover
1347 * the data we're wrapped around.
1354 dissect_spnego_krb5_cfx_flags(tvbuff_t *tvb, int offset,
1355 proto_tree *spnego_krb5_tree,
1358 proto_tree *cfx_flags_tree = NULL;
1359 proto_item *tf = NULL;
1361 if (spnego_krb5_tree) {
1362 tf = proto_tree_add_uint(spnego_krb5_tree,
1363 hf_spnego_krb5_cfx_flags,
1364 tvb, offset, 1, cfx_flags);
1365 cfx_flags_tree = proto_item_add_subtree(tf, ett_spnego_krb5_cfx_flags);
1368 proto_tree_add_boolean(cfx_flags_tree,
1369 hf_spnego_krb5_cfx_flags_04,
1370 tvb, offset, 1, cfx_flags);
1371 proto_tree_add_boolean(cfx_flags_tree,
1372 hf_spnego_krb5_cfx_flags_02,
1373 tvb, offset, 1, cfx_flags);
1374 proto_tree_add_boolean(cfx_flags_tree,
1375 hf_spnego_krb5_cfx_flags_01,
1376 tvb, offset, 1, cfx_flags);
1378 return (offset + 1);
1382 * XXX - This is for GSSAPI CFX Wrap tokens ...
1385 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1386 #ifndef HAVE_KERBEROS
1389 , proto_tree *tree, guint16 token_id _U_
1396 int start_offset=offset;
1399 * The KRB5 blob conforms to RFC4121:
1404 /* Now, the sign and seal algorithms ... */
1406 flags = tvb_get_guint8(tvb, offset);
1407 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1409 pinfo->gssapi_data_encrypted=(flags & 2);
1411 /* Skip the filler */
1413 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 1,
1418 ec = tvb_get_ntohs(tvb, offset);
1419 proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2,
1424 rrc = tvb_get_ntohs(tvb, offset);
1425 proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2,
1429 /* sequence number */
1431 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1435 /* Checksum of plaintext padded data */
1437 if (pinfo->gssapi_data_encrypted) {
1438 checksum_size = 44 + ec;
1443 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1444 checksum_size, FALSE);
1445 offset += checksum_size;
1447 if(pinfo->decrypt_gssapi_tvb){
1448 /* if the caller did not provide a tvb, then we just use
1449 whatever is left of our current tvb.
1451 if(!pinfo->gssapi_encrypted_tvb){
1453 len=tvb_reported_length_remaining(tvb,offset);
1454 if(len>tvb_length_remaining(tvb, offset)){
1455 /* no point in trying to decrypt,
1456 we dont have the full pdu.
1460 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1461 tvb, offset, len, len);
1464 if (pinfo->gssapi_data_encrypted) {
1465 /* do we need to create a tvb for the wrapper
1468 if(!pinfo->gssapi_wrap_tvb){
1469 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1470 tvb, start_offset-2,
1471 offset - (start_offset-2),
1472 offset - (start_offset-2));
1478 * Return the offset past the checksum, so that we know where
1479 * the data we're wrapped around starts. Also, set the length
1480 * of our top-level item to that offset, so it doesn't cover
1481 * the data we're wrapped around.
1483 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1490 * XXX - This is for GSSAPI CFX GetMIC tokens ...
1493 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1499 * The KRB5 blob conforms to RFC4121:
1500 * USHORT (0x0404 == GSS_GetMIC)
1504 flags = tvb_get_guint8(tvb, offset);
1505 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1507 /* Skip the filler */
1509 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 5,
1513 /* sequence number */
1515 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1519 /* Checksum of plaintext padded data */
1521 checksum_size = tvb_length_remaining(tvb, offset);
1523 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1524 checksum_size, FALSE);
1525 offset += checksum_size;
1528 * Return the offset past the checksum, so that we know where
1529 * the data we're wrapped around starts. Also, set the length
1530 * of our top-level item to that offset, so it doesn't cover
1531 * the data we're wrapped around.
1538 * XXX - is this for SPNEGO or just GSS-API?
1539 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1540 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1541 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1542 * getting it accepted.
1545 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1548 proto_tree *subtree;
1552 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
1554 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1557 * The KRB5 blob conforms to RFC1964:
1558 * USHORT (0x0102 == GSS_Wrap)
1562 /* First, the token ID ... */
1564 token_id = tvb_get_letohs(tvb, offset);
1565 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1571 case KRB_TOKEN_GETMIC:
1572 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
1575 case KRB_TOKEN_WRAP:
1576 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1579 case KRB_TOKEN_CFX_GETMIC:
1580 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
1583 case KRB_TOKEN_CFX_WRAP:
1584 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
1593 * Return the offset past the checksum, so that we know where
1594 * the data we're wrapped around starts. Also, set the length
1595 * of our top-level item to that offset, so it doesn't cover
1596 * the data we're wrapped around.
1598 proto_item_set_len(item, offset);
1602 /* Spnego stuff from here */
1605 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1608 proto_tree *subtree;
1610 asn1_ctx_t asn1_ctx;
1611 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1616 * We need this later, so lets get it now ...
1617 * It has to be per-frame as there can be more than one GSS-API
1618 * negotiation in a conversation.
1622 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1625 subtree = proto_item_add_subtree(item, ett_spnego);
1627 * The TVB contains a [0] header and a sequence that consists of an
1628 * object ID and a blob containing the data ...
1629 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1630 * with the "optional" "use in non-initial tokens" being chosen.
1631 * ASN1 code addet to spnego.asn to handle this.
1634 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, &asn1_ctx , subtree, -1);
1641 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1644 proto_tree *subtree;
1646 conversation_t *conversation;
1647 asn1_ctx_t asn1_ctx;
1648 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1651 * We need this later, so lets get it now ...
1652 * It has to be per-frame as there can be more than one GSS-API
1653 * negotiation in a conversation.
1655 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1656 if (!next_level_value && !pinfo->fd->flags.visited) {
1658 * No handle attached to this frame, but it's the first
1659 * pass, so it'd be attached to the conversation.
1660 * If we have a conversation, try to get the handle,
1661 * and if we get one, attach it to the frame.
1663 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1664 pinfo->ptype, pinfo->srcport,
1665 pinfo->destport, 0);
1668 next_level_value = conversation_get_proto_data(conversation,
1670 if (next_level_value)
1671 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1675 item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset,
1678 subtree = proto_item_add_subtree(item, ett_spnego);
1681 * The TVB contains a [0] header and a sequence that consists of an
1682 * object ID and a blob containing the data ...
1683 * Actually, it contains, according to RFC2478:
1684 * NegotiationToken ::= CHOICE {
1685 * negTokenInit [0] NegTokenInit,
1686 * negTokenTarg [1] NegTokenTarg }
1687 * NegTokenInit ::= SEQUENCE {
1688 * mechTypes [0] MechTypeList OPTIONAL,
1689 * reqFlags [1] ContextFlags OPTIONAL,
1690 * mechToken [2] OCTET STRING OPTIONAL,
1691 * mechListMIC [3] OCTET STRING OPTIONAL }
1692 * NegTokenTarg ::= SEQUENCE {
1693 * negResult [0] ENUMERATED {
1694 * accept_completed (0),
1695 * accept_incomplete (1),
1696 * reject (2) } OPTIONAL,
1697 * supportedMech [1] MechType OPTIONAL,
1698 * responseToken [2] OCTET STRING OPTIONAL,
1699 * mechListMIC [3] OCTET STRING OPTIONAL }
1701 * Windows typically includes mechTypes and mechListMic ('NONE'
1702 * in the case of NTLMSSP only).
1703 * It seems to duplicate the responseToken into the mechListMic field
1704 * as well. Naughty, naughty.
1707 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
1711 /*--- proto_register_spnego -------------------------------------------*/
1712 void proto_register_spnego(void) {
1714 /* List of fields */
1715 static hf_register_info hf[] = {
1717 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1719 { &hf_spnego_wraptoken,
1720 { "wrapToken", "spnego.wraptoken",
1721 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1724 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1725 BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1726 { &hf_spnego_krb5_oid,
1727 { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
1728 BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
1729 { &hf_spnego_krb5_tok_id,
1730 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1731 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1732 { &hf_spnego_krb5_sgn_alg,
1733 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1734 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1735 { &hf_spnego_krb5_seal_alg,
1736 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1737 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1738 { &hf_spnego_krb5_snd_seq,
1739 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1740 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1741 { &hf_spnego_krb5_sgn_cksum,
1742 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1743 NULL, 0, "KRB5 Data Checksum", HFILL}},
1744 { &hf_spnego_krb5_confounder,
1745 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1746 NULL, 0, "KRB5 Confounder", HFILL}},
1747 { &hf_spnego_krb5_filler,
1748 { "krb5_filler", "spnego.krb5.filler", FT_BYTES, BASE_HEX,
1749 NULL, 0, "KRB5 Filler", HFILL}},
1750 { &hf_spnego_krb5_cfx_flags,
1751 { "krb5_cfx_flags", "spnego.krb5.cfx_flags", FT_UINT8, BASE_HEX,
1752 NULL, 0, "KRB5 CFX Flags", HFILL}},
1753 { &hf_spnego_krb5_cfx_flags_01,
1754 { "SendByAcceptor", "spnego.krb5.send_by_acceptor", FT_BOOLEAN, 8,
1755 TFS (&flags_set_truth), 0x01, "", HFILL}},
1756 { &hf_spnego_krb5_cfx_flags_02,
1757 { "Sealed", "spnego.krb5.sealed", FT_BOOLEAN, 8,
1758 TFS (&flags_set_truth), 0x02, "", HFILL}},
1759 { &hf_spnego_krb5_cfx_flags_04,
1760 { "AcceptorSubkey", "spnego.krb5.acceptor_subkey", FT_BOOLEAN, 8,
1761 TFS (&flags_set_truth), 0x04, "", HFILL}},
1762 { &hf_spnego_krb5_cfx_ec,
1763 { "krb5_cfx_ec", "spnego.krb5.cfx_ec", FT_UINT16, BASE_DEC,
1764 NULL, 0, "KRB5 CFX Extra Count", HFILL}},
1765 { &hf_spnego_krb5_cfx_rrc,
1766 { "krb5_cfx_rrc", "spnego.krb5.cfx_rrc", FT_UINT16, BASE_DEC,
1767 NULL, 0, "KRB5 CFX Right Rotation Count", HFILL}},
1768 { &hf_spnego_krb5_cfx_seq,
1769 { "krb5_cfx_seq", "spnego.krb5.cfx_seq", FT_UINT64, BASE_DEC,
1770 NULL, 0, "KRB5 Sequence Number", HFILL}},
1773 /*--- Included file: packet-spnego-hfarr.c ---*/
1774 #line 1 "packet-spnego-hfarr.c"
1775 { &hf_spnego_negTokenInit,
1776 { "negTokenInit", "spnego.negTokenInit",
1777 FT_NONE, BASE_NONE, NULL, 0,
1778 "spnego.NegTokenInit", HFILL }},
1779 { &hf_spnego_negTokenTarg,
1780 { "negTokenTarg", "spnego.negTokenTarg",
1781 FT_NONE, BASE_NONE, NULL, 0,
1782 "spnego.NegTokenTarg", HFILL }},
1783 { &hf_spnego_MechTypeList_item,
1784 { "Item", "spnego.MechTypeList_item",
1785 FT_OID, BASE_NONE, NULL, 0,
1786 "spnego.MechType", HFILL }},
1787 { &hf_spnego_principal,
1788 { "principal", "spnego.principal",
1789 FT_STRING, BASE_NONE, NULL, 0,
1790 "spnego.GeneralString", HFILL }},
1791 { &hf_spnego_mechTypes,
1792 { "mechTypes", "spnego.mechTypes",
1793 FT_UINT32, BASE_DEC, NULL, 0,
1794 "spnego.MechTypeList", HFILL }},
1795 { &hf_spnego_reqFlags,
1796 { "reqFlags", "spnego.reqFlags",
1797 FT_BYTES, BASE_HEX, NULL, 0,
1798 "spnego.ContextFlags", HFILL }},
1799 { &hf_spnego_mechToken,
1800 { "mechToken", "spnego.mechToken",
1801 FT_BYTES, BASE_HEX, NULL, 0,
1802 "spnego.T_mechToken", HFILL }},
1803 { &hf_spnego_negTokenInit_mechListMIC,
1804 { "mechListMIC", "spnego.mechListMIC",
1805 FT_BYTES, BASE_HEX, NULL, 0,
1806 "spnego.T_NegTokenInit_mechListMIC", HFILL }},
1807 { &hf_spnego_negResult,
1808 { "negResult", "spnego.negResult",
1809 FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
1810 "spnego.T_negResult", HFILL }},
1811 { &hf_spnego_supportedMech,
1812 { "supportedMech", "spnego.supportedMech",
1813 FT_OID, BASE_NONE, NULL, 0,
1814 "spnego.T_supportedMech", HFILL }},
1815 { &hf_spnego_responseToken,
1816 { "responseToken", "spnego.responseToken",
1817 FT_BYTES, BASE_HEX, NULL, 0,
1818 "spnego.T_responseToken", HFILL }},
1819 { &hf_spnego_mechListMIC,
1820 { "mechListMIC", "spnego.mechListMIC",
1821 FT_BYTES, BASE_HEX, NULL, 0,
1822 "spnego.T_mechListMIC", HFILL }},
1823 { &hf_spnego_thisMech,
1824 { "thisMech", "spnego.thisMech",
1825 FT_OID, BASE_NONE, NULL, 0,
1826 "spnego.MechType", HFILL }},
1827 { &hf_spnego_innerContextToken,
1828 { "innerContextToken", "spnego.innerContextToken",
1829 FT_NONE, BASE_NONE, NULL, 0,
1830 "spnego.InnerContextToken", HFILL }},
1831 { &hf_spnego_ContextFlags_delegFlag,
1832 { "delegFlag", "spnego.delegFlag",
1833 FT_BOOLEAN, 8, NULL, 0x80,
1835 { &hf_spnego_ContextFlags_mutualFlag,
1836 { "mutualFlag", "spnego.mutualFlag",
1837 FT_BOOLEAN, 8, NULL, 0x40,
1839 { &hf_spnego_ContextFlags_replayFlag,
1840 { "replayFlag", "spnego.replayFlag",
1841 FT_BOOLEAN, 8, NULL, 0x20,
1843 { &hf_spnego_ContextFlags_sequenceFlag,
1844 { "sequenceFlag", "spnego.sequenceFlag",
1845 FT_BOOLEAN, 8, NULL, 0x10,
1847 { &hf_spnego_ContextFlags_anonFlag,
1848 { "anonFlag", "spnego.anonFlag",
1849 FT_BOOLEAN, 8, NULL, 0x08,
1851 { &hf_spnego_ContextFlags_confFlag,
1852 { "confFlag", "spnego.confFlag",
1853 FT_BOOLEAN, 8, NULL, 0x04,
1855 { &hf_spnego_ContextFlags_integFlag,
1856 { "integFlag", "spnego.integFlag",
1857 FT_BOOLEAN, 8, NULL, 0x02,
1860 /*--- End of included file: packet-spnego-hfarr.c ---*/
1861 #line 1274 "packet-spnego-template.c"
1864 /* List of subtrees */
1865 static gint *ett[] = {
1867 &ett_spnego_wraptoken,
1869 &ett_spnego_krb5_cfx_flags,
1872 /*--- Included file: packet-spnego-ettarr.c ---*/
1873 #line 1 "packet-spnego-ettarr.c"
1874 &ett_spnego_NegotiationToken,
1875 &ett_spnego_MechTypeList,
1876 &ett_spnego_PrincipalSeq,
1877 &ett_spnego_NegTokenInit,
1878 &ett_spnego_ContextFlags,
1879 &ett_spnego_NegTokenTarg,
1880 &ett_spnego_InitialContextToken_U,
1882 /*--- End of included file: packet-spnego-ettarr.c ---*/
1883 #line 1284 "packet-spnego-template.c"
1886 /* Register protocol */
1887 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1889 register_dissector("spnego", dissect_spnego, proto_spnego);
1891 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1895 register_dissector("spnego-krb5", dissect_spnego_krb5, proto_spnego_krb5);
1896 new_register_dissector("spnego-krb5-wrap", dissect_spnego_krb5_wrap, proto_spnego_krb5);
1898 /* Register fields and subtrees */
1899 proto_register_field_array(proto_spnego, hf, array_length(hf));
1900 proto_register_subtree_array(ett, array_length(ett));
1904 /*--- proto_reg_handoff_spnego ---------------------------------------*/
1905 void proto_reg_handoff_spnego(void) {
1907 dissector_handle_t spnego_handle, spnego_wrap_handle;
1908 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1910 /* Register protocol with GSS-API module */
1912 spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
1913 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
1915 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1916 spnego_handle, spnego_wrap_handle,
1917 "SPNEGO - Simple Protected Negotiation");
1919 /* Register both the one MS created and the real one */
1921 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1922 * mystery of the MS KRB5 OID is cleared up. It was due to a library
1923 * that did not handle OID components greater than 16 bits, and was
1924 * fixed in Win2K SP2 as well as WinXP.
1925 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1926 * SPNEGO implementation issues. 3-Dec-2002.
1928 spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
1930 spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
1932 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1933 spnego_krb5_handle, spnego_krb5_wrap_handle,
1934 "MS KRB5 - Microsoft Kerberos 5");
1935 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1936 spnego_krb5_handle, spnego_krb5_wrap_handle,
1937 "KRB5 - Kerberos 5");
1938 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1939 spnego_krb5_handle, spnego_krb5_wrap_handle,
1940 "KRB5 - Kerberos 5 - User to User");
1943 * Find the data handle for some calls
1945 data_handle = find_dissector("data");