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