From Naoyoshi Ueda:

Patch to fix DTLS decryption.

https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6847

svn path=/trunk/; revision=41036
This commit is contained in:
Anders Broman 2012-02-16 05:21:09 +00:00
parent ea02598924
commit 245fb95f47
3 changed files with 102 additions and 69 deletions

View File

@ -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> {

View File

@ -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;
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);
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);
/* 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;

View File

@ -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;
}
}
else{
/* 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 failed\n");
return -1;
}
}
*outl = worklen;