diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c index 37478a4c3..65dde6899 100644 --- a/lib/gnutls_cipher.c +++ b/lib/gnutls_cipher.c @@ -434,40 +434,41 @@ compressed_to_ciphertext(gnutls_session_t session, return length; } -static void dummy_wait(record_parameters_st * params, - gnutls_datum_t * plaintext, unsigned pad_failed, - unsigned int pad, unsigned total) +static void dummy_wait(record_parameters_st *params, + gnutls_datum_t *plaintext, + unsigned int mac_data, unsigned int max_mac_data) { /* this hack is only needed on CBC ciphers */ if (_gnutls_cipher_is_block(params->cipher) == CIPHER_BLOCK) { - unsigned len, v; + unsigned v; + unsigned int tag_size = + _gnutls_auth_cipher_tag_len(¶ms->read.cipher_state); + unsigned hash_block = _gnutls_mac_block_size(params->mac); - /* force an additional hash compression function evaluation to prevent timing + /* force additional hash compression function evaluations to prevent timing * attacks that distinguish between wrong-mac + correct pad, from wrong-mac + incorrect pad. */ - if (pad_failed == 0 && pad > 0) { - len = _gnutls_mac_block_size(params->mac); - if (len > 0) { - if (params->mac && params->mac->id == GNUTLS_MAC_SHA384) - /* v = 1 for the hash function padding + 16 for message length */ - v = 17; - else /* v = 1 for the hash function padding + 8 for message length */ - v = 9; - - if ((pad + total) % len > len - v - && total % len <= len - v) { - if (len < plaintext->size) - _gnutls_auth_cipher_add_auth - (¶ms->read. - cipher_state, - plaintext->data, len); - else - _gnutls_auth_cipher_add_auth - (¶ms->read. - cipher_state, - plaintext->data, - plaintext->size); - } + if (params->mac && params->mac->id == GNUTLS_MAC_SHA384) + /* v = 1 for the hash function padding + 16 for message length */ + v = 17; + else /* v = 1 for the hash function padding + 8 for message length */ + v = 9; + + if (hash_block > 0) { + int max_blocks = (max_mac_data+v+hash_block-1)/hash_block; + int hashed_blocks = (mac_data+v+hash_block-1)/hash_block; + unsigned to_hash; + + max_blocks -= hashed_blocks; + if (max_blocks < 1) + return; + + to_hash = max_blocks * hash_block; + if ((unsigned)to_hash+1+tag_size < plaintext->size) { + _gnutls_auth_cipher_add_auth + (¶ms->read.cipher_state, + plaintext->data+plaintext->size-tag_size-to_hash-1, + to_hash); } } } @@ -725,8 +726,10 @@ ciphertext_to_compressed(gnutls_session_t session, if (unlikely (memcmp(tag, tag_ptr, tag_size) != 0 || pad_failed != 0)) { /* HMAC was not the same. */ - dummy_wait(params, compressed, pad_failed, pad, - length + preamble_size); + gnutls_datum_t data = {compressed->data, ciphertext->size}; + + dummy_wait(params, &data, length + preamble_size, + preamble_size + ciphertext->size - tag_size - 1); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } -- 2.14.3