aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2006-05-03 05:29:04 +0000
committerAnders Broman <anders.broman@ericsson.com>2006-05-03 05:29:04 +0000
commitdbdb3729deaef9af95dfdd69578706c39d40b0f9 (patch)
tree5faec4679313a7a4c743baff09655417314e6080
parent97419848da8486a623caed0821a7c73677ea38dc (diff)
From Paolo Abeni:
authesserre samuel <sauthess@gmail.com> kindly pointed out an issue with session renegotiation in the current ssl decryption code. Encrypted handshake message are decrypted, but the dissector try to interpret the encrypted code. Renegotiation messages are therefore ignored. The attached pcap trace and key can be used to trigger the issue. The attached patch fix the problem storing the decrypted version of encrypted handshake message and dissecting it when available. The patch also fix bad issue with des cipher (alike the issue fixed in my previous post) svn path=/trunk/; revision=18081
-rw-r--r--epan/dissectors/packet-ssl-utils.c34
-rw-r--r--epan/dissectors/packet-ssl-utils.h16
-rw-r--r--epan/dissectors/packet-ssl.c136
-rw-r--r--gtk/ssl-dlg.c8
4 files changed, 133 insertions, 61 deletions
diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c
index ee3b2bdeb0..e9fb2730e4 100644
--- a/epan/dissectors/packet-ssl-utils.c
+++ b/epan/dissectors/packet-ssl-utils.c
@@ -179,6 +179,13 @@ ssl_get_cipher_by_name(const char* name)
return gcry_cipher_map_name(name);
}
+static inline void
+ssl_cipher_cleanup(gcry_cipher_hd_t *cipher)
+{
+ gcry_cipher_close(*cipher);
+ *cipher = NULL;
+}
+
/* private key abstraction layer */
static inline int
ssl_get_key_len(SSL_PRIVATE_KEY* pk) {return gcry_pk_get_nbits (pk); }
@@ -355,8 +362,8 @@ static SslCipherSuite cipher_suites[]={
{5,KEX_RSA,SIG_RSA,ENC_RC4,1,128,128,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
{6,KEX_RSA,SIG_RSA,ENC_RC2,8,128,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
{7,KEX_RSA,SIG_RSA,ENC_IDEA,8,128,128,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
- {8,KEX_RSA,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
- {9,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
+ {8,KEX_RSA,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_CBC},
+ {9,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_CBC},
{10,KEX_RSA,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0, SSL_CIPHER_MODE_CBC},
{11,KEX_DH,SIG_DSS,ENC_DES,8,64,40,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM},
{12,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,20,0, SSL_CIPHER_MODE_STREAM},
@@ -591,7 +598,7 @@ ssl_create_decoder(SslDecoder *dec, SslCipherSuite *cipher_suite,
}
if (ciph == 0) {
ssl_debug_printf("ssl_create_decoder can't find cipher %s\n",
- ciphers[(cipher_suite->enc-0x30) > 7 ? 7 : (cipher_suite->enc-0x30)]);
+ ciphers[(cipher_suite->enc-0x30) > 7 ? 7 : (cipher_suite->enc-0x30)]);
return -1;
}
@@ -600,6 +607,10 @@ ssl_create_decoder(SslDecoder *dec, SslCipherSuite *cipher_suite,
dec->cipher_suite=cipher_suite;
dec->mac_key.data = dec->_mac_key;
ssl_data_set(&dec->mac_key, mk, cipher_suite->dig_len);
+ dec->seq = 0;
+
+ if (dec->evp)
+ ssl_cipher_cleanup(&dec->evp);
if (ssl_cipher_init(&dec->evp,ciph,sk,iv,cipher_suite->mode) < 0) {
ssl_debug_printf("ssl_create_decoder: can't create cipher id:%d mode:%d\n",
@@ -812,7 +823,9 @@ ssl_generate_keyring_material(SslDecryptSession*ssl_session)
ssl_debug_printf("ssl_generate_keyring_material can't init client decoder\n");
goto fail;
}
-
+
+ ssl_debug_printf("ssl_generate_keyring_material client seq %d server seq %d\n",
+ ssl_session->client.seq, ssl_session->server.seq);
g_free(key_block.data);
return 0;
@@ -853,7 +866,7 @@ ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session,
/* Remove the master secret if it was there.
This force keying material regeneration in
case we're renegotiating */
- ssl_session->state &= ~SSL_MASTER_SECRET;
+ ssl_session->state &= ~(SSL_MASTER_SECRET|SSL_HAVE_SESSION_KEY);
return 0;
}
@@ -926,10 +939,7 @@ ssl3_check_mac(SslDecoder*decoder,int ct,guint8* data,
/* get cipher used for digest comptuation */
md=ssl_get_digest_by_name(digests[decoder->cipher_suite->dig-0x40]);
- ssl_debug_printf("ssl3_check_mac digest%s md %d\n",
- digests[decoder->cipher_suite->dig-0x40], md);
ssl_md_init(&mc,md);
- ssl_debug_printf("ssl3_check_mac memory digest %p\n",mc);
/* do hash computation on data && padding */
ssl_md_update(&mc,decoder->mac_key.data,decoder->mac_key.data_len);
@@ -1009,19 +1019,19 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct,
return -1;
}
mac=out+worklen;
- /*ssl_print_data("Record data",out,*outl);*/
/* Now check the MAC */
- ssl_debug_printf("checking mac (len %d, version %X, ct %d)\n", worklen,ssl->version_netorder, ct);
+ ssl_debug_printf("checking mac (len %d, version %X, ct %d seq %d)\n",
+ worklen, ssl->version_netorder, ct, decoder->seq);
if(ssl->version_netorder==0x300){
if(ssl3_check_mac(decoder,ct,out,worklen,mac) < 0) {
- ssl_debug_printf("ssl_decrypt_record: mac falied\n");
+ ssl_debug_printf("ssl_decrypt_record: mac failed\n");
return -1;
}
}
else{
if(tls_check_mac(decoder,ct,ssl->version_netorder,out,worklen,mac)< 0) {
- ssl_debug_printf("ssl_decrypt_record: mac falied\n");
+ ssl_debug_printf("ssl_decrypt_record: mac failed\n");
return -1;
}
}
diff --git a/epan/dissectors/packet-ssl-utils.h b/epan/dissectors/packet-ssl-utils.h
index f852e5c4c3..4a4f71aeba 100644
--- a/epan/dissectors/packet-ssl-utils.h
+++ b/epan/dissectors/packet-ssl-utils.h
@@ -113,10 +113,18 @@ typedef struct _SslDecoder {
#define DIG_MD5 0x40
#define DIG_SHA 0x41
-/*typedef struct _SslService {
- address addr;
- guint port;
-} SslService;*/
+struct tvbuff;
+
+typedef struct _SslRecordInfo {
+ struct tvbuff* tvb;
+ int id;
+ struct _SslRecordInfo* next;
+} SslRecordInfo;
+
+typedef struct {
+ StringInfo app_data;
+ SslRecordInfo* handshake_data;
+} SslPacketInfo;
typedef struct _SslDecryptSession {
unsigned char _master_secret[48];
diff --git a/epan/dissectors/packet-ssl.c b/epan/dissectors/packet-ssl.c
index 6fc2d7c9d8..b43a13dab3 100644
--- a/epan/dissectors/packet-ssl.c
+++ b/epan/dissectors/packet-ssl.c
@@ -231,6 +231,7 @@ static GHashTable *ssl_key_hash = NULL;
static GTree* ssl_associations = NULL;
static dissector_handle_t ssl_handle = NULL;
static StringInfo ssl_decrypted_data = {NULL, 0};
+static int ssl_decrypted_data_avail = 0;
/* Hash Functions for ssl sessions table and private keys table*/
static gint
@@ -349,6 +350,44 @@ ssl_packet_from_server(unsigned int port)
return ret;
}
+/* add to packet data a newly allocated tvb with the specified real data*/
+static void
+ssl_add_record_info(packet_info *pinfo, unsigned char* data, int data_len, int record_id)
+{
+ unsigned char* real_data = se_alloc(data_len);
+ SslRecordInfo* rec = se_alloc(sizeof(SslRecordInfo));
+ SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl);
+ if (!pi)
+ {
+ pi = se_alloc0(sizeof(SslPacketInfo));
+ p_add_proto_data(pinfo->fd, proto_ssl,pi);
+ }
+
+ rec->id = record_id;
+ rec->tvb = tvb_new_real_data(real_data, data_len, data_len);
+ memcpy(real_data, data, data_len);
+
+ /* head insertion */
+ rec->next= pi->handshake_data;
+ pi->handshake_data = rec;
+}
+
+/* search in packet data the tvbuff associated to the specified id */
+static tvbuff_t*
+ssl_get_record_info(packet_info *pinfo, int record_id)
+{
+ SslRecordInfo* rec;
+ SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl);
+ if (!pi)
+ return NULL;
+
+ for (rec = pi->handshake_data; rec; rec = rec->next)
+ if (rec->id == record_id)
+ return rec->tvb;
+
+ return NULL;
+}
+
/* initialize/reset per capture state data (ssl sessions cache) */
static void
ssl_init(void)
@@ -1379,12 +1418,13 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
tap_queue_packet(ssl_tap, pinfo, (gpointer)proto_ssl);
}
-static void
+static int
decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
guint32 record_length, guint8 content_type, SslDecryptSession* ssl,
gboolean save_plaintext)
{
- int len, direction;
+ int ret = 0;
+ int direction;
SslDecoder* decoder;
/* if we can decrypt and decryption have success
@@ -1393,7 +1433,7 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
record_length, ssl->state);
if (!(ssl->state & SSL_HAVE_SESSION_KEY)) {
ssl_debug_printf("decrypt_ssl3_record: no session key\n");
- return ;
+ return ret;
}
/* retrive decoder for this packet direction*/
@@ -1419,46 +1459,48 @@ decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
/* run decryption and add decrypted payload to protocol data, if decryption
* is successful*/
- len = ssl_decrypted_data.data_len;
- if ((ssl_decrypt_record(ssl, decoder,
- content_type, tvb_get_ptr(tvb, offset, record_length),
- record_length, ssl_decrypted_data.data, &len) == 0) &&
- save_plaintext)
+ ssl_decrypted_data_avail = ssl_decrypted_data.data_len;
+ if (ssl_decrypt_record(ssl, decoder,
+ content_type, tvb_get_ptr(tvb, offset, record_length),
+ record_length, ssl_decrypted_data.data, &ssl_decrypted_data_avail) == 0)
+ ret = 1;
+ if (ret && save_plaintext)
{
- StringInfo* data = p_get_proto_data(pinfo->fd, proto_ssl);
- if (!data)
+ SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl);
+ if (!pi)
{
ssl_debug_printf("decrypt_ssl3_record: allocating app_data %d "
- "bytes for app data\n", len);
+ "bytes for app data\n", ssl_decrypted_data_avail);
/* first app data record: allocate and put packet data*/
- data = se_alloc(sizeof(StringInfo));
- data->data = se_alloc(len);
- data->data_len = len;
- memcpy(data->data, ssl_decrypted_data.data, len);
+ pi = se_alloc0(sizeof(SslPacketInfo));
+ pi->app_data.data = se_alloc(ssl_decrypted_data_avail);
+ pi->app_data.data_len = ssl_decrypted_data_avail;
+ memcpy(pi->app_data.data, ssl_decrypted_data.data, ssl_decrypted_data_avail);
}
else {
unsigned char* store;
/* update previus record*/
ssl_debug_printf("decrypt_ssl3_record: reallocating app_data "
"%d bytes for app data (total %d appdata bytes)\n",
- len, data->data_len + len);
- store = se_alloc(data->data_len + len);
- memcpy(store, data->data, data->data_len);
- memcpy(&store[data->data_len], ssl_decrypted_data.data, len);
- data->data_len += len;
+ ssl_decrypted_data_avail, pi->app_data.data_len + ssl_decrypted_data_avail);
+ store = se_alloc(pi->app_data.data_len + ssl_decrypted_data_avail);
+ memcpy(store, pi->app_data.data, pi->app_data.data_len);
+ memcpy(&store[pi->app_data.data_len], ssl_decrypted_data.data, ssl_decrypted_data_avail);
+ pi->app_data.data_len += ssl_decrypted_data_avail;
/* old decrypted data ptr here appare to be leaked, but it's
* collected by emem allocator */
- data->data = store;
+ pi->app_data.data = store;
/* data ptr is changed, so remove old one and re-add the new one*/
ssl_debug_printf("decrypt_ssl3_record: removing old app_data ptr\n");
p_remove_proto_data(pinfo->fd, proto_ssl);
}
- ssl_debug_printf("decrypt_ssl3_record: setting decrypted app_data ptr %p\n",data);
- p_add_proto_data(pinfo->fd, proto_ssl, data);
+ ssl_debug_printf("decrypt_ssl3_record: setting decrypted app_data ptr %p\n",pi);
+ p_add_proto_data(pinfo->fd, proto_ssl, pi);
}
+ return ret;
}
@@ -1500,7 +1542,7 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *ti = NULL;
proto_tree *ssl_record_tree = NULL;
guint32 available_bytes = 0;
- StringInfo* decrypted;
+ SslPacketInfo* pi;
SslAssociation* association;
available_bytes = tvb_length_remaining(tvb, offset);
@@ -1671,6 +1713,7 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec");
dissect_ssl3_change_cipher_spec(tvb, ssl_record_tree,
offset, conv_version, content_type);
+ ssl_debug_printf("dissect_ssl3_change_cipher_spec\n");
break;
case SSL_ID_ALERT:
if (ssl)
@@ -1680,12 +1723,27 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
conv_version);
break;
case SSL_ID_HANDSHAKE:
- if (ssl)
- decrypt_ssl3_record(tvb, pinfo, offset,
- record_length, content_type, ssl, FALSE);
- dissect_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset,
+ {
+ tvbuff_t* decrypted=0;
+ /* try to decrypt handshake record, if possible. Store decrypted
+ * record for later usage. The offset is used as 'key' to itentify
+ * this record into the packet (we can have multiple handshake records
+ * in the same frame) */
+ if (ssl && decrypt_ssl3_record(tvb, pinfo, offset,
+ record_length, content_type, ssl, FALSE))
+ ssl_add_record_info(pinfo, ssl_decrypted_data.data,
+ ssl_decrypted_data_avail, offset);
+
+ /* try to retrive and use decrypted handshake record, if any. */
+ decrypted = ssl_get_record_info(pinfo, offset);
+ if (decrypted)
+ dissect_ssl3_handshake(decrypted, pinfo, ssl_record_tree, 0,
+ decrypted->length, conv_version, ssl, content_type);
+ else
+ dissect_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset,
record_length, conv_version, ssl, content_type);
break;
+ }
case SSL_ID_APP_DATA:
if (ssl)
decrypt_ssl3_record(tvb, pinfo, offset,
@@ -1711,32 +1769,33 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
association?association->info:"Application Data");
/* show decrypted data info, if available */
- decrypted = p_get_proto_data(pinfo->fd, proto_ssl);
- if (decrypted)
+ pi = p_get_proto_data(pinfo->fd, proto_ssl);
+ if (pi && pi->app_data.data)
{
tvbuff_t* new_tvb;
/* try to dissect decrypted data*/
- ssl_debug_printf("dissect_ssl3_record decrypted len %d\n", decrypted->data_len);
+ ssl_debug_printf("dissect_ssl3_record decrypted len %d\n",
+ pi->app_data.data_len);
/* create new tvbuff for the decrypted data */
- new_tvb = tvb_new_real_data(decrypted->data,
- decrypted->data_len, decrypted->data_len);
+ new_tvb = tvb_new_real_data(pi->app_data.data,
+ pi->app_data.data_len, pi->app_data.data_len);
tvb_set_free_cb(new_tvb, g_free);
/* tvb_set_child_real_data_tvbuff(tvb, new_tvb); */
/* find out a dissector using server port*/
if (association && association->handle) {
ssl_debug_printf("dissect_ssl3_record found association %p\n", association);
- ssl_print_text_data("decrypted app data",decrypted->data,
- decrypted->data_len);
+ ssl_print_text_data("decrypted app data",pi->app_data.data,
+ pi->app_data.data_len);
call_dissector(association->handle, new_tvb, pinfo, ssl_record_tree);
}
/* add raw decrypted data only if a decoder is not found*/
else
proto_tree_add_string(ssl_record_tree, hf_ssl_record_appdata_decrypted, tvb,
- offset, decrypted->data_len, (char*) decrypted->data);
+ offset, pi->app_data.data_len, (char*) pi->app_data.data);
}
else {
tvb_ensure_bytes_exist(tvb, offset, record_length);
@@ -2121,11 +2180,6 @@ dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree,
ssl_restore_session(ssl);
}
else {
- /* reset state on renegotiation*/
- if (!from_server)
- ssl->state &= ~(SSL_HAVE_SESSION_KEY|SSL_MASTER_SECRET|
- SSL_CIPHER|SSL_SERVER_RANDOM);
-
tvb_memcpy(tvb,ssl->session_id.data, offset+33, session_id_length);
ssl->session_id.data_len = session_id_length;
}
diff --git a/gtk/ssl-dlg.c b/gtk/ssl-dlg.c
index 8f3034534b..44787804ce 100644
--- a/gtk/ssl-dlg.c
+++ b/gtk/ssl-dlg.c
@@ -141,10 +141,10 @@ ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_
follow_info_t* follow_info = tapdata;
SslDecryptedRecord* rec;
int proto_ssl = (int) ssl;
- StringInfo* data = p_get_proto_data(pinfo->fd, proto_ssl);
+ SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl);
/* skip packet without decrypted data payload*/
- if (!data)
+ if (!pi || !pi->app_data.data)
return 0;
/* compute packet direction */
@@ -162,10 +162,10 @@ ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_
rec->is_server = 1;
/* update stream counter */
- follow_info->bytes_written[rec->is_server] += data->data_len;
+ follow_info->bytes_written[rec->is_server] += pi->app_data.data_len;
/* extract decrypted data and queue it locally */
- rec->data = data;
+ rec->data = &pi->app_data;
follow_info->ssl_decrypted_data = g_list_append(
follow_info->ssl_decrypted_data,rec);