1 /* Do not modify this file. Changes will be overwritten. */
2 /* Generated automatically by the ASN.1 to Wireshark dissector compiler */
4 /* asn2wrs.py -b -q -L -p spnego -c ./spnego.cnf -s ./packet-spnego-template -D . -O ../.. spnego.asn */
6 /* packet-spnego-template.c
7 * Routines for the simple and protected GSS-API negotiation mechanism
8 * as described in RFC 2478.
9 * Copyright 2002, Tim Potter <tpot@samba.org>
10 * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
11 * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
12 * Copyright 2005, Ronnie Sahlberg (krb decryption)
13 * Copyright 2005, Anders Broman (converted to asn2wrs generated dissector)
15 * Wireshark - Network traffic analyzer
16 * By Gerald Combs <gerald@wireshark.org>
17 * Copyright 1998 Gerald Combs
19 * SPDX-License-Identifier: GPL-2.0-or-later
21 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
22 Heimdal 1.6 and has been modified for wireshark's requirements.
27 #include <epan/packet.h>
28 #include <epan/expert.h>
29 #include <epan/asn1.h>
30 #include <epan/conversation.h>
31 #include <epan/proto_data.h>
33 #include <wsutil/wsgcrypt.h>
34 #include <wsutil/array.h>
35 #include "packet-gssapi.h"
36 #include "packet-kerberos.h"
37 #include "packet-ber.h"
39 #define PNAME "Simple Protected Negotiation"
40 #define PSNAME "SPNEGO"
41 #define PFNAME "spnego"
43 void proto_register_spnego(void);
44 void proto_reg_handoff_spnego(void);
46 static dissector_handle_t spnego_wrap_handle
;
48 /* Initialize the protocol and registered fields */
49 static int proto_spnego
;
50 static int proto_spnego_krb5
;
53 static int hf_spnego_wraptoken
;
54 static int hf_spnego_krb5_oid
;
55 static int hf_spnego_krb5
;
56 static int hf_spnego_krb5_tok_id
;
57 static int hf_spnego_krb5_sgn_alg
;
58 static int hf_spnego_krb5_seal_alg
;
59 static int hf_spnego_krb5_snd_seq
;
60 static int hf_spnego_krb5_sgn_cksum
;
61 static int hf_spnego_krb5_confounder
;
62 static int hf_spnego_krb5_filler
;
63 static int hf_spnego_krb5_cfx_flags
;
64 static int hf_spnego_krb5_cfx_flags_01
;
65 static int hf_spnego_krb5_cfx_flags_02
;
66 static int hf_spnego_krb5_cfx_flags_04
;
67 static int hf_spnego_krb5_cfx_ec
;
68 static int hf_spnego_krb5_cfx_rrc
;
69 static int hf_spnego_krb5_cfx_seq
;
71 static int hf_spnego_negTokenInit
; /* T_negTokenInit */
72 static int hf_spnego_negTokenTarg
; /* NegTokenTarg */
73 static int hf_spnego_MechTypeList_item
; /* MechType */
74 static int hf_spnego_mechTypes
; /* MechTypeList */
75 static int hf_spnego_reqFlags
; /* ContextFlags */
76 static int hf_spnego_mechToken
; /* T_mechToken */
77 static int hf_spnego_mechListMIC
; /* OCTET_STRING */
78 static int hf_spnego_hintName
; /* GeneralString */
79 static int hf_spnego_hintAddress
; /* OCTET_STRING */
80 static int hf_spnego_mechToken_01
; /* OCTET_STRING */
81 static int hf_spnego_negHints
; /* NegHints */
82 static int hf_spnego_negResult
; /* T_negResult */
83 static int hf_spnego_supportedMech
; /* T_supportedMech */
84 static int hf_spnego_responseToken
; /* T_responseToken */
85 static int hf_spnego_mechListMIC_01
; /* T_mechListMIC */
86 static int hf_spnego_thisMech
; /* MechType */
87 static int hf_spnego_innerContextToken
; /* InnerContextToken */
88 static int hf_spnego_target_realm
; /* T_target_realm */
89 static int hf_spnego_cookie
; /* OCTET_STRING */
91 static int hf_spnego_ContextFlags_delegFlag
;
92 static int hf_spnego_ContextFlags_mutualFlag
;
93 static int hf_spnego_ContextFlags_replayFlag
;
94 static int hf_spnego_ContextFlags_sequenceFlag
;
95 static int hf_spnego_ContextFlags_anonFlag
;
96 static int hf_spnego_ContextFlags_confFlag
;
97 static int hf_spnego_ContextFlags_integFlag
;
99 /* Global variables */
100 static const char *MechType_oid
;
101 gssapi_oid_value
*next_level_value
;
105 /* Initialize the subtree pointers */
106 static int ett_spnego
;
107 static int ett_spnego_wraptoken
;
108 static int ett_spnego_krb5
;
109 static int ett_spnego_krb5_cfx_flags
;
111 static int ett_spnego_NegotiationToken
;
112 static int ett_spnego_MechTypeList
;
113 static int ett_spnego_NegTokenInit
;
114 static int ett_spnego_NegHints
;
115 static int ett_spnego_NegTokenInit2
;
116 static int ett_spnego_ContextFlags
;
117 static int ett_spnego_NegTokenTarg
;
118 static int ett_spnego_InitialContextToken_U
;
119 static int ett_spnego_IAKERB_HEADER
;
121 static expert_field ei_spnego_decrypted_keytype
;
122 static expert_field ei_spnego_unknown_header
;
124 static dissector_handle_t spnego_handle
;
125 static dissector_handle_t spnego_krb5_handle
;
126 static dissector_handle_t spnego_krb5_wrap_handle
;
129 * Unfortunately, we have to have forward declarations of these,
130 * as the code generated by asn2wrs includes a call before the
133 static int dissect_spnego_NegTokenInit(bool implicit_tag
, tvbuff_t
*tvb
,
134 int offset
, asn1_ctx_t
*actx _U_
,
135 proto_tree
*tree
, int hf_index
);
136 static int dissect_spnego_NegTokenInit2(bool implicit_tag
, tvbuff_t
*tvb
,
137 int offset
, asn1_ctx_t
*actx _U_
,
138 proto_tree
*tree
, int hf_index
);
143 dissect_spnego_MechType(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
145 gssapi_oid_value
*value
;
147 offset
= dissect_ber_object_identifier_str(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, &MechType_oid
);
150 value
= gssapi_lookup_oid_str(MechType_oid
);
153 * Tell our caller the first mechanism we see, so that if
154 * this is a negTokenInit with a mechToken, it can interpret
155 * the mechToken according to the first mechType. (There
156 * might not have been any indication of the mechType
157 * in prior frames, so we can't necessarily use the
158 * mechanism from the conversation; i.e., a negTokenInit
159 * can contain the initial security token for the desired
160 * mechanism of the initiator - that's the first mechanism
163 if (!saw_mechanism
) {
165 next_level_value
= value
;
166 saw_mechanism
= true;
174 static const ber_sequence_t MechTypeList_sequence_of
[1] = {
175 { &hf_spnego_MechTypeList_item
, BER_CLASS_UNI
, BER_UNI_TAG_OID
, BER_FLAGS_NOOWNTAG
, dissect_spnego_MechType
},
179 dissect_spnego_MechTypeList(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
181 conversation_t
*conversation
;
183 saw_mechanism
= false;
185 offset
= dissect_ber_sequence_of(implicit_tag
, actx
, tree
, tvb
, offset
,
186 MechTypeList_sequence_of
, hf_index
, ett_spnego_MechTypeList
);
190 * If we saw a mechType we need to store it in case the negTokenTarg
191 * does not provide a supportedMech.
194 conversation
= find_or_create_conversation(actx
->pinfo
);
195 conversation_add_proto_data(conversation
, proto_spnego
, next_level_value
);
203 static int * const ContextFlags_bits
[] = {
204 &hf_spnego_ContextFlags_delegFlag
,
205 &hf_spnego_ContextFlags_mutualFlag
,
206 &hf_spnego_ContextFlags_replayFlag
,
207 &hf_spnego_ContextFlags_sequenceFlag
,
208 &hf_spnego_ContextFlags_anonFlag
,
209 &hf_spnego_ContextFlags_confFlag
,
210 &hf_spnego_ContextFlags_integFlag
,
215 dissect_spnego_ContextFlags(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
216 offset
= dissect_ber_bitstring(implicit_tag
, actx
, tree
, tvb
, offset
,
217 ContextFlags_bits
, 7, hf_index
, ett_spnego_ContextFlags
,
226 dissect_spnego_T_mechToken(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
228 tvbuff_t
*mechToken_tvb
= NULL
;
230 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
235 * Now, we should be able to dispatch, if we've gotten a tvbuff for
236 * the token and we have information on how to dissect its contents.
238 if (mechToken_tvb
&& next_level_value
)
239 call_dissector(next_level_value
->handle
, mechToken_tvb
, actx
->pinfo
, tree
);
248 dissect_spnego_OCTET_STRING(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
249 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
256 static const ber_sequence_t NegTokenInit_sequence
[] = {
257 { &hf_spnego_mechTypes
, BER_CLASS_CON
, 0, BER_FLAGS_OPTIONAL
, dissect_spnego_MechTypeList
},
258 { &hf_spnego_reqFlags
, BER_CLASS_CON
, 1, BER_FLAGS_OPTIONAL
, dissect_spnego_ContextFlags
},
259 { &hf_spnego_mechToken
, BER_CLASS_CON
, 2, BER_FLAGS_OPTIONAL
, dissect_spnego_T_mechToken
},
260 { &hf_spnego_mechListMIC
, BER_CLASS_CON
, 3, BER_FLAGS_OPTIONAL
, dissect_spnego_OCTET_STRING
},
261 { NULL
, 0, 0, 0, NULL
}
265 dissect_spnego_NegTokenInit(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
266 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
267 NegTokenInit_sequence
, hf_index
, ett_spnego_NegTokenInit
);
275 dissect_spnego_T_negTokenInit(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
276 bool is_response
= actx
->pinfo
->ptype
== PT_TCP
&&
277 actx
->pinfo
->srcport
< 1024;
280 * We decode as negTokenInit2 or negTokenInit depending on whether or not
281 * we are in a response or a request. That is essentially what MS-SPNG
285 return dissect_spnego_NegTokenInit2(implicit_tag
, tvb
, offset
,
286 actx
, tree
, hf_index
);
288 return dissect_spnego_NegTokenInit(implicit_tag
, tvb
, offset
,
289 actx
, tree
, hf_index
);
297 static const value_string spnego_T_negResult_vals
[] = {
298 { 0, "accept-completed" },
299 { 1, "accept-incomplete" },
306 dissect_spnego_T_negResult(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
307 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
316 dissect_spnego_T_supportedMech(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
318 conversation_t
*conversation
;
320 saw_mechanism
= false;
322 offset
= dissect_spnego_MechType(implicit_tag
, tvb
, offset
, actx
, tree
, hf_index
);
326 * If we saw an explicit mechType we store this in the conversation so that
327 * it will override any mechType we might have picked up from the
331 conversation
= find_or_create_conversation(actx
->pinfo
);
332 conversation_add_proto_data(conversation
, proto_spnego
, next_level_value
);
343 dissect_spnego_T_responseToken(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
345 tvbuff_t
*responseToken_tvb
;
348 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
354 * Now, we should be able to dispatch, if we've gotten a tvbuff for
355 * the token and we have information on how to dissect its contents.
356 * However, we should make sure that there is something in the
359 if (responseToken_tvb
&& (tvb_reported_length(responseToken_tvb
) > 0) ){
360 gssapi_oid_value
*value
=next_level_value
;
363 call_dissector(value
->handle
, responseToken_tvb
, actx
->pinfo
, tree
);
375 dissect_spnego_T_mechListMIC(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
377 tvbuff_t
*mechListMIC_tvb
;
380 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
,
386 * Now, we should be able to dispatch, if we've gotten a tvbuff for
387 * the token and we have information on how to dissect its contents.
388 * However, we should make sure that there is something in the
391 if (mechListMIC_tvb
&& (tvb_reported_length(mechListMIC_tvb
) > 0) ){
392 gssapi_oid_value
*value
=next_level_value
;
395 call_dissector(value
->handle
, mechListMIC_tvb
, actx
->pinfo
, tree
);
405 static const ber_sequence_t NegTokenTarg_sequence
[] = {
406 { &hf_spnego_negResult
, BER_CLASS_CON
, 0, BER_FLAGS_OPTIONAL
, dissect_spnego_T_negResult
},
407 { &hf_spnego_supportedMech
, BER_CLASS_CON
, 1, BER_FLAGS_OPTIONAL
, dissect_spnego_T_supportedMech
},
408 { &hf_spnego_responseToken
, BER_CLASS_CON
, 2, BER_FLAGS_OPTIONAL
, dissect_spnego_T_responseToken
},
409 { &hf_spnego_mechListMIC_01
, BER_CLASS_CON
, 3, BER_FLAGS_OPTIONAL
, dissect_spnego_T_mechListMIC
},
410 { NULL
, 0, 0, 0, NULL
}
414 dissect_spnego_NegTokenTarg(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
415 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
416 NegTokenTarg_sequence
, hf_index
, ett_spnego_NegTokenTarg
);
422 static const ber_choice_t NegotiationToken_choice
[] = {
423 { 0, &hf_spnego_negTokenInit
, BER_CLASS_CON
, 0, 0, dissect_spnego_T_negTokenInit
},
424 { 1, &hf_spnego_negTokenTarg
, BER_CLASS_CON
, 1, 0, dissect_spnego_NegTokenTarg
},
425 { 0, NULL
, 0, 0, 0, NULL
}
429 dissect_spnego_NegotiationToken(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
430 offset
= dissect_ber_choice(actx
, tree
, tvb
, offset
,
431 NegotiationToken_choice
, hf_index
, ett_spnego_NegotiationToken
,
440 dissect_spnego_GeneralString(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
441 offset
= dissect_ber_restricted_string(implicit_tag
, BER_UNI_TAG_GeneralString
,
442 actx
, tree
, tvb
, offset
, hf_index
,
449 static const ber_sequence_t NegHints_sequence
[] = {
450 { &hf_spnego_hintName
, BER_CLASS_CON
, 0, BER_FLAGS_OPTIONAL
, dissect_spnego_GeneralString
},
451 { &hf_spnego_hintAddress
, BER_CLASS_CON
, 1, BER_FLAGS_OPTIONAL
, dissect_spnego_OCTET_STRING
},
452 { NULL
, 0, 0, 0, NULL
}
456 dissect_spnego_NegHints(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
457 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
458 NegHints_sequence
, hf_index
, ett_spnego_NegHints
);
464 static const ber_sequence_t NegTokenInit2_sequence
[] = {
465 { &hf_spnego_mechTypes
, BER_CLASS_CON
, 0, BER_FLAGS_OPTIONAL
, dissect_spnego_MechTypeList
},
466 { &hf_spnego_reqFlags
, BER_CLASS_CON
, 1, BER_FLAGS_OPTIONAL
, dissect_spnego_ContextFlags
},
467 { &hf_spnego_mechToken_01
, BER_CLASS_CON
, 2, BER_FLAGS_OPTIONAL
, dissect_spnego_OCTET_STRING
},
468 { &hf_spnego_negHints
, BER_CLASS_CON
, 3, BER_FLAGS_OPTIONAL
, dissect_spnego_NegHints
},
469 { &hf_spnego_mechListMIC
, BER_CLASS_CON
, 4, BER_FLAGS_OPTIONAL
, dissect_spnego_OCTET_STRING
},
470 { NULL
, 0, 0, 0, NULL
}
474 dissect_spnego_NegTokenInit2(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
475 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
476 NegTokenInit2_sequence
, hf_index
, ett_spnego_NegTokenInit2
);
484 dissect_spnego_InnerContextToken(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
486 gssapi_oid_value
*next_level_value_lcl
;
493 * XXX - what should we do if this OID doesn't match the value
494 * attached to the frame or conversation? (That would be
495 * bogus, but that's not impossible - some broken implementation
496 * might negotiate some security mechanism but put the OID
497 * for some other security mechanism in GSS_Wrap tokens.)
500 next_level_value_lcl
= gssapi_lookup_oid_str(MechType_oid
);
503 * Now dissect the GSS_Wrap token; it's assumed to be in the
504 * rest of the tvbuff.
506 item
= proto_tree_add_item(tree
, hf_spnego_wraptoken
, tvb
, offset
, -1, ENC_NA
);
508 subtree
= proto_item_add_subtree(item
, ett_spnego_wraptoken
);
511 * Now, we should be able to dispatch after creating a new TVB.
512 * The subdissector must return the length of the part of the
513 * token it dissected, so we can return the length of the part
514 * we (and it) dissected.
516 token_tvb
= tvb_new_subset_remaining(tvb
, offset
);
517 if (next_level_value_lcl
&& next_level_value_lcl
->wrap_handle
) {
518 len
= call_dissector(next_level_value_lcl
->wrap_handle
, token_tvb
, actx
->pinfo
,
521 offset
= tvb_reported_length(tvb
);
523 offset
= offset
+ len
;
525 offset
= tvb_reported_length(tvb
);
532 static const ber_sequence_t InitialContextToken_U_sequence
[] = {
533 { &hf_spnego_thisMech
, BER_CLASS_UNI
, BER_UNI_TAG_OID
, BER_FLAGS_NOOWNTAG
, dissect_spnego_MechType
},
534 { &hf_spnego_innerContextToken
, BER_CLASS_ANY
, 0, BER_FLAGS_NOOWNTAG
, dissect_spnego_InnerContextToken
},
535 { NULL
, 0, 0, 0, NULL
}
539 dissect_spnego_InitialContextToken_U(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
540 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
541 InitialContextToken_U_sequence
, hf_index
, ett_spnego_InitialContextToken_U
);
549 dissect_spnego_InitialContextToken(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
550 offset
= dissect_ber_tagged_type(implicit_tag
, actx
, tree
, tvb
, offset
,
551 hf_index
, BER_CLASS_APP
, 0, true, dissect_spnego_InitialContextToken_U
);
559 dissect_spnego_T_target_realm(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
566 * MIT Kerberos sends an IAKERB-HEADER like this:
568 * <30 2B A1 29 04 27 53 32 2D 57 32 30 31 32 2D 4C 34 2E 53 31 2D 57 32 30>
570 * <A1 29 04 27 53 32 2D 57 32 30 31 32 2D 4C 34 2E 53 31 2D 57 32 30 31 32>
572 * <04 27 53 32 2D 57 32 30 31 32 2D 4C 34 2E 53 31 2D 57 32 30 31 32 2D 4C>
573 * 4 39: OCTET STRING 'S2-W2012-L4.S1-W2012-L4.W2012R2-L4.BASE'
578 get_ber_identifier(tvb
, offset
, &ber_class
, &pc
, &tag
);
579 if (ber_class
== BER_CLASS_UNI
&& pc
== false && tag
== BER_UNI_TAG_OCTETSTRING
) {
580 proto_tree_add_text_internal(tree
, tvb
, offset
, 1,
581 "target-realm encoded as OCTET STRING: MIT Kerberos?");
582 offset
= dissect_ber_restricted_string(implicit_tag
, BER_UNI_TAG_OCTETSTRING
,
583 actx
, tree
, tvb
, offset
, hf_index
,
586 offset
= dissect_ber_restricted_string(implicit_tag
, BER_UNI_TAG_UTF8String
,
587 actx
, tree
, tvb
, offset
, hf_index
,
596 static const ber_sequence_t IAKERB_HEADER_sequence
[] = {
597 { &hf_spnego_target_realm
, BER_CLASS_CON
, 1, 0, dissect_spnego_T_target_realm
},
598 { &hf_spnego_cookie
, BER_CLASS_CON
, 2, BER_FLAGS_OPTIONAL
, dissect_spnego_OCTET_STRING
},
599 { NULL
, 0, 0, 0, NULL
}
603 dissect_spnego_IAKERB_HEADER(bool implicit_tag _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, asn1_ctx_t
*actx _U_
, proto_tree
*tree _U_
, int hf_index _U_
) {
604 offset
= dissect_ber_sequence(implicit_tag
, actx
, tree
, tvb
, offset
,
605 IAKERB_HEADER_sequence
, hf_index
, ett_spnego_IAKERB_HEADER
);
611 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
612 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
613 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
616 #define KRB_TOKEN_AP_REQ 0x0001
617 #define KRB_TOKEN_AP_REP 0x0002
618 #define KRB_TOKEN_AP_ERR 0x0003
619 #define KRB_TOKEN_GETMIC 0x0101
620 #define KRB_TOKEN_WRAP 0x0102
621 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
622 #define KRB_TOKEN_TGT_REQ 0x0004
623 #define KRB_TOKEN_TGT_REP 0x0104
624 #define KRB_TOKEN_IAKERB_PROXY 0x0105
625 #define KRB_TOKEN_CFX_GETMIC 0x0404
626 #define KRB_TOKEN_CFX_WRAP 0x0405
628 static const value_string spnego_krb5_tok_id_vals
[] = {
629 { KRB_TOKEN_AP_REQ
, "KRB5_AP_REQ"},
630 { KRB_TOKEN_AP_REP
, "KRB5_AP_REP"},
631 { KRB_TOKEN_AP_ERR
, "KRB5_ERROR"},
632 { KRB_TOKEN_GETMIC
, "KRB5_GSS_GetMIC" },
633 { KRB_TOKEN_WRAP
, "KRB5_GSS_Wrap" },
634 { KRB_TOKEN_DELETE_SEC_CONTEXT
, "KRB5_GSS_Delete_sec_context" },
635 { KRB_TOKEN_TGT_REQ
, "KERB_TGT_REQUEST" },
636 { KRB_TOKEN_TGT_REP
, "KERB_TGT_REPLY" },
637 { KRB_TOKEN_IAKERB_PROXY
, "KRB_TOKEN_IAKERB_PROXY" },
638 { KRB_TOKEN_CFX_GETMIC
, "KRB_TOKEN_CFX_GetMic" },
639 { KRB_TOKEN_CFX_WRAP
, "KRB_TOKEN_CFX_WRAP" },
643 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
644 #define KRB_SGN_ALG_MD2_5 0x0001
645 #define KRB_SGN_ALG_DES_MAC 0x0002
646 #define KRB_SGN_ALG_HMAC 0x0011
648 static const value_string spnego_krb5_sgn_alg_vals
[] = {
649 { KRB_SGN_ALG_DES_MAC_MD5
, "DES MAC MD5"},
650 { KRB_SGN_ALG_MD2_5
, "MD2.5"},
651 { KRB_SGN_ALG_DES_MAC
, "DES MAC"},
652 { KRB_SGN_ALG_HMAC
, "HMAC"},
656 #define KRB_SEAL_ALG_DES_CBC 0x0000
657 #define KRB_SEAL_ALG_RC4 0x0010
658 #define KRB_SEAL_ALG_NONE 0xffff
660 static const value_string spnego_krb5_seal_alg_vals
[] = {
661 { KRB_SEAL_ALG_DES_CBC
, "DES CBC"},
662 { KRB_SEAL_ALG_RC4
, "RC4"},
663 { KRB_SEAL_ALG_NONE
, "None"},
668 * XXX - is this for SPNEGO or just GSS-API?
669 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
670 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
671 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
672 * getting it accepted.
675 dissect_spnego_krb5_getmic_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
);
677 dissect_spnego_krb5_wrap_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, uint16_t token_id
, gssapi_encrypt_info_t
* gssapi_encrypt
);
679 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
);
681 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, uint16_t token_id
, gssapi_encrypt_info_t
* gssapi_encrypt
);
684 dissect_spnego_krb5(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
696 gssapi_encrypt_info_t
* encrypt_info
= (gssapi_encrypt_info_t
*)data
;
698 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
700 item
= proto_tree_add_item(tree
, hf_spnego_krb5
, tvb
, offset
, -1, ENC_NA
);
702 subtree
= proto_item_add_subtree(item
, ett_spnego_krb5
);
705 * The KRB5 blob conforms to RFC1964:
708 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
711 * However, for some protocols, the KRB5 blob starts at the SHORT
712 * and has no DER encoded header etc.
714 * It appears that for some other protocols the KRB5 blob is just
715 * a Kerberos message, with no [APPLICATION 0] header, no OID,
720 * If we see an [APPLICATION 0] HEADER, we show the OID and
721 * the USHORT, and then dissect the rest as a Kerberos message.
723 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
724 * we assume it's an AP-REQ or AP-REP message, and dissect
725 * it all as a Kerberos message.
727 * Otherwise, we show the USHORT, and then dissect the rest
728 * as a Kerberos message.
732 * Get the first header ...
734 get_ber_identifier(tvb
, offset
, &ber_class
, &pc
, &tag
);
735 if (ber_class
== BER_CLASS_APP
&& pc
) {
737 * [APPLICATION <tag>]
739 offset
= dissect_ber_identifier(pinfo
, subtree
, tvb
, offset
, &ber_class
, &pc
, &tag
);
740 offset
= dissect_ber_length(pinfo
, subtree
, tvb
, offset
, &len
, &ind
);
750 offset
=dissect_ber_object_identifier_str(false, &asn1_ctx
, subtree
, tvb
, offset
, hf_spnego_krb5_oid
, &oid
);
752 token_id
= tvb_get_letohs(tvb
, offset
);
753 proto_tree_add_uint(subtree
, hf_spnego_krb5_tok_id
, tvb
, offset
, 2, token_id
);
759 case 14: /* [APPLICATION 14] */
760 case 15: /* [APPLICATION 15] */
762 * No token ID - just dissect as a Kerberos message and
765 dissect_kerberos_main(tvb
, pinfo
, subtree
, false, NULL
);
766 return tvb_captured_length(tvb
);
769 proto_tree_add_expert_format(subtree
, pinfo
, &ei_spnego_unknown_header
, tvb
, offset
, 0,
770 "Unknown header (class=%d, pc=%d, tag=%d)", ber_class
, pc
, tag
);
774 /* Next, the token ID ... */
776 token_id
= tvb_get_letohs(tvb
, offset
);
777 proto_tree_add_uint(subtree
, hf_spnego_krb5_tok_id
, tvb
, offset
, 2, token_id
);
784 case KRB_TOKEN_TGT_REQ
:
785 offset
= dissect_kerberos_TGT_REQ(false, tvb
, offset
, &asn1_ctx
, subtree
, -1);
787 case KRB_TOKEN_TGT_REP
:
788 offset
= dissect_kerberos_TGT_REP(false, tvb
, offset
, &asn1_ctx
, subtree
, -1);
791 case KRB_TOKEN_AP_REQ
:
792 case KRB_TOKEN_AP_REP
:
793 case KRB_TOKEN_AP_ERR
:
794 krb5_tvb
= tvb_new_subset_remaining(tvb
, offset
);
795 offset
+= dissect_kerberos_main(krb5_tvb
, pinfo
, subtree
, false, NULL
);
798 case KRB_TOKEN_GETMIC
:
799 offset
= dissect_spnego_krb5_getmic_base(tvb
, offset
, pinfo
, subtree
);
803 offset
= dissect_spnego_krb5_wrap_base(tvb
, offset
, pinfo
, subtree
, token_id
, encrypt_info
);
806 case KRB_TOKEN_DELETE_SEC_CONTEXT
:
810 case KRB_TOKEN_CFX_GETMIC
:
811 offset
= dissect_spnego_krb5_cfx_getmic_base(tvb
, offset
, pinfo
, subtree
);
814 case KRB_TOKEN_CFX_WRAP
:
815 offset
= dissect_spnego_krb5_cfx_wrap_base(tvb
, offset
, pinfo
, subtree
, token_id
, encrypt_info
);
818 case KRB_TOKEN_IAKERB_PROXY
:
819 offset
= dissect_spnego_IAKERB_HEADER(false, tvb
, offset
, &asn1_ctx
, subtree
, -1);
820 krb5_tvb
= tvb_new_subset_remaining(tvb
, offset
);
821 offset
+= dissect_kerberos_main(krb5_tvb
, pinfo
, subtree
, false, NULL
);
829 proto_item_set_len(item
, offset
);
830 return tvb_captured_length(tvb
);
834 #ifndef KEYTYPE_ARCFOUR_56
835 # define KEYTYPE_ARCFOUR_56 24
837 #ifndef KEYTYPE_ARCFOUR_HMAC
838 # define KEYTYPE_ARCFOUR_HMAC 23
840 /* XXX - We should probably do a configure-time check for this instead */
841 #ifndef KRB5_KU_USAGE_SEAL
842 # define KRB5_KU_USAGE_SEAL 22
846 arcfour_mic_key(const uint8_t *key_data
, size_t key_size
, int key_type
,
847 const uint8_t *cksum_data
, size_t cksum_size
,
850 uint8_t k5_data
[HASH_MD5_LENGTH
];
851 uint8_t T
[4] = { 0 };
853 if (key_type
== KEYTYPE_ARCFOUR_56
) {
854 uint8_t L40
[14] = "fortybits";
855 memcpy(L40
+ 10, T
, sizeof(T
));
856 if (ws_hmac_buffer(GCRY_MD_MD5
, k5_data
, L40
, 14, key_data
, key_size
)) {
859 memset(&k5_data
[7], 0xAB, 9);
861 if (ws_hmac_buffer(GCRY_MD_MD5
, k5_data
, T
, 4, key_data
, key_size
)) {
866 if (ws_hmac_buffer(GCRY_MD_MD5
, key6_data
, cksum_data
, cksum_size
, k5_data
, HASH_MD5_LENGTH
)) {
873 usage2arcfour(int usage
)
876 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
877 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
879 case 22: /*KRB5_KU_USAGE_SEAL 22 */
881 case 23: /*KRB5_KU_USAGE_SIGN 23 */
883 case 24: /*KRB5_KU_USAGE_SEQ 24 */
891 arcfour_mic_cksum(uint8_t *key_data
, int key_length
,
893 uint8_t sgn_cksum
[8],
894 const uint8_t *v1
, size_t l1
,
895 const uint8_t *v2
, size_t l2
,
896 const uint8_t *v3
, size_t l3
)
898 static const uint8_t signature
[] = "signaturekey";
899 uint8_t ksign_c
[HASH_MD5_LENGTH
];
901 uint8_t digest
[HASH_MD5_LENGTH
];
903 uint8_t cksum
[HASH_MD5_LENGTH
];
904 gcry_md_hd_t md5_handle
;
906 rc4_usage
=usage2arcfour(usage
);
907 if (ws_hmac_buffer(GCRY_MD_MD5
, ksign_c
, signature
, sizeof(signature
), key_data
, key_length
)) {
911 if (gcry_md_open(&md5_handle
, GCRY_MD_MD5
, 0)) {
914 t
[0] = (rc4_usage
>> 0) & 0xFF;
915 t
[1] = (rc4_usage
>> 8) & 0xFF;
916 t
[2] = (rc4_usage
>> 16) & 0xFF;
917 t
[3] = (rc4_usage
>> 24) & 0xFF;
918 gcry_md_write(md5_handle
, t
, 4);
919 gcry_md_write(md5_handle
, v1
, l1
);
920 gcry_md_write(md5_handle
, v2
, l2
);
921 gcry_md_write(md5_handle
, v3
, l3
);
922 memcpy(digest
, gcry_md_read(md5_handle
, 0), HASH_MD5_LENGTH
);
923 gcry_md_close(md5_handle
);
925 if (ws_hmac_buffer(GCRY_MD_MD5
, cksum
, digest
, HASH_MD5_LENGTH
, ksign_c
, HASH_MD5_LENGTH
)) {
929 memcpy(sgn_cksum
, cksum
, 8);
935 * Verify padding of a gss wrapped message and return its length.
938 gssapi_verify_pad(uint8_t *wrapped_data
, int wrapped_length
,
946 pad
= wrapped_data
+ wrapped_length
- 1;
949 if (padlength
> datalen
)
952 for (i
= padlength
; i
> 0 && *pad
== padlength
; i
--, pad
--);
962 decrypt_arcfour(gssapi_encrypt_info_t
* gssapi_encrypt
, uint8_t *input_message_buffer
, uint8_t *output_message_buffer
,
963 uint8_t *key_value
, int key_size
, int key_type
)
965 uint8_t Klocaldata
[16];
970 uint8_t Confounder
[8];
971 uint8_t cksum_data
[8];
975 gcry_cipher_hd_t rc4_handle
;
978 datalen
= tvb_captured_length(gssapi_encrypt
->gssapi_encrypted_tvb
);
980 if(tvb_get_ntohs(gssapi_encrypt
->gssapi_wrap_tvb
, 4)==0x1000){
982 } else if (tvb_get_ntohs(gssapi_encrypt
->gssapi_wrap_tvb
, 4)==0xffff){
988 if(tvb_get_ntohs(gssapi_encrypt
->gssapi_wrap_tvb
, 6)!=0xffff){
992 ret
= arcfour_mic_key(key_value
, key_size
, key_type
,
993 tvb_get_ptr(gssapi_encrypt
->gssapi_wrap_tvb
, 16, 8),
1000 tvb_memcpy(gssapi_encrypt
->gssapi_wrap_tvb
, SND_SEQ
, 8, 8);
1001 if (gcry_cipher_open (&rc4_handle
, GCRY_CIPHER_ARCFOUR
, GCRY_CIPHER_MODE_STREAM
, 0)) {
1004 if (gcry_cipher_setkey(rc4_handle
, k6_data
, sizeof(k6_data
))) {
1005 gcry_cipher_close(rc4_handle
);
1008 gcry_cipher_decrypt(rc4_handle
, (uint8_t *)SND_SEQ
, 8, NULL
, 0);
1009 gcry_cipher_close(rc4_handle
);
1011 memset(k6_data
, 0, sizeof(k6_data
));
1015 if (SND_SEQ
[1] != 0xFFFFFFFF && SND_SEQ
[1] != 0x00000000) {
1020 for (i
= 0; i
< 16; i
++)
1021 Klocaldata
[i
] = ((uint8_t *)key_value
)[i
] ^ 0xF0;
1023 ret
= arcfour_mic_key(Klocaldata
,sizeof(Klocaldata
),key_type
,
1024 (const uint8_t *)SND_SEQ
, 4,
1026 memset(Klocaldata
, 0, sizeof(Klocaldata
));
1033 tvb_memcpy(gssapi_encrypt
->gssapi_wrap_tvb
, Confounder
, 24, 8);
1034 if (gcry_cipher_open (&rc4_handle
, GCRY_CIPHER_ARCFOUR
, GCRY_CIPHER_MODE_STREAM
, 0)) {
1037 if (gcry_cipher_setkey(rc4_handle
, k6_data
, sizeof(k6_data
))) {
1038 gcry_cipher_close(rc4_handle
);
1042 gcry_cipher_decrypt(rc4_handle
, Confounder
, 8, NULL
, 0);
1043 gcry_cipher_decrypt(rc4_handle
, output_message_buffer
, datalen
, input_message_buffer
, datalen
);
1044 gcry_cipher_close(rc4_handle
);
1046 tvb_memcpy(gssapi_encrypt
->gssapi_wrap_tvb
, Confounder
, 24, 8);
1047 memcpy(output_message_buffer
, input_message_buffer
, datalen
);
1049 memset(k6_data
, 0, sizeof(k6_data
));
1051 /* only normal (i.e. non DCE style wrapping use padding ? */
1052 if(gssapi_encrypt
->decrypt_gssapi_tvb
==DECRYPT_GSSAPI_NORMAL
){
1053 ret
= gssapi_verify_pad(output_message_buffer
,datalen
,datalen
, &padlen
);
1060 /* don't know what the checksum looks like for dce style gssapi */
1061 if(gssapi_encrypt
->decrypt_gssapi_tvb
==DECRYPT_GSSAPI_NORMAL
){
1062 ret
= arcfour_mic_cksum(key_value
, key_size
, KRB5_KU_USAGE_SEAL
,
1064 tvb_get_ptr(gssapi_encrypt
->gssapi_wrap_tvb
, 0, 8), 8,
1065 Confounder
, sizeof(Confounder
), output_message_buffer
,
1071 cmp
= tvb_memeql(gssapi_encrypt
->gssapi_wrap_tvb
, 16, cksum_data
, 8); /* SGN_CKSUM */
1082 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1085 decrypt_gssapi_krb_arcfour_wrap(proto_tree
*tree _U_
, packet_info
*pinfo
, tvbuff_t
*tvb
, int keytype
, gssapi_encrypt_info_t
* gssapi_encrypt
)
1090 const uint8_t *original_data
;
1092 uint8_t *cryptocopy
=NULL
; /* workaround for pre-0.6.1 heimdal bug */
1093 uint8_t *output_message_buffer
;
1095 length
=tvb_captured_length(gssapi_encrypt
->gssapi_encrypted_tvb
);
1096 original_data
=tvb_get_ptr(gssapi_encrypt
->gssapi_encrypted_tvb
, 0, length
);
1098 /* don't do anything if we are not attempting to decrypt data */
1104 /* XXX we should only do this for first time, then store somewhere */
1105 /* XXX We also need to re-read the keytab when the preference changes */
1107 cryptocopy
=(uint8_t *)wmem_alloc(pinfo
->pool
, length
);
1108 output_message_buffer
=(uint8_t *)wmem_alloc(pinfo
->pool
, length
);
1110 for(ek
=enc_key_list
;ek
;ek
=ek
->next
){
1111 /* shortcircuit and bail out if enctypes are not matching */
1112 if(ek
->keytype
!=keytype
){
1116 /* pre-0.6.1 versions of Heimdal would sometimes change
1117 the cryptotext data even when the decryption failed.
1118 This would obviously not work since we iterate over the
1119 keys. So just give it a copy of the crypto data instead.
1120 This has been seen for RC4-HMAC blobs.
1122 memcpy(cryptocopy
, original_data
, length
);
1123 ret
=decrypt_arcfour(gssapi_encrypt
,
1125 output_message_buffer
,
1130 expert_add_info_format(pinfo
, NULL
, &ei_spnego_decrypted_keytype
,
1131 "Decrypted keytype %d in frame %u using %s",
1132 ek
->keytype
, pinfo
->num
, ek
->key_origin
);
1134 gssapi_encrypt
->gssapi_decrypted_tvb
=tvb_new_child_real_data(tvb
, output_message_buffer
, ret
, ret
);
1135 gssapi_encrypt
->used_decryption_key
= kerberos_last_decryption_key
= ek
;
1136 add_new_data_source(pinfo
, gssapi_encrypt
->gssapi_decrypted_tvb
, "Decrypted GSS-Krb5");
1142 /* borrowed from heimdal */
1144 rrc_rotate(uint8_t *data
, int len
, uint16_t rrc
, int unrotate
)
1146 uint8_t *tmp
, buf
[256];
1159 if (rrc
<= sizeof(buf
)) {
1162 tmp
= (uint8_t *)g_malloc(rrc
);
1168 memcpy(tmp
, data
, rrc
);
1169 memmove(data
, data
+ rrc
, left
);
1170 memcpy(data
+ left
, tmp
, rrc
);
1172 memcpy(tmp
, data
+ left
, rrc
);
1173 memmove(data
+ rrc
, data
, left
);
1174 memcpy(data
, tmp
, rrc
);
1177 if (rrc
> sizeof(buf
))
1185 decrypt_gssapi_krb_cfx_wrap(proto_tree
*tree
,
1187 tvbuff_t
*checksum_tvb
,
1188 gssapi_encrypt_info_t
* gssapi_encrypt
,
1199 /* don't do anything if we are not attempting to decrypt data */
1204 if (gssapi_encrypt
->decrypt_gssapi_tvb
==DECRYPT_GSSAPI_DCE
) {
1205 tvbuff_t
*out_tvb
= NULL
;
1207 out_tvb
= decrypt_krb5_krb_cfx_dce(tree
, pinfo
, usage
, keytype
,
1208 gssapi_encrypt
->gssapi_header_tvb
,
1209 gssapi_encrypt
->gssapi_encrypted_tvb
,
1210 gssapi_encrypt
->gssapi_trailer_tvb
,
1213 gssapi_encrypt
->gssapi_decrypted_tvb
= out_tvb
;
1214 gssapi_encrypt
->used_decryption_key
= kerberos_last_decryption_key
;
1215 add_new_data_source(pinfo
, gssapi_encrypt
->gssapi_decrypted_tvb
, "Decrypted GSS-Krb5 CFX DCE");
1220 datalen
= tvb_captured_length(checksum_tvb
) + tvb_captured_length(gssapi_encrypt
->gssapi_encrypted_tvb
);
1222 rotated
= (uint8_t *)wmem_alloc(pinfo
->pool
, datalen
);
1224 tvb_memcpy(checksum_tvb
, rotated
, 0, tvb_captured_length(checksum_tvb
));
1225 tvb_memcpy(gssapi_encrypt
->gssapi_encrypted_tvb
, rotated
+ tvb_captured_length(checksum_tvb
),
1226 0, tvb_captured_length(gssapi_encrypt
->gssapi_encrypted_tvb
));
1228 rrc_rotate(rotated
, datalen
, rrc
, true);
1230 next_tvb
=tvb_new_child_real_data(gssapi_encrypt
->gssapi_encrypted_tvb
, rotated
,
1232 add_new_data_source(pinfo
, next_tvb
, "GSSAPI CFX");
1234 output
= decrypt_krb5_data(tree
, pinfo
, usage
, next_tvb
, keytype
, &datalen
);
1239 outdata
= (uint8_t *)wmem_memdup(pinfo
->pool
, output
, tvb_captured_length(gssapi_encrypt
->gssapi_encrypted_tvb
));
1241 gssapi_encrypt
->gssapi_decrypted_tvb
=tvb_new_child_real_data(gssapi_encrypt
->gssapi_encrypted_tvb
,
1243 tvb_captured_length(gssapi_encrypt
->gssapi_encrypted_tvb
),
1244 tvb_captured_length(gssapi_encrypt
->gssapi_encrypted_tvb
));
1245 gssapi_encrypt
->used_decryption_key
= kerberos_last_decryption_key
;
1246 add_new_data_source(pinfo
, gssapi_encrypt
->gssapi_decrypted_tvb
, "Decrypted GSS-Krb5");
1250 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1256 * This is for GSSAPI Wrap tokens ...
1259 dissect_spnego_krb5_wrap_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, uint16_t token_id
, gssapi_encrypt_info_t
* gssapi_encrypt
)
1261 uint16_t sgn_alg
, seal_alg
;
1262 #ifdef HAVE_KERBEROS
1263 int start_offset
=offset
;
1270 * The KRB5 blob conforms to RFC1964:
1271 * USHORT (0x0102 == GSS_Wrap)
1275 /* Now, the sign and seal algorithms ... */
1277 sgn_alg
= tvb_get_letohs(tvb
, offset
);
1278 proto_tree_add_uint(tree
, hf_spnego_krb5_sgn_alg
, tvb
, offset
, 2, sgn_alg
);
1282 seal_alg
= tvb_get_letohs(tvb
, offset
);
1283 proto_tree_add_uint(tree
, hf_spnego_krb5_seal_alg
, tvb
, offset
, 2, seal_alg
);
1287 /* Skip the filler */
1291 /* Encrypted sequence number */
1293 proto_tree_add_item(tree
, hf_spnego_krb5_snd_seq
, tvb
, offset
, 8, ENC_NA
);
1297 /* Checksum of plaintext padded data */
1299 proto_tree_add_item(tree
, hf_spnego_krb5_sgn_cksum
, tvb
, offset
, 8, ENC_NA
);
1304 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1305 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1306 * extra 8 bytes of "Random confounder" after the checksum.
1307 * It certainly confounds code expecting all Kerberos 5
1308 * GSS_Wrap() tokens to look the same....
1310 if ((sgn_alg
== KRB_SGN_ALG_HMAC
) ||
1311 /* there also seems to be a confounder for DES MAC MD5 - certainly seen when using with
1312 SASL with LDAP between a Java client and Active Directory. If this breaks other things
1313 we may need to make this an option. gal 17/2/06 */
1314 (sgn_alg
== KRB_SGN_ALG_DES_MAC_MD5
)) {
1315 proto_tree_add_item(tree
, hf_spnego_krb5_confounder
, tvb
, offset
, 8, ENC_NA
);
1319 /* Is the data encrypted? */
1320 if (gssapi_encrypt
!= NULL
)
1321 gssapi_encrypt
->gssapi_data_encrypted
=(seal_alg
!=KRB_SEAL_ALG_NONE
);
1323 #ifdef HAVE_KERBEROS
1324 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
1325 if(gssapi_encrypt
&& gssapi_encrypt
->decrypt_gssapi_tvb
){
1326 /* if the caller did not provide a tvb, then we just use
1327 whatever is left of our current tvb.
1329 if(!gssapi_encrypt
->gssapi_encrypted_tvb
){
1331 len
=tvb_reported_length_remaining(tvb
,offset
);
1332 if(len
>tvb_captured_length_remaining(tvb
, offset
)){
1333 /* no point in trying to decrypt,
1334 we don't have the full pdu.
1338 gssapi_encrypt
->gssapi_encrypted_tvb
= tvb_new_subset_length(
1342 /* if this is KRB5 wrapped rc4-hmac */
1343 if((token_id
==KRB_TOKEN_WRAP
)
1344 &&(sgn_alg
==KRB_SGN_ALG_HMAC
)
1345 &&(seal_alg
==KRB_SEAL_ALG_RC4
)){
1346 /* do we need to create a tvb for the wrapper
1349 if(!gssapi_encrypt
->gssapi_wrap_tvb
){
1350 gssapi_encrypt
->gssapi_wrap_tvb
= tvb_new_subset_length(
1351 tvb
, start_offset
-2,
1352 GSS_ARCFOUR_WRAP_TOKEN_SIZE
);
1354 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1355 decrypt_gssapi_krb_arcfour_wrap(tree
,
1358 KEYTYPE_ARCFOUR_HMAC
,
1360 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1365 * Return the offset past the checksum, so that we know where
1366 * the data we're wrapped around starts. Also, set the length
1367 * of our top-level item to that offset, so it doesn't cover
1368 * the data we're wrapped around.
1370 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1377 * XXX - This is for GSSAPI GetMIC tokens ...
1380 dissect_spnego_krb5_getmic_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
, proto_tree
*tree
)
1385 * The KRB5 blob conforms to RFC1964:
1386 * USHORT (0x0101 == GSS_GetMIC)
1390 /* Now, the sign algorithm ... */
1392 sgn_alg
= tvb_get_letohs(tvb
, offset
);
1393 proto_tree_add_uint(tree
, hf_spnego_krb5_sgn_alg
, tvb
, offset
, 2, sgn_alg
);
1397 /* Skip the filler */
1401 /* Encrypted sequence number */
1403 proto_tree_add_item(tree
, hf_spnego_krb5_snd_seq
, tvb
, offset
, 8, ENC_NA
);
1407 /* Checksum of plaintext padded data */
1409 proto_tree_add_item(tree
, hf_spnego_krb5_sgn_cksum
, tvb
, offset
, 8, ENC_NA
);
1414 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1415 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1416 * extra 8 bytes of "Random confounder" after the checksum.
1417 * It certainly confounds code expecting all Kerberos 5
1418 * GSS_Wrap() tokens to look the same....
1420 * The exception is DNS/TSIG where there is no such confounder
1421 * so we need to test here if there are more bytes in our tvb or not.
1424 if (tvb_reported_length_remaining(tvb
, offset
)) {
1425 if (sgn_alg
== KRB_SGN_ALG_HMAC
) {
1426 proto_tree_add_item(tree
, hf_spnego_krb5_confounder
, tvb
, offset
, 8, ENC_NA
);
1433 * Return the offset past the checksum, so that we know where
1434 * the data we're wrapped around starts. Also, set the length
1435 * of our top-level item to that offset, so it doesn't cover
1436 * the data we're wrapped around.
1443 dissect_spnego_krb5_cfx_flags(tvbuff_t
*tvb
, int offset
,
1444 proto_tree
*spnego_krb5_tree
,
1445 uint8_t cfx_flags _U_
)
1447 static int * const flags
[] = {
1448 &hf_spnego_krb5_cfx_flags_04
,
1449 &hf_spnego_krb5_cfx_flags_02
,
1450 &hf_spnego_krb5_cfx_flags_01
,
1454 proto_tree_add_bitmask(spnego_krb5_tree
, tvb
, offset
, hf_spnego_krb5_cfx_flags
, ett_spnego_krb5_cfx_flags
, flags
, ENC_NA
);
1455 return (offset
+ 1);
1459 * This is for GSSAPI CFX Wrap tokens ...
1462 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, uint16_t token_id _U_
, gssapi_encrypt_info_t
* gssapi_encrypt
)
1466 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1472 int start_offset
=offset
;
1475 * The KRB5 blob conforms to RFC4121:
1480 /* Now, the sign and seal algorithms ... */
1482 flags
= tvb_get_uint8(tvb
, offset
);
1483 offset
= dissect_spnego_krb5_cfx_flags(tvb
, offset
, tree
, flags
);
1485 if (gssapi_encrypt
!= NULL
)
1486 gssapi_encrypt
->gssapi_data_encrypted
=(flags
& 2);
1488 /* Skip the filler */
1490 proto_tree_add_item(tree
, hf_spnego_krb5_filler
, tvb
, offset
, 1, ENC_NA
);
1494 ec
= tvb_get_ntohs(tvb
, offset
);
1495 proto_tree_add_item(tree
, hf_spnego_krb5_cfx_ec
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1499 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1500 rrc
= tvb_get_ntohs(tvb
, offset
);
1502 proto_tree_add_item(tree
, hf_spnego_krb5_cfx_rrc
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1505 /* sequence number */
1507 proto_tree_add_item(tree
, hf_spnego_krb5_cfx_seq
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1510 if (gssapi_encrypt
== NULL
) /* Probably shouldn't happen, but just protect ourselves */
1513 /* Checksum of plaintext padded data */
1515 if (gssapi_encrypt
->gssapi_data_encrypted
) {
1516 checksum_size
= 44 + ec
;
1518 proto_tree_add_item(tree
, hf_spnego_krb5_sgn_cksum
, tvb
, offset
, checksum_size
, ENC_NA
);
1519 offset
+= checksum_size
;
1522 int returned_offset
;
1523 int inner_token_len
= 0;
1526 * We know we have a wrap token, but we have to let the proto
1527 * above us decode that, so hand it back in gssapi_wrap_tvb
1528 * and put the checksum in the tree.
1533 inner_token_len
= tvb_reported_length_remaining(tvb
, offset
);
1534 if (inner_token_len
> ec
) {
1535 inner_token_len
-= ec
;
1539 * We handle only the two common cases for now
1540 * (rrc == 0 and rrc == ec)
1542 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1544 proto_tree_add_item(tree
, hf_spnego_krb5_sgn_cksum
, tvb
, offset
, checksum_size
, ENC_NA
);
1545 offset
+= checksum_size
;
1549 returned_offset
= offset
;
1550 gssapi_encrypt
->gssapi_wrap_tvb
= tvb_new_subset_length(tvb
, offset
,
1552 gssapi_encrypt
->gssapi_decrypted_tvb
= tvb_new_subset_length(tvb
, offset
,
1555 offset
+= inner_token_len
;
1557 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1561 proto_tree_add_item(tree
, hf_spnego_krb5_sgn_cksum
, tvb
, offset
, checksum_size
, ENC_NA
);
1565 * Return an offset that puts our caller before the inner
1566 * token. This is better than before, but we still see the
1567 * checksum included in the LDAP query at times.
1569 return returned_offset
;
1572 if(gssapi_encrypt
->decrypt_gssapi_tvb
){
1573 /* if the caller did not provide a tvb, then we just use
1574 whatever is left of our current tvb.
1576 if(!gssapi_encrypt
->gssapi_encrypted_tvb
){
1578 len
=tvb_reported_length_remaining(tvb
,offset
);
1579 if(len
>tvb_captured_length_remaining(tvb
, offset
)){
1580 /* no point in trying to decrypt,
1581 we don't have the full pdu.
1585 gssapi_encrypt
->gssapi_encrypted_tvb
= tvb_new_subset_length_caplen(
1586 tvb
, offset
, len
, len
);
1589 if (gssapi_encrypt
->gssapi_data_encrypted
) {
1590 /* do we need to create a tvb for the wrapper
1593 if(!gssapi_encrypt
->gssapi_wrap_tvb
){
1594 gssapi_encrypt
->gssapi_wrap_tvb
= tvb_new_subset_length(
1595 tvb
, start_offset
-2,
1596 offset
- (start_offset
-2));
1601 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1603 tvbuff_t
*checksum_tvb
= tvb_new_subset_length(tvb
, 16, checksum_size
);
1605 if (gssapi_encrypt
->gssapi_data_encrypted
) {
1606 if(gssapi_encrypt
->gssapi_encrypted_tvb
){
1607 decrypt_gssapi_krb_cfx_wrap(tree
,
1615 KRB5_KU_USAGE_ACCEPTOR_SEAL
:
1616 KRB5_KU_USAGE_INITIATOR_SEAL
);
1620 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1623 * Return the offset past the checksum, so that we know where
1624 * the data we're wrapped around starts. Also, set the length
1625 * of our top-level item to that offset, so it doesn't cover
1626 * the data we're wrapped around.
1628 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1635 * XXX - This is for GSSAPI CFX GetMIC tokens ...
1638 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
, proto_tree
*tree
)
1644 * The KRB5 blob conforms to RFC4121:
1645 * USHORT (0x0404 == GSS_GetMIC)
1649 flags
= tvb_get_uint8(tvb
, offset
);
1650 offset
= dissect_spnego_krb5_cfx_flags(tvb
, offset
, tree
, flags
);
1652 /* Skip the filler */
1654 proto_tree_add_item(tree
, hf_spnego_krb5_filler
, tvb
, offset
, 5, ENC_NA
);
1657 /* sequence number */
1659 proto_tree_add_item(tree
, hf_spnego_krb5_cfx_seq
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1662 /* Checksum of plaintext padded data */
1664 checksum_size
= tvb_captured_length_remaining(tvb
, offset
);
1666 proto_tree_add_item(tree
, hf_spnego_krb5_sgn_cksum
, tvb
, offset
, checksum_size
, ENC_NA
);
1667 offset
+= checksum_size
;
1670 * Return the offset past the checksum, so that we know where
1671 * the data we're wrapped around starts. Also, set the length
1672 * of our top-level item to that offset, so it doesn't cover
1673 * the data we're wrapped around.
1680 * XXX - is this for SPNEGO or just GSS-API?
1681 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1682 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1683 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1684 * getting it accepted.
1687 dissect_spnego_krb5_wrap(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data
)
1690 proto_tree
*subtree
;
1693 gssapi_encrypt_info_t
* encrypt_info
= (gssapi_encrypt_info_t
*)data
;
1695 item
= proto_tree_add_item(tree
, hf_spnego_krb5
, tvb
, 0, -1, ENC_NA
);
1697 subtree
= proto_item_add_subtree(item
, ett_spnego_krb5
);
1700 * The KRB5 blob conforms to RFC1964:
1701 * USHORT (0x0102 == GSS_Wrap)
1705 /* First, the token ID ... */
1707 token_id
= tvb_get_letohs(tvb
, offset
);
1708 proto_tree_add_uint(subtree
, hf_spnego_krb5_tok_id
, tvb
, offset
, 2, token_id
);
1713 case KRB_TOKEN_GETMIC
:
1714 offset
= dissect_spnego_krb5_getmic_base(tvb
, offset
, pinfo
, subtree
);
1717 case KRB_TOKEN_WRAP
:
1718 offset
= dissect_spnego_krb5_wrap_base(tvb
, offset
, pinfo
, subtree
, token_id
, encrypt_info
);
1721 case KRB_TOKEN_CFX_GETMIC
:
1722 offset
= dissect_spnego_krb5_cfx_getmic_base(tvb
, offset
, pinfo
, subtree
);
1725 case KRB_TOKEN_CFX_WRAP
:
1726 offset
= dissect_spnego_krb5_cfx_wrap_base(tvb
, offset
, pinfo
, subtree
, token_id
, encrypt_info
);
1735 * Return the offset past the checksum, so that we know where
1736 * the data we're wrapped around starts. Also, set the length
1737 * of our top-level item to that offset, so it doesn't cover
1738 * the data we're wrapped around.
1740 proto_item_set_len(item
, offset
);
1744 /* Spnego stuff from here */
1747 dissect_spnego_wrap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1750 proto_tree
*subtree
;
1752 asn1_ctx_t asn1_ctx
;
1753 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
1755 MechType_oid
= NULL
;
1758 * We need this later, so lets get it now ...
1759 * It has to be per-frame as there can be more than one GSS-API
1760 * negotiation in a conversation.
1764 item
= proto_tree_add_item(tree
, proto_spnego
, tvb
, offset
, -1, ENC_NA
);
1766 subtree
= proto_item_add_subtree(item
, ett_spnego
);
1768 * The TVB contains a [0] header and a sequence that consists of an
1769 * object ID and a blob containing the data ...
1770 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1771 * with the "optional" "use in non-initial tokens" being chosen.
1772 * ASN1 code addet to spnego.asn to handle this.
1775 offset
= dissect_spnego_InitialContextToken(false, tvb
, offset
, &asn1_ctx
, subtree
, -1);
1782 dissect_spnego(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
1785 proto_tree
*subtree
;
1787 conversation_t
*conversation
;
1788 asn1_ctx_t asn1_ctx
;
1789 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
1792 * We need this later, so lets get it now ...
1793 * It has to be per-frame as there can be more than one GSS-API
1794 * negotiation in a conversation.
1796 next_level_value
= (gssapi_oid_value
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_spnego
, 0);
1797 if (!next_level_value
&& !pinfo
->fd
->visited
) {
1799 * No handle attached to this frame, but it's the first
1800 * pass, so it'd be attached to the conversation.
1801 * If we have a conversation, try to get the handle,
1802 * and if we get one, attach it to the frame.
1804 conversation
= find_conversation_pinfo(pinfo
, 0);
1807 next_level_value
= (gssapi_oid_value
*)conversation_get_proto_data(conversation
, proto_spnego
);
1808 if (next_level_value
)
1809 p_add_proto_data(wmem_file_scope(), pinfo
, proto_spnego
, 0, next_level_value
);
1813 item
= proto_tree_add_item(parent_tree
, proto_spnego
, tvb
, offset
, -1, ENC_NA
);
1815 subtree
= proto_item_add_subtree(item
, ett_spnego
);
1818 * The TVB contains a [0] header and a sequence that consists of an
1819 * object ID and a blob containing the data ...
1820 * Actually, it contains, according to RFC2478:
1821 * NegotiationToken ::= CHOICE {
1822 * negTokenInit [0] NegTokenInit,
1823 * negTokenTarg [1] NegTokenTarg }
1824 * NegTokenInit ::= SEQUENCE {
1825 * mechTypes [0] MechTypeList OPTIONAL,
1826 * reqFlags [1] ContextFlags OPTIONAL,
1827 * mechToken [2] OCTET STRING OPTIONAL,
1828 * mechListMIC [3] OCTET STRING OPTIONAL }
1829 * NegTokenTarg ::= SEQUENCE {
1830 * negResult [0] ENUMERATED {
1831 * accept_completed (0),
1832 * accept_incomplete (1),
1833 * reject (2) } OPTIONAL,
1834 * supportedMech [1] MechType OPTIONAL,
1835 * responseToken [2] OCTET STRING OPTIONAL,
1836 * mechListMIC [3] OCTET STRING OPTIONAL }
1838 * Windows typically includes mechTypes and mechListMic ('NONE'
1839 * in the case of NTLMSSP only).
1840 * It seems to duplicate the responseToken into the mechListMic field
1841 * as well. Naughty, naughty.
1844 dissect_spnego_NegotiationToken(false, tvb
, offset
, &asn1_ctx
, subtree
, -1);
1845 return tvb_captured_length(tvb
);
1848 /*--- proto_register_spnego -------------------------------------------*/
1849 void proto_register_spnego(void) {
1851 /* List of fields */
1852 static hf_register_info hf
[] = {
1853 { &hf_spnego_wraptoken
,
1854 { "wrapToken", "spnego.wraptoken",
1855 FT_NONE
, BASE_NONE
, NULL
, 0x0, "SPNEGO wrapToken",
1858 { "krb5_blob", "spnego.krb5.blob", FT_BYTES
,
1859 BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1860 { &hf_spnego_krb5_oid
,
1861 { "KRB5 OID", "spnego.krb5_oid", FT_STRING
,
1862 BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1863 { &hf_spnego_krb5_tok_id
,
1864 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16
, BASE_HEX
,
1865 VALS(spnego_krb5_tok_id_vals
), 0, "KRB5 Token Id", HFILL
}},
1866 { &hf_spnego_krb5_sgn_alg
,
1867 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16
, BASE_HEX
,
1868 VALS(spnego_krb5_sgn_alg_vals
), 0, "KRB5 Signing Algorithm", HFILL
}},
1869 { &hf_spnego_krb5_seal_alg
,
1870 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16
, BASE_HEX
,
1871 VALS(spnego_krb5_seal_alg_vals
), 0, "KRB5 Sealing Algorithm", HFILL
}},
1872 { &hf_spnego_krb5_snd_seq
,
1873 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES
, BASE_NONE
,
1874 NULL
, 0, "KRB5 Encrypted Sequence Number", HFILL
}},
1875 { &hf_spnego_krb5_sgn_cksum
,
1876 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES
, BASE_NONE
,
1877 NULL
, 0, "KRB5 Data Checksum", HFILL
}},
1878 { &hf_spnego_krb5_confounder
,
1879 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES
, BASE_NONE
,
1880 NULL
, 0, "KRB5 Confounder", HFILL
}},
1881 { &hf_spnego_krb5_filler
,
1882 { "krb5_filler", "spnego.krb5.filler", FT_BYTES
, BASE_NONE
,
1883 NULL
, 0, "KRB5 Filler", HFILL
}},
1884 { &hf_spnego_krb5_cfx_flags
,
1885 { "krb5_cfx_flags", "spnego.krb5.cfx_flags", FT_UINT8
, BASE_HEX
,
1886 NULL
, 0, "KRB5 CFX Flags", HFILL
}},
1887 { &hf_spnego_krb5_cfx_flags_01
,
1888 { "SendByAcceptor", "spnego.krb5.send_by_acceptor", FT_BOOLEAN
, 8,
1889 TFS (&tfs_set_notset
), 0x01, NULL
, HFILL
}},
1890 { &hf_spnego_krb5_cfx_flags_02
,
1891 { "Sealed", "spnego.krb5.sealed", FT_BOOLEAN
, 8,
1892 TFS (&tfs_set_notset
), 0x02, NULL
, HFILL
}},
1893 { &hf_spnego_krb5_cfx_flags_04
,
1894 { "AcceptorSubkey", "spnego.krb5.acceptor_subkey", FT_BOOLEAN
, 8,
1895 TFS (&tfs_set_notset
), 0x04, NULL
, HFILL
}},
1896 { &hf_spnego_krb5_cfx_ec
,
1897 { "krb5_cfx_ec", "spnego.krb5.cfx_ec", FT_UINT16
, BASE_DEC
,
1898 NULL
, 0, "KRB5 CFX Extra Count", HFILL
}},
1899 { &hf_spnego_krb5_cfx_rrc
,
1900 { "krb5_cfx_rrc", "spnego.krb5.cfx_rrc", FT_UINT16
, BASE_DEC
,
1901 NULL
, 0, "KRB5 CFX Right Rotation Count", HFILL
}},
1902 { &hf_spnego_krb5_cfx_seq
,
1903 { "krb5_cfx_seq", "spnego.krb5.cfx_seq", FT_UINT64
, BASE_DEC
,
1904 NULL
, 0, "KRB5 Sequence Number", HFILL
}},
1906 { &hf_spnego_negTokenInit
,
1907 { "negTokenInit", "spnego.negTokenInit_element",
1908 FT_NONE
, BASE_NONE
, NULL
, 0,
1910 { &hf_spnego_negTokenTarg
,
1911 { "negTokenTarg", "spnego.negTokenTarg_element",
1912 FT_NONE
, BASE_NONE
, NULL
, 0,
1914 { &hf_spnego_MechTypeList_item
,
1915 { "MechType", "spnego.MechType",
1916 FT_OID
, BASE_NONE
, NULL
, 0,
1918 { &hf_spnego_mechTypes
,
1919 { "mechTypes", "spnego.mechTypes",
1920 FT_UINT32
, BASE_DEC
, NULL
, 0,
1921 "MechTypeList", HFILL
}},
1922 { &hf_spnego_reqFlags
,
1923 { "reqFlags", "spnego.reqFlags",
1924 FT_BYTES
, BASE_NONE
, NULL
, 0,
1925 "ContextFlags", HFILL
}},
1926 { &hf_spnego_mechToken
,
1927 { "mechToken", "spnego.mechToken",
1928 FT_BYTES
, BASE_NONE
, NULL
, 0,
1930 { &hf_spnego_mechListMIC
,
1931 { "mechListMIC", "spnego.mechListMIC",
1932 FT_BYTES
, BASE_NONE
, NULL
, 0,
1933 "OCTET_STRING", HFILL
}},
1934 { &hf_spnego_hintName
,
1935 { "hintName", "spnego.hintName",
1936 FT_STRING
, BASE_NONE
, NULL
, 0,
1937 "GeneralString", HFILL
}},
1938 { &hf_spnego_hintAddress
,
1939 { "hintAddress", "spnego.hintAddress",
1940 FT_BYTES
, BASE_NONE
, NULL
, 0,
1941 "OCTET_STRING", HFILL
}},
1942 { &hf_spnego_mechToken_01
,
1943 { "mechToken", "spnego.mechToken",
1944 FT_BYTES
, BASE_NONE
, NULL
, 0,
1945 "OCTET_STRING", HFILL
}},
1946 { &hf_spnego_negHints
,
1947 { "negHints", "spnego.negHints_element",
1948 FT_NONE
, BASE_NONE
, NULL
, 0,
1950 { &hf_spnego_negResult
,
1951 { "negResult", "spnego.negResult",
1952 FT_UINT32
, BASE_DEC
, VALS(spnego_T_negResult_vals
), 0,
1954 { &hf_spnego_supportedMech
,
1955 { "supportedMech", "spnego.supportedMech",
1956 FT_OID
, BASE_NONE
, NULL
, 0,
1958 { &hf_spnego_responseToken
,
1959 { "responseToken", "spnego.responseToken",
1960 FT_BYTES
, BASE_NONE
, NULL
, 0,
1962 { &hf_spnego_mechListMIC_01
,
1963 { "mechListMIC", "spnego.mechListMIC",
1964 FT_BYTES
, BASE_NONE
, NULL
, 0,
1966 { &hf_spnego_thisMech
,
1967 { "thisMech", "spnego.thisMech",
1968 FT_OID
, BASE_NONE
, NULL
, 0,
1969 "MechType", HFILL
}},
1970 { &hf_spnego_innerContextToken
,
1971 { "innerContextToken", "spnego.innerContextToken_element",
1972 FT_NONE
, BASE_NONE
, NULL
, 0,
1974 { &hf_spnego_target_realm
,
1975 { "target-realm", "spnego.target_realm",
1976 FT_STRING
, BASE_NONE
, NULL
, 0,
1977 "T_target_realm", HFILL
}},
1978 { &hf_spnego_cookie
,
1979 { "cookie", "spnego.cookie",
1980 FT_BYTES
, BASE_NONE
, NULL
, 0,
1981 "OCTET_STRING", HFILL
}},
1982 { &hf_spnego_ContextFlags_delegFlag
,
1983 { "delegFlag", "spnego.ContextFlags.delegFlag",
1984 FT_BOOLEAN
, 8, NULL
, 0x80,
1986 { &hf_spnego_ContextFlags_mutualFlag
,
1987 { "mutualFlag", "spnego.ContextFlags.mutualFlag",
1988 FT_BOOLEAN
, 8, NULL
, 0x40,
1990 { &hf_spnego_ContextFlags_replayFlag
,
1991 { "replayFlag", "spnego.ContextFlags.replayFlag",
1992 FT_BOOLEAN
, 8, NULL
, 0x20,
1994 { &hf_spnego_ContextFlags_sequenceFlag
,
1995 { "sequenceFlag", "spnego.ContextFlags.sequenceFlag",
1996 FT_BOOLEAN
, 8, NULL
, 0x10,
1998 { &hf_spnego_ContextFlags_anonFlag
,
1999 { "anonFlag", "spnego.ContextFlags.anonFlag",
2000 FT_BOOLEAN
, 8, NULL
, 0x08,
2002 { &hf_spnego_ContextFlags_confFlag
,
2003 { "confFlag", "spnego.ContextFlags.confFlag",
2004 FT_BOOLEAN
, 8, NULL
, 0x04,
2006 { &hf_spnego_ContextFlags_integFlag
,
2007 { "integFlag", "spnego.ContextFlags.integFlag",
2008 FT_BOOLEAN
, 8, NULL
, 0x02,
2012 /* List of subtrees */
2013 static int *ett
[] = {
2015 &ett_spnego_wraptoken
,
2017 &ett_spnego_krb5_cfx_flags
,
2019 &ett_spnego_NegotiationToken
,
2020 &ett_spnego_MechTypeList
,
2021 &ett_spnego_NegTokenInit
,
2022 &ett_spnego_NegHints
,
2023 &ett_spnego_NegTokenInit2
,
2024 &ett_spnego_ContextFlags
,
2025 &ett_spnego_NegTokenTarg
,
2026 &ett_spnego_InitialContextToken_U
,
2027 &ett_spnego_IAKERB_HEADER
,
2030 static ei_register_info ei
[] = {
2031 { &ei_spnego_decrypted_keytype
, { "spnego.decrypted_keytype", PI_SECURITY
, PI_CHAT
, "Decrypted keytype", EXPFILL
}},
2032 { &ei_spnego_unknown_header
, { "spnego.unknown_header", PI_PROTOCOL
, PI_WARN
, "Unknown header", EXPFILL
}},
2035 expert_module_t
* expert_spnego
;
2037 /* Register protocol */
2038 proto_spnego
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
2040 spnego_handle
= register_dissector("spnego", dissect_spnego
, proto_spnego
);
2041 spnego_wrap_handle
= register_dissector("spnego-wrap", dissect_spnego_wrap
, proto_spnego
);
2043 proto_spnego_krb5
= proto_register_protocol("SPNEGO-KRB5", "SPNEGO-KRB5", "spnego-krb5");
2045 spnego_krb5_handle
= register_dissector("spnego-krb5", dissect_spnego_krb5
, proto_spnego_krb5
);
2046 spnego_krb5_wrap_handle
= register_dissector("spnego-krb5-wrap", dissect_spnego_krb5_wrap
, proto_spnego_krb5
);
2048 /* Register fields and subtrees */
2049 proto_register_field_array(proto_spnego
, hf
, array_length(hf
));
2050 proto_register_subtree_array(ett
, array_length(ett
));
2051 expert_spnego
= expert_register_protocol(proto_spnego
);
2052 expert_register_field_array(expert_spnego
, ei
, array_length(ei
));
2056 /*--- proto_reg_handoff_spnego ---------------------------------------*/
2057 void proto_reg_handoff_spnego(void) {
2059 /* Register protocol with GSS-API module */
2061 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego
, ett_spnego
,
2062 spnego_handle
, spnego_wrap_handle
,
2063 "SPNEGO - Simple Protected Negotiation");
2065 /* Register both the one MS created and the real one */
2067 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
2068 * mystery of the MS KRB5 OID is cleared up. It was due to a library
2069 * that did not handle OID components greater than 16 bits, and was
2070 * fixed in Win2K SP2 as well as WinXP.
2071 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
2072 * SPNEGO implementation issues. 3-Dec-2002.
2074 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5
, ett_spnego_krb5
,
2075 spnego_krb5_handle
, spnego_krb5_wrap_handle
,
2076 "MS KRB5 - Microsoft Kerberos 5");
2077 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5
, ett_spnego_krb5
,
2078 spnego_krb5_handle
, spnego_krb5_wrap_handle
,
2079 "KRB5 - Kerberos 5");
2080 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5
, ett_spnego_krb5
,
2081 spnego_krb5_handle
, spnego_krb5_wrap_handle
,
2082 "KRB5 - Kerberos 5 - User to User");
2083 gssapi_init_oid("1.3.6.1.5.2.5", proto_spnego_krb5
, ett_spnego_krb5
,
2084 spnego_krb5_handle
, spnego_krb5_wrap_handle
,
2094 * indent-tabs-mode: nil
2097 * ex: set shiftwidth=2 tabstop=8 expandtab:
2098 * :indentSize=2:tabSize=8:noTabs=true: