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 . -O ../../epan/dissectors spnego.asn */
6 /* Input file: packet-spnego-template.c */
8 #line 1 "../../asn1/spnego/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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
45 #include <epan/packet.h>
46 #include <epan/asn1.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>
53 #include <epan/asn1.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_wraptoken = -1;
70 static int hf_spnego_krb5_oid;
71 static int hf_spnego_krb5 = -1;
72 static int hf_spnego_krb5_tok_id = -1;
73 static int hf_spnego_krb5_sgn_alg = -1;
74 static int hf_spnego_krb5_seal_alg = -1;
75 static int hf_spnego_krb5_snd_seq = -1;
76 static int hf_spnego_krb5_sgn_cksum = -1;
77 static int hf_spnego_krb5_confounder = -1;
78 static int hf_spnego_krb5_filler = -1;
79 static int hf_spnego_krb5_cfx_flags = -1;
80 static int hf_spnego_krb5_cfx_flags_01 = -1;
81 static int hf_spnego_krb5_cfx_flags_02 = -1;
82 static int hf_spnego_krb5_cfx_flags_04 = -1;
83 static int hf_spnego_krb5_cfx_ec = -1;
84 static int hf_spnego_krb5_cfx_rrc = -1;
85 static int hf_spnego_krb5_cfx_seq = -1;
88 /*--- Included file: packet-spnego-hf.c ---*/
89 #line 1 "../../asn1/spnego/packet-spnego-hf.c"
90 static int hf_spnego_negTokenInit = -1; /* NegTokenInit */
91 static int hf_spnego_negTokenTarg = -1; /* NegTokenTarg */
92 static int hf_spnego_MechTypeList_item = -1; /* MechType */
93 static int hf_spnego_principal = -1; /* GeneralString */
94 static int hf_spnego_mechTypes = -1; /* MechTypeList */
95 static int hf_spnego_reqFlags = -1; /* ContextFlags */
96 static int hf_spnego_mechToken = -1; /* T_mechToken */
97 static int hf_spnego_negTokenInit_mechListMIC = -1; /* T_NegTokenInit_mechListMIC */
98 static int hf_spnego_negResult = -1; /* T_negResult */
99 static int hf_spnego_supportedMech = -1; /* T_supportedMech */
100 static int hf_spnego_responseToken = -1; /* T_responseToken */
101 static int hf_spnego_mechListMIC = -1; /* T_mechListMIC */
102 static int hf_spnego_thisMech = -1; /* MechType */
103 static int hf_spnego_innerContextToken = -1; /* InnerContextToken */
105 static int hf_spnego_ContextFlags_delegFlag = -1;
106 static int hf_spnego_ContextFlags_mutualFlag = -1;
107 static int hf_spnego_ContextFlags_replayFlag = -1;
108 static int hf_spnego_ContextFlags_sequenceFlag = -1;
109 static int hf_spnego_ContextFlags_anonFlag = -1;
110 static int hf_spnego_ContextFlags_confFlag = -1;
111 static int hf_spnego_ContextFlags_integFlag = -1;
113 /*--- End of included file: packet-spnego-hf.c ---*/
114 #line 80 "../../asn1/spnego/packet-spnego-template.c"
116 /* Global variables */
117 static const char *MechType_oid;
118 gssapi_oid_value *next_level_value;
119 gboolean saw_mechanism = FALSE;
122 /* Initialize the subtree pointers */
123 static gint ett_spnego = -1;
124 static gint ett_spnego_wraptoken = -1;
125 static gint ett_spnego_krb5 = -1;
126 static gint ett_spnego_krb5_cfx_flags = -1;
129 /*--- Included file: packet-spnego-ett.c ---*/
130 #line 1 "../../asn1/spnego/packet-spnego-ett.c"
131 static gint ett_spnego_NegotiationToken = -1;
132 static gint ett_spnego_MechTypeList = -1;
133 static gint ett_spnego_PrincipalSeq = -1;
134 static gint ett_spnego_NegTokenInit = -1;
135 static gint ett_spnego_ContextFlags = -1;
136 static gint ett_spnego_NegTokenTarg = -1;
137 static gint ett_spnego_InitialContextToken_U = -1;
139 /*--- End of included file: packet-spnego-ett.c ---*/
140 #line 94 "../../asn1/spnego/packet-spnego-template.c"
143 * Unfortunately, we have to have a forward declaration of this,
144 * as the code generated by asn2wrs includes a call before the
147 static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
148 int offset, asn1_ctx_t *actx _U_,
149 proto_tree *tree, int hf_index);
152 /*--- Included file: packet-spnego-fn.c ---*/
153 #line 1 "../../asn1/spnego/packet-spnego-fn.c"
157 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_) {
158 #line 23 "../../asn1/spnego/spnego.cnf"
160 gssapi_oid_value *value;
162 offset = dissect_ber_object_identifier_str(implicit_tag, actx, tree, tvb, offset, hf_index, &MechType_oid);
165 value = gssapi_lookup_oid_str(MechType_oid);
168 * Tell our caller the first mechanism we see, so that if
169 * this is a negTokenInit with a mechToken, it can interpret
170 * the mechToken according to the first mechType. (There
171 * might not have been any indication of the mechType
172 * in prior frames, so we can't necessarily use the
173 * mechanism from the conversation; i.e., a negTokenInit
174 * can contain the initial security token for the desired
175 * mechanism of the initiator - that's the first mechanism
178 if (!saw_mechanism) {
180 next_level_value = value;
181 saw_mechanism = TRUE;
190 static const ber_sequence_t MechTypeList_sequence_of[1] = {
191 { &hf_spnego_MechTypeList_item, BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_spnego_MechType },
195 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_) {
196 #line 91 "../../asn1/spnego/spnego.cnf"
198 conversation_t *conversation;
200 saw_mechanism = FALSE;
202 offset = dissect_ber_sequence_of(implicit_tag, actx, tree, tvb, offset,
203 MechTypeList_sequence_of, hf_index, ett_spnego_MechTypeList);
207 * If we saw a mechType we need to store it in case the negTokenTarg
208 * does not provide a supportedMech.
211 conversation = find_or_create_conversation(actx->pinfo);
212 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
221 static const asn_namedbit ContextFlags_bits[] = {
222 { 0, &hf_spnego_ContextFlags_delegFlag, -1, -1, "delegFlag", NULL },
223 { 1, &hf_spnego_ContextFlags_mutualFlag, -1, -1, "mutualFlag", NULL },
224 { 2, &hf_spnego_ContextFlags_replayFlag, -1, -1, "replayFlag", NULL },
225 { 3, &hf_spnego_ContextFlags_sequenceFlag, -1, -1, "sequenceFlag", NULL },
226 { 4, &hf_spnego_ContextFlags_anonFlag, -1, -1, "anonFlag", NULL },
227 { 5, &hf_spnego_ContextFlags_confFlag, -1, -1, "confFlag", NULL },
228 { 6, &hf_spnego_ContextFlags_integFlag, -1, -1, "integFlag", NULL },
229 { 0, NULL, 0, 0, NULL, NULL }
233 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_) {
234 offset = dissect_ber_bitstring(implicit_tag, actx, tree, tvb, offset,
235 ContextFlags_bits, hf_index, ett_spnego_ContextFlags,
244 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_) {
245 #line 112 "../../asn1/spnego/spnego.cnf"
247 tvbuff_t *mechToken_tvb = NULL;
249 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
254 * Now, we should be able to dispatch, if we've gotten a tvbuff for
255 * the token and we have information on how to dissect its contents.
257 if (mechToken_tvb && next_level_value)
258 call_dissector(next_level_value->handle, mechToken_tvb, actx->pinfo, tree);
269 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_) {
270 #line 126 "../../asn1/spnego/spnego.cnf"
275 tvbuff_t *mechListMIC_tvb;
278 * There seems to be two different forms this can take,
279 * one as an octet string, and one as a general string in a
282 * Peek at the header, and then decide which it is we're seeing.
284 get_ber_identifier(tvb, offset, &class, &pc, &tag);
285 if (class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE) {
289 return dissect_spnego_PrincipalSeq(FALSE, tvb, offset, actx, tree,
290 hf_spnego_mechListMIC);
293 * It's not a sequence, so dissect it as an octet string,
294 * which is what it's supposed to be; that'll cause the
295 * right error report if it's not an octet string, either.
297 offset = dissect_ber_octet_string(FALSE, actx, tree, tvb, offset,
298 hf_spnego_mechListMIC, &mechListMIC_tvb);
301 * Now, we should be able to dispatch with that tvbuff.
303 if (mechListMIC_tvb && next_level_value)
304 call_dissector(next_level_value->handle, mechListMIC_tvb, actx->pinfo, tree);
314 static const ber_sequence_t NegTokenInit_sequence[] = {
315 { &hf_spnego_mechTypes , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_MechTypeList },
316 { &hf_spnego_reqFlags , BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_ContextFlags },
317 { &hf_spnego_mechToken , BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechToken },
318 { &hf_spnego_negTokenInit_mechListMIC, BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_NegTokenInit_mechListMIC },
319 { NULL, 0, 0, 0, NULL }
323 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_) {
324 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
325 NegTokenInit_sequence, hf_index, ett_spnego_NegTokenInit);
331 static const value_string spnego_T_negResult_vals[] = {
332 { 0, "accept-completed" },
333 { 1, "accept-incomplete" },
340 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_) {
341 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
350 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_) {
351 #line 164 "../../asn1/spnego/spnego.cnf"
353 conversation_t *conversation;
355 saw_mechanism = FALSE;
357 offset = dissect_spnego_MechType(implicit_tag, tvb, offset, actx, tree, hf_index);
361 * If we saw an explicit mechType we store this in the conversation so that
362 * it will override any mechType we might have picked up from the
366 conversation = find_or_create_conversation(actx->pinfo);
367 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
379 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_) {
380 #line 187 "../../asn1/spnego/spnego.cnf"
382 tvbuff_t *responseToken_tvb;
385 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
391 * Now, we should be able to dispatch, if we've gotten a tvbuff for
392 * the token and we have information on how to dissect its contents.
393 * However, we should make sure that there is something in the
396 if (responseToken_tvb && (tvb_reported_length(responseToken_tvb) > 0) ){
397 gssapi_oid_value *value=next_level_value;
400 call_dissector(value->handle, responseToken_tvb, actx->pinfo, tree);
413 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_) {
414 #line 214 "../../asn1/spnego/spnego.cnf"
416 tvbuff_t *mechListMIC_tvb;
419 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
425 * Now, we should be able to dispatch, if we've gotten a tvbuff for
426 * the MIC and we have information on how to dissect its contents.
428 if (mechListMIC_tvb && (tvb_reported_length(mechListMIC_tvb) > 0) ){
429 gssapi_oid_value *value=next_level_value;
432 call_dissector(value->handle, mechListMIC_tvb, actx->pinfo, tree);
443 static const ber_sequence_t NegTokenTarg_sequence[] = {
444 { &hf_spnego_negResult , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_T_negResult },
445 { &hf_spnego_supportedMech, BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_T_supportedMech },
446 { &hf_spnego_responseToken, BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_responseToken },
447 { &hf_spnego_mechListMIC , BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechListMIC },
448 { NULL, 0, 0, 0, NULL }
452 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_) {
453 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
454 NegTokenTarg_sequence, hf_index, ett_spnego_NegTokenTarg);
460 static const value_string spnego_NegotiationToken_vals[] = {
461 { 0, "negTokenInit" },
462 { 1, "negTokenTarg" },
466 static const ber_choice_t NegotiationToken_choice[] = {
467 { 0, &hf_spnego_negTokenInit , BER_CLASS_CON, 0, 0, dissect_spnego_NegTokenInit },
468 { 1, &hf_spnego_negTokenTarg , BER_CLASS_CON, 1, 0, dissect_spnego_NegTokenTarg },
469 { 0, NULL, 0, 0, 0, NULL }
473 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_) {
474 offset = dissect_ber_choice(actx, tree, tvb, offset,
475 NegotiationToken_choice, hf_index, ett_spnego_NegotiationToken,
484 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_) {
485 offset = dissect_ber_restricted_string(implicit_tag, BER_UNI_TAG_GeneralString,
486 actx, tree, tvb, offset, hf_index,
493 static const ber_sequence_t PrincipalSeq_sequence[] = {
494 { &hf_spnego_principal , BER_CLASS_CON, 0, 0, dissect_spnego_GeneralString },
495 { NULL, 0, 0, 0, NULL }
499 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_) {
500 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
501 PrincipalSeq_sequence, hf_index, ett_spnego_PrincipalSeq);
509 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_) {
510 #line 48 "../../asn1/spnego/spnego.cnf"
512 gssapi_oid_value *next_level_value_lcl;
519 * XXX - what should we do if this OID doesn't match the value
520 * attached to the frame or conversation? (That would be
521 * bogus, but that's not impossible - some broken implementation
522 * might negotiate some security mechanism but put the OID
523 * for some other security mechanism in GSS_Wrap tokens.)
526 next_level_value_lcl = gssapi_lookup_oid_str(MechType_oid);
529 * Now dissect the GSS_Wrap token; it's assumed to be in the
530 * rest of the tvbuff.
532 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, -1, ENC_NA);
534 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
537 * Now, we should be able to dispatch after creating a new TVB.
538 * The subdissector must return the length of the part of the
539 * token it dissected, so we can return the length of the part
540 * we (and it) dissected.
542 token_tvb = tvb_new_subset_remaining(tvb, offset);
543 if (next_level_value_lcl && next_level_value_lcl->wrap_handle) {
544 len = call_dissector(next_level_value_lcl->wrap_handle, token_tvb, actx->pinfo,
547 offset = tvb_length(tvb);
549 offset = offset + len;
551 offset = tvb_length(tvb);
559 static const ber_sequence_t InitialContextToken_U_sequence[] = {
560 { &hf_spnego_thisMech , BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_spnego_MechType },
561 { &hf_spnego_innerContextToken, BER_CLASS_ANY, 0, BER_FLAGS_NOOWNTAG, dissect_spnego_InnerContextToken },
562 { NULL, 0, 0, 0, NULL }
566 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_) {
567 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
568 InitialContextToken_U_sequence, hf_index, ett_spnego_InitialContextToken_U);
576 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_) {
577 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
578 hf_index, BER_CLASS_APP, 0, TRUE, dissect_spnego_InitialContextToken_U);
584 /*--- End of included file: packet-spnego-fn.c ---*/
585 #line 105 "../../asn1/spnego/packet-spnego-template.c"
587 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
588 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
589 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
592 #define KRB_TOKEN_AP_REQ 0x0001
593 #define KRB_TOKEN_AP_REP 0x0002
594 #define KRB_TOKEN_AP_ERR 0x0003
595 #define KRB_TOKEN_GETMIC 0x0101
596 #define KRB_TOKEN_WRAP 0x0102
597 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
598 #define KRB_TOKEN_CFX_GETMIC 0x0404
599 #define KRB_TOKEN_CFX_WRAP 0x0405
601 static const value_string spnego_krb5_tok_id_vals[] = {
602 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
603 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
604 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
605 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
606 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
607 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
608 { KRB_TOKEN_CFX_GETMIC, "KRB_TOKEN_CFX_GetMic" },
609 { KRB_TOKEN_CFX_WRAP, "KRB_TOKEN_CFX_WRAP" },
613 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
614 #define KRB_SGN_ALG_MD2_5 0x0001
615 #define KRB_SGN_ALG_DES_MAC 0x0002
616 #define KRB_SGN_ALG_HMAC 0x0011
618 static const value_string spnego_krb5_sgn_alg_vals[] = {
619 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
620 { KRB_SGN_ALG_MD2_5, "MD2.5"},
621 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
622 { KRB_SGN_ALG_HMAC, "HMAC"},
626 #define KRB_SEAL_ALG_DES_CBC 0x0000
627 #define KRB_SEAL_ALG_RC4 0x0010
628 #define KRB_SEAL_ALG_NONE 0xffff
630 static const value_string spnego_krb5_seal_alg_vals[] = {
631 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
632 { KRB_SEAL_ALG_RC4, "RC4"},
633 { KRB_SEAL_ALG_NONE, "None"},
638 * XXX - is this for SPNEGO or just GSS-API?
639 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
640 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
641 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
642 * getting it accepted.
645 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
647 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
649 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
651 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
654 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
663 gboolean pc, ind = 0;
667 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
669 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
672 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
675 * The KRB5 blob conforms to RFC1964:
678 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
681 * However, for some protocols, the KRB5 blob starts at the SHORT
682 * and has no DER encoded header etc.
684 * It appears that for some other protocols the KRB5 blob is just
685 * a Kerberos message, with no [APPLICATION 0] header, no OID,
690 * If we see an [APPLICATION 0] HEADER, we show the OID and
691 * the USHORT, and then dissect the rest as a Kerberos message.
693 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
694 * we assume it's an AP-REQ or AP-REP message, and dissect
695 * it all as a Kerberos message.
697 * Otherwise, we show the USHORT, and then dissect the rest
698 * as a Kerberos message.
702 * Get the first header ...
704 get_ber_identifier(tvb, offset, &class, &pc, &tag);
705 if (class == BER_CLASS_APP && pc) {
707 * [APPLICATION <tag>]
709 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
710 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
720 offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
722 token_id = tvb_get_letohs(tvb, offset);
723 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
730 case 14: /* [APPLICATION 14] */
731 case 15: /* [APPLICATION 15] */
733 * No token ID - just dissect as a Kerberos message and
736 dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
740 proto_tree_add_text(subtree, tvb, offset, 0,
741 "Unknown header (class=%d, pc=%d, tag=%d)",
746 /* Next, the token ID ... */
748 token_id = tvb_get_letohs(tvb, offset);
749 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
757 case KRB_TOKEN_AP_REQ:
758 case KRB_TOKEN_AP_REP:
759 case KRB_TOKEN_AP_ERR:
760 krb5_tvb = tvb_new_subset_remaining(tvb, offset);
761 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
764 case KRB_TOKEN_GETMIC:
765 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
769 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
772 case KRB_TOKEN_DELETE_SEC_CONTEXT:
776 case KRB_TOKEN_CFX_GETMIC:
777 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
780 case KRB_TOKEN_CFX_WRAP:
781 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
790 proto_item_set_len(item, offset);
795 #include <epan/crypt/md5.h>
797 #ifndef KEYTYPE_ARCFOUR_56
798 # define KEYTYPE_ARCFOUR_56 24
800 /* XXX - We should probably do a configure-time check for this instead */
801 #ifndef KRB5_KU_USAGE_SEAL
802 # define KRB5_KU_USAGE_SEAL 22
806 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
807 void *cksum_data, size_t cksum_size,
815 if (key_type == KEYTYPE_ARCFOUR_56) {
816 guint8 L40[14] = "fortybits";
818 memcpy(L40 + 10, T, sizeof(T));
824 memset(&k5_data[7], 0xAB, 9);
834 cksum_data, cksum_size,
843 usage2arcfour(int usage)
846 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
847 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
849 case 22: /*KRB5_KU_USAGE_SEAL 22 */
851 case 23: /*KRB5_KU_USAGE_SIGN 23 */
853 case 24: /*KRB5_KU_USAGE_SEQ 24 */
861 arcfour_mic_cksum(guint8 *key_data, int key_length,
864 const void *v1, size_t l1,
865 const void *v2, size_t l2,
866 const void *v3, size_t l3)
868 const guint8 signature[] = "signaturekey";
872 unsigned char digest[16];
876 rc4_usage=usage2arcfour(usage);
877 md5_hmac(signature, sizeof(signature),
878 key_data, key_length,
881 t[0] = (rc4_usage >> 0) & 0xFF;
882 t[1] = (rc4_usage >> 8) & 0xFF;
883 t[2] = (rc4_usage >> 16) & 0xFF;
884 t[3] = (rc4_usage >> 24) & 0xFF;
885 md5_append(&ms, t, 4);
886 md5_append(&ms, v1, l1);
887 md5_append(&ms, v2, l2);
888 md5_append(&ms, v3, l3);
889 md5_finish(&ms, digest);
890 md5_hmac(digest, 16, ksign_c, 16, cksum);
892 memcpy(sgn_cksum, cksum, 8);
898 * Verify padding of a gss wrapped message and return its length.
901 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
909 pad = wrapped_data + wrapped_length - 1;
912 if (padlength > datalen)
915 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
926 decrypt_arcfour(packet_info *pinfo,
927 guint8 *input_message_buffer,
928 guint8 *output_message_buffer,
929 guint8 *key_value, int key_size, int key_type)
931 guint8 Klocaldata[16];
936 guint8 Confounder[8];
937 guint8 cksum_data[8];
942 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
944 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
946 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
952 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
956 ret = arcfour_mic_key(key_value, key_size, key_type,
957 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
965 rc4_state_struct rc4_state;
967 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
968 tvb_memcpy(pinfo->gssapi_wrap_tvb, SND_SEQ, 8, 8);
969 crypt_rc4(&rc4_state, (unsigned char *)SND_SEQ, 8);
971 memset(k6_data, 0, sizeof(k6_data));
975 if (SND_SEQ[1] != 0xFFFFFFFF && SND_SEQ[1] != 0x00000000) {
982 for (i = 0; i < 16; i++)
983 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
985 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
986 (unsigned char *)SND_SEQ, 4,
988 memset(Klocaldata, 0, sizeof(Klocaldata));
994 rc4_state_struct rc4_state;
996 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
997 tvb_memcpy(pinfo->gssapi_wrap_tvb, Confounder, 24, 8);
998 crypt_rc4(&rc4_state, Confounder, 8);
999 memcpy(output_message_buffer, input_message_buffer, datalen);
1000 crypt_rc4(&rc4_state, output_message_buffer, datalen);
1002 tvb_memcpy(pinfo->gssapi_wrap_tvb, Confounder, 24, 8);
1003 memcpy(output_message_buffer,
1004 input_message_buffer,
1007 memset(k6_data, 0, sizeof(k6_data));
1009 /* only normal (i.e. non DCE style wrapping use padding ? */
1010 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1011 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
1018 /* dont know what the checksum looks like for dce style gssapi */
1019 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1020 ret = arcfour_mic_cksum(key_value, key_size,
1023 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
1024 Confounder, sizeof(Confounder),
1025 output_message_buffer,
1031 cmp = tvb_memeql(pinfo->gssapi_wrap_tvb, 16, cksum_data, 8); /* SGN_CKSUM */
1042 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1045 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
1050 const guint8 *original_data;
1052 static int omb_index=0;
1053 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
1054 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
1055 guint8 *output_message_buffer;
1061 output_message_buffer=omb_arr[omb_index];
1064 length=tvb_length(pinfo->gssapi_encrypted_tvb);
1065 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
1067 /* dont do anything if we are not attempting to decrypt data */
1073 /* XXX we should only do this for first time, then store somewhere */
1074 /* XXX We also need to re-read the keytab when the preference changes */
1076 cryptocopy=ep_alloc(length);
1077 if(output_message_buffer){
1078 g_free(output_message_buffer);
1079 output_message_buffer=NULL;
1081 output_message_buffer=g_malloc(length);
1083 for(ek=enc_key_list;ek;ek=ek->next){
1084 /* shortcircuit and bail out if enctypes are not matching */
1085 if(ek->keytype!=keytype){
1089 /* pre-0.6.1 versions of Heimdal would sometimes change
1090 the cryptotext data even when the decryption failed.
1091 This would obviously not work since we iterate over the
1092 keys. So just give it a copy of the crypto data instead.
1093 This has been seen for RC4-HMAC blobs.
1095 memcpy(cryptocopy, original_data, length);
1096 ret=decrypt_arcfour(pinfo,
1098 output_message_buffer,
1104 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
1105 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
1106 output_message_buffer,
1108 tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
1109 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1116 /* borrowed from heimdal */
1118 rrc_rotate(void *data, int len, guint16 rrc, int unrotate)
1120 unsigned char *tmp, buf[256];
1133 if (rrc <= sizeof(buf)) {
1136 tmp = g_malloc(rrc);
1142 memcpy(tmp, data, rrc);
1143 memmove(data, (unsigned char *)data + rrc, left);
1144 memcpy((unsigned char *)data + left, tmp, rrc);
1146 memcpy(tmp, (unsigned char *)data + left, rrc);
1147 memmove((unsigned char *)data + rrc, data, left);
1148 memcpy(data, tmp, rrc);
1151 if (rrc > sizeof(buf))
1158 #define KRB5_KU_USAGE_ACCEPTOR_SEAL 22
1159 #define KRB5_KU_USAGE_ACCEPTOR_SIGN 23
1160 #define KRB5_KU_USAGE_INITIATOR_SEAL 24
1161 #define KRB5_KU_USAGE_INITIATOR_SIGN 25
1164 decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_,
1166 tvbuff_t *checksum_tvb,
1167 tvbuff_t *encrypted_tvb,
1179 /* dont do anything if we are not attempting to decrypt data */
1184 datalen = tvb_length(checksum_tvb) + tvb_length(encrypted_tvb);
1186 rotated = g_malloc(datalen);
1188 tvb_memcpy(checksum_tvb, rotated,
1189 0, tvb_length(checksum_tvb));
1190 tvb_memcpy(encrypted_tvb, rotated + tvb_length(checksum_tvb),
1191 0, tvb_length(encrypted_tvb));
1197 rrc_rotate(rotated, datalen, rrc, TRUE);
1199 next_tvb=tvb_new_child_real_data(encrypted_tvb, rotated,
1201 tvb_set_free_cb(next_tvb, g_free);
1202 add_new_data_source(pinfo, next_tvb, "GSSAPI CFX");
1204 output = decrypt_krb5_data(tree, pinfo, usage, next_tvb,
1210 outdata = g_memdup(output, tvb_length(encrypted_tvb));
1213 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(encrypted_tvb,
1215 tvb_length(encrypted_tvb),
1216 tvb_length(encrypted_tvb));
1217 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1218 tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
1224 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1230 * This is for GSSAPI Wrap tokens ...
1233 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1234 #ifndef HAVE_KERBEROS
1237 , proto_tree *tree, guint16 token_id
1238 #ifndef HAVE_KERBEROS
1243 guint16 sgn_alg, seal_alg;
1244 #ifdef HAVE_KERBEROS
1245 int start_offset=offset;
1249 * The KRB5 blob conforms to RFC1964:
1250 * USHORT (0x0102 == GSS_Wrap)
1254 /* Now, the sign and seal algorithms ... */
1256 sgn_alg = tvb_get_letohs(tvb, offset);
1257 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1262 seal_alg = tvb_get_letohs(tvb, offset);
1263 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
1268 /* Skip the filler */
1272 /* Encrypted sequence number */
1274 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1279 /* Checksum of plaintext padded data */
1281 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1287 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1288 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1289 * extra 8 bytes of "Random confounder" after the checksum.
1290 * It certainly confounds code expecting all Kerberos 5
1291 * GSS_Wrap() tokens to look the same....
1293 if ((sgn_alg == KRB_SGN_ALG_HMAC) ||
1294 /* there also seems to be a confounder for DES MAC MD5 - certainly seen when using with
1295 SASL with LDAP between a Java client and Active Directory. If this breaks other things
1296 we may need to make this an option. gal 17/2/06 */
1297 (sgn_alg == KRB_SGN_ALG_DES_MAC_MD5)) {
1298 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1303 /* Is the data encrypted? */
1304 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
1306 #ifdef HAVE_KERBEROS
1307 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
1308 if(pinfo->decrypt_gssapi_tvb){
1309 /* if the caller did not provide a tvb, then we just use
1310 whatever is left of our current tvb.
1312 if(!pinfo->gssapi_encrypted_tvb){
1314 len=tvb_reported_length_remaining(tvb,offset);
1315 if(len>tvb_length_remaining(tvb, offset)){
1316 /* no point in trying to decrypt,
1317 we dont have the full pdu.
1321 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1322 tvb, offset, len, len);
1325 /* if this is KRB5 wrapped rc4-hmac */
1326 if((token_id==KRB_TOKEN_WRAP)
1327 &&(sgn_alg==KRB_SGN_ALG_HMAC)
1328 &&(seal_alg==KRB_SEAL_ALG_RC4)){
1329 /* do we need to create a tvb for the wrapper
1332 if(!pinfo->gssapi_wrap_tvb){
1333 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1334 tvb, start_offset-2,
1335 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
1336 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
1338 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1339 decrypt_gssapi_krb_arcfour_wrap(tree,
1343 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1348 * Return the offset past the checksum, so that we know where
1349 * the data we're wrapped around starts. Also, set the length
1350 * of our top-level item to that offset, so it doesn't cover
1351 * the data we're wrapped around.
1353 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1360 * XXX - This is for GSSAPI GetMIC tokens ...
1363 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1368 * The KRB5 blob conforms to RFC1964:
1369 * USHORT (0x0101 == GSS_GetMIC)
1373 /* Now, the sign algorithm ... */
1375 sgn_alg = tvb_get_letohs(tvb, offset);
1376 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1381 /* Skip the filler */
1385 /* Encrypted sequence number */
1387 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1392 /* Checksum of plaintext padded data */
1394 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1400 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1401 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1402 * extra 8 bytes of "Random confounder" after the checksum.
1403 * It certainly confounds code expecting all Kerberos 5
1404 * GSS_Wrap() tokens to look the same....
1406 * The exception is DNS/TSIG where there is no such confounder
1407 * so we need to test here if there are more bytes in our tvb or not.
1410 if (tvb_length_remaining(tvb, offset)) {
1411 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1412 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1420 * Return the offset past the checksum, so that we know where
1421 * the data we're wrapped around starts. Also, set the length
1422 * of our top-level item to that offset, so it doesn't cover
1423 * the data we're wrapped around.
1430 dissect_spnego_krb5_cfx_flags(tvbuff_t *tvb, int offset,
1431 proto_tree *spnego_krb5_tree,
1434 proto_tree *cfx_flags_tree = NULL;
1435 proto_item *tf = NULL;
1437 if (spnego_krb5_tree) {
1438 tf = proto_tree_add_uint(spnego_krb5_tree,
1439 hf_spnego_krb5_cfx_flags,
1440 tvb, offset, 1, cfx_flags);
1441 cfx_flags_tree = proto_item_add_subtree(tf, ett_spnego_krb5_cfx_flags);
1444 proto_tree_add_boolean(cfx_flags_tree,
1445 hf_spnego_krb5_cfx_flags_04,
1446 tvb, offset, 1, cfx_flags);
1447 proto_tree_add_boolean(cfx_flags_tree,
1448 hf_spnego_krb5_cfx_flags_02,
1449 tvb, offset, 1, cfx_flags);
1450 proto_tree_add_boolean(cfx_flags_tree,
1451 hf_spnego_krb5_cfx_flags_01,
1452 tvb, offset, 1, cfx_flags);
1454 return (offset + 1);
1458 * This is for GSSAPI CFX Wrap tokens ...
1461 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1462 #ifndef HAVE_KERBEROS
1465 , proto_tree *tree, guint16 token_id _U_
1470 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1474 int start_offset=offset;
1477 * The KRB5 blob conforms to RFC4121:
1482 /* Now, the sign and seal algorithms ... */
1484 flags = tvb_get_guint8(tvb, offset);
1485 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1487 pinfo->gssapi_data_encrypted=(flags & 2);
1489 /* Skip the filler */
1491 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 1,
1496 ec = tvb_get_ntohs(tvb, offset);
1497 proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2,
1502 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1503 rrc = tvb_get_ntohs(tvb, offset);
1505 proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2,
1509 /* sequence number */
1511 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1515 /* Checksum of plaintext padded data */
1517 if (pinfo->gssapi_data_encrypted) {
1518 checksum_size = 44 + ec;
1523 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1524 checksum_size, ENC_NA);
1525 offset += checksum_size;
1527 if(pinfo->decrypt_gssapi_tvb){
1528 /* if the caller did not provide a tvb, then we just use
1529 whatever is left of our current tvb.
1531 if(!pinfo->gssapi_encrypted_tvb){
1533 len=tvb_reported_length_remaining(tvb,offset);
1534 if(len>tvb_length_remaining(tvb, offset)){
1535 /* no point in trying to decrypt,
1536 we dont have the full pdu.
1540 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1541 tvb, offset, len, len);
1544 if (pinfo->gssapi_data_encrypted) {
1545 /* do we need to create a tvb for the wrapper
1548 if(!pinfo->gssapi_wrap_tvb){
1549 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1550 tvb, start_offset-2,
1551 offset - (start_offset-2),
1552 offset - (start_offset-2));
1557 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1559 tvbuff_t *checksum_tvb = tvb_new_subset(tvb, 16, checksum_size, checksum_size);
1561 if (pinfo->gssapi_data_encrypted) {
1562 if(pinfo->gssapi_encrypted_tvb){
1563 decrypt_gssapi_krb_cfx_wrap(tree,
1566 pinfo->gssapi_encrypted_tvb,
1569 (pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_DCE)?TRUE:FALSE,
1572 KRB5_KU_USAGE_ACCEPTOR_SEAL:
1573 KRB5_KU_USAGE_INITIATOR_SEAL);
1577 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1580 * Return the offset past the checksum, so that we know where
1581 * the data we're wrapped around starts. Also, set the length
1582 * of our top-level item to that offset, so it doesn't cover
1583 * the data we're wrapped around.
1585 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1592 * XXX - This is for GSSAPI CFX GetMIC tokens ...
1595 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1601 * The KRB5 blob conforms to RFC4121:
1602 * USHORT (0x0404 == GSS_GetMIC)
1606 flags = tvb_get_guint8(tvb, offset);
1607 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1609 /* Skip the filler */
1611 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 5,
1615 /* sequence number */
1617 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1621 /* Checksum of plaintext padded data */
1623 checksum_size = tvb_length_remaining(tvb, offset);
1625 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1626 checksum_size, ENC_NA);
1627 offset += checksum_size;
1630 * Return the offset past the checksum, so that we know where
1631 * the data we're wrapped around starts. Also, set the length
1632 * of our top-level item to that offset, so it doesn't cover
1633 * the data we're wrapped around.
1640 * XXX - is this for SPNEGO or just GSS-API?
1641 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1642 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1643 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1644 * getting it accepted.
1647 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
1650 proto_tree *subtree;
1654 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, ENC_NA);
1656 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1659 * The KRB5 blob conforms to RFC1964:
1660 * USHORT (0x0102 == GSS_Wrap)
1664 /* First, the token ID ... */
1666 token_id = tvb_get_letohs(tvb, offset);
1667 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1673 case KRB_TOKEN_GETMIC:
1674 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
1677 case KRB_TOKEN_WRAP:
1678 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1681 case KRB_TOKEN_CFX_GETMIC:
1682 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
1685 case KRB_TOKEN_CFX_WRAP:
1686 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
1695 * Return the offset past the checksum, so that we know where
1696 * the data we're wrapped around starts. Also, set the length
1697 * of our top-level item to that offset, so it doesn't cover
1698 * the data we're wrapped around.
1700 proto_item_set_len(item, offset);
1704 /* Spnego stuff from here */
1707 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1710 proto_tree *subtree;
1712 asn1_ctx_t asn1_ctx;
1713 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1715 MechType_oid = NULL;
1718 * We need this later, so lets get it now ...
1719 * It has to be per-frame as there can be more than one GSS-API
1720 * negotiation in a conversation.
1724 item = proto_tree_add_item(tree, proto_spnego, tvb, offset,
1727 subtree = proto_item_add_subtree(item, ett_spnego);
1729 * The TVB contains a [0] header and a sequence that consists of an
1730 * object ID and a blob containing the data ...
1731 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1732 * with the "optional" "use in non-initial tokens" being chosen.
1733 * ASN1 code addet to spnego.asn to handle this.
1736 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, &asn1_ctx , subtree, -1);
1743 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1746 proto_tree *subtree;
1748 conversation_t *conversation;
1749 asn1_ctx_t asn1_ctx;
1750 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1753 * We need this later, so lets get it now ...
1754 * It has to be per-frame as there can be more than one GSS-API
1755 * negotiation in a conversation.
1757 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1758 if (!next_level_value && !pinfo->fd->flags.visited) {
1760 * No handle attached to this frame, but it's the first
1761 * pass, so it'd be attached to the conversation.
1762 * If we have a conversation, try to get the handle,
1763 * and if we get one, attach it to the frame.
1765 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1766 pinfo->ptype, pinfo->srcport,
1767 pinfo->destport, 0);
1770 next_level_value = conversation_get_proto_data(conversation,
1772 if (next_level_value)
1773 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1777 item = proto_tree_add_item(parent_tree, proto_spnego, tvb, offset,
1780 subtree = proto_item_add_subtree(item, ett_spnego);
1783 * The TVB contains a [0] header and a sequence that consists of an
1784 * object ID and a blob containing the data ...
1785 * Actually, it contains, according to RFC2478:
1786 * NegotiationToken ::= CHOICE {
1787 * negTokenInit [0] NegTokenInit,
1788 * negTokenTarg [1] NegTokenTarg }
1789 * NegTokenInit ::= SEQUENCE {
1790 * mechTypes [0] MechTypeList OPTIONAL,
1791 * reqFlags [1] ContextFlags OPTIONAL,
1792 * mechToken [2] OCTET STRING OPTIONAL,
1793 * mechListMIC [3] OCTET STRING OPTIONAL }
1794 * NegTokenTarg ::= SEQUENCE {
1795 * negResult [0] ENUMERATED {
1796 * accept_completed (0),
1797 * accept_incomplete (1),
1798 * reject (2) } OPTIONAL,
1799 * supportedMech [1] MechType OPTIONAL,
1800 * responseToken [2] OCTET STRING OPTIONAL,
1801 * mechListMIC [3] OCTET STRING OPTIONAL }
1803 * Windows typically includes mechTypes and mechListMic ('NONE'
1804 * in the case of NTLMSSP only).
1805 * It seems to duplicate the responseToken into the mechListMic field
1806 * as well. Naughty, naughty.
1809 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
1813 /*--- proto_register_spnego -------------------------------------------*/
1814 void proto_register_spnego(void) {
1816 /* List of fields */
1817 static hf_register_info hf[] = {
1818 { &hf_spnego_wraptoken,
1819 { "wrapToken", "spnego.wraptoken",
1820 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1823 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1824 BASE_NONE, NULL, 0, NULL, HFILL }},
1825 { &hf_spnego_krb5_oid,
1826 { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
1827 BASE_NONE, NULL, 0, NULL, HFILL }},
1828 { &hf_spnego_krb5_tok_id,
1829 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1830 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1831 { &hf_spnego_krb5_sgn_alg,
1832 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1833 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1834 { &hf_spnego_krb5_seal_alg,
1835 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1836 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1837 { &hf_spnego_krb5_snd_seq,
1838 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1839 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1840 { &hf_spnego_krb5_sgn_cksum,
1841 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1842 NULL, 0, "KRB5 Data Checksum", HFILL}},
1843 { &hf_spnego_krb5_confounder,
1844 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1845 NULL, 0, "KRB5 Confounder", HFILL}},
1846 { &hf_spnego_krb5_filler,
1847 { "krb5_filler", "spnego.krb5.filler", FT_BYTES, BASE_NONE,
1848 NULL, 0, "KRB5 Filler", HFILL}},
1849 { &hf_spnego_krb5_cfx_flags,
1850 { "krb5_cfx_flags", "spnego.krb5.cfx_flags", FT_UINT8, BASE_HEX,
1851 NULL, 0, "KRB5 CFX Flags", HFILL}},
1852 { &hf_spnego_krb5_cfx_flags_01,
1853 { "SendByAcceptor", "spnego.krb5.send_by_acceptor", FT_BOOLEAN, 8,
1854 TFS (&tfs_set_notset), 0x01, NULL, HFILL}},
1855 { &hf_spnego_krb5_cfx_flags_02,
1856 { "Sealed", "spnego.krb5.sealed", FT_BOOLEAN, 8,
1857 TFS (&tfs_set_notset), 0x02, NULL, HFILL}},
1858 { &hf_spnego_krb5_cfx_flags_04,
1859 { "AcceptorSubkey", "spnego.krb5.acceptor_subkey", FT_BOOLEAN, 8,
1860 TFS (&tfs_set_notset), 0x04, NULL, HFILL}},
1861 { &hf_spnego_krb5_cfx_ec,
1862 { "krb5_cfx_ec", "spnego.krb5.cfx_ec", FT_UINT16, BASE_DEC,
1863 NULL, 0, "KRB5 CFX Extra Count", HFILL}},
1864 { &hf_spnego_krb5_cfx_rrc,
1865 { "krb5_cfx_rrc", "spnego.krb5.cfx_rrc", FT_UINT16, BASE_DEC,
1866 NULL, 0, "KRB5 CFX Right Rotation Count", HFILL}},
1867 { &hf_spnego_krb5_cfx_seq,
1868 { "krb5_cfx_seq", "spnego.krb5.cfx_seq", FT_UINT64, BASE_DEC,
1869 NULL, 0, "KRB5 Sequence Number", HFILL}},
1872 /*--- Included file: packet-spnego-hfarr.c ---*/
1873 #line 1 "../../asn1/spnego/packet-spnego-hfarr.c"
1874 { &hf_spnego_negTokenInit,
1875 { "negTokenInit", "spnego.negTokenInit",
1876 FT_NONE, BASE_NONE, NULL, 0,
1878 { &hf_spnego_negTokenTarg,
1879 { "negTokenTarg", "spnego.negTokenTarg",
1880 FT_NONE, BASE_NONE, NULL, 0,
1882 { &hf_spnego_MechTypeList_item,
1883 { "MechType", "spnego.MechType",
1884 FT_OID, BASE_NONE, NULL, 0,
1886 { &hf_spnego_principal,
1887 { "principal", "spnego.principal",
1888 FT_STRING, BASE_NONE, NULL, 0,
1889 "GeneralString", HFILL }},
1890 { &hf_spnego_mechTypes,
1891 { "mechTypes", "spnego.mechTypes",
1892 FT_UINT32, BASE_DEC, NULL, 0,
1893 "MechTypeList", HFILL }},
1894 { &hf_spnego_reqFlags,
1895 { "reqFlags", "spnego.reqFlags",
1896 FT_BYTES, BASE_NONE, NULL, 0,
1897 "ContextFlags", HFILL }},
1898 { &hf_spnego_mechToken,
1899 { "mechToken", "spnego.mechToken",
1900 FT_BYTES, BASE_NONE, NULL, 0,
1902 { &hf_spnego_negTokenInit_mechListMIC,
1903 { "mechListMIC", "spnego.mechListMIC",
1904 FT_BYTES, BASE_NONE, NULL, 0,
1905 "T_NegTokenInit_mechListMIC", HFILL }},
1906 { &hf_spnego_negResult,
1907 { "negResult", "spnego.negResult",
1908 FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
1910 { &hf_spnego_supportedMech,
1911 { "supportedMech", "spnego.supportedMech",
1912 FT_OID, BASE_NONE, NULL, 0,
1914 { &hf_spnego_responseToken,
1915 { "responseToken", "spnego.responseToken",
1916 FT_BYTES, BASE_NONE, NULL, 0,
1918 { &hf_spnego_mechListMIC,
1919 { "mechListMIC", "spnego.mechListMIC",
1920 FT_BYTES, BASE_NONE, NULL, 0,
1922 { &hf_spnego_thisMech,
1923 { "thisMech", "spnego.thisMech",
1924 FT_OID, BASE_NONE, NULL, 0,
1925 "MechType", HFILL }},
1926 { &hf_spnego_innerContextToken,
1927 { "innerContextToken", "spnego.innerContextToken",
1928 FT_NONE, BASE_NONE, NULL, 0,
1930 { &hf_spnego_ContextFlags_delegFlag,
1931 { "delegFlag", "spnego.delegFlag",
1932 FT_BOOLEAN, 8, NULL, 0x80,
1934 { &hf_spnego_ContextFlags_mutualFlag,
1935 { "mutualFlag", "spnego.mutualFlag",
1936 FT_BOOLEAN, 8, NULL, 0x40,
1938 { &hf_spnego_ContextFlags_replayFlag,
1939 { "replayFlag", "spnego.replayFlag",
1940 FT_BOOLEAN, 8, NULL, 0x20,
1942 { &hf_spnego_ContextFlags_sequenceFlag,
1943 { "sequenceFlag", "spnego.sequenceFlag",
1944 FT_BOOLEAN, 8, NULL, 0x10,
1946 { &hf_spnego_ContextFlags_anonFlag,
1947 { "anonFlag", "spnego.anonFlag",
1948 FT_BOOLEAN, 8, NULL, 0x08,
1950 { &hf_spnego_ContextFlags_confFlag,
1951 { "confFlag", "spnego.confFlag",
1952 FT_BOOLEAN, 8, NULL, 0x04,
1954 { &hf_spnego_ContextFlags_integFlag,
1955 { "integFlag", "spnego.integFlag",
1956 FT_BOOLEAN, 8, NULL, 0x02,
1959 /*--- End of included file: packet-spnego-hfarr.c ---*/
1960 #line 1391 "../../asn1/spnego/packet-spnego-template.c"
1963 /* List of subtrees */
1964 static gint *ett[] = {
1966 &ett_spnego_wraptoken,
1968 &ett_spnego_krb5_cfx_flags,
1971 /*--- Included file: packet-spnego-ettarr.c ---*/
1972 #line 1 "../../asn1/spnego/packet-spnego-ettarr.c"
1973 &ett_spnego_NegotiationToken,
1974 &ett_spnego_MechTypeList,
1975 &ett_spnego_PrincipalSeq,
1976 &ett_spnego_NegTokenInit,
1977 &ett_spnego_ContextFlags,
1978 &ett_spnego_NegTokenTarg,
1979 &ett_spnego_InitialContextToken_U,
1981 /*--- End of included file: packet-spnego-ettarr.c ---*/
1982 #line 1401 "../../asn1/spnego/packet-spnego-template.c"
1985 /* Register protocol */
1986 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1988 register_dissector("spnego", dissect_spnego, proto_spnego);
1990 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1994 register_dissector("spnego-krb5", dissect_spnego_krb5, proto_spnego_krb5);
1995 new_register_dissector("spnego-krb5-wrap", dissect_spnego_krb5_wrap, proto_spnego_krb5);
1997 /* Register fields and subtrees */
1998 proto_register_field_array(proto_spnego, hf, array_length(hf));
1999 proto_register_subtree_array(ett, array_length(ett));
2003 /*--- proto_reg_handoff_spnego ---------------------------------------*/
2004 void proto_reg_handoff_spnego(void) {
2006 dissector_handle_t spnego_handle, spnego_wrap_handle;
2007 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
2009 /* Register protocol with GSS-API module */
2011 spnego_handle = find_dissector("spnego");
2012 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap, proto_spnego);
2013 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
2014 spnego_handle, spnego_wrap_handle,
2015 "SPNEGO - Simple Protected Negotiation");
2017 /* Register both the one MS created and the real one */
2019 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
2020 * mystery of the MS KRB5 OID is cleared up. It was due to a library
2021 * that did not handle OID components greater than 16 bits, and was
2022 * fixed in Win2K SP2 as well as WinXP.
2023 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
2024 * SPNEGO implementation issues. 3-Dec-2002.
2026 spnego_krb5_handle = find_dissector("spnego-krb5");
2027 spnego_krb5_wrap_handle = find_dissector("spnego-krb5-wrap");
2028 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2029 spnego_krb5_handle, spnego_krb5_wrap_handle,
2030 "MS KRB5 - Microsoft Kerberos 5");
2031 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2032 spnego_krb5_handle, spnego_krb5_wrap_handle,
2033 "KRB5 - Kerberos 5");
2034 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
2035 spnego_krb5_handle, spnego_krb5_wrap_handle,
2036 "KRB5 - Kerberos 5 - User to User");