aboutsummaryrefslogtreecommitdiffstats
path: root/asn1
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2005-09-15 05:38:37 +0000
committerAnders Broman <anders.broman@ericsson.com>2005-09-15 05:38:37 +0000
commit0060eaf3908ebdb5673b914a83ceca316d9591fb (patch)
treedabe7ca1b969aa3cc512537af5ed1d1e2062e5bd /asn1
parent11a05a318aa303af591546020eb9811315dc8071 (diff)
Replace the spnego dissector with an asn2eth generated one.
svn path=/trunk/; revision=15810
Diffstat (limited to 'asn1')
-rw-r--r--asn1/spnego/Makefile.nmake42
-rw-r--r--asn1/spnego/packet-spnego-template.c1074
-rw-r--r--asn1/spnego/packet-spnego-template.h30
-rw-r--r--asn1/spnego/spnego.asn85
-rw-r--r--asn1/spnego/spnego.cnf128
5 files changed, 1359 insertions, 0 deletions
diff --git a/asn1/spnego/Makefile.nmake b/asn1/spnego/Makefile.nmake
new file mode 100644
index 0000000000..392f95f102
--- /dev/null
+++ b/asn1/spnego/Makefile.nmake
@@ -0,0 +1,42 @@
+## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
+#
+# $Id$
+
+include ../../config.nmake
+
+UNIX2DOS=$(PERL) ../../tools/unix2dos.pl
+
+PROTOCOL_NAME=spnego
+DISSECTOR_FILES=packet-$(PROTOCOL_NAME).c packet-$(PROTOCOL_NAME).h
+
+all: generate_dissector
+
+generate_dissector: $(DISSECTOR_FILES)
+
+$(DISSECTOR_FILES): ../../tools/asn2eth.py spnego.asn packet-spnego-template.c packet-spnego-template.h spnego.cnf
+!IFDEF PYTHON
+ $(PYTHON) ../../tools/asn2eth.py -X -b -e -p $(PROTOCOL_NAME) -c spnego.cnf -s packet-spnego-template spnego.asn
+!ELSE
+ @echo Error: You need Python to use asn2eth.py
+ @exit 1
+!ENDIF
+
+clean:
+ rm -f parsetab.py $(DISSECTOR_FILES)
+
+# Fix EOL in generated dissectors. Cygwin's python generates files with
+# mixed EOL styles, which can't be commited to the SVN repository.
+# Stuff included from template and "cnf" files has "\r\n" on windows, while
+# the generated stuff has "\n".
+
+fix_eol: generate_dissector
+ move packet-$(PROTOCOL_NAME).c packet-$(PROTOCOL_NAME).c.tmp
+ move packet-$(PROTOCOL_NAME).h packet-$(PROTOCOL_NAME).h.tmp
+ $(UNIX2DOS) < packet-$(PROTOCOL_NAME).c.tmp > packet-$(PROTOCOL_NAME).c
+ $(UNIX2DOS) < packet-$(PROTOCOL_NAME).h.tmp > packet-$(PROTOCOL_NAME).h
+ del /f packet-$(PROTOCOL_NAME).c.tmp packet-$(PROTOCOL_NAME).h.tmp
+
+copy_files: generate_dissector fix_eol
+ xcopy packet-$(PROTOCOL_NAME).c ..\..\epan\dissectors /d
+ xcopy packet-$(PROTOCOL_NAME).h ..\..\epan\dissectors /d
+
diff --git a/asn1/spnego/packet-spnego-template.c b/asn1/spnego/packet-spnego-template.c
new file mode 100644
index 0000000000..d5ea031b15
--- /dev/null
+++ b/asn1/spnego/packet-spnego-template.c
@@ -0,0 +1,1074 @@
+/* packet-spnego.c
+ * Routines for the simple and protected GSS-API negotiation mechanism
+ * as described in RFC 2478.
+ * Copyright 2002, Tim Potter <tpot@samba.org>
+ * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
+ * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
+ * Copyright 2005, Ronnie Sahlberg (krb decryption)
+ * Copyright 2005, Anders Broman (converted to asn2eth generated dissector)
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
+ Heimdal 1.6 and has been modified for ethereal's requirements.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+#include "packet-dcerpc.h"
+#include "packet-gssapi.h"
+#include "packet-kerberos.h"
+#include <epan/crypt-rc4.h>
+#include <epan/conversation.h>
+#include <epan/emem.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "packet-ber.h"
+
+
+#define PNAME "Simple Protected Negotiation"
+#define PSNAME "SPNEGO"
+#define PFNAME "spnego"
+
+/* Initialize the protocol and registered fields */
+static int proto_spnego = -1;
+static int proto_spnego_krb5 = -1;
+
+
+static int hf_spnego = -1;
+static int hf_spnego_wraptoken = -1;
+static int hf_spnego_krb5_oid;
+static int hf_spnego_krb5 = -1;
+static int hf_spnego_krb5_tok_id = -1;
+static int hf_spnego_krb5_sgn_alg = -1;
+static int hf_spnego_krb5_seal_alg = -1;
+static int hf_spnego_krb5_snd_seq = -1;
+static int hf_spnego_krb5_sgn_cksum = -1;
+static int hf_spnego_krb5_confounder = -1;
+
+#include "packet-spnego-hf.c"
+
+/* Global variables */
+gchar MechType_oid[MAX_OID_STR_LEN];
+gssapi_oid_value *next_level_value;
+gboolean saw_mechanism = FALSE;
+
+
+/* Initialize the subtree pointers */
+static gint ett_spnego;
+static gint ett_spnego_wraptoken;
+static gint ett_spnego_krb5 = -1;
+
+#include "packet-spnego-ett.c"
+
+static dissector_handle_t data_handle;
+
+static dissector_handle_t
+
+gssapi_dissector_handle(gssapi_oid_value *next_level_value) {
+ if (next_level_value == NULL) {
+ return NULL;
+ }
+ return next_level_value->handle;
+}
+
+
+#include "packet-spnego-fn.c"
+/*
+ * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
+ * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
+ * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
+ */
+
+#define KRB_TOKEN_AP_REQ 0x0001
+#define KRB_TOKEN_AP_REP 0x0002
+#define KRB_TOKEN_AP_ERR 0x0003
+#define KRB_TOKEN_GETMIC 0x0101
+#define KRB_TOKEN_WRAP 0x0102
+#define KRB_TOKEN_DELETE_SEC_CONTEXT 0x0201
+
+static const value_string spnego_krb5_tok_id_vals[] = {
+ { KRB_TOKEN_AP_REQ, "KRB5_AP_REQ"},
+ { KRB_TOKEN_AP_REP, "KRB5_AP_REP"},
+ { KRB_TOKEN_AP_ERR, "KRB5_ERROR"},
+ { KRB_TOKEN_GETMIC, "KRB5_GSS_GetMIC" },
+ { KRB_TOKEN_WRAP, "KRB5_GSS_Wrap" },
+ { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
+ { 0, NULL}
+};
+
+#define KRB_SGN_ALG_DES_MAC_MD5 0x0000
+#define KRB_SGN_ALG_MD2_5 0x0001
+#define KRB_SGN_ALG_DES_MAC 0x0002
+#define KRB_SGN_ALG_HMAC 0x0011
+
+static const value_string spnego_krb5_sgn_alg_vals[] = {
+ { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
+ { KRB_SGN_ALG_MD2_5, "MD2.5"},
+ { KRB_SGN_ALG_DES_MAC, "DES MAC"},
+ { KRB_SGN_ALG_HMAC, "HMAC"},
+ { 0, NULL}
+};
+
+#define KRB_SEAL_ALG_DES_CBC 0x0000
+#define KRB_SEAL_ALG_RC4 0x0010
+#define KRB_SEAL_ALG_NONE 0xffff
+
+static const value_string spnego_krb5_seal_alg_vals[] = {
+ { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
+ { KRB_SEAL_ALG_RC4, "RC4"},
+ { KRB_SEAL_ALG_NONE, "None"},
+ { 0, NULL}
+};
+
+/*
+ * XXX - is this for SPNEGO or just GSS-API?
+ * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
+ * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
+ * than designating SPNEGO as the mechanism, offering Kerberos V5, and
+ * getting it accepted.
+ */
+static int
+dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
+static int
+dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
+
+static void
+dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ int offset = 0;
+ guint16 token_id;
+ gchar oid[MAX_OID_STR_LEN];
+ gssapi_oid_value *value;
+ tvbuff_t *krb5_tvb;
+ gint8 class;
+ gboolean pc, ind = 0;
+ gint32 tag;
+ guint32 len;
+
+
+ item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
+ -1, FALSE);
+
+ subtree = proto_item_add_subtree(item, ett_spnego_krb5);
+
+ /*
+ * The KRB5 blob conforms to RFC1964:
+ * [APPLICATION 0] {
+ * OID,
+ * USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
+ * OCTET STRING }
+ *
+ * However, for some protocols, the KRB5 blob starts at the SHORT
+ * and has no DER encoded header etc.
+ *
+ * It appears that for some other protocols the KRB5 blob is just
+ * a Kerberos message, with no [APPLICATION 0] header, no OID,
+ * and no USHORT.
+ *
+ * So:
+ *
+ * If we see an [APPLICATION 0] HEADER, we show the OID and
+ * the USHORT, and then dissect the rest as a Kerberos message.
+ *
+ * If we see an [APPLICATION 14] or [APPLICATION 15] header,
+ * we assume it's an AP-REQ or AP-REP message, and dissect
+ * it all as a Kerberos message.
+ *
+ * Otherwise, we show the USHORT, and then dissect the rest
+ * as a Kerberos message.
+ */
+
+ /*
+ * Get the first header ...
+ */
+ offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
+ offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
+
+ if (class == BER_CLASS_APP && pc == 1) {
+ /*
+ * [APPLICATION <tag>]
+ */
+ switch (tag) {
+
+ case 0:
+ /*
+ * [APPLICATION 0]
+ */
+
+ /* Next, the OID */
+ offset=dissect_ber_object_identifier(FALSE, pinfo, subtree, tvb, offset, hf_spnego_krb5_oid, oid);
+
+ value = gssapi_lookup_oid_str(oid);
+
+ token_id = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
+ token_id);
+
+ offset += 2;
+
+ break;
+
+ case 14: /* [APPLICATION 14] */
+ case 15: /* [APPLICATION 15] */
+ /*
+ * No token ID - just dissect as a Kerberos message and
+ * return.
+ */
+ offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
+ return;
+
+ default:
+ proto_tree_add_text(subtree, tvb, offset, 0,
+ "Unknown header (class=%d, pc=%d, tag=%d)",
+ class, pc, tag);
+ goto done;
+ }
+ } else {
+ /* Next, the token ID ... */
+
+ token_id = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
+ token_id);
+
+ offset += 2;
+ }
+
+ switch (token_id) {
+
+ case KRB_TOKEN_AP_REQ:
+ case KRB_TOKEN_AP_REP:
+ case KRB_TOKEN_AP_ERR:
+ krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
+ break;
+
+ case KRB_TOKEN_GETMIC:
+ offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
+ break;
+
+ case KRB_TOKEN_WRAP:
+ offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
+ break;
+
+ case KRB_TOKEN_DELETE_SEC_CONTEXT:
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ done:
+ return;
+}
+
+#ifdef HAVE_KERBEROS
+#include <epan/crypt-md5.h>
+
+#ifndef KEYTYPE_ARCFOUR_56
+# define KEYTYPE_ARCFOUR_56 24
+#endif
+/* XXX - We should probably do a configure-time check for this instead */
+#ifndef KRB5_KU_USAGE_SEAL
+# define KRB5_KU_USAGE_SEAL 22
+#endif
+
+static int
+arcfour_mic_key(void *key_data, size_t key_size, int key_type,
+ void *cksum_data, size_t cksum_size,
+ void *key6_data)
+{
+ guint8 k5_data[16];
+ guint8 T[4];
+
+ memset(T, 0, 4);
+
+ if (key_type == KEYTYPE_ARCFOUR_56) {
+ guint8 L40[14] = "fortybits";
+
+ memcpy(L40 + 10, T, sizeof(T));
+ md5_hmac(
+ L40, 14,
+ key_data,
+ key_size,
+ k5_data);
+ memset(&k5_data[7], 0xAB, 9);
+ } else {
+ md5_hmac(
+ T, 4,
+ key_data,
+ key_size,
+ k5_data);
+ }
+
+ md5_hmac(
+ cksum_data, cksum_size,
+ k5_data,
+ 16,
+ key6_data);
+
+ return 0;
+}
+
+static int
+usage2arcfour(int usage)
+{
+ switch (usage) {
+ case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
+ case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
+ return 8;
+ case 22: /*KRB5_KU_USAGE_SEAL 22 */
+ return 13;
+ case 23: /*KRB5_KU_USAGE_SIGN 23 */
+ return 15;
+ case 24: /*KRB5_KU_USAGE_SEQ 24 */
+ return 0;
+ default :
+ return 0;
+ }
+}
+
+static int
+arcfour_mic_cksum(guint8 *key_data, int key_length,
+ unsigned usage,
+ u_char sgn_cksum[8],
+ const void *v1, size_t l1,
+ const void *v2, size_t l2,
+ const void *v3, size_t l3)
+{
+ const guint8 signature[] = "signaturekey";
+ guint8 ksign_c[16];
+ unsigned char t[4];
+ md5_state_t ms;
+ unsigned char digest[16];
+ int rc4_usage;
+ guint8 cksum[16];
+
+ rc4_usage=usage2arcfour(usage);
+ md5_hmac(signature, sizeof(signature),
+ key_data, key_length,
+ ksign_c);
+ md5_init(&ms);
+ t[0] = (rc4_usage >> 0) & 0xFF;
+ t[1] = (rc4_usage >> 8) & 0xFF;
+ t[2] = (rc4_usage >> 16) & 0xFF;
+ t[3] = (rc4_usage >> 24) & 0xFF;
+ md5_append(&ms, t, 4);
+ md5_append(&ms, v1, l1);
+ md5_append(&ms, v2, l2);
+ md5_append(&ms, v3, l3);
+ md5_finish(&ms, digest);
+ md5_hmac(digest, 16, ksign_c, 16, cksum);
+
+ memcpy(sgn_cksum, cksum, 8);
+
+ return 0;
+}
+
+/*
+ * Verify padding of a gss wrapped message and return its length.
+ */
+static int
+gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
+ size_t datalen,
+ size_t *padlen)
+{
+ unsigned char *pad;
+ size_t padlength;
+ int i;
+
+ pad = wrapped_data + wrapped_length - 1;
+ padlength = *pad;
+
+ if (padlength > datalen)
+ return 1;
+
+ for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
+ ;
+ if (i != 0)
+ return 2;
+
+ *padlen = padlength;
+
+ return 0;
+}
+
+static int
+decrypt_arcfour(packet_info *pinfo,
+ guint8 *input_message_buffer,
+ guint8 *output_message_buffer,
+ guint8 *key_value, int key_size, int key_type)
+{
+ guint8 Klocaldata[16];
+ int ret;
+ gint32 seq_number;
+ size_t datalen;
+ guint8 k6_data[16], SND_SEQ[8], Confounder[8];
+ guint8 cksum_data[8];
+ int cmp;
+ int conf_flag;
+ size_t padlen = 0;
+
+ datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
+
+ if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
+ conf_flag=1;
+ } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
+ conf_flag=0;
+ } else {
+ return -3;
+ }
+
+ if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
+ return -4;
+ }
+
+ ret = arcfour_mic_key(key_value, key_size, key_type,
+ (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
+ 8, /* SGN_CKSUM */
+ k6_data);
+ if (ret) {
+ return -5;
+ }
+
+ {
+ rc4_state_struct rc4_state;
+
+ crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
+ memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
+ crypt_rc4(&rc4_state, SND_SEQ, 8);
+
+ memset(k6_data, 0, sizeof(k6_data));
+ }
+
+ seq_number=g_ntohl(*((guint32 *)SND_SEQ));
+
+ cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+ if(cmp){
+ cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+ }
+
+ if (cmp != 0) {
+ return -6;
+ }
+
+ {
+ int i;
+
+ for (i = 0; i < 16; i++)
+ Klocaldata[i] = ((u_char *)key_value)[i] ^ 0xF0;
+ }
+ ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
+ SND_SEQ, 4,
+ k6_data);
+ memset(Klocaldata, 0, sizeof(Klocaldata));
+ if (ret) {
+ return -7;
+ }
+
+ if(conf_flag) {
+ rc4_state_struct rc4_state;
+
+ crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
+ memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
+ crypt_rc4(&rc4_state, Confounder, 8);
+ memcpy(output_message_buffer, input_message_buffer, datalen);
+ crypt_rc4(&rc4_state, output_message_buffer, datalen);
+ } else {
+ memcpy(Confounder,
+ tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
+ 8); /* Confounder */
+ memcpy(output_message_buffer,
+ input_message_buffer,
+ datalen);
+ }
+ memset(k6_data, 0, sizeof(k6_data));
+
+ /* only normal (i.e. non DCE style wrapping use padding ? */
+ if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
+ ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
+ if (ret) {
+ return -9;
+ }
+ datalen -= padlen;
+ }
+
+ /* dont know what the checksum looks like for dce style gssapi */
+ if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
+ ret = arcfour_mic_cksum(key_value, key_size,
+ KRB5_KU_USAGE_SEAL,
+ cksum_data,
+ tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
+ Confounder, sizeof(Confounder),
+ output_message_buffer,
+ datalen + padlen);
+ if (ret) {
+ return -10;
+ }
+
+ cmp = memcmp(cksum_data,
+ tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
+ 8); /* SGN_CKSUM */
+ if (cmp) {
+ return -11;
+ }
+ }
+
+ return datalen;
+}
+
+
+
+#if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
+
+static void
+decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
+{
+ int ret;
+ enc_key_t *ek;
+ int length;
+ const guint8 *original_data;
+
+ static int omb_index=0;
+ static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
+ static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
+ guint8 *output_message_buffer;
+
+ omb_index++;
+ if(omb_index>=4){
+ omb_index=0;
+ }
+ output_message_buffer=omb_arr[omb_index];
+
+
+ length=tvb_length(pinfo->gssapi_encrypted_tvb);
+ original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
+
+ /* dont do anything if we are not attempting to decrypt data */
+/*
+ if(!krb_decrypt){
+ return;
+ }
+*/
+ /* XXX we should only do this for first time, then store somewhere */
+ /* XXX We also need to re-read the keytab when the preference changes */
+
+ cryptocopy=ep_alloc(length);
+ if(output_message_buffer){
+ g_free(output_message_buffer);
+ output_message_buffer=NULL;
+ }
+ output_message_buffer=g_malloc(length);
+
+ for(ek=enc_key_list;ek;ek=ek->next){
+ /* shortcircuit and bail out if enctypes are not matching */
+ if(ek->keytype!=keytype){
+ continue;
+ }
+
+ /* pre-0.6.1 versions of Heimdal would sometimes change
+ the cryptotext data even when the decryption failed.
+ This would obviously not work since we iterate over the
+ keys. So just give it a copy of the crypto data instead.
+ This has been seen for RC4-HMAC blobs.
+ */
+ memcpy(cryptocopy, original_data, length);
+ ret=decrypt_arcfour(pinfo,
+ cryptocopy,
+ output_message_buffer,
+ ek->keyvalue,
+ ek->keylength,
+ ek->keytype
+ );
+ if (ret >= 0) {
+ proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
+ pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
+ output_message_buffer,
+ ret, ret);
+ tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
+ add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
+ return;
+ }
+ }
+ return;
+}
+#endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
+
+
+#endif
+
+/*
+ * XXX - This is for GSSAPI Wrap tokens ...
+ */
+static int
+dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
+#ifndef HAVE_KERBEROS
+ _U_
+#endif
+ , proto_tree *tree, guint16 token_id
+#ifndef HAVE_KERBEROS
+ _U_
+#endif
+ )
+{
+ guint16 sgn_alg, seal_alg;
+#ifdef HAVE_KERBEROS
+ int start_offset=offset;
+#endif
+
+ /*
+ * The KRB5 blob conforms to RFC1964:
+ * USHORT (0x0102 == GSS_Wrap)
+ * and so on }
+ */
+
+ /* Now, the sign and seal algorithms ... */
+
+ sgn_alg = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
+ sgn_alg);
+
+ offset += 2;
+
+ seal_alg = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
+ seal_alg);
+
+ offset += 2;
+
+ /* Skip the filler */
+
+ offset += 2;
+
+ /* Encrypted sequence number */
+
+ proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
+ TRUE);
+
+ offset += 8;
+
+ /* Checksum of plaintext padded data */
+
+ proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
+ TRUE);
+
+ offset += 8;
+
+ /*
+ * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
+ * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
+ * extra 8 bytes of "Random confounder" after the checksum.
+ * It certainly confounds code expecting all Kerberos 5
+ * GSS_Wrap() tokens to look the same....
+ */
+ if (sgn_alg == KRB_SGN_ALG_HMAC) {
+ proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
+ TRUE);
+ offset += 8;
+ }
+
+ /* Is the data encrypted? */
+ pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
+
+#ifdef HAVE_KERBEROS
+#define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
+ if(pinfo->decrypt_gssapi_tvb){
+ /* if the caller did not provide a tvb, then we just use
+ whatever is left of our current tvb.
+ */
+ if(!pinfo->gssapi_encrypted_tvb){
+ int len;
+ len=tvb_reported_length_remaining(tvb,offset);
+ if(len>tvb_length_remaining(tvb, offset)){
+ /* no point in trying to decrypt,
+ we dont have the full pdu.
+ */
+ return offset;
+ }
+ pinfo->gssapi_encrypted_tvb = tvb_new_subset(
+ tvb, offset, len, len);
+ }
+
+ /* if this is KRB5 wrapped rc4-hmac */
+ if((token_id==KRB_TOKEN_WRAP)
+ &&(sgn_alg==KRB_SGN_ALG_HMAC)
+ &&(seal_alg==KRB_SEAL_ALG_RC4)){
+ /* do we need to create a tvb for the wrapper
+ as well ?
+ */
+ if(!pinfo->gssapi_wrap_tvb){
+ pinfo->gssapi_wrap_tvb = tvb_new_subset(
+ tvb, start_offset-2,
+ GSS_ARCFOUR_WRAP_TOKEN_SIZE,
+ GSS_ARCFOUR_WRAP_TOKEN_SIZE);
+ }
+#if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
+ decrypt_gssapi_krb_arcfour_wrap(tree,
+ pinfo,
+ tvb,
+ 23 /* rc4-hmac */);
+#endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
+ }
+ }
+#endif
+ /*
+ * Return the offset past the checksum, so that we know where
+ * the data we're wrapped around starts. Also, set the length
+ * of our top-level item to that offset, so it doesn't cover
+ * the data we're wrapped around.
+ *
+ * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
+ * not before.
+ */
+ return offset;
+}
+
+/*
+ * XXX - This is for GSSAPI GetMIC tokens ...
+ */
+static int
+dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
+{
+ guint16 sgn_alg;
+
+ /*
+ * The KRB5 blob conforms to RFC1964:
+ * USHORT (0x0101 == GSS_GetMIC)
+ * and so on }
+ */
+
+ /* Now, the sign algorithm ... */
+
+ sgn_alg = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
+ sgn_alg);
+
+ offset += 2;
+
+ /* Skip the filler */
+
+ offset += 4;
+
+ /* Encrypted sequence number */
+
+ proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
+ TRUE);
+
+ offset += 8;
+
+ /* Checksum of plaintext padded data */
+
+ proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
+ TRUE);
+
+ offset += 8;
+
+ /*
+ * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
+ * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
+ * extra 8 bytes of "Random confounder" after the checksum.
+ * It certainly confounds code expecting all Kerberos 5
+ * GSS_Wrap() tokens to look the same....
+ */
+ if (sgn_alg == KRB_SGN_ALG_HMAC) {
+ proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
+ TRUE);
+
+ offset += 8;
+ }
+
+ /*
+ * Return the offset past the checksum, so that we know where
+ * the data we're wrapped around starts. Also, set the length
+ * of our top-level item to that offset, so it doesn't cover
+ * the data we're wrapped around.
+ */
+
+ return offset;
+}
+
+/*
+ * XXX - is this for SPNEGO or just GSS-API?
+ * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
+ * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
+ * than designating SPNEGO as the mechanism, offering Kerberos V5, and
+ * getting it accepted.
+ */
+static int
+dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ int offset = 0;
+ guint16 token_id;
+
+ item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
+
+ subtree = proto_item_add_subtree(item, ett_spnego_krb5);
+
+ /*
+ * The KRB5 blob conforms to RFC1964:
+ * USHORT (0x0102 == GSS_Wrap)
+ * and so on }
+ */
+
+ /* First, the token ID ... */
+
+ token_id = tvb_get_letohs(tvb, offset);
+ proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
+ token_id);
+
+ offset += 2;
+
+ offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
+
+ /*
+ * Return the offset past the checksum, so that we know where
+ * the data we're wrapped around starts. Also, set the length
+ * of our top-level item to that offset, so it doesn't cover
+ * the data we're wrapped around.
+ */
+ proto_item_set_len(item, offset);
+ return offset;
+}
+
+/* Spnego stuff from here */
+
+static int
+dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *item;
+ proto_tree *subtree;
+
+ int offset = 0;
+
+
+ /*
+ * We need this later, so lets get it now ...
+ * It has to be per-frame as there can be more than one GSS-API
+ * negotiation in a conversation.
+ */
+
+
+ item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
+ -1, FALSE);
+
+ subtree = proto_item_add_subtree(item, ett_spnego);
+ /*
+ * The TVB contains a [0] header and a sequence that consists of an
+ * object ID and a blob containing the data ...
+ * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
+ * with the "optional" "use in non-initial tokens" being chosen.
+ * ASN1 code addet to spnego.asn to handle this.
+ */
+
+ offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, pinfo , subtree, -1);
+
+ return offset;
+}
+
+
+static void
+dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ int offset = 0;
+ conversation_t *conversation;
+
+ /*
+ * We need this later, so lets get it now ...
+ * It has to be per-frame as there can be more than one GSS-API
+ * negotiation in a conversation.
+ */
+
+ next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
+ if (!next_level_value && !pinfo->fd->flags.visited) {
+ /*
+ * No handle attached to this frame, but it's the first
+ * pass, so it'd be attached to the conversation.
+ * If we have a conversation, try to get the handle,
+ * and if we get one, attach it to the frame.
+ */
+ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+
+ if (conversation) {
+ next_level_value = conversation_get_proto_data(conversation,
+ proto_spnego);
+ if (next_level_value)
+ p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
+ }
+ }
+
+ item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset,
+ -1, FALSE);
+
+ subtree = proto_item_add_subtree(item, ett_spnego);
+
+ /*
+ * The TVB contains a [0] header and a sequence that consists of an
+ * object ID and a blob containing the data ...
+ * Actually, it contains, according to RFC2478:
+ * NegotiationToken ::= CHOICE {
+ * negTokenInit [0] NegTokenInit,
+ * negTokenTarg [1] NegTokenTarg }
+ * NegTokenInit ::= SEQUENCE {
+ * mechTypes [0] MechTypeList OPTIONAL,
+ * reqFlags [1] ContextFlags OPTIONAL,
+ * mechToken [2] OCTET STRING OPTIONAL,
+ * mechListMIC [3] OCTET STRING OPTIONAL }
+ * NegTokenTarg ::= SEQUENCE {
+ * negResult [0] ENUMERATED {
+ * accept_completed (0),
+ * accept_incomplete (1),
+ * reject (2) } OPTIONAL,
+ * supportedMech [1] MechType OPTIONAL,
+ * responseToken [2] OCTET STRING OPTIONAL,
+ * mechListMIC [3] OCTET STRING OPTIONAL }
+ *
+ * Windows typically includes mechTypes and mechListMic ('NONE'
+ * in the case of NTLMSSP only).
+ * It seems to duplicate the responseToken into the mechListMic field
+ * as well. Naughty, naughty.
+ *
+ */
+ offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, pinfo, subtree, -1);
+
+}
+
+/*--- proto_register_spnego -------------------------------------------*/
+void proto_register_spnego(void) {
+
+ /* List of fields */
+ static hf_register_info hf[] = {
+ { &hf_spnego,
+ { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
+ "SPNEGO", HFILL }},
+ { &hf_spnego_wraptoken,
+ { "wrapToken", "spnego.wraptoken",
+ FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
+ HFILL}},
+ { &hf_spnego_krb5,
+ { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
+ BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
+ {&hf_spnego_krb5_oid,
+ {"KRB5 OID", "spnego.krb5_oid", FT_STRING,
+ BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
+ { &hf_spnego_krb5_tok_id,
+ { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
+ VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
+ { &hf_spnego_krb5_sgn_alg,
+ { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
+ VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
+ { &hf_spnego_krb5_seal_alg,
+ { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
+ VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
+ { &hf_spnego_krb5_snd_seq,
+ { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
+ NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
+ { &hf_spnego_krb5_sgn_cksum,
+ { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
+ NULL, 0, "KRB5 Data Checksum", HFILL}},
+ { &hf_spnego_krb5_confounder,
+ { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
+ NULL, 0, "KRB5 Confounder", HFILL}},
+
+#include "packet-spnego-hfarr.c"
+ };
+
+ /* List of subtrees */
+ static gint *ett[] = {
+ &ett_spnego,
+ &ett_spnego_wraptoken,
+ &ett_spnego_krb5,
+
+#include "packet-spnego-ettarr.c"
+ };
+
+ /* Register protocol */
+ proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
+
+ proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
+ "SPNEGO-KRB5",
+ "spnego-krb5");
+ /* Register fields and subtrees */
+ proto_register_field_array(proto_spnego, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+}
+
+
+/*--- proto_reg_handoff_spnego ---------------------------------------*/
+void proto_reg_handoff_spnego(void) {
+
+ dissector_handle_t spnego_handle, spnego_wrap_handle;
+ dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
+
+ /* Register protocol with GSS-API module */
+
+ spnego_handle = create_dissector_handle(dissect_spnego, proto_spnego);
+ spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,
+ proto_spnego);
+ gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
+ spnego_handle, spnego_wrap_handle,
+ "SPNEGO - Simple Protected Negotiation");
+
+ /* Register both the one MS created and the real one */
+ /*
+ * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
+ * mystery of the MS KRB5 OID is cleared up. It was due to a library
+ * that did not handle OID components greater than 16 bits, and was
+ * fixed in Win2K SP2 as well as WinXP.
+ * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
+ * SPNEGO implementation issues. 3-Dec-2002.
+ */
+ spnego_krb5_handle = create_dissector_handle(dissect_spnego_krb5,
+ proto_spnego_krb5);
+ spnego_krb5_wrap_handle = new_create_dissector_handle(dissect_spnego_krb5_wrap,
+ proto_spnego_krb5);
+ gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
+ spnego_krb5_handle, spnego_krb5_wrap_handle,
+ "MS KRB5 - Microsoft Kerberos 5");
+ gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
+ spnego_krb5_handle, spnego_krb5_wrap_handle,
+ "KRB5 - Kerberos 5");
+ gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
+ spnego_krb5_handle, spnego_krb5_wrap_handle,
+ "KRB5 - Kerberos 5 - User to User");
+
+ /*
+ * Find the data handle for some calls
+ */
+ data_handle = find_dissector("data");
+
+}
diff --git a/asn1/spnego/packet-spnego-template.h b/asn1/spnego/packet-spnego-template.h
new file mode 100644
index 0000000000..8b8130f8d9
--- /dev/null
+++ b/asn1/spnego/packet-spnego-template.h
@@ -0,0 +1,30 @@
+/* packet-spnego.h
+ * Routines for spnego packet dissection
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PACKET_SPNEGO_H
+#define PACKET_SPNEGO_H
+
+/*#include "packet-spnego-exp.h"*/
+
+#endif /* PACKET_spnego_H */
diff --git a/asn1/spnego/spnego.asn b/asn1/spnego/spnego.asn
new file mode 100644
index 0000000000..8813fea9cc
--- /dev/null
+++ b/asn1/spnego/spnego.asn
@@ -0,0 +1,85 @@
+Spnego {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) snego(2)}
+-- (1.3.6.1.5.5.2)
+DEFINITIONS ::=
+
+BEGIN
+
+MechType::= OBJECT IDENTIFIER
+
+NegotiationToken ::= CHOICE {
+ negTokenInit [0] NegTokenInit,
+ negTokenTarg [1] NegTokenTarg }
+
+MechTypeList ::= SEQUENCE OF MechType
+
+NegTokenInit ::= SEQUENCE {
+ mechTypes [0] MechTypeList OPTIONAL,
+ reqFlags [1] ContextFlags OPTIONAL,
+ mechToken [2] OCTET STRING OPTIONAL,
+ mechListMIC [3] OCTET STRING OPTIONAL
+ }
+
+ContextFlags ::= BIT STRING {
+ delegFlag (0),
+ mutualFlag (1),
+ replayFlag (2),
+ sequenceFlag (3),
+ anonFlag (4),
+ confFlag (5),
+ integFlag (6)
+}
+
+NegTokenTarg ::= SEQUENCE {
+ negResult [0] ENUMERATED {
+ accept-completed (0),
+ accept-incomplete (1),
+ reject (2) } OPTIONAL,
+ supportedMech [1] MechType OPTIONAL,
+ responseToken [2] OCTET STRING OPTIONAL,
+ mechListMIC [3] OCTET STRING OPTIONAL
+}
+
+--GSS-API DEFINITIONS ::=
+--BEGIN
+--MechType ::= OBJECT IDENTIFIER
+-- data structure definitions
+-- callers must be able to distinguish among
+-- InitialContextToken, SubsequentContextToken,
+-- PerMsgToken, and SealedMessage data elements
+-- based on the usage in which they occur
+InitialContextToken ::=
+ -- option indication (delegation, etc.) indicated within
+ -- mechanism-specific token
+[APPLICATION 0] IMPLICIT SEQUENCE {
+ thisMech MechType,
+ innerContextToken InnerContextToken
+ -- DEFINED BY thisMech
+ -- contents mechanism-specific
+ -- ASN.1 structure not required
+ }
+
+-- SubsequentContextToken ::= InnerContextToken
+
+InnerContextToken ::= ANY
+-- interpretation based on predecessor InitialContextToken
+-- ASN.1 structure not required
+
+-- PerMsgToken ::=
+-- as emitted by GSS_GetMIC and processed by GSS_VerifyMIC
+-- ASN.1 structure not required
+-- InnerMsgToken
+
+-- InnerMsgToken ::= ANY
+
+-- SealedMessage ::=
+-- as emitted by GSS_Wrap and processed by GSS_Unwrap
+-- includes internal, mechanism-defined indicator
+-- of whether or not encrypted
+-- ASN.1 structure not required
+-- SealedUserData
+
+-- SealedUserData ::= ANY
+
+-- END GSS-API DEFINITIONS
+
+END \ No newline at end of file
diff --git a/asn1/spnego/spnego.cnf b/asn1/spnego/spnego.cnf
new file mode 100644
index 0000000000..476e4ce3b3
--- /dev/null
+++ b/asn1/spnego/spnego.cnf
@@ -0,0 +1,128 @@
+# spnego.cnf
+# spnego conformation file
+
+# $Id$
+
+#.EXPORTS
+
+#.PDU
+
+#.NO_EMIT
+
+#.TYPE_RENAME
+
+#.FIELD_RENAME
+
+#.FN_PARS MechType
+
+ VAL_PTR = MechType_oid
+
+#.FN_BODY MechType
+
+ gssapi_oid_value *value;
+
+%(DEFAULT_BODY)s
+
+ value = gssapi_lookup_oid_str(MechType_oid);
+
+ /*
+ * Tell our caller the first mechanism we see, so that if
+ * this is a negTokenInit with a mechToken, it can interpret
+ * the mechToken according to the first mechType. (There
+ * might not have been any indication of the mechType
+ * in prior frames, so we can't necessarily use the
+ * mechanism from the conversation; i.e., a negTokenInit
+ * can contain the initial security token for the desired
+ * mechanism of the initiator - that's the first mechanism
+ * in the list.)
+ */
+ if (!saw_mechanism) {
+ if (value)
+ next_level_value = value;
+ saw_mechanism = TRUE;
+ }
+
+#.FN_BODY InnerContextToken
+
+ conversation_t *conversation;
+ gssapi_oid_value *next_level_value;
+ proto_item *item;
+ proto_tree *subtree;
+ tvbuff_t *token_tvb;
+ int len;
+
+ next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
+ if (!next_level_value && !pinfo->fd->flags.visited) {
+ /*
+ * No handle attached to this frame, but it's the first
+ * pass, so it'd be attached to the conversation.
+ * If we have a conversation, try to get the handle,
+ * and if we get one, attach it to the frame.
+ */
+ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+
+ if (conversation) {
+ next_level_value = conversation_get_proto_data(conversation,
+ proto_spnego);
+ if (next_level_value)
+ p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
+ }
+ }
+
+ next_level_value = gssapi_lookup_oid_str(MechType_oid);
+ /*
+ * Now dissect the GSS_Wrap token; it's assumed to be in the
+ * rest of the tvbuff.
+ */
+ item = proto_tree_add_item(tree, hf_spnego_wraptoken, tvb, offset,
+ -1, FALSE);
+
+ subtree = proto_item_add_subtree(item, ett_spnego_wraptoken);
+
+ /*
+ * Now, we should be able to dispatch after creating a new TVB.
+ * The subdissector must return the length of the part of the
+ * token it dissected, so we can return the length of the part
+ * we (and it) dissected.
+ */
+
+ token_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ if (next_level_value->wrap_handle) {
+ len = call_dissector(next_level_value->wrap_handle, token_tvb, pinfo, subtree);
+ if (len == 0)
+ offset = tvb_length(tvb);
+ else
+ offset = offset + len;
+ } else
+
+ offset = tvb_length(tvb);
+
+
+#.FN_HDR MechTypeList
+
+
+ saw_mechanism = FALSE;
+
+#.FN_PARS NegTokenInit/mechToken
+
+ VAL_PTR = &mechToken_tvb
+
+#.FN_BODY NegTokenInit/mechToken
+
+ tvbuff_t *mechToken_tvb;
+
+
+%(DEFAULT_BODY)s
+
+
+ /*
+ * Now, we should be able to dispatch after creating a new TVB.
+ */
+
+ if (next_level_value)
+ call_dissector(gssapi_dissector_handle(next_level_value), mechToken_tvb, pinfo, tree);
+
+
+#.END