1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
/*
* Copyright (C) 2000-2013 Free Software Foundation, Inc.
* Copyright (C) 2013 Nikos Mavrogiannopoulos
* Copyright (C) 2017-2018 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GnuTLS.
*
* The GnuTLS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>
*
*/
#include "gnutls_int.h"
#include "cipher.h"
static void dummy_wait(record_parameters_st *params, const uint8_t *data,
size_t data_size, unsigned int mac_data,
unsigned int max_mac_data)
{
/* this hack is only needed on CBC ciphers when Encrypt-then-MAC mode
* is not supported by the peer. */
unsigned v;
unsigned int tag_size =
_gnutls_auth_cipher_tag_len(¶ms->read.ctx.tls12);
unsigned hash_block = _gnutls_mac_block_size(params->mac);
/* force additional hash compression function evaluations to prevent timing
* attacks that distinguish between wrong-mac + correct pad, from wrong-mac + incorrect pad.
*/
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 < data_size) {
_gnutls_auth_cipher_add_auth(
¶ms->read.ctx.tls12,
data + data_size - tag_size - to_hash - 1,
to_hash);
}
}
}
/* Verifies the CBC HMAC. That's a special case as it tries to avoid
* any leaks which could make CBC ciphersuites without EtM usable as an
* oracle to attacks.
*/
int cbc_mac_verify(gnutls_session_t session, record_parameters_st *params,
uint8_t preamble[MAX_PREAMBLE_SIZE], content_type_t type,
uint64_t sequence, const uint8_t *data, size_t data_size,
size_t tag_size)
{
int ret;
const version_entry_st *ver = get_version(session);
unsigned int tmp_pad_failed = 0;
unsigned int pad_failed = 0;
unsigned int pad, i, length;
const uint8_t *tag_ptr = NULL;
unsigned preamble_size;
uint8_t tag[MAX_HASH_SIZE];
#ifdef ENABLE_SSL3
unsigned blocksize = _gnutls_cipher_get_block_size(params->cipher);
#endif
pad = data[data_size - 1]; /* pad */
/* Check the padding 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).
*/
#ifdef ENABLE_SSL3
if (ver->id == GNUTLS_SSL3) {
if (pad >= blocksize)
pad_failed = 1;
} else
#endif
{
for (i = 2; i <= MIN(256, data_size); i++) {
tmp_pad_failed |= (data[data_size - i] != pad);
pad_failed |= ((i <= (1 + pad)) & (tmp_pad_failed));
}
}
if (unlikely(pad_failed != 0 ||
(1 + pad > ((int)data_size - tag_size)))) {
/* We do not fail here. We check below for the
* the pad_failed. If zero means success.
*/
pad_failed = 1;
pad = 0;
}
length = data_size - tag_size - pad - 1;
tag_ptr = &data[length];
/* Pass the type, version, length and plain through
* MAC.
*/
preamble_size =
_gnutls_make_preamble(sequence, type, length, ver, preamble);
ret = _gnutls_auth_cipher_add_auth(¶ms->read.ctx.tls12, preamble,
preamble_size);
if (unlikely(ret < 0))
return gnutls_assert_val(ret);
ret = _gnutls_auth_cipher_add_auth(¶ms->read.ctx.tls12, data,
length);
if (unlikely(ret < 0))
return gnutls_assert_val(ret);
ret = _gnutls_auth_cipher_tag(¶ms->read.ctx.tls12, tag, tag_size);
if (unlikely(ret < 0))
return gnutls_assert_val(ret);
if (unlikely(gnutls_memcmp(tag, tag_ptr, tag_size) != 0 ||
pad_failed != 0)) {
/* HMAC was not the same. */
dummy_wait(params, data, data_size, length + preamble_size,
preamble_size + data_size - tag_size - 1);
return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
}
return length;
}
|