* 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 <stdio.h>
#include <string.h>
#include "packet-ber.h"
#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;
#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"
/*
int offset = 0;
guint16 token_id;
const char *oid;
- gssapi_oid_value *value;
tvbuff_t *krb5_tvb;
- gint8 class;
+ gint8 ber_class;
gboolean pc, ind = 0;
gint32 tag;
guint32 len;
asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
- -1, FALSE);
+ -1, ENC_NA);
subtree = proto_item_add_subtree(item, ett_spnego_krb5);
/*
* 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) {
/* Next, the OID */
offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, 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);
* No token ID - just dissect as a Kerberos message and
* return.
*/
- offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
+ 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);
+ ber_class, pc, tag);
goto done;
}
} else {
}
#ifdef HAVE_KERBEROS
-#include <epan/crypt/crypt-md5.h>
+#include <wsutil/md5.h>
#ifndef KEYTYPE_ARCFOUR_56
# define KEYTYPE_ARCFOUR_56 24
#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];
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(
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];
* 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;
{
guint8 Klocaldata[16];
int ret;
- gint32 seq_number;
- 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);
}
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) {
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, (unsigned char *)SND_SEQ, 8);
+ tvb_memcpy(pinfo->gssapi_wrap_tvb, SND_SEQ, 8, 8);
+ crypt_rc4(&rc4_state, (guint8 *)SND_SEQ, 8);
memset(k6_data, 0, sizeof(k6_data));
}
- seq_number=g_ntohl(SND_SEQ[0]);
if (SND_SEQ[1] != 0xFFFFFFFF && SND_SEQ[1] != 0x00000000) {
return -6;
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) {
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);
+ tvb_memcpy(pinfo->gssapi_wrap_tvb, Confounder, 24, 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 */
+ tvb_memcpy(pinfo->gssapi_wrap_tvb, Confounder, 24, 8);
memcpy(output_message_buffer,
input_message_buffer,
datalen);
return -10;
}
- cmp = memcmp(cksum_data,
- tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
- 8); /* SGN_CKSUM */
+ cmp = tvb_memeql(pinfo->gssapi_wrap_tvb, 16, cksum_data, 8); /* SGN_CKSUM */
if (cmp) {
return -11;
}
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);
/* 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 */
);
if (ret >= 0) {
proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
- pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
+ 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;
}
/* 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)
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);
}
#define KRB5_KU_USAGE_INITIATOR_SIGN 25
static void
-decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_, packet_info *pinfo _U_, tvbuff_t *tvb _U_, guint16 ec _U_, guint16 rrc _U_, int keytype, unsigned int usage)
+decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_,
+ packet_info *pinfo,
+ tvbuff_t *checksum_tvb,
+ tvbuff_t *encrypted_tvb,
+ guint16 ec,
+ guint16 rrc,
+ gboolean is_dce,
+ int keytype,
+ unsigned int usage)
{
- int res;
- char *rotated;
- char *output;
+ guint8 *rotated;
+ guint8 *output;
int datalen;
tvbuff_t *next_tvb;
return;
}
- rotated = tvb_memdup(tvb, 0, tvb_length(tvb));
- res = rrc_rotate(rotated, tvb_length(tvb), rrc, TRUE);
+ datalen = tvb_length(checksum_tvb) + tvb_length(encrypted_tvb);
- next_tvb=tvb_new_child_real_data(tvb, rotated, tvb_length(tvb), tvb_reported_length(tvb));
- tvb_set_free_cb(next_tvb, g_free);
+ rotated = (guint8 *)wmem_alloc(pinfo->pool, datalen);
+
+ tvb_memcpy(checksum_tvb, rotated,
+ 0, tvb_length(checksum_tvb));
+ tvb_memcpy(encrypted_tvb, rotated + tvb_length(checksum_tvb),
+ 0, tvb_length(encrypted_tvb));
+
+ if (is_dce) {
+ rrc += ec;
+ }
+
+ rrc_rotate(rotated, datalen, rrc, TRUE);
+
+ next_tvb=tvb_new_child_real_data(encrypted_tvb, rotated,
+ datalen, datalen);
add_new_data_source(pinfo, next_tvb, "GSSAPI CFX");
output = decrypt_krb5_data(tree, pinfo, usage, next_tvb,
keytype, &datalen);
if (output) {
- char *outdata;
+ guint8 *outdata;
- outdata = g_memdup(output, tvb_length(tvb));
+ outdata = (guint8 *)g_memdup(output, tvb_length(encrypted_tvb));
g_free(output);
- pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(tvb,
+ pinfo->gssapi_decrypted_tvb=tvb_new_child_real_data(encrypted_tvb,
outdata,
- datalen-16,
- datalen-16);
+ tvb_length(encrypted_tvb),
+ tvb_length(encrypted_tvb));
add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
tvb_set_free_cb(pinfo->gssapi_decrypted_tvb, g_free);
return;
/* Encrypted sequence number */
proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
- TRUE);
+ ENC_NA);
offset += 8;
/* Checksum of plaintext padded data */
proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
- TRUE);
+ ENC_NA);
offset += 8;
we may need to make this an option. gal 17/2/06 */
(sgn_alg == KRB_SGN_ALG_DES_MAC_MD5)) {
proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
- TRUE);
+ ENC_NA);
offset += 8;
}
/* Encrypted sequence number */
proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
- TRUE);
+ ENC_NA);
offset += 8;
/* Checksum of plaintext padded data */
proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
- TRUE);
+ ENC_NA);
offset += 8;
if (tvb_length_remaining(tvb, offset)) {
if (sgn_alg == KRB_SGN_ALG_HMAC) {
proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
- TRUE);
+ ENC_NA);
offset += 8;
}
{
guint8 flags;
guint16 ec;
+#if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
guint16 rrc;
+#endif
int checksum_size;
int start_offset=offset;
/* Skip the filler */
proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 1,
- FALSE);
+ ENC_NA);
offset += 1;
/* EC */
ec = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2,
- FALSE);
+ ENC_BIG_ENDIAN);
offset += 2;
/* RRC */
+#if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
rrc = tvb_get_ntohs(tvb, offset);
+#endif
proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2,
- FALSE);
+ ENC_BIG_ENDIAN);
offset += 2;
/* sequence number */
proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
- FALSE);
+ ENC_BIG_ENDIAN);
offset += 8;
/* Checksum of plaintext padded data */
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, FALSE);
- 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
}
#if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
- pinfo->gssapi_encrypted_tvb = tvb_new_subset_remaining(tvb, 16);
+{
+ tvbuff_t *checksum_tvb = tvb_new_subset(tvb, 16, checksum_size, checksum_size);
- if (flags & 0x0002) {
+ if (pinfo->gssapi_data_encrypted) {
if(pinfo->gssapi_encrypted_tvb){
decrypt_gssapi_krb_cfx_wrap(tree,
pinfo,
+ checksum_tvb,
pinfo->gssapi_encrypted_tvb,
ec,
rrc,
+ (pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_DCE)?TRUE:FALSE,
-1,
(flags & 0x0001)?
KRB5_KU_USAGE_ACCEPTOR_SEAL:
KRB5_KU_USAGE_INITIATOR_SEAL);
}
}
+}
#endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
/*
/* Skip the filler */
proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 5,
- FALSE);
+ ENC_NA);
offset += 5;
/* sequence number */
proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
- FALSE);
+ ENC_BIG_ENDIAN);
offset += 8;
/* Checksum of plaintext padded data */
checksum_size = tvb_length_remaining(tvb, offset);
proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
- checksum_size, FALSE);
+ checksum_size, ENC_NA);
offset += checksum_size;
/*
* 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;
int offset = 0;
guint16 token_id;
- item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
+ item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, ENC_NA);
subtree = proto_item_add_subtree(item, ett_spnego_krb5);
/* 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;
asn1_ctx_t asn1_ctx;
asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
-
+ MechType_oid = NULL;
/*
* We need this later, so lets get it now ...
item = proto_tree_add_item(tree, proto_spnego, tvb, offset,
- -1, FALSE);
+ -1, ENC_NA);
subtree = proto_item_add_subtree(item, ett_spnego);
/*
* 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
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);
}
}
item = proto_tree_add_item(parent_tree, proto_spnego, tvb, offset,
- -1, FALSE);
+ -1, ENC_NA);
subtree = proto_item_add_subtree(item, ett_spnego);
* 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);
}