summaryrefslogtreecommitdiffstats
path: root/ssl/record
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2020-06-10 15:11:28 +0100
committerMatt Caswell <matt@openssl.org>2020-07-06 09:26:00 +0100
commitebacd57bee1baef6236a518a0eec3135d593f47a (patch)
tree6974261d2795910e58b59645274304371eb23985 /ssl/record
parentec27e619e86c6ce4dfa905044eb4737eeba28a9d (diff)
Split the padding/mac removal functions out into a separate file
We split these functions out into a separate file because we are preparing to make this file shared between libssl and providers. Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12288)
Diffstat (limited to 'ssl/record')
-rw-r--r--ssl/record/ssl3_record.c269
-rw-r--r--ssl/record/tls_pad.c282
2 files changed, 282 insertions, 269 deletions
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 3b1007f574..55a3a3b6e6 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -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;
diff --git a/ssl/record/tls_pad.c b/ssl/record/tls_pad.c
new file mode 100644
index 0000000000..2e6a6e8971
--- /dev/null
+++ b/ssl/record/tls_pad.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/rand.h>
+#include "internal/constant_time.h"
+#include "internal/cryptlib.h"
+#include "../ssl_local.h"
+#include "record_local.h"
+
+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);
+
+/*-
+ * 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;
+}