diff options
Diffstat (limited to 'patches/source/gnutls/gnutls-2.10.5_CVE-2013-1619_CVE-2013-2116.diff')
-rw-r--r-- | patches/source/gnutls/gnutls-2.10.5_CVE-2013-1619_CVE-2013-2116.diff | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/patches/source/gnutls/gnutls-2.10.5_CVE-2013-1619_CVE-2013-2116.diff b/patches/source/gnutls/gnutls-2.10.5_CVE-2013-1619_CVE-2013-2116.diff new file mode 100644 index 000000000..6ec41e099 --- /dev/null +++ b/patches/source/gnutls/gnutls-2.10.5_CVE-2013-1619_CVE-2013-2116.diff @@ -0,0 +1,186 @@ +From 6c4c4baca8e4d3311501b2c8c2d32a0ccbe881ad Mon Sep 17 00:00:00 2001 +From: mancha <mancha1@hush.com> +Date: Sun, 29 Sep 2013 +Subject: CVE-2013-1619 and CVE-2013-2116 [GNUTLS-SA-2013-1,GNUTLS-SA-2013-2] + +Fix to avoid a timing attack in TLS CBC record parsing (aka Lucky 13). + +For background, see http://www.isg.rhul.ac.uk/tls/Lucky13.html + +The fix for CVE-2013-2116 is folded into this patch since it addresses +a problem introduced by the fix for CVE-2013-1619. + +This is a backport adaptation for use with GnuTLS 2.10.5. + +Relevant upstream commits: +-------------------------- +https://gitorious.org/gnutls/gnutls/commit/458c67cf98740e +https://gitorious.org/gnutls/gnutls/commit/93b7fcfa3297a9 + +--- + lib/gnutls_hash_int.h | 21 +++++++++++ + lib/gnutls_cipher.c | 90 ++++++++++++++++++++++++++++++++---------------- + 2 files changed, 81 insertions(+), 30 deletions(-) + +--- a/lib/gnutls_cipher.c ++++ b/lib/gnutls_cipher.c +@@ -447,6 +447,49 @@ _gnutls_compressed2ciphertext (gnutls_se + return length; + } + ++static void dummy_wait(gnutls_session_t session, gnutls_datum_t* plaintext, ++ unsigned pad_failed, unsigned int pad, unsigned total, int ver) ++{ ++ /* this hack is only needed on CBC ciphers */ ++ if (_gnutls_cipher_is_block (session->security_parameters.read_bulk_cipher_algorithm) == CIPHER_BLOCK) ++ { ++ uint8_t MAC[MAX_HASH_SIZE]; ++ unsigned len; ++ digest_hd_st td; ++ int ret; ++ ++ ret = mac_init (&td, session->security_parameters.read_mac_algorithm, ++ session->connection_state.read_mac_secret.data, ++ session->connection_state.read_mac_secret.size, ver); ++ ++ if (ret < 0) ++ return; ++ ++ /* force an additional hash compression function evaluation to prevent timing ++ * attacks that distinguish between wrong-mac + correct pad, from wrong-mac + incorrect pad. ++ */ ++ if (pad_failed == 0 && pad > 0) ++ { ++ len = _gnutls_get_hash_block_len(session->security_parameters.read_mac_algorithm); ++ if (len > 0) ++ { ++ /* This is really specific to the current hash functions. ++ * It should be removed once a protocol fix is in place. ++ */ ++ if ((pad+total) % len > len-9 && total % len <= len-9) ++ { ++ if (len < plaintext->size) ++ mac_hash (&td, plaintext->data, len, ver); ++ else ++ mac_hash (&td, plaintext->data, plaintext->size, ver); ++ } ++ } ++ } ++ ++ mac_deinit (&td, MAC, ver); ++ } ++} ++ + /* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size. + * Returns the actual compressed packet size. + */ +@@ -458,12 +501,12 @@ _gnutls_ciphertext2compressed (gnutls_se + { + uint8_t MAC[MAX_HASH_SIZE]; + uint16_t c_length; +- uint8_t pad; ++ unsigned int pad = 0; + int length; + uint16_t blocksize; + int ret, i, pad_failed = 0; + opaque preamble[PREAMBLE_SIZE]; +- int preamble_size; ++ int preamble_size = 0; + int ver = gnutls_protocol_get_version (session); + int hash_size = + _gnutls_hash_get_algo_len (session-> +@@ -522,31 +565,23 @@ _gnutls_ciphertext2compressed (gnutls_se + gnutls_assert (); + return GNUTLS_E_DECRYPTION_FAILED; + } +- pad = ciphertext.data[ciphertext.size - 1] + 1; /* pad */ ++ pad = ciphertext.data[ciphertext.size - 1]; /* pad */ + +- if ((int) pad > (int) ciphertext.size - hash_size) +- { +- gnutls_assert (); +- _gnutls_record_log +- ("REC[%p]: Short record length %d > %d - %d (under attack?)\n", +- session, pad, ciphertext.size, hash_size); +- /* We do not fail here. We check below for the +- * the pad_failed. If zero means success. +- */ +- pad_failed = GNUTLS_E_DECRYPTION_FAILED; +- } +- +- length = ciphertext.size - hash_size - pad; +- +- /* Check the pading bytes (TLS 1.x) ++ /* Check the pading bytes (TLS 1.x). ++ * Note that we access all 256 bytes of ciphertext for padding check ++ * because there is a timing channel in that memory access (in certain CPUs). + */ + if (_gnutls_version_has_variable_padding (ver) && pad_failed == 0) + for (i = 2; i < pad; i++) + { +- if (ciphertext.data[ciphertext.size - i] != +- ciphertext.data[ciphertext.size - 1]) ++ if (ciphertext.data[ciphertext.size - i] != pad) + pad_failed = GNUTLS_E_DECRYPTION_FAILED; + } ++ ++ if (pad_failed) ++ pad = 0; ++ length = ciphertext.size - hash_size - pad - 1; ++ + break; + default: + gnutls_assert (); +@@ -585,19 +620,14 @@ _gnutls_ciphertext2compressed (gnutls_se + mac_deinit (&td, MAC, ver); + } + +- /* This one was introduced to avoid a timing attack against the TLS +- * 1.0 protocol. +- */ +- if (pad_failed != 0) +- { +- gnutls_assert (); +- return pad_failed; +- } +- + /* HMAC was not the same. + */ +- if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0) ++ if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0 || pad_failed != 0) + { ++ gnutls_datum_t compressed = {compress_data, compress_size}; ++ /* HMAC was not the same. */ ++ dummy_wait(session, &compressed, pad_failed, pad, length+preamble_size, ver); ++ + gnutls_assert (); + return GNUTLS_E_DECRYPTION_FAILED; + } +--- a/lib/gnutls_hash_int.h ++++ b/lib/gnutls_hash_int.h +@@ -98,4 +98,25 @@ void _gnutls_mac_deinit_ssl3_handshake ( + + int _gnutls_hash_copy (digest_hd_st * dst_handle, digest_hd_st * src_handle); + ++/* We shouldn't need to know that, but a work-around in decoding ++ * TLS record padding requires that. ++ */ ++inline static size_t ++_gnutls_get_hash_block_len (gnutls_digest_algorithm_t algo) ++{ ++ switch (algo) ++ { ++ case GNUTLS_DIG_MD5: ++ case GNUTLS_DIG_SHA1: ++ case GNUTLS_DIG_RMD160: ++ case GNUTLS_DIG_SHA256: ++ case GNUTLS_DIG_SHA384: ++ case GNUTLS_DIG_SHA512: ++ case GNUTLS_DIG_SHA224: ++ return 64; ++ default: ++ return 0; ++ } ++} ++ + #endif /* GNUTLS_HASH_INT_H */ |