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>
59 #include "packet-ber.h"
62 #define PNAME "Simple Protected Negotiation"
63 #define PSNAME "SPNEGO"
64 #define PFNAME "spnego"
66 /* Initialize the protocol and registered fields */
67 static int proto_spnego = -1;
68 static int proto_spnego_krb5 = -1;
71 static int hf_spnego_wraptoken = -1;
72 static int hf_spnego_krb5_oid;
73 static int hf_spnego_krb5 = -1;
74 static int hf_spnego_krb5_tok_id = -1;
75 static int hf_spnego_krb5_sgn_alg = -1;
76 static int hf_spnego_krb5_seal_alg = -1;
77 static int hf_spnego_krb5_snd_seq = -1;
78 static int hf_spnego_krb5_sgn_cksum = -1;
79 static int hf_spnego_krb5_confounder = -1;
80 static int hf_spnego_krb5_filler = -1;
81 static int hf_spnego_krb5_cfx_flags = -1;
82 static int hf_spnego_krb5_cfx_flags_01 = -1;
83 static int hf_spnego_krb5_cfx_flags_02 = -1;
84 static int hf_spnego_krb5_cfx_flags_04 = -1;
85 static int hf_spnego_krb5_cfx_ec = -1;
86 static int hf_spnego_krb5_cfx_rrc = -1;
87 static int hf_spnego_krb5_cfx_seq = -1;
90 /*--- Included file: packet-spnego-hf.c ---*/
91 #line 1 "packet-spnego-hf.c"
92 static int hf_spnego_negTokenInit = -1; /* NegTokenInit */
93 static int hf_spnego_negTokenTarg = -1; /* NegTokenTarg */
94 static int hf_spnego_MechTypeList_item = -1; /* MechType */
95 static int hf_spnego_principal = -1; /* GeneralString */
96 static int hf_spnego_mechTypes = -1; /* MechTypeList */
97 static int hf_spnego_reqFlags = -1; /* ContextFlags */
98 static int hf_spnego_mechToken = -1; /* T_mechToken */
99 static int hf_spnego_negTokenInit_mechListMIC = -1; /* T_NegTokenInit_mechListMIC */
100 static int hf_spnego_negResult = -1; /* T_negResult */
101 static int hf_spnego_supportedMech = -1; /* T_supportedMech */
102 static int hf_spnego_responseToken = -1; /* T_responseToken */
103 static int hf_spnego_mechListMIC = -1; /* T_mechListMIC */
104 static int hf_spnego_thisMech = -1; /* MechType */
105 static int hf_spnego_innerContextToken = -1; /* InnerContextToken */
107 static int hf_spnego_ContextFlags_delegFlag = -1;
108 static int hf_spnego_ContextFlags_mutualFlag = -1;
109 static int hf_spnego_ContextFlags_replayFlag = -1;
110 static int hf_spnego_ContextFlags_sequenceFlag = -1;
111 static int hf_spnego_ContextFlags_anonFlag = -1;
112 static int hf_spnego_ContextFlags_confFlag = -1;
113 static int hf_spnego_ContextFlags_integFlag = -1;
115 /*--- End of included file: packet-spnego-hf.c ---*/
116 #line 82 "packet-spnego-template.c"
118 /* Global variables */
119 static const char *MechType_oid;
120 gssapi_oid_value *next_level_value;
121 gboolean saw_mechanism = FALSE;
124 /* Initialize the subtree pointers */
125 static gint ett_spnego = -1;
126 static gint ett_spnego_wraptoken = -1;
127 static gint ett_spnego_krb5 = -1;
128 static gint ett_spnego_krb5_cfx_flags = -1;
131 /*--- Included file: packet-spnego-ett.c ---*/
132 #line 1 "packet-spnego-ett.c"
133 static gint ett_spnego_NegotiationToken = -1;
134 static gint ett_spnego_MechTypeList = -1;
135 static gint ett_spnego_PrincipalSeq = -1;
136 static gint ett_spnego_NegTokenInit = -1;
137 static gint ett_spnego_ContextFlags = -1;
138 static gint ett_spnego_NegTokenTarg = -1;
139 static gint ett_spnego_InitialContextToken_U = -1;
141 /*--- End of included file: packet-spnego-ett.c ---*/
142 #line 96 "packet-spnego-template.c"
145 * Unfortunately, we have to have a forward declaration of this,
146 * as the code generated by asn2wrs includes a call before the
149 static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
150 int offset, asn1_ctx_t *actx _U_,
151 proto_tree *tree, int hf_index);
154 /*--- Included file: packet-spnego-fn.c ---*/
155 #line 1 "packet-spnego-fn.c"
159 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_) {
160 #line 23 "spnego.cnf"
162 gssapi_oid_value *value;
164 offset = dissect_ber_object_identifier_str(implicit_tag, actx, tree, tvb, offset, hf_index, &MechType_oid);
167 value = gssapi_lookup_oid_str(MechType_oid);
170 * Tell our caller the first mechanism we see, so that if
171 * this is a negTokenInit with a mechToken, it can interpret
172 * the mechToken according to the first mechType. (There
173 * might not have been any indication of the mechType
174 * in prior frames, so we can't necessarily use the
175 * mechanism from the conversation; i.e., a negTokenInit
176 * can contain the initial security token for the desired
177 * mechanism of the initiator - that's the first mechanism
180 if (!saw_mechanism) {
182 next_level_value = value;
183 saw_mechanism = TRUE;
192 static const ber_sequence_t MechTypeList_sequence_of[1] = {
193 { &hf_spnego_MechTypeList_item, BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_spnego_MechType },
197 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_) {
198 #line 91 "spnego.cnf"
200 conversation_t *conversation;
202 saw_mechanism = FALSE;
204 offset = dissect_ber_sequence_of(implicit_tag, actx, tree, tvb, offset,
205 MechTypeList_sequence_of, hf_index, ett_spnego_MechTypeList);
209 * If we saw a mechType we need to store it in case the negTokenTarg
210 * does not provide a supportedMech.
213 conversation = find_or_create_conversation(actx->pinfo);
214 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
223 static const asn_namedbit ContextFlags_bits[] = {
224 { 0, &hf_spnego_ContextFlags_delegFlag, -1, -1, "delegFlag", NULL },
225 { 1, &hf_spnego_ContextFlags_mutualFlag, -1, -1, "mutualFlag", NULL },
226 { 2, &hf_spnego_ContextFlags_replayFlag, -1, -1, "replayFlag", NULL },
227 { 3, &hf_spnego_ContextFlags_sequenceFlag, -1, -1, "sequenceFlag", NULL },
228 { 4, &hf_spnego_ContextFlags_anonFlag, -1, -1, "anonFlag", NULL },
229 { 5, &hf_spnego_ContextFlags_confFlag, -1, -1, "confFlag", NULL },
230 { 6, &hf_spnego_ContextFlags_integFlag, -1, -1, "integFlag", NULL },
231 { 0, NULL, 0, 0, NULL, NULL }
235 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_) {
236 offset = dissect_ber_bitstring(implicit_tag, actx, tree, tvb, offset,
237 ContextFlags_bits, hf_index, ett_spnego_ContextFlags,
246 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_) {
247 #line 112 "spnego.cnf"
249 tvbuff_t *mechToken_tvb = NULL;
251 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
256 * Now, we should be able to dispatch, if we've gotten a tvbuff for
257 * the token and we have information on how to dissect its contents.
259 if (mechToken_tvb && next_level_value)
260 call_dissector(next_level_value->handle, mechToken_tvb, actx->pinfo, tree);
271 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_) {
272 #line 126 "spnego.cnf"
277 tvbuff_t *mechListMIC_tvb;
280 * There seems to be two different forms this can take,
281 * one as an octet string, and one as a general string in a
284 * Peek at the header, and then decide which it is we're seeing.
286 get_ber_identifier(tvb, offset, &class, &pc, &tag);
287 if (class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE) {
291 return dissect_spnego_PrincipalSeq(FALSE, tvb, offset, actx, tree,
292 hf_spnego_mechListMIC);
295 * It's not a sequence, so dissect it as an octet string,
296 * which is what it's supposed to be; that'll cause the
297 * right error report if it's not an octet string, either.
299 offset = dissect_ber_octet_string(FALSE, actx, tree, tvb, offset,
300 hf_spnego_mechListMIC, &mechListMIC_tvb);
303 * Now, we should be able to dispatch with that tvbuff.
305 if (mechListMIC_tvb && next_level_value)
306 call_dissector(next_level_value->handle, mechListMIC_tvb, actx->pinfo, tree);
316 static const ber_sequence_t NegTokenInit_sequence[] = {
317 { &hf_spnego_mechTypes , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_MechTypeList },
318 { &hf_spnego_reqFlags , BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_ContextFlags },
319 { &hf_spnego_mechToken , BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechToken },
320 { &hf_spnego_negTokenInit_mechListMIC, BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_NegTokenInit_mechListMIC },
321 { NULL, 0, 0, 0, NULL }
325 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_) {
326 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
327 NegTokenInit_sequence, hf_index, ett_spnego_NegTokenInit);
333 static const value_string spnego_T_negResult_vals[] = {
334 { 0, "accept-completed" },
335 { 1, "accept-incomplete" },
342 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_) {
343 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
352 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_) {
353 #line 164 "spnego.cnf"
355 conversation_t *conversation;
357 saw_mechanism = FALSE;
359 offset = dissect_spnego_MechType(implicit_tag, tvb, offset, actx, tree, hf_index);
363 * If we saw an explicit mechType we store this in the conversation so that
364 * it will override any mechType we might have picked up from the
368 conversation = find_or_create_conversation(actx->pinfo);
369 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
381 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_) {
382 #line 187 "spnego.cnf"
384 tvbuff_t *responseToken_tvb;
387 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
393 * Now, we should be able to dispatch, if we've gotten a tvbuff for
394 * the token and we have information on how to dissect its contents.
395 * However, we should make sure that there is something in the
398 if (responseToken_tvb && (tvb_reported_length(responseToken_tvb) > 0) ){
399 gssapi_oid_value *value=next_level_value;
402 call_dissector(value->handle, responseToken_tvb, actx->pinfo, tree);
415 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_) {
416 #line 214 "spnego.cnf"
418 tvbuff_t *mechListMIC_tvb;
421 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
427 * Now, we should be able to dispatch, if we've gotten a tvbuff for
428 * the MIC and we have information on how to dissect its contents.
430 if (mechListMIC_tvb && (tvb_reported_length(mechListMIC_tvb) > 0) ){
431 gssapi_oid_value *value=next_level_value;
434 call_dissector(value->handle, mechListMIC_tvb, actx->pinfo, tree);
445 static const ber_sequence_t NegTokenTarg_sequence[] = {
446 { &hf_spnego_negResult , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_T_negResult },
447 { &hf_spnego_supportedMech, BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_T_supportedMech },
448 { &hf_spnego_responseToken, BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_responseToken },
449 { &hf_spnego_mechListMIC , BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechListMIC },
450 { NULL, 0, 0, 0, NULL }
454 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_) {
455 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
456 NegTokenTarg_sequence, hf_index, ett_spnego_NegTokenTarg);
462 static const value_string spnego_NegotiationToken_vals[] = {
463 { 0, "negTokenInit" },
464 { 1, "negTokenTarg" },
468 static const ber_choice_t NegotiationToken_choice[] = {
469 { 0, &hf_spnego_negTokenInit , BER_CLASS_CON, 0, 0, dissect_spnego_NegTokenInit },
470 { 1, &hf_spnego_negTokenTarg , BER_CLASS_CON, 1, 0, dissect_spnego_NegTokenTarg },
471 { 0, NULL, 0, 0, 0, NULL }
475 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_) {
476 offset = dissect_ber_choice(actx, tree, tvb, offset,
477 NegotiationToken_choice, hf_index, ett_spnego_NegotiationToken,
486 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_) {
487 offset = dissect_ber_restricted_string(implicit_tag, BER_UNI_TAG_GeneralString,
488 actx, tree, tvb, offset, hf_index,
495 static const ber_sequence_t PrincipalSeq_sequence[] = {
496 { &hf_spnego_principal , BER_CLASS_CON, 0, 0, dissect_spnego_GeneralString },
497 { NULL, 0, 0, 0, NULL }
501 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_) {
502 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
503 PrincipalSeq_sequence, hf_index, ett_spnego_PrincipalSeq);
511 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_) {
512 #line 48 "spnego.cnf"
514 gssapi_oid_value *next_level_value_lcl;
521 * XXX - what should we do if this OID doesn't match the value
522 * attached to the frame or conversation? (That would be
523 * bogus, but that's not impossible - some broken implementation
524 * might negotiate some security mechanism but put the OID
525 * for some other security mechanism in GSS_Wrap tokens.)
528 next_level_value_lcl = gssapi_lookup_oid_str(MechType_oid);
531 * Now dissect the GSS_Wrap token; it's assumed to be in the
532 * rest of the tvbuff.
534 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, -1, FALSE);
536 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
539 * Now, we should be able to dispatch after creating a new TVB.
540 * The subdissector must return the length of the part of the
541 * token it dissected, so we can return the length of the part
542 * we (and it) dissected.
544 token_tvb = tvb_new_subset_remaining(tvb, offset);
545 if (next_level_value_lcl && next_level_value_lcl->wrap_handle) {
546 len = call_dissector(next_level_value_lcl->wrap_handle, token_tvb, actx->pinfo,
549 offset = tvb_length(tvb);
551 offset = offset + len;
553 offset = tvb_length(tvb);
561 static const ber_sequence_t InitialContextToken_U_sequence[] = {
562 { &hf_spnego_thisMech , BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_spnego_MechType },
563 { &hf_spnego_innerContextToken, BER_CLASS_ANY, 0, BER_FLAGS_NOOWNTAG, dissect_spnego_InnerContextToken },
564 { NULL, 0, 0, 0, NULL }
568 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_) {
569 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
570 InitialContextToken_U_sequence, hf_index, ett_spnego_InitialContextToken_U);
578 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_) {
579 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
580 hf_index, BER_CLASS_APP, 0, TRUE, dissect_spnego_InitialContextToken_U);
586 /*--- End of included file: packet-spnego-fn.c ---*/
587 #line 107 "packet-spnego-template.c"
589 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
590 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
591 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
594 #define KRB_TOKEN_AP_REQ 0x0001
595 #define KRB_TOKEN_AP_REP 0x0002
596 #define KRB_TOKEN_AP_ERR 0x0003
597 #define KRB_TOKEN_GETMIC 0x0101
598 #define KRB_TOKEN_WRAP 0x0102
599 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
600 #define KRB_TOKEN_CFX_GETMIC 0x0404
601 #define KRB_TOKEN_CFX_WRAP 0x0405
603 static const value_string spnego_krb5_tok_id_vals[] = {
604 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
605 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
606 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
607 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
608 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
609 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
610 { KRB_TOKEN_CFX_GETMIC, "KRB_TOKEN_CFX_GetMic" },
611 { KRB_TOKEN_CFX_WRAP, "KRB_TOKEN_CFX_WRAP" },
615 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
616 #define KRB_SGN_ALG_MD2_5 0x0001
617 #define KRB_SGN_ALG_DES_MAC 0x0002
618 #define KRB_SGN_ALG_HMAC 0x0011
620 static const value_string spnego_krb5_sgn_alg_vals[] = {
621 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
622 { KRB_SGN_ALG_MD2_5, "MD2.5"},
623 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
624 { KRB_SGN_ALG_HMAC, "HMAC"},
628 #define KRB_SEAL_ALG_DES_CBC 0x0000
629 #define KRB_SEAL_ALG_RC4 0x0010
630 #define KRB_SEAL_ALG_NONE 0xffff
632 static const value_string spnego_krb5_seal_alg_vals[] = {
633 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
634 { KRB_SEAL_ALG_RC4, "RC4"},
635 { KRB_SEAL_ALG_NONE, "None"},
640 * XXX - is this for SPNEGO or just GSS-API?
641 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
642 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
643 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
644 * getting it accepted.
647 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
649 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
651 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
653 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
656 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
663 gssapi_oid_value *value;
666 gboolean pc, ind = 0;
670 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
672 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
675 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
678 * The KRB5 blob conforms to RFC1964:
681 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
684 * However, for some protocols, the KRB5 blob starts at the SHORT
685 * and has no DER encoded header etc.
687 * It appears that for some other protocols the KRB5 blob is just
688 * a Kerberos message, with no [APPLICATION 0] header, no OID,
693 * If we see an [APPLICATION 0] HEADER, we show the OID and
694 * the USHORT, and then dissect the rest as a Kerberos message.
696 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
697 * we assume it's an AP-REQ or AP-REP message, and dissect
698 * it all as a Kerberos message.
700 * Otherwise, we show the USHORT, and then dissect the rest
701 * as a Kerberos message.
705 * Get the first header ...
707 get_ber_identifier(tvb, offset, &class, &pc, &tag);
708 if (class == BER_CLASS_APP && pc) {
710 * [APPLICATION <tag>]
712 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
713 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
723 offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
725 value = gssapi_lookup_oid_str(oid);
727 token_id = tvb_get_letohs(tvb, offset);
728 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
735 case 14: /* [APPLICATION 14] */
736 case 15: /* [APPLICATION 15] */
738 * No token ID - just dissect as a Kerberos message and
741 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
745 proto_tree_add_text(subtree, tvb, offset, 0,
746 "Unknown header (class=%d, pc=%d, tag=%d)",
751 /* Next, the token ID ... */
753 token_id = tvb_get_letohs(tvb, offset);
754 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
762 case KRB_TOKEN_AP_REQ:
763 case KRB_TOKEN_AP_REP:
764 case KRB_TOKEN_AP_ERR:
765 krb5_tvb = tvb_new_subset_remaining(tvb, offset);
766 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
769 case KRB_TOKEN_GETMIC:
770 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
774 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
777 case KRB_TOKEN_DELETE_SEC_CONTEXT:
781 case KRB_TOKEN_CFX_GETMIC:
782 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
785 case KRB_TOKEN_CFX_WRAP:
786 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
795 proto_item_set_len(item, offset);
800 #include <epan/crypt/crypt-md5.h>
802 #ifndef KEYTYPE_ARCFOUR_56
803 # define KEYTYPE_ARCFOUR_56 24
805 /* XXX - We should probably do a configure-time check for this instead */
806 #ifndef KRB5_KU_USAGE_SEAL
807 # define KRB5_KU_USAGE_SEAL 22
811 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
812 void *cksum_data, size_t cksum_size,
820 if (key_type == KEYTYPE_ARCFOUR_56) {
821 guint8 L40[14] = "fortybits";
823 memcpy(L40 + 10, T, sizeof(T));
829 memset(&k5_data[7], 0xAB, 9);
839 cksum_data, cksum_size,
848 usage2arcfour(int usage)
851 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
852 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
854 case 22: /*KRB5_KU_USAGE_SEAL 22 */
856 case 23: /*KRB5_KU_USAGE_SIGN 23 */
858 case 24: /*KRB5_KU_USAGE_SEQ 24 */
866 arcfour_mic_cksum(guint8 *key_data, int key_length,
869 const void *v1, size_t l1,
870 const void *v2, size_t l2,
871 const void *v3, size_t l3)
873 const guint8 signature[] = "signaturekey";
877 unsigned char digest[16];
881 rc4_usage=usage2arcfour(usage);
882 md5_hmac(signature, sizeof(signature),
883 key_data, key_length,
886 t[0] = (rc4_usage >> 0) & 0xFF;
887 t[1] = (rc4_usage >> 8) & 0xFF;
888 t[2] = (rc4_usage >> 16) & 0xFF;
889 t[3] = (rc4_usage >> 24) & 0xFF;
890 md5_append(&ms, t, 4);
891 md5_append(&ms, v1, l1);
892 md5_append(&ms, v2, l2);
893 md5_append(&ms, v3, l3);
894 md5_finish(&ms, digest);
895 md5_hmac(digest, 16, ksign_c, 16, cksum);
897 memcpy(sgn_cksum, cksum, 8);
903 * Verify padding of a gss wrapped message and return its length.
906 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
914 pad = wrapped_data + wrapped_length - 1;
917 if (padlength > datalen)
920 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
931 decrypt_arcfour(packet_info *pinfo,
932 guint8 *input_message_buffer,
933 guint8 *output_message_buffer,
934 guint8 *key_value, int key_size, int key_type)
936 guint8 Klocaldata[16];
942 guint8 Confounder[8];
943 guint8 cksum_data[8];
948 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
950 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
952 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
958 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
962 ret = arcfour_mic_key(key_value, key_size, key_type,
963 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
971 rc4_state_struct rc4_state;
973 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
974 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
975 crypt_rc4(&rc4_state, (unsigned char *)SND_SEQ, 8);
977 memset(k6_data, 0, sizeof(k6_data));
980 seq_number=g_ntohl(SND_SEQ[0]);
982 if (SND_SEQ[1] != 0xFFFFFFFF && SND_SEQ[1] != 0x00000000) {
989 for (i = 0; i < 16; i++)
990 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
992 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
993 (unsigned char *)SND_SEQ, 4,
995 memset(Klocaldata, 0, sizeof(Klocaldata));
1001 rc4_state_struct rc4_state;
1003 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
1004 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
1005 crypt_rc4(&rc4_state, Confounder, 8);
1006 memcpy(output_message_buffer, input_message_buffer, datalen);
1007 crypt_rc4(&rc4_state, output_message_buffer, datalen);
1010 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
1011 8); /* Confounder */
1012 memcpy(output_message_buffer,
1013 input_message_buffer,
1016 memset(k6_data, 0, sizeof(k6_data));
1018 /* only normal (i.e. non DCE style wrapping use padding ? */
1019 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1020 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
1027 /* dont know what the checksum looks like for dce style gssapi */
1028 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1029 ret = arcfour_mic_cksum(key_value, key_size,
1032 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
1033 Confounder, sizeof(Confounder),
1034 output_message_buffer,
1040 cmp = memcmp(cksum_data,
1041 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
1053 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1056 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
1061 const guint8 *original_data;
1063 static int omb_index=0;
1064 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
1065 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
1066 guint8 *output_message_buffer;
1072 output_message_buffer=omb_arr[omb_index];
1075 length=tvb_length(pinfo->gssapi_encrypted_tvb);
1076 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
1078 /* dont do anything if we are not attempting to decrypt data */
1084 /* XXX we should only do this for first time, then store somewhere */
1085 /* XXX We also need to re-read the keytab when the preference changes */
1087 cryptocopy=ep_alloc(length);
1088 if(output_message_buffer){
1089 g_free(output_message_buffer);
1090 output_message_buffer=NULL;
1092 output_message_buffer=g_malloc(length);
1094 for(ek=enc_key_list;ek;ek=ek->next){
1095 /* shortcircuit and bail out if enctypes are not matching */
1096 if(ek->keytype!=keytype){
1100 /* pre-0.6.1 versions of Heimdal would sometimes change
1101 the cryptotext data even when the decryption failed.
1102 This would obviously not work since we iterate over the
1103 keys. So just give it a copy of the crypto data instead.
1104 This has been seen for RC4-HMAC blobs.
1106 memcpy(cryptocopy, original_data, length);
1107 ret=decrypt_arcfour(pinfo,
1109 output_message_buffer,
1115 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
1116 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
1117 output_message_buffer,
1119 tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
1120 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1127 /* borrowed from heimdal */
1129 rrc_rotate(void *data, int len, guint16 rrc, int unrotate)
1131 unsigned char *tmp, buf[256];
1144 if (rrc <= sizeof(buf)) {
1147 tmp = g_malloc(rrc);
1153 memcpy(tmp, data, rrc);
1154 memmove(data, (unsigned char *)data + rrc, left);
1155 memcpy((unsigned char *)data + left, tmp, rrc);
1157 memcpy(tmp, (unsigned char *)data + left, rrc);
1158 memmove((unsigned char *)data + rrc, data, left);
1159 memcpy(data, tmp, rrc);
1162 if (rrc > sizeof(buf))
1169 #define KRB5_KU_USAGE_ACCEPTOR_SEAL 22
1170 #define KRB5_KU_USAGE_ACCEPTOR_SIGN 23
1171 #define KRB5_KU_USAGE_INITIATOR_SEAL 24
1172 #define KRB5_KU_USAGE_INITIATOR_SIGN 25
1175 decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_,
1177 tvbuff_t *checksum_tvb,
1178 tvbuff_t *encrypted_tvb,
1191 /* dont do anything if we are not attempting to decrypt data */
1196 datalen = tvb_length(checksum_tvb) + tvb_length(encrypted_tvb);
1198 rotated = g_malloc(datalen);
1200 tvb_memcpy(checksum_tvb, rotated,
1201 0, tvb_length(checksum_tvb));
1202 tvb_memcpy(encrypted_tvb, rotated + tvb_length(checksum_tvb),
1203 0, tvb_length(encrypted_tvb));
1209 res = rrc_rotate(rotated, datalen, rrc, TRUE);
1211 next_tvb=tvb_new_child_real_data(encrypted_tvb, rotated,
1213 tvb_set_free_cb(next_tvb, g_free);
1214 add_new_data_source(pinfo, next_tvb, "GSSAPI CFX");
1216 output = decrypt_krb5_data(tree, pinfo, usage, next_tvb,
1222 outdata = g_memdup(output, tvb_length(encrypted_tvb));
1225 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(encrypted_tvb,
1227 tvb_length(encrypted_tvb),
1228 tvb_length(encrypted_tvb));
1229 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1230 tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
1236 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1242 * This is for GSSAPI Wrap tokens ...
1245 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1246 #ifndef HAVE_KERBEROS
1249 , proto_tree *tree, guint16 token_id
1250 #ifndef HAVE_KERBEROS
1255 guint16 sgn_alg, seal_alg;
1256 #ifdef HAVE_KERBEROS
1257 int start_offset=offset;
1261 * The KRB5 blob conforms to RFC1964:
1262 * USHORT (0x0102 == GSS_Wrap)
1266 /* Now, the sign and seal algorithms ... */
1268 sgn_alg = tvb_get_letohs(tvb, offset);
1269 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1274 seal_alg = tvb_get_letohs(tvb, offset);
1275 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
1280 /* Skip the filler */
1284 /* Encrypted sequence number */
1286 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1291 /* Checksum of plaintext padded data */
1293 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1299 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1300 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1301 * extra 8 bytes of "Random confounder" after the checksum.
1302 * It certainly confounds code expecting all Kerberos 5
1303 * GSS_Wrap() tokens to look the same....
1305 if ((sgn_alg == KRB_SGN_ALG_HMAC) ||
1306 /* there also seems to be a confounder for DES MAC MD5 - certainly seen when using with
1307 SASL with LDAP between a Java client and Active Directory. If this breaks other things
1308 we may need to make this an option. gal 17/2/06 */
1309 (sgn_alg == KRB_SGN_ALG_DES_MAC_MD5)) {
1310 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1315 /* Is the data encrypted? */
1316 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
1318 #ifdef HAVE_KERBEROS
1319 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
1320 if(pinfo->decrypt_gssapi_tvb){
1321 /* if the caller did not provide a tvb, then we just use
1322 whatever is left of our current tvb.
1324 if(!pinfo->gssapi_encrypted_tvb){
1326 len=tvb_reported_length_remaining(tvb,offset);
1327 if(len>tvb_length_remaining(tvb, offset)){
1328 /* no point in trying to decrypt,
1329 we dont have the full pdu.
1333 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1334 tvb, offset, len, len);
1337 /* if this is KRB5 wrapped rc4-hmac */
1338 if((token_id==KRB_TOKEN_WRAP)
1339 &&(sgn_alg==KRB_SGN_ALG_HMAC)
1340 &&(seal_alg==KRB_SEAL_ALG_RC4)){
1341 /* do we need to create a tvb for the wrapper
1344 if(!pinfo->gssapi_wrap_tvb){
1345 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1346 tvb, start_offset-2,
1347 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
1348 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
1350 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1351 decrypt_gssapi_krb_arcfour_wrap(tree,
1355 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1360 * Return the offset past the checksum, so that we know where
1361 * the data we're wrapped around starts. Also, set the length
1362 * of our top-level item to that offset, so it doesn't cover
1363 * the data we're wrapped around.
1365 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1372 * XXX - This is for GSSAPI GetMIC tokens ...
1375 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1380 * The KRB5 blob conforms to RFC1964:
1381 * USHORT (0x0101 == GSS_GetMIC)
1385 /* Now, the sign algorithm ... */
1387 sgn_alg = tvb_get_letohs(tvb, offset);
1388 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1393 /* Skip the filler */
1397 /* Encrypted sequence number */
1399 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1404 /* Checksum of plaintext padded data */
1406 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1412 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1413 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1414 * extra 8 bytes of "Random confounder" after the checksum.
1415 * It certainly confounds code expecting all Kerberos 5
1416 * GSS_Wrap() tokens to look the same....
1418 * The exception is DNS/TSIG where there is no such confounder
1419 * so we need to test here if there are more bytes in our tvb or not.
1422 if (tvb_length_remaining(tvb, offset)) {
1423 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1424 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1432 * Return the offset past the checksum, so that we know where
1433 * the data we're wrapped around starts. Also, set the length
1434 * of our top-level item to that offset, so it doesn't cover
1435 * the data we're wrapped around.
1442 dissect_spnego_krb5_cfx_flags(tvbuff_t *tvb, int offset,
1443 proto_tree *spnego_krb5_tree,
1446 proto_tree *cfx_flags_tree = NULL;
1447 proto_item *tf = NULL;
1449 if (spnego_krb5_tree) {
1450 tf = proto_tree_add_uint(spnego_krb5_tree,
1451 hf_spnego_krb5_cfx_flags,
1452 tvb, offset, 1, cfx_flags);
1453 cfx_flags_tree = proto_item_add_subtree(tf, ett_spnego_krb5_cfx_flags);
1456 proto_tree_add_boolean(cfx_flags_tree,
1457 hf_spnego_krb5_cfx_flags_04,
1458 tvb, offset, 1, cfx_flags);
1459 proto_tree_add_boolean(cfx_flags_tree,
1460 hf_spnego_krb5_cfx_flags_02,
1461 tvb, offset, 1, cfx_flags);
1462 proto_tree_add_boolean(cfx_flags_tree,
1463 hf_spnego_krb5_cfx_flags_01,
1464 tvb, offset, 1, cfx_flags);
1466 return (offset + 1);
1470 * This is for GSSAPI CFX Wrap tokens ...
1473 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1474 #ifndef HAVE_KERBEROS
1477 , proto_tree *tree, guint16 token_id _U_
1484 int start_offset=offset;
1487 * The KRB5 blob conforms to RFC4121:
1492 /* Now, the sign and seal algorithms ... */
1494 flags = tvb_get_guint8(tvb, offset);
1495 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1497 pinfo->gssapi_data_encrypted=(flags & 2);
1499 /* Skip the filler */
1501 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 1,
1506 ec = tvb_get_ntohs(tvb, offset);
1507 proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2,
1512 rrc = tvb_get_ntohs(tvb, offset);
1513 proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2,
1517 /* sequence number */
1519 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1523 /* Checksum of plaintext padded data */
1525 if (pinfo->gssapi_data_encrypted) {
1526 checksum_size = 44 + ec;
1531 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1532 checksum_size, FALSE);
1533 offset += checksum_size;
1535 if(pinfo->decrypt_gssapi_tvb){
1536 /* if the caller did not provide a tvb, then we just use
1537 whatever is left of our current tvb.
1539 if(!pinfo->gssapi_encrypted_tvb){
1541 len=tvb_reported_length_remaining(tvb,offset);
1542 if(len>tvb_length_remaining(tvb, offset)){
1543 /* no point in trying to decrypt,
1544 we dont have the full pdu.
1548 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1549 tvb, offset, len, len);
1552 if (pinfo->gssapi_data_encrypted) {
1553 /* do we need to create a tvb for the wrapper
1556 if(!pinfo->gssapi_wrap_tvb){
1557 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1558 tvb, start_offset-2,
1559 offset - (start_offset-2),
1560 offset - (start_offset-2));
1565 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1567 tvbuff_t *checksum_tvb = tvb_new_subset(tvb, 16, checksum_size, checksum_size);
1569 if (pinfo->gssapi_data_encrypted) {
1570 if(pinfo->gssapi_encrypted_tvb){
1571 decrypt_gssapi_krb_cfx_wrap(tree,
1574 pinfo->gssapi_encrypted_tvb,
1577 (pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_DCE)?TRUE:FALSE,
1580 KRB5_KU_USAGE_ACCEPTOR_SEAL:
1581 KRB5_KU_USAGE_INITIATOR_SEAL);
1585 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1588 * Return the offset past the checksum, so that we know where
1589 * the data we're wrapped around starts. Also, set the length
1590 * of our top-level item to that offset, so it doesn't cover
1591 * the data we're wrapped around.
1593 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1600 * XXX - This is for GSSAPI CFX GetMIC tokens ...
1603 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1609 * The KRB5 blob conforms to RFC4121:
1610 * USHORT (0x0404 == GSS_GetMIC)
1614 flags = tvb_get_guint8(tvb, offset);
1615 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1617 /* Skip the filler */
1619 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 5,
1623 /* sequence number */
1625 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1629 /* Checksum of plaintext padded data */
1631 checksum_size = tvb_length_remaining(tvb, offset);
1633 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1634 checksum_size, FALSE);
1635 offset += checksum_size;
1638 * Return the offset past the checksum, so that we know where
1639 * the data we're wrapped around starts. Also, set the length
1640 * of our top-level item to that offset, so it doesn't cover
1641 * the data we're wrapped around.
1648 * XXX - is this for SPNEGO or just GSS-API?
1649 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1650 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1651 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1652 * getting it accepted.
1655 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1658 proto_tree *subtree;
1662 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
1664 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1667 * The KRB5 blob conforms to RFC1964:
1668 * USHORT (0x0102 == GSS_Wrap)
1672 /* First, the token ID ... */
1674 token_id = tvb_get_letohs(tvb, offset);
1675 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1681 case KRB_TOKEN_GETMIC:
1682 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
1685 case KRB_TOKEN_WRAP:
1686 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1689 case KRB_TOKEN_CFX_GETMIC:
1690 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
1693 case KRB_TOKEN_CFX_WRAP:
1694 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
1703 * Return the offset past the checksum, so that we know where
1704 * the data we're wrapped around starts. Also, set the length
1705 * of our top-level item to that offset, so it doesn't cover
1706 * the data we're wrapped around.
1708 proto_item_set_len(item, offset);
1712 /* Spnego stuff from here */
1715 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1718 proto_tree *subtree;
1720 asn1_ctx_t asn1_ctx;
1721 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1723 MechType_oid = NULL;
1726 * We need this later, so lets get it now ...
1727 * It has to be per-frame as there can be more than one GSS-API
1728 * negotiation in a conversation.
1732 item = proto_tree_add_item(tree, proto_spnego, tvb, offset,
1735 subtree = proto_item_add_subtree(item, ett_spnego);
1737 * The TVB contains a [0] header and a sequence that consists of an
1738 * object ID and a blob containing the data ...
1739 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1740 * with the "optional" "use in non-initial tokens" being chosen.
1741 * ASN1 code addet to spnego.asn to handle this.
1744 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, &asn1_ctx , subtree, -1);
1751 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1754 proto_tree *subtree;
1756 conversation_t *conversation;
1757 asn1_ctx_t asn1_ctx;
1758 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1761 * We need this later, so lets get it now ...
1762 * It has to be per-frame as there can be more than one GSS-API
1763 * negotiation in a conversation.
1765 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1766 if (!next_level_value && !pinfo->fd->flags.visited) {
1768 * No handle attached to this frame, but it's the first
1769 * pass, so it'd be attached to the conversation.
1770 * If we have a conversation, try to get the handle,
1771 * and if we get one, attach it to the frame.
1773 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1774 pinfo->ptype, pinfo->srcport,
1775 pinfo->destport, 0);
1778 next_level_value = conversation_get_proto_data(conversation,
1780 if (next_level_value)
1781 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1785 item = proto_tree_add_item(parent_tree, proto_spnego, tvb, offset,
1788 subtree = proto_item_add_subtree(item, ett_spnego);
1791 * The TVB contains a [0] header and a sequence that consists of an
1792 * object ID and a blob containing the data ...
1793 * Actually, it contains, according to RFC2478:
1794 * NegotiationToken ::= CHOICE {
1795 * negTokenInit [0] NegTokenInit,
1796 * negTokenTarg [1] NegTokenTarg }
1797 * NegTokenInit ::= SEQUENCE {
1798 * mechTypes [0] MechTypeList OPTIONAL,
1799 * reqFlags [1] ContextFlags OPTIONAL,
1800 * mechToken [2] OCTET STRING OPTIONAL,
1801 * mechListMIC [3] OCTET STRING OPTIONAL }
1802 * NegTokenTarg ::= SEQUENCE {
1803 * negResult [0] ENUMERATED {
1804 * accept_completed (0),
1805 * accept_incomplete (1),
1806 * reject (2) } OPTIONAL,
1807 * supportedMech [1] MechType OPTIONAL,
1808 * responseToken [2] OCTET STRING OPTIONAL,
1809 * mechListMIC [3] OCTET STRING OPTIONAL }
1811 * Windows typically includes mechTypes and mechListMic ('NONE'
1812 * in the case of NTLMSSP only).
1813 * It seems to duplicate the responseToken into the mechListMic field
1814 * as well. Naughty, naughty.
1817 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
1821 /*--- proto_register_spnego -------------------------------------------*/
1822 void proto_register_spnego(void) {
1824 /* List of fields */
1825 static hf_register_info hf[] = {
1826 { &hf_spnego_wraptoken,
1827 { "wrapToken", "spnego.wraptoken",
1828 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1831 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1832 BASE_NONE, NULL, 0, NULL, HFILL }},
1833 { &hf_spnego_krb5_oid,
1834 { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
1835 BASE_NONE, NULL, 0, NULL, HFILL }},
1836 { &hf_spnego_krb5_tok_id,
1837 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1838 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1839 { &hf_spnego_krb5_sgn_alg,
1840 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1841 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1842 { &hf_spnego_krb5_seal_alg,
1843 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1844 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1845 { &hf_spnego_krb5_snd_seq,
1846 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1847 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1848 { &hf_spnego_krb5_sgn_cksum,
1849 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1850 NULL, 0, "KRB5 Data Checksum", HFILL}},
1851 { &hf_spnego_krb5_confounder,
1852 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1853 NULL, 0, "KRB5 Confounder", HFILL}},
1854 { &hf_spnego_krb5_filler,
1855 { "krb5_filler", "spnego.krb5.filler", FT_BYTES, BASE_NONE,
1856 NULL, 0, "KRB5 Filler", HFILL}},
1857 { &hf_spnego_krb5_cfx_flags,
1858 { "krb5_cfx_flags", "spnego.krb5.cfx_flags", FT_UINT8, BASE_HEX,
1859 NULL, 0, "KRB5 CFX Flags", HFILL}},
1860 { &hf_spnego_krb5_cfx_flags_01,
1861 { "SendByAcceptor", "spnego.krb5.send_by_acceptor", FT_BOOLEAN, 8,
1862 TFS (&tfs_set_notset), 0x01, NULL, HFILL}},
1863 { &hf_spnego_krb5_cfx_flags_02,
1864 { "Sealed", "spnego.krb5.sealed", FT_BOOLEAN, 8,
1865 TFS (&tfs_set_notset), 0x02, NULL, HFILL}},
1866 { &hf_spnego_krb5_cfx_flags_04,
1867 { "AcceptorSubkey", "spnego.krb5.acceptor_subkey", FT_BOOLEAN, 8,
1868 TFS (&tfs_set_notset), 0x04, NULL, HFILL}},
1869 { &hf_spnego_krb5_cfx_ec,
1870 { "krb5_cfx_ec", "spnego.krb5.cfx_ec", FT_UINT16, BASE_DEC,
1871 NULL, 0, "KRB5 CFX Extra Count", HFILL}},
1872 { &hf_spnego_krb5_cfx_rrc,
1873 { "krb5_cfx_rrc", "spnego.krb5.cfx_rrc", FT_UINT16, BASE_DEC,
1874 NULL, 0, "KRB5 CFX Right Rotation Count", HFILL}},
1875 { &hf_spnego_krb5_cfx_seq,
1876 { "krb5_cfx_seq", "spnego.krb5.cfx_seq", FT_UINT64, BASE_DEC,
1877 NULL, 0, "KRB5 Sequence Number", HFILL}},
1880 /*--- Included file: packet-spnego-hfarr.c ---*/
1881 #line 1 "packet-spnego-hfarr.c"
1882 { &hf_spnego_negTokenInit,
1883 { "negTokenInit", "spnego.negTokenInit",
1884 FT_NONE, BASE_NONE, NULL, 0,
1886 { &hf_spnego_negTokenTarg,
1887 { "negTokenTarg", "spnego.negTokenTarg",
1888 FT_NONE, BASE_NONE, NULL, 0,
1890 { &hf_spnego_MechTypeList_item,
1891 { "MechType", "spnego.MechType",
1892 FT_OID, BASE_NONE, NULL, 0,
1894 { &hf_spnego_principal,
1895 { "principal", "spnego.principal",
1896 FT_STRING, BASE_NONE, NULL, 0,
1897 "GeneralString", HFILL }},
1898 { &hf_spnego_mechTypes,
1899 { "mechTypes", "spnego.mechTypes",
1900 FT_UINT32, BASE_DEC, NULL, 0,
1901 "MechTypeList", HFILL }},
1902 { &hf_spnego_reqFlags,
1903 { "reqFlags", "spnego.reqFlags",
1904 FT_BYTES, BASE_NONE, NULL, 0,
1905 "ContextFlags", HFILL }},
1906 { &hf_spnego_mechToken,
1907 { "mechToken", "spnego.mechToken",
1908 FT_BYTES, BASE_NONE, NULL, 0,
1910 { &hf_spnego_negTokenInit_mechListMIC,
1911 { "mechListMIC", "spnego.mechListMIC",
1912 FT_BYTES, BASE_NONE, NULL, 0,
1913 "T_NegTokenInit_mechListMIC", HFILL }},
1914 { &hf_spnego_negResult,
1915 { "negResult", "spnego.negResult",
1916 FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
1918 { &hf_spnego_supportedMech,
1919 { "supportedMech", "spnego.supportedMech",
1920 FT_OID, BASE_NONE, NULL, 0,
1922 { &hf_spnego_responseToken,
1923 { "responseToken", "spnego.responseToken",
1924 FT_BYTES, BASE_NONE, NULL, 0,
1926 { &hf_spnego_mechListMIC,
1927 { "mechListMIC", "spnego.mechListMIC",
1928 FT_BYTES, BASE_NONE, NULL, 0,
1930 { &hf_spnego_thisMech,
1931 { "thisMech", "spnego.thisMech",
1932 FT_OID, BASE_NONE, NULL, 0,
1933 "MechType", HFILL }},
1934 { &hf_spnego_innerContextToken,
1935 { "innerContextToken", "spnego.innerContextToken",
1936 FT_NONE, BASE_NONE, NULL, 0,
1938 { &hf_spnego_ContextFlags_delegFlag,
1939 { "delegFlag", "spnego.delegFlag",
1940 FT_BOOLEAN, 8, NULL, 0x80,
1942 { &hf_spnego_ContextFlags_mutualFlag,
1943 { "mutualFlag", "spnego.mutualFlag",
1944 FT_BOOLEAN, 8, NULL, 0x40,
1946 { &hf_spnego_ContextFlags_replayFlag,
1947 { "replayFlag", "spnego.replayFlag",
1948 FT_BOOLEAN, 8, NULL, 0x20,
1950 { &hf_spnego_ContextFlags_sequenceFlag,
1951 { "sequenceFlag", "spnego.sequenceFlag",
1952 FT_BOOLEAN, 8, NULL, 0x10,
1954 { &hf_spnego_ContextFlags_anonFlag,
1955 { "anonFlag", "spnego.anonFlag",
1956 FT_BOOLEAN, 8, NULL, 0x08,
1958 { &hf_spnego_ContextFlags_confFlag,
1959 { "confFlag", "spnego.confFlag",
1960 FT_BOOLEAN, 8, NULL, 0x04,
1962 { &hf_spnego_ContextFlags_integFlag,
1963 { "integFlag", "spnego.integFlag",
1964 FT_BOOLEAN, 8, NULL, 0x02,
1967 /*--- End of included file: packet-spnego-hfarr.c ---*/
1968 #line 1399 "packet-spnego-template.c"
1971 /* List of subtrees */
1972 static gint *ett[] = {
1974 &ett_spnego_wraptoken,
1976 &ett_spnego_krb5_cfx_flags,
1979 /*--- Included file: packet-spnego-ettarr.c ---*/
1980 #line 1 "packet-spnego-ettarr.c"
1981 &ett_spnego_NegotiationToken,
1982 &ett_spnego_MechTypeList,
1983 &ett_spnego_PrincipalSeq,
1984 &ett_spnego_NegTokenInit,
1985 &ett_spnego_ContextFlags,
1986 &ett_spnego_NegTokenTarg,
1987 &ett_spnego_InitialContextToken_U,
1989 /*--- End of included file: packet-spnego-ettarr.c ---*/
1990 #line 1409 "packet-spnego-template.c"
1993 /* Register protocol */
1994 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1996 register_dissector("spnego", dissect_spnego, proto_spnego);
1998 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
2002 register_dissector("spnego-krb5", dissect_spnego_krb5, proto_spnego_krb5);
2003 new_register_dissector("spnego-krb5-wrap", dissect_spnego_krb5_wrap, proto_spnego_krb5);
2005 /* Register fields and subtrees */
2006 proto_register_field_array(proto_spnego, hf, array_length(hf));
2007 proto_register_subtree_array(ett, array_length(ett));
2011 /*--- proto_reg_handoff_spnego ---------------------------------------*/
2012 void proto_reg_handoff_spnego(void) {
2014 dissector_handle_t spnego_handle, spnego_wrap_handle;
2015 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
2017 /* Register protocol with GSS-API module */
2019 spnego_handle = find_dissector("spnego");
2020 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap, proto_spnego);
2021 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
2022 spnego_handle, spnego_wrap_handle,
2023 "SPNEGO - Simple Protected Negotiation");
2025 /* Register both the one MS created and the real one */
2027 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
2028 * mystery of the MS KRB5 OID is cleared up. It was due to a library
2029 * that did not handle OID components greater than 16 bits, and was
2030 * fixed in Win2K SP2 as well as WinXP.
2031 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
2032 * SPNEGO implementation issues. 3-Dec-2002.
2034 spnego_krb5_handle = find_dissector("spnego-krb5");
2035 spnego_krb5_wrap_handle = find_dissector("spnego-krb5-wrap");
2036 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2037 spnego_krb5_handle, spnego_krb5_wrap_handle,
2038 "MS KRB5 - Microsoft Kerberos 5");
2039 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2040 spnego_krb5_handle, spnego_krb5_wrap_handle,
2041 "KRB5 - Kerberos 5");
2042 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
2043 spnego_krb5_handle, spnego_krb5_wrap_handle,
2044 "KRB5 - Kerberos 5 - User to User");