aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ssl-utils.c
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2013-12-08 00:58:06 +0000
committerMichael Mann <mmann78@netscape.net>2013-12-08 00:58:06 +0000
commit0f05597ab17ea7fc5161458c670f56a523cb9c42 (patch)
tree8c2b74875e140f8e0996ef530421136e1456a85d /epan/dissectors/packet-ssl-utils.c
parent7d10a416a355567c3c3a61c64d53bc23fcd21ffb (diff)
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
Diffstat (limited to 'epan/dissectors/packet-ssl-utils.c')
-rw-r--r--epan/dissectors/packet-ssl-utils.c193
1 files changed, 183 insertions, 10 deletions
diff --git a/epan/dissectors/packet-ssl-utils.c b/epan/dissectors/packet-ssl-utils.c
index 50d1e0fefb..9383416bbc 100644
--- a/epan/dissectors/packet-ssl-utils.c
+++ b/epan/dissectors/packet-ssl-utils.c
@@ -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}
};
@@ -2287,6 +2302,135 @@ ssl_create_decoder(SslCipherSuite *cipher_suite, gint compression,
}
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)
{
StringInfo key_block;
@@ -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) {