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