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_conversation(actx->pinfo->fd->num,
214 &actx->pinfo->src, &actx->pinfo->dst,
216 actx->pinfo->srcport, actx->pinfo->destport, 0);
218 conversation = conversation_new(actx->pinfo->fd->num,
219 &actx->pinfo->src, &actx->pinfo->dst,
221 actx->pinfo->srcport, actx->pinfo->destport, 0);
223 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
232 static const asn_namedbit ContextFlags_bits[] = {
233 { 0, &hf_spnego_ContextFlags_delegFlag, -1, -1, "delegFlag", NULL },
234 { 1, &hf_spnego_ContextFlags_mutualFlag, -1, -1, "mutualFlag", NULL },
235 { 2, &hf_spnego_ContextFlags_replayFlag, -1, -1, "replayFlag", NULL },
236 { 3, &hf_spnego_ContextFlags_sequenceFlag, -1, -1, "sequenceFlag", NULL },
237 { 4, &hf_spnego_ContextFlags_anonFlag, -1, -1, "anonFlag", NULL },
238 { 5, &hf_spnego_ContextFlags_confFlag, -1, -1, "confFlag", NULL },
239 { 6, &hf_spnego_ContextFlags_integFlag, -1, -1, "integFlag", NULL },
240 { 0, NULL, 0, 0, NULL, NULL }
244 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_) {
245 offset = dissect_ber_bitstring(implicit_tag, actx, tree, tvb, offset,
246 ContextFlags_bits, hf_index, ett_spnego_ContextFlags,
255 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_) {
256 #line 121 "spnego.cnf"
258 tvbuff_t *mechToken_tvb = NULL;
260 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
265 * Now, we should be able to dispatch, if we've gotten a tvbuff for
266 * the token and we have information on how to dissect its contents.
268 if (mechToken_tvb && next_level_value)
269 call_dissector(next_level_value->handle, mechToken_tvb, actx->pinfo, tree);
280 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_) {
281 #line 135 "spnego.cnf"
286 tvbuff_t *mechListMIC_tvb;
289 * There seems to be two different forms this can take,
290 * one as an octet string, and one as a general string in a
293 * Peek at the header, and then decide which it is we're seeing.
295 get_ber_identifier(tvb, offset, &class, &pc, &tag);
296 if (class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE) {
300 return dissect_spnego_PrincipalSeq(FALSE, tvb, offset, actx, tree,
301 hf_spnego_mechListMIC);
304 * It's not a sequence, so dissect it as an octet string,
305 * which is what it's supposed to be; that'll cause the
306 * right error report if it's not an octet string, either.
308 offset = dissect_ber_octet_string(FALSE, actx, tree, tvb, offset,
309 hf_spnego_mechListMIC, &mechListMIC_tvb);
312 * Now, we should be able to dispatch with that tvbuff.
314 if (mechListMIC_tvb && next_level_value)
315 call_dissector(next_level_value->handle, mechListMIC_tvb, actx->pinfo, tree);
325 static const ber_sequence_t NegTokenInit_sequence[] = {
326 { &hf_spnego_mechTypes , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_MechTypeList },
327 { &hf_spnego_reqFlags , BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_ContextFlags },
328 { &hf_spnego_mechToken , BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechToken },
329 { &hf_spnego_negTokenInit_mechListMIC, BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_NegTokenInit_mechListMIC },
330 { NULL, 0, 0, 0, NULL }
334 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_) {
335 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
336 NegTokenInit_sequence, hf_index, ett_spnego_NegTokenInit);
342 static const value_string spnego_T_negResult_vals[] = {
343 { 0, "accept-completed" },
344 { 1, "accept-incomplete" },
351 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_) {
352 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
361 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_) {
362 #line 173 "spnego.cnf"
364 conversation_t *conversation;
366 saw_mechanism = FALSE;
368 offset = dissect_spnego_MechType(implicit_tag, tvb, offset, actx, tree, hf_index);
372 * If we saw an explicit mechType we store this in the conversation so that
373 * it will override any mechType we might have picked up from the
377 conversation = find_conversation(actx->pinfo->fd->num,
378 &actx->pinfo->src, &actx->pinfo->dst,
380 actx->pinfo->srcport, actx->pinfo->destport, 0);
382 conversation = conversation_new(actx->pinfo->fd->num,
383 &actx->pinfo->src, &actx->pinfo->dst,
385 actx->pinfo->srcport, actx->pinfo->destport, 0);
387 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
399 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_) {
400 #line 205 "spnego.cnf"
402 tvbuff_t *responseToken_tvb;
405 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
411 * Now, we should be able to dispatch, if we've gotten a tvbuff for
412 * the token and we have information on how to dissect its contents.
413 * However, we should make sure that there is something in the
416 if (responseToken_tvb && (tvb_reported_length(responseToken_tvb) > 0) ){
417 gssapi_oid_value *value=next_level_value;
420 call_dissector(value->handle, responseToken_tvb, actx->pinfo, tree);
433 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_) {
434 #line 232 "spnego.cnf"
436 tvbuff_t *mechListMIC_tvb;
439 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
445 * Now, we should be able to dispatch, if we've gotten a tvbuff for
446 * the MIC and we have information on how to dissect its contents.
448 if (mechListMIC_tvb && (tvb_reported_length(mechListMIC_tvb) > 0) ){
449 gssapi_oid_value *value=next_level_value;
452 call_dissector(value->handle, mechListMIC_tvb, actx->pinfo, tree);
463 static const ber_sequence_t NegTokenTarg_sequence[] = {
464 { &hf_spnego_negResult , BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_spnego_T_negResult },
465 { &hf_spnego_supportedMech, BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_spnego_T_supportedMech },
466 { &hf_spnego_responseToken, BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_spnego_T_responseToken },
467 { &hf_spnego_mechListMIC , BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_spnego_T_mechListMIC },
468 { NULL, 0, 0, 0, NULL }
472 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_) {
473 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
474 NegTokenTarg_sequence, hf_index, ett_spnego_NegTokenTarg);
480 static const value_string spnego_NegotiationToken_vals[] = {
481 { 0, "negTokenInit" },
482 { 1, "negTokenTarg" },
486 static const ber_choice_t NegotiationToken_choice[] = {
487 { 0, &hf_spnego_negTokenInit , BER_CLASS_CON, 0, 0, dissect_spnego_NegTokenInit },
488 { 1, &hf_spnego_negTokenTarg , BER_CLASS_CON, 1, 0, dissect_spnego_NegTokenTarg },
489 { 0, NULL, 0, 0, 0, NULL }
493 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_) {
494 offset = dissect_ber_choice(actx, tree, tvb, offset,
495 NegotiationToken_choice, hf_index, ett_spnego_NegotiationToken,
504 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_) {
505 offset = dissect_ber_restricted_string(implicit_tag, BER_UNI_TAG_GeneralString,
506 actx, tree, tvb, offset, hf_index,
513 static const ber_sequence_t PrincipalSeq_sequence[] = {
514 { &hf_spnego_principal , BER_CLASS_CON, 0, 0, dissect_spnego_GeneralString },
515 { NULL, 0, 0, 0, NULL }
519 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_) {
520 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
521 PrincipalSeq_sequence, hf_index, ett_spnego_PrincipalSeq);
529 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_) {
530 #line 48 "spnego.cnf"
532 gssapi_oid_value *next_level_value_lcl;
539 * XXX - what should we do if this OID doesn't match the value
540 * attached to the frame or conversation? (That would be
541 * bogus, but that's not impossible - some broken implementation
542 * might negotiate some security mechanism but put the OID
543 * for some other security mechanism in GSS_Wrap tokens.)
546 next_level_value_lcl = gssapi_lookup_oid_str(MechType_oid);
549 * Now dissect the GSS_Wrap token; it's assumed to be in the
550 * rest of the tvbuff.
552 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset, -1, FALSE);
554 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
557 * Now, we should be able to dispatch after creating a new TVB.
558 * The subdissector must return the length of the part of the
559 * token it dissected, so we can return the length of the part
560 * we (and it) dissected.
562 token_tvb = tvb_new_subset_remaining(tvb, offset);
563 if (next_level_value_lcl && next_level_value_lcl->wrap_handle) {
564 len = call_dissector(next_level_value_lcl->wrap_handle, token_tvb, actx->pinfo,
567 offset = tvb_length(tvb);
569 offset = offset + len;
571 offset = tvb_length(tvb);
579 static const ber_sequence_t InitialContextToken_U_sequence[] = {
580 { &hf_spnego_thisMech , BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_spnego_MechType },
581 { &hf_spnego_innerContextToken, BER_CLASS_ANY, 0, BER_FLAGS_NOOWNTAG, dissect_spnego_InnerContextToken },
582 { NULL, 0, 0, 0, NULL }
586 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_) {
587 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
588 InitialContextToken_U_sequence, hf_index, ett_spnego_InitialContextToken_U);
596 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_) {
597 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
598 hf_index, BER_CLASS_APP, 0, TRUE, dissect_spnego_InitialContextToken_U);
604 /*--- End of included file: packet-spnego-fn.c ---*/
605 #line 107 "packet-spnego-template.c"
607 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
608 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
609 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
612 #define KRB_TOKEN_AP_REQ 0x0001
613 #define KRB_TOKEN_AP_REP 0x0002
614 #define KRB_TOKEN_AP_ERR 0x0003
615 #define KRB_TOKEN_GETMIC 0x0101
616 #define KRB_TOKEN_WRAP 0x0102
617 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
618 #define KRB_TOKEN_CFX_GETMIC 0x0404
619 #define KRB_TOKEN_CFX_WRAP 0x0405
621 static const value_string spnego_krb5_tok_id_vals[] = {
622 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
623 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
624 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
625 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
626 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
627 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
628 { KRB_TOKEN_CFX_GETMIC, "KRB_TOKEN_CFX_GetMic" },
629 { KRB_TOKEN_CFX_WRAP, "KRB_TOKEN_CFX_WRAP" },
633 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
634 #define KRB_SGN_ALG_MD2_5 0x0001
635 #define KRB_SGN_ALG_DES_MAC 0x0002
636 #define KRB_SGN_ALG_HMAC 0x0011
638 static const value_string spnego_krb5_sgn_alg_vals[] = {
639 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
640 { KRB_SGN_ALG_MD2_5, "MD2.5"},
641 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
642 { KRB_SGN_ALG_HMAC, "HMAC"},
646 #define KRB_SEAL_ALG_DES_CBC 0x0000
647 #define KRB_SEAL_ALG_RC4 0x0010
648 #define KRB_SEAL_ALG_NONE 0xffff
650 static const value_string spnego_krb5_seal_alg_vals[] = {
651 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
652 { KRB_SEAL_ALG_RC4, "RC4"},
653 { KRB_SEAL_ALG_NONE, "None"},
658 * XXX - is this for SPNEGO or just GSS-API?
659 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
660 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
661 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
662 * getting it accepted.
665 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
667 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
669 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
671 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
674 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
681 gssapi_oid_value *value;
684 gboolean pc, ind = 0;
688 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
690 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
693 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
696 * The KRB5 blob conforms to RFC1964:
699 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
702 * However, for some protocols, the KRB5 blob starts at the SHORT
703 * and has no DER encoded header etc.
705 * It appears that for some other protocols the KRB5 blob is just
706 * a Kerberos message, with no [APPLICATION 0] header, no OID,
711 * If we see an [APPLICATION 0] HEADER, we show the OID and
712 * the USHORT, and then dissect the rest as a Kerberos message.
714 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
715 * we assume it's an AP-REQ or AP-REP message, and dissect
716 * it all as a Kerberos message.
718 * Otherwise, we show the USHORT, and then dissect the rest
719 * as a Kerberos message.
723 * Get the first header ...
725 get_ber_identifier(tvb, offset, &class, &pc, &tag);
726 if (class == BER_CLASS_APP && pc) {
728 * [APPLICATION <tag>]
730 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
731 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
741 offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
743 value = gssapi_lookup_oid_str(oid);
745 token_id = tvb_get_letohs(tvb, offset);
746 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
753 case 14: /* [APPLICATION 14] */
754 case 15: /* [APPLICATION 15] */
756 * No token ID - just dissect as a Kerberos message and
759 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
763 proto_tree_add_text(subtree, tvb, offset, 0,
764 "Unknown header (class=%d, pc=%d, tag=%d)",
769 /* Next, the token ID ... */
771 token_id = tvb_get_letohs(tvb, offset);
772 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
780 case KRB_TOKEN_AP_REQ:
781 case KRB_TOKEN_AP_REP:
782 case KRB_TOKEN_AP_ERR:
783 krb5_tvb = tvb_new_subset_remaining(tvb, offset);
784 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
787 case KRB_TOKEN_GETMIC:
788 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
792 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
795 case KRB_TOKEN_DELETE_SEC_CONTEXT:
799 case KRB_TOKEN_CFX_GETMIC:
800 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
803 case KRB_TOKEN_CFX_WRAP:
804 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
813 proto_item_set_len(item, offset);
818 #include <epan/crypt/crypt-md5.h>
820 #ifndef KEYTYPE_ARCFOUR_56
821 # define KEYTYPE_ARCFOUR_56 24
823 /* XXX - We should probably do a configure-time check for this instead */
824 #ifndef KRB5_KU_USAGE_SEAL
825 # define KRB5_KU_USAGE_SEAL 22
829 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
830 void *cksum_data, size_t cksum_size,
838 if (key_type == KEYTYPE_ARCFOUR_56) {
839 guint8 L40[14] = "fortybits";
841 memcpy(L40 + 10, T, sizeof(T));
847 memset(&k5_data[7], 0xAB, 9);
857 cksum_data, cksum_size,
866 usage2arcfour(int usage)
869 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
870 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
872 case 22: /*KRB5_KU_USAGE_SEAL 22 */
874 case 23: /*KRB5_KU_USAGE_SIGN 23 */
876 case 24: /*KRB5_KU_USAGE_SEQ 24 */
884 arcfour_mic_cksum(guint8 *key_data, int key_length,
887 const void *v1, size_t l1,
888 const void *v2, size_t l2,
889 const void *v3, size_t l3)
891 const guint8 signature[] = "signaturekey";
895 unsigned char digest[16];
899 rc4_usage=usage2arcfour(usage);
900 md5_hmac(signature, sizeof(signature),
901 key_data, key_length,
904 t[0] = (rc4_usage >> 0) & 0xFF;
905 t[1] = (rc4_usage >> 8) & 0xFF;
906 t[2] = (rc4_usage >> 16) & 0xFF;
907 t[3] = (rc4_usage >> 24) & 0xFF;
908 md5_append(&ms, t, 4);
909 md5_append(&ms, v1, l1);
910 md5_append(&ms, v2, l2);
911 md5_append(&ms, v3, l3);
912 md5_finish(&ms, digest);
913 md5_hmac(digest, 16, ksign_c, 16, cksum);
915 memcpy(sgn_cksum, cksum, 8);
921 * Verify padding of a gss wrapped message and return its length.
924 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
932 pad = wrapped_data + wrapped_length - 1;
935 if (padlength > datalen)
938 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
949 decrypt_arcfour(packet_info *pinfo,
950 guint8 *input_message_buffer,
951 guint8 *output_message_buffer,
952 guint8 *key_value, int key_size, int key_type)
954 guint8 Klocaldata[16];
960 guint8 Confounder[8];
961 guint8 cksum_data[8];
966 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
968 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
970 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
976 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
980 ret = arcfour_mic_key(key_value, key_size, key_type,
981 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
989 rc4_state_struct rc4_state;
991 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
992 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
993 crypt_rc4(&rc4_state, (unsigned char *)SND_SEQ, 8);
995 memset(k6_data, 0, sizeof(k6_data));
998 seq_number=g_ntohl(SND_SEQ[0]);
1000 if (SND_SEQ[1] != 0xFFFFFFFF && SND_SEQ[1] != 0x00000000) {
1007 for (i = 0; i < 16; i++)
1008 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
1010 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
1011 (unsigned char *)SND_SEQ, 4,
1013 memset(Klocaldata, 0, sizeof(Klocaldata));
1019 rc4_state_struct rc4_state;
1021 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
1022 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
1023 crypt_rc4(&rc4_state, Confounder, 8);
1024 memcpy(output_message_buffer, input_message_buffer, datalen);
1025 crypt_rc4(&rc4_state, output_message_buffer, datalen);
1028 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
1029 8); /* Confounder */
1030 memcpy(output_message_buffer,
1031 input_message_buffer,
1034 memset(k6_data, 0, sizeof(k6_data));
1036 /* only normal (i.e. non DCE style wrapping use padding ? */
1037 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1038 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
1045 /* dont know what the checksum looks like for dce style gssapi */
1046 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
1047 ret = arcfour_mic_cksum(key_value, key_size,
1050 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
1051 Confounder, sizeof(Confounder),
1052 output_message_buffer,
1058 cmp = memcmp(cksum_data,
1059 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
1071 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1074 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
1079 const guint8 *original_data;
1081 static int omb_index=0;
1082 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
1083 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
1084 guint8 *output_message_buffer;
1090 output_message_buffer=omb_arr[omb_index];
1093 length=tvb_length(pinfo->gssapi_encrypted_tvb);
1094 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
1096 /* dont do anything if we are not attempting to decrypt data */
1102 /* XXX we should only do this for first time, then store somewhere */
1103 /* XXX We also need to re-read the keytab when the preference changes */
1105 cryptocopy=ep_alloc(length);
1106 if(output_message_buffer){
1107 g_free(output_message_buffer);
1108 output_message_buffer=NULL;
1110 output_message_buffer=g_malloc(length);
1112 for(ek=enc_key_list;ek;ek=ek->next){
1113 /* shortcircuit and bail out if enctypes are not matching */
1114 if(ek->keytype!=keytype){
1118 /* pre-0.6.1 versions of Heimdal would sometimes change
1119 the cryptotext data even when the decryption failed.
1120 This would obviously not work since we iterate over the
1121 keys. So just give it a copy of the crypto data instead.
1122 This has been seen for RC4-HMAC blobs.
1124 memcpy(cryptocopy, original_data, length);
1125 ret=decrypt_arcfour(pinfo,
1127 output_message_buffer,
1133 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
1134 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
1135 output_message_buffer,
1137 tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
1138 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1145 /* borrowed from heimdal */
1147 rrc_rotate(void *data, int len, guint16 rrc, int unrotate)
1149 unsigned char *tmp, buf[256];
1162 if (rrc <= sizeof(buf)) {
1165 tmp = g_malloc(rrc);
1171 memcpy(tmp, data, rrc);
1172 memmove(data, (unsigned char *)data + rrc, left);
1173 memcpy((unsigned char *)data + left, tmp, rrc);
1175 memcpy(tmp, (unsigned char *)data + left, rrc);
1176 memmove((unsigned char *)data + rrc, data, left);
1177 memcpy(data, tmp, rrc);
1180 if (rrc > sizeof(buf))
1187 #define KRB5_KU_USAGE_ACCEPTOR_SEAL 22
1188 #define KRB5_KU_USAGE_ACCEPTOR_SIGN 23
1189 #define KRB5_KU_USAGE_INITIATOR_SEAL 24
1190 #define KRB5_KU_USAGE_INITIATOR_SIGN 25
1193 decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_,
1195 tvbuff_t *checksum_tvb,
1196 tvbuff_t *encrypted_tvb,
1209 /* dont do anything if we are not attempting to decrypt data */
1214 datalen = tvb_length(checksum_tvb) + tvb_length(encrypted_tvb);
1216 rotated = g_malloc(datalen);
1218 tvb_memcpy(checksum_tvb, rotated,
1219 0, tvb_length(checksum_tvb));
1220 tvb_memcpy(encrypted_tvb, rotated + tvb_length(checksum_tvb),
1221 0, tvb_length(encrypted_tvb));
1227 res = rrc_rotate(rotated, datalen, rrc, TRUE);
1229 next_tvb=tvb_new_child_real_data(encrypted_tvb, rotated,
1231 tvb_set_free_cb(next_tvb, g_free);
1232 add_new_data_source(pinfo, next_tvb, "GSSAPI CFX");
1234 output = decrypt_krb5_data(tree, pinfo, usage, next_tvb,
1240 outdata = g_memdup(output, tvb_length(encrypted_tvb));
1243 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(encrypted_tvb,
1245 tvb_length(encrypted_tvb),
1246 tvb_length(encrypted_tvb));
1247 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
1248 tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
1254 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1260 * This is for GSSAPI Wrap tokens ...
1263 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1264 #ifndef HAVE_KERBEROS
1267 , proto_tree *tree, guint16 token_id
1268 #ifndef HAVE_KERBEROS
1273 guint16 sgn_alg, seal_alg;
1274 #ifdef HAVE_KERBEROS
1275 int start_offset=offset;
1279 * The KRB5 blob conforms to RFC1964:
1280 * USHORT (0x0102 == GSS_Wrap)
1284 /* Now, the sign and seal algorithms ... */
1286 sgn_alg = tvb_get_letohs(tvb, offset);
1287 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1292 seal_alg = tvb_get_letohs(tvb, offset);
1293 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
1298 /* Skip the filler */
1302 /* Encrypted sequence number */
1304 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1309 /* Checksum of plaintext padded data */
1311 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1317 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1318 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1319 * extra 8 bytes of "Random confounder" after the checksum.
1320 * It certainly confounds code expecting all Kerberos 5
1321 * GSS_Wrap() tokens to look the same....
1323 if ((sgn_alg == KRB_SGN_ALG_HMAC) ||
1324 /* there also seems to be a confounder for DES MAC MD5 - certainly seen when using with
1325 SASL with LDAP between a Java client and Active Directory. If this breaks other things
1326 we may need to make this an option. gal 17/2/06 */
1327 (sgn_alg == KRB_SGN_ALG_DES_MAC_MD5)) {
1328 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1333 /* Is the data encrypted? */
1334 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
1336 #ifdef HAVE_KERBEROS
1337 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
1338 if(pinfo->decrypt_gssapi_tvb){
1339 /* if the caller did not provide a tvb, then we just use
1340 whatever is left of our current tvb.
1342 if(!pinfo->gssapi_encrypted_tvb){
1344 len=tvb_reported_length_remaining(tvb,offset);
1345 if(len>tvb_length_remaining(tvb, offset)){
1346 /* no point in trying to decrypt,
1347 we dont have the full pdu.
1351 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1352 tvb, offset, len, len);
1355 /* if this is KRB5 wrapped rc4-hmac */
1356 if((token_id==KRB_TOKEN_WRAP)
1357 &&(sgn_alg==KRB_SGN_ALG_HMAC)
1358 &&(seal_alg==KRB_SEAL_ALG_RC4)){
1359 /* do we need to create a tvb for the wrapper
1362 if(!pinfo->gssapi_wrap_tvb){
1363 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1364 tvb, start_offset-2,
1365 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
1366 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
1368 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1369 decrypt_gssapi_krb_arcfour_wrap(tree,
1373 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1378 * Return the offset past the checksum, so that we know where
1379 * the data we're wrapped around starts. Also, set the length
1380 * of our top-level item to that offset, so it doesn't cover
1381 * the data we're wrapped around.
1383 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1390 * XXX - This is for GSSAPI GetMIC tokens ...
1393 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1398 * The KRB5 blob conforms to RFC1964:
1399 * USHORT (0x0101 == GSS_GetMIC)
1403 /* Now, the sign algorithm ... */
1405 sgn_alg = tvb_get_letohs(tvb, offset);
1406 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1411 /* Skip the filler */
1415 /* Encrypted sequence number */
1417 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1422 /* Checksum of plaintext padded data */
1424 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1430 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1431 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1432 * extra 8 bytes of "Random confounder" after the checksum.
1433 * It certainly confounds code expecting all Kerberos 5
1434 * GSS_Wrap() tokens to look the same....
1436 * The exception is DNS/TSIG where there is no such confounder
1437 * so we need to test here if there are more bytes in our tvb or not.
1440 if (tvb_length_remaining(tvb, offset)) {
1441 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1442 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1450 * Return the offset past the checksum, so that we know where
1451 * the data we're wrapped around starts. Also, set the length
1452 * of our top-level item to that offset, so it doesn't cover
1453 * the data we're wrapped around.
1460 dissect_spnego_krb5_cfx_flags(tvbuff_t *tvb, int offset,
1461 proto_tree *spnego_krb5_tree,
1464 proto_tree *cfx_flags_tree = NULL;
1465 proto_item *tf = NULL;
1467 if (spnego_krb5_tree) {
1468 tf = proto_tree_add_uint(spnego_krb5_tree,
1469 hf_spnego_krb5_cfx_flags,
1470 tvb, offset, 1, cfx_flags);
1471 cfx_flags_tree = proto_item_add_subtree(tf, ett_spnego_krb5_cfx_flags);
1474 proto_tree_add_boolean(cfx_flags_tree,
1475 hf_spnego_krb5_cfx_flags_04,
1476 tvb, offset, 1, cfx_flags);
1477 proto_tree_add_boolean(cfx_flags_tree,
1478 hf_spnego_krb5_cfx_flags_02,
1479 tvb, offset, 1, cfx_flags);
1480 proto_tree_add_boolean(cfx_flags_tree,
1481 hf_spnego_krb5_cfx_flags_01,
1482 tvb, offset, 1, cfx_flags);
1484 return (offset + 1);
1488 * This is for GSSAPI CFX Wrap tokens ...
1491 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
1492 #ifndef HAVE_KERBEROS
1495 , proto_tree *tree, guint16 token_id _U_
1502 int start_offset=offset;
1505 * The KRB5 blob conforms to RFC4121:
1510 /* Now, the sign and seal algorithms ... */
1512 flags = tvb_get_guint8(tvb, offset);
1513 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1515 pinfo->gssapi_data_encrypted=(flags & 2);
1517 /* Skip the filler */
1519 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 1,
1524 ec = tvb_get_ntohs(tvb, offset);
1525 proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2,
1530 rrc = tvb_get_ntohs(tvb, offset);
1531 proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2,
1535 /* sequence number */
1537 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1541 /* Checksum of plaintext padded data */
1543 if (pinfo->gssapi_data_encrypted) {
1544 checksum_size = 44 + ec;
1549 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1550 checksum_size, FALSE);
1551 offset += checksum_size;
1553 if(pinfo->decrypt_gssapi_tvb){
1554 /* if the caller did not provide a tvb, then we just use
1555 whatever is left of our current tvb.
1557 if(!pinfo->gssapi_encrypted_tvb){
1559 len=tvb_reported_length_remaining(tvb,offset);
1560 if(len>tvb_length_remaining(tvb, offset)){
1561 /* no point in trying to decrypt,
1562 we dont have the full pdu.
1566 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1567 tvb, offset, len, len);
1570 if (pinfo->gssapi_data_encrypted) {
1571 /* do we need to create a tvb for the wrapper
1574 if(!pinfo->gssapi_wrap_tvb){
1575 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1576 tvb, start_offset-2,
1577 offset - (start_offset-2),
1578 offset - (start_offset-2));
1583 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1585 tvbuff_t *checksum_tvb = tvb_new_subset(tvb, 16, checksum_size, checksum_size);
1587 if (pinfo->gssapi_data_encrypted) {
1588 if(pinfo->gssapi_encrypted_tvb){
1589 decrypt_gssapi_krb_cfx_wrap(tree,
1592 pinfo->gssapi_encrypted_tvb,
1595 (pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_DCE)?TRUE:FALSE,
1598 KRB5_KU_USAGE_ACCEPTOR_SEAL:
1599 KRB5_KU_USAGE_INITIATOR_SEAL);
1603 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1606 * Return the offset past the checksum, so that we know where
1607 * the data we're wrapped around starts. Also, set the length
1608 * of our top-level item to that offset, so it doesn't cover
1609 * the data we're wrapped around.
1611 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1618 * XXX - This is for GSSAPI CFX GetMIC tokens ...
1621 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1627 * The KRB5 blob conforms to RFC4121:
1628 * USHORT (0x0404 == GSS_GetMIC)
1632 flags = tvb_get_guint8(tvb, offset);
1633 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1635 /* Skip the filler */
1637 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 5,
1641 /* sequence number */
1643 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1647 /* Checksum of plaintext padded data */
1649 checksum_size = tvb_length_remaining(tvb, offset);
1651 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1652 checksum_size, FALSE);
1653 offset += checksum_size;
1656 * Return the offset past the checksum, so that we know where
1657 * the data we're wrapped around starts. Also, set the length
1658 * of our top-level item to that offset, so it doesn't cover
1659 * the data we're wrapped around.
1666 * XXX - is this for SPNEGO or just GSS-API?
1667 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1668 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1669 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1670 * getting it accepted.
1673 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1676 proto_tree *subtree;
1680 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
1682 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1685 * The KRB5 blob conforms to RFC1964:
1686 * USHORT (0x0102 == GSS_Wrap)
1690 /* First, the token ID ... */
1692 token_id = tvb_get_letohs(tvb, offset);
1693 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1699 case KRB_TOKEN_GETMIC:
1700 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
1703 case KRB_TOKEN_WRAP:
1704 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1707 case KRB_TOKEN_CFX_GETMIC:
1708 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
1711 case KRB_TOKEN_CFX_WRAP:
1712 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
1721 * Return the offset past the checksum, so that we know where
1722 * the data we're wrapped around starts. Also, set the length
1723 * of our top-level item to that offset, so it doesn't cover
1724 * the data we're wrapped around.
1726 proto_item_set_len(item, offset);
1730 /* Spnego stuff from here */
1733 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1736 proto_tree *subtree;
1738 asn1_ctx_t asn1_ctx;
1739 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1744 * We need this later, so lets get it now ...
1745 * It has to be per-frame as there can be more than one GSS-API
1746 * negotiation in a conversation.
1750 item = proto_tree_add_item(tree, proto_spnego, tvb, offset,
1753 subtree = proto_item_add_subtree(item, ett_spnego);
1755 * The TVB contains a [0] header and a sequence that consists of an
1756 * object ID and a blob containing the data ...
1757 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1758 * with the "optional" "use in non-initial tokens" being chosen.
1759 * ASN1 code addet to spnego.asn to handle this.
1762 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, &asn1_ctx , subtree, -1);
1769 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1772 proto_tree *subtree;
1774 conversation_t *conversation;
1775 asn1_ctx_t asn1_ctx;
1776 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1779 * We need this later, so lets get it now ...
1780 * It has to be per-frame as there can be more than one GSS-API
1781 * negotiation in a conversation.
1783 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1784 if (!next_level_value && !pinfo->fd->flags.visited) {
1786 * No handle attached to this frame, but it's the first
1787 * pass, so it'd be attached to the conversation.
1788 * If we have a conversation, try to get the handle,
1789 * and if we get one, attach it to the frame.
1791 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1792 pinfo->ptype, pinfo->srcport,
1793 pinfo->destport, 0);
1796 next_level_value = conversation_get_proto_data(conversation,
1798 if (next_level_value)
1799 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1803 item = proto_tree_add_item(parent_tree, proto_spnego, tvb, offset,
1806 subtree = proto_item_add_subtree(item, ett_spnego);
1809 * The TVB contains a [0] header and a sequence that consists of an
1810 * object ID and a blob containing the data ...
1811 * Actually, it contains, according to RFC2478:
1812 * NegotiationToken ::= CHOICE {
1813 * negTokenInit [0] NegTokenInit,
1814 * negTokenTarg [1] NegTokenTarg }
1815 * NegTokenInit ::= SEQUENCE {
1816 * mechTypes [0] MechTypeList OPTIONAL,
1817 * reqFlags [1] ContextFlags OPTIONAL,
1818 * mechToken [2] OCTET STRING OPTIONAL,
1819 * mechListMIC [3] OCTET STRING OPTIONAL }
1820 * NegTokenTarg ::= SEQUENCE {
1821 * negResult [0] ENUMERATED {
1822 * accept_completed (0),
1823 * accept_incomplete (1),
1824 * reject (2) } OPTIONAL,
1825 * supportedMech [1] MechType OPTIONAL,
1826 * responseToken [2] OCTET STRING OPTIONAL,
1827 * mechListMIC [3] OCTET STRING OPTIONAL }
1829 * Windows typically includes mechTypes and mechListMic ('NONE'
1830 * in the case of NTLMSSP only).
1831 * It seems to duplicate the responseToken into the mechListMic field
1832 * as well. Naughty, naughty.
1835 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
1839 /*--- proto_register_spnego -------------------------------------------*/
1840 void proto_register_spnego(void) {
1842 /* List of fields */
1843 static hf_register_info hf[] = {
1844 { &hf_spnego_wraptoken,
1845 { "wrapToken", "spnego.wraptoken",
1846 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1849 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1850 BASE_NONE, NULL, 0, NULL, HFILL }},
1851 { &hf_spnego_krb5_oid,
1852 { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
1853 BASE_NONE, NULL, 0, NULL, HFILL }},
1854 { &hf_spnego_krb5_tok_id,
1855 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1856 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1857 { &hf_spnego_krb5_sgn_alg,
1858 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1859 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1860 { &hf_spnego_krb5_seal_alg,
1861 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1862 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1863 { &hf_spnego_krb5_snd_seq,
1864 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1865 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1866 { &hf_spnego_krb5_sgn_cksum,
1867 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1868 NULL, 0, "KRB5 Data Checksum", HFILL}},
1869 { &hf_spnego_krb5_confounder,
1870 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1871 NULL, 0, "KRB5 Confounder", HFILL}},
1872 { &hf_spnego_krb5_filler,
1873 { "krb5_filler", "spnego.krb5.filler", FT_BYTES, BASE_NONE,
1874 NULL, 0, "KRB5 Filler", HFILL}},
1875 { &hf_spnego_krb5_cfx_flags,
1876 { "krb5_cfx_flags", "spnego.krb5.cfx_flags", FT_UINT8, BASE_HEX,
1877 NULL, 0, "KRB5 CFX Flags", HFILL}},
1878 { &hf_spnego_krb5_cfx_flags_01,
1879 { "SendByAcceptor", "spnego.krb5.send_by_acceptor", FT_BOOLEAN, 8,
1880 TFS (&tfs_set_notset), 0x01, NULL, HFILL}},
1881 { &hf_spnego_krb5_cfx_flags_02,
1882 { "Sealed", "spnego.krb5.sealed", FT_BOOLEAN, 8,
1883 TFS (&tfs_set_notset), 0x02, NULL, HFILL}},
1884 { &hf_spnego_krb5_cfx_flags_04,
1885 { "AcceptorSubkey", "spnego.krb5.acceptor_subkey", FT_BOOLEAN, 8,
1886 TFS (&tfs_set_notset), 0x04, NULL, HFILL}},
1887 { &hf_spnego_krb5_cfx_ec,
1888 { "krb5_cfx_ec", "spnego.krb5.cfx_ec", FT_UINT16, BASE_DEC,
1889 NULL, 0, "KRB5 CFX Extra Count", HFILL}},
1890 { &hf_spnego_krb5_cfx_rrc,
1891 { "krb5_cfx_rrc", "spnego.krb5.cfx_rrc", FT_UINT16, BASE_DEC,
1892 NULL, 0, "KRB5 CFX Right Rotation Count", HFILL}},
1893 { &hf_spnego_krb5_cfx_seq,
1894 { "krb5_cfx_seq", "spnego.krb5.cfx_seq", FT_UINT64, BASE_DEC,
1895 NULL, 0, "KRB5 Sequence Number", HFILL}},
1898 /*--- Included file: packet-spnego-hfarr.c ---*/
1899 #line 1 "packet-spnego-hfarr.c"
1900 { &hf_spnego_negTokenInit,
1901 { "negTokenInit", "spnego.negTokenInit",
1902 FT_NONE, BASE_NONE, NULL, 0,
1904 { &hf_spnego_negTokenTarg,
1905 { "negTokenTarg", "spnego.negTokenTarg",
1906 FT_NONE, BASE_NONE, NULL, 0,
1908 { &hf_spnego_MechTypeList_item,
1909 { "MechType", "spnego.MechType",
1910 FT_OID, BASE_NONE, NULL, 0,
1912 { &hf_spnego_principal,
1913 { "principal", "spnego.principal",
1914 FT_STRING, BASE_NONE, NULL, 0,
1915 "GeneralString", HFILL }},
1916 { &hf_spnego_mechTypes,
1917 { "mechTypes", "spnego.mechTypes",
1918 FT_UINT32, BASE_DEC, NULL, 0,
1919 "MechTypeList", HFILL }},
1920 { &hf_spnego_reqFlags,
1921 { "reqFlags", "spnego.reqFlags",
1922 FT_BYTES, BASE_NONE, NULL, 0,
1923 "ContextFlags", HFILL }},
1924 { &hf_spnego_mechToken,
1925 { "mechToken", "spnego.mechToken",
1926 FT_BYTES, BASE_NONE, NULL, 0,
1927 "T_mechToken", HFILL }},
1928 { &hf_spnego_negTokenInit_mechListMIC,
1929 { "mechListMIC", "spnego.mechListMIC",
1930 FT_BYTES, BASE_NONE, NULL, 0,
1931 "T_NegTokenInit_mechListMIC", HFILL }},
1932 { &hf_spnego_negResult,
1933 { "negResult", "spnego.negResult",
1934 FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
1935 "T_negResult", HFILL }},
1936 { &hf_spnego_supportedMech,
1937 { "supportedMech", "spnego.supportedMech",
1938 FT_OID, BASE_NONE, NULL, 0,
1939 "T_supportedMech", HFILL }},
1940 { &hf_spnego_responseToken,
1941 { "responseToken", "spnego.responseToken",
1942 FT_BYTES, BASE_NONE, NULL, 0,
1943 "T_responseToken", HFILL }},
1944 { &hf_spnego_mechListMIC,
1945 { "mechListMIC", "spnego.mechListMIC",
1946 FT_BYTES, BASE_NONE, NULL, 0,
1947 "T_mechListMIC", HFILL }},
1948 { &hf_spnego_thisMech,
1949 { "thisMech", "spnego.thisMech",
1950 FT_OID, BASE_NONE, NULL, 0,
1951 "MechType", HFILL }},
1952 { &hf_spnego_innerContextToken,
1953 { "innerContextToken", "spnego.innerContextToken",
1954 FT_NONE, BASE_NONE, NULL, 0,
1956 { &hf_spnego_ContextFlags_delegFlag,
1957 { "delegFlag", "spnego.delegFlag",
1958 FT_BOOLEAN, 8, NULL, 0x80,
1960 { &hf_spnego_ContextFlags_mutualFlag,
1961 { "mutualFlag", "spnego.mutualFlag",
1962 FT_BOOLEAN, 8, NULL, 0x40,
1964 { &hf_spnego_ContextFlags_replayFlag,
1965 { "replayFlag", "spnego.replayFlag",
1966 FT_BOOLEAN, 8, NULL, 0x20,
1968 { &hf_spnego_ContextFlags_sequenceFlag,
1969 { "sequenceFlag", "spnego.sequenceFlag",
1970 FT_BOOLEAN, 8, NULL, 0x10,
1972 { &hf_spnego_ContextFlags_anonFlag,
1973 { "anonFlag", "spnego.anonFlag",
1974 FT_BOOLEAN, 8, NULL, 0x08,
1976 { &hf_spnego_ContextFlags_confFlag,
1977 { "confFlag", "spnego.confFlag",
1978 FT_BOOLEAN, 8, NULL, 0x04,
1980 { &hf_spnego_ContextFlags_integFlag,
1981 { "integFlag", "spnego.integFlag",
1982 FT_BOOLEAN, 8, NULL, 0x02,
1985 /*--- End of included file: packet-spnego-hfarr.c ---*/
1986 #line 1399 "packet-spnego-template.c"
1989 /* List of subtrees */
1990 static gint *ett[] = {
1992 &ett_spnego_wraptoken,
1994 &ett_spnego_krb5_cfx_flags,
1997 /*--- Included file: packet-spnego-ettarr.c ---*/
1998 #line 1 "packet-spnego-ettarr.c"
1999 &ett_spnego_NegotiationToken,
2000 &ett_spnego_MechTypeList,
2001 &ett_spnego_PrincipalSeq,
2002 &ett_spnego_NegTokenInit,
2003 &ett_spnego_ContextFlags,
2004 &ett_spnego_NegTokenTarg,
2005 &ett_spnego_InitialContextToken_U,
2007 /*--- End of included file: packet-spnego-ettarr.c ---*/
2008 #line 1409 "packet-spnego-template.c"
2011 /* Register protocol */
2012 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
2014 register_dissector("spnego", dissect_spnego, proto_spnego);
2016 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
2020 register_dissector("spnego-krb5", dissect_spnego_krb5, proto_spnego_krb5);
2021 new_register_dissector("spnego-krb5-wrap", dissect_spnego_krb5_wrap, proto_spnego_krb5);
2023 /* Register fields and subtrees */
2024 proto_register_field_array(proto_spnego, hf, array_length(hf));
2025 proto_register_subtree_array(ett, array_length(ett));
2029 /*--- proto_reg_handoff_spnego ---------------------------------------*/
2030 void proto_reg_handoff_spnego(void) {
2032 dissector_handle_t spnego_handle, spnego_wrap_handle;
2033 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
2035 /* Register protocol with GSS-API module */
2037 spnego_handle = find_dissector("spnego");
2038 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap, proto_spnego);
2039 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
2040 spnego_handle, spnego_wrap_handle,
2041 "SPNEGO - Simple Protected Negotiation");
2043 /* Register both the one MS created and the real one */
2045 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
2046 * mystery of the MS KRB5 OID is cleared up. It was due to a library
2047 * that did not handle OID components greater than 16 bits, and was
2048 * fixed in Win2K SP2 as well as WinXP.
2049 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
2050 * SPNEGO implementation issues. 3-Dec-2002.
2052 spnego_krb5_handle = find_dissector("spnego-krb5");
2053 spnego_krb5_wrap_handle = find_dissector("spnego-krb5-wrap");
2054 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2055 spnego_krb5_handle, spnego_krb5_wrap_handle,
2056 "MS KRB5 - Microsoft Kerberos 5");
2057 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2058 spnego_krb5_handle, spnego_krb5_wrap_handle,
2059 "KRB5 - Kerberos 5");
2060 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
2061 spnego_krb5_handle, spnego_krb5_wrap_handle,
2062 "KRB5 - Kerberos 5 - User to User");