aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2012-02-16 05:21:09 +0000
committerAnders Broman <anders.broman@ericsson.com>2012-02-16 05:21:09 +0000
commit245fb95f47f9f1714d7a17832892d1958c099e38 (patch)
tree67c4eb31111dd9dae8e57bb219fff9d0273743dc
parentea02598924bb1eccbe3fbe0bb87e641ee3605633 (diff)
From Naoyoshi Ueda:
Patch to fix DTLS decryption. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6847 svn path=/trunk/; revision=41036
-rw-r--r--AUTHORS1
-rw-r--r--epan/dissectors/packet-dtls.c131
-rw-r--r--epan/dissectors/packet-ssl-utils.c39
3 files changed, 102 insertions, 69 deletions
diff --git a/AUTHORS b/AUTHORS
index 7a5697a067..fad8da259c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2919,6 +2919,7 @@ Christian Durrer <christian.durrer [AT] sensemail.ch> {
Naoyoshi Ueda <piyomaru3141 [AT] gmail.com> {
IKEv2 decryption support
TLS 1.2 decryption support
+ DTLS 1.0 decryption fixes
}
Javier Cardona <javier [AT] cozybit.com> {
diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c
index ead632581a..3ae3fd33c2 100644
--- a/epan/dissectors/packet-dtls.c
+++ b/epan/dissectors/packet-dtls.c
@@ -371,6 +371,7 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
gboolean first_record_in_frame;
SslDecryptSession *ssl_session;
guint* conv_version;
+ Ssl_private_key_t *private_key;
ti = NULL;
dtls_tree = NULL;
@@ -420,9 +421,13 @@ dissect_dtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
* is not always available
* Note that with HAVE_LIBGNUTLS undefined private_key is allways 0
* and thus decryption never engaged*/
- ssl_session->private_key = g_hash_table_lookup(dtls_key_hash, &dummy);
- if (!ssl_session->private_key)
+ private_key = g_hash_table_lookup(dtls_key_hash, &dummy);
+ if (!private_key) {
ssl_debug_printf("dissect_dtls can't find private key for this server!\n");
+ }
+ else {
+ ssl_session->private_key = private_key->sexp_pkey;
+ }
}
conv_version= & ssl_session->version;
@@ -584,6 +589,11 @@ decrypt_dtls_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
decoder = ssl->client;
}
+ if (!decoder) {
+ ssl_debug_printf("decrypt_dtls_record: no decoder available\n");
+ return ret;
+ }
+
/* ensure we have enough storage space for decrypted data */
if (record_length > dtls_decrypted_data.data_len)
{
@@ -806,6 +816,7 @@ dissect_dtls_record(tvbuff_t *tvb, packet_info *pinfo,
col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec");
dissect_dtls_change_cipher_spec(tvb, dtls_record_tree,
offset, conv_version, content_type);
+ if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl, dtls_associations, pinfo));
break;
case SSL_ID_ALERT:
{
@@ -1315,6 +1326,18 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
break;
}
+ /* Skip leading two bytes length field. Older openssl's DTLS implementation seems not to have this field.
+ * See implementation note in RFC 4346 section 7.4.7.1
+ */
+ if (ssl->cipher_suite.kex==KEX_RSA && ssl->version_netorder != DTLSV1DOT0_VERSION_NOT) {
+ encrlen = tvb_get_ntohs(tvb, offset);
+ skip = 2;
+ if (encrlen > length - 2) {
+ ssl_debug_printf("dissect_dtls_handshake wrong encrypted length (%d max %d)\n", encrlen, length);
+ break;
+ }
+ }
+
encrypted_pre_master.data = se_alloc(encrlen);
encrypted_pre_master.data_len = encrlen;
tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen);
@@ -1362,67 +1385,71 @@ dissect_dtls_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree,
nstime_t gmt_unix_time;
guint8 session_id_length;
- if (ssl)
+ if (tree || ssl)
{
- /* get proper peer information*/
- StringInfo* rnd;
- if (from_server)
- rnd = &ssl->server_random;
- else
- rnd = &ssl->client_random;
-
- /* get provided random for keyring generation*/
- tvb_memcpy(tvb, rnd->data, offset, 32);
- rnd->data_len = 32;
- if (from_server)
- ssl->state |= SSL_SERVER_RANDOM;
- else
- ssl->state |= SSL_CLIENT_RANDOM;
- ssl_debug_printf("dissect_dtls_hnd_hello_common found random state %X\n",
- ssl->state);
-
- session_id_length = tvb_get_guint8(tvb, offset + 32);
- /* check stored session id info */
- if (from_server && (session_id_length == ssl->session_id.data_len) &&
- (tvb_memeql(tvb, offset+33, ssl->session_id.data, session_id_length) == 0))
- {
- /* clinet/server id match: try to restore a previous cached session*/
- ssl_restore_session(ssl, dtls_session_hash);
+ if (ssl)
+ {
+ /* get proper peer information*/
+ StringInfo* rnd;
+ if (from_server)
+ rnd = &ssl->server_random;
+ else
+ rnd = &ssl->client_random;
+
+ /* get provided random for keyring generation*/
+ tvb_memcpy(tvb, rnd->data, offset, 32);
+ rnd->data_len = 32;
+ if (from_server)
+ ssl->state |= SSL_SERVER_RANDOM;
+ else
+ ssl->state |= SSL_CLIENT_RANDOM;
+ ssl_debug_printf("dissect_dtls_hnd_hello_common found random state %X\n",
+ ssl->state);
}
- else {
- tvb_memcpy(tvb,ssl->session_id.data, offset+33, session_id_length);
- ssl->session_id.data_len = session_id_length;
- }
- }
- if (tree)
- {
/* show the time */
- gmt_unix_time.secs = tvb_get_ntohl(tvb, offset);
- gmt_unix_time.nsecs = 0;
- proto_tree_add_time(tree, hf_dtls_handshake_random_time,
- tvb, offset, 4, &gmt_unix_time);
+ if (tree)
+ {
+ gmt_unix_time.secs = tvb_get_ntohl(tvb, offset);
+ gmt_unix_time.nsecs = 0;
+ proto_tree_add_time(tree, hf_dtls_handshake_random_time,
+ tvb, offset, 4, &gmt_unix_time);
+ }
offset += 4;
/* show the random bytes */
- proto_tree_add_item(tree, hf_dtls_handshake_random_bytes,
- tvb, offset, 28, ENC_NA);
+ if (tree)
+ proto_tree_add_item(tree, hf_dtls_handshake_random_bytes,
+ tvb, offset, 28, ENC_NA);
offset += 28;
/* show the session id */
session_id_length = tvb_get_guint8(tvb, offset);
- proto_tree_add_item(tree, hf_dtls_handshake_session_id_len,
- tvb, offset++, 1, ENC_BIG_ENDIAN);
- if (session_id_length > 0)
+ if (tree)
+ proto_tree_add_item(tree, hf_dtls_handshake_session_id_len,
+ tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ if (ssl)
{
- proto_tree_add_bytes_format(tree, hf_dtls_handshake_session_id,
- tvb, offset, session_id_length,
- NULL, "Session ID (%u byte%s)",
- session_id_length,
- plurality(session_id_length, "", "s"));
- offset += session_id_length;
+ /* check stored session id info */
+ if (from_server && (session_id_length == ssl->session_id.data_len) &&
+ (tvb_memeql(tvb, offset, ssl->session_id.data, session_id_length) == 0))
+ {
+ /* clinet/server id match: try to restore a previous cached session*/
+ ssl_restore_session(ssl, dtls_session_hash);
+ }
+ else {
+ tvb_memcpy(tvb,ssl->session_id.data, offset, session_id_length);
+ ssl->session_id.data_len = session_id_length;
+ }
}
-
+ if (tree && session_id_length > 0)
+ proto_tree_add_bytes_format(tree, hf_dtls_handshake_session_id,
+ tvb, offset, session_id_length,
+ NULL, "Session ID (%u byte%s)",
+ session_id_length,
+ plurality(session_id_length, "", "s"));
+ offset += session_id_length;
}
/* XXXX */
@@ -1729,6 +1756,10 @@ dissect_dtls_hnd_srv_hello(tvbuff_t *tvb,
ssl->state |= SSL_HAVE_SESSION_KEY;
}
no_cipher:
+ if (ssl) {
+ /* store selected compression method for decompression */
+ ssl->compression = tvb_get_guint8(tvb, offset+2);
+ }
if (!tree)
return offset;
diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c
index 1b5af3923c..10c6fc1074 100644
--- a/epan/dissectors/packet-ssl-utils.c
+++ b/epan/dissectors/packet-ssl-utils.c
@@ -1885,7 +1885,8 @@ static gint prf(SslDecryptSession* ssl,StringInfo* secret,gchar* usage,StringInf
gint ret;
if (ssl->version_netorder==SSLV3_VERSION){
ret = ssl3_prf(secret,usage,rnd1,rnd2,out);
- }else if (ssl->version_netorder==TLSV1_VERSION || ssl->version_netorder==TLSV1DOT1_VERSION){
+ }else if (ssl->version_netorder==TLSV1_VERSION || ssl->version_netorder==TLSV1DOT1_VERSION ||
+ ssl->version_netorder==DTLSV1DOT0_VERSION || ssl->version_netorder==DTLSV1DOT0_VERSION_NOT){
ret = tls_prf(secret,usage,rnd1,rnd2,out);
}else{
if (ssl->cipher_suite.dig == DIG_SHA384){
@@ -2410,7 +2411,6 @@ ssl3_check_mac(SslDecoder*decoder,int ct,guint8* data,
return(0);
}
-#if 0
static gint
dtls_check_mac(SslDecoder*decoder, gint ct,int ver, guint8* data,
guint32 datalen, guint8* mac)
@@ -2419,7 +2419,8 @@ dtls_check_mac(SslDecoder*decoder, gint ct,int ver, guint8* data,
gint md;
guint32 len;
guint8 buf[20];
- guint32 netnum;
+ gint16 temp;
+
md=ssl_get_digest_by_name(digests[decoder->cipher_suite->dig-0x40]);
ssl_debug_printf("dtls_check_mac mac type:%s md %d\n",
digests[decoder->cipher_suite->dig-0x40], md);
@@ -2430,7 +2431,7 @@ dtls_check_mac(SslDecoder*decoder, gint ct,int ver, guint8* data,
/* hash sequence number */
fmt_seq(decoder->seq,buf);
buf[0]=decoder->epoch>>8;
- buf[1]=decoder->epoch;
+ buf[1]=(guint8)decoder->epoch;
ssl_hmac_update(&hm,buf,8);
@@ -2439,10 +2440,12 @@ dtls_check_mac(SslDecoder*decoder, gint ct,int ver, guint8* data,
ssl_hmac_update(&hm,buf,1);
/* hash version,data length and data */
- *((gint16*)buf) = g_htons(ver);
+ temp = g_htons(ver);
+ memcpy(buf, &temp, 2);
ssl_hmac_update(&hm,buf,2);
- *((gint16*)buf) = g_htons(datalen);
+ temp = g_htons(datalen);
+ memcpy(buf, &temp, 2);
ssl_hmac_update(&hm,buf,2);
ssl_hmac_update(&hm,data,datalen);
/* get digest and digest len */
@@ -2454,7 +2457,6 @@ dtls_check_mac(SslDecoder*decoder, gint ct,int ver, guint8* data,
return(0);
}
-#endif
#ifdef HAVE_LIBZ
int
@@ -2584,21 +2586,20 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct,
}
else if(ssl->version_netorder==DTLSV1DOT0_VERSION ||
ssl->version_netorder==DTLSV1DOT0_VERSION_NOT){
- /* following the openssl dtls errors the right test is:
- if(dtls_check_mac(decoder,ct,ssl->version_netorder,out_str->data,worklen,mac)< 0) { */
- if(tls_check_mac(decoder,ct,TLSV1_VERSION,out_str->data,worklen,mac)< 0) {
- if(ssl_ignore_mac_failed) {
- ssl_debug_printf("ssl_decrypt_record: mac failed, but ignored for troubleshooting ;-)\n");
- }
- else{
- ssl_debug_printf("ssl_decrypt_record: mac failed\n");
- return -1;
- }
+ /* Try rfc-compliant mac first, and if failed, try old openssl's non-rfc-compliant mac */
+ if(dtls_check_mac(decoder,ct,ssl->version_netorder,out_str->data,worklen,mac)>= 0) {
+ ssl_debug_printf("ssl_decrypt_record: mac ok\n");
+ }
+ else if(tls_check_mac(decoder,ct,TLSV1_VERSION,out_str->data,worklen,mac)>= 0) {
+ ssl_debug_printf("ssl_decrypt_record: dtls rfc-compliant mac failed, but old openssl's non-rfc-compliant mac ok\n");
+ }
+ else if(ssl_ignore_mac_failed) {
+ ssl_debug_printf("ssl_decrypt_record: mac failed, but ignored for troubleshooting ;-)\n");
}
else{
- ssl_debug_printf("ssl_decrypt_record: mac ok\n");
+ ssl_debug_printf("ssl_decrypt_record: mac failed\n");
+ return -1;
}
-
}
*outl = worklen;