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