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:
parent
ea02598924
commit
245fb95f47
1
AUTHORS
1
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> {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue