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