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)
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
30 Heimdal 1.6 and has been modified for ethereal's requirements.
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
42 #include <epan/packet.h>
44 #include <epan/asn1.h>
45 #include "format-oid.h"
46 #include "packet-ber.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>
53 #define SPNEGO_negTokenInit 0
54 #define SPNEGO_negTokenTarg 1
55 #define SPNEGO_mechTypes 0
56 #define SPNEGO_reqFlags 1
57 #define SPNEGO_mechToken 2
58 #define SPNEGO_mechListMIC 3
59 #define SPNEGO_negResult 0
60 #define SPNEGO_supportedMech 1
61 #define SPNEGO_responseToken 2
62 #define SPNEGO_negResult_accept_completed 0
63 #define SPNEGO_negResult_accept_incomplete 1
64 #define SPNEGO_negResult_accept_reject 2
66 static int proto_spnego = -1;
67 static int proto_spnego_krb5 = -1;
69 static int hf_spnego = -1;
70 static int hf_spnego_mech = -1;
71 static int hf_spnego_this_mech = -1;
72 static int hf_spnego_negtokeninit = -1;
73 static int hf_spnego_negtokentarg = -1;
74 static int hf_spnego_mechtype = -1;
75 static int hf_spnego_mechtoken = -1;
76 static int hf_spnego_negtokentarg_negresult = -1;
77 static int hf_spnego_mechlistmic = -1;
78 static int hf_spnego_responsetoken = -1;
79 static int hf_spnego_reqflags = -1;
80 static int hf_spnego_wraptoken = -1;
81 static int hf_spnego_krb5 = -1;
82 static int hf_spnego_krb5_tok_id = -1;
83 static int hf_spnego_krb5_sgn_alg = -1;
84 static int hf_spnego_krb5_seal_alg = -1;
85 static int hf_spnego_krb5_snd_seq = -1;
86 static int hf_spnego_krb5_sgn_cksum = -1;
87 static int hf_spnego_krb5_confounder = -1;
88 static int hf_gssapi_reqflags_deleg = -1;
89 static int hf_gssapi_reqflags_mutual = -1;
90 static int hf_gssapi_reqflags_replay = -1;
91 static int hf_gssapi_reqflags_sequence = -1;
92 static int hf_gssapi_reqflags_anon = -1;
93 static int hf_gssapi_reqflags_conf = -1;
94 static int hf_gssapi_reqflags_integ = -1;
96 static gint ett_spnego = -1;
97 static gint ett_spnego_negtokeninit = -1;
98 static gint ett_spnego_negtokentarg = -1;
99 static gint ett_spnego_mechtype = -1;
100 static gint ett_spnego_mechtoken = -1;
101 static gint ett_spnego_mechlistmic = -1;
102 static gint ett_spnego_responsetoken = -1;
103 static gint ett_spnego_wraptoken = -1;
104 static gint ett_spnego_krb5 = -1;
105 static gint ett_spnego_reqflags = -1;
107 static const value_string spnego_negResult_vals[] = {
108 { SPNEGO_negResult_accept_completed, "Accept Completed" },
109 { SPNEGO_negResult_accept_incomplete, "Accept Incomplete" },
110 { SPNEGO_negResult_accept_reject, "Accept Reject"},
115 * These should be in the GSSAPI dissector ... XXX
118 static const true_false_string tfs_reqflags_deleg = {
119 "Delegation Requested",
120 "Delegation NOT Requested"
123 static const true_false_string tfs_reqflags_mutual = {
124 "Mutual Authentication Requested",
125 "Mutual Authentication NOT Requested"
128 static const true_false_string tfs_reqflags_replay = {
129 "Replay Detection Requested",
130 "Replay Detection NOT Requested"
133 static const true_false_string tfs_reqflags_sequence = {
134 "Out-of-sequence Detection Requested",
135 "Out-of-sequence Detection NOT Requested"
138 static const true_false_string tfs_reqflags_anon = {
139 "Anonymous Authentication Requested",
140 "Anonymous Authentication NOT Requested"
143 static const true_false_string tfs_reqflags_conf = {
144 "Per-message Confidentiality Requested",
145 "Per-message Confidentiality NOT Requested"
148 static const true_false_string tfs_reqflags_integ = {
149 "Per-message Integrity Requested",
150 "Per-message Integrity NOT Requested"
154 * This takes an OID in binary form, not an OID as a text string, as
157 static gssapi_oid_value *
158 gssapi_lookup_oid(subid_t *oid, guint oid_len)
164 gssapi_oid_value *value;
167 * Convert the OID to a string, as text strings are used as
168 * keys in the OID hash table.
170 oid_key = g_malloc(oid_len * 22 + 1);
172 len = sprintf(p, "%lu", (unsigned long)oid[0]);
174 for (i = 1; i < oid_len;i++) {
175 len = sprintf(p, ".%lu", (unsigned long)oid[i]);
179 value = gssapi_lookup_oid_str(oid_key);
185 /* Display an ASN1 parse error. Taken from packet-snmp.c */
187 static dissector_handle_t data_handle;
189 static dissector_handle_t
190 gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
191 if (next_level_value == NULL) {
194 return next_level_value->handle;
198 dissect_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
199 proto_tree *tree, const char *field_name, int ret)
203 errstr = asn1_err_to_str(ret);
206 proto_tree_add_text(tree, tvb, offset, 0,
207 "ERROR: Couldn't parse %s: %s", field_name, errstr);
208 call_dissector(data_handle,
209 tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
214 * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
215 * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
216 * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
219 #define KRB_TOKEN_AP_REQ 0x0001
220 #define KRB_TOKEN_AP_REP 0x0002
221 #define KRB_TOKEN_AP_ERR 0x0003
222 #define KRB_TOKEN_GETMIC 0x0101
223 #define KRB_TOKEN_WRAP 0x0102
224 #define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
226 static const value_string spnego_krb5_tok_id_vals[] = {
227 { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
228 { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
229 { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
230 { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
231 { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
232 { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
236 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
237 #define KRB_SGN_ALG_MD2_5 0x0001
238 #define KRB_SGN_ALG_DES_MAC 0x0002
239 #define KRB_SGN_ALG_HMAC 0x0011
241 static const value_string spnego_krb5_sgn_alg_vals[] = {
242 { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
243 { KRB_SGN_ALG_MD2_5, "MD2.5"},
244 { KRB_SGN_ALG_DES_MAC, "DES MAC"},
245 { KRB_SGN_ALG_HMAC, "HMAC"},
249 #define KRB_SEAL_ALG_DES_CBC 0x0000
250 #define KRB_SEAL_ALG_RC4 0x0010
251 #define KRB_SEAL_ALG_NONE 0xffff
253 static const value_string spnego_krb5_seal_alg_vals[] = {
254 { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
255 { KRB_SEAL_ALG_RC4, "RC4"},
256 { KRB_SEAL_ALG_NONE, "None"},
261 * XXX - is this for SPNEGO or just GSS-API?
262 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
263 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
264 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
265 * getting it accepted.
268 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
270 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
273 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
280 guint len1, cls, con, tag, oid_len, nbytes;
284 gssapi_oid_value *value;
287 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
290 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
293 * The KRB5 blob conforms to RFC1964:
296 * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
299 * However, for some protocols, the KRB5 blob starts at the SHORT
300 * and has no DER encoded header etc.
302 * It appears that for some other protocols the KRB5 blob is just
303 * a Kerberos message, with no [APPLICATION 0] header, no OID,
308 * If we see an [APPLICATION 0] HEADER, we show the OID and
309 * the USHORT, and then dissect the rest as a Kerberos message.
311 * If we see an [APPLICATION 14] or [APPLICATION 15] header,
312 * we assume it's an AP-REQ or AP-REP message, and dissect
313 * it all as a Kerberos message.
315 * Otherwise, we show the USHORT, and then dissect the rest
316 * as a Kerberos message.
319 asn1_open(&hnd, tvb, offset);
322 * Get the first header ...
325 ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
327 if (ret != ASN1_ERR_NOERROR) {
328 dissect_parse_error(tvb, offset, pinfo, subtree,
329 "SPNEGO KRB5 Header", ret);
333 if (cls == ASN1_APL && con == ASN1_CON) {
335 * [APPLICATION <tag>]
348 ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
350 if (ret != ASN1_ERR_NOERROR) {
351 dissect_parse_error(tvb, offset, pinfo, subtree,
352 "SPNEGO supportedMech token", ret);
356 oid_string = format_oid(oid, oid_len);
358 value = gssapi_lookup_oid(oid, oid_len);
361 proto_tree_add_text(subtree, tvb, offset, nbytes,
363 oid_string, value->comment);
365 proto_tree_add_text(subtree, tvb, offset, nbytes,
373 /* Next, the token ID ... */
375 token_id = tvb_get_letohs(tvb, offset);
376 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
385 case 14: /* [APPLICATION 14] */
386 case 15: /* [APPLICATION 15] */
388 * No token ID - just dissect as a Kerberos message and
391 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
392 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
396 proto_tree_add_text(subtree, tvb, offset, 0,
397 "Unknown header (cls=%d, con=%d, tag=%d)",
402 /* Next, the token ID ... */
404 token_id = tvb_get_letohs(tvb, offset);
405 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
415 case KRB_TOKEN_AP_REQ:
416 case KRB_TOKEN_AP_REP:
417 case KRB_TOKEN_AP_ERR:
418 krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
419 offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
422 case KRB_TOKEN_GETMIC:
423 offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
427 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
430 case KRB_TOKEN_DELETE_SEC_CONTEXT:
444 #include <epan/crypt-md5.h>
446 #ifndef KEYTYPE_ARCFOUR_56
447 # define KEYTYPE_ARCFOUR_56 24
449 /* XXX - We should probably do a configure-time check for this instead */
450 #ifndef KRB5_KU_USAGE_SEAL
451 # define KRB5_KU_USAGE_SEAL 22
455 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
456 void *cksum_data, size_t cksum_size,
464 if (key_type == KEYTYPE_ARCFOUR_56) {
465 char L40[14] = "fortybits";
467 memcpy(L40 + 10, T, sizeof(T));
473 memset(&k5_data[7], 0xAB, 9);
483 cksum_data, cksum_size,
492 usage2arcfour(int usage)
495 case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
496 case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
498 case 22: /*KRB5_KU_USAGE_SEAL 22 */
500 case 23: /*KRB5_KU_USAGE_SIGN 23 */
502 case 24: /*KRB5_KU_USAGE_SEQ 24 */
510 arcfour_mic_cksum(char *key_data, int key_length,
513 const char *v1, size_t l1,
514 const void *v2, size_t l2,
515 const void *v3, size_t l3)
517 const char signature[] = "signaturekey";
521 unsigned char digest[16];
525 rc4_usage=usage2arcfour(usage);
526 md5_hmac(signature, sizeof(signature),
527 key_data, key_length,
530 t[0] = (rc4_usage >> 0) & 0xFF;
531 t[1] = (rc4_usage >> 8) & 0xFF;
532 t[2] = (rc4_usage >> 16) & 0xFF;
533 t[3] = (rc4_usage >> 24) & 0xFF;
534 md5_append(&ms, t, 4);
535 md5_append(&ms, v1, l1);
536 md5_append(&ms, v2, l2);
537 md5_append(&ms, v3, l3);
538 md5_finish(&ms, digest);
539 md5_hmac(digest, 16, ksign_c, 16, cksum);
541 memcpy(sgn_cksum, cksum, 8);
547 * Verify padding of a gss wrapped message and return its length.
550 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
558 pad = wrapped_data + wrapped_length - 1;
561 if (padlength > datalen)
564 for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
575 decrypt_arcfour(packet_info *pinfo,
576 char *input_message_buffer,
577 char *output_message_buffer,
578 char *key_value, int key_size, int key_type)
580 unsigned char Klocaldata[16];
584 char k6_data[16], SND_SEQ[8], Confounder[8];
590 datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
592 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
594 } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
600 if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
604 ret = arcfour_mic_key(key_value, key_size, key_type,
605 (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
613 rc4_state_struct rc4_state;
615 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
616 memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
617 crypt_rc4(&rc4_state, SND_SEQ, 8);
619 memset(k6_data, 0, sizeof(k6_data));
622 seq_number=g_ntohl(*((guint32 *)SND_SEQ));
624 cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
626 cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
636 for (i = 0; i < 16; i++)
637 Klocaldata[i] = ((u_char *)key_value)[i] ^ 0xF0;
639 ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
642 memset(Klocaldata, 0, sizeof(Klocaldata));
648 rc4_state_struct rc4_state;
650 crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
651 memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
652 crypt_rc4(&rc4_state, Confounder, 8);
653 memcpy(output_message_buffer, input_message_buffer, datalen);
654 crypt_rc4(&rc4_state, output_message_buffer, datalen);
657 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
659 memcpy(output_message_buffer,
660 input_message_buffer,
663 memset(k6_data, 0, sizeof(k6_data));
665 /* only normal (i.e. non DCE style wrapping use padding ? */
666 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
667 ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
674 /* dont know what the checksum looks like for dce style gssapi */
675 if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
676 ret = arcfour_mic_cksum(key_value, key_size,
679 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
680 Confounder, sizeof(Confounder),
681 output_message_buffer,
687 cmp = memcmp(cksum_data,
688 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
700 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
703 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
708 const guint8 *original_data;
710 static int omb_index=0;
711 static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
712 static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
713 guint8 *output_message_buffer;
719 output_message_buffer=omb_arr[omb_index];
722 length=tvb_length(pinfo->gssapi_encrypted_tvb);
723 original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
725 /* dont do anything if we are not attempting to decrypt data */
731 /* XXX we should only do this for first time, then store somewhere */
732 /* XXX We also need to re-read the keytab when the preference changes */
738 cryptocopy=g_malloc(length);
739 if(output_message_buffer){
740 g_free(output_message_buffer);
741 output_message_buffer=NULL;
743 output_message_buffer=g_malloc(length);
745 for(ek=enc_key_list;ek;ek=ek->next){
746 /* shortcircuit and bail out if enctypes are not matching */
747 if(ek->keytype!=keytype){
751 /* pre-0.6.1 versions of Heimdal would sometimes change
752 the cryptotext data even when the decryption failed.
753 This would obviously not work since we iterate over the
754 keys. So just give it a copy of the crypto data instead.
755 This has been seen for RC4-HMAC blobs.
757 memcpy(cryptocopy, original_data, length);
758 ret=decrypt_arcfour(pinfo,
760 output_message_buffer,
766 proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
767 pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
768 output_message_buffer,
770 tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
771 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
777 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
783 * XXX - This is for GSSAPI Wrap tokens ...
786 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
787 #ifndef HAVE_KERBEROS
790 , proto_tree *tree, guint16 token_id
791 #ifndef HAVE_KERBEROS
796 guint16 sgn_alg, seal_alg;
798 int start_offset=offset;
802 * The KRB5 blob conforms to RFC1964:
803 * USHORT (0x0102 == GSS_Wrap)
807 /* Now, the sign and seal algorithms ... */
809 sgn_alg = tvb_get_letohs(tvb, offset);
810 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
815 seal_alg = tvb_get_letohs(tvb, offset);
816 proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
821 /* Skip the filler */
825 /* Encrypted sequence number */
827 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
832 /* Checksum of plaintext padded data */
834 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
840 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
841 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
842 * extra 8 bytes of "Random confounder" after the checksum.
843 * It certainly confounds code expecting all Kerberos 5
844 * GSS_Wrap() tokens to look the same....
846 if (sgn_alg == KRB_SGN_ALG_HMAC) {
847 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
852 /* Is the data encrypted? */
853 pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
856 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
857 if(pinfo->decrypt_gssapi_tvb){
858 /* if the caller did not provide a tvb, then we just use
859 whatever is left of our current tvb.
861 if(!pinfo->gssapi_encrypted_tvb){
863 len=tvb_reported_length_remaining(tvb,offset);
864 if(len>tvb_length_remaining(tvb, offset)){
865 /* no point in trying to decrypt,
866 we dont have the full pdu.
870 pinfo->gssapi_encrypted_tvb = tvb_new_subset(
871 tvb, offset, len, len);
874 /* if this is KRB5 wrapped rc4-hmac */
875 if((token_id==KRB_TOKEN_WRAP)
876 &&(sgn_alg==KRB_SGN_ALG_HMAC)
877 &&(seal_alg==KRB_SEAL_ALG_RC4)){
878 /* do we need to create a tvb for the wrapper
881 if(!pinfo->gssapi_wrap_tvb){
882 pinfo->gssapi_wrap_tvb = tvb_new_subset(
884 GSS_ARCFOUR_WRAP_TOKEN_SIZE,
885 GSS_ARCFOUR_WRAP_TOKEN_SIZE);
887 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
888 decrypt_gssapi_krb_arcfour_wrap(tree,
892 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
897 * Return the offset past the checksum, so that we know where
898 * the data we're wrapped around starts. Also, set the length
899 * of our top-level item to that offset, so it doesn't cover
900 * the data we're wrapped around.
902 * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
909 * XXX - This is for GSSAPI GetMIC tokens ...
912 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
917 * The KRB5 blob conforms to RFC1964:
918 * USHORT (0x0101 == GSS_GetMIC)
922 /* Now, the sign algorithm ... */
924 sgn_alg = tvb_get_letohs(tvb, offset);
925 proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
930 /* Skip the filler */
934 /* Encrypted sequence number */
936 proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
941 /* Checksum of plaintext padded data */
943 proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
949 * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
950 * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
951 * extra 8 bytes of "Random confounder" after the checksum.
952 * It certainly confounds code expecting all Kerberos 5
953 * GSS_Wrap() tokens to look the same....
955 if (sgn_alg == KRB_SGN_ALG_HMAC) {
956 proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
963 * Return the offset past the checksum, so that we know where
964 * the data we're wrapped around starts. Also, set the length
965 * of our top-level item to that offset, so it doesn't cover
966 * the data we're wrapped around.
973 * XXX - is this for SPNEGO or just GSS-API?
974 * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
975 * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
976 * than designating SPNEGO as the mechanism, offering Kerberos V5, and
977 * getting it accepted.
980 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
987 item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
989 subtree = proto_item_add_subtree(item, ett_spnego_krb5);
992 * The KRB5 blob conforms to RFC1964:
993 * USHORT (0x0102 == GSS_Wrap)
997 /* First, the token ID ... */
999 token_id = tvb_get_letohs(tvb, offset);
1000 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1005 offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1008 * Return the offset past the checksum, so that we know where
1009 * the data we're wrapped around starts. Also, set the length
1010 * of our top-level item to that offset, so it doesn't cover
1011 * the data we're wrapped around.
1013 proto_item_set_len(item, offset);
1017 /* Spnego stuff from here */
1020 dissect_spnego_mechTypes(tvbuff_t *tvb, int offset, packet_info *pinfo,
1022 gssapi_oid_value **next_level_value_p)
1024 proto_item *item = NULL;
1025 proto_tree *subtree = NULL;
1026 gboolean saw_mechanism = FALSE;
1027 int start_offset, start_oid_offset;
1029 gboolean pc, ind_field;
1032 gchar oid[MAX_OID_STR_LEN];
1034 start_offset=offset;
1036 * MechTypeList ::= SEQUENCE OF MechType
1038 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1039 offset = get_ber_length(tree, tvb, offset, &len1, &ind_field);
1041 if (!(class == BER_CLASS_UNI && pc && tag == BER_UNI_TAG_SEQUENCE)) {
1042 proto_tree_add_text(
1043 tree, tvb, offset, 0,
1044 "Unknown header (class=%d, pc=%d, tag=%d)",
1049 item = proto_tree_add_item(tree, hf_spnego_mechtype, tvb,
1050 start_offset, len1, FALSE);
1051 subtree = proto_item_add_subtree(item, ett_spnego_mechtype);
1054 * Now, the object IDs ...
1056 start_oid_offset=offset;
1057 while (offset<(start_oid_offset+len1)) {
1058 gssapi_oid_value *value;
1060 offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_mech, oid);
1061 value = gssapi_lookup_oid_str(oid);
1064 * Tell our caller the first mechanism we see, so that if
1065 * this is a negTokenInit with a mechToken, it can interpret
1066 * the mechToken according to the first mechType. (There
1067 * might not have been any indication of the mechType
1068 * in prior frames, so we can't necessarily use the
1069 * mechanism from the conversation; i.e., a negTokenInit
1070 * can contain the initial security token for the desired
1071 * mechanism of the initiator - that's the first mechanism
1074 if (!saw_mechanism) {
1076 *next_level_value_p = value;
1077 saw_mechanism = TRUE;
1088 dissect_spnego_reqFlags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1089 proto_tree *tree, ASN1_SCK *hnd)
1092 guint len1, cls, con, tag, flags;
1095 proto_tree *subtree;
1097 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1099 if (ret != ASN1_ERR_NOERROR) {
1100 dissect_parse_error(tvb, offset, pinfo, tree,
1101 "SPNEGO reqFlags header", ret);
1105 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_BTS)) {
1106 proto_tree_add_text(
1107 tree, tvb, offset, 0,
1108 "Unknown header (cls=%d, con=%d, tag=%d)",
1113 /* We must have a Bit String ... insert it */
1115 offset = hnd->offset;
1117 flags = tvb_get_guint8(tvb, offset);
1119 item = proto_tree_add_item(tree, hf_spnego_reqflags, tvb, offset, len1,
1122 subtree = proto_item_add_subtree(item, ett_spnego_reqflags);
1125 * Now, the bits. XXX: Assume 8 bits. FIXME.
1128 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_deleg, tvb, offset, len1, flags);
1129 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_mutual, tvb, offset, len1, flags);
1130 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_replay, tvb, offset, len1, flags);
1131 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_sequence, tvb, offset, len1, flags);
1132 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_anon, tvb, offset, len1, flags);
1133 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_conf, tvb, offset, len1, flags);
1134 proto_tree_add_boolean(subtree, hf_gssapi_reqflags_integ, tvb, offset, len1, flags);
1136 hnd->offset += len1;
1139 return offset + len1;
1144 dissect_spnego_mechToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1145 proto_tree *tree, ASN1_SCK *hnd,
1146 dissector_handle_t next_level_dissector)
1149 proto_tree *subtree;
1152 guint cls, con, tag, nbytes;
1153 gint length_remaining, reported_length_remaining;
1154 tvbuff_t *token_tvb;
1157 * This appears to be a simple octet string ...
1160 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
1162 if (ret != ASN1_ERR_NOERROR) {
1163 dissect_parse_error(tvb, offset, pinfo, tree,
1164 "SPNEGO sequence header", ret);
1168 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
1169 proto_tree_add_text(
1170 tree, tvb, offset, 0,
1171 "Unknown header (cls=%d, con=%d, tag=%d)",
1176 offset = hnd->offset;
1179 /* Dont try to create an item with more bytes than remains in the
1180 * frame or we will not even attempt to dissect those bytes we
1181 * do have. (since there will be an exception)
1183 * We use "tvb_ensure_length_remaining()" so that we throw
1184 * an exception if there's nothing to dissect.
1186 length_remaining = tvb_ensure_length_remaining(tvb,offset);
1187 reported_length_remaining = tvb_reported_length_remaining(tvb,offset);
1188 if ((guint)length_remaining > nbytes)
1189 length_remaining = nbytes;
1190 if ((guint)reported_length_remaining > nbytes)
1191 reported_length_remaining = nbytes;
1192 item = proto_tree_add_item(tree, hf_spnego_mechtoken, tvb, offset,
1193 length_remaining, FALSE);
1194 subtree = proto_item_add_subtree(item, ett_spnego_mechtoken);
1197 * Now, we should be able to dispatch after creating a new TVB.
1200 token_tvb = tvb_new_subset(tvb, offset, length_remaining,
1201 reported_length_remaining);
1202 if (next_level_dissector)
1203 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1205 hnd->offset += nbytes; /* Update this ... */
1208 return offset + nbytes;
1212 dissect_spnego_mechListMIC(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1213 proto_tree *tree, ASN1_SCK *hnd,
1214 dissector_handle_t next_level_dissector)
1216 guint len1, cls, con, tag;
1219 proto_tree *subtree = NULL;
1222 * Add the mechListMIC [3] Octet String or General String ...
1224 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1226 if (ret != ASN1_ERR_NOERROR) {
1227 dissect_parse_error(tvb, offset, pinfo, subtree,
1228 "SPNEGO sequence header", ret);
1232 offset = hnd->offset;
1234 if (cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ) {
1237 * There seems to be two different forms this can take
1238 * One as an Octet string, and one as a general string in a
1239 * sequence ... We will have to dissect this later
1242 proto_tree_add_text(tree, tvb, offset + 4, len1 - 4,
1244 tvb_format_text(tvb, offset + 4, len1 - 4));
1246 /* Naughty ... but we have to adjust for what we never took */
1248 hnd->offset += len1;
1252 else if (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS) {
1253 tvbuff_t *token_tvb;
1255 proto_tree *subtree;
1257 item = proto_tree_add_item(tree, hf_spnego_mechlistmic, tvb, offset,
1259 subtree = proto_item_add_subtree(item, ett_spnego_mechlistmic);
1262 * Now, we should be able to dispatch after creating a new TVB.
1265 token_tvb = tvb_new_subset(tvb, offset, len1, -1);
1266 if (next_level_dissector)
1267 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1269 hnd->offset += len1; /* Update this ... */
1275 proto_tree_add_text(subtree, tvb, offset, 0,
1276 "Unknown header (cls=%d, con=%d, tag=%d)",
1288 dissect_spnego_negTokenInit(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1289 proto_tree *tree, ASN1_SCK *hnd,
1290 gssapi_oid_value **next_level_value_p)
1293 proto_tree *subtree;
1295 guint len1, len, cls, con, tag;
1298 item = proto_tree_add_item( tree, hf_spnego_negtokeninit, tvb, offset,
1300 subtree = proto_item_add_subtree(item, ett_spnego_negtokeninit);
1303 * Here is what we need to get ...
1304 * NegTokenInit ::= SEQUENCE {
1305 * mechTypes [0] MechTypeList OPTIONAL,
1306 * reqFlags [1] ContextFlags OPTIONAL,
1307 * mechToken [2] OCTET STRING OPTIONAL,
1308 * mechListMIC [3] OCTET STRING OPTIONAL }
1312 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1314 if (ret != ASN1_ERR_NOERROR) {
1315 dissect_parse_error(tvb, offset, pinfo, subtree,
1316 "SPNEGO sequence header", ret);
1320 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
1321 proto_tree_add_text(
1322 subtree, tvb, offset, 0,
1323 "Unknown header (cls=%d, con=%d, tag=%d)",
1328 offset = hnd->offset;
1333 hdr_ofs = hnd->offset;
1335 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1337 if (ret != ASN1_ERR_NOERROR) {
1338 dissect_parse_error(tvb, offset, pinfo, subtree,
1339 "SPNEGO context header", ret);
1343 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1344 proto_tree_add_text(subtree, tvb, offset, 0,
1345 "Unknown header (cls=%d, con=%d, tag=%d)",
1350 /* Adjust for the length of the header */
1352 len1 -= (hnd->offset - hdr_ofs);
1354 /* Should be one of the fields */
1358 case SPNEGO_mechTypes:
1360 offset = dissect_spnego_mechTypes(tvb, hnd->offset, pinfo,
1362 next_level_value_p);
1367 case SPNEGO_reqFlags:
1369 offset = dissect_spnego_reqFlags(tvb, offset, pinfo, subtree, hnd);
1373 case SPNEGO_mechToken:
1375 offset = dissect_spnego_mechToken(tvb, offset, pinfo, subtree,
1376 hnd, gssapi_dissector_handle(*next_level_value_p));
1379 case SPNEGO_mechListMIC:
1381 offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
1382 hnd, gssapi_dissector_handle(*next_level_value_p));
1396 return offset; /* Not sure this is right */
1400 dissect_spnego_negResult(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1401 proto_tree *tree, ASN1_SCK *hnd)
1405 guint len, cls, con, tag, val;
1407 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1409 if (ret != ASN1_ERR_NOERROR) {
1410 dissect_parse_error(tvb, offset, pinfo, tree,
1411 "SPNEGO context header", ret);
1415 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_ENUM)) {
1416 proto_tree_add_text(
1417 tree, tvb, offset, 0,
1418 "Unknown header (cls=%d, con=%d, tag=%d) xxx",
1423 offset = hnd->offset;
1425 /* Now, get the value */
1427 ret = asn1_uint32_value_decode(hnd, len, &val);
1429 if (ret != ASN1_ERR_NOERROR) {
1430 dissect_parse_error(tvb, offset, pinfo, tree,
1431 "SPNEGO negResult value", ret);
1435 proto_tree_add_item(tree, hf_spnego_negtokentarg_negresult, tvb,
1438 offset = hnd->offset;
1445 dissect_spnego_supportedMech(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1446 proto_tree *tree, ASN1_SCK *hnd,
1447 gssapi_oid_value **next_level_value_p)
1450 guint oid_len, nbytes;
1453 gssapi_oid_value *value;
1454 conversation_t *conversation;
1457 * Now, get the OID, and find the handle, if any
1460 offset = hnd->offset;
1462 ret = asn1_oid_decode(hnd, &oid, &oid_len, &nbytes);
1464 if (ret != ASN1_ERR_NOERROR) {
1465 dissect_parse_error(tvb, offset, pinfo, tree,
1466 "SPNEGO supportedMech token", ret);
1470 oid_string = format_oid(oid, oid_len);
1471 value = gssapi_lookup_oid(oid, oid_len);
1474 proto_tree_add_text(tree, tvb, offset, nbytes,
1475 "supportedMech: %s (%s)",
1476 oid_string, value->comment);
1478 proto_tree_add_text(tree, tvb, offset, nbytes, "supportedMech: %s",
1485 /* Should check for an unrecognized OID ... */
1488 *next_level_value_p = value;
1491 * Now, we need to save this in per proto info in the
1492 * conversation if it exists. We also should create a
1493 * conversation if one does not exist. FIXME!
1494 * Hmmm, might need to be smarter, because there can be
1495 * multiple mechTypes in a negTokenInit with one being the
1496 * default used in the Token if present. Then the negTokenTarg
1497 * could override that. :-(
1500 if ((conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1501 pinfo->ptype, pinfo->srcport,
1502 pinfo->destport, 0))) {
1505 conversation_add_proto_data(conversation, proto_spnego,
1506 *next_level_value_p);
1517 dissect_spnego_responseToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1518 proto_tree *tree, ASN1_SCK *hnd,
1519 dissector_handle_t next_level_dissector)
1523 guint cls, con, tag, nbytes;
1524 tvbuff_t *token_tvb;
1526 proto_tree *subtree;
1528 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
1530 if (ret != ASN1_ERR_NOERROR) {
1531 dissect_parse_error(tvb, offset, pinfo, tree,
1532 "SPNEGO sequence header", ret);
1536 if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
1537 proto_tree_add_text(
1538 tree, tvb, offset, 0,
1539 "Unknown header (cls=%d, con=%d, tag=%d)",
1544 offset = hnd->offset;
1546 item = proto_tree_add_item(tree, hf_spnego_responsetoken, tvb, offset -2 ,
1549 subtree = proto_item_add_subtree(item, ett_spnego_responsetoken);
1553 * Now, we should be able to dispatch after creating a new TVB.
1554 * However, we should make sure that there is something in the
1555 * response token ...
1559 token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
1560 if (next_level_dissector)
1561 call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
1564 proto_tree_add_text(subtree, tvb, offset-2, 2, "<Empty String>");
1566 hnd->offset += nbytes; /* Update this ... */
1569 return offset + nbytes;
1573 dissect_spnego_negTokenTarg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1574 proto_tree *tree, ASN1_SCK *hnd,
1575 gssapi_oid_value **next_level_value_p)
1579 proto_tree *subtree;
1582 guint len1, len, cls, con, tag;
1584 item = proto_tree_add_item( tree, hf_spnego_negtokentarg, tvb, offset,
1586 subtree = proto_item_add_subtree(item, ett_spnego_negtokentarg);
1589 * Here is what we need to get ...
1590 * NegTokenTarg ::= SEQUENCE {
1591 * negResult [0] ENUMERATED {
1592 * accept_completed (0),
1593 * accept_incomplete (1),
1594 * reject (2) } OPTIONAL,
1595 * supportedMech [1] MechType OPTIONAL,
1596 * responseToken [2] OCTET STRING OPTIONAL,
1597 * mechListMIC [3] OCTET STRING OPTIONAL }
1600 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
1602 if (ret != ASN1_ERR_NOERROR) {
1603 dissect_parse_error(tvb, offset, pinfo, subtree,
1604 "SPNEGO sequence header", ret);
1608 if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
1609 proto_tree_add_text(
1610 subtree, tvb, offset, 0,
1611 "Unknown header (cls=%d, con=%d, tag=%d)",
1616 offset = hnd->offset;
1621 hdr_ofs = hnd->offset;
1623 ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
1625 if (ret != ASN1_ERR_NOERROR) {
1626 dissect_parse_error(tvb, offset, pinfo, subtree,
1627 "SPNEGO context header", ret);
1631 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1632 proto_tree_add_text(
1633 subtree, tvb, offset, 0,
1634 "Unknown header (cls=%d, con=%d, tag=%d)",
1639 /* Adjust for the length of the header */
1641 len1 -= (hnd->offset - hdr_ofs);
1643 /* Should be one of the fields */
1647 case SPNEGO_negResult:
1649 offset = dissect_spnego_negResult(tvb, offset, pinfo, subtree,
1653 case SPNEGO_supportedMech:
1655 offset = dissect_spnego_supportedMech(tvb, offset, pinfo, subtree,
1656 hnd, next_level_value_p);
1660 case SPNEGO_responseToken:
1662 offset = dissect_spnego_responseToken(tvb, offset, pinfo, subtree,
1663 hnd, gssapi_dissector_handle(*next_level_value_p));
1666 case SPNEGO_mechListMIC:
1668 offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
1669 hnd, gssapi_dissector_handle(*next_level_value_p));
1687 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1690 proto_tree *subtree;
1691 int ret, offset = 0;
1694 guint len1, cls, con, tag;
1695 conversation_t *conversation;
1696 gssapi_oid_value *next_level_value;
1699 * We need this later, so lets get it now ...
1700 * It has to be per-frame as there can be more than one GSS-API
1701 * negotiation in a conversation.
1704 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1705 if (!next_level_value && !pinfo->fd->flags.visited) {
1707 * No handle attached to this frame, but it's the first
1708 * pass, so it'd be attached to the conversation.
1709 * If we have a conversation, try to get the handle,
1710 * and if we get one, attach it to the frame.
1712 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1713 pinfo->ptype, pinfo->srcport,
1714 pinfo->destport, 0);
1717 next_level_value = conversation_get_proto_data(conversation,
1719 if (next_level_value)
1720 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1724 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1727 subtree = proto_item_add_subtree(item, ett_spnego);
1730 * The TVB contains a [0] header and a sequence that consists of an
1731 * object ID and a blob containing the data ...
1732 * Actually, it contains, according to RFC2478:
1733 * NegotiationToken ::= CHOICE {
1734 * negTokenInit [0] NegTokenInit,
1735 * negTokenTarg [1] NegTokenTarg }
1736 * NegTokenInit ::= SEQUENCE {
1737 * mechTypes [0] MechTypeList OPTIONAL,
1738 * reqFlags [1] ContextFlags OPTIONAL,
1739 * mechToken [2] OCTET STRING OPTIONAL,
1740 * mechListMIC [3] OCTET STRING OPTIONAL }
1741 * NegTokenTarg ::= SEQUENCE {
1742 * negResult [0] ENUMERATED {
1743 * accept_completed (0),
1744 * accept_incomplete (1),
1745 * reject (2) } OPTIONAL,
1746 * supportedMech [1] MechType OPTIONAL,
1747 * responseToken [2] OCTET STRING OPTIONAL,
1748 * mechListMIC [3] OCTET STRING OPTIONAL }
1750 * Windows typically includes mechTypes and mechListMic ('NONE'
1751 * in the case of NTLMSSP only).
1752 * It seems to duplicate the responseToken into the mechListMic field
1753 * as well. Naughty, naughty.
1757 asn1_open(&hnd, tvb, offset);
1760 * Get the first header ...
1763 ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
1765 if (ret != ASN1_ERR_NOERROR) {
1766 dissect_parse_error(tvb, offset, pinfo, subtree,
1767 "SPNEGO context header", ret);
1771 if (!(cls == ASN1_CTX && con == ASN1_CON)) {
1772 proto_tree_add_text(
1773 subtree, tvb, offset, 0,
1774 "Unknown header (cls=%d, con=%d, tag=%d)",
1779 offset = hnd.offset;
1782 * The Tag is one of negTokenInit or negTokenTarg
1787 case SPNEGO_negTokenInit:
1789 offset = dissect_spnego_negTokenInit(tvb, offset, pinfo,
1795 case SPNEGO_negTokenTarg:
1797 offset = dissect_spnego_negTokenTarg(tvb, offset, pinfo,
1802 default: /* Broken, what to do? */
1809 asn1_close(&hnd, &offset);
1814 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1817 proto_tree *subtree;
1819 conversation_t *conversation;
1820 gssapi_oid_value *next_level_value;
1821 tvbuff_t *token_tvb;
1822 int len, offset, start_offset;
1824 gboolean pc, ind_field;
1827 gchar oid[MAX_OID_STR_LEN];
1830 offset=start_offset;
1833 * We need this later, so lets get it now ...
1834 * It has to be per-frame as there can be more than one GSS-API
1835 * negotiation in a conversation.
1838 next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1839 if (!next_level_value && !pinfo->fd->flags.visited) {
1841 * No handle attached to this frame, but it's the first
1842 * pass, so it'd be attached to the conversation.
1843 * If we have a conversation, try to get the handle,
1844 * and if we get one, attach it to the frame.
1846 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1847 pinfo->ptype, pinfo->srcport,
1848 pinfo->destport, 0);
1851 next_level_value = conversation_get_proto_data(conversation,
1853 if (next_level_value)
1854 p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1858 item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1861 subtree = proto_item_add_subtree(item, ett_spnego);
1864 * The TVB contains a [0] header and a sequence that consists of an
1865 * object ID and a blob containing the data ...
1866 * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1867 * with the "optional" "use in non-initial tokens" being chosen.
1871 * Get the first header ...
1873 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1874 offset = get_ber_length(tree, tvb, offset, &len1, &ind_field);
1876 if (!(class == BER_CLASS_APP && pc && tag == 0)) {
1877 proto_tree_add_text(
1878 subtree, tvb, start_offset, 0,
1879 "Unknown header (class=%d, pc=%d, tag=%d)",
1881 return_offset = tvb_length(tvb);
1886 * Get the OID, and find the handle, if any
1888 * XXX - what should we do if this OID doesn't match the value
1889 * attached to the frame or conversation? (That would be
1890 * bogus, but that's not impossible - some broken implementation
1891 * might negotiate some security mechanism but put the OID
1892 * for some other security mechanism in GSS_Wrap tokens.)
1894 offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_this_mech, oid);
1895 next_level_value = gssapi_lookup_oid_str(oid);
1898 * Now dissect the GSS_Wrap token; it's assumed to be in the
1899 * rest of the tvbuff.
1901 item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset,
1904 subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
1907 * Now, we should be able to dispatch after creating a new TVB.
1908 * The subdissector must return the length of the part of the
1909 * token it dissected, so we can return the length of the part
1910 * we (and it) dissected.
1913 token_tvb = tvb_new_subset(tvb, offset, -1, -1);
1914 if (next_level_value->wrap_handle) {
1915 len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
1917 return_offset = tvb_length(tvb);
1919 return_offset = offset + len;
1921 return_offset = tvb_length(tvb);
1924 return return_offset;
1928 proto_register_spnego(void)
1930 static hf_register_info hf[] = {
1932 { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1934 { &hf_spnego_mech, {
1935 "Mech", "spnego.mech", FT_STRING, BASE_NONE,
1936 NULL, 0, "This is a SPNEGO Object Identifier", HFILL }},
1937 { &hf_spnego_this_mech, {
1938 "thisMech", "spnego.this_mech", FT_STRING, BASE_NONE,
1939 NULL, 0, "This is a SPNEGO Object Identifier", HFILL }},
1940 { &hf_spnego_negtokeninit,
1941 { "negTokenInit", "spnego.negtokeninit", FT_NONE, BASE_NONE,
1942 NULL, 0x0, "SPNEGO negTokenInit", HFILL}},
1943 { &hf_spnego_negtokentarg,
1944 { "negTokenTarg", "spnego.negtokentarg", FT_NONE, BASE_NONE,
1945 NULL, 0x0, "SPNEGO negTokenTarg", HFILL}},
1946 { &hf_spnego_mechtype,
1947 { "mechType", "spnego.negtokeninit.mechtype", FT_NONE,
1948 BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechTypes", HFILL}},
1949 { &hf_spnego_mechtoken,
1950 { "mechToken", "spnego.negtokeninit.mechtoken", FT_NONE,
1951 BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechToken", HFILL}},
1952 { &hf_spnego_mechlistmic,
1953 { "mechListMIC", "spnego.mechlistmic", FT_NONE,
1954 BASE_NONE, NULL, 0x0, "SPNEGO mechListMIC", HFILL}},
1955 { &hf_spnego_responsetoken,
1956 { "responseToken", "spnego.negtokentarg.responsetoken",
1957 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO responseToken",
1959 { &hf_spnego_negtokentarg_negresult,
1960 { "negResult", "spnego.negtokeninit.negresult", FT_UINT16,
1961 BASE_HEX, VALS(spnego_negResult_vals), 0, "negResult", HFILL}},
1962 { &hf_spnego_reqflags,
1963 { "reqFlags", "spnego.negtokeninit.reqflags", FT_BYTES,
1964 BASE_HEX, NULL, 0, "reqFlags", HFILL }},
1965 { &hf_gssapi_reqflags_deleg,
1966 { "Delegation", "gssapi.reqflags.deleg", FT_BOOLEAN, 8,
1967 TFS(&tfs_reqflags_deleg), 0x01, "Delegation", HFILL }},
1968 { &hf_gssapi_reqflags_mutual,
1969 { "Mutual Authentication", "gssapi.reqflags.mutual", FT_BOOLEAN,
1970 8, TFS(&tfs_reqflags_mutual), 0x02, "Mutual Authentication", HFILL}},
1971 { &hf_gssapi_reqflags_replay,
1972 { "Replay Detection", "gssapi.reqflags.replay", FT_BOOLEAN,
1973 8, TFS(&tfs_reqflags_replay), 0x04, "Replay Detection", HFILL}},
1974 { &hf_gssapi_reqflags_sequence,
1975 { "Out-of-sequence Detection", "gssapi.reqflags.sequence",
1976 FT_BOOLEAN, 8, TFS(&tfs_reqflags_sequence), 0x08,
1977 "Out-of-sequence Detection", HFILL}},
1978 { &hf_gssapi_reqflags_anon,
1979 { "Anonymous Authentication", "gssapi.reqflags.anon",
1980 FT_BOOLEAN, 8, TFS(&tfs_reqflags_anon), 0x10,
1981 "Anonymous Authentication", HFILL}},
1982 { &hf_gssapi_reqflags_conf,
1983 { "Per-message Confidentiality", "gssapi.reqflags.conf",
1984 FT_BOOLEAN, 8, TFS(&tfs_reqflags_conf), 0x20,
1985 "Per-message Confidentiality", HFILL}},
1986 { &hf_gssapi_reqflags_integ,
1987 { "Per-message Integrity", "gssapi.reqflags.integ",
1988 FT_BOOLEAN, 8, TFS(&tfs_reqflags_integ), 0x40,
1989 "Per-message Integrity", HFILL}},
1990 { &hf_spnego_wraptoken,
1991 { "wrapToken", "spnego.wraptoken",
1992 FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1995 { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1996 BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1997 { &hf_spnego_krb5_tok_id,
1998 { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1999 VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
2000 { &hf_spnego_krb5_sgn_alg,
2001 { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
2002 VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
2003 { &hf_spnego_krb5_seal_alg,
2004 { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
2005 VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
2006 { &hf_spnego_krb5_snd_seq,
2007 { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
2008 NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
2009 { &hf_spnego_krb5_sgn_cksum,
2010 { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
2011 NULL, 0, "KRB5 Data Checksum", HFILL}},
2012 { &hf_spnego_krb5_confounder,
2013 { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
2014 NULL, 0, "KRB5 Confounder", HFILL}},
2017 static gint *ett[] = {
2019 &ett_spnego_negtokeninit,
2020 &ett_spnego_negtokentarg,
2021 &ett_spnego_mechtype,
2022 &ett_spnego_mechtoken,
2023 &ett_spnego_mechlistmic,
2024 &ett_spnego_responsetoken,
2025 &ett_spnego_wraptoken,
2029 proto_spnego = proto_register_protocol(
2030 "Spnego", "Spnego", "spnego");
2031 proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
2035 proto_register_field_array(proto_spnego, hf, array_length(hf));
2036 proto_register_subtree_array(ett, array_length(ett));
2040 proto_reg_handoff_spnego(void)
2042 dissector_handle_t spnego_handle, spnego_wrap_handle;
2043 dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
2045 /* Register protocol with GSS-API module */
2047 spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
2048 spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
2050 gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
2051 spnego_handle, spnego_wrap_handle,
2052 "SPNEGO - Simple Protected Negotiation");
2054 /* Register both the one MS created and the real one */
2056 * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
2057 * mystery of the MS KRB5 OID is cleared up. It was due to a library
2058 * that did not handle OID components greater than 16 bits, and was
2059 * fixed in Win2K SP2 as well as WinXP.
2060 * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
2061 * SPNEGO implementation issues. 3-Dec-2002.
2063 spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
2065 spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
2067 gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2068 spnego_krb5_handle, spnego_krb5_wrap_handle,
2069 "MS KRB5 - Microsoft Kerberos 5");
2070 gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
2071 spnego_krb5_handle, spnego_krb5_wrap_handle,
2072 "KRB5 - Kerberos 5");
2073 gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
2074 spnego_krb5_handle, spnego_krb5_wrap_handle,
2075 "KRB5 - Kerberos 5 - User to User");
2078 * Find the data handle for some calls
2080 data_handle = find_dissector("data");