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