1 /*
2 * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <openssl/rand.h>
11 #include <openssl/evp.h>
12
13 #include "internal/constant_time.h"
14 #include "internal/cryptlib.h"
15 #include "internal/ssl3_cbc.h"
16
17 /*
18 * This file has no dependencies on the rest of libssl because it is shared
19 * with the providers. It contains functions for low level CBC TLS padding
20 * removal. Responsibility for this lies with the cipher implementations in the
21 * providers. However there are legacy code paths in libssl which also need to
22 * do this. In time those legacy code paths can be removed and this file can be
23 * moved out of libssl.
24 */
25
26 static int ssl3_cbc_copy_mac(size_t *reclen,
27 size_t origreclen,
28 unsigned char *recdata,
29 unsigned char **mac,
30 int *alloced,
31 size_t block_size,
32 size_t mac_size,
33 size_t good,
34 OSSL_LIB_CTX *libctx);
35
36 /*-
37 * ssl3_cbc_remove_padding removes padding from the decrypted, SSLv3, CBC
38 * record in |recdata| by updating |reclen| in constant time. It also extracts
39 * the MAC from the underlying record and places a pointer to it in |mac|. The
40 * MAC data can either be newly allocated memory, or a pointer inside the
41 * |recdata| buffer. If allocated then |*alloced| is set to 1, otherwise it is
42 * set to 0.
43 *
44 * origreclen: the original record length before any changes were made
45 * block_size: the block size of the cipher used to encrypt the record.
46 * mac_size: the size of the MAC to be extracted
47 * aead: 1 if an AEAD cipher is in use, or 0 otherwise
48 * returns:
49 * 0: if the record is publicly invalid.
50 * 1: if the record is publicly valid. If the padding removal fails then the
51 * MAC returned is random.
52 */
ssl3_cbc_remove_padding_and_mac(size_t * reclen,size_t origreclen,unsigned char * recdata,unsigned char ** mac,int * alloced,size_t block_size,size_t mac_size,OSSL_LIB_CTX * libctx)53 int ssl3_cbc_remove_padding_and_mac(size_t *reclen,
54 size_t origreclen,
55 unsigned char *recdata,
56 unsigned char **mac,
57 int *alloced,
58 size_t block_size, size_t mac_size,
59 OSSL_LIB_CTX *libctx)
60 {
61 size_t padding_length;
62 size_t good;
63 const size_t overhead = 1 /* padding length byte */ + mac_size;
64
65 /*
66 * These lengths are all public so we can test them in non-constant time.
67 */
68 if (overhead > *reclen)
69 return 0;
70
71 padding_length = recdata[*reclen - 1];
72 good = constant_time_ge_s(*reclen, padding_length + overhead);
73 /* SSLv3 requires that the padding is minimal. */
74 good &= constant_time_ge_s(block_size, padding_length + 1);
75 *reclen -= good & (padding_length + 1);
76
77 return ssl3_cbc_copy_mac(reclen, origreclen, recdata, mac, alloced,
78 block_size, mac_size, good, libctx);
79 }
80
81 /*-
82 * tls1_cbc_remove_padding_and_mac removes padding from the decrypted, TLS, CBC
83 * record in |recdata| by updating |reclen| in constant time. It also extracts
84 * the MAC from the underlying record and places a pointer to it in |mac|. The
85 * MAC data can either be newly allocated memory, or a pointer inside the
86 * |recdata| buffer. If allocated then |*alloced| is set to 1, otherwise it is
87 * set to 0.
88 *
89 * origreclen: the original record length before any changes were made
90 * block_size: the block size of the cipher used to encrypt the record.
91 * mac_size: the size of the MAC to be extracted
92 * aead: 1 if an AEAD cipher is in use, or 0 otherwise
93 * returns:
94 * 0: if the record is publicly invalid.
95 * 1: if the record is publicly valid. If the padding removal fails then the
96 * MAC returned is random.
97 */
tls1_cbc_remove_padding_and_mac(size_t * reclen,size_t origreclen,unsigned char * recdata,unsigned char ** mac,int * alloced,size_t block_size,size_t mac_size,int aead,OSSL_LIB_CTX * libctx)98 int tls1_cbc_remove_padding_and_mac(size_t *reclen,
99 size_t origreclen,
100 unsigned char *recdata,
101 unsigned char **mac,
102 int *alloced,
103 size_t block_size, size_t mac_size,
104 int aead,
105 OSSL_LIB_CTX *libctx)
106 {
107 size_t good = -1;
108 size_t padding_length, to_check, i;
109 size_t overhead = ((block_size == 1) ? 0 : 1) /* padding length byte */
110 + mac_size;
111
112 /*
113 * These lengths are all public so we can test them in non-constant
114 * time.
115 */
116 if (overhead > *reclen)
117 return 0;
118
119 if (block_size != 1) {
120
121 padding_length = recdata[*reclen - 1];
122
123 if (aead) {
124 /* padding is already verified and we don't need to check the MAC */
125 *reclen -= padding_length + 1 + mac_size;
126 return 1;
127 }
128
129 good = constant_time_ge_s(*reclen, overhead + padding_length);
130 /*
131 * The padding consists of a length byte at the end of the record and
132 * then that many bytes of padding, all with the same value as the
133 * length byte. Thus, with the length byte included, there are i+1 bytes
134 * of padding. We can't check just |padding_length+1| bytes because that
135 * leaks decrypted information. Therefore we always have to check the
136 * maximum amount of padding possible. (Again, the length of the record
137 * is public information so we can use it.)
138 */
139 to_check = 256; /* maximum amount of padding, inc length byte. */
140 if (to_check > *reclen)
141 to_check = *reclen;
142
143 for (i = 0; i < to_check; i++) {
144 unsigned char mask = constant_time_ge_8_s(padding_length, i);
145 unsigned char b = recdata[*reclen - 1 - i];
146 /*
147 * The final |padding_length+1| bytes should all have the value
148 * |padding_length|. Therefore the XOR should be zero.
149 */
150 good &= ~(mask & (padding_length ^ b));
151 }
152
153 /*
154 * If any of the final |padding_length+1| bytes had the wrong value, one
155 * or more of the lower eight bits of |good| will be cleared.
156 */
157 good = constant_time_eq_s(0xff, good & 0xff);
158 *reclen -= good & (padding_length + 1);
159 }
160
161 return ssl3_cbc_copy_mac(reclen, origreclen, recdata, mac, alloced,
162 block_size, mac_size, good, libctx);
163 }
164
165 /*-
166 * ssl3_cbc_copy_mac copies |md_size| bytes from the end of the record in
167 * |recdata| to |*mac| in constant time (independent of the concrete value of
168 * the record length |reclen|, which may vary within a 256-byte window).
169 *
170 * On entry:
171 * origreclen >= mac_size
172 * mac_size <= EVP_MAX_MD_SIZE
173 *
174 * If CBC_MAC_ROTATE_IN_PLACE is defined then the rotation is performed with
175 * variable accesses in a 64-byte-aligned buffer. Assuming that this fits into
176 * a single or pair of cache-lines, then the variable memory accesses don't
177 * actually affect the timing. CPUs with smaller cache-lines [if any] are
178 * not multi-core and are not considered vulnerable to cache-timing attacks.
179 */
180 #define CBC_MAC_ROTATE_IN_PLACE
181
ssl3_cbc_copy_mac(size_t * reclen,size_t origreclen,unsigned char * recdata,unsigned char ** mac,int * alloced,size_t block_size,size_t mac_size,size_t good,OSSL_LIB_CTX * libctx)182 static int ssl3_cbc_copy_mac(size_t *reclen,
183 size_t origreclen,
184 unsigned char *recdata,
185 unsigned char **mac,
186 int *alloced,
187 size_t block_size,
188 size_t mac_size,
189 size_t good,
190 OSSL_LIB_CTX *libctx)
191 {
192 #if defined(CBC_MAC_ROTATE_IN_PLACE)
193 unsigned char rotated_mac_buf[64 + EVP_MAX_MD_SIZE];
194 unsigned char *rotated_mac;
195 char aux1, aux2, aux3, mask;
196 #else
197 unsigned char rotated_mac[EVP_MAX_MD_SIZE];
198 #endif
199 unsigned char randmac[EVP_MAX_MD_SIZE];
200 unsigned char *out;
201
202 /*
203 * mac_end is the index of |recdata| just after the end of the MAC.
204 */
205 size_t mac_end = *reclen;
206 size_t mac_start = mac_end - mac_size;
207 size_t in_mac;
208 /*
209 * scan_start contains the number of bytes that we can ignore because the
210 * MAC's position can only vary by 255 bytes.
211 */
212 size_t scan_start = 0;
213 size_t i, j;
214 size_t rotate_offset;
215
216 if (!ossl_assert(origreclen >= mac_size
217 && mac_size <= EVP_MAX_MD_SIZE))
218 return 0;
219
220 /* If no MAC then nothing to be done */
221 if (mac_size == 0) {
222 /* No MAC so we can do this in non-constant time */
223 if (good == 0)
224 return 0;
225 return 1;
226 }
227
228 *reclen -= mac_size;
229
230 if (block_size == 1) {
231 /* There's no padding so the position of the MAC is fixed */
232 if (mac != NULL)
233 *mac = &recdata[*reclen];
234 if (alloced != NULL)
235 *alloced = 0;
236 return 1;
237 }
238
239 /* Create the random MAC we will emit if padding is bad */
240 if (RAND_bytes_ex(libctx, randmac, mac_size, 0) <= 0)
241 return 0;
242
243 if (!ossl_assert(mac != NULL && alloced != NULL))
244 return 0;
245 *mac = out = OPENSSL_malloc(mac_size);
246 if (*mac == NULL)
247 return 0;
248 *alloced = 1;
249
250 #if defined(CBC_MAC_ROTATE_IN_PLACE)
251 rotated_mac = rotated_mac_buf + ((0 - (size_t)rotated_mac_buf) & 63);
252 #endif
253
254 /* This information is public so it's safe to branch based on it. */
255 if (origreclen > mac_size + 255 + 1)
256 scan_start = origreclen - (mac_size + 255 + 1);
257
258 in_mac = 0;
259 rotate_offset = 0;
260 memset(rotated_mac, 0, mac_size);
261 for (i = scan_start, j = 0; i < origreclen; i++) {
262 size_t mac_started = constant_time_eq_s(i, mac_start);
263 size_t mac_ended = constant_time_lt_s(i, mac_end);
264 unsigned char b = recdata[i];
265
266 in_mac |= mac_started;
267 in_mac &= mac_ended;
268 rotate_offset |= j & mac_started;
269 rotated_mac[j++] |= b & in_mac;
270 j &= constant_time_lt_s(j, mac_size);
271 }
272
273 /* Now rotate the MAC */
274 #if defined(CBC_MAC_ROTATE_IN_PLACE)
275 j = 0;
276 for (i = 0; i < mac_size; i++) {
277 /*
278 * in case cache-line is 32 bytes,
279 * load from both lines and select appropriately
280 */
281 aux1 = rotated_mac[rotate_offset & ~32];
282 aux2 = rotated_mac[rotate_offset | 32];
283 mask = constant_time_eq_8(rotate_offset & ~32, rotate_offset);
284 aux3 = constant_time_select_8(mask, aux1, aux2);
285 rotate_offset++;
286
287 /* If the padding wasn't good we emit a random MAC */
288 out[j++] = constant_time_select_8((unsigned char)(good & 0xff),
289 aux3,
290 randmac[i]);
291 rotate_offset &= constant_time_lt_s(rotate_offset, mac_size);
292 }
293 #else
294 memset(out, 0, mac_size);
295 rotate_offset = mac_size - rotate_offset;
296 rotate_offset &= constant_time_lt_s(rotate_offset, mac_size);
297 for (i = 0; i < mac_size; i++) {
298 for (j = 0; j < mac_size; j++)
299 out[j] |= rotated_mac[i] & constant_time_eq_8_s(j, rotate_offset);
300 rotate_offset++;
301 rotate_offset &= constant_time_lt_s(rotate_offset, mac_size);
302
303 /* If the padding wasn't good we emit a random MAC */
304 out[i] = constant_time_select_8((unsigned char)(good & 0xff), out[i],
305 randmac[i]);
306 }
307 #endif
308
309 return 1;
310 }
311