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 <epan/asn1.h>
41 #include "packet-dcerpc.h"
42 #include "packet-gssapi.h"
43 #include "packet-kerberos.h"
44 #include <epan/crypt/crypt-rc4.h>
45 #include <epan/conversation.h>
46 #include <epan/emem.h>
47 #include <epan/asn1.h>
52 #include "packet-ber.h"
55 #define PNAME "Simple Protected Negotiation"
56 #define PSNAME "SPNEGO"
57 #define PFNAME "spnego"
59 /* Initialize the protocol and registered fields */
60 static int proto_spnego = -1;
61 static int proto_spnego_krb5 = -1;
64 static int hf_spnego = -1;
65 static int hf_spnego_wraptoken = -1;
66 static int hf_spnego_krb5_oid;
67 static int hf_spnego_krb5 = -1;
68 static int hf_spnego_krb5_tok_id = -1;
69 static int hf_spnego_krb5_sgn_alg = -1;
70 static int hf_spnego_krb5_seal_alg = -1;
71 static int hf_spnego_krb5_snd_seq = -1;
72 static int hf_spnego_krb5_sgn_cksum = -1;
73 static int hf_spnego_krb5_confounder = -1;
74 static int hf_spnego_krb5_filler = -1;
75 static int hf_spnego_krb5_cfx_flags = -1;
76 static int hf_spnego_krb5_cfx_flags_01 = -1;
77 static int hf_spnego_krb5_cfx_flags_02 = -1;
78 static int hf_spnego_krb5_cfx_flags_04 = -1;
79 static int hf_spnego_krb5_cfx_ec = -1;
80 static int hf_spnego_krb5_cfx_rrc = -1;
81 static int hf_spnego_krb5_cfx_seq = -1;
83 #include "packet-spnego-hf.c"
85 /* Global variables */
86 static const char *MechType_oid;
87 gssapi_oid_value *next_level_value;
88 gboolean saw_mechanism = FALSE;
91 /* Initialize the subtree pointers */
92 static gint ett_spnego;
93 static gint ett_spnego_wraptoken;
94 static gint ett_spnego_krb5 = -1;
95 static gint ett_spnego_krb5_cfx_flags = -1;
97 #include "packet-spnego-ett.c"
100 * Unfortunately, we have to have a forward declaration of this,
101 * as the code generated by asn2wrs includes a call before the
104 static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
105 int offset, asn1_ctx_t *actx _U_,
106 proto_tree *tree, int hf_index);
108 #include "packet-spnego-fn.c"
110 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
111 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
112 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
115 #define KRB_TOKEN_AP_REQ 0x0001
116 #define KRB_TOKEN_AP_REP 0x0002
117 #define KRB_TOKEN_AP_ERR 0x0003
118 #define KRB_TOKEN_GETMIC 0x0101
119 #define KRB_TOKEN_WRAP 0x0102
120 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
121 #define KRB_TOKEN_CFX_GETMIC 0x0404
122 #define KRB_TOKEN_CFX_WRAP 0x0405
124 static const value_string spnego_krb5_tok_id_vals[] = {
125 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
126 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
127 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
128 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
129 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
130 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
131 { KRB_TOKEN_CFX_GETMIC, "KRB_TOKEN_CFX_GetMic" },
132 { KRB_TOKEN_CFX_WRAP, "KRB_TOKEN_CFX_WRAP" },
136 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
137 #define KRB_SGN_ALG_MD2_5 0x0001
138 #define KRB_SGN_ALG_DES_MAC 0x0002
139 #define KRB_SGN_ALG_HMAC 0x0011
141 static const value_string spnego_krb5_sgn_alg_vals[] = {
142 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
143 { KRB_SGN_ALG_MD2_5, "MD2.5"},
144 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
145 { KRB_SGN_ALG_HMAC, "HMAC"},
149 #define KRB_SEAL_ALG_DES_CBC 0x0000
150 #define KRB_SEAL_ALG_RC4 0x0010
151 #define KRB_SEAL_ALG_NONE 0xffff
153 static const value_string spnego_krb5_seal_alg_vals[] = {
154 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
155 { KRB_SEAL_ALG_RC4, "RC4"},
156 { KRB_SEAL_ALG_NONE, "None"},
161 * XXX - is this for SPNEGO or just GSS-API?
162 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
163 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
164 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
165 * getting it accepted.
168 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
170 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
172 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
174 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
177 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
184 gssapi_oid_value *value;
187 gboolean pc, ind = 0;
191 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
193 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
196 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
199 * The KRB5 blob conforms to RFC1964:
202 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
205 * However, for some protocols, the KRB5 blob starts at the SHORT
206 * and has no DER encoded header etc.
208 * It appears that for some other protocols the KRB5 blob is just
209 * a Kerberos message, with no [APPLICATION 0] header, no OID,
214 * If we see an [APPLICATION 0] HEADER, we show the OID and
215 * the USHORT, and then dissect the rest as a Kerberos message.
217 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
218 * we assume it's an AP-REQ or AP-REP message, and dissect
219 * it all as a Kerberos message.
221 * Otherwise, we show the USHORT, and then dissect the rest
222 * as a Kerberos message.
226 * Get the first header ...
228 get_ber_identifier(tvb, offset, &class, &pc, &tag);
229 if (class == BER_CLASS_APP && pc) {
231 * [APPLICATION <tag>]
233 offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
234 offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
244 offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
246 value = gssapi_lookup_oid_str(oid);
248 token_id = tvb_get_letohs(tvb, offset);
249 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
256 case 14: /* [APPLICATION 14] */
257 case 15: /* [APPLICATION 15] */
259 * No token ID - just dissect as a Kerberos message and
262 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
266 proto_tree_add_text(subtree, tvb, offset, 0,
267 "Unknown header (class=%d, pc=%d, tag=%d)",
272 /* Next, the token ID ... */
274 token_id = tvb_get_letohs(tvb, offset);
275 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
283 case KRB_TOKEN_AP_REQ:
284 case KRB_TOKEN_AP_REP:
285 case KRB_TOKEN_AP_ERR:
286 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
287 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
290 case KRB_TOKEN_GETMIC:
291 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
295 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
298 case KRB_TOKEN_DELETE_SEC_CONTEXT:
302 case KRB_TOKEN_CFX_GETMIC:
303 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
306 case KRB_TOKEN_CFX_WRAP:
307 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
316 proto_item_set_len(item, offset);
321 #include <epan/crypt/crypt-md5.h>
323 #ifndef KEYTYPE_ARCFOUR_56
324 # define KEYTYPE_ARCFOUR_56 24
326 /* XXX - We should probably do a configure-time check for this instead */
327 #ifndef KRB5_KU_USAGE_SEAL
328 # define KRB5_KU_USAGE_SEAL 22
332 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
333 void *cksum_data, size_t cksum_size,
341 if (key_type == KEYTYPE_ARCFOUR_56) {
342 guint8 L40[14] = "fortybits";
344 memcpy(L40 + 10, T, sizeof(T));
350 memset(&k5_data[7], 0xAB, 9);
360 cksum_data, cksum_size,
369 usage2arcfour(int usage)
372 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
373 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
375 case 22: /*KRB5_KU_USAGE_SEAL 22 */
377 case 23: /*KRB5_KU_USAGE_SIGN 23 */
379 case 24: /*KRB5_KU_USAGE_SEQ 24 */
387 arcfour_mic_cksum(guint8 *key_data, int key_length,
390 const void *v1, size_t l1,
391 const void *v2, size_t l2,
392 const void *v3, size_t l3)
394 const guint8 signature[] = "signaturekey";
398 unsigned char digest[16];
402 rc4_usage=usage2arcfour(usage);
403 md5_hmac(signature, sizeof(signature),
404 key_data, key_length,
407 t[0] = (rc4_usage >> 0) & 0xFF;
408 t[1] = (rc4_usage >> 8) & 0xFF;
409 t[2] = (rc4_usage >> 16) & 0xFF;
410 t[3] = (rc4_usage >> 24) & 0xFF;
411 md5_append(&ms, t, 4);
412 md5_append(&ms, v1, l1);
413 md5_append(&ms, v2, l2);
414 md5_append(&ms, v3, l3);
415 md5_finish(&ms, digest);
416 md5_hmac(digest, 16, ksign_c, 16, cksum);
418 memcpy(sgn_cksum, cksum, 8);
424 * Verify padding of a gss wrapped message and return its length.
427 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
435 pad = wrapped_data + wrapped_length - 1;
438 if (padlength > datalen)
441 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
452 decrypt_arcfour(packet_info *pinfo,
453 guint8 *input_message_buffer,
454 guint8 *output_message_buffer,
455 guint8 *key_value, int key_size, int key_type)
457 guint8 Klocaldata[16];
463 guint8 Confounder[8];
464 guint8 cksum_data[8];
469 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
471 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
473 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
479 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
483 ret = arcfour_mic_key(key_value, key_size, key_type,
484 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
492 rc4_state_struct rc4_state;
494 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
495 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
496 crypt_rc4(&rc4_state, (unsigned char *)SND_SEQ, 8);
498 memset(k6_data, 0, sizeof(k6_data));
501 seq_number=g_ntohl(SND_SEQ[0]);
503 if (SND_SEQ[1] != 0xFFFFFFFF && SND_SEQ[1] != 0x00000000) {
510 for (i = 0; i < 16; i++)
511 Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
513 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
514 (unsigned char *)SND_SEQ, 4,
516 memset(Klocaldata, 0, sizeof(Klocaldata));
522 rc4_state_struct rc4_state;
524 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
525 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
526 crypt_rc4(&rc4_state, Confounder, 8);
527 memcpy(output_message_buffer, input_message_buffer, datalen);
528 crypt_rc4(&rc4_state, output_message_buffer, datalen);
531 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
533 memcpy(output_message_buffer,
534 input_message_buffer,
537 memset(k6_data, 0, sizeof(k6_data));
539 /* only normal (i.e. non DCE style wrapping use padding ? */
540 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
541 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
548 /* dont know what the checksum looks like for dce style gssapi */
549 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
550 ret = arcfour_mic_cksum(key_value, key_size,
553 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
554 Confounder, sizeof(Confounder),
555 output_message_buffer,
561 cmp = memcmp(cksum_data,
562 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
574 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
577 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
582 const guint8 *original_data;
584 static int omb_index=0;
585 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
586 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
587 guint8 *output_message_buffer;
593 output_message_buffer=omb_arr[omb_index];
596 length=tvb_length(pinfo->gssapi_encrypted_tvb);
597 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
599 /* dont do anything if we are not attempting to decrypt data */
605 /* XXX we should only do this for first time, then store somewhere */
606 /* XXX We also need to re-read the keytab when the preference changes */
608 cryptocopy=ep_alloc(length);
609 if(output_message_buffer){
610 g_free(output_message_buffer);
611 output_message_buffer=NULL;
613 output_message_buffer=g_malloc(length);
615 for(ek=enc_key_list;ek;ek=ek->next){
616 /* shortcircuit and bail out if enctypes are not matching */
617 if(ek->keytype!=keytype){
621 /* pre-0.6.1 versions of Heimdal would sometimes change
622 the cryptotext data even when the decryption failed.
623 This would obviously not work since we iterate over the
624 keys. So just give it a copy of the crypto data instead.
625 This has been seen for RC4-HMAC blobs.
627 memcpy(cryptocopy, original_data, length);
628 ret=decrypt_arcfour(pinfo,
630 output_message_buffer,
636 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
637 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
638 output_message_buffer,
640 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
647 /* borrowed from heimdal */
649 rrc_rotate(void *data, int len, guint16 rrc, int unrotate)
651 unsigned char *tmp, buf[256];
664 if (rrc <= sizeof(buf)) {
673 memcpy(tmp, data, rrc);
674 memmove(data, (unsigned char *)data + rrc, left);
675 memcpy((unsigned char *)data + left, tmp, rrc);
677 memcpy(tmp, (unsigned char *)data + left, rrc);
678 memmove((unsigned char *)data + rrc, data, left);
679 memcpy(data, tmp, rrc);
682 if (rrc > sizeof(buf))
689 #define KRB5_KU_USAGE_ACCEPTOR_SEAL 22
690 #define KRB5_KU_USAGE_ACCEPTOR_SIGN 23
691 #define KRB5_KU_USAGE_INITIATOR_SEAL 24
692 #define KRB5_KU_USAGE_INITIATOR_SIGN 25
695 decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_, packet_info *pinfo _U_, tvbuff_t *tvb _U_, guint16 ec _U_, guint16 rrc _U_, int keytype, unsigned int usage)
702 /* dont do anything if we are not attempting to decrypt data */
707 rotated = ep_alloc(tvb_length(tvb));
709 tvb_memcpy(tvb, rotated, 0, tvb_length(tvb));
710 res = rrc_rotate(rotated, tvb_length(tvb), rrc, TRUE);
712 output = decrypt_krb5_data(tree, pinfo, usage, tvb_length(tvb),
713 rotated, keytype, &datalen);
718 outdata = ep_alloc(tvb_length(tvb));
719 memcpy(outdata, output, tvb_length(tvb));
722 pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
726 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
732 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
738 * This is for GSSAPI Wrap tokens ...
741 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
742 #ifndef HAVE_KERBEROS
745 , proto_tree *tree, guint16 token_id
746 #ifndef HAVE_KERBEROS
751 guint16 sgn_alg, seal_alg;
753 int start_offset=offset;
757 * The KRB5 blob conforms to RFC1964:
758 * USHORT (0x0102 == GSS_Wrap)
762 /* Now, the sign and seal algorithms ... */
764 sgn_alg = tvb_get_letohs(tvb, offset);
765 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
770 seal_alg = tvb_get_letohs(tvb, offset);
771 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
776 /* Skip the filler */
780 /* Encrypted sequence number */
782 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
787 /* Checksum of plaintext padded data */
789 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
795 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
796 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
797 * extra 8 bytes of "Random confounder" after the checksum.
798 * It certainly confounds code expecting all Kerberos 5
799 * GSS_Wrap() tokens to look the same....
801 if ((sgn_alg == KRB_SGN_ALG_HMAC) ||
802 /* there also seems to be a confounder for DES MAC MD5 - certainly seen when using with
803 SASL with LDAP between a Java client and Active Directory. If this breaks other things
804 we may need to make this an option. gal 17/2/06 */
805 (sgn_alg == KRB_SGN_ALG_DES_MAC_MD5)) {
806 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
811 /* Is the data encrypted? */
812 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
815 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
816 if(pinfo->decrypt_gssapi_tvb){
817 /* if the caller did not provide a tvb, then we just use
818 whatever is left of our current tvb.
820 if(!pinfo->gssapi_encrypted_tvb){
822 len=tvb_reported_length_remaining(tvb,offset);
823 if(len>tvb_length_remaining(tvb, offset)){
824 /* no point in trying to decrypt,
825 we dont have the full pdu.
829 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
830 tvb, offset, len, len);
833 /* if this is KRB5 wrapped rc4-hmac */
834 if((token_id==KRB_TOKEN_WRAP)
835 &&(sgn_alg==KRB_SGN_ALG_HMAC)
836 &&(seal_alg==KRB_SEAL_ALG_RC4)){
837 /* do we need to create a tvb for the wrapper
840 if(!pinfo->gssapi_wrap_tvb){
841 pinfo->gssapi_wrap_tvb = tvb_new_subset(
843 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
844 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
846 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
847 decrypt_gssapi_krb_arcfour_wrap(tree,
851 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
856 * Return the offset past the checksum, so that we know where
857 * the data we're wrapped around starts. Also, set the length
858 * of our top-level item to that offset, so it doesn't cover
859 * the data we're wrapped around.
861 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
868 * XXX - This is for GSSAPI GetMIC tokens ...
871 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
876 * The KRB5 blob conforms to RFC1964:
877 * USHORT (0x0101 == GSS_GetMIC)
881 /* Now, the sign algorithm ... */
883 sgn_alg = tvb_get_letohs(tvb, offset);
884 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
889 /* Skip the filler */
893 /* Encrypted sequence number */
895 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
900 /* Checksum of plaintext padded data */
902 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
908 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
909 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
910 * extra 8 bytes of "Random confounder" after the checksum.
911 * It certainly confounds code expecting all Kerberos 5
912 * GSS_Wrap() tokens to look the same....
914 * The exception is DNS/TSIG where there is no such confounder
915 * so we need to test here if there are more bytes in our tvb or not.
918 if (tvb_length_remaining(tvb, offset)) {
919 if (sgn_alg == KRB_SGN_ALG_HMAC) {
920 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
928 * Return the offset past the checksum, so that we know where
929 * the data we're wrapped around starts. Also, set the length
930 * of our top-level item to that offset, so it doesn't cover
931 * the data we're wrapped around.
938 dissect_spnego_krb5_cfx_flags(tvbuff_t *tvb, int offset,
939 proto_tree *spnego_krb5_tree,
942 proto_tree *cfx_flags_tree = NULL;
943 proto_item *tf = NULL;
945 if (spnego_krb5_tree) {
946 tf = proto_tree_add_uint(spnego_krb5_tree,
947 hf_spnego_krb5_cfx_flags,
948 tvb, offset, 1, cfx_flags);
949 cfx_flags_tree = proto_item_add_subtree(tf, ett_spnego_krb5_cfx_flags);
952 proto_tree_add_boolean(cfx_flags_tree,
953 hf_spnego_krb5_cfx_flags_04,
954 tvb, offset, 1, cfx_flags);
955 proto_tree_add_boolean(cfx_flags_tree,
956 hf_spnego_krb5_cfx_flags_02,
957 tvb, offset, 1, cfx_flags);
958 proto_tree_add_boolean(cfx_flags_tree,
959 hf_spnego_krb5_cfx_flags_01,
960 tvb, offset, 1, cfx_flags);
966 * This is for GSSAPI CFX Wrap tokens ...
969 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
970 #ifndef HAVE_KERBEROS
973 , proto_tree *tree, guint16 token_id _U_
980 int start_offset=offset;
983 * The KRB5 blob conforms to RFC4121:
988 /* Now, the sign and seal algorithms ... */
990 flags = tvb_get_guint8(tvb, offset);
991 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
993 pinfo->gssapi_data_encrypted=(flags & 2);
995 /* Skip the filler */
997 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 1,
1002 ec = tvb_get_ntohs(tvb, offset);
1003 proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2,
1008 rrc = tvb_get_ntohs(tvb, offset);
1009 proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2,
1013 /* sequence number */
1015 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1019 /* Checksum of plaintext padded data */
1021 if (pinfo->gssapi_data_encrypted) {
1022 checksum_size = 44 + ec;
1027 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1028 checksum_size, FALSE);
1029 offset += checksum_size;
1031 if(pinfo->decrypt_gssapi_tvb){
1032 /* if the caller did not provide a tvb, then we just use
1033 whatever is left of our current tvb.
1035 if(!pinfo->gssapi_encrypted_tvb){
1037 len=tvb_reported_length_remaining(tvb,offset);
1038 if(len>tvb_length_remaining(tvb, offset)){
1039 /* no point in trying to decrypt,
1040 we dont have the full pdu.
1044 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1045 tvb, offset, len, len);
1048 if (pinfo->gssapi_data_encrypted) {
1049 /* do we need to create a tvb for the wrapper
1052 if(!pinfo->gssapi_wrap_tvb){
1053 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1054 tvb, start_offset-2,
1055 offset - (start_offset-2),
1056 offset - (start_offset-2));
1061 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1062 pinfo->gssapi_encrypted_tvb = tvb_new_subset(tvb, 16, -1, -1);
1064 if (flags & 0x0002) {
1065 if(pinfo->gssapi_encrypted_tvb){
1066 decrypt_gssapi_krb_cfx_wrap(tree,
1068 pinfo->gssapi_encrypted_tvb,
1073 KRB5_KU_USAGE_ACCEPTOR_SEAL:
1074 KRB5_KU_USAGE_INITIATOR_SEAL);
1077 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1080 * Return the offset past the checksum, so that we know where
1081 * the data we're wrapped around starts. Also, set the length
1082 * of our top-level item to that offset, so it doesn't cover
1083 * the data we're wrapped around.
1085 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1092 * XXX - This is for GSSAPI CFX GetMIC tokens ...
1095 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1101 * The KRB5 blob conforms to RFC4121:
1102 * USHORT (0x0404 == GSS_GetMIC)
1106 flags = tvb_get_guint8(tvb, offset);
1107 offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1109 /* Skip the filler */
1111 proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 5,
1115 /* sequence number */
1117 proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1121 /* Checksum of plaintext padded data */
1123 checksum_size = tvb_length_remaining(tvb, offset);
1125 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1126 checksum_size, FALSE);
1127 offset += checksum_size;
1130 * Return the offset past the checksum, so that we know where
1131 * the data we're wrapped around starts. Also, set the length
1132 * of our top-level item to that offset, so it doesn't cover
1133 * the data we're wrapped around.
1140 * XXX - is this for SPNEGO or just GSS-API?
1141 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1142 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1143 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1144 * getting it accepted.
1147 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1150 proto_tree *subtree;
1154 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
1156 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1159 * The KRB5 blob conforms to RFC1964:
1160 * USHORT (0x0102 == GSS_Wrap)
1164 /* First, the token ID ... */
1166 token_id = tvb_get_letohs(tvb, offset);
1167 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1173 case KRB_TOKEN_GETMIC:
1174 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
1177 case KRB_TOKEN_WRAP:
1178 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1181 case KRB_TOKEN_CFX_GETMIC:
1182 offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
1185 case KRB_TOKEN_CFX_WRAP:
1186 offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
1195 * Return the offset past the checksum, so that we know where
1196 * the data we're wrapped around starts. Also, set the length
1197 * of our top-level item to that offset, so it doesn't cover
1198 * the data we're wrapped around.
1200 proto_item_set_len(item, offset);
1204 /* Spnego stuff from here */
1207 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1210 proto_tree *subtree;
1212 asn1_ctx_t asn1_ctx;
1213 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1218 * We need this later, so lets get it now ...
1219 * It has to be per-frame as there can be more than one GSS-API
1220 * negotiation in a conversation.
1224 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1227 subtree = proto_item_add_subtree(item, ett_spnego);
1229 * The TVB contains a [0] header and a sequence that consists of an
1230 * object ID and a blob containing the data ...
1231 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1232 * with the "optional" "use in non-initial tokens" being chosen.
1233 * ASN1 code addet to spnego.asn to handle this.
1236 offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, &asn1_ctx , subtree, -1);
1243 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1246 proto_tree *subtree;
1248 conversation_t *conversation;
1249 asn1_ctx_t asn1_ctx;
1250 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1253 * We need this later, so lets get it now ...
1254 * It has to be per-frame as there can be more than one GSS-API
1255 * negotiation in a conversation.
1257 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1258 if (!next_level_value && !pinfo->fd->flags.visited) {
1260 * No handle attached to this frame, but it's the first
1261 * pass, so it'd be attached to the conversation.
1262 * If we have a conversation, try to get the handle,
1263 * and if we get one, attach it to the frame.
1265 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1266 pinfo->ptype, pinfo->srcport,
1267 pinfo->destport, 0);
1270 next_level_value = conversation_get_proto_data(conversation,
1272 if (next_level_value)
1273 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1277 item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset,
1280 subtree = proto_item_add_subtree(item, ett_spnego);
1283 * The TVB contains a [0] header and a sequence that consists of an
1284 * object ID and a blob containing the data ...
1285 * Actually, it contains, according to RFC2478:
1286 * NegotiationToken ::= CHOICE {
1287 * negTokenInit [0] NegTokenInit,
1288 * negTokenTarg [1] NegTokenTarg }
1289 * NegTokenInit ::= SEQUENCE {
1290 * mechTypes [0] MechTypeList OPTIONAL,
1291 * reqFlags [1] ContextFlags OPTIONAL,
1292 * mechToken [2] OCTET STRING OPTIONAL,
1293 * mechListMIC [3] OCTET STRING OPTIONAL }
1294 * NegTokenTarg ::= SEQUENCE {
1295 * negResult [0] ENUMERATED {
1296 * accept_completed (0),
1297 * accept_incomplete (1),
1298 * reject (2) } OPTIONAL,
1299 * supportedMech [1] MechType OPTIONAL,
1300 * responseToken [2] OCTET STRING OPTIONAL,
1301 * mechListMIC [3] OCTET STRING OPTIONAL }
1303 * Windows typically includes mechTypes and mechListMic ('NONE'
1304 * in the case of NTLMSSP only).
1305 * It seems to duplicate the responseToken into the mechListMic field
1306 * as well. Naughty, naughty.
1309 offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
1313 /*--- proto_register_spnego -------------------------------------------*/
1314 void proto_register_spnego(void) {
1316 /* List of fields */
1317 static hf_register_info hf[] = {
1319 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1321 { &hf_spnego_wraptoken,
1322 { "wrapToken", "spnego.wraptoken",
1323 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1326 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1327 BASE_NONE, NULL, 0, NULL, HFILL }},
1328 { &hf_spnego_krb5_oid,
1329 { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
1330 BASE_NONE, NULL, 0, NULL, HFILL }},
1331 { &hf_spnego_krb5_tok_id,
1332 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1333 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1334 { &hf_spnego_krb5_sgn_alg,
1335 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1336 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1337 { &hf_spnego_krb5_seal_alg,
1338 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1339 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1340 { &hf_spnego_krb5_snd_seq,
1341 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1342 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1343 { &hf_spnego_krb5_sgn_cksum,
1344 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1345 NULL, 0, "KRB5 Data Checksum", HFILL}},
1346 { &hf_spnego_krb5_confounder,
1347 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1348 NULL, 0, "KRB5 Confounder", HFILL}},
1349 { &hf_spnego_krb5_filler,
1350 { "krb5_filler", "spnego.krb5.filler", FT_BYTES, BASE_NONE,
1351 NULL, 0, "KRB5 Filler", HFILL}},
1352 { &hf_spnego_krb5_cfx_flags,
1353 { "krb5_cfx_flags", "spnego.krb5.cfx_flags", FT_UINT8, BASE_HEX,
1354 NULL, 0, "KRB5 CFX Flags", HFILL}},
1355 { &hf_spnego_krb5_cfx_flags_01,
1356 { "SendByAcceptor", "spnego.krb5.send_by_acceptor", FT_BOOLEAN, 8,
1357 TFS (&flags_set_truth), 0x01, NULL, HFILL}},
1358 { &hf_spnego_krb5_cfx_flags_02,
1359 { "Sealed", "spnego.krb5.sealed", FT_BOOLEAN, 8,
1360 TFS (&flags_set_truth), 0x02, NULL, HFILL}},
1361 { &hf_spnego_krb5_cfx_flags_04,
1362 { "AcceptorSubkey", "spnego.krb5.acceptor_subkey", FT_BOOLEAN, 8,
1363 TFS (&flags_set_truth), 0x04, NULL, HFILL}},
1364 { &hf_spnego_krb5_cfx_ec,
1365 { "krb5_cfx_ec", "spnego.krb5.cfx_ec", FT_UINT16, BASE_DEC,
1366 NULL, 0, "KRB5 CFX Extra Count", HFILL}},
1367 { &hf_spnego_krb5_cfx_rrc,
1368 { "krb5_cfx_rrc", "spnego.krb5.cfx_rrc", FT_UINT16, BASE_DEC,
1369 NULL, 0, "KRB5 CFX Right Rotation Count", HFILL}},
1370 { &hf_spnego_krb5_cfx_seq,
1371 { "krb5_cfx_seq", "spnego.krb5.cfx_seq", FT_UINT64, BASE_DEC,
1372 NULL, 0, "KRB5 Sequence Number", HFILL}},
1374 #include "packet-spnego-hfarr.c"
1377 /* List of subtrees */
1378 static gint *ett[] = {
1380 &ett_spnego_wraptoken,
1382 &ett_spnego_krb5_cfx_flags,
1384 #include "packet-spnego-ettarr.c"
1387 /* Register protocol */
1388 proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1390 register_dissector("spnego", dissect_spnego, proto_spnego);
1392 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1396 register_dissector("spnego-krb5", dissect_spnego_krb5, proto_spnego_krb5);
1397 new_register_dissector("spnego-krb5-wrap", dissect_spnego_krb5_wrap, proto_spnego_krb5);
1399 /* Register fields and subtrees */
1400 proto_register_field_array(proto_spnego, hf, array_length(hf));
1401 proto_register_subtree_array(ett, array_length(ett));
1405 /*--- proto_reg_handoff_spnego ---------------------------------------*/
1406 void proto_reg_handoff_spnego(void) {
1408 dissector_handle_t spnego_handle, spnego_wrap_handle;
1409 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1411 /* Register protocol with GSS-API module */
1413 spnego_handle = find_dissector("spnego");
1414 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap, proto_spnego);
1415 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1416 spnego_handle, spnego_wrap_handle,
1417 "SPNEGO - Simple Protected Negotiation");
1419 /* Register both the one MS created and the real one */
1421 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1422 * mystery of the MS KRB5 OID is cleared up. It was due to a library
1423 * that did not handle OID components greater than 16 bits, and was
1424 * fixed in Win2K SP2 as well as WinXP.
1425 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1426 * SPNEGO implementation issues. 3-Dec-2002.
1428 spnego_krb5_handle = find_dissector("spnego-krb5");
1429 spnego_krb5_wrap_handle = find_dissector("spnego-krb5-wrap");
1430 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1431 spnego_krb5_handle, spnego_krb5_wrap_handle,
1432 "MS KRB5 - Microsoft Kerberos 5");
1433 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1434 spnego_krb5_handle, spnego_krb5_wrap_handle,
1435 "KRB5 - Kerberos 5");
1436 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1437 spnego_krb5_handle, spnego_krb5_wrap_handle,
1438 "KRB5 - Kerberos 5 - User to User");