Split the padding/mac removal functions out into a separate file
[openssl.git] / ssl / record / ssl3_record.c
index 3b1007f5748f802eb12c5f8d17c45988114088fc..55a3a3b6e64a7c937a1bebe13bbcadebd1b50406 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include "../ssl_local.h"
-#include "internal/constant_time.h"
 #include <openssl/trace.h>
 #include <openssl/rand.h>
 #include "record_local.h"
@@ -32,14 +31,6 @@ static const unsigned char ssl3_pad_2[48] = {
     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
 };
 
-static int ssl3_cbc_copy_mac(const SSL *s,
-                             SSL3_RECORD *rec,
-                             unsigned char **mac,
-                             int *alloced,
-                             size_t block_size,
-                             size_t mac_size,
-                             size_t good);
-
 /*
  * Clear the contents of an SSL3_RECORD but retain any memory allocated
  */
@@ -1404,266 +1395,6 @@ int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int sending)
     return 1;
 }
 
-/*-
- * ssl3_cbc_remove_padding removes padding from the decrypted, SSLv3, CBC
- * record in |rec| by updating |rec->length| in constant time. It also extracts
- * the MAC from the underlying record.
- *
- * block_size: the block size of the cipher used to encrypt the record.
- * returns:
- *   0: if the record is publicly invalid.
- *   1: if the record is publicly valid. If the padding removal fails then the
- *      MAC returned is random.
- */
-int ssl3_cbc_remove_padding_and_mac(SSL *s,
-                                    SSL3_RECORD *rec,
-                                    unsigned char **mac,
-                                    int *alloced,
-                                    size_t block_size, size_t mac_size)
-{
-    size_t padding_length;
-    size_t good;
-    const size_t overhead = 1 /* padding length byte */  + mac_size;
-
-    /*
-     * These lengths are all public so we can test them in non-constant time.
-     */
-    if (overhead > rec->length)
-        return 0;
-
-    padding_length = rec->data[rec->length - 1];
-    good = constant_time_ge_s(rec->length, padding_length + overhead);
-    /* SSLv3 requires that the padding is minimal. */
-    good &= constant_time_ge_s(block_size, padding_length + 1);
-    rec->length -= good & (padding_length + 1);
-
-    return ssl3_cbc_copy_mac(s, rec, mac, alloced, block_size, mac_size, good);
-}
-
-/*-
- * tls1_cbc_remove_padding removes the CBC padding from the decrypted, TLS, CBC
- * record in |rec| in constant time. It also removes any explicit IV from the
- * start of the record without leaking any timing about whether there was enough
- * space after the padding was removed, as well as extracting the embedded MAC
- * (also in constant time). For Mac-then-encrypt, if the padding is invalid then
- * a success result will occur and a randomised MAC will be returned.
- *
- * block_size: the block size of the cipher used to encrypt the record.
- * returns:
- *    0: if the record is publicly invalid, or an internal error
- *    1: Success or Mac-then-encrypt decryption failed (MAC will be randomised)
- */
-int tls1_cbc_remove_padding_and_mac(const SSL *s,
-                                    SSL3_RECORD *rec,
-                                    unsigned char **mac,
-                                    int *alloced,
-                                    size_t block_size, size_t mac_size)
-{
-    size_t good;
-    size_t padding_length, to_check, i;
-    size_t overhead = ((block_size == 1) ? 0 : 1) /* padding length byte */
-                      + (SSL_USE_EXPLICIT_IV(s) ? block_size : 0)
-                      + mac_size;
-
-    /*
-     * These lengths are all public so we can test them in non-constant
-     * time.
-     */
-    if (overhead > rec->length)
-        return 0;
-
-    if (block_size != 1) {
-        if (SSL_USE_EXPLICIT_IV(s)) {
-            rec->data += block_size;
-            rec->input += block_size;
-            rec->length -= block_size;
-            rec->orig_len -= block_size;
-            overhead -= block_size;
-        }
-
-        padding_length = rec->data[rec->length - 1];
-
-        if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx)) &
-            EVP_CIPH_FLAG_AEAD_CIPHER) {
-            /* padding is already verified and we don't need to check the MAC */
-            rec->length -= padding_length + 1 + mac_size;
-            *mac = NULL;
-            *alloced = 0;
-            return 1;
-        }
-
-        good = constant_time_ge_s(rec->length, overhead + padding_length);
-        /*
-         * The padding consists of a length byte at the end of the record and
-         * then that many bytes of padding, all with the same value as the
-         * length byte. Thus, with the length byte included, there are i+1 bytes
-         * of padding. We can't check just |padding_length+1| bytes because that
-         * leaks decrypted information. Therefore we always have to check the
-         * maximum amount of padding possible. (Again, the length of the record
-         * is public information so we can use it.)
-         */
-        to_check = 256;        /* maximum amount of padding, inc length byte. */
-        if (to_check > rec->length)
-            to_check = rec->length;
-
-        for (i = 0; i < to_check; i++) {
-            unsigned char mask = constant_time_ge_8_s(padding_length, i);
-            unsigned char b = rec->data[rec->length - 1 - i];
-            /*
-             * The final |padding_length+1| bytes should all have the value
-             * |padding_length|. Therefore the XOR should be zero.
-             */
-            good &= ~(mask & (padding_length ^ b));
-        }
-
-        /*
-         * If any of the final |padding_length+1| bytes had the wrong value, one
-         * or more of the lower eight bits of |good| will be cleared.
-         */
-        good = constant_time_eq_s(0xff, good & 0xff);
-        rec->length -= good & (padding_length + 1);
-    }
-
-    return ssl3_cbc_copy_mac(s, rec, mac, alloced, block_size, mac_size, good);
-}
-
-/*-
- * ssl3_cbc_copy_mac copies |md_size| bytes from the end of |rec| to |out| in
- * constant time (independent of the concrete value of rec->length, which may
- * vary within a 256-byte window).
- *
- * On entry:
- *   rec->orig_len >= md_size
- *   md_size <= EVP_MAX_MD_SIZE
- *
- * If CBC_MAC_ROTATE_IN_PLACE is defined then the rotation is performed with
- * variable accesses in a 64-byte-aligned buffer. Assuming that this fits into
- * a single or pair of cache-lines, then the variable memory accesses don't
- * actually affect the timing. CPUs with smaller cache-lines [if any] are
- * not multi-core and are not considered vulnerable to cache-timing attacks.
- */
-#define CBC_MAC_ROTATE_IN_PLACE
-
-static int ssl3_cbc_copy_mac(const SSL *s,
-                             SSL3_RECORD *rec,
-                             unsigned char **mac,
-                             int *alloced,
-                             size_t block_size,
-                             size_t mac_size,
-                             size_t good)
-{
-#if defined(CBC_MAC_ROTATE_IN_PLACE)
-    unsigned char rotated_mac_buf[64 + EVP_MAX_MD_SIZE];
-    unsigned char *rotated_mac;
-#else
-    unsigned char rotated_mac[EVP_MAX_MD_SIZE];
-#endif
-    unsigned char randmac[EVP_MAX_MD_SIZE];
-    unsigned char *out;
-
-    /*
-     * mac_end is the index of |rec->data| just after the end of the MAC.
-     */
-    size_t mac_end = rec->length;
-    size_t mac_start = mac_end - mac_size;
-    size_t in_mac;
-    /*
-     * scan_start contains the number of bytes that we can ignore because the
-     * MAC's position can only vary by 255 bytes.
-     */
-    size_t scan_start = 0;
-    size_t i, j;
-    size_t rotate_offset;
-
-    if (!ossl_assert(rec->orig_len >= mac_size
-                     && mac_size <= EVP_MAX_MD_SIZE))
-        return 0;
-
-    /* If no MAC then nothing to be done */
-    if (mac_size == 0) {
-        /* No MAC so we can do this in non-constant time */
-        if (good == 0)
-            return 0;
-        return 1;
-    }
-
-    rec->length -= mac_size;
-
-    if (block_size == 1) {
-        /* There's no padding so the position of the MAC is fixed */
-        if (mac != NULL)
-            *mac = &rec->data[rec->length];
-        if (alloced != NULL)
-            *alloced = 0;
-        return 1;
-    }
-
-    /* Create the random MAC we will emit if padding is bad */
-    if (!RAND_bytes_ex(s->ctx->libctx, randmac, mac_size))
-        return 0;
-
-    if (!ossl_assert(mac != NULL && alloced != NULL))
-        return 0;
-    *mac = out = OPENSSL_malloc(mac_size);
-    if (*mac == NULL)
-        return 0;
-    *alloced = 1;
-
-#if defined(CBC_MAC_ROTATE_IN_PLACE)
-    rotated_mac = rotated_mac_buf + ((0 - (size_t)rotated_mac_buf) & 63);
-#endif
-
-    /* This information is public so it's safe to branch based on it. */
-    if (rec->orig_len > mac_size + 255 + 1)
-        scan_start = rec->orig_len - (mac_size + 255 + 1);
-
-    in_mac = 0;
-    rotate_offset = 0;
-    memset(rotated_mac, 0, mac_size);
-    for (i = scan_start, j = 0; i < rec->orig_len; i++) {
-        size_t mac_started = constant_time_eq_s(i, mac_start);
-        size_t mac_ended = constant_time_lt_s(i, mac_end);
-        unsigned char b = rec->data[i];
-
-        in_mac |= mac_started;
-        in_mac &= mac_ended;
-        rotate_offset |= j & mac_started;
-        rotated_mac[j++] |= b & in_mac;
-        j &= constant_time_lt_s(j, mac_size);
-    }
-
-    /* Now rotate the MAC */
-#if defined(CBC_MAC_ROTATE_IN_PLACE)
-    j = 0;
-    for (i = 0; i < mac_size; i++) {
-        /* in case cache-line is 32 bytes, touch second line */
-        ((volatile unsigned char *)rotated_mac)[rotate_offset ^ 32];
-
-        /* If the padding wasn't good we emit a random MAC */
-        out[j++] = constant_time_select_8((unsigned char)(good & 0xff),
-                                          rotated_mac[rotate_offset++],
-                                          randmac[i]);
-        rotate_offset &= constant_time_lt_s(rotate_offset, mac_size);
-    }
-#else
-    memset(out, 0, mac_size);
-    rotate_offset = mac_size - rotate_offset;
-    rotate_offset &= constant_time_lt_s(rotate_offset, mac_size);
-    for (i = 0; i < mac_size; i++) {
-        for (j = 0; j < mac_size; j++)
-            out[j] |= rotated_mac[i] & constant_time_eq_8_s(j, rotate_offset);
-        rotate_offset++;
-        rotate_offset &= constant_time_lt_s(rotate_offset, mac_size);
-
-        /* If the padding wasn't good we emit a random MAC */
-        out[i] = constant_time_select_8((unsigned char)(good & 0xff), out[i],
-                                        randmac[i]);
-    }
-#endif
-
-    return 1;
-}
-
 int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap)
 {
     int i;