2 * Routines for the simple and protected GSS-API negotiation mechanism
3 * as described in RFC 2478.
4 * Copyright 2002, Tim Potter <tpot@samba.org>
5 * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
6 * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
7 * Copyright 2005, Ronnie Sahlberg (krb decryption)
8 * Copyright 2005, Anders Broman (converted to asn2wrs generated dissector)
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 1998 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
31 Heimdal 1.6 and has been modified for wireshark's requirements.
39 #include <epan/packet.h>
40 #include "packet-dcerpc.h"
41 #include "packet-gssapi.h"
42 #include "packet-kerberos.h"
43 #include <epan/crypt-rc4.h>
44 #include <epan/conversation.h>
45 #include <epan/emem.h>
50 #include "packet-ber.h"
53 #define PNAME "Simple Protected Negotiation"
54 #define PSNAME "SPNEGO"
55 #define PFNAME "spnego"
57 /* Initialize the protocol and registered fields */
58 static int proto_spnego = -1;
59 static int proto_spnego_krb5 = -1;
62 static int hf_spnego = -1;
63 static int hf_spnego_wraptoken = -1;
64 static int hf_spnego_krb5_oid;
65 static int hf_spnego_krb5 = -1;
66 static int hf_spnego_krb5_tok_id = -1;
67 static int hf_spnego_krb5_sgn_alg = -1;
68 static int hf_spnego_krb5_seal_alg = -1;
69 static int hf_spnego_krb5_snd_seq = -1;
70 static int hf_spnego_krb5_sgn_cksum = -1;
71 static int hf_spnego_krb5_confounder = -1;
73 #include "packet-spnego-hf.c"
75 /* Global variables */
76 static const char *MechType_oid;
77 gssapi_oid_value *next_level_value;
78 gboolean saw_mechanism = FALSE;
81 /* Initialize the subtree pointers */
82 static gint ett_spnego;
83 static gint ett_spnego_wraptoken;
84 static gint ett_spnego_krb5 = -1;
86 #include "packet-spnego-ett.c"
88 static dissector_handle_t data_handle;
91 * Unfortunately, we have to have a forward declaration of this,
92 * as the code generated by asn2wrs includes a call before the
95 static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
96 int offset, packet_info *pinfo,
97 proto_tree *tree, int hf_index);
99 #include "packet-spnego-fn.c"
101 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
102 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
103 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
106 #define KRB_TOKEN_AP_REQ 0x0001
107 #define KRB_TOKEN_AP_REP 0x0002
108 #define KRB_TOKEN_AP_ERR 0x0003
109 #define KRB_TOKEN_GETMIC 0x0101
110 #define KRB_TOKEN_WRAP 0x0102
111 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
113 static const value_string spnego_krb5_tok_id_vals[] = {
114 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
115 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
116 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
117 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
118 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
119 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
123 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
124 #define KRB_SGN_ALG_MD2_5 0x0001
125 #define KRB_SGN_ALG_DES_MAC 0x0002
126 #define KRB_SGN_ALG_HMAC 0x0011
128 static const value_string spnego_krb5_sgn_alg_vals[] = {
129 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
130 { KRB_SGN_ALG_MD2_5, "MD2.5"},
131 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
132 { KRB_SGN_ALG_HMAC, "HMAC"},
136 #define KRB_SEAL_ALG_DES_CBC 0x0000
137 #define KRB_SEAL_ALG_RC4 0x0010
138 #define KRB_SEAL_ALG_NONE 0xffff
140 static const value_string spnego_krb5_seal_alg_vals[] = {
141 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
142 { KRB_SEAL_ALG_RC4, "RC4"},
143 { KRB_SEAL_ALG_NONE, "None"},
148 * XXX - is this for SPNEGO or just GSS-API?
149 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
150 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
151 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
152 * getting it accepted.
155 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
157 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
160 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
167 gssapi_oid_value *value;
170 gboolean pc, ind = 0;
174 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
177 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
180 * The KRB5 blob conforms to RFC1964:
183 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
186 * However, for some protocols, the KRB5 blob starts at the SHORT
187 * and has no DER encoded header etc.
189 * It appears that for some other protocols the KRB5 blob is just
190 * a Kerberos message, with no [APPLICATION 0] header, no OID,
195 * If we see an [APPLICATION 0] HEADER, we show the OID and
196 * the USHORT, and then dissect the rest as a Kerberos message.
198 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
199 * we assume it's an AP-REQ or AP-REP message, and dissect
200 * it all as a Kerberos message.
202 * Otherwise, we show the USHORT, and then dissect the rest
203 * as a Kerberos message.
207 * Get the first header ...
209 get_ber_identifier(tvb, offset, &class, &pc, &tag);
210 if (class == BER_CLASS_APP && pc) {
212 * [APPLICATION <tag>]
214 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
215 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
225 offset=dissect_ber_object_identifier_str(FALSE, pinfo, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
227 value = gssapi_lookup_oid_str(oid);
229 token_id = tvb_get_letohs(tvb, offset);
230 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
237 case 14: /* [APPLICATION 14] */
238 case 15: /* [APPLICATION 15] */
240 * No token ID - just dissect as a Kerberos message and
243 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
247 proto_tree_add_text(subtree, tvb, offset, 0,
248 "Unknown header (class=%d, pc=%d, tag=%d)",
253 /* Next, the token ID ... */
255 token_id = tvb_get_letohs(tvb, offset);
256 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
264 case KRB_TOKEN_AP_REQ:
265 case KRB_TOKEN_AP_REP:
266 case KRB_TOKEN_AP_ERR:
267 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
268 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
271 case KRB_TOKEN_GETMIC:
272 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
276 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
279 case KRB_TOKEN_DELETE_SEC_CONTEXT:
293 #include <epan/crypt/crypt-md5.h>
295 #ifndef KEYTYPE_ARCFOUR_56
296 # define KEYTYPE_ARCFOUR_56 24
298 /* XXX - We should probably do a configure-time check for this instead */
299 #ifndef KRB5_KU_USAGE_SEAL
300 # define KRB5_KU_USAGE_SEAL 22
304 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
305 void *cksum_data, size_t cksum_size,
313 if (key_type == KEYTYPE_ARCFOUR_56) {
314 guint8 L40[14] = "fortybits";
316 memcpy(L40 + 10, T, sizeof(T));
322 memset(&k5_data[7], 0xAB, 9);
332 cksum_data, cksum_size,
341 usage2arcfour(int usage)
344 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
345 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
347 case 22: /*KRB5_KU_USAGE_SEAL 22 */
349 case 23: /*KRB5_KU_USAGE_SIGN 23 */
351 case 24: /*KRB5_KU_USAGE_SEQ 24 */
359 arcfour_mic_cksum(guint8 *key_data, int key_length,
362 const void *v1, size_t l1,
363 const void *v2, size_t l2,
364 const void *v3, size_t l3)
366 const guint8 signature[] = "signaturekey";
370 unsigned char digest[16];
374 rc4_usage=usage2arcfour(usage);
375 md5_hmac(signature, sizeof(signature),
376 key_data, key_length,
379 t[0] = (rc4_usage >> 0) & 0xFF;
380 t[1] = (rc4_usage >> 8) & 0xFF;
381 t[2] = (rc4_usage >> 16) & 0xFF;
382 t[3] = (rc4_usage >> 24) & 0xFF;
383 md5_append(&ms, t, 4);
384 md5_append(&ms, v1, l1);
385 md5_append(&ms, v2, l2);
386 md5_append(&ms, v3, l3);
387 md5_finish(&ms, digest);
388 md5_hmac(digest, 16, ksign_c, 16, cksum);
390 memcpy(sgn_cksum, cksum, 8);
396 * Verify padding of a gss wrapped message and return its length.
399 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
407 pad = wrapped_data + wrapped_length - 1;
410 if (padlength > datalen)
413 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
424 decrypt_arcfour(packet_info *pinfo,
425 guint8 *input_message_buffer,
426 guint8 *output_message_buffer,
427 guint8 *key_value, int key_size, int key_type)
429 guint8 Klocaldata[16];
433 guint8 k6_data[16], SND_SEQ[8], Confounder[8];
434 guint8 cksum_data[8];
439 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
441 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
443 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
449 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
453 ret = arcfour_mic_key(key_value, key_size, key_type,
454 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
462 rc4_state_struct rc4_state;
464 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
465 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
466 crypt_rc4(&rc4_state, SND_SEQ, 8);
468 memset(k6_data, 0, sizeof(k6_data));
471 seq_number=g_ntohl(*((guint32 *)SND_SEQ));
473 cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
475 cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
485 for (i = 0; i < 16; i++)
486 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
488 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
491 memset(Klocaldata, 0, sizeof(Klocaldata));
497 rc4_state_struct rc4_state;
499 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
500 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
501 crypt_rc4(&rc4_state, Confounder, 8);
502 memcpy(output_message_buffer, input_message_buffer, datalen);
503 crypt_rc4(&rc4_state, output_message_buffer, datalen);
506 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
508 memcpy(output_message_buffer,
509 input_message_buffer,
512 memset(k6_data, 0, sizeof(k6_data));
514 /* only normal (i.e. non DCE style wrapping use padding ? */
515 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
516 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
523 /* dont know what the checksum looks like for dce style gssapi */
524 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
525 ret = arcfour_mic_cksum(key_value, key_size,
528 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
529 Confounder, sizeof(Confounder),
530 output_message_buffer,
536 cmp = memcmp(cksum_data,
537 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
549 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
552 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
557 const guint8 *original_data;
559 static int omb_index=0;
560 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
561 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
562 guint8 *output_message_buffer;
568 output_message_buffer=omb_arr[omb_index];
571 length=tvb_length(pinfo->gssapi_encrypted_tvb);
572 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
574 /* dont do anything if we are not attempting to decrypt data */
580 /* XXX we should only do this for first time, then store somewhere */
581 /* XXX We also need to re-read the keytab when the preference changes */
583 cryptocopy=ep_alloc(length);
584 if(output_message_buffer){
585 g_free(output_message_buffer);
586 output_message_buffer=NULL;
588 output_message_buffer=g_malloc(length);
590 for(ek=enc_key_list;ek;ek=ek->next){
591 /* shortcircuit and bail out if enctypes are not matching */
592 if(ek->keytype!=keytype){
596 /* pre-0.6.1 versions of Heimdal would sometimes change
597 the cryptotext data even when the decryption failed.
598 This would obviously not work since we iterate over the
599 keys. So just give it a copy of the crypto data instead.
600 This has been seen for RC4-HMAC blobs.
602 memcpy(cryptocopy, original_data, length);
603 ret=decrypt_arcfour(pinfo,
605 output_message_buffer,
611 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
612 pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
613 output_message_buffer,
615 tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
616 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
622 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
628 * XXX - This is for GSSAPI Wrap tokens ...
631 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
632 #ifndef HAVE_KERBEROS
635 , proto_tree *tree, guint16 token_id
636 #ifndef HAVE_KERBEROS
641 guint16 sgn_alg, seal_alg;
643 int start_offset=offset;
647 * The KRB5 blob conforms to RFC1964:
648 * USHORT (0x0102 == GSS_Wrap)
652 /* Now, the sign and seal algorithms ... */
654 sgn_alg = tvb_get_letohs(tvb, offset);
655 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
660 seal_alg = tvb_get_letohs(tvb, offset);
661 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
666 /* Skip the filler */
670 /* Encrypted sequence number */
672 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
677 /* Checksum of plaintext padded data */
679 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
685 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
686 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
687 * extra 8 bytes of "Random confounder" after the checksum.
688 * It certainly confounds code expecting all Kerberos 5
689 * GSS_Wrap() tokens to look the same....
691 if (sgn_alg == KRB_SGN_ALG_HMAC) {
692 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
697 /* Is the data encrypted? */
698 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
701 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
702 if(pinfo->decrypt_gssapi_tvb){
703 /* if the caller did not provide a tvb, then we just use
704 whatever is left of our current tvb.
706 if(!pinfo->gssapi_encrypted_tvb){
708 len=tvb_reported_length_remaining(tvb,offset);
709 if(len>tvb_length_remaining(tvb, offset)){
710 /* no point in trying to decrypt,
711 we dont have the full pdu.
715 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
716 tvb, offset, len, len);
719 /* if this is KRB5 wrapped rc4-hmac */
720 if((token_id==KRB_TOKEN_WRAP)
721 &&(sgn_alg==KRB_SGN_ALG_HMAC)
722 &&(seal_alg==KRB_SEAL_ALG_RC4)){
723 /* do we need to create a tvb for the wrapper
726 if(!pinfo->gssapi_wrap_tvb){
727 pinfo->gssapi_wrap_tvb = tvb_new_subset(
729 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
730 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
732 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
733 decrypt_gssapi_krb_arcfour_wrap(tree,
737 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
742 * Return the offset past the checksum, so that we know where
743 * the data we're wrapped around starts. Also, set the length
744 * of our top-level item to that offset, so it doesn't cover
745 * the data we're wrapped around.
747 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
754 * XXX - This is for GSSAPI GetMIC tokens ...
757 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
762 * The KRB5 blob conforms to RFC1964:
763 * USHORT (0x0101 == GSS_GetMIC)
767 /* Now, the sign algorithm ... */
769 sgn_alg = tvb_get_letohs(tvb, offset);
770 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
775 /* Skip the filler */
779 /* Encrypted sequence number */
781 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
786 /* Checksum of plaintext padded data */
788 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
794 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
795 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
796 * extra 8 bytes of "Random confounder" after the checksum.
797 * It certainly confounds code expecting all Kerberos 5
798 * GSS_Wrap() tokens to look the same....
800 * The exception is DNS/TSIG where there is no such confounder
801 * so we need to test here if there are more bytes in our tvb or not.
804 if (tvb_length_remaining(tvb, offset)) {
805 if (sgn_alg == KRB_SGN_ALG_HMAC) {
806 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
814 * Return the offset past the checksum, so that we know where
815 * the data we're wrapped around starts. Also, set the length
816 * of our top-level item to that offset, so it doesn't cover
817 * the data we're wrapped around.
824 * XXX - is this for SPNEGO or just GSS-API?
825 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
826 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
827 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
828 * getting it accepted.
831 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
838 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
840 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
843 * The KRB5 blob conforms to RFC1964:
844 * USHORT (0x0102 == GSS_Wrap)
848 /* First, the token ID ... */
850 token_id = tvb_get_letohs(tvb, offset);
851 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
856 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
859 * Return the offset past the checksum, so that we know where
860 * the data we're wrapped around starts. Also, set the length
861 * of our top-level item to that offset, so it doesn't cover
862 * the data we're wrapped around.
864 proto_item_set_len(item, offset);
868 /* Spnego stuff from here */
871 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
880 * We need this later, so lets get it now ...
881 * It has to be per-frame as there can be more than one GSS-API
882 * negotiation in a conversation.
886 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
889 subtree = proto_item_add_subtree(item, ett_spnego);
891 * The TVB contains a [0] header and a sequence that consists of an
892 * object ID and a blob containing the data ...
893 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
894 * with the "optional" "use in non-initial tokens" being chosen.
895 * ASN1 code addet to spnego.asn to handle this.
898 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, pinfo , subtree, -1);
905 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
910 conversation_t *conversation;
913 * We need this later, so lets get it now ...
914 * It has to be per-frame as there can be more than one GSS-API
915 * negotiation in a conversation.
917 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
918 if (!next_level_value && !pinfo->fd->flags.visited) {
920 * No handle attached to this frame, but it's the first
921 * pass, so it'd be attached to the conversation.
922 * If we have a conversation, try to get the handle,
923 * and if we get one, attach it to the frame.
925 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
926 pinfo->ptype, pinfo->srcport,
930 next_level_value = conversation_get_proto_data(conversation,
932 if (next_level_value)
933 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
937 item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset,
940 subtree = proto_item_add_subtree(item, ett_spnego);
943 * The TVB contains a [0] header and a sequence that consists of an
944 * object ID and a blob containing the data ...
945 * Actually, it contains, according to RFC2478:
946 * NegotiationToken ::= CHOICE {
947 * negTokenInit [0] NegTokenInit,
948 * negTokenTarg [1] NegTokenTarg }
949 * NegTokenInit ::= SEQUENCE {
950 * mechTypes [0] MechTypeList OPTIONAL,
951 * reqFlags [1] ContextFlags OPTIONAL,
952 * mechToken [2] OCTET STRING OPTIONAL,
953 * mechListMIC [3] OCTET STRING OPTIONAL }
954 * NegTokenTarg ::= SEQUENCE {
955 * negResult [0] ENUMERATED {
956 * accept_completed (0),
957 * accept_incomplete (1),
958 * reject (2) } OPTIONAL,
959 * supportedMech [1] MechType OPTIONAL,
960 * responseToken [2] OCTET STRING OPTIONAL,
961 * mechListMIC [3] OCTET STRING OPTIONAL }
963 * Windows typically includes mechTypes and mechListMic ('NONE'
964 * in the case of NTLMSSP only).
965 * It seems to duplicate the responseToken into the mechListMic field
966 * as well. Naughty, naughty.
969 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, pinfo, subtree, -1);
973 /*--- proto_register_spnego -------------------------------------------*/
974 void proto_register_spnego(void) {
977 static hf_register_info hf[] = {
979 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
981 { &hf_spnego_wraptoken,
982 { "wrapToken", "spnego.wraptoken",
983 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
986 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
987 BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
988 { &hf_spnego_krb5_oid,
989 { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
990 BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
991 { &hf_spnego_krb5_tok_id,
992 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
993 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
994 { &hf_spnego_krb5_sgn_alg,
995 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
996 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
997 { &hf_spnego_krb5_seal_alg,
998 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
999 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1000 { &hf_spnego_krb5_snd_seq,
1001 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1002 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1003 { &hf_spnego_krb5_sgn_cksum,
1004 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1005 NULL, 0, "KRB5 Data Checksum", HFILL}},
1006 { &hf_spnego_krb5_confounder,
1007 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1008 NULL, 0, "KRB5 Confounder", HFILL}},
1010 #include "packet-spnego-hfarr.c"
1013 /* List of subtrees */
1014 static gint *ett[] = {
1016 &ett_spnego_wraptoken,
1019 #include "packet-spnego-ettarr.c"
1022 /* Register protocol */
1023 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1025 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1028 /* Register fields and subtrees */
1029 proto_register_field_array(proto_spnego, hf, array_length(hf));
1030 proto_register_subtree_array(ett, array_length(ett));
1034 /*--- proto_reg_handoff_spnego ---------------------------------------*/
1035 void proto_reg_handoff_spnego(void) {
1037 dissector_handle_t spnego_handle, spnego_wrap_handle;
1038 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1040 /* Register protocol with GSS-API module */
1042 spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
1043 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
1045 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1046 spnego_handle, spnego_wrap_handle,
1047 "SPNEGO - Simple Protected Negotiation");
1049 /* Register both the one MS created and the real one */
1051 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1052 * mystery of the MS KRB5 OID is cleared up. It was due to a library
1053 * that did not handle OID components greater than 16 bits, and was
1054 * fixed in Win2K SP2 as well as WinXP.
1055 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1056 * SPNEGO implementation issues. 3-Dec-2002.
1058 spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
1060 spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
1062 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1063 spnego_krb5_handle, spnego_krb5_wrap_handle,
1064 "MS KRB5 - Microsoft Kerberos 5");
1065 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1066 spnego_krb5_handle, spnego_krb5_wrap_handle,
1067 "KRB5 - Kerberos 5");
1068 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1069 spnego_krb5_handle, spnego_krb5_wrap_handle,
1070 "KRB5 - Kerberos 5 - User to User");
1073 * Find the data handle for some calls
1075 data_handle = find_dissector("data");