This fix now allows SASL/GSS-API with integrity only to be properly dissected
[metze/wireshark/wip.git] / asn1 / spnego / packet-spnego-template.c
index a0c5ceafa60eae12f6e27e617fae0d45d58af560..801ba66de7191ae9dd5d8a0393627151da531ad0 100644 (file)
@@ -7,8 +7,6 @@
  * Copyright 2005, Ronnie Sahlberg (krb decryption)
  * Copyright 2005, Anders Broman (converted to asn2wrs generated dissector)
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
    Heimdal 1.6 and has been modified for wireshark's requirements.
 */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <glib.h>
+
+#include <wsutil/rc4.h>
+
 #include <epan/packet.h>
 #include <epan/asn1.h>
 #include "packet-dcerpc.h"
 #include "packet-gssapi.h"
 #include "packet-kerberos.h"
-#include <epan/crypt/crypt-rc4.h>
 #include <epan/conversation.h>
-#include <epan/emem.h>
+#include <epan/wmem/wmem.h>
 #include <epan/asn1.h>
 
 #include <string.h>
@@ -55,6 +53,9 @@
 #define PSNAME "SPNEGO"
 #define PFNAME "spnego"
 
+void proto_register_spnego(void);
+void proto_reg_handoff_spnego(void);
+
 /* Initialize the protocol and registered fields */
 static int proto_spnego = -1;
 static int proto_spnego_krb5 = -1;
@@ -95,13 +96,16 @@ static gint ett_spnego_krb5_cfx_flags = -1;
 #include "packet-spnego-ett.c"
 
 /*
- * Unfortunately, we have to have a forward declaration of this,
+ * Unfortunately, we have to have forward declarations of thess,
  * as the code generated by asn2wrs includes a call before the
  * definition.
  */
-static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
+static int dissect_spnego_NegTokenInit(gboolean implicit_tag, tvbuff_t *tvb,
                                        int offset, asn1_ctx_t *actx _U_,
                                        proto_tree *tree, int hf_index);
+static int dissect_spnego_NegTokenInit2(gboolean implicit_tag, tvbuff_t *tvb,
+                                        int offset, asn1_ctx_t *actx _U_,
+                                        proto_tree *tree, int hf_index);
 
 #include "packet-spnego-fn.c"
 /*
@@ -180,7 +184,7 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        guint16 token_id;
        const char *oid;
        tvbuff_t *krb5_tvb;
-       gint8 class;
+       gint8 ber_class;
        gboolean pc, ind = 0;
        gint32 tag;
        guint32 len;
@@ -222,12 +226,12 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        /*
         * Get the first header ...
         */
-       get_ber_identifier(tvb, offset, &class, &pc, &tag);
-       if (class == BER_CLASS_APP && pc) {
+       get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
+       if (ber_class == BER_CLASS_APP && pc) {
            /*
             * [APPLICATION <tag>]
             */
-           offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
+           offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &ber_class, &pc, &tag);
            offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
 
            switch (tag) {
@@ -260,7 +264,7 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            default:
                proto_tree_add_text(subtree, tvb, offset, 0,
                        "Unknown header (class=%d, pc=%d, tag=%d)",
-                       class, pc, tag);
+                       ber_class, pc, tag);
                goto done;
            }
        } else {
@@ -313,7 +317,7 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 }
 
 #ifdef HAVE_KERBEROS
-#include <epan/crypt/crypt-md5.h>
+#include <wsutil/md5.h>
 
 #ifndef KEYTYPE_ARCFOUR_56
 # define KEYTYPE_ARCFOUR_56 24
@@ -324,9 +328,9 @@ dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 #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)
+arcfour_mic_key(const guint8 *key_data, size_t key_size, int key_type,
+               const guint8 *cksum_data, size_t cksum_size,
+               guint8 *key6_data)
 {
     guint8 k5_data[16];
     guint8 T[4];
@@ -341,14 +345,14 @@ arcfour_mic_key(void *key_data, size_t key_size, int key_type,
                 L40, 14,
                 key_data,
                 key_size,
-               k5_data);
+               k5_data);
        memset(&k5_data[7], 0xAB, 9);
     } else {
        md5_hmac(
                 T, 4,
                 key_data,
                 key_size,
-               k5_data);
+               k5_data);
     }
 
     md5_hmac(
@@ -380,17 +384,17 @@ usage2arcfour(int usage)
 
 static int
 arcfour_mic_cksum(guint8 *key_data, int key_length,
-                 unsigned usage,
+                 unsigned int usage,
                  guint8 sgn_cksum[8],
-                 const void *v1, size_t l1,
-                 const void *v2, size_t l2,
-                 const void *v3, size_t l3)
+                 const guint8 *v1, size_t l1,
+                 const guint8 *v2, size_t l2,
+                 const guint8 *v3, size_t l3)
 {
-    const guint8 signature[] = "signaturekey";
+    static const guint8 signature[] = "signaturekey";
     guint8 ksign_c[16];
-    unsigned char t[4];
+    guint8 t[4];
     md5_state_t ms;
-    unsigned char digest[16];
+    guint8 digest[16];
     int rc4_usage;
     guint8 cksum[16];
 
@@ -419,12 +423,12 @@ arcfour_mic_cksum(guint8 *key_data, int key_length,
  * 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)
+gssapi_verify_pad(guint8 *wrapped_data, int wrapped_length,
+                  int datalen,
+                  int *padlen)
 {
-    unsigned char *pad;
-    size_t padlength;
+    guint8 *pad;
+    int padlength;
     int i;
 
     pad = wrapped_data + wrapped_length - 1;
@@ -451,14 +455,14 @@ decrypt_arcfour(packet_info *pinfo,
 {
     guint8 Klocaldata[16];
     int ret;
-    size_t datalen;
+    int datalen;
     guint8 k6_data[16];
     guint32 SND_SEQ[2];
     guint8 Confounder[8];
     guint8 cksum_data[8];
     int cmp;
     int conf_flag;
-    size_t padlen = 0;
+    int padlen = 0;
 
     datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
 
@@ -475,7 +479,7 @@ decrypt_arcfour(packet_info *pinfo,
     }
 
     ret = arcfour_mic_key(key_value, key_size, key_type,
-                         (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
+                         tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
                          8, /* SGN_CKSUM */
                          k6_data);
     if (ret) {
@@ -487,7 +491,7 @@ decrypt_arcfour(packet_info *pinfo,
 
        crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
        tvb_memcpy(pinfo->gssapi_wrap_tvb, SND_SEQ, 8, 8);
-       crypt_rc4(&rc4_state, (unsigned char *)SND_SEQ, 8);
+       crypt_rc4(&rc4_state, (guint8 *)SND_SEQ, 8);
 
        memset(k6_data, 0, sizeof(k6_data));
     }
@@ -504,7 +508,7 @@ decrypt_arcfour(packet_info *pinfo,
            Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
     }
     ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
-                         (unsigned char *)SND_SEQ, 4,
+                         (const guint8 *)SND_SEQ, 4,
                          k6_data);
     memset(Klocaldata, 0, sizeof(Klocaldata));
     if (ret) {
@@ -570,18 +574,9 @@ decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *
        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 *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);
 
@@ -594,12 +589,8 @@ decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *
        /* 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);
+       cryptocopy=(guint8 *)wmem_alloc(wmem_packet_scope(), length);
+       output_message_buffer=(guint8 *)wmem_alloc(pinfo->pool, length);
 
        for(ek=enc_key_list;ek;ek=ek->next){
                /* shortcircuit and bail out if enctypes are not matching */
@@ -626,7 +617,6 @@ decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *
                        pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
                                output_message_buffer,
                                ret, ret);
-                       tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
                        add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
                        return;
                }
@@ -636,9 +626,9 @@ decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *
 
 /* borrowed from heimdal */
 static int
-rrc_rotate(void *data, int len, guint16 rrc, int unrotate)
+rrc_rotate(guint8 *data, int len, guint16 rrc, int unrotate)
 {
-       unsigned char *tmp, buf[256];
+       guint8 *tmp, buf[256];
        size_t left;
 
        if (len == 0)
@@ -654,18 +644,18 @@ rrc_rotate(void *data, int len, guint16 rrc, int unrotate)
        if (rrc <= sizeof(buf)) {
                tmp = buf;
        } else {
-               tmp = g_malloc(rrc);
+               tmp = (guint8 *)g_malloc(rrc);
                if (tmp == NULL)
                        return -1;
        }
 
        if (unrotate) {
                memcpy(tmp, data, rrc);
-               memmove(data, (unsigned char *)data + rrc, left);
-               memcpy((unsigned char *)data + left, tmp, rrc);
+               memmove(data, data + rrc, left);
+               memcpy(data + left, tmp, rrc);
        } else {
-               memcpy(tmp, (unsigned char *)data + left, rrc);
-               memmove((unsigned char *)data + rrc, data, left);
+               memcpy(tmp, data + left, rrc);
+               memmove(data + rrc, data, left);
                memcpy(data, tmp, rrc);
        }
 
@@ -704,7 +694,7 @@ decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_,
 
        datalen = tvb_length(checksum_tvb) + tvb_length(encrypted_tvb);
 
-       rotated = g_malloc(datalen);
+       rotated = (guint8 *)wmem_alloc(pinfo->pool, datalen);
 
        tvb_memcpy(checksum_tvb, rotated,
                   0, tvb_length(checksum_tvb));
@@ -719,7 +709,6 @@ decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_,
 
        next_tvb=tvb_new_child_real_data(encrypted_tvb, rotated,
                                         datalen, datalen);
-       tvb_set_free_cb(next_tvb, g_free);
        add_new_data_source(pinfo, next_tvb, "GSSAPI CFX");
 
        output = decrypt_krb5_data(tree, pinfo, usage, next_tvb,
@@ -728,7 +717,7 @@ decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_,
        if (output) {
                guint8 *outdata;
 
-               outdata = g_memdup(output, tvb_length(encrypted_tvb));
+               outdata = (guint8 *)g_memdup(output, tvb_length(encrypted_tvb));
                g_free(output);
 
                pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(encrypted_tvb,
@@ -1037,13 +1026,40 @@ dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
 
        if (pinfo->gssapi_data_encrypted) {
                checksum_size = 44 + ec;
+
+               proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
+                                   checksum_size, ENC_NA);
+               offset += checksum_size;
+
        } else {
-               checksum_size = 12;
-       }
+               int inner_token_len = 0;
 
-       proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
-                           checksum_size, ENC_NA);
-       offset += checksum_size;
+               /*
+                * We know we have a wrap token, but we have to let the proto
+                * above us decode that, so hand it back in gssapi_wrap_tvb
+                * and put the checksum in the tree.
+                */
+
+               checksum_size = ec;
+
+               inner_token_len = tvb_reported_length_remaining(tvb, offset) -
+                                       ec;
+
+               pinfo->gssapi_wrap_tvb = tvb_new_subset(tvb, offset,
+                                               inner_token_len, inner_token_len);
+
+               offset += inner_token_len;
+
+               proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
+                                   checksum_size, ENC_NA);
+
+               /*
+                * Return an offset that puts our caller before the inner
+                * token. This is better than before, but we still see the
+                * checksum included in the LDAP query at times.
+                */
+               return offset - inner_token_len;
+       }
 
        if(pinfo->decrypt_gssapi_tvb){
                /* if the caller did not provide a tvb, then we just use
@@ -1165,7 +1181,7 @@ dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinf
  * getting it accepted.
  */
 static int
-dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
+dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
 {
        proto_item *item;
        proto_tree *subtree;
@@ -1225,7 +1241,7 @@ dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree
 /* Spnego stuff from here */
 
 static int
-dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
        proto_item *item;
        proto_tree *subtree;
@@ -1275,7 +1291,7 @@ dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
         * 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);
+       next_level_value = (gssapi_oid_value *)p_get_proto_data(wmem_file_scope(), pinfo, proto_spnego, 0);
        if (!next_level_value && !pinfo->fd->flags.visited) {
            /*
             * No handle attached to this frame, but it's the first
@@ -1288,10 +1304,10 @@ dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                             pinfo->destport, 0);
 
            if (conversation) {
-               next_level_value = conversation_get_proto_data(conversation,
+               next_level_value = (gssapi_oid_value *)conversation_get_proto_data(conversation,
                                                               proto_spnego);
                if (next_level_value)
-                   p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
+                   p_add_proto_data(wmem_file_scope(), pinfo, proto_spnego, 0, next_level_value);
            }
        }
 
@@ -1327,7 +1343,7 @@ dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
         * as well. Naughty, naughty.
         *
         */
-       offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
+       dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
 
 }