aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-spnego.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-spnego.c')
-rw-r--r--epan/dissectors/packet-spnego.c1694
1 files changed, 1694 insertions, 0 deletions
diff --git a/epan/dissectors/packet-spnego.c b/epan/dissectors/packet-spnego.c
new file mode 100644
index 0000000000..70eace5ff2
--- /dev/null
+++ b/epan/dissectors/packet-spnego.c
@@ -0,0 +1,1694 @@
+/* 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>
+ *
+ * $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+
+#include "asn1.h"
+#include "format-oid.h"
+#include "packet-gssapi.h"
+#include "packet-kerberos.h"
+#include <epan/conversation.h>
+
+#define SPNEGO_negTokenInit 0
+#define SPNEGO_negTokenTarg 1
+#define SPNEGO_mechTypes 0
+#define SPNEGO_reqFlags 1
+#define SPNEGO_mechToken 2
+#define SPNEGO_mechListMIC 3
+#define SPNEGO_negResult 0
+#define SPNEGO_supportedMech 1
+#define SPNEGO_responseToken 2
+#define SPNEGO_negResult_accept_completed 0
+#define SPNEGO_negResult_accept_incomplete 1
+#define SPNEGO_negResult_accept_reject 2
+
+static int proto_spnego = -1;
+static int proto_spnego_krb5 = -1;
+
+static int hf_spnego = -1;
+static int hf_spnego_negtokeninit = -1;
+static int hf_spnego_negtokentarg = -1;
+static int hf_spnego_mechtype = -1;
+static int hf_spnego_mechtoken = -1;
+static int hf_spnego_negtokentarg_negresult = -1;
+static int hf_spnego_mechlistmic = -1;
+static int hf_spnego_responsetoken = -1;
+static int hf_spnego_reqflags = -1;
+static int hf_spnego_wraptoken = -1;
+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;
+static int hf_gssapi_reqflags_deleg = -1;
+static int hf_gssapi_reqflags_mutual = -1;
+static int hf_gssapi_reqflags_replay = -1;
+static int hf_gssapi_reqflags_sequence = -1;
+static int hf_gssapi_reqflags_anon = -1;
+static int hf_gssapi_reqflags_conf = -1;
+static int hf_gssapi_reqflags_integ = -1;
+
+static gint ett_spnego = -1;
+static gint ett_spnego_negtokeninit = -1;
+static gint ett_spnego_negtokentarg = -1;
+static gint ett_spnego_mechtype = -1;
+static gint ett_spnego_mechtoken = -1;
+static gint ett_spnego_mechlistmic = -1;
+static gint ett_spnego_responsetoken = -1;
+static gint ett_spnego_wraptoken = -1;
+static gint ett_spnego_krb5 = -1;
+static gint ett_spnego_reqflags = -1;
+
+static const value_string spnego_negResult_vals[] = {
+ { SPNEGO_negResult_accept_completed, "Accept Completed" },
+ { SPNEGO_negResult_accept_incomplete, "Accept Incomplete" },
+ { SPNEGO_negResult_accept_reject, "Accept Reject"},
+ { 0, NULL}
+};
+
+/*
+ * These should be in the GSSAPI dissector ... XXX
+ */
+
+static const true_false_string tfs_reqflags_deleg = {
+ "Delegation Requested",
+ "Delegation NOT Requested"
+};
+
+static const true_false_string tfs_reqflags_mutual = {
+ "Mutual Authentication Requested",
+ "Mutual Authentication NOT Requested"
+};
+
+static const true_false_string tfs_reqflags_replay = {
+ "Replay Detection Requested",
+ "Replay Detection NOT Requested"
+};
+
+static const true_false_string tfs_reqflags_sequence = {
+ "Out-of-sequence Detection Requested",
+ "Out-of-sequence Detection NOT Requested"
+};
+
+static const true_false_string tfs_reqflags_anon = {
+ "Anonymous Authentication Requested",
+ "Anonymous Authentication NOT Requested"
+};
+
+static const true_false_string tfs_reqflags_conf = {
+ "Per-message Confidentiality Requested",
+ "Per-message Confidentiality NOT Requested"
+};
+
+static const true_false_string tfs_reqflags_integ = {
+ "Per-message Integrity Requested",
+ "Per-message Integrity NOT Requested"
+};
+
+/* Display an ASN1 parse error. Taken from packet-snmp.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;
+}
+
+static void
+dissect_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, const char *field_name, int ret)
+{
+ char *errstr;
+
+ errstr = asn1_err_to_str(ret);
+
+ if (tree != NULL) {
+ proto_tree_add_text(tree, tvb, offset, 0,
+ "ERROR: Couldn't parse %s: %s", field_name, errstr);
+ call_dissector(data_handle,
+ tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
+ }
+}
+
+/*
+ * 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);
+
+static void
+dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ int ret, offset = 0;
+ ASN1_SCK hnd;
+ gboolean def;
+ guint len1, cls, con, tag, oid_len, nbytes;
+ guint16 token_id;
+ subid_t *oid;
+ gchar *oid_string;
+ gssapi_oid_value *value;
+ tvbuff_t *krb5_tvb;
+
+ 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.
+ */
+
+ asn1_open(&hnd, tvb, offset);
+
+ /*
+ * Get the first header ...
+ */
+
+ ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO KRB5 Header", ret);
+ goto done;
+ }
+
+ if (cls == ASN1_APL && con == ASN1_CON) {
+ /*
+ * [APPLICATION <tag>]
+ */
+ switch (tag) {
+
+ case 0:
+ /*
+ * [APPLICATION 0]
+ */
+
+ offset = hnd.offset;
+
+ /* Next, the OID */
+
+ ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO supportedMech token", ret);
+ goto done;
+ }
+
+ oid_string = format_oid(oid, oid_len);
+
+ value = gssapi_lookup_oid(oid, oid_len);
+
+ if (value)
+ proto_tree_add_text(subtree, tvb, offset, nbytes,
+ "OID: %s (%s)",
+ oid_string, value->comment);
+ else
+ proto_tree_add_text(subtree, tvb, offset, nbytes,
+ "OID: %s",
+ oid_string);
+
+ g_free(oid_string);
+
+ offset += nbytes;
+
+ /* 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);
+
+ hnd.offset += 2;
+
+ offset += 2;
+
+ break;
+
+ case 14: /* [APPLICATION 14] */
+ case 15: /* [APPLICATION 15] */
+ /*
+ * No token ID - just dissect as a Kerberos message and
+ * return.
+ */
+ krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
+ return;
+
+ default:
+ proto_tree_add_text(subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, 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);
+
+ hnd.offset += 2;
+
+ 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);
+ break;
+
+ case KRB_TOKEN_DELETE_SEC_CONTEXT:
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ done:
+ return;
+}
+
+/*
+ * XXX - This is for GSSAPI Wrap tokens ...
+ */
+static int
+dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
+{
+ guint16 sgn_alg;
+
+ /*
+ * 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;
+
+ proto_tree_add_item(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
+ TRUE);
+
+ 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;
+ }
+
+ /*
+ * 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 - 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;
+
+ 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 ... */
+
+ proto_tree_add_item(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
+ TRUE);
+
+ offset += 2;
+
+ offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree);
+
+ /*
+ * 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_mechTypes(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, ASN1_SCK *hnd,
+ gssapi_oid_value **next_level_value_p)
+{
+ proto_item *item = NULL;
+ proto_tree *subtree = NULL;
+ gboolean def;
+ guint len1, len, cls, con, tag, nbytes;
+ subid_t *oid;
+ gchar *oid_string;
+ int ret;
+ gboolean saw_mechanism = FALSE;
+
+ /*
+ * MechTypeList ::= SEQUENCE OF MechType
+ */
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO last sequence header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
+ proto_tree_add_text(
+ subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ offset = hnd->offset;
+
+ item = proto_tree_add_item(tree, hf_spnego_mechtype, tvb, offset,
+ len1, FALSE);
+ subtree = proto_item_add_subtree(item, ett_spnego_mechtype);
+
+ /*
+ * Now, the object IDs ... We should translate them: FIXME
+ */
+
+ while (len1) {
+ gssapi_oid_value *value;
+
+ ret = asn1_oid_decode(hnd, &oid, &len, &nbytes);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO mechTypes token", ret);
+ goto done;
+ }
+
+ oid_string = format_oid(oid, len);
+ value = gssapi_lookup_oid(oid, len);
+ if (value)
+ proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s (%s)",
+ oid_string, value->comment);
+ else
+ proto_tree_add_text(subtree, tvb, offset, nbytes, "OID: %s",
+ oid_string);
+
+ g_free(oid_string);
+
+ /*
+ * 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_p = value;
+ saw_mechanism = TRUE;
+ }
+
+ offset += nbytes;
+ len1 -= nbytes;
+
+ }
+
+ done:
+
+ return offset;
+
+}
+
+static int
+dissect_spnego_reqFlags(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd)
+{
+ gboolean def;
+ guint len1, cls, con, tag, flags;
+ int ret;
+ proto_item *item;
+ proto_tree *subtree;
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, tree,
+ "SPNEGO reqFlags header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_BTS)) {
+ proto_tree_add_text(
+ tree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ /* We must have a Bit String ... insert it */
+
+ offset = hnd->offset;
+
+ flags = tvb_get_guint8(tvb, offset);
+
+ item = proto_tree_add_item(tree, hf_spnego_reqflags, tvb, offset, len1,
+ FALSE);
+
+ subtree = proto_item_add_subtree(item, ett_spnego_reqflags);
+
+ /*
+ * Now, the bits. XXX: Assume 8 bits. FIXME.
+ */
+
+ proto_tree_add_boolean(subtree, hf_gssapi_reqflags_deleg, tvb, offset, len1, flags);
+ proto_tree_add_boolean(subtree, hf_gssapi_reqflags_mutual, tvb, offset, len1, flags);
+ proto_tree_add_boolean(subtree, hf_gssapi_reqflags_replay, tvb, offset, len1, flags);
+ proto_tree_add_boolean(subtree, hf_gssapi_reqflags_sequence, tvb, offset, len1, flags);
+ proto_tree_add_boolean(subtree, hf_gssapi_reqflags_anon, tvb, offset, len1, flags);
+ proto_tree_add_boolean(subtree, hf_gssapi_reqflags_conf, tvb, offset, len1, flags);
+ proto_tree_add_boolean(subtree, hf_gssapi_reqflags_integ, tvb, offset, len1, flags);
+
+ hnd->offset += len1;
+
+ done:
+ return offset + len1;
+
+}
+
+static int
+dissect_spnego_mechToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd,
+ dissector_handle_t next_level_dissector)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ gboolean def;
+ int ret;
+ guint cls, con, tag, nbytes;
+ gint length_remaining, reported_length_remaining;
+ tvbuff_t *token_tvb;
+
+ /*
+ * This appears to be a simple octet string ...
+ */
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, tree,
+ "SPNEGO sequence header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
+ proto_tree_add_text(
+ tree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ offset = hnd->offset;
+
+
+ /* Dont try to create an item with more bytes than remains in the
+ * frame or we will not even attempt to dissect those bytes we
+ * do have. (since there will be an exception)
+ *
+ * We use "tvb_ensure_length_remaining()" so that we throw
+ * an exception if there's nothing to dissect.
+ */
+ length_remaining = tvb_ensure_length_remaining(tvb,offset);
+ reported_length_remaining = tvb_reported_length_remaining(tvb,offset);
+ if ((guint)length_remaining > nbytes)
+ length_remaining = nbytes;
+ if ((guint)reported_length_remaining > nbytes)
+ reported_length_remaining = nbytes;
+ item = proto_tree_add_item(tree, hf_spnego_mechtoken, tvb, offset,
+ length_remaining, FALSE);
+ subtree = proto_item_add_subtree(item, ett_spnego_mechtoken);
+
+ /*
+ * Now, we should be able to dispatch after creating a new TVB.
+ */
+
+ token_tvb = tvb_new_subset(tvb, offset, length_remaining,
+ reported_length_remaining);
+ if (next_level_dissector)
+ call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
+
+ hnd->offset += nbytes; /* Update this ... */
+
+done:
+ return offset + nbytes;
+}
+
+static int
+dissect_spnego_mechListMIC(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd,
+ dissector_handle_t next_level_dissector)
+{
+ guint len1, cls, con, tag;
+ int ret;
+ gboolean def;
+ proto_tree *subtree = NULL;
+
+ /*
+ * Add the mechListMIC [3] Octet String or General String ...
+ */
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO sequence header", ret);
+ goto done;
+ }
+
+ offset = hnd->offset;
+
+ if (cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ) {
+
+ /*
+ * There seems to be two different forms this can take
+ * One as an Octet string, and one as a general string in a
+ * sequence ... We will have to dissect this later
+ */
+
+ proto_tree_add_text(tree, tvb, offset + 4, len1 - 4,
+ "mechListMIC: %s",
+ tvb_format_text(tvb, offset + 4, len1 - 4));
+
+ /* Naughty ... but we have to adjust for what we never took */
+
+ hnd->offset += len1;
+ offset += len1;
+
+ }
+ else if (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS) {
+ tvbuff_t *token_tvb;
+ proto_item *item;
+ proto_tree *subtree;
+
+ item = proto_tree_add_item(tree, hf_spnego_mechlistmic, tvb, offset,
+ len1, FALSE);
+ subtree = proto_item_add_subtree(item, ett_spnego_mechlistmic);
+
+ /*
+ * Now, we should be able to dispatch after creating a new TVB.
+ */
+
+ token_tvb = tvb_new_subset(tvb, offset, len1, -1);
+ if (next_level_dissector)
+ call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
+
+ hnd->offset += len1; /* Update this ... */
+ offset += len1;
+
+ }
+ else {
+
+ proto_tree_add_text(subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ done:
+
+ return offset;
+
+}
+
+static int
+dissect_spnego_negTokenInit(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd,
+ gssapi_oid_value **next_level_value_p)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ gboolean def;
+ guint len1, len, cls, con, tag;
+ int ret;
+
+ item = proto_tree_add_item( tree, hf_spnego_negtokeninit, tvb, offset,
+ -1, FALSE);
+ subtree = proto_item_add_subtree(item, ett_spnego_negtokeninit);
+
+ /*
+ * Here is what we need to get ...
+ * NegTokenInit ::= SEQUENCE {
+ * mechTypes [0] MechTypeList OPTIONAL,
+ * reqFlags [1] ContextFlags OPTIONAL,
+ * mechToken [2] OCTET STRING OPTIONAL,
+ * mechListMIC [3] OCTET STRING OPTIONAL }
+
+ */
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO sequence header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
+ proto_tree_add_text(
+ subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ offset = hnd->offset;
+
+ while (len1) {
+ int hdr_ofs;
+
+ hdr_ofs = hnd->offset;
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO context header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_CTX && con == ASN1_CON)) {
+ proto_tree_add_text(subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ /* Adjust for the length of the header */
+
+ len1 -= (hnd->offset - hdr_ofs);
+
+ /* Should be one of the fields */
+
+ switch (tag) {
+
+ case SPNEGO_mechTypes:
+
+ offset = dissect_spnego_mechTypes(tvb, offset, pinfo,
+ subtree, hnd,
+ next_level_value_p);
+
+ break;
+
+ case SPNEGO_reqFlags:
+
+ offset = dissect_spnego_reqFlags(tvb, offset, pinfo, subtree, hnd);
+
+ break;
+
+ case SPNEGO_mechToken:
+
+ offset = dissect_spnego_mechToken(tvb, offset, pinfo, subtree,
+ hnd, gssapi_dissector_handle(*next_level_value_p));
+ break;
+
+ case SPNEGO_mechListMIC:
+
+ offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
+ hnd, gssapi_dissector_handle(*next_level_value_p));
+ break;
+
+ default:
+
+ break;
+ }
+
+ len1 -= len;
+
+ }
+
+ done:
+
+ return offset; /* Not sure this is right */
+}
+
+static int
+dissect_spnego_negResult(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd)
+{
+ gboolean def;
+ int ret;
+ guint len, cls, con, tag, val;
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, tree,
+ "SPNEGO context header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_ENUM)) {
+ proto_tree_add_text(
+ tree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d) xxx",
+ cls, con, tag);
+ goto done;
+ }
+
+ offset = hnd->offset;
+
+ /* Now, get the value */
+
+ ret = asn1_uint32_value_decode(hnd, len, &val);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, tree,
+ "SPNEGO negResult value", ret);
+ goto done;
+ }
+
+ proto_tree_add_item(tree, hf_spnego_negtokentarg_negresult, tvb,
+ offset, 1, FALSE);
+
+ offset = hnd->offset;
+
+ done:
+ return offset;
+}
+
+static int
+dissect_spnego_supportedMech(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd,
+ gssapi_oid_value **next_level_value_p)
+{
+ int ret;
+ guint oid_len, nbytes;
+ subid_t *oid;
+ gchar *oid_string;
+ gssapi_oid_value *value;
+ conversation_t *conversation;
+
+ /*
+ * Now, get the OID, and find the handle, if any
+ */
+
+ offset = hnd->offset;
+
+ ret = asn1_oid_decode(hnd, &oid, &oid_len, &nbytes);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, tree,
+ "SPNEGO supportedMech token", ret);
+ goto done;
+ }
+
+ oid_string = format_oid(oid, oid_len);
+ value = gssapi_lookup_oid(oid, oid_len);
+
+ if (value)
+ proto_tree_add_text(tree, tvb, offset, nbytes,
+ "supportedMech: %s (%s)",
+ oid_string, value->comment);
+ else
+ proto_tree_add_text(tree, tvb, offset, nbytes, "supportedMech: %s",
+ oid_string);
+
+ g_free(oid_string);
+
+ offset += nbytes;
+
+ /* Should check for an unrecognized OID ... */
+
+ if (value)
+ *next_level_value_p = value;
+
+ /*
+ * Now, we need to save this in per proto info in the
+ * conversation if it exists. We also should create a
+ * conversation if one does not exist. FIXME!
+ * Hmmm, might need to be smarter, because there can be
+ * multiple mechTypes in a negTokenInit with one being the
+ * default used in the Token if present. Then the negTokenTarg
+ * could override that. :-(
+ */
+
+ if ((conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0))) {
+
+
+ conversation_add_proto_data(conversation, proto_spnego,
+ *next_level_value_p);
+ }
+ else {
+
+ }
+
+ done:
+ return offset;
+}
+
+static int
+dissect_spnego_responseToken(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd,
+ dissector_handle_t next_level_dissector)
+{
+ gboolean def;
+ int ret;
+ guint cls, con, tag, nbytes;
+ tvbuff_t *token_tvb;
+ proto_item *item;
+ proto_tree *subtree;
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &nbytes);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, tree,
+ "SPNEGO sequence header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)) {
+ proto_tree_add_text(
+ tree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ offset = hnd->offset;
+
+ item = proto_tree_add_item(tree, hf_spnego_responsetoken, tvb, offset -2 ,
+ nbytes + 2, FALSE);
+
+ subtree = proto_item_add_subtree(item, ett_spnego_responsetoken);
+
+
+ /*
+ * Now, we should be able to dispatch after creating a new TVB.
+ * However, we should make sure that there is something in the
+ * response token ...
+ */
+
+ if (nbytes) {
+ token_tvb = tvb_new_subset(tvb, offset, nbytes, -1);
+ if (next_level_dissector)
+ call_dissector(next_level_dissector, token_tvb, pinfo, subtree);
+ }
+ else {
+ proto_tree_add_text(subtree, tvb, offset-2, 2, "<Empty String>");
+ }
+ hnd->offset += nbytes; /* Update this ... */
+
+ done:
+ return offset + nbytes;
+}
+
+static int
+dissect_spnego_negTokenTarg(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, ASN1_SCK *hnd,
+ gssapi_oid_value **next_level_value_p)
+
+{
+ proto_item *item;
+ proto_tree *subtree;
+ gboolean def;
+ int ret;
+ guint len1, len, cls, con, tag;
+
+ item = proto_tree_add_item( tree, hf_spnego_negtokentarg, tvb, offset,
+ -1, FALSE);
+ subtree = proto_item_add_subtree(item, ett_spnego_negtokentarg);
+
+ /*
+ * Here is what we need to get ...
+ * 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 }
+ */
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO sequence header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_UNI && con == ASN1_CON && tag == ASN1_SEQ)) {
+ proto_tree_add_text(
+ subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ offset = hnd->offset;
+
+ while (len1) {
+ int hdr_ofs;
+
+ hdr_ofs = hnd->offset;
+
+ ret = asn1_header_decode(hnd, &cls, &con, &tag, &def, &len);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO context header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_CTX && con == ASN1_CON)) {
+ proto_tree_add_text(
+ subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ /* Adjust for the length of the header */
+
+ len1 -= (hnd->offset - hdr_ofs);
+
+ /* Should be one of the fields */
+
+ switch (tag) {
+
+ case SPNEGO_negResult:
+
+ offset = dissect_spnego_negResult(tvb, offset, pinfo, subtree,
+ hnd);
+ break;
+
+ case SPNEGO_supportedMech:
+
+ offset = dissect_spnego_supportedMech(tvb, offset, pinfo, subtree,
+ hnd, next_level_value_p);
+
+ break;
+
+ case SPNEGO_responseToken:
+
+ offset = dissect_spnego_responseToken(tvb, offset, pinfo, subtree,
+ hnd, gssapi_dissector_handle(*next_level_value_p));
+ break;
+
+ case SPNEGO_mechListMIC:
+
+ offset = dissect_spnego_mechListMIC(tvb, offset, pinfo, subtree,
+ hnd, gssapi_dissector_handle(*next_level_value_p));
+ break;
+
+ default:
+
+ break;
+ }
+
+ len1 -= len;
+
+ }
+
+ done:
+ return offset;
+
+}
+
+static void
+dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ int ret, offset = 0;
+ ASN1_SCK hnd;
+ gboolean def;
+ guint len1, cls, con, tag;
+ conversation_t *conversation;
+ gssapi_oid_value *next_level_value;
+
+ /*
+ * 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->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(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.
+ *
+ */
+
+ asn1_open(&hnd, tvb, offset);
+
+ /*
+ * Get the first header ...
+ */
+
+ ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO context header", ret);
+ goto done;
+ }
+
+ if (!(cls == ASN1_CTX && con == ASN1_CON)) {
+ proto_tree_add_text(
+ subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ goto done;
+ }
+
+ offset = hnd.offset;
+
+ /*
+ * The Tag is one of negTokenInit or negTokenTarg
+ */
+
+ switch (tag) {
+
+ case SPNEGO_negTokenInit:
+
+ offset = dissect_spnego_negTokenInit(tvb, offset, pinfo,
+ subtree, &hnd,
+ &next_level_value);
+
+ break;
+
+ case SPNEGO_negTokenTarg:
+
+ offset = dissect_spnego_negTokenTarg(tvb, offset, pinfo,
+ subtree, &hnd,
+ &next_level_value);
+ break;
+
+ default: /* Broken, what to do? */
+
+ break;
+ }
+
+
+ done:
+ asn1_close(&hnd, &offset);
+
+}
+
+static int
+dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *item;
+ proto_tree *subtree;
+ int ret, offset = 0;
+ int return_offset;
+ ASN1_SCK hnd;
+ gboolean def;
+ guint len1, cls, con, tag, nbytes;
+ guint oid_len;
+ subid_t *oid;
+ gchar *oid_string;
+ conversation_t *conversation;
+ gssapi_oid_value *next_level_value;
+ tvbuff_t *token_tvb;
+ int len;
+
+ /*
+ * 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->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(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_open(&hnd, tvb, offset);
+
+ /*
+ * Get the first header ...
+ */
+
+ ret = asn1_header_decode(&hnd, &cls, &con, &tag, &def, &len1);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, subtree,
+ "SPNEGO context header", ret);
+ return_offset = tvb_length(tvb);
+ goto done;
+ }
+
+ if (!(cls == ASN1_APL && con == ASN1_CON && tag == 0)) {
+ proto_tree_add_text(
+ subtree, tvb, offset, 0,
+ "Unknown header (cls=%d, con=%d, tag=%d)",
+ cls, con, tag);
+ return_offset = tvb_length(tvb);
+ goto done;
+ }
+
+ offset = hnd.offset;
+
+ /*
+ * Get the OID, and find the handle, if any
+ */
+
+ ret = asn1_oid_decode(&hnd, &oid, &oid_len, &nbytes);
+
+ if (ret != ASN1_ERR_NOERROR) {
+ dissect_parse_error(tvb, offset, pinfo, tree,
+ "SPNEGO wrap token", ret);
+ return_offset = tvb_length(tvb);
+ goto done;
+ }
+
+ oid_string = format_oid(oid, oid_len);
+ next_level_value = gssapi_lookup_oid(oid, oid_len);
+
+ /*
+ * XXX - what should we do if this doesn't match the value
+ * attached to the frame or conversation? (That would be
+ * bogus, but that's not impossible - some broken implementation
+ * might negotiate some security mechanism but put the OID
+ * for some other security mechanism in GSS_Wrap tokens.)
+ */
+ if (next_level_value)
+ proto_tree_add_text(tree, tvb, offset, nbytes,
+ "thisMech: %s (%s)",
+ oid_string, next_level_value->comment);
+ else
+ proto_tree_add_text(tree, tvb, offset, nbytes, "thisMech: %s",
+ oid_string);
+
+ g_free(oid_string);
+
+ offset += nbytes;
+
+ /*
+ * 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)
+ return_offset = tvb_length(tvb);
+ else
+ return_offset = offset + len;
+ } else
+ return_offset = tvb_length(tvb);
+ done:
+ asn1_close(&hnd, &offset);
+
+ return return_offset;
+}
+
+void
+proto_register_spnego(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_spnego,
+ { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
+ "SPNEGO", HFILL }},
+ { &hf_spnego_negtokeninit,
+ { "negTokenInit", "spnego.negtokeninit", FT_NONE, BASE_NONE,
+ NULL, 0x0, "SPNEGO negTokenInit", HFILL}},
+ { &hf_spnego_negtokentarg,
+ { "negTokenTarg", "spnego.negtokentarg", FT_NONE, BASE_NONE,
+ NULL, 0x0, "SPNEGO negTokenTarg", HFILL}},
+ { &hf_spnego_mechtype,
+ { "mechType", "spnego.negtokeninit.mechtype", FT_NONE,
+ BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechTypes", HFILL}},
+ { &hf_spnego_mechtoken,
+ { "mechToken", "spnego.negtokeninit.mechtoken", FT_NONE,
+ BASE_NONE, NULL, 0x0, "SPNEGO negTokenInit mechToken", HFILL}},
+ { &hf_spnego_mechlistmic,
+ { "mechListMIC", "spnego.mechlistmic", FT_NONE,
+ BASE_NONE, NULL, 0x0, "SPNEGO mechListMIC", HFILL}},
+ { &hf_spnego_responsetoken,
+ { "responseToken", "spnego.negtokentarg.responsetoken",
+ FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO responseToken",
+ HFILL}},
+ { &hf_spnego_negtokentarg_negresult,
+ { "negResult", "spnego.negtokeninit.negresult", FT_UINT16,
+ BASE_HEX, VALS(spnego_negResult_vals), 0, "negResult", HFILL}},
+ { &hf_spnego_reqflags,
+ { "reqFlags", "spnego.negtokeninit.reqflags", FT_BYTES,
+ BASE_HEX, NULL, 0, "reqFlags", HFILL }},
+ { &hf_gssapi_reqflags_deleg,
+ { "Delegation", "gssapi.reqflags.deleg", FT_BOOLEAN, 8,
+ TFS(&tfs_reqflags_deleg), 0x01, "Delegation", HFILL }},
+ { &hf_gssapi_reqflags_mutual,
+ { "Mutual Authentication", "gssapi.reqflags.mutual", FT_BOOLEAN,
+ 8, TFS(&tfs_reqflags_mutual), 0x02, "Mutual Authentication", HFILL}},
+ { &hf_gssapi_reqflags_replay,
+ { "Replay Detection", "gssapi.reqflags.replay", FT_BOOLEAN,
+ 8, TFS(&tfs_reqflags_replay), 0x04, "Replay Detection", HFILL}},
+ { &hf_gssapi_reqflags_sequence,
+ { "Out-of-sequence Detection", "gssapi.reqflags.sequence",
+ FT_BOOLEAN, 8, TFS(&tfs_reqflags_sequence), 0x08,
+ "Out-of-sequence Detection", HFILL}},
+ { &hf_gssapi_reqflags_anon,
+ { "Anonymous Authentication", "gssapi.reqflags.anon",
+ FT_BOOLEAN, 8, TFS(&tfs_reqflags_anon), 0x10,
+ "Anonymous Authentication", HFILL}},
+ { &hf_gssapi_reqflags_conf,
+ { "Per-message Confidentiality", "gssapi.reqflags.conf",
+ FT_BOOLEAN, 8, TFS(&tfs_reqflags_conf), 0x20,
+ "Per-message Confidentiality", HFILL}},
+ { &hf_gssapi_reqflags_integ,
+ { "Per-message Integrity", "gssapi.reqflags.integ",
+ FT_BOOLEAN, 8, TFS(&tfs_reqflags_integ), 0x40,
+ "Per-message Integrity", 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_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}},
+ };
+
+ static gint *ett[] = {
+ &ett_spnego,
+ &ett_spnego_negtokeninit,
+ &ett_spnego_negtokentarg,
+ &ett_spnego_mechtype,
+ &ett_spnego_mechtoken,
+ &ett_spnego_mechlistmic,
+ &ett_spnego_responsetoken,
+ &ett_spnego_wraptoken,
+ &ett_spnego_krb5,
+ };
+
+ proto_spnego = proto_register_protocol(
+ "Spnego", "Spnego", "spnego");
+ proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
+ "SPNEGO-KRB5",
+ "spnego-krb5");
+
+ proto_register_field_array(proto_spnego, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+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");
+}