xref: /openssl/ssl/record/methods/tls_pad.c (revision da1c088f)
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