Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-spnego.c
blobb4651159ea60026ff7179f55c88bf13908765269
1 /* Do not modify this file. Changes will be overwritten. */
2 /* Generated automatically by the ASN.1 to Wireshark dissector compiler */
3 /* packet-spnego.c */
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.
25 #include "config.h"
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>
32 #include <epan/tfs.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 */
90 /* named bits */
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;
102 bool saw_mechanism;
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
131 * definition.
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);
142 static int
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
161 * in the list.)
163 if (!saw_mechanism) {
164 if (value)
165 next_level_value = value;
166 saw_mechanism = true;
170 return offset;
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 },
178 static int
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.
193 if(saw_mechanism){
194 conversation = find_or_create_conversation(actx->pinfo);
195 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
199 return offset;
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,
211 NULL
214 static int
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,
218 NULL);
220 return offset;
225 static int
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,
231 &mechToken_tvb);
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);
242 return offset;
247 static int
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,
250 NULL);
252 return offset;
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 }
264 static int
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);
269 return offset;
274 static int
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
282 * says.
284 if (is_response) {
285 return dissect_spnego_NegTokenInit2(implicit_tag, tvb, offset,
286 actx, tree, hf_index);
287 } else {
288 return dissect_spnego_NegTokenInit(implicit_tag, tvb, offset,
289 actx, tree, hf_index);
293 return offset;
297 static const value_string spnego_T_negResult_vals[] = {
298 { 0, "accept-completed" },
299 { 1, "accept-incomplete" },
300 { 2, "reject" },
301 { 0, NULL }
305 static int
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,
308 NULL);
310 return offset;
315 static int
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
328 * negTokenInit.
330 if(saw_mechanism){
331 conversation = find_or_create_conversation(actx->pinfo);
332 conversation_add_proto_data(conversation, proto_spnego, next_level_value);
337 return offset;
342 static int
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,
349 &responseToken_tvb);
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
357 * response token ...
359 if (responseToken_tvb && (tvb_reported_length(responseToken_tvb) > 0) ){
360 gssapi_oid_value *value=next_level_value;
362 if(value){
363 call_dissector(value->handle, responseToken_tvb, actx->pinfo, tree);
369 return offset;
374 static int
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,
381 &mechListMIC_tvb);
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
389 * response token ...
391 if (mechListMIC_tvb && (tvb_reported_length(mechListMIC_tvb) > 0) ){
392 gssapi_oid_value *value=next_level_value;
394 if(value){
395 call_dissector(value->handle, mechListMIC_tvb, actx->pinfo, tree);
401 return offset;
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 }
413 static int
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);
418 return offset;
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 }
428 static int
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,
432 NULL);
434 return offset;
439 static int
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,
443 NULL);
445 return offset;
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 }
455 static int
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);
460 return offset;
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 }
473 static int
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);
478 return offset;
483 static int
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;
487 proto_item *item;
488 proto_tree *subtree;
489 tvbuff_t *token_tvb;
490 int len;
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.)
498 * Does it matter?
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,
519 subtree);
520 if (len == 0)
521 offset = tvb_reported_length(tvb);
522 else
523 offset = offset + len;
524 } else
525 offset = tvb_reported_length(tvb);
528 return offset;
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 }
538 static int
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);
543 return offset;
548 static int
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);
553 return offset;
558 static int
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_) {
561 int8_t ber_class;
562 bool pc;
563 int32_t tag;
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>
569 * 0 43: SEQUENCE {
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>
571 * 2 41: [1] {
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'
574 * : }
575 * : }
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,
584 NULL);
585 } else {
586 offset = dissect_ber_restricted_string(implicit_tag, BER_UNI_TAG_UTF8String,
587 actx, tree, tvb, offset, hf_index,
588 NULL);
592 return offset;
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 }
602 static int
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);
607 return offset;
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" },
640 { 0, NULL}
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"},
653 { 0, NULL}
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"},
664 { 0, NULL}
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.
674 static int
675 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
676 static int
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);
678 static int
679 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
680 static int
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);
683 static int
684 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
686 proto_item *item;
687 proto_tree *subtree;
688 int offset = 0;
689 uint16_t token_id;
690 const char *oid;
691 tvbuff_t *krb5_tvb;
692 int8_t ber_class;
693 bool pc, ind = 0;
694 int32_t tag;
695 uint32_t len;
696 gssapi_encrypt_info_t* encrypt_info = (gssapi_encrypt_info_t*)data;
697 asn1_ctx_t asn1_ctx;
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:
706 * [APPLICATION 0] {
707 * OID,
708 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
709 * OCTET STRING }
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,
716 * and no USHORT.
718 * So:
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);
742 switch (tag) {
744 case 0:
746 * [APPLICATION 0]
749 /* Next, the OID */
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);
755 offset += 2;
757 break;
759 case 14: /* [APPLICATION 14] */
760 case 15: /* [APPLICATION 15] */
762 * No token ID - just dissect as a Kerberos message and
763 * return.
765 dissect_kerberos_main(tvb, pinfo, subtree, false, NULL);
766 return tvb_captured_length(tvb);
768 default:
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);
771 goto done;
773 } else {
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);
779 offset += 2;
782 switch (token_id) {
784 case KRB_TOKEN_TGT_REQ:
785 offset = dissect_kerberos_TGT_REQ(false, tvb, offset, &asn1_ctx, subtree, -1);
786 break;
787 case KRB_TOKEN_TGT_REP:
788 offset = dissect_kerberos_TGT_REP(false, tvb, offset, &asn1_ctx, subtree, -1);
789 break;
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);
796 break;
798 case KRB_TOKEN_GETMIC:
799 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
800 break;
802 case KRB_TOKEN_WRAP:
803 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id, encrypt_info);
804 break;
806 case KRB_TOKEN_DELETE_SEC_CONTEXT:
808 break;
810 case KRB_TOKEN_CFX_GETMIC:
811 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
812 break;
814 case KRB_TOKEN_CFX_WRAP:
815 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id, encrypt_info);
816 break;
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);
822 break;
823 default:
825 break;
828 done:
829 proto_item_set_len(item, offset);
830 return tvb_captured_length(tvb);
833 #ifdef HAVE_KERBEROS
834 #ifndef KEYTYPE_ARCFOUR_56
835 # define KEYTYPE_ARCFOUR_56 24
836 #endif
837 #ifndef KEYTYPE_ARCFOUR_HMAC
838 # define KEYTYPE_ARCFOUR_HMAC 23
839 #endif
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
843 #endif
845 static int
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,
848 uint8_t *key6_data)
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)) {
857 return 0;
859 memset(&k5_data[7], 0xAB, 9);
860 } else {
861 if (ws_hmac_buffer(GCRY_MD_MD5, k5_data, T, 4, key_data, key_size)) {
862 return 0;
866 if (ws_hmac_buffer(GCRY_MD_MD5, key6_data, cksum_data, cksum_size, k5_data, HASH_MD5_LENGTH)) {
867 return 0;
869 return 0;
872 static int
873 usage2arcfour(int usage)
875 switch (usage) {
876 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
877 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
878 return 8;
879 case 22: /*KRB5_KU_USAGE_SEAL 22 */
880 return 13;
881 case 23: /*KRB5_KU_USAGE_SIGN 23 */
882 return 15;
883 case 24: /*KRB5_KU_USAGE_SEQ 24 */
884 return 0;
885 default :
886 return 0;
890 static int
891 arcfour_mic_cksum(uint8_t *key_data, int key_length,
892 unsigned int usage,
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];
900 uint8_t t[4];
901 uint8_t digest[HASH_MD5_LENGTH];
902 int rc4_usage;
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)) {
908 return 0;
911 if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
912 return 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)) {
926 return 0;
929 memcpy(sgn_cksum, cksum, 8);
931 return 0;
935 * Verify padding of a gss wrapped message and return its length.
937 static int
938 gssapi_verify_pad(uint8_t *wrapped_data, int wrapped_length,
939 int datalen,
940 int *padlen)
942 uint8_t *pad;
943 int padlength;
944 int i;
946 pad = wrapped_data + wrapped_length - 1;
947 padlength = *pad;
949 if (padlength > datalen)
950 return 1;
952 for (i = padlength; i > 0 && *pad == padlength; i--, pad--);
953 if (i != 0)
954 return 2;
956 *padlen = padlength;
958 return 0;
961 static int
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];
966 int ret;
967 int datalen;
968 uint8_t k6_data[16];
969 uint32_t SND_SEQ[2];
970 uint8_t Confounder[8];
971 uint8_t cksum_data[8];
972 int cmp;
973 int conf_flag;
974 int padlen = 0;
975 gcry_cipher_hd_t rc4_handle;
976 int i;
978 datalen = tvb_captured_length(gssapi_encrypt->gssapi_encrypted_tvb);
980 if(tvb_get_ntohs(gssapi_encrypt->gssapi_wrap_tvb, 4)==0x1000){
981 conf_flag=1;
982 } else if (tvb_get_ntohs(gssapi_encrypt->gssapi_wrap_tvb, 4)==0xffff){
983 conf_flag=0;
984 } else {
985 return -3;
988 if(tvb_get_ntohs(gssapi_encrypt->gssapi_wrap_tvb, 6)!=0xffff){
989 return -4;
992 ret = arcfour_mic_key(key_value, key_size, key_type,
993 tvb_get_ptr(gssapi_encrypt->gssapi_wrap_tvb, 16, 8),
994 8, /* SGN_CKSUM */
995 k6_data);
996 if (ret) {
997 return -5;
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)) {
1002 return -12;
1004 if (gcry_cipher_setkey(rc4_handle, k6_data, sizeof(k6_data))) {
1005 gcry_cipher_close(rc4_handle);
1006 return -13;
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) {
1016 return -6;
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,
1025 k6_data);
1026 memset(Klocaldata, 0, sizeof(Klocaldata));
1027 if (ret) {
1028 return -7;
1031 if(conf_flag) {
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)) {
1035 return -14;
1037 if (gcry_cipher_setkey(rc4_handle, k6_data, sizeof(k6_data))) {
1038 gcry_cipher_close(rc4_handle);
1039 return -15;
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);
1045 } else {
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);
1054 if (ret) {
1055 return -9;
1057 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,
1063 cksum_data,
1064 tvb_get_ptr(gssapi_encrypt->gssapi_wrap_tvb, 0, 8), 8,
1065 Confounder, sizeof(Confounder), output_message_buffer,
1066 datalen + padlen);
1067 if (ret) {
1068 return -10;
1071 cmp = tvb_memeql(gssapi_encrypt->gssapi_wrap_tvb, 16, cksum_data, 8); /* SGN_CKSUM */
1072 if (cmp) {
1073 return -11;
1077 return datalen;
1082 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1084 static void
1085 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree _U_, packet_info *pinfo, tvbuff_t *tvb, int keytype, gssapi_encrypt_info_t* gssapi_encrypt)
1087 int ret;
1088 enc_key_t *ek;
1089 int length;
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 */
1100 if(!krb_decrypt){
1101 return;
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){
1113 continue;
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,
1124 cryptocopy,
1125 output_message_buffer,
1126 ek->keyvalue,
1127 ek->keylength,
1128 ek->keytype);
1129 if (ret >= 0) {
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");
1137 return;
1142 /* borrowed from heimdal */
1143 static int
1144 rrc_rotate(uint8_t *data, int len, uint16_t rrc, int unrotate)
1146 uint8_t *tmp, buf[256];
1147 size_t left;
1149 if (len == 0)
1150 return 0;
1152 rrc %= len;
1154 if (rrc == 0)
1155 return 0;
1157 left = len - rrc;
1159 if (rrc <= sizeof(buf)) {
1160 tmp = buf;
1161 } else {
1162 tmp = (uint8_t *)g_malloc(rrc);
1163 if (tmp == NULL)
1164 return -1;
1167 if (unrotate) {
1168 memcpy(tmp, data, rrc);
1169 memmove(data, data + rrc, left);
1170 memcpy(data + left, tmp, rrc);
1171 } else {
1172 memcpy(tmp, data + left, rrc);
1173 memmove(data + rrc, data, left);
1174 memcpy(data, tmp, rrc);
1177 if (rrc > sizeof(buf))
1178 g_free(tmp);
1180 return 0;
1184 static void
1185 decrypt_gssapi_krb_cfx_wrap(proto_tree *tree,
1186 packet_info *pinfo,
1187 tvbuff_t *checksum_tvb,
1188 gssapi_encrypt_info_t* gssapi_encrypt,
1189 uint16_t ec _U_,
1190 uint16_t rrc,
1191 int keytype,
1192 unsigned int usage)
1194 uint8_t *rotated;
1195 uint8_t *output;
1196 int datalen;
1197 tvbuff_t *next_tvb;
1199 /* don't do anything if we are not attempting to decrypt data */
1200 if(!krb_decrypt){
1201 return;
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,
1211 checksum_tvb);
1212 if (out_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");
1217 return;
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,
1231 datalen, datalen);
1232 add_new_data_source(pinfo, next_tvb, "GSSAPI CFX");
1234 output = decrypt_krb5_data(tree, pinfo, usage, next_tvb, keytype, &datalen);
1236 if (output) {
1237 uint8_t *outdata;
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,
1242 outdata,
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 */
1253 #endif
1256 * This is for GSSAPI Wrap tokens ...
1258 static int
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;
1264 #else
1265 (void) pinfo;
1266 (void) token_id;
1267 #endif
1270 * The KRB5 blob conforms to RFC1964:
1271 * USHORT (0x0102 == GSS_Wrap)
1272 * and so on }
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);
1280 offset += 2;
1282 seal_alg = tvb_get_letohs(tvb, offset);
1283 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2, seal_alg);
1285 offset += 2;
1287 /* Skip the filler */
1289 offset += 2;
1291 /* Encrypted sequence number */
1293 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8, ENC_NA);
1295 offset += 8;
1297 /* Checksum of plaintext padded data */
1299 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8, ENC_NA);
1301 offset += 8;
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);
1316 offset += 8;
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){
1330 int len;
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.
1336 return offset;
1338 gssapi_encrypt->gssapi_encrypted_tvb = tvb_new_subset_length(
1339 tvb, offset, len);
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
1347 as well ?
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,
1356 pinfo,
1357 tvb,
1358 KEYTYPE_ARCFOUR_HMAC,
1359 gssapi_encrypt);
1360 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1363 #endif
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,
1371 * not before.
1373 return offset;
1377 * XXX - This is for GSSAPI GetMIC tokens ...
1379 static int
1380 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1382 uint16_t sgn_alg;
1385 * The KRB5 blob conforms to RFC1964:
1386 * USHORT (0x0101 == GSS_GetMIC)
1387 * and so on }
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);
1395 offset += 2;
1397 /* Skip the filler */
1399 offset += 4;
1401 /* Encrypted sequence number */
1403 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8, ENC_NA);
1405 offset += 8;
1407 /* Checksum of plaintext padded data */
1409 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8, ENC_NA);
1411 offset += 8;
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.
1422 * -- ronnie
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);
1428 offset += 8;
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.
1439 return offset;
1442 static int
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,
1451 NULL
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 ...
1461 static int
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)
1464 uint8_t flags;
1465 uint16_t ec;
1466 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1467 uint16_t rrc;
1468 #else
1469 (void) pinfo;
1470 #endif
1471 int checksum_size;
1472 int start_offset=offset;
1475 * The KRB5 blob conforms to RFC4121:
1476 * USHORT (0x0504)
1477 * and so on }
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);
1491 offset += 1;
1493 /* EC */
1494 ec = tvb_get_ntohs(tvb, offset);
1495 proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2, ENC_BIG_ENDIAN);
1496 offset += 2;
1498 /* RRC */
1499 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1500 rrc = tvb_get_ntohs(tvb, offset);
1501 #endif
1502 proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2, ENC_BIG_ENDIAN);
1503 offset += 2;
1505 /* sequence number */
1507 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8, ENC_BIG_ENDIAN);
1508 offset += 8;
1510 if (gssapi_encrypt == NULL) /* Probably shouldn't happen, but just protect ourselves */
1511 return offset;
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;
1521 } else {
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.
1531 checksum_size = ec;
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)
1543 if (rrc == ec) {
1544 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, checksum_size, ENC_NA);
1545 offset += checksum_size;
1547 #endif
1549 returned_offset = offset;
1550 gssapi_encrypt->gssapi_wrap_tvb = tvb_new_subset_length(tvb, offset,
1551 inner_token_len);
1552 gssapi_encrypt->gssapi_decrypted_tvb = tvb_new_subset_length(tvb, offset,
1553 inner_token_len);
1555 offset += inner_token_len;
1557 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1558 if (rrc == 0)
1559 #endif
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){
1577 int len;
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.
1583 return offset;
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
1591 as well ?
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,
1608 pinfo,
1609 checksum_tvb,
1610 gssapi_encrypt,
1612 rrc,
1614 (flags & 0x0001)?
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,
1629 * not before.
1631 return offset;
1635 * XXX - This is for GSSAPI CFX GetMIC tokens ...
1637 static int
1638 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1640 uint8_t flags;
1641 int checksum_size;
1644 * The KRB5 blob conforms to RFC4121:
1645 * USHORT (0x0404 == GSS_GetMIC)
1646 * and so on }
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);
1655 offset += 5;
1657 /* sequence number */
1659 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8, ENC_BIG_ENDIAN);
1660 offset += 8;
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.
1676 return offset;
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.
1686 static int
1687 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
1689 proto_item *item;
1690 proto_tree *subtree;
1691 int offset = 0;
1692 uint16_t token_id;
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)
1702 * and so on }
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);
1710 offset += 2;
1712 switch (token_id) {
1713 case KRB_TOKEN_GETMIC:
1714 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
1715 break;
1717 case KRB_TOKEN_WRAP:
1718 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id, encrypt_info);
1719 break;
1721 case KRB_TOKEN_CFX_GETMIC:
1722 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
1723 break;
1725 case KRB_TOKEN_CFX_WRAP:
1726 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id, encrypt_info);
1727 break;
1729 default:
1731 break;
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);
1741 return offset;
1744 /* Spnego stuff from here */
1746 static int
1747 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1749 proto_item *item;
1750 proto_tree *subtree;
1751 int offset = 0;
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);
1777 return offset;
1781 static int
1782 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
1784 proto_item *item;
1785 proto_tree *subtree;
1786 int offset = 0;
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);
1806 if (conversation) {
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",
1856 HFILL}},
1857 { &hf_spnego_krb5,
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,
1909 NULL, HFILL }},
1910 { &hf_spnego_negTokenTarg,
1911 { "negTokenTarg", "spnego.negTokenTarg_element",
1912 FT_NONE, BASE_NONE, NULL, 0,
1913 NULL, HFILL }},
1914 { &hf_spnego_MechTypeList_item,
1915 { "MechType", "spnego.MechType",
1916 FT_OID, BASE_NONE, NULL, 0,
1917 NULL, HFILL }},
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,
1929 NULL, HFILL }},
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,
1949 NULL, HFILL }},
1950 { &hf_spnego_negResult,
1951 { "negResult", "spnego.negResult",
1952 FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
1953 NULL, HFILL }},
1954 { &hf_spnego_supportedMech,
1955 { "supportedMech", "spnego.supportedMech",
1956 FT_OID, BASE_NONE, NULL, 0,
1957 NULL, HFILL }},
1958 { &hf_spnego_responseToken,
1959 { "responseToken", "spnego.responseToken",
1960 FT_BYTES, BASE_NONE, NULL, 0,
1961 NULL, HFILL }},
1962 { &hf_spnego_mechListMIC_01,
1963 { "mechListMIC", "spnego.mechListMIC",
1964 FT_BYTES, BASE_NONE, NULL, 0,
1965 NULL, HFILL }},
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,
1973 NULL, HFILL }},
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,
1985 NULL, HFILL }},
1986 { &hf_spnego_ContextFlags_mutualFlag,
1987 { "mutualFlag", "spnego.ContextFlags.mutualFlag",
1988 FT_BOOLEAN, 8, NULL, 0x40,
1989 NULL, HFILL }},
1990 { &hf_spnego_ContextFlags_replayFlag,
1991 { "replayFlag", "spnego.ContextFlags.replayFlag",
1992 FT_BOOLEAN, 8, NULL, 0x20,
1993 NULL, HFILL }},
1994 { &hf_spnego_ContextFlags_sequenceFlag,
1995 { "sequenceFlag", "spnego.ContextFlags.sequenceFlag",
1996 FT_BOOLEAN, 8, NULL, 0x10,
1997 NULL, HFILL }},
1998 { &hf_spnego_ContextFlags_anonFlag,
1999 { "anonFlag", "spnego.ContextFlags.anonFlag",
2000 FT_BOOLEAN, 8, NULL, 0x08,
2001 NULL, HFILL }},
2002 { &hf_spnego_ContextFlags_confFlag,
2003 { "confFlag", "spnego.ContextFlags.confFlag",
2004 FT_BOOLEAN, 8, NULL, 0x04,
2005 NULL, HFILL }},
2006 { &hf_spnego_ContextFlags_integFlag,
2007 { "integFlag", "spnego.ContextFlags.integFlag",
2008 FT_BOOLEAN, 8, NULL, 0x02,
2009 NULL, HFILL }},
2012 /* List of subtrees */
2013 static int *ett[] = {
2014 &ett_spnego,
2015 &ett_spnego_wraptoken,
2016 &ett_spnego_krb5,
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,
2085 "KRB5 - IAKERB");
2089 * Editor modelines
2091 * Local Variables:
2092 * c-basic-offset: 2
2093 * tab-width: 8
2094 * indent-tabs-mode: nil
2095 * End:
2097 * ex: set shiftwidth=2 tabstop=8 expandtab:
2098 * :indentSize=2:tabSize=8:noTabs=true: