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