/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, const uint8_t *data, |
29 | | size_t data_size, unsigned int mac_data, |
30 | | 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], content_type_t type, |
76 | | uint64_t sequence, const uint8_t *data, size_t data_size, |
77 | | size_t tag_size) |
78 | 0 | { |
79 | 0 | int ret; |
80 | 0 | const version_entry_st *ver = get_version(session); |
81 | 0 | unsigned int tmp_pad_failed = 0; |
82 | 0 | unsigned int pad_failed = 0; |
83 | 0 | unsigned int pad, i, length; |
84 | 0 | const uint8_t *tag_ptr = NULL; |
85 | 0 | unsigned preamble_size; |
86 | 0 | uint8_t tag[MAX_HASH_SIZE]; |
87 | | #ifdef ENABLE_SSL3 |
88 | | unsigned blocksize = _gnutls_cipher_get_block_size(params->cipher); |
89 | | #endif |
90 | |
|
91 | 0 | pad = data[data_size - 1]; /* pad */ |
92 | | |
93 | | /* Check the padding bytes (TLS 1.x). |
94 | | * Note that we access all 256 bytes of ciphertext for padding check |
95 | | * because there is a timing channel in that memory access (in certain CPUs). |
96 | | */ |
97 | | #ifdef ENABLE_SSL3 |
98 | | if (ver->id == GNUTLS_SSL3) { |
99 | | if (pad >= blocksize) |
100 | | pad_failed = 1; |
101 | | } else |
102 | | #endif |
103 | 0 | { |
104 | 0 | for (i = 2; i <= MIN(256, data_size); i++) { |
105 | 0 | tmp_pad_failed |= (data[data_size - i] != pad); |
106 | 0 | pad_failed |= ((i <= (1 + pad)) & (tmp_pad_failed)); |
107 | 0 | } |
108 | 0 | } |
109 | |
|
110 | 0 | if (unlikely(pad_failed != 0 || |
111 | 0 | (1 + pad > ((int)data_size - tag_size)))) { |
112 | | /* We do not fail here. We check below for the |
113 | | * the pad_failed. If zero means success. |
114 | | */ |
115 | 0 | pad_failed = 1; |
116 | 0 | pad = 0; |
117 | 0 | } |
118 | |
|
119 | 0 | length = data_size - tag_size - pad - 1; |
120 | 0 | tag_ptr = &data[length]; |
121 | | |
122 | | /* Pass the type, version, length and plain through |
123 | | * MAC. |
124 | | */ |
125 | 0 | preamble_size = |
126 | 0 | _gnutls_make_preamble(sequence, type, length, ver, preamble); |
127 | |
|
128 | 0 | ret = _gnutls_auth_cipher_add_auth(¶ms->read.ctx.tls12, preamble, |
129 | 0 | preamble_size); |
130 | 0 | if (unlikely(ret < 0)) |
131 | 0 | return gnutls_assert_val(ret); |
132 | | |
133 | 0 | ret = _gnutls_auth_cipher_add_auth(¶ms->read.ctx.tls12, data, |
134 | 0 | length); |
135 | 0 | if (unlikely(ret < 0)) |
136 | 0 | return gnutls_assert_val(ret); |
137 | | |
138 | 0 | ret = _gnutls_auth_cipher_tag(¶ms->read.ctx.tls12, tag, tag_size); |
139 | 0 | if (unlikely(ret < 0)) |
140 | 0 | return gnutls_assert_val(ret); |
141 | | |
142 | 0 | if (unlikely(gnutls_memcmp(tag, tag_ptr, tag_size) != 0 || |
143 | 0 | pad_failed != 0)) { |
144 | | /* HMAC was not the same. */ |
145 | 0 | dummy_wait(params, data, data_size, length + preamble_size, |
146 | 0 | preamble_size + data_size - tag_size - 1); |
147 | |
|
148 | 0 | return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); |
149 | 0 | } |
150 | | |
151 | 0 | return length; |
152 | 0 | } |