diff options
author | Anders Broman <anders.broman@ericsson.com> | 2012-02-16 05:21:09 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2012-02-16 05:21:09 +0000 |
commit | 245fb95f47f9f1714d7a17832892d1958c099e38 (patch) | |
tree | 67c4eb31111dd9dae8e57bb219fff9d0273743dc | |
parent | ea02598924bb1eccbe3fbe0bb87e641ee3605633 (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-- | AUTHORS | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-dtls.c | 131 | ||||
-rw-r--r-- | epan/dissectors/packet-ssl-utils.c | 39 |
3 files changed, 102 insertions, 69 deletions
@@ -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; |