diff options
author | Matt Caswell <matt@openssl.org> | 2020-06-10 15:34:04 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2020-07-06 09:26:09 +0100 |
commit | f0237a6c6266535e105d6778ca7c34a080b88e92 (patch) | |
tree | e1bb25c344d5d25608e9a96d271dc197e67c8d78 /ssl | |
parent | ebacd57bee1baef6236a518a0eec3135d593f47a (diff) |
Remove SSL dependencies from tls_pad.c
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12288)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/record/record_local.h | 17 | ||||
-rw-r--r-- | ssl/record/ssl3_record.c | 30 | ||||
-rw-r--r-- | ssl/record/tls_pad.c | 165 |
3 files changed, 135 insertions, 77 deletions
diff --git a/ssl/record/record_local.h b/ssl/record/record_local.h index dc92732243..9047c23fd5 100644 --- a/ssl/record/record_local.h +++ b/ssl/record/record_local.h @@ -107,16 +107,21 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num); int ssl3_get_record(SSL *s); __owur int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr); __owur int ssl3_do_uncompress(SSL *ssl, SSL3_RECORD *rr); -__owur int ssl3_cbc_remove_padding_and_mac(SSL *s, - SSL3_RECORD *rec, +__owur int ssl3_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, unsigned char **mac, int *alloced, - size_t block_size, size_t mac_size); -__owur int tls1_cbc_remove_padding_and_mac(const SSL *s, - SSL3_RECORD *rec, + size_t block_size, size_t mac_size, + OPENSSL_CTX *libctx); +__owur int tls1_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, unsigned char **mac, int *alloced, - size_t block_size, size_t mac_size); + size_t block_size, size_t mac_size, + int aead, + OPENSSL_CTX *libctx); int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap); __owur int dtls1_get_record(SSL *s); int early_data_count_ok(SSL *s, size_t length, size_t overhead, int send); diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index 55a3a3b6e6..5efa77a5b3 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -904,11 +904,14 @@ int ssl3_enc(SSL *s, SSL3_RECORD *inrecs, size_t n_recs, int sending, } if (!sending) - return !ssl3_cbc_remove_padding_and_mac(s, rec, - (mac != NULL) ? &mac->mac : NULL, - (mac != NULL) ? &mac->alloced : NULL, - bs, - macsize); + return ssl3_cbc_remove_padding_and_mac(&rec->length, + rec->orig_len, + rec->data, + (mac != NULL) ? &mac->mac : NULL, + (mac != NULL) ? &mac->alloced : NULL, + bs, + macsize, + s->ctx->libctx); } return 1; } @@ -1166,15 +1169,28 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending, if (!sending) { for (ctr = 0; ctr < n_recs; ctr++) { + if (bs != 1 && SSL_USE_EXPLICIT_IV(s)) { + if (recs[ctr].length < bs) + return 0; + recs[ctr].data += bs; + recs[ctr].input += bs; + recs[ctr].length -= bs; + recs[ctr].orig_len -= bs; + } /* * If using Mac-then-encrypt, then this will succeed but with a * random MAC if padding is invalid */ - if (!tls1_cbc_remove_padding_and_mac(s, &recs[ctr], + if (!tls1_cbc_remove_padding_and_mac(&recs[ctr].length, + recs[ctr].orig_len, + recs[ctr].data, (macs != NULL) ? &macs[ctr].mac : NULL, (macs != NULL) ? &macs[ctr].alloced : NULL, bs, - macsize)) + macsize, + (EVP_CIPHER_CTX_flags(s->enc_read_ctx) + & EVP_CIPH_FLAG_AEAD_CIPHER) != 0, + s->ctx->libctx)) return 0; } } diff --git a/ssl/record/tls_pad.c b/ssl/record/tls_pad.c index 2e6a6e8971..9f698483f1 100644 --- a/ssl/record/tls_pad.c +++ b/ssl/record/tls_pad.c @@ -8,35 +8,70 @@ */ #include <openssl/rand.h> +#include <openssl/evp.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, +/* + * This file has no dependencies on the rest of libssl because it is shared + * with the providers. It contains functions for low level CBC TLS padding + * removal. Responsibility for this lies with the cipher implementations in the + * providers. However there are legacy code paths in libssl which also need to + * do this. In time those legacy code paths can be removed and this file can be + * moved out of libssl. + */ + +static int ssl3_cbc_copy_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, unsigned char **mac, int *alloced, size_t block_size, size_t mac_size, - size_t good); + size_t good, + OPENSSL_CTX *libctx); + +int ssl3_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, + unsigned char **mac, + int *alloced, + size_t block_size, size_t mac_size, + OPENSSL_CTX *libctx); + +int tls1_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, + unsigned char **mac, + int *alloced, + size_t block_size, size_t mac_size, + int aead, + OPENSSL_CTX *libctx); /*- * 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. + * record in |recdata| by updating |reclen| in constant time. It also extracts + * the MAC from the underlying record and places a pointer to it in |mac|. The + * MAC data can either be newly allocated memory, or a pointer inside the + * |recdata| buffer. If allocated then |*alloced| is set to 1, otherwise it is + * set to 0. * + * origreclen: the original record length before any changes were made * block_size: the block size of the cipher used to encrypt the record. + * mac_size: the size of the MAC to be extracted + * aead: 1 if an AEAD cipher is in use, or 0 otherwise * 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, +int ssl3_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, unsigned char **mac, int *alloced, - size_t block_size, size_t mac_size) + size_t block_size, size_t mac_size, + OPENSSL_CTX *libctx) { size_t padding_length; size_t good; @@ -45,71 +80,70 @@ int ssl3_cbc_remove_padding_and_mac(SSL *s, /* * These lengths are all public so we can test them in non-constant time. */ - if (overhead > rec->length) + if (overhead > *reclen) return 0; - padding_length = rec->data[rec->length - 1]; - good = constant_time_ge_s(rec->length, padding_length + overhead); + padding_length = recdata[*reclen - 1]; + good = constant_time_ge_s(*reclen, 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); + *reclen -= good & (padding_length + 1); - return ssl3_cbc_copy_mac(s, rec, mac, alloced, block_size, mac_size, good); + return ssl3_cbc_copy_mac(reclen, origreclen, recdata, mac, alloced, + block_size, mac_size, good, libctx); } /*- - * 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. + * tls1_cbc_remove_padding_and_mac removes padding from the decrypted, TLS, CBC + * record in |recdata| by updating |reclen| in constant time. It also extracts + * the MAC from the underlying record and places a pointer to it in |mac|. The + * MAC data can either be newly allocated memory, or a pointer inside the + * |recdata| buffer. If allocated then |*alloced| is set to 1, otherwise it is + * set to 0. * + * origreclen: the original record length before any changes were made * block_size: the block size of the cipher used to encrypt the record. + * mac_size: the size of the MAC to be extracted + * aead: 1 if an AEAD cipher is in use, or 0 otherwise * returns: - * 0: if the record is publicly invalid, or an internal error - * 1: Success or Mac-then-encrypt decryption failed (MAC will be randomised) + * 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 tls1_cbc_remove_padding_and_mac(const SSL *s, - SSL3_RECORD *rec, +int tls1_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, unsigned char **mac, int *alloced, - size_t block_size, size_t mac_size) + size_t block_size, size_t mac_size, + int aead, + OPENSSL_CTX *libctx) { - size_t good; + size_t good = -1; 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) + if (overhead > *reclen) 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]; + padding_length = recdata[*reclen - 1]; - if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx)) & - EVP_CIPH_FLAG_AEAD_CIPHER) { + if (aead) { /* padding is already verified and we don't need to check the MAC */ - rec->length -= padding_length + 1 + mac_size; + *reclen -= padding_length + 1 + mac_size; *mac = NULL; *alloced = 0; return 1; } - good = constant_time_ge_s(rec->length, overhead + padding_length); + good = constant_time_ge_s(*reclen, 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 @@ -120,12 +154,12 @@ int tls1_cbc_remove_padding_and_mac(const SSL *s, * 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; + if (to_check > *reclen) + to_check = *reclen; 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]; + unsigned char b = recdata[*reclen - 1 - i]; /* * The final |padding_length+1| bytes should all have the value * |padding_length|. Therefore the XOR should be zero. @@ -138,20 +172,21 @@ int tls1_cbc_remove_padding_and_mac(const SSL *s, * 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); + *reclen -= good & (padding_length + 1); } - return ssl3_cbc_copy_mac(s, rec, mac, alloced, block_size, mac_size, good); + return ssl3_cbc_copy_mac(reclen, origreclen, recdata, mac, alloced, + block_size, mac_size, good, libctx); } /*- - * 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). + * ssl3_cbc_copy_mac copies |md_size| bytes from the end of the record in + * |recdata| to |*mac| in constant time (independent of the concrete value of + * the record length |reclen|, which may vary within a 256-byte window). * * On entry: - * rec->orig_len >= md_size - * md_size <= EVP_MAX_MD_SIZE + * origreclen >= mac_size + * mac_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 @@ -161,13 +196,15 @@ int tls1_cbc_remove_padding_and_mac(const SSL *s, */ #define CBC_MAC_ROTATE_IN_PLACE -static int ssl3_cbc_copy_mac(const SSL *s, - SSL3_RECORD *rec, +static int ssl3_cbc_copy_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, unsigned char **mac, int *alloced, size_t block_size, size_t mac_size, - size_t good) + size_t good, + OPENSSL_CTX *libctx) { #if defined(CBC_MAC_ROTATE_IN_PLACE) unsigned char rotated_mac_buf[64 + EVP_MAX_MD_SIZE]; @@ -179,9 +216,9 @@ static int ssl3_cbc_copy_mac(const SSL *s, unsigned char *out; /* - * mac_end is the index of |rec->data| just after the end of the MAC. + * mac_end is the index of |recdata| just after the end of the MAC. */ - size_t mac_end = rec->length; + size_t mac_end = *reclen; size_t mac_start = mac_end - mac_size; size_t in_mac; /* @@ -192,7 +229,7 @@ static int ssl3_cbc_copy_mac(const SSL *s, size_t i, j; size_t rotate_offset; - if (!ossl_assert(rec->orig_len >= mac_size + if (!ossl_assert(origreclen >= mac_size && mac_size <= EVP_MAX_MD_SIZE)) return 0; @@ -204,19 +241,19 @@ static int ssl3_cbc_copy_mac(const SSL *s, return 1; } - rec->length -= mac_size; + *reclen -= 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]; + *mac = &recdata[*reclen]; 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)) + if (!RAND_bytes_ex(libctx, randmac, mac_size)) return 0; if (!ossl_assert(mac != NULL && alloced != NULL)) @@ -231,16 +268,16 @@ static int ssl3_cbc_copy_mac(const SSL *s, #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); + if (origreclen > mac_size + 255 + 1) + scan_start = origreclen - (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++) { + for (i = scan_start, j = 0; i < origreclen; 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]; + unsigned char b = recdata[i]; in_mac |= mac_started; in_mac &= mac_ended; |