xref: /freebsd/crypto/openssl/providers/implementations/ciphers/ciphercommon_block.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1b077aed3SPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
3b077aed3SPierre Pronchery  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5b077aed3SPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6b077aed3SPierre Pronchery  * in the file LICENSE in the source distribution or at
7b077aed3SPierre Pronchery  * https://www.openssl.org/source/license.html
8b077aed3SPierre Pronchery  */
9b077aed3SPierre Pronchery 
10b077aed3SPierre Pronchery #include <assert.h>
11b077aed3SPierre Pronchery /* For SSL3_VERSION, TLS1_VERSION etc */
12b077aed3SPierre Pronchery #include <openssl/prov_ssl.h>
13b077aed3SPierre Pronchery #include <openssl/rand.h>
14b077aed3SPierre Pronchery #include <openssl/proverr.h>
15b077aed3SPierre Pronchery #include "internal/constant_time.h"
16*e7be843bSPierre Pronchery #include "internal/ssl3_cbc.h"
17b077aed3SPierre Pronchery #include "ciphercommon_local.h"
18b077aed3SPierre Pronchery 
19b077aed3SPierre Pronchery /*
20b077aed3SPierre Pronchery  * Fills a single block of buffered data from the input, and returns the amount
21b077aed3SPierre Pronchery  * of data remaining in the input that is a multiple of the blocksize. The buffer
22b077aed3SPierre Pronchery  * is only filled if it already has some data in it, isn't full already or we
23b077aed3SPierre Pronchery  * don't have at least one block in the input.
24b077aed3SPierre Pronchery  *
25b077aed3SPierre Pronchery  * buf: a buffer of blocksize bytes
26b077aed3SPierre Pronchery  * buflen: contains the amount of data already in buf on entry. Updated with the
27b077aed3SPierre Pronchery  *         amount of data in buf at the end. On entry *buflen must always be
28b077aed3SPierre Pronchery  *         less than the blocksize
29b077aed3SPierre Pronchery  * blocksize: size of a block. Must be greater than 0 and a power of 2
30b077aed3SPierre Pronchery  * in: pointer to a pointer containing the input data
31b077aed3SPierre Pronchery  * inlen: amount of input data available
32b077aed3SPierre Pronchery  *
33b077aed3SPierre Pronchery  * On return buf is filled with as much data as possible up to a full block,
34b077aed3SPierre Pronchery  * *buflen is updated containing the amount of data in buf. *in is updated to
35b077aed3SPierre Pronchery  * the new location where input data should be read from, *inlen is updated with
36b077aed3SPierre Pronchery  * the remaining amount of data in *in. Returns the largest value <= *inlen
37b077aed3SPierre Pronchery  * which is a multiple of the blocksize.
38b077aed3SPierre Pronchery  */
ossl_cipher_fillblock(unsigned char * buf,size_t * buflen,size_t blocksize,const unsigned char ** in,size_t * inlen)39b077aed3SPierre Pronchery size_t ossl_cipher_fillblock(unsigned char *buf, size_t *buflen,
40b077aed3SPierre Pronchery                              size_t blocksize,
41b077aed3SPierre Pronchery                              const unsigned char **in, size_t *inlen)
42b077aed3SPierre Pronchery {
43b077aed3SPierre Pronchery     size_t blockmask = ~(blocksize - 1);
44b077aed3SPierre Pronchery     size_t bufremain = blocksize - *buflen;
45b077aed3SPierre Pronchery 
46b077aed3SPierre Pronchery     assert(*buflen <= blocksize);
47b077aed3SPierre Pronchery     assert(blocksize > 0 && (blocksize & (blocksize - 1)) == 0);
48b077aed3SPierre Pronchery 
49b077aed3SPierre Pronchery     if (*inlen < bufremain)
50b077aed3SPierre Pronchery         bufremain = *inlen;
51b077aed3SPierre Pronchery     memcpy(buf + *buflen, *in, bufremain);
52b077aed3SPierre Pronchery     *in += bufremain;
53b077aed3SPierre Pronchery     *inlen -= bufremain;
54b077aed3SPierre Pronchery     *buflen += bufremain;
55b077aed3SPierre Pronchery 
56b077aed3SPierre Pronchery     return *inlen & blockmask;
57b077aed3SPierre Pronchery }
58b077aed3SPierre Pronchery 
59b077aed3SPierre Pronchery /*
60b077aed3SPierre Pronchery  * Fills the buffer with trailing data from an encryption/decryption that didn't
61b077aed3SPierre Pronchery  * fit into a full block.
62b077aed3SPierre Pronchery  */
ossl_cipher_trailingdata(unsigned char * buf,size_t * buflen,size_t blocksize,const unsigned char ** in,size_t * inlen)63b077aed3SPierre Pronchery int ossl_cipher_trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize,
64b077aed3SPierre Pronchery                              const unsigned char **in, size_t *inlen)
65b077aed3SPierre Pronchery {
66b077aed3SPierre Pronchery     if (*inlen == 0)
67b077aed3SPierre Pronchery         return 1;
68b077aed3SPierre Pronchery 
69b077aed3SPierre Pronchery     if (*buflen + *inlen > blocksize) {
70b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
71b077aed3SPierre Pronchery         return 0;
72b077aed3SPierre Pronchery     }
73b077aed3SPierre Pronchery 
74b077aed3SPierre Pronchery     memcpy(buf + *buflen, *in, *inlen);
75b077aed3SPierre Pronchery     *buflen += *inlen;
76b077aed3SPierre Pronchery     *inlen = 0;
77b077aed3SPierre Pronchery 
78b077aed3SPierre Pronchery     return 1;
79b077aed3SPierre Pronchery }
80b077aed3SPierre Pronchery 
81b077aed3SPierre Pronchery /* Pad the final block for encryption */
ossl_cipher_padblock(unsigned char * buf,size_t * buflen,size_t blocksize)82b077aed3SPierre Pronchery void ossl_cipher_padblock(unsigned char *buf, size_t *buflen, size_t blocksize)
83b077aed3SPierre Pronchery {
84b077aed3SPierre Pronchery     size_t i;
85b077aed3SPierre Pronchery     unsigned char pad = (unsigned char)(blocksize - *buflen);
86b077aed3SPierre Pronchery 
87b077aed3SPierre Pronchery     for (i = *buflen; i < blocksize; i++)
88b077aed3SPierre Pronchery         buf[i] = pad;
89b077aed3SPierre Pronchery }
90b077aed3SPierre Pronchery 
ossl_cipher_unpadblock(unsigned char * buf,size_t * buflen,size_t blocksize)91b077aed3SPierre Pronchery int ossl_cipher_unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize)
92b077aed3SPierre Pronchery {
93b077aed3SPierre Pronchery     size_t pad, i;
94b077aed3SPierre Pronchery     size_t len = *buflen;
95b077aed3SPierre Pronchery 
96b077aed3SPierre Pronchery     if (len != blocksize) {
97b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
98b077aed3SPierre Pronchery         return 0;
99b077aed3SPierre Pronchery     }
100b077aed3SPierre Pronchery 
101b077aed3SPierre Pronchery     /*
102b077aed3SPierre Pronchery      * The following assumes that the ciphertext has been authenticated.
103b077aed3SPierre Pronchery      * Otherwise it provides a padding oracle.
104b077aed3SPierre Pronchery      */
105b077aed3SPierre Pronchery     pad = buf[blocksize - 1];
106b077aed3SPierre Pronchery     if (pad == 0 || pad > blocksize) {
107b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
108b077aed3SPierre Pronchery         return 0;
109b077aed3SPierre Pronchery     }
110b077aed3SPierre Pronchery     for (i = 0; i < pad; i++) {
111b077aed3SPierre Pronchery         if (buf[--len] != pad) {
112b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
113b077aed3SPierre Pronchery             return 0;
114b077aed3SPierre Pronchery         }
115b077aed3SPierre Pronchery     }
116b077aed3SPierre Pronchery     *buflen = len;
117b077aed3SPierre Pronchery     return 1;
118b077aed3SPierre Pronchery }
119b077aed3SPierre Pronchery 
120b077aed3SPierre Pronchery /*-
121b077aed3SPierre Pronchery  * ossl_cipher_tlsunpadblock removes the CBC padding from the decrypted, TLS, CBC
122b077aed3SPierre Pronchery  * record in constant time. Also removes the MAC from the record in constant
123b077aed3SPierre Pronchery  * time.
124b077aed3SPierre Pronchery  *
125b077aed3SPierre Pronchery  * libctx: Our library context
126b077aed3SPierre Pronchery  * tlsversion: The TLS version in use, e.g. SSL3_VERSION, TLS1_VERSION, etc
127b077aed3SPierre Pronchery  * buf: The decrypted TLS record data
128b077aed3SPierre Pronchery  * buflen: The length of the decrypted TLS record data. Updated with the new
129b077aed3SPierre Pronchery  *         length after the padding is removed
130b077aed3SPierre Pronchery  * block_size: the block size of the cipher used to encrypt the record.
131b077aed3SPierre Pronchery  * mac: Location to store the pointer to the MAC
132b077aed3SPierre Pronchery  * alloced: Whether the MAC is stored in a newly allocated buffer, or whether
133b077aed3SPierre Pronchery  *          *mac points into *buf
134b077aed3SPierre Pronchery  * macsize: the size of the MAC inside the record (or 0 if there isn't one)
135b077aed3SPierre Pronchery  * aead: whether this is an aead cipher
136b077aed3SPierre Pronchery  * returns:
137b077aed3SPierre Pronchery  *   0: (in non-constant time) if the record is publicly invalid.
138b077aed3SPierre Pronchery  *   1: (in constant time) Record is publicly valid. If padding is invalid then
139b077aed3SPierre Pronchery  *      the mac is random
140b077aed3SPierre Pronchery  */
ossl_cipher_tlsunpadblock(OSSL_LIB_CTX * libctx,unsigned int tlsversion,unsigned char * buf,size_t * buflen,size_t blocksize,unsigned char ** mac,int * alloced,size_t macsize,int aead)141b077aed3SPierre Pronchery int ossl_cipher_tlsunpadblock(OSSL_LIB_CTX *libctx, unsigned int tlsversion,
142b077aed3SPierre Pronchery                               unsigned char *buf, size_t *buflen,
143b077aed3SPierre Pronchery                               size_t blocksize,
144b077aed3SPierre Pronchery                               unsigned char **mac, int *alloced, size_t macsize,
145b077aed3SPierre Pronchery                               int aead)
146b077aed3SPierre Pronchery {
147b077aed3SPierre Pronchery     int ret;
148b077aed3SPierre Pronchery 
149b077aed3SPierre Pronchery     switch (tlsversion) {
150b077aed3SPierre Pronchery     case SSL3_VERSION:
151b077aed3SPierre Pronchery         return ssl3_cbc_remove_padding_and_mac(buflen, *buflen, buf, mac,
152b077aed3SPierre Pronchery                                                alloced, blocksize, macsize,
153b077aed3SPierre Pronchery                                                libctx);
154b077aed3SPierre Pronchery 
155b077aed3SPierre Pronchery     case TLS1_2_VERSION:
156b077aed3SPierre Pronchery     case DTLS1_2_VERSION:
157b077aed3SPierre Pronchery     case TLS1_1_VERSION:
158b077aed3SPierre Pronchery     case DTLS1_VERSION:
159b077aed3SPierre Pronchery     case DTLS1_BAD_VER:
160b077aed3SPierre Pronchery         /* Remove the explicit IV */
161b077aed3SPierre Pronchery         buf += blocksize;
162b077aed3SPierre Pronchery         *buflen -= blocksize;
163b077aed3SPierre Pronchery         /* Fall through */
164b077aed3SPierre Pronchery     case TLS1_VERSION:
165b077aed3SPierre Pronchery         ret = tls1_cbc_remove_padding_and_mac(buflen, *buflen, buf, mac,
166b077aed3SPierre Pronchery                                               alloced, blocksize, macsize,
167b077aed3SPierre Pronchery                                               aead, libctx);
168b077aed3SPierre Pronchery         return ret;
169b077aed3SPierre Pronchery 
170b077aed3SPierre Pronchery     default:
171b077aed3SPierre Pronchery         return 0;
172b077aed3SPierre Pronchery     }
173b077aed3SPierre Pronchery }
174