1 /* Do not modify this file. */
2 /* It is created automatically by the ASN.1 to Ethereal dissector compiler */
3 /* ./packet-spnego.c */
4 /* ../../tools/asn2eth.py -X -b -e -p spnego -c spnego.cnf -s packet-spnego-template spnego.asn */
6 /* Input file: packet-spnego-template.c */
9 * Routines for the simple and protected GSS-API negotiation mechanism
10 * as described in RFC 2478.
11 * Copyright 2002, Tim Potter <tpot@samba.org>
12 * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
13 * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
14 * Copyright 2005, Ronnie Sahlberg (krb decryption)
15 * Copyright 2005, Anders Broman (converted to asn2eth generated dissector)
19 * Ethereal - Network traffic analyzer
20 * By Gerald Combs <gerald@ethereal.com>
21 * Copyright 1998 Gerald Combs
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
38 Heimdal 1.6 and has been modified for ethereal's requirements.
46 #include <epan/packet.h>
47 #include "packet-dcerpc.h"
48 #include "packet-gssapi.h"
49 #include "packet-kerberos.h"
50 #include <epan/crypt-rc4.h>
51 #include <epan/conversation.h>
52 #include <epan/emem.h>
57 #include "packet-ber.h"
60 #define PNAME "Simple Protected Negotiation"
61 #define PSNAME "SPNEGO"
62 #define PFNAME "spnego"
64 /* Initialize the protocol and registered fields */
65 static int proto_spnego = -1;
66 static int proto_spnego_krb5 = -1;
69 static int hf_spnego = -1;
70 static int hf_spnego_wraptoken = -1;
71 static int hf_spnego_krb5_oid;
72 static int hf_spnego_krb5 = -1;
73 static int hf_spnego_krb5_tok_id = -1;
74 static int hf_spnego_krb5_sgn_alg = -1;
75 static int hf_spnego_krb5_seal_alg = -1;
76 static int hf_spnego_krb5_snd_seq = -1;
77 static int hf_spnego_krb5_sgn_cksum = -1;
78 static int hf_spnego_krb5_confounder = -1;
81 /*--- Included file: packet-spnego-hf.c ---*/
83 static int hf_spnego_negTokenInit = -1; /* NegTokenInit */
84 static int hf_spnego_negTokenTarg = -1; /* NegTokenTarg */
85 static int hf_spnego_MechTypeList_item = -1; /* MechType */
86 static int hf_spnego_mechTypes = -1; /* MechTypeList */
87 static int hf_spnego_reqFlags = -1; /* ContextFlags */
88 static int hf_spnego_mechToken = -1; /* T_mechToken */
89 static int hf_spnego_mechListMIC = -1; /* OCTET_STRING */
90 static int hf_spnego_negResult = -1; /* T_negResult */
91 static int hf_spnego_supportedMech = -1; /* MechType */
92 static int hf_spnego_responseToken = -1; /* OCTET_STRING */
93 static int hf_spnego_thisMech = -1; /* MechType */
94 static int hf_spnego_innerContextToken = -1; /* InnerContextToken */
96 static int hf_spnego_ContextFlags_delegFlag = -1;
97 static int hf_spnego_ContextFlags_mutualFlag = -1;
98 static int hf_spnego_ContextFlags_replayFlag = -1;
99 static int hf_spnego_ContextFlags_sequenceFlag = -1;
100 static int hf_spnego_ContextFlags_anonFlag = -1;
101 static int hf_spnego_ContextFlags_confFlag = -1;
102 static int hf_spnego_ContextFlags_integFlag = -1;
104 /*--- End of included file: packet-spnego-hf.c ---*/
107 /* Global variables */
108 gchar MechType_oid[MAX_OID_STR_LEN];
109 gssapi_oid_value *next_level_value;
110 gboolean saw_mechanism = FALSE;
113 /* Initialize the subtree pointers */
114 static gint ett_spnego;
115 static gint ett_spnego_wraptoken;
116 static gint ett_spnego_krb5 = -1;
119 /*--- Included file: packet-spnego-ett.c ---*/
121 static gint ett_spnego_NegotiationToken = -1;
122 static gint ett_spnego_MechTypeList = -1;
123 static gint ett_spnego_NegTokenInit = -1;
124 static gint ett_spnego_ContextFlags = -1;
125 static gint ett_spnego_NegTokenTarg = -1;
126 static gint ett_spnego_InitialContextToken = -1;
128 /*--- End of included file: packet-spnego-ett.c ---*/
131 static dissector_handle_t data_handle;
133 static dissector_handle_t
135 gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
136 if (next_level_value == NULL) {
139 return next_level_value->handle;
144 /*--- Included file: packet-spnego-fn.c ---*/
146 /*--- Fields for imported types ---*/
152 dissect_spnego_MechType(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
154 gssapi_oid_value *value;
156 offset = dissect_ber_object_identifier(implicit_tag, pinfo, tree, tvb, offset, hf_index,
160 value = gssapi_lookup_oid_str(MechType_oid);
163 * Tell our caller the first mechanism we see, so that if
164 * this is a negTokenInit with a mechToken, it can interpret
165 * the mechToken according to the first mechType. (There
166 * might not have been any indication of the mechType
167 * in prior frames, so we can't necessarily use the
168 * mechanism from the conversation; i.e., a negTokenInit
169 * can contain the initial security token for the desired
170 * mechanism of the initiator - that's the first mechanism
173 if (!saw_mechanism) {
175 next_level_value = value;
176 saw_mechanism = TRUE;
182 static int dissect_MechTypeList_item(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
183 return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_MechTypeList_item);
185 static int dissect_supportedMech(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
186 return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_supportedMech);
188 static int dissect_thisMech(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
189 return dissect_spnego_MechType(FALSE, tvb, offset, pinfo, tree, hf_spnego_thisMech);
193 static const ber_sequence_t MechTypeList_sequence_of[1] = {
194 { BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_MechTypeList_item },
198 dissect_spnego_MechTypeList(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
201 saw_mechanism = FALSE;
203 offset = dissect_ber_sequence_of(implicit_tag, pinfo, tree, tvb, offset,
204 MechTypeList_sequence_of, hf_index, ett_spnego_MechTypeList);
208 static int dissect_mechTypes(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
209 return dissect_spnego_MechTypeList(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechTypes);
213 static const asn_namedbit ContextFlags_bits[] = {
214 { 0, &hf_spnego_ContextFlags_delegFlag, -1, -1, "delegFlag", NULL },
215 { 1, &hf_spnego_ContextFlags_mutualFlag, -1, -1, "mutualFlag", NULL },
216 { 2, &hf_spnego_ContextFlags_replayFlag, -1, -1, "replayFlag", NULL },
217 { 3, &hf_spnego_ContextFlags_sequenceFlag, -1, -1, "sequenceFlag", NULL },
218 { 4, &hf_spnego_ContextFlags_anonFlag, -1, -1, "anonFlag", NULL },
219 { 5, &hf_spnego_ContextFlags_confFlag, -1, -1, "confFlag", NULL },
220 { 6, &hf_spnego_ContextFlags_integFlag, -1, -1, "integFlag", NULL },
221 { 0, NULL, 0, 0, NULL, NULL }
225 dissect_spnego_ContextFlags(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
226 offset = dissect_ber_bitstring(implicit_tag, pinfo, tree, tvb, offset,
227 ContextFlags_bits, hf_index, ett_spnego_ContextFlags,
232 static int dissect_reqFlags(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
233 return dissect_spnego_ContextFlags(FALSE, tvb, offset, pinfo, tree, hf_spnego_reqFlags);
239 dissect_spnego_T_mechToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
241 tvbuff_t *mechToken_tvb = NULL;
244 offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index,
248 if (! mechToken_tvb) {
249 THROW(ReportedBoundsError);
253 * Now, we should be able to dispatch after creating a new TVB.
256 if (next_level_value)
257 call_dissector(gssapi_dissector_handle(next_level_value), mechToken_tvb, pinfo, tree);
263 static int dissect_mechToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
264 return dissect_spnego_T_mechToken(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechToken);
270 dissect_spnego_OCTET_STRING(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
271 offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index,
276 static int dissect_mechListMIC(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
277 return dissect_spnego_OCTET_STRING(FALSE, tvb, offset, pinfo, tree, hf_spnego_mechListMIC);
279 static int dissect_responseToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
280 return dissect_spnego_OCTET_STRING(FALSE, tvb, offset, pinfo, tree, hf_spnego_responseToken);
284 static const ber_sequence_t NegTokenInit_sequence[] = {
285 { BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_mechTypes },
286 { BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_reqFlags },
287 { BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_mechToken },
288 { BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_mechListMIC },
293 dissect_spnego_NegTokenInit(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
294 offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
295 NegTokenInit_sequence, hf_index, ett_spnego_NegTokenInit);
299 static int dissect_negTokenInit(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
300 return dissect_spnego_NegTokenInit(FALSE, tvb, offset, pinfo, tree, hf_spnego_negTokenInit);
304 static const value_string spnego_T_negResult_vals[] = {
305 { 0, "accept-completed" },
306 { 1, "accept-incomplete" },
313 dissect_spnego_T_negResult(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
314 offset = dissect_ber_integer(implicit_tag, pinfo, tree, tvb, offset, hf_index,
319 static int dissect_negResult(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
320 return dissect_spnego_T_negResult(FALSE, tvb, offset, pinfo, tree, hf_spnego_negResult);
324 static const ber_sequence_t NegTokenTarg_sequence[] = {
325 { BER_CLASS_CON, 0, BER_FLAGS_OPTIONAL, dissect_negResult },
326 { BER_CLASS_CON, 1, BER_FLAGS_OPTIONAL, dissect_supportedMech },
327 { BER_CLASS_CON, 2, BER_FLAGS_OPTIONAL, dissect_responseToken },
328 { BER_CLASS_CON, 3, BER_FLAGS_OPTIONAL, dissect_mechListMIC },
333 dissect_spnego_NegTokenTarg(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
334 offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
335 NegTokenTarg_sequence, hf_index, ett_spnego_NegTokenTarg);
339 static int dissect_negTokenTarg(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
340 return dissect_spnego_NegTokenTarg(FALSE, tvb, offset, pinfo, tree, hf_spnego_negTokenTarg);
344 static const value_string spnego_NegotiationToken_vals[] = {
345 { 0, "negTokenInit" },
346 { 1, "negTokenTarg" },
350 static const ber_choice_t NegotiationToken_choice[] = {
351 { 0, BER_CLASS_CON, 0, 0, dissect_negTokenInit },
352 { 1, BER_CLASS_CON, 1, 0, dissect_negTokenTarg },
357 dissect_spnego_NegotiationToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
358 offset = dissect_ber_choice(pinfo, tree, tvb, offset,
359 NegotiationToken_choice, hf_index, ett_spnego_NegotiationToken,
368 dissect_spnego_InnerContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
370 conversation_t *conversation;
371 gssapi_oid_value *next_level_value;
377 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
378 if (!next_level_value && !pinfo->fd->flags.visited) {
380 * No handle attached to this frame, but it's the first
381 * pass, so it'd be attached to the conversation.
382 * If we have a conversation, try to get the handle,
383 * and if we get one, attach it to the frame.
385 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
386 pinfo->ptype, pinfo->srcport,
390 next_level_value = conversation_get_proto_data(conversation,
392 if (next_level_value)
393 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
397 next_level_value = gssapi_lookup_oid_str(MechType_oid);
399 * Now dissect the GSS_Wrap token; it's assumed to be in the
400 * rest of the tvbuff.
402 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset,
405 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
408 * Now, we should be able to dispatch after creating a new TVB.
409 * The subdissector must return the length of the part of the
410 * token it dissected, so we can return the length of the part
411 * we (and it) dissected.
414 token_tvb = tvb_new_subset(tvb, offset, -1, -1);
415 if (next_level_value->wrap_handle) {
416 len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
418 offset = tvb_length(tvb);
420 offset = offset + len;
423 offset = tvb_length(tvb);
429 static int dissect_innerContextToken(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {
430 return dissect_spnego_InnerContextToken(FALSE, tvb, offset, pinfo, tree, hf_spnego_innerContextToken);
434 static const ber_sequence_t InitialContextToken_sequence[] = {
435 { BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_thisMech },
436 { BER_CLASS_ANY, 0, BER_FLAGS_NOOWNTAG, dissect_innerContextToken },
441 dissect_spnego_InitialContextToken(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {
442 offset = dissect_ber_sequence(implicit_tag, pinfo, tree, tvb, offset,
443 InitialContextToken_sequence, hf_index, ett_spnego_InitialContextToken);
449 /*--- End of included file: packet-spnego-fn.c ---*/
452 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
453 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
454 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
457 #define KRB_TOKEN_AP_REQ 0x0001
458 #define KRB_TOKEN_AP_REP 0x0002
459 #define KRB_TOKEN_AP_ERR 0x0003
460 #define KRB_TOKEN_GETMIC 0x0101
461 #define KRB_TOKEN_WRAP 0x0102
462 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
464 static const value_string spnego_krb5_tok_id_vals[] = {
465 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
466 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
467 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
468 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
469 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
470 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
474 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
475 #define KRB_SGN_ALG_MD2_5 0x0001
476 #define KRB_SGN_ALG_DES_MAC 0x0002
477 #define KRB_SGN_ALG_HMAC 0x0011
479 static const value_string spnego_krb5_sgn_alg_vals[] = {
480 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
481 { KRB_SGN_ALG_MD2_5, "MD2.5"},
482 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
483 { KRB_SGN_ALG_HMAC, "HMAC"},
487 #define KRB_SEAL_ALG_DES_CBC 0x0000
488 #define KRB_SEAL_ALG_RC4 0x0010
489 #define KRB_SEAL_ALG_NONE 0xffff
491 static const value_string spnego_krb5_seal_alg_vals[] = {
492 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
493 { KRB_SEAL_ALG_RC4, "RC4"},
494 { KRB_SEAL_ALG_NONE, "None"},
499 * XXX - is this for SPNEGO or just GSS-API?
500 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
501 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
502 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
503 * getting it accepted.
506 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
508 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
511 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
517 gchar oid[MAX_OID_STR_LEN];
518 gssapi_oid_value *value;
521 gboolean pc, ind = 0;
526 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
529 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
532 * The KRB5 blob conforms to RFC1964:
535 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
538 * However, for some protocols, the KRB5 blob starts at the SHORT
539 * and has no DER encoded header etc.
541 * It appears that for some other protocols the KRB5 blob is just
542 * a Kerberos message, with no [APPLICATION 0] header, no OID,
547 * If we see an [APPLICATION 0] HEADER, we show the OID and
548 * the USHORT, and then dissect the rest as a Kerberos message.
550 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
551 * we assume it's an AP-REQ or AP-REP message, and dissect
552 * it all as a Kerberos message.
554 * Otherwise, we show the USHORT, and then dissect the rest
555 * as a Kerberos message.
559 * Get the first header ...
561 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
562 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
564 if (class == BER_CLASS_APP && pc == 1) {
566 * [APPLICATION <tag>]
576 offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_krb5_oid, oid);
578 value = gssapi_lookup_oid_str(oid);
580 token_id = tvb_get_letohs(tvb, offset);
581 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
588 case 14: /* [APPLICATION 14] */
589 case 15: /* [APPLICATION 15] */
591 * No token ID - just dissect as a Kerberos message and
594 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
598 proto_tree_add_text(subtree, tvb, offset, 0,
599 "Unknown header (class=%d, pc=%d, tag=%d)",
604 /* Next, the token ID ... */
606 token_id = tvb_get_letohs(tvb, offset);
607 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
615 case KRB_TOKEN_AP_REQ:
616 case KRB_TOKEN_AP_REP:
617 case KRB_TOKEN_AP_ERR:
618 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
619 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
622 case KRB_TOKEN_GETMIC:
623 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
627 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
630 case KRB_TOKEN_DELETE_SEC_CONTEXT:
644 #include <epan/crypt-md5.h>
646 #ifndef KEYTYPE_ARCFOUR_56
647 # define KEYTYPE_ARCFOUR_56 24
649 /* XXX - We should probably do a configure-time check for this instead */
650 #ifndef KRB5_KU_USAGE_SEAL
651 # define KRB5_KU_USAGE_SEAL 22
655 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
656 void *cksum_data, size_t cksum_size,
664 if (key_type == KEYTYPE_ARCFOUR_56) {
665 guint8 L40[14] = "fortybits";
667 memcpy(L40 + 10, T, sizeof(T));
673 memset(&k5_data[7], 0xAB, 9);
683 cksum_data, cksum_size,
692 usage2arcfour(int usage)
695 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
696 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
698 case 22: /*KRB5_KU_USAGE_SEAL 22 */
700 case 23: /*KRB5_KU_USAGE_SIGN 23 */
702 case 24: /*KRB5_KU_USAGE_SEQ 24 */
710 arcfour_mic_cksum(guint8 *key_data, int key_length,
713 const void *v1, size_t l1,
714 const void *v2, size_t l2,
715 const void *v3, size_t l3)
717 const guint8 signature[] = "signaturekey";
721 unsigned char digest[16];
725 rc4_usage=usage2arcfour(usage);
726 md5_hmac(signature, sizeof(signature),
727 key_data, key_length,
730 t[0] = (rc4_usage >> 0) & 0xFF;
731 t[1] = (rc4_usage >> 8) & 0xFF;
732 t[2] = (rc4_usage >> 16) & 0xFF;
733 t[3] = (rc4_usage >> 24) & 0xFF;
734 md5_append(&ms, t, 4);
735 md5_append(&ms, v1, l1);
736 md5_append(&ms, v2, l2);
737 md5_append(&ms, v3, l3);
738 md5_finish(&ms, digest);
739 md5_hmac(digest, 16, ksign_c, 16, cksum);
741 memcpy(sgn_cksum, cksum, 8);
747 * Verify padding of a gss wrapped message and return its length.
750 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
758 pad = wrapped_data + wrapped_length - 1;
761 if (padlength > datalen)
764 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
775 decrypt_arcfour(packet_info *pinfo,
776 guint8 *input_message_buffer,
777 guint8 *output_message_buffer,
778 guint8 *key_value, int key_size, int key_type)
780 guint8 Klocaldata[16];
784 guint8 k6_data[16], SND_SEQ[8], Confounder[8];
785 guint8 cksum_data[8];
790 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
792 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
794 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
800 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
804 ret = arcfour_mic_key(key_value, key_size, key_type,
805 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
813 rc4_state_struct rc4_state;
815 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
816 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
817 crypt_rc4(&rc4_state, SND_SEQ, 8);
819 memset(k6_data, 0, sizeof(k6_data));
822 seq_number=g_ntohl(*((guint32 *)SND_SEQ));
824 cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
826 cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
836 for (i = 0; i < 16; i++)
837 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
839 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
842 memset(Klocaldata, 0, sizeof(Klocaldata));
848 rc4_state_struct rc4_state;
850 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
851 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
852 crypt_rc4(&rc4_state, Confounder, 8);
853 memcpy(output_message_buffer, input_message_buffer, datalen);
854 crypt_rc4(&rc4_state, output_message_buffer, datalen);
857 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
859 memcpy(output_message_buffer,
860 input_message_buffer,
863 memset(k6_data, 0, sizeof(k6_data));
865 /* only normal (i.e. non DCE style wrapping use padding ? */
866 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
867 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
874 /* dont know what the checksum looks like for dce style gssapi */
875 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
876 ret = arcfour_mic_cksum(key_value, key_size,
879 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
880 Confounder, sizeof(Confounder),
881 output_message_buffer,
887 cmp = memcmp(cksum_data,
888 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
900 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
903 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
908 const guint8 *original_data;
910 static int omb_index=0;
911 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
912 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
913 guint8 *output_message_buffer;
919 output_message_buffer=omb_arr[omb_index];
922 length=tvb_length(pinfo->gssapi_encrypted_tvb);
923 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
925 /* dont do anything if we are not attempting to decrypt data */
931 /* XXX we should only do this for first time, then store somewhere */
932 /* XXX We also need to re-read the keytab when the preference changes */
934 cryptocopy=ep_alloc(length);
935 if(output_message_buffer){
936 g_free(output_message_buffer);
937 output_message_buffer=NULL;
939 output_message_buffer=g_malloc(length);
941 for(ek=enc_key_list;ek;ek=ek->next){
942 /* shortcircuit and bail out if enctypes are not matching */
943 if(ek->keytype!=keytype){
947 /* pre-0.6.1 versions of Heimdal would sometimes change
948 the cryptotext data even when the decryption failed.
949 This would obviously not work since we iterate over the
950 keys. So just give it a copy of the crypto data instead.
951 This has been seen for RC4-HMAC blobs.
953 memcpy(cryptocopy, original_data, length);
954 ret=decrypt_arcfour(pinfo,
956 output_message_buffer,
962 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
963 pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
964 output_message_buffer,
966 tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
967 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
973 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
979 * XXX - This is for GSSAPI Wrap tokens ...
982 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
983 #ifndef HAVE_KERBEROS
986 , proto_tree *tree, guint16 token_id
987 #ifndef HAVE_KERBEROS
992 guint16 sgn_alg, seal_alg;
994 int start_offset=offset;
998 * The KRB5 blob conforms to RFC1964:
999 * USHORT (0x0102 == GSS_Wrap)
1003 /* Now, the sign and seal algorithms ... */
1005 sgn_alg = tvb_get_letohs(tvb, offset);
1006 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1011 seal_alg = tvb_get_letohs(tvb, offset);
1012 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
1017 /* Skip the filler */
1021 /* Encrypted sequence number */
1023 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1028 /* Checksum of plaintext padded data */
1030 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1036 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1037 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1038 * extra 8 bytes of "Random confounder" after the checksum.
1039 * It certainly confounds code expecting all Kerberos 5
1040 * GSS_Wrap() tokens to look the same....
1042 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1043 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1048 /* Is the data encrypted? */
1049 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
1051 #ifdef HAVE_KERBEROS
1052 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
1053 if(pinfo->decrypt_gssapi_tvb){
1054 /* if the caller did not provide a tvb, then we just use
1055 whatever is left of our current tvb.
1057 if(!pinfo->gssapi_encrypted_tvb){
1059 len=tvb_reported_length_remaining(tvb,offset);
1060 if(len>tvb_length_remaining(tvb, offset)){
1061 /* no point in trying to decrypt,
1062 we dont have the full pdu.
1066 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1067 tvb, offset, len, len);
1070 /* if this is KRB5 wrapped rc4-hmac */
1071 if((token_id==KRB_TOKEN_WRAP)
1072 &&(sgn_alg==KRB_SGN_ALG_HMAC)
1073 &&(seal_alg==KRB_SEAL_ALG_RC4)){
1074 /* do we need to create a tvb for the wrapper
1077 if(!pinfo->gssapi_wrap_tvb){
1078 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1079 tvb, start_offset-2,
1080 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
1081 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
1083 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1084 decrypt_gssapi_krb_arcfour_wrap(tree,
1088 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1093 * Return the offset past the checksum, so that we know where
1094 * the data we're wrapped around starts. Also, set the length
1095 * of our top-level item to that offset, so it doesn't cover
1096 * the data we're wrapped around.
1098 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1105 * XXX - This is for GSSAPI GetMIC tokens ...
1108 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1113 * The KRB5 blob conforms to RFC1964:
1114 * USHORT (0x0101 == GSS_GetMIC)
1118 /* Now, the sign algorithm ... */
1120 sgn_alg = tvb_get_letohs(tvb, offset);
1121 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
1126 /* Skip the filler */
1130 /* Encrypted sequence number */
1132 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
1137 /* Checksum of plaintext padded data */
1139 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
1145 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
1146 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
1147 * extra 8 bytes of "Random confounder" after the checksum.
1148 * It certainly confounds code expecting all Kerberos 5
1149 * GSS_Wrap() tokens to look the same....
1151 if (sgn_alg == KRB_SGN_ALG_HMAC) {
1152 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
1159 * Return the offset past the checksum, so that we know where
1160 * the data we're wrapped around starts. Also, set the length
1161 * of our top-level item to that offset, so it doesn't cover
1162 * the data we're wrapped around.
1169 * XXX - is this for SPNEGO or just GSS-API?
1170 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1171 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1172 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1173 * getting it accepted.
1176 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1179 proto_tree *subtree;
1183 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
1185 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1188 * The KRB5 blob conforms to RFC1964:
1189 * USHORT (0x0102 == GSS_Wrap)
1193 /* First, the token ID ... */
1195 token_id = tvb_get_letohs(tvb, offset);
1196 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1201 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1204 * Return the offset past the checksum, so that we know where
1205 * the data we're wrapped around starts. Also, set the length
1206 * of our top-level item to that offset, so it doesn't cover
1207 * the data we're wrapped around.
1209 proto_item_set_len(item, offset);
1213 /* Spnego stuff from here */
1216 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1219 proto_tree *subtree;
1225 * We need this later, so lets get it now ...
1226 * It has to be per-frame as there can be more than one GSS-API
1227 * negotiation in a conversation.
1231 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1234 subtree = proto_item_add_subtree(item, ett_spnego);
1236 * The TVB contains a [0] header and a sequence that consists of an
1237 * object ID and a blob containing the data ...
1238 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1239 * with the "optional" "use in non-initial tokens" being chosen.
1240 * ASN1 code addet to spnego.asn to handle this.
1243 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, pinfo , subtree, -1);
1250 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1253 proto_tree *subtree;
1255 conversation_t *conversation;
1258 * We need this later, so lets get it now ...
1259 * It has to be per-frame as there can be more than one GSS-API
1260 * negotiation in a conversation.
1263 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1264 if (!next_level_value && !pinfo->fd->flags.visited) {
1266 * No handle attached to this frame, but it's the first
1267 * pass, so it'd be attached to the conversation.
1268 * If we have a conversation, try to get the handle,
1269 * and if we get one, attach it to the frame.
1271 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1272 pinfo->ptype, pinfo->srcport,
1273 pinfo->destport, 0);
1276 next_level_value = conversation_get_proto_data(conversation,
1278 if (next_level_value)
1279 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1283 item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset,
1286 subtree = proto_item_add_subtree(item, ett_spnego);
1289 * The TVB contains a [0] header and a sequence that consists of an
1290 * object ID and a blob containing the data ...
1291 * Actually, it contains, according to RFC2478:
1292 * NegotiationToken ::= CHOICE {
1293 * negTokenInit [0] NegTokenInit,
1294 * negTokenTarg [1] NegTokenTarg }
1295 * NegTokenInit ::= SEQUENCE {
1296 * mechTypes [0] MechTypeList OPTIONAL,
1297 * reqFlags [1] ContextFlags OPTIONAL,
1298 * mechToken [2] OCTET STRING OPTIONAL,
1299 * mechListMIC [3] OCTET STRING OPTIONAL }
1300 * NegTokenTarg ::= SEQUENCE {
1301 * negResult [0] ENUMERATED {
1302 * accept_completed (0),
1303 * accept_incomplete (1),
1304 * reject (2) } OPTIONAL,
1305 * supportedMech [1] MechType OPTIONAL,
1306 * responseToken [2] OCTET STRING OPTIONAL,
1307 * mechListMIC [3] OCTET STRING OPTIONAL }
1309 * Windows typically includes mechTypes and mechListMic ('NONE'
1310 * in the case of NTLMSSP only).
1311 * It seems to duplicate the responseToken into the mechListMic field
1312 * as well. Naughty, naughty.
1315 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, pinfo, subtree, -1);
1319 /*--- proto_register_spnego -------------------------------------------*/
1320 void proto_register_spnego(void) {
1322 /* List of fields */
1323 static hf_register_info hf[] = {
1325 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1327 { &hf_spnego_wraptoken,
1328 { "wrapToken", "spnego.wraptoken",
1329 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1332 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1333 BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1334 {&hf_spnego_krb5_oid,
1335 {"KRB5 OID", "spnego.krb5_oid", FT_STRING,
1336 BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
1337 { &hf_spnego_krb5_tok_id,
1338 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1339 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1340 { &hf_spnego_krb5_sgn_alg,
1341 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1342 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1343 { &hf_spnego_krb5_seal_alg,
1344 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1345 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1346 { &hf_spnego_krb5_snd_seq,
1347 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1348 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1349 { &hf_spnego_krb5_sgn_cksum,
1350 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1351 NULL, 0, "KRB5 Data Checksum", HFILL}},
1352 { &hf_spnego_krb5_confounder,
1353 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1354 NULL, 0, "KRB5 Confounder", HFILL}},
1357 /*--- Included file: packet-spnego-hfarr.c ---*/
1359 { &hf_spnego_negTokenInit,
1360 { "negTokenInit", "spnego.negTokenInit",
1361 FT_NONE, BASE_NONE, NULL, 0,
1362 "NegotiationToken/negTokenInit", HFILL }},
1363 { &hf_spnego_negTokenTarg,
1364 { "negTokenTarg", "spnego.negTokenTarg",
1365 FT_NONE, BASE_NONE, NULL, 0,
1366 "NegotiationToken/negTokenTarg", HFILL }},
1367 { &hf_spnego_MechTypeList_item,
1368 { "Item", "spnego.MechTypeList_item",
1369 FT_STRING, BASE_NONE, NULL, 0,
1370 "MechTypeList/_item", HFILL }},
1371 { &hf_spnego_mechTypes,
1372 { "mechTypes", "spnego.mechTypes",
1373 FT_UINT32, BASE_DEC, NULL, 0,
1374 "NegTokenInit/mechTypes", HFILL }},
1375 { &hf_spnego_reqFlags,
1376 { "reqFlags", "spnego.reqFlags",
1377 FT_BYTES, BASE_HEX, NULL, 0,
1378 "NegTokenInit/reqFlags", HFILL }},
1379 { &hf_spnego_mechToken,
1380 { "mechToken", "spnego.mechToken",
1381 FT_BYTES, BASE_HEX, NULL, 0,
1382 "NegTokenInit/mechToken", HFILL }},
1383 { &hf_spnego_mechListMIC,
1384 { "mechListMIC", "spnego.mechListMIC",
1385 FT_BYTES, BASE_HEX, NULL, 0,
1387 { &hf_spnego_negResult,
1388 { "negResult", "spnego.negResult",
1389 FT_UINT32, BASE_DEC, VALS(spnego_T_negResult_vals), 0,
1390 "NegTokenTarg/negResult", HFILL }},
1391 { &hf_spnego_supportedMech,
1392 { "supportedMech", "spnego.supportedMech",
1393 FT_STRING, BASE_NONE, NULL, 0,
1394 "NegTokenTarg/supportedMech", HFILL }},
1395 { &hf_spnego_responseToken,
1396 { "responseToken", "spnego.responseToken",
1397 FT_BYTES, BASE_HEX, NULL, 0,
1398 "NegTokenTarg/responseToken", HFILL }},
1399 { &hf_spnego_thisMech,
1400 { "thisMech", "spnego.thisMech",
1401 FT_STRING, BASE_NONE, NULL, 0,
1402 "InitialContextToken/thisMech", HFILL }},
1403 { &hf_spnego_innerContextToken,
1404 { "innerContextToken", "spnego.innerContextToken",
1405 FT_NONE, BASE_NONE, NULL, 0,
1406 "InitialContextToken/innerContextToken", HFILL }},
1407 { &hf_spnego_ContextFlags_delegFlag,
1408 { "delegFlag", "spnego.delegFlag",
1409 FT_BOOLEAN, 8, NULL, 0x80,
1411 { &hf_spnego_ContextFlags_mutualFlag,
1412 { "mutualFlag", "spnego.mutualFlag",
1413 FT_BOOLEAN, 8, NULL, 0x40,
1415 { &hf_spnego_ContextFlags_replayFlag,
1416 { "replayFlag", "spnego.replayFlag",
1417 FT_BOOLEAN, 8, NULL, 0x20,
1419 { &hf_spnego_ContextFlags_sequenceFlag,
1420 { "sequenceFlag", "spnego.sequenceFlag",
1421 FT_BOOLEAN, 8, NULL, 0x10,
1423 { &hf_spnego_ContextFlags_anonFlag,
1424 { "anonFlag", "spnego.anonFlag",
1425 FT_BOOLEAN, 8, NULL, 0x08,
1427 { &hf_spnego_ContextFlags_confFlag,
1428 { "confFlag", "spnego.confFlag",
1429 FT_BOOLEAN, 8, NULL, 0x04,
1431 { &hf_spnego_ContextFlags_integFlag,
1432 { "integFlag", "spnego.integFlag",
1433 FT_BOOLEAN, 8, NULL, 0x02,
1436 /*--- End of included file: packet-spnego-hfarr.c ---*/
1440 /* List of subtrees */
1441 static gint *ett[] = {
1443 &ett_spnego_wraptoken,
1447 /*--- Included file: packet-spnego-ettarr.c ---*/
1449 &ett_spnego_NegotiationToken,
1450 &ett_spnego_MechTypeList,
1451 &ett_spnego_NegTokenInit,
1452 &ett_spnego_ContextFlags,
1453 &ett_spnego_NegTokenTarg,
1454 &ett_spnego_InitialContextToken,
1456 /*--- End of included file: packet-spnego-ettarr.c ---*/
1460 /* Register protocol */
1461 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1463 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1466 /* Register fields and subtrees */
1467 proto_register_field_array(proto_spnego, hf, array_length(hf));
1468 proto_register_subtree_array(ett, array_length(ett));
1473 /*--- proto_reg_handoff_spnego ---------------------------------------*/
1474 void proto_reg_handoff_spnego(void) {
1476 dissector_handle_t spnego_handle, spnego_wrap_handle;
1477 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1479 /* Register protocol with GSS-API module */
1481 spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
1482 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
1484 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1485 spnego_handle, spnego_wrap_handle,
1486 "SPNEGO - Simple Protected Negotiation");
1488 /* Register both the one MS created and the real one */
1490 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1491 * mystery of the MS KRB5 OID is cleared up. It was due to a library
1492 * that did not handle OID components greater than 16 bits, and was
1493 * fixed in Win2K SP2 as well as WinXP.
1494 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1495 * SPNEGO implementation issues. 3-Dec-2002.
1497 spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
1499 spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
1501 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1502 spnego_krb5_handle, spnego_krb5_wrap_handle,
1503 "MS KRB5 - Microsoft Kerberos 5");
1504 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1505 spnego_krb5_handle, spnego_krb5_wrap_handle,
1506 "KRB5 - Kerberos 5");
1507 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1508 spnego_krb5_handle, spnego_krb5_wrap_handle,
1509 "KRB5 - Kerberos 5 - User to User");
1512 * Find the data handle for some calls
1514 data_handle = find_dissector("data");