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 */ 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 */ 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 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