DTLS decryption enhancements. Bug 9499 (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9499)
From Hauke Mehrtens 1. dtls: set ssl_set_server() in DTLS dissector so wireshark knows if this is client or server 2. SSL: add decrypt support for CCM and CCM_8 Ciphers per rfc 6655 3. dtls: add psk decrypt support svn path=/trunk/; revision=53836
This commit is contained in:
parent
7d10a416a3
commit
0f05597ab1
|
@ -2,6 +2,7 @@
|
|||
* Routines for dtls dissection
|
||||
* Copyright (c) 2006, Authesserre Samuel <sauthess@gmail.com>
|
||||
* Copyright (c) 2007, Mikael Magnusson <mikma@users.sourceforge.net>
|
||||
* Copyright (c) 2013, Hauke Mehrtens <hauke@hauke-m.de>
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
|
@ -227,6 +228,7 @@ static gint dtls_decrypted_data_avail = 0;
|
|||
|
||||
static uat_t *dtlsdecrypt_uat = NULL;
|
||||
static const gchar *dtls_keys_list = NULL;
|
||||
static const gchar *dtls_psk = NULL;
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
static const gchar *dtls_debug_file_name = NULL;
|
||||
#endif
|
||||
|
@ -374,6 +376,7 @@ static void dissect_dtls_heartbeat(tvbuff_t *tvb, packet_info *pinfo,
|
|||
|
||||
|
||||
static void dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
|
||||
packet_info *pinfo,
|
||||
proto_tree *tree,
|
||||
guint32 offset, guint32 length,
|
||||
SslDecryptSession* ssl);
|
||||
|
@ -1443,7 +1446,7 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
|
|||
break;
|
||||
|
||||
case SSL_HND_CLIENT_HELLO:
|
||||
dissect_dtls_hnd_cli_hello(sub_tvb, ssl_hand_tree, 0, length, ssl);
|
||||
dissect_dtls_hnd_cli_hello(sub_tvb, pinfo, ssl_hand_tree, 0, length, ssl);
|
||||
break;
|
||||
|
||||
case SSL_HND_SERVER_HELLO:
|
||||
|
@ -1514,62 +1517,21 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
{
|
||||
/* here we can have all the data to build session key */
|
||||
StringInfo encrypted_pre_master;
|
||||
gint ret;
|
||||
guint encrlen = length, skip;
|
||||
skip = 0;
|
||||
|
||||
if (!ssl)
|
||||
/* here we can have all the data to build session key */
|
||||
if (!ssl)
|
||||
break;
|
||||
|
||||
/* check for required session data */
|
||||
ssl_debug_printf("dissect_dtls_handshake found SSL_HND_CLIENT_KEY_EXCHG, state %X\n",
|
||||
ssl->state);
|
||||
if ((ssl->state & (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) !=
|
||||
(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) {
|
||||
ssl_debug_printf("dissect_dtls_handshake not enough data to generate key (required state %X)\n",
|
||||
(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION));
|
||||
if (ssl_generate_pre_master_secret(ssl, length, tvb, offset, dtls_psk, NULL) < 0) {
|
||||
ssl_debug_printf("dissect_dtls_handshake can't generate pre master secret\n");
|
||||
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 = (guchar *)wmem_alloc(wmem_file_scope(), encrlen);
|
||||
encrypted_pre_master.data_len = encrlen;
|
||||
tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen);
|
||||
|
||||
if (!ssl->private_key) {
|
||||
ssl_debug_printf("dissect_dtls_handshake can't find private key\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* go with ssl key processing; encrypted_pre_master
|
||||
* will be used for master secret store*/
|
||||
ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl->private_key);
|
||||
if (ret < 0) {
|
||||
ssl_debug_printf("dissect_dtls_handshake can't decrypt pre master secret\n");
|
||||
break;
|
||||
}
|
||||
if (ssl_generate_keyring_material(ssl)<0) {
|
||||
}
|
||||
if (ssl_generate_keyring_material(ssl) < 0) {
|
||||
ssl_debug_printf("dissect_dtls_handshake can't generate keyring material\n");
|
||||
break;
|
||||
}
|
||||
ssl->state |= SSL_HAVE_SESSION_KEY;
|
||||
ssl_save_session(ssl, dtls_session_hash);
|
||||
ssl_debug_printf("dissect_dtls_handshake session keys successfully generated\n");
|
||||
}
|
||||
|
||||
ssl_save_session(ssl, dtls_session_hash);
|
||||
ssl_debug_printf("dissect_dtls_handshake session keys successfully generated\n");
|
||||
break;
|
||||
|
||||
case SSL_HND_FINISHED:
|
||||
|
@ -1798,7 +1760,7 @@ dissect_dtls_hnd_hello_ext(tvbuff_t *tvb,
|
|||
}
|
||||
|
||||
static void
|
||||
dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
|
||||
dissect_dtls_hnd_cli_hello(tvbuff_t *tvb, packet_info *pinfo,
|
||||
proto_tree *tree, guint32 offset, guint32 length,
|
||||
SslDecryptSession*ssl)
|
||||
{
|
||||
|
@ -1822,6 +1784,11 @@ dissect_dtls_hnd_cli_hello(tvbuff_t *tvb,
|
|||
guint16 start_offset = offset;
|
||||
guint8 cookie_length;
|
||||
|
||||
if (ssl) {
|
||||
ssl_set_server(ssl, &pinfo->dst, pinfo->ptype, pinfo->destport);
|
||||
ssl_find_private_key(ssl, dtls_key_hash, dtls_associations, pinfo);
|
||||
}
|
||||
|
||||
if (tree || ssl)
|
||||
{
|
||||
/* show the client version */
|
||||
|
@ -3527,6 +3494,9 @@ proto_register_dtls(void)
|
|||
"Used by versions of Wireshark prior to 1.6",
|
||||
&dtls_keys_list);
|
||||
|
||||
prefs_register_string_preference(dtls_module, "psk", "Pre-Shared-Key",
|
||||
"Pre-Shared-Key as HEX string, should be 0 to 16 bytes",
|
||||
&dtls_psk);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* ssl manipulation functions
|
||||
* By Paolo Abeni <paolo.abeni@email.com>
|
||||
*
|
||||
* Copyright (c) 2013, Hauke Mehrtens <hauke@hauke-m.de>
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
|
@ -1513,7 +1515,7 @@ static gint
|
|||
ssl_cipher_init(gcry_cipher_hd_t *cipher, gint algo, guchar* sk,
|
||||
guchar* iv, gint mode)
|
||||
{
|
||||
gint gcry_modes[]={GCRY_CIPHER_MODE_STREAM,GCRY_CIPHER_MODE_CBC,GCRY_CIPHER_MODE_CTR};
|
||||
gint gcry_modes[]={GCRY_CIPHER_MODE_STREAM,GCRY_CIPHER_MODE_CBC,GCRY_CIPHER_MODE_CTR,GCRY_CIPHER_MODE_CTR,GCRY_CIPHER_MODE_CTR};
|
||||
gint err;
|
||||
if (algo == -1) {
|
||||
/* NULL mode */
|
||||
|
@ -1753,6 +1755,7 @@ static const SslDigestAlgo digests[]={
|
|||
{"SHA1", 20},
|
||||
{"SHA256", 32},
|
||||
{"SHA384", 48},
|
||||
{"Not Applicable", 0},
|
||||
};
|
||||
|
||||
/* get index digest index */
|
||||
|
@ -1921,6 +1924,18 @@ static SslCipherSuite cipher_suites[]={
|
|||
{49200,KEX_DH,SIG_RSA,ENC_AES256,4,256,256,DIG_SHA384, SSL_CIPHER_MODE_GCM}, /* TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 */
|
||||
{49201,KEX_DH,SIG_RSA,ENC_AES,4,128,128,DIG_SHA256, SSL_CIPHER_MODE_GCM}, /* TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 */
|
||||
{49202,KEX_DH,SIG_RSA,ENC_AES256,4,256,256,DIG_SHA384, SSL_CIPHER_MODE_GCM}, /* TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 */
|
||||
{0xC09C,KEX_RSA,SIG_RSA,ENC_AES,4,128,128,DIG_NA, SSL_CIPHER_MODE_CCM}, /* TLS_RSA_WITH_AES_128_CCM */
|
||||
{0xC09D,KEX_RSA,SIG_RSA,ENC_AES256,4,256,256,DIG_NA, SSL_CIPHER_MODE_CCM}, /* TLS_RSA_WITH_AES_256_CCM */
|
||||
{0xC09E,KEX_DH,SIG_RSA,ENC_AES,4,128,128,DIG_NA, SSL_CIPHER_MODE_CCM}, /* TLS_DHE_RSA_WITH_AES_128_CCM */
|
||||
{0xC09F,KEX_DH,SIG_RSA,ENC_AES256,4,256,256,DIG_NA, SSL_CIPHER_MODE_CCM}, /* TLS_DHE_RSA_WITH_AES_256_CCM */
|
||||
{0xC0A0,KEX_RSA,SIG_RSA,ENC_AES,4,128,128,DIG_NA, SSL_CIPHER_MODE_CCM_8}, /* TLS_RSA_WITH_AES_128_CCM_8 */
|
||||
{0xC0A1,KEX_RSA,SIG_RSA,ENC_AES256,4,256,256,DIG_NA, SSL_CIPHER_MODE_CCM_8}, /* TLS_RSA_WITH_AES_256_CCM_8 */
|
||||
{0xC0A2,KEX_DH,SIG_RSA,ENC_AES,4,128,128,DIG_NA, SSL_CIPHER_MODE_CCM_8}, /* TLS_DHE_RSA_WITH_AES_128_CCM_8 */
|
||||
{0xC0A3,KEX_DH,SIG_RSA,ENC_AES256,4,256,256,DIG_NA, SSL_CIPHER_MODE_CCM_8}, /* TLS_DHE_RSA_WITH_AES_256_CCM_8 */
|
||||
{0xC0A4,KEX_PSK,SIG_NONE,ENC_AES,4,128,128,DIG_NA, SSL_CIPHER_MODE_CCM}, /* TLS_PSK_WITH_AES_128_CCM */
|
||||
{0xC0A5,KEX_PSK,SIG_NONE,ENC_AES256,4,256,256,DIG_NA, SSL_CIPHER_MODE_CCM}, /* TLS_PSK_WITH_AES_256_CCM */
|
||||
{0xC0A8,KEX_PSK,SIG_NONE,ENC_AES,4,128,128,DIG_NA, SSL_CIPHER_MODE_CCM_8}, /* TLS_PSK_WITH_AES_128_CCM_8 */
|
||||
{0xC0A9,KEX_PSK,SIG_NONE,ENC_AES256,4,256,256,DIG_NA, SSL_CIPHER_MODE_CCM_8}, /* TLS_PSK_WITH_AES_256_CCM_8 */
|
||||
{-1, 0,0,0,0,0,0,0, 0}
|
||||
};
|
||||
|
||||
|
@ -2286,6 +2301,135 @@ ssl_create_decoder(SslCipherSuite *cipher_suite, gint compression,
|
|||
return dec;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_generate_pre_master_secret(SslDecryptSession *ssl_session,
|
||||
guint32 length, tvbuff_t *tvb, guint32 offset,
|
||||
const gchar *ssl_psk, const gchar *keylog_filename)
|
||||
{
|
||||
/* check for required session data */
|
||||
ssl_debug_printf("ssl_generate_pre_master_secret: found SSL_HND_CLIENT_KEY_EXCHG, state %X\n",
|
||||
ssl_session->state);
|
||||
if ((ssl_session->state & (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) !=
|
||||
(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) {
|
||||
ssl_debug_printf("ssl_generate_pre_master_secret: not enough data to generate key (required state %X)\n",
|
||||
(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssl_session->cipher_suite.kex == KEX_PSK)
|
||||
{
|
||||
/* calculate pre master secret*/
|
||||
StringInfo pre_master_secret;
|
||||
guint psk_len, pre_master_len;
|
||||
|
||||
int size;
|
||||
unsigned char *out;
|
||||
int i,j = 0;
|
||||
char input[2];
|
||||
|
||||
if (!ssl_psk || (ssl_psk[0] == 0)) {
|
||||
ssl_debug_printf("ssl_generate_pre_master_secret: can't find pre-shared-key\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = (int)strlen(ssl_psk);
|
||||
|
||||
/* The length of PSK ranges from 0..2^16-1 octets (times two for hex string) */
|
||||
if (size < 0 || size % 2 != 0 || size >= (2 << 16))
|
||||
{
|
||||
ssl_debug_printf("ssl_generate_pre_master_secret: length of ssl.psk must be multiple of two");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* convert hex string into char*/
|
||||
out = (unsigned char*) wmem_alloc(wmem_packet_scope(), size / 2);
|
||||
|
||||
for (i = 0; i < size; i+=2)
|
||||
{
|
||||
input[0] = ssl_psk[0 + i];
|
||||
input[1] = ssl_psk[1 + i];
|
||||
out[j++] = (unsigned int) strtoul((const char*)&input, NULL, 16);
|
||||
}
|
||||
|
||||
ssl_session->psk = (guchar*) out;
|
||||
|
||||
psk_len = size / 2;
|
||||
pre_master_len = psk_len * 2 + 4;
|
||||
|
||||
pre_master_secret.data = (guchar *)wmem_alloc(wmem_file_scope(), pre_master_len);
|
||||
pre_master_secret.data_len = pre_master_len;
|
||||
/* 2 bytes psk_len*/
|
||||
pre_master_secret.data[0] = psk_len >> 8;
|
||||
pre_master_secret.data[1] = psk_len & 0xFF;
|
||||
/* psk_len bytes times 0*/
|
||||
memset(&pre_master_secret.data[2], 0, psk_len);
|
||||
/* 2 bytes psk_len*/
|
||||
pre_master_secret.data[psk_len + 2] = psk_len >> 8;
|
||||
pre_master_secret.data[psk_len + 3] = psk_len & 0xFF;
|
||||
/* psk*/
|
||||
memcpy(&pre_master_secret.data[psk_len + 4], ssl_session->psk, psk_len);
|
||||
|
||||
ssl_session->pre_master_secret.data = pre_master_secret.data;
|
||||
ssl_session->pre_master_secret.data_len = pre_master_len;
|
||||
/*ssl_debug_printf("pre master secret",&ssl->pre_master_secret);*/
|
||||
|
||||
/* Remove the master secret if it was there.
|
||||
This forces keying material regeneration in
|
||||
case we're renegotiating */
|
||||
ssl_session->state &= ~(SSL_MASTER_SECRET|SSL_HAVE_SESSION_KEY);
|
||||
ssl_session->state |= SSL_PRE_MASTER_SECRET;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
StringInfo encrypted_pre_master;
|
||||
gint ret;
|
||||
guint encrlen, skip;
|
||||
encrlen = length;
|
||||
skip = 0;
|
||||
|
||||
/* get encrypted data, on tls1 we have to skip two bytes
|
||||
* (it's the encrypted len and should be equal to record len - 2)
|
||||
* in case of rsa1024 that would be 128 + 2 = 130; for psk not necessary
|
||||
*/
|
||||
if (ssl_session->cipher_suite.kex == KEX_RSA &&
|
||||
(ssl_session->version == SSL_VER_TLS || ssl_session->version == SSL_VER_TLSv1DOT1 ||
|
||||
ssl_session->version == SSL_VER_TLSv1DOT2 || ssl_session->version == SSL_VER_DTLS ||
|
||||
ssl_session->version == SSL_VER_DTLS1DOT2))
|
||||
{
|
||||
encrlen = tvb_get_ntohs(tvb, offset);
|
||||
skip = 2;
|
||||
if (encrlen > length - 2)
|
||||
{
|
||||
ssl_debug_printf("ssl_generate_pre_master_secret: wrong encrypted length (%d max %d)\n",
|
||||
encrlen, length);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
encrypted_pre_master.data = (guchar *)wmem_alloc(wmem_file_scope(), encrlen);
|
||||
encrypted_pre_master.data_len = encrlen;
|
||||
tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen);
|
||||
|
||||
if (ssl_session->private_key) {
|
||||
/* go with ssl key processessing; encrypted_pre_master
|
||||
* will be used for master secret store*/
|
||||
ret = ssl_decrypt_pre_master_secret(ssl_session, &encrypted_pre_master, ssl_session->private_key);
|
||||
if (ret < 0) {
|
||||
ssl_debug_printf("ssl_generate_pre_master_secret: can't decrypt pre master secret\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else if (keylog_filename != NULL) {
|
||||
/* try to find the key in the key log */
|
||||
if (ssl_keylog_lookup(ssl_session, keylog_filename, &encrypted_pre_master) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_generate_keyring_material(SslDecryptSession*ssl_session)
|
||||
{
|
||||
|
@ -2343,7 +2487,9 @@ ssl_generate_keyring_material(SslDecryptSession*ssl_session)
|
|||
|
||||
ptr=key_block.data;
|
||||
/* AEAD ciphers do not have a separate MAC */
|
||||
if (ssl_session->cipher_suite.mode == SSL_CIPHER_MODE_GCM) {
|
||||
if (ssl_session->cipher_suite.mode == SSL_CIPHER_MODE_GCM ||
|
||||
ssl_session->cipher_suite.mode == SSL_CIPHER_MODE_CCM ||
|
||||
ssl_session->cipher_suite.mode == SSL_CIPHER_MODE_CCM_8) {
|
||||
c_mk = s_mk = NULL;
|
||||
} else {
|
||||
c_mk=ptr; ptr+=ssl_cipher_suite_dig(&ssl_session->cipher_suite)->len;
|
||||
|
@ -2844,7 +2990,9 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct,
|
|||
}
|
||||
|
||||
/* Nonce for GenericAEADCipher */
|
||||
if (decoder->cipher_suite->mode == SSL_CIPHER_MODE_GCM) {
|
||||
if (decoder->cipher_suite->mode == SSL_CIPHER_MODE_GCM ||
|
||||
decoder->cipher_suite->mode == SSL_CIPHER_MODE_CCM ||
|
||||
decoder->cipher_suite->mode == SSL_CIPHER_MODE_CCM_8) {
|
||||
/* 4 bytes write_iv, 8 bytes explicit_nonce, 4 bytes counter */
|
||||
guchar gcm_nonce[16] = { 0 };
|
||||
|
||||
|
@ -2853,11 +3001,25 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct,
|
|||
inl, SSL_EX_NONCE_LEN_GCM);
|
||||
return -1;
|
||||
}
|
||||
memcpy(gcm_nonce, decoder->write_iv.data, decoder->write_iv.data_len); /* salt */
|
||||
memcpy(gcm_nonce + decoder->write_iv.data_len, in, SSL_EX_NONCE_LEN_GCM);
|
||||
/* NIST SP 800-38D, sect. 7.2 says that the 32-bit counter part starts
|
||||
* at 1, and gets incremented before passing to the block cipher. */
|
||||
gcm_nonce[4 + SSL_EX_NONCE_LEN_GCM + 3] = 2;
|
||||
|
||||
if (decoder->cipher_suite->mode == SSL_CIPHER_MODE_GCM) {
|
||||
memcpy(gcm_nonce, decoder->write_iv.data, decoder->write_iv.data_len); /* salt */
|
||||
memcpy(gcm_nonce + decoder->write_iv.data_len, in, SSL_EX_NONCE_LEN_GCM);
|
||||
/* NIST SP 800-38D, sect. 7.2 says that the 32-bit counter part starts
|
||||
* at 1, and gets incremented before passing to the block cipher. */
|
||||
gcm_nonce[4 + SSL_EX_NONCE_LEN_GCM + 3] = 2;
|
||||
} else { /* SSL_CIPHER_MODE_CCM and SSL_CIPHER_MODE_CCM_8 */
|
||||
/* The nonce for CCM and GCM are the same, but the nonce is used as input
|
||||
* in the CCM algorithm described in RFC 3610. The nonce generated here is
|
||||
* the one from RFC 3610 sect 2.3. Encryption. */
|
||||
/* Flags: (L-1) ; L = 16 - 1 - nonceSize */
|
||||
gcm_nonce[0] = 3 - 1;
|
||||
|
||||
memcpy(gcm_nonce + 1, decoder->write_iv.data, decoder->write_iv.data_len); /* salt */
|
||||
memcpy(gcm_nonce + 1 + decoder->write_iv.data_len, in, SSL_EX_NONCE_LEN_GCM);
|
||||
gcm_nonce[4 + SSL_EX_NONCE_LEN_GCM + 3] = 1;
|
||||
}
|
||||
|
||||
pad = gcry_cipher_setctr (decoder->evp, gcm_nonce, sizeof (gcm_nonce));
|
||||
if (pad != 0) {
|
||||
ssl_debug_printf("ssl_decrypt_record failed: failed to set CTR: %s %s\n",
|
||||
|
@ -2878,8 +3040,10 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct,
|
|||
ssl_print_data("Plaintext", out_str->data, inl);
|
||||
worklen=inl;
|
||||
|
||||
/* RFC 5116 sect 5.1/5.3: AES128/256 GCM/CCM uses 16 bytes for auth tag */
|
||||
if (decoder->cipher_suite->mode == SSL_CIPHER_MODE_GCM) {
|
||||
/* RFC 5116 sect 5.1/5.3: AES128/256 GCM/CCM uses 16 bytes for auth tag
|
||||
* RFC 6655 sect 6.1: AEAD_AES_128_CCM uses 16 bytes for auth tag */
|
||||
if (decoder->cipher_suite->mode == SSL_CIPHER_MODE_GCM ||
|
||||
decoder->cipher_suite->mode == SSL_CIPHER_MODE_CCM) {
|
||||
if (worklen < 16) {
|
||||
ssl_debug_printf("ssl_decrypt_record failed: missing tag, work %d\n", worklen);
|
||||
return -1;
|
||||
|
@ -2887,6 +3051,15 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct,
|
|||
/* XXX - validate auth tag */
|
||||
worklen -= 16;
|
||||
}
|
||||
/* RFC 6655 sect 6.1: AEAD_AES_128_CCM_8 uses 8 bytes for auth tag */
|
||||
if (decoder->cipher_suite->mode == SSL_CIPHER_MODE_CCM_8) {
|
||||
if (worklen < 8) {
|
||||
ssl_debug_printf("ssl_decrypt_record failed: missing tag, work %d\n", worklen);
|
||||
return -1;
|
||||
}
|
||||
/* XXX - validate auth tag */
|
||||
worklen -= 8;
|
||||
}
|
||||
|
||||
/* strip padding for GenericBlockCipher */
|
||||
if (decoder->cipher_suite->mode == SSL_CIPHER_MODE_CBC) {
|
||||
|
|
|
@ -233,6 +233,8 @@ typedef struct _StringInfo {
|
|||
#define SSL_CIPHER_MODE_STREAM 0 /* GenericStreamCipher */
|
||||
#define SSL_CIPHER_MODE_CBC 1 /* GenericBlockCipher */
|
||||
#define SSL_CIPHER_MODE_GCM 2 /* GenericAEADCipher */
|
||||
#define SSL_CIPHER_MODE_CCM 3 /* AEAD_AES_{128,256}_CCM with 16 byte auth tag */
|
||||
#define SSL_CIPHER_MODE_CCM_8 4 /* AEAD_AES_{128,256}_CCM with 8 byte auth tag */
|
||||
|
||||
/* Explicit nonce length */
|
||||
#define SSL_EX_NONCE_LEN_GCM 8 /* RFC 5288 - section 3 */
|
||||
|
@ -300,6 +302,7 @@ typedef struct _SslDecoder {
|
|||
#define DIG_SHA 0x41
|
||||
#define DIG_SHA256 0x42
|
||||
#define DIG_SHA384 0x43
|
||||
#define DIG_NA 0x44 /* Not Applicable */
|
||||
|
||||
typedef struct {
|
||||
const gchar *name;
|
||||
|
@ -447,6 +450,11 @@ ssl_find_private_key(SslDecryptSession *ssl_session, GHashTable *key_hash, GTree
|
|||
extern gint
|
||||
ssl_find_cipher(int num,SslCipherSuite* cs);
|
||||
|
||||
int
|
||||
ssl_generate_pre_master_secret(SslDecryptSession *ssl_session,
|
||||
guint32 length, tvbuff_t *tvb, guint32 offset,
|
||||
const gchar *ssl_psk, const gchar *keylog_filename);
|
||||
|
||||
/** Expand the pre_master_secret to generate all the session information
|
||||
* (master secret, session keys, ivs)
|
||||
@param ssl_session the store for all the session data
|
||||
|
|
|
@ -2161,128 +2161,23 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
{
|
||||
/* PAOLO: here we can have all the data to build session key*/
|
||||
/* PAOLO: here we can have all the data to build session key*/
|
||||
|
||||
gint cipher_num;
|
||||
if (!ssl)
|
||||
break;
|
||||
|
||||
if (!ssl)
|
||||
break;
|
||||
|
||||
cipher_num = ssl->cipher;
|
||||
|
||||
if (cipher_num == 0x8a || cipher_num == 0x8b || cipher_num == 0x8c || cipher_num == 0x8d)
|
||||
{
|
||||
/* calculate pre master secret*/
|
||||
StringInfo pre_master_secret;
|
||||
guint psk_len, pre_master_len;
|
||||
|
||||
int size;
|
||||
unsigned char *out;
|
||||
int i,j = 0;
|
||||
char input[2];
|
||||
|
||||
if (!ssl_psk || (ssl_psk[0] == 0)) {
|
||||
ssl_debug_printf("dissect_ssl3_handshake can't find pre-shared-key\n");
|
||||
break;
|
||||
}
|
||||
|
||||
size = (int)strlen(ssl_psk);
|
||||
|
||||
/* The length of PSK ranges from 0..2^16-1 octets (times two for hex string) */
|
||||
if (size < 0 || size % 2 != 0 || size >= (2 << 16))
|
||||
{
|
||||
ssl_debug_printf("dissect_ssl3_handshake: length of ssl.psk must be multiple of two");
|
||||
break;
|
||||
}
|
||||
|
||||
/* convert hex string into char*/
|
||||
out = (unsigned char*) wmem_alloc(wmem_packet_scope(), size / 2);
|
||||
|
||||
for (i = 0; i < size; i+=2)
|
||||
{
|
||||
input[0] = ssl_psk[0 + i];
|
||||
input[1] = ssl_psk[1 + i];
|
||||
out[j++] = (unsigned int) strtoul((const char*)&input, NULL, 16);
|
||||
}
|
||||
|
||||
ssl->psk = (guchar*) out;
|
||||
|
||||
psk_len = size / 2;
|
||||
pre_master_len = psk_len * 2 + 4;
|
||||
|
||||
pre_master_secret.data = (guchar *)wmem_alloc(wmem_file_scope(), pre_master_len);
|
||||
pre_master_secret.data_len = pre_master_len;
|
||||
/* 2 bytes psk_len*/
|
||||
pre_master_secret.data[0] = psk_len >> 8;
|
||||
pre_master_secret.data[1] = psk_len & 0xFF;
|
||||
/* psk_len bytes times 0*/
|
||||
memset(&pre_master_secret.data[2], 0, psk_len);
|
||||
/* 2 bytes psk_len*/
|
||||
pre_master_secret.data[psk_len + 2] = psk_len >> 8;
|
||||
pre_master_secret.data[psk_len + 3] = psk_len & 0xFF;
|
||||
/* psk*/
|
||||
memcpy(&pre_master_secret.data[psk_len + 4], ssl->psk, psk_len);
|
||||
|
||||
ssl->pre_master_secret.data = pre_master_secret.data;
|
||||
ssl->pre_master_secret.data_len = pre_master_len;
|
||||
/*ssl_debug_printf("pre master secret",&ssl->pre_master_secret);*/
|
||||
|
||||
/* Remove the master secret if it was there.
|
||||
This forces keying material regeneration in
|
||||
case we're renegotiating */
|
||||
ssl->state &= ~(SSL_MASTER_SECRET|SSL_HAVE_SESSION_KEY);
|
||||
ssl->state |= SSL_PRE_MASTER_SECRET;
|
||||
}
|
||||
else
|
||||
{
|
||||
StringInfo encrypted_pre_master;
|
||||
gint ret;
|
||||
guint encrlen, skip;
|
||||
encrlen = length;
|
||||
skip = 0;
|
||||
|
||||
/* get encrypted data, on tls1 we have to skip two bytes
|
||||
* (it's the encrypted len and should be equal to record len - 2)
|
||||
* in case of rsa1024 that would be 128 + 2 = 130; for psk not necessary
|
||||
*/
|
||||
if (ssl->cipher_suite.kex==KEX_RSA && (ssl->version == SSL_VER_TLS||ssl->version == SSL_VER_TLSv1DOT1||ssl->version == SSL_VER_TLSv1DOT2))
|
||||
{
|
||||
encrlen = tvb_get_ntohs(tvb, offset);
|
||||
skip = 2;
|
||||
if (encrlen > length - 2)
|
||||
{
|
||||
ssl_debug_printf("dissect_ssl3_handshake wrong encrypted length (%d max %d)\n",
|
||||
encrlen, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
encrypted_pre_master.data = (guchar *)wmem_alloc(wmem_file_scope(), encrlen);
|
||||
encrypted_pre_master.data_len = encrlen;
|
||||
tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen);
|
||||
|
||||
if (ssl->private_key) {
|
||||
/* go with ssl key processessing; encrypted_pre_master
|
||||
* will be used for master secret store*/
|
||||
ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl->private_key);
|
||||
if (ret < 0) {
|
||||
ssl_debug_printf("dissect_ssl3_handshake can't decrypt pre master secret\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* try to find the key in the key log */
|
||||
if (ssl_keylog_lookup(ssl, ssl_keylog_filename, &encrypted_pre_master)<0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ssl_generate_keyring_material(ssl)<0) {
|
||||
ssl_debug_printf("dissect_ssl3_handshake can't generate keyring material\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ssl_save_session(ssl, ssl_session_hash);
|
||||
ssl_debug_printf("dissect_ssl3_handshake session keys successfully generated\n");
|
||||
if (ssl_generate_pre_master_secret(ssl, length, tvb, offset, ssl_psk, ssl_keylog_filename) < 0) {
|
||||
ssl_debug_printf("dissect_ssl3_handshake can't generate pre master secret\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (ssl_generate_keyring_material(ssl) < 0) {
|
||||
ssl_debug_printf("dissect_ssl3_handshake can't generate keyring material\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ssl_save_session(ssl, ssl_session_hash);
|
||||
ssl_debug_printf("dissect_ssl3_handshake session keys successfully generated\n");
|
||||
break;
|
||||
|
||||
case SSL_HND_FINISHED:
|
||||
|
|
Loading…
Reference in New Issue