summaryrefslogtreecommitdiff
path: root/lib/libssl
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2020-10-03 17:35:18 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2020-10-03 17:35:18 +0000
commit57ac3469dd8dcd4a3e0977fcb9e619f2213269f0 (patch)
treebeb9624b1897d17738bf559cfd70a658203c3e44 /lib/libssl
parent221ee06f6ac63da03b111e2ec8fce5ccc80a4784 (diff)
Reimplement the TLSv1.2 record handling for the read side.
This is the next step in replacing the TLSv1.2 record layer. The existing record handling code does decryption and processing in place, which is not ideal for various reasons, however it is retained for now as other code depends on this behaviour. Additionally, CBC requires special handling to avoid timing oracles - for now the existing timing safe code is largely retained. ok beck@ inoguchi@ tb@
Diffstat (limited to 'lib/libssl')
-rw-r--r--lib/libssl/d1_pkt.c134
-rw-r--r--lib/libssl/s3_cbc.c30
-rw-r--r--lib/libssl/ssl_locl.h14
-rw-r--r--lib/libssl/ssl_pkt.c166
-rw-r--r--lib/libssl/t1_enc.c339
-rw-r--r--lib/libssl/tls12_record_layer.c348
6 files changed, 426 insertions, 605 deletions
diff --git a/lib/libssl/d1_pkt.c b/lib/libssl/d1_pkt.c
index 859043a3cec..30ce78414d3 100644
--- a/lib/libssl/d1_pkt.c
+++ b/lib/libssl/d1_pkt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: d1_pkt.c,v 1.84 2020/10/03 17:11:28 jsing Exp $ */
+/* $OpenBSD: d1_pkt.c,v 1.85 2020/10/03 17:35:16 jsing Exp $ */
/*
* DTLS implementation written by Nagendra Modadugu
* (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
@@ -310,130 +310,40 @@ dtls1_process_buffered_records(SSL *s)
static int
dtls1_process_record(SSL *s)
{
- int i, al;
- int enc_err;
- SSL_SESSION *sess;
- SSL3_RECORD_INTERNAL *rr;
- unsigned int mac_size, orig_len;
- unsigned char md[EVP_MAX_MD_SIZE];
-
- rr = &(S3I(s)->rrec);
- sess = s->session;
-
- /* At this point, s->internal->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
- * and we have that many bytes in s->internal->packet
- */
- rr->input = &(s->internal->packet[DTLS1_RT_HEADER_LENGTH]);
-
- /* ok, we can now read from 's->internal->packet' data into 'rr'
- * rr->input points at rr->length bytes, which
- * need to be copied into rr->data by either
- * the decryption or by the decompression
- * When the data is 'copied' into the rr->data buffer,
- * rr->input will be pointed at the new buffer */
-
- /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
- * rr->length bytes of encrypted compressed stuff. */
-
- /* check is not needed I believe */
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
- al = SSL_AD_RECORD_OVERFLOW;
- SSLerror(s, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- /* decrypt in place in 'rr->input' */
- rr->data = rr->input;
-
- /* enc_err is:
- * 0: (in non-constant time) if the record is publically invalid.
- * 1: if the padding is valid
- * -1: if the padding is invalid */
- if ((enc_err = tls1_enc(s, 0)) == 0) {
- /* For DTLS we simply ignore bad packets. */
- rr->length = 0;
- s->internal->packet_length = 0;
- goto err;
- }
+ SSL3_RECORD_INTERNAL *rr = &(S3I(s)->rrec);
+ uint8_t alert_desc;
+ uint8_t *out;
+ size_t out_len;
- /* r->length is now the compressed data plus mac */
- if ((sess != NULL) && (s->enc_read_ctx != NULL) &&
- (EVP_MD_CTX_md(s->read_hash) != NULL)) {
- /* s->read_hash != NULL => mac_size != -1 */
- unsigned char *mac = NULL;
- unsigned char mac_tmp[EVP_MAX_MD_SIZE];
- mac_size = EVP_MD_CTX_size(s->read_hash);
- OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
-
- orig_len = rr->length + rr->padding_length;
-
- /* orig_len is the length of the record before any padding was
- * removed. This is public information, as is the MAC in use,
- * therefore we can safely process the record in a different
- * amount of time if it's too short to possibly contain a MAC.
- */
- if (orig_len < mac_size ||
- /* CBC records must have a padding length byte too. */
- (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
- orig_len < mac_size + 1)) {
- al = SSL_AD_DECODE_ERROR;
- SSLerror(s, SSL_R_LENGTH_TOO_SHORT);
- goto f_err;
- }
+ tls12_record_layer_set_version(s->internal->rl, s->version);
+ tls12_record_layer_set_read_epoch(s->internal->rl, rr->epoch);
- if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) {
- /* We update the length so that the TLS header bytes
- * can be constructed correctly but we need to extract
- * the MAC in constant time from within the record,
- * without leaking the contents of the padding bytes.
- * */
- mac = mac_tmp;
- ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
- rr->length -= mac_size;
- } else {
- /* In this case there's no padding, so |orig_len|
- * equals |rec->length| and we checked that there's
- * enough bytes for |mac_size| above. */
- rr->length -= mac_size;
- mac = &rr->data[rr->length];
- }
+ if (!tls12_record_layer_open_record(s->internal->rl, s->internal->packet,
+ s->internal->packet_length, &out, &out_len)) {
+ tls12_record_layer_alert(s->internal->rl, &alert_desc);
- i = tls1_mac(s, md, 0 /* not send */);
- if (i < 0 || mac == NULL || timingsafe_memcmp(md, mac, (size_t)mac_size) != 0)
- enc_err = -1;
- if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
- enc_err = -1;
- }
+ if (alert_desc == 0)
+ goto err;
- if (enc_err < 0) {
- /* decryption failed, silently discard message */
- rr->length = 0;
- s->internal->packet_length = 0;
- goto err;
- }
+ if (alert_desc == SSL_AD_RECORD_OVERFLOW)
+ SSLerror(s, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ else if (alert_desc == SSL_AD_BAD_RECORD_MAC)
+ SSLerror(s, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
- if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) {
- al = SSL_AD_RECORD_OVERFLOW;
- SSLerror(s, SSL_R_DATA_LENGTH_TOO_LONG);
goto f_err;
}
+ rr->data = out;
+ rr->length = out_len;
rr->off = 0;
- /* So at this point the following is true
- * ssl->s3->internal->rrec.type is the type of record
- * ssl->s3->internal->rrec.length == number of bytes in record
- * ssl->s3->internal->rrec.off == offset to first valid byte
- * ssl->s3->internal->rrec.data == where to take bytes from, increment
- * after use :-).
- */
- /* we have pulled in a full packet so zero things */
s->internal->packet_length = 0;
+
return (1);
-f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
-err:
+ f_err:
+ ssl3_send_alert(s, SSL3_AL_FATAL, alert_desc);
+ err:
return (0);
}
diff --git a/lib/libssl/s3_cbc.c b/lib/libssl/s3_cbc.c
index 74e0562c2db..4f84c9485bd 100644
--- a/lib/libssl/s3_cbc.c
+++ b/lib/libssl/s3_cbc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: s3_cbc.c,v 1.22 2020/06/19 21:26:40 tb Exp $ */
+/* $OpenBSD: s3_cbc.c,v 1.23 2020/10/03 17:35:16 jsing Exp $ */
/* ====================================================================
* Copyright (c) 2012 The OpenSSL Project. All rights reserved.
*
@@ -101,7 +101,7 @@ constant_time_eq_8(unsigned int a, unsigned int b)
return DUPLICATE_MSB_TO_ALL_8(c);
}
-/* tls1_cbc_remove_padding removes the CBC padding from the decrypted, TLS, CBC
+/* ssl3_cbc_remove_padding removes the CBC padding from the decrypted, TLS, CBC
* record in |rec| in constant time and returns 1 if the padding is valid and
* -1 otherwise. It also removes any explicit IV from the start of the record
* without leaking any timing about whether there was enough space after the
@@ -113,26 +113,24 @@ constant_time_eq_8(unsigned int a, unsigned int b)
* 1: if the padding was valid
* -1: otherwise. */
int
-tls1_cbc_remove_padding(const SSL* s, SSL3_RECORD_INTERNAL *rec,
- unsigned int block_size, unsigned int mac_size)
+ssl3_cbc_remove_padding(SSL3_RECORD_INTERNAL *rec, unsigned int eiv_len,
+ unsigned int mac_size)
{
unsigned int padding_length, good, to_check, i;
const unsigned int overhead = 1 /* padding length byte */ + mac_size;
- /* Check if version requires explicit IV */
- if (SSL_USE_EXPLICIT_IV(s)) {
- /* These lengths are all public so we can test them in
- * non-constant time.
- */
- if (overhead + block_size > rec->length)
- return 0;
- /* We can now safely skip explicit IV */
- rec->data += block_size;
- rec->input += block_size;
- rec->length -= block_size;
- } else if (overhead > rec->length)
+ /*
+ * These lengths are all public so we can test them in
+ * non-constant time.
+ */
+ if (overhead + eiv_len > rec->length)
return 0;
+ /* We can now safely skip explicit IV, if any. */
+ rec->data += eiv_len;
+ rec->input += eiv_len;
+ rec->length -= eiv_len;
+
padding_length = rec->data[rec->length - 1];
good = constant_time_ge(rec->length, overhead + padding_length);
diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h
index 9a9ef592826..0dda3ecd019 100644
--- a/lib/libssl/ssl_locl.h
+++ b/lib/libssl/ssl_locl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_locl.h,v 1.295 2020/09/24 18:12:00 jsing Exp $ */
+/* $OpenBSD: ssl_locl.h,v 1.296 2020/10/03 17:35:16 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -477,6 +477,8 @@ struct tls12_record_layer;
struct tls12_record_layer *tls12_record_layer_new(void);
void tls12_record_layer_free(struct tls12_record_layer *rl);
+void tls12_record_layer_alert(struct tls12_record_layer *rl,
+ uint8_t *alert_desc);
void tls12_record_layer_set_version(struct tls12_record_layer *rl,
uint16_t version);
void tls12_record_layer_set_read_epoch(struct tls12_record_layer *rl,
@@ -497,6 +499,10 @@ int tls12_record_layer_set_read_cipher_hash(struct tls12_record_layer *rl,
EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *hash_ctx, int stream_mac);
int tls12_record_layer_set_write_cipher_hash(struct tls12_record_layer *rl,
EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *hash_ctx, int stream_mac);
+int tls12_record_layer_set_read_mac_key(struct tls12_record_layer *rl,
+ const uint8_t *mac_key, size_t mac_key_len);
+int tls12_record_layer_open_record(struct tls12_record_layer *rl,
+ uint8_t *buf, size_t buf_len, uint8_t **out, size_t *out_len);
int tls12_record_layer_seal_record(struct tls12_record_layer *rl,
uint8_t content_type, const uint8_t *content, size_t content_len,
CBB *out);
@@ -1361,9 +1367,7 @@ int tls1_transcript_record(SSL *s, const unsigned char *buf, size_t len);
void tls1_cleanup_key_block(SSL *s);
int tls1_change_cipher_state(SSL *s, int which);
int tls1_setup_key_block(SSL *s);
-int tls1_enc(SSL *s, int snd);
int tls1_final_finish_mac(SSL *s, const char *str, int slen, unsigned char *p);
-int tls1_mac(SSL *ssl, unsigned char *md, int snd);
int tls1_generate_master_secret(SSL *s, unsigned char *out,
unsigned char *p, int len);
int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
@@ -1411,8 +1415,8 @@ int tls1_check_ec_server_key(SSL *s);
/* s3_cbc.c */
void ssl3_cbc_copy_mac(unsigned char *out, const SSL3_RECORD_INTERNAL *rec,
unsigned int md_size, unsigned int orig_len);
-int tls1_cbc_remove_padding(const SSL *s, SSL3_RECORD_INTERNAL *rec,
- unsigned int block_size, unsigned int mac_size);
+int ssl3_cbc_remove_padding(SSL3_RECORD_INTERNAL *rec, unsigned int eiv_len,
+ unsigned int mac_size);
char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx);
int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx, unsigned char *md_out,
size_t *md_out_size, const unsigned char header[13],
diff --git a/lib/libssl/ssl_pkt.c b/lib/libssl/ssl_pkt.c
index c9c86471d3c..02a476ea82b 100644
--- a/lib/libssl/ssl_pkt.c
+++ b/lib/libssl/ssl_pkt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_pkt.c,v 1.31 2020/08/30 15:40:20 jsing Exp $ */
+/* $OpenBSD: ssl_pkt.c,v 1.32 2020/10/03 17:35:16 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -149,15 +149,14 @@ ssl_force_want_read(SSL *s)
static int
ssl3_read_n(SSL *s, int n, int max, int extend)
{
+ SSL3_BUFFER_INTERNAL *rb = &(S3I(s)->rbuf);
int i, len, left;
size_t align;
unsigned char *pkt;
- SSL3_BUFFER_INTERNAL *rb;
if (n <= 0)
return n;
- rb = &(S3I(s)->rbuf);
if (rb->buf == NULL)
if (!ssl3_setup_read_buffer(s))
return -1;
@@ -327,15 +326,13 @@ ssl3_packet_extend(SSL *s, int plen)
static int
ssl3_get_record(SSL *s)
{
- int al;
- int enc_err, n, i, ret = -1;
- SSL3_RECORD_INTERNAL *rr;
- SSL_SESSION *sess;
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int mac_size, orig_len;
-
- rr = &(S3I(s)->rrec);
- sess = s->session;
+ SSL3_BUFFER_INTERNAL *rb = &(S3I(s)->rbuf);
+ SSL3_RECORD_INTERNAL *rr = &(S3I(s)->rrec);
+ uint8_t alert_desc;
+ uint8_t *out;
+ size_t out_len;
+ int al, n;
+ int ret = -1;
again:
/* check if we have the header */
@@ -387,17 +384,13 @@ ssl3_get_record(SSL *s)
goto err;
}
- if (rr->length > S3I(s)->rbuf.len - SSL3_RT_HEADER_LENGTH) {
+ if (rr->length > rb->len - SSL3_RT_HEADER_LENGTH) {
al = SSL_AD_RECORD_OVERFLOW;
SSLerror(s, SSL_R_PACKET_LENGTH_TOO_LONG);
goto f_err;
}
-
- /* now s->internal->rstate == SSL_ST_READ_BODY */
}
- /* s->internal->rstate == SSL_ST_READ_BODY, get and decode the data */
-
n = ssl3_packet_extend(s, SSL3_RT_HEADER_LENGTH + rr->length);
if (n <= 0)
return (n);
@@ -406,133 +399,40 @@ ssl3_get_record(SSL *s)
s->internal->rstate = SSL_ST_READ_HEADER; /* set state for later operations */
- /* At this point, s->internal->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
- * and we have that many bytes in s->internal->packet
+ /*
+ * A full record has now been read from the wire, which now needs
+ * to be processed.
*/
- rr->input = &(s->internal->packet[SSL3_RT_HEADER_LENGTH]);
-
- /* ok, we can now read from 's->internal->packet' data into 'rr'
- * rr->input points at rr->length bytes, which
- * need to be copied into rr->data by either
- * the decryption or by the decompression
- * When the data is 'copied' into the rr->data buffer,
- * rr->input will be pointed at the new buffer */
-
- /* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
- * rr->length bytes of encrypted compressed stuff. */
-
- /* check is not needed I believe */
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
- al = SSL_AD_RECORD_OVERFLOW;
- SSLerror(s, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
- goto f_err;
- }
-
- /* decrypt in place in 'rr->input' */
- rr->data = rr->input;
+ tls12_record_layer_set_version(s->internal->rl, s->version);
- /* enc_err is:
- * 0: (in non-constant time) if the record is publically invalid.
- * 1: if the padding is valid
- * -1: if the padding is invalid */
- if ((enc_err = tls1_enc(s, 0)) == 0) {
- al = SSL_AD_BAD_RECORD_MAC;
- SSLerror(s, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
- goto f_err;
- }
-
- /* r->length is now the compressed data plus mac */
- if ((sess != NULL) && (s->enc_read_ctx != NULL) &&
- (EVP_MD_CTX_md(s->read_hash) != NULL)) {
- /* s->read_hash != NULL => mac_size != -1 */
- unsigned char *mac = NULL;
- unsigned char mac_tmp[EVP_MAX_MD_SIZE];
-
- mac_size = EVP_MD_CTX_size(s->read_hash);
- OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
-
- orig_len = rr->length + rr->padding_length;
+ if (!tls12_record_layer_open_record(s->internal->rl, s->internal->packet,
+ s->internal->packet_length, &out, &out_len)) {
+ tls12_record_layer_alert(s->internal->rl, &alert_desc);
- /* orig_len is the length of the record before any padding was
- * removed. This is public information, as is the MAC in use,
- * therefore we can safely process the record in a different
- * amount of time if it's too short to possibly contain a MAC.
- */
- if (orig_len < mac_size ||
- /* CBC records must have a padding length byte too. */
- (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
- orig_len < mac_size + 1)) {
- al = SSL_AD_DECODE_ERROR;
- SSLerror(s, SSL_R_LENGTH_TOO_SHORT);
- goto f_err;
- }
-
- if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) {
- /* We update the length so that the TLS header bytes
- * can be constructed correctly but we need to extract
- * the MAC in constant time from within the record,
- * without leaking the contents of the padding bytes.
- * */
- mac = mac_tmp;
- ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
- rr->length -= mac_size;
- } else {
- /* In this case there's no padding, so |orig_len|
- * equals |rec->length| and we checked that there's
- * enough bytes for |mac_size| above. */
- rr->length -= mac_size;
- mac = &rr->data[rr->length];
- }
+ if (alert_desc == 0)
+ goto err;
- i = tls1_mac(s,md,0 /* not send */);
- if (i < 0 || mac == NULL ||
- timingsafe_memcmp(md, mac, (size_t)mac_size) != 0)
- enc_err = -1;
- if (rr->length >
- SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
- enc_err = -1;
- }
+ if (alert_desc == SSL_AD_RECORD_OVERFLOW)
+ SSLerror(s, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ else if (alert_desc == SSL_AD_BAD_RECORD_MAC)
+ SSLerror(s, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
- if (enc_err < 0) {
- /*
- * A separate 'decryption_failed' alert was introduced with
- * TLS 1.0, SSL 3.0 only has 'bad_record_mac'. But unless a
- * decryption failure is directly visible from the ciphertext
- * anyway, we should not reveal which kind of error
- * occurred -- this might become visible to an attacker
- * (e.g. via a logfile)
- */
- al = SSL_AD_BAD_RECORD_MAC;
- SSLerror(s, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
- goto f_err;
- }
-
- if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) {
- al = SSL_AD_RECORD_OVERFLOW;
- SSLerror(s, SSL_R_DATA_LENGTH_TOO_LONG);
+ al = alert_desc;
goto f_err;
}
+ rr->data = out;
+ rr->length = out_len;
rr->off = 0;
- /*
- * So at this point the following is true
- *
- * ssl->s3->internal->rrec.type is the type of record
- * ssl->s3->internal->rrec.length == number of bytes in record
- * ssl->s3->internal->rrec.off == offset to first valid byte
- * ssl->s3->internal->rrec.data == where to take bytes from, increment
- * after use :-).
- */
/* we have pulled in a full packet so zero things */
s->internal->packet_length = 0;
if (rr->length == 0) {
/*
- * CBC countermeasures for known IV weaknesses
- * can legitimately insert a single empty record,
- * so we allow ourselves to read once past a single
- * empty record without forcing want_read.
+ * CBC countermeasures for known IV weaknesses can legitimately
+ * insert a single empty record, so we allow ourselves to read
+ * once past a single empty record without forcing want_read.
*/
if (s->internal->empty_record_count++ > SSL_MAX_EMPTY_RECORDS) {
SSLerror(s, SSL_R_PEER_BEHAVING_BADLY);
@@ -543,15 +443,15 @@ ssl3_get_record(SSL *s)
return -1;
}
goto again;
- } else {
- s->internal->empty_record_count = 0;
}
+ s->internal->empty_record_count = 0;
+
return (1);
-f_err:
+ f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
-err:
+ err:
return (ret);
}
diff --git a/lib/libssl/t1_enc.c b/lib/libssl/t1_enc.c
index a66c82bdca6..7a71a084349 100644
--- a/lib/libssl/t1_enc.c
+++ b/lib/libssl/t1_enc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: t1_enc.c,v 1.123 2020/08/30 15:40:20 jsing Exp $ */
+/* $OpenBSD: t1_enc.c,v 1.124 2020/10/03 17:35:16 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -440,6 +440,10 @@ tls1_change_cipher_state_cipher(SSL *s, char is_read,
if (!tls12_record_layer_set_read_cipher_hash(s->internal->rl,
cipher_ctx, mac_ctx, stream_mac))
goto err;
+
+ if (!tls12_record_layer_set_read_mac_key(s->internal->rl,
+ S3I(s)->read_mac_secret, mac_secret_size))
+ goto err;
} else {
if (stream_mac)
s->internal->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
@@ -672,260 +676,6 @@ tls1_setup_key_block(SSL *s)
return (ret);
}
-/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
- *
- * Returns:
- * 0: (in non-constant time) if the record is publically invalid (i.e. too
- * short etc).
- * 1: if the record's padding is valid / the encryption was successful.
- * -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
- * an internal error occured.
- */
-int
-tls1_enc(SSL *s, int send)
-{
- const SSL_AEAD_CTX *aead;
- const EVP_CIPHER *enc;
- EVP_CIPHER_CTX *ds;
- SSL3_RECORD_INTERNAL *rec;
- unsigned char *seq;
- unsigned long l;
- int bs, i, j, k, ret, mac_size = 0;
-
- if (send) {
- /* No longer supported. */
- return -1;
- } else {
- aead = s->internal->aead_read_ctx;
- rec = &S3I(s)->rrec;
- seq = S3I(s)->read_sequence;
- }
-
- if (aead) {
- unsigned char ad[13], *in, *out, nonce[16];
- size_t out_len, pad_len = 0;
- unsigned int nonce_used;
-
- if (SSL_IS_DTLS(s)) {
- dtls1_build_sequence_number(ad, seq,
- send ? D1I(s)->w_epoch : D1I(s)->r_epoch);
- } else {
- memcpy(ad, seq, SSL3_SEQUENCE_SIZE);
- tls1_record_sequence_increment(seq);
- }
-
- ad[8] = rec->type;
- ad[9] = (unsigned char)(s->version >> 8);
- ad[10] = (unsigned char)(s->version);
-
- if (aead->variable_nonce_len > 8 ||
- aead->variable_nonce_len > sizeof(nonce))
- return -1;
-
- if (aead->xor_fixed_nonce) {
- if (aead->fixed_nonce_len > sizeof(nonce) ||
- aead->variable_nonce_len > aead->fixed_nonce_len)
- return -1; /* Should never happen. */
- pad_len = aead->fixed_nonce_len - aead->variable_nonce_len;
- } else {
- if (aead->fixed_nonce_len +
- aead->variable_nonce_len > sizeof(nonce))
- return -1; /* Should never happen. */
- }
-
- if (send) {
- size_t len = rec->length;
- size_t eivlen = 0;
- in = rec->input;
- out = rec->data;
-
- if (aead->xor_fixed_nonce) {
- /*
- * The sequence number is left zero
- * padded, then xored with the fixed
- * nonce.
- */
- memset(nonce, 0, pad_len);
- memcpy(nonce + pad_len, ad,
- aead->variable_nonce_len);
- for (i = 0; i < aead->fixed_nonce_len; i++)
- nonce[i] ^= aead->fixed_nonce[i];
- nonce_used = aead->fixed_nonce_len;
- } else {
- /*
- * When sending we use the sequence number as
- * the variable part of the nonce.
- */
- memcpy(nonce, aead->fixed_nonce,
- aead->fixed_nonce_len);
- nonce_used = aead->fixed_nonce_len;
- memcpy(nonce + nonce_used, ad,
- aead->variable_nonce_len);
- nonce_used += aead->variable_nonce_len;
- }
-
- /*
- * In do_ssl3_write, rec->input is moved forward by
- * variable_nonce_len in order to leave space for the
- * variable nonce. Thus we can copy the sequence number
- * bytes into place without overwriting any of the
- * plaintext.
- */
- if (aead->variable_nonce_in_record) {
- memcpy(out, ad, aead->variable_nonce_len);
- len -= aead->variable_nonce_len;
- eivlen = aead->variable_nonce_len;
- }
-
- ad[11] = len >> 8;
- ad[12] = len & 0xff;
-
- if (!EVP_AEAD_CTX_seal(&aead->ctx,
- out + eivlen, &out_len, len + aead->tag_len, nonce,
- nonce_used, in + eivlen, len, ad, sizeof(ad)))
- return -1;
- if (aead->variable_nonce_in_record)
- out_len += aead->variable_nonce_len;
- } else {
- /* receive */
- size_t len = rec->length;
-
- if (rec->data != rec->input)
- return -1; /* internal error - should never happen. */
- out = in = rec->input;
-
- if (len < aead->variable_nonce_len)
- return 0;
-
- if (aead->xor_fixed_nonce) {
- /*
- * The sequence number is left zero
- * padded, then xored with the fixed
- * nonce.
- */
- memset(nonce, 0, pad_len);
- memcpy(nonce + pad_len, ad,
- aead->variable_nonce_len);
- for (i = 0; i < aead->fixed_nonce_len; i++)
- nonce[i] ^= aead->fixed_nonce[i];
- nonce_used = aead->fixed_nonce_len;
- } else {
- memcpy(nonce, aead->fixed_nonce,
- aead->fixed_nonce_len);
- nonce_used = aead->fixed_nonce_len;
-
- memcpy(nonce + nonce_used,
- aead->variable_nonce_in_record ? in : ad,
- aead->variable_nonce_len);
- nonce_used += aead->variable_nonce_len;
- }
-
- if (aead->variable_nonce_in_record) {
- in += aead->variable_nonce_len;
- len -= aead->variable_nonce_len;
- out += aead->variable_nonce_len;
- }
-
- if (len < aead->tag_len)
- return 0;
- len -= aead->tag_len;
-
- ad[11] = len >> 8;
- ad[12] = len & 0xff;
-
- if (!EVP_AEAD_CTX_open(&aead->ctx, out, &out_len, len,
- nonce, nonce_used, in, len + aead->tag_len, ad,
- sizeof(ad)))
- return -1;
-
- rec->data = rec->input = out;
- }
-
- rec->length = out_len;
-
- return 1;
- }
-
- if (send) {
- if (EVP_MD_CTX_md(s->internal->write_hash)) {
- int n = EVP_MD_CTX_size(s->internal->write_hash);
- OPENSSL_assert(n >= 0);
- }
- ds = s->internal->enc_write_ctx;
- if (s->internal->enc_write_ctx == NULL)
- enc = NULL;
- else {
- int ivlen = 0;
- enc = EVP_CIPHER_CTX_cipher(s->internal->enc_write_ctx);
- if (SSL_USE_EXPLICIT_IV(s) &&
- EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE)
- ivlen = EVP_CIPHER_iv_length(enc);
- if (ivlen > 1) {
- if (rec->data != rec->input) {
-#ifdef DEBUG
- /* we can't write into the input stream:
- * Can this ever happen?? (steve)
- */
- fprintf(stderr,
- "%s:%d: rec->data != rec->input\n",
- __FILE__, __LINE__);
-#endif
- } else
- arc4random_buf(rec->input, ivlen);
- }
- }
- } else {
- if (EVP_MD_CTX_md(s->read_hash)) {
- int n = EVP_MD_CTX_size(s->read_hash);
- OPENSSL_assert(n >= 0);
- }
- ds = s->enc_read_ctx;
- if (s->enc_read_ctx == NULL)
- enc = NULL;
- else
- enc = EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
- }
-
- if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) {
- memmove(rec->data, rec->input, rec->length);
- rec->input = rec->data;
- ret = 1;
- } else {
- l = rec->length;
- bs = EVP_CIPHER_block_size(ds->cipher);
-
- if (bs != 1 && send) {
- i = bs - ((int)l % bs);
-
- /* Add weird padding of upto 256 bytes */
-
- /* we need to add 'i' padding bytes of value j */
- j = i - 1;
- for (k = (int)l; k < (int)(l + i); k++)
- rec->input[k] = j;
- l += i;
- rec->length += i;
- }
-
- if (!send) {
- if (l == 0 || l % bs != 0)
- return 0;
- }
-
- i = EVP_Cipher(ds, rec->data, rec->input, l);
- if ((EVP_CIPHER_flags(ds->cipher) &
- EVP_CIPH_FLAG_CUSTOM_CIPHER) ? (i < 0) : (i == 0))
- return -1; /* AEAD can fail to verify MAC */
-
- ret = 1;
- if (EVP_MD_CTX_md(s->read_hash) != NULL)
- mac_size = EVP_MD_CTX_size(s->read_hash);
- if ((bs != 1) && !send)
- ret = tls1_cbc_remove_padding(s, rec, bs, mac_size);
- }
- return ret;
-}
-
int
tls1_final_finish_mac(SSL *s, const char *str, int str_len, unsigned char *out)
{
@@ -947,85 +697,6 @@ tls1_final_finish_mac(SSL *s, const char *str, int str_len, unsigned char *out)
}
int
-tls1_mac(SSL *ssl, unsigned char *md, int send)
-{
- SSL3_RECORD_INTERNAL *rec;
- unsigned char *seq;
- EVP_MD_CTX *hash;
- size_t md_size, orig_len;
- EVP_MD_CTX hmac, *mac_ctx;
- unsigned char header[13];
- int stream_mac = (send ?
- (ssl->internal->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM) :
- (ssl->internal->mac_flags & SSL_MAC_FLAG_READ_MAC_STREAM));
- int t;
-
- if (send) {
- /* No longer supported. */
- return -1;
- } else {
- rec = &(ssl->s3->internal->rrec);
- seq = &(ssl->s3->internal->read_sequence[0]);
- hash = ssl->read_hash;
- }
-
- t = EVP_MD_CTX_size(hash);
- OPENSSL_assert(t >= 0);
- md_size = t;
-
- /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
- if (stream_mac) {
- mac_ctx = hash;
- } else {
- if (!EVP_MD_CTX_copy(&hmac, hash))
- return -1;
- mac_ctx = &hmac;
- }
-
- if (SSL_IS_DTLS(ssl))
- dtls1_build_sequence_number(header, seq,
- send ? D1I(ssl)->w_epoch : D1I(ssl)->r_epoch);
- else
- memcpy(header, seq, SSL3_SEQUENCE_SIZE);
-
- orig_len = rec->length + md_size + rec->padding_length;
-
- header[8] = rec->type;
- header[9] = (unsigned char)(ssl->version >> 8);
- header[10] = (unsigned char)(ssl->version);
- header[11] = (rec->length) >> 8;
- header[12] = (rec->length) & 0xff;
-
- if (!send &&
- EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
- ssl3_cbc_record_digest_supported(mac_ctx)) {
- /* This is a CBC-encrypted record. We must avoid leaking any
- * timing-side channel information about how many blocks of
- * data we are hashing because that gives an attacker a
- * timing-oracle. */
- if (!ssl3_cbc_digest_record(mac_ctx,
- md, &md_size, header, rec->input,
- rec->length + md_size, orig_len,
- ssl->s3->internal->read_mac_secret,
- ssl->s3->internal->read_mac_secret_size))
- return -1;
- } else {
- EVP_DigestSignUpdate(mac_ctx, header, sizeof(header));
- EVP_DigestSignUpdate(mac_ctx, rec->input, rec->length);
- t = EVP_DigestSignFinal(mac_ctx, md, &md_size);
- OPENSSL_assert(t > 0);
- }
-
- if (!stream_mac)
- EVP_MD_CTX_cleanup(&hmac);
-
- if (!SSL_IS_DTLS(ssl))
- tls1_record_sequence_increment(seq);
-
- return (md_size);
-}
-
-int
tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
int len)
{
diff --git a/lib/libssl/tls12_record_layer.c b/lib/libssl/tls12_record_layer.c
index 10d0f1194b4..56ff94d95c9 100644
--- a/lib/libssl/tls12_record_layer.c
+++ b/lib/libssl/tls12_record_layer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls12_record_layer.c,v 1.4 2020/09/16 17:15:01 jsing Exp $ */
+/* $OpenBSD: tls12_record_layer.c,v 1.5 2020/10/03 17:35:17 jsing Exp $ */
/*
* Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
*
@@ -25,6 +25,8 @@ struct tls12_record_layer {
uint16_t version;
int dtls;
+ uint8_t alert_desc;
+
uint16_t read_epoch;
uint16_t write_epoch;
@@ -43,6 +45,9 @@ struct tls12_record_layer {
EVP_CIPHER_CTX *write_cipher_ctx;
EVP_MD_CTX *write_hash_ctx;
+ const uint8_t *read_mac_key;
+ size_t read_mac_key_len;
+
uint8_t *read_seq_num;
uint8_t *write_seq_num;
};
@@ -65,6 +70,12 @@ tls12_record_layer_free(struct tls12_record_layer *rl)
}
void
+tls12_record_layer_alert(struct tls12_record_layer *rl, uint8_t *alert_desc)
+{
+ *alert_desc = rl->alert_desc;
+}
+
+void
tls12_record_layer_set_version(struct tls12_record_layer *rl, uint16_t version)
{
rl->version = version;
@@ -111,6 +122,7 @@ void
tls12_record_layer_clear_read_state(struct tls12_record_layer *rl)
{
tls12_record_layer_set_read_state(rl, NULL, NULL, NULL, 0);
+ tls12_record_layer_set_read_mac_key(rl, NULL, 0);
rl->read_seq_num = NULL;
}
@@ -173,6 +185,16 @@ tls12_record_layer_set_write_cipher_hash(struct tls12_record_layer *rl,
return 1;
}
+int
+tls12_record_layer_set_read_mac_key(struct tls12_record_layer *rl,
+ const uint8_t *mac_key, size_t mac_key_len)
+{
+ rl->read_mac_key = mac_key;
+ rl->read_mac_key_len = mac_key_len;
+
+ return 1;
+}
+
static int
tls12_record_layer_build_seq_num(struct tls12_record_layer *rl, CBB *cbb,
uint16_t epoch, uint8_t *seq_num, size_t seq_num_len)
@@ -234,7 +256,7 @@ tls12_record_layer_mac(struct tls12_record_layer *rl, CBB *cbb,
{
EVP_MD_CTX *mac_ctx = NULL;
uint8_t *header = NULL;
- size_t header_len;
+ size_t header_len = 0;
size_t mac_len;
uint8_t *mac;
int ret = 0;
@@ -258,6 +280,8 @@ tls12_record_layer_mac(struct tls12_record_layer *rl, CBB *cbb,
goto err;
if (EVP_DigestSignFinal(mac_ctx, mac, &mac_len) <= 0)
goto err;
+ if (mac_len == 0)
+ goto err;
if (stream_mac) {
if (!EVP_MD_CTX_copy(hash_ctx, mac_ctx))
@@ -269,12 +293,67 @@ tls12_record_layer_mac(struct tls12_record_layer *rl, CBB *cbb,
err:
EVP_MD_CTX_free(mac_ctx);
- free(header);
+ freezero(header, header_len);
return ret;
}
static int
+tls12_record_layer_read_mac_cbc(struct tls12_record_layer *rl, CBB *cbb,
+ uint8_t content_type, const uint8_t *content, size_t content_len,
+ size_t mac_len, size_t padding_len)
+{
+ uint8_t *header = NULL;
+ size_t header_len = 0;
+ uint8_t *mac = NULL;
+ size_t out_mac_len = 0;
+ int ret = 0;
+
+ /*
+ * Must be constant time to avoid leaking details about CBC padding.
+ */
+
+ if (!ssl3_cbc_record_digest_supported(rl->read_hash_ctx))
+ goto err;
+
+ if (!tls12_record_layer_pseudo_header(rl, content_type, content_len,
+ rl->read_epoch, rl->read_seq_num, SSL3_SEQUENCE_SIZE,
+ &header, &header_len))
+ goto err;
+
+ if (!CBB_add_space(cbb, &mac, mac_len))
+ goto err;
+ if (!ssl3_cbc_digest_record(rl->read_hash_ctx, mac, &out_mac_len, header,
+ content, content_len + mac_len, content_len + mac_len + padding_len,
+ rl->read_mac_key, rl->read_mac_key_len))
+ goto err;
+ if (mac_len != out_mac_len)
+ goto err;
+
+ ret = 1;
+
+ err:
+ freezero(header, header_len);
+
+ return ret;
+}
+
+static int
+tls12_record_layer_read_mac(struct tls12_record_layer *rl, CBB *cbb,
+ uint8_t content_type, const uint8_t *content, size_t content_len)
+{
+ EVP_CIPHER_CTX *enc = rl->read_cipher_ctx;
+ size_t out_len;
+
+ if (EVP_CIPHER_CTX_mode(enc) == EVP_CIPH_CBC_MODE)
+ return 0;
+
+ return tls12_record_layer_mac(rl, cbb, rl->read_hash_ctx,
+ rl->read_stream_mac, rl->read_epoch, rl->read_seq_num,
+ SSL3_SEQUENCE_SIZE, content_type, content, content_len, &out_len);
+}
+
+static int
tls12_record_layer_write_mac(struct tls12_record_layer *rl, CBB *cbb,
uint8_t content_type, const uint8_t *content, size_t content_len,
size_t *out_len)
@@ -286,7 +365,8 @@ tls12_record_layer_write_mac(struct tls12_record_layer *rl, CBB *cbb,
static int
tls12_record_layer_aead_concat_nonce(struct tls12_record_layer *rl,
- const SSL_AEAD_CTX *aead, uint8_t *seq_num, uint8_t **out, size_t *out_len)
+ const SSL_AEAD_CTX *aead, const uint8_t *seq_num,
+ uint8_t **out, size_t *out_len)
{
CBB cbb;
@@ -314,7 +394,8 @@ tls12_record_layer_aead_concat_nonce(struct tls12_record_layer *rl,
static int
tls12_record_layer_aead_xored_nonce(struct tls12_record_layer *rl,
- const SSL_AEAD_CTX *aead, uint8_t *seq_num, uint8_t **out, size_t *out_len)
+ const SSL_AEAD_CTX *aead, const uint8_t *seq_num,
+ uint8_t **out, size_t *out_len)
{
uint8_t *nonce = NULL;
size_t nonce_len = 0;
@@ -357,6 +438,263 @@ tls12_record_layer_aead_xored_nonce(struct tls12_record_layer *rl,
}
static int
+tls12_record_layer_open_record_plaintext(struct tls12_record_layer *rl,
+ uint8_t content_type, CBS *fragment, uint8_t **out, size_t *out_len)
+{
+ if (rl->read_aead_ctx != NULL || rl->read_cipher_ctx != NULL)
+ return 0;
+
+ /* XXX - decrypt/process in place for now. */
+ *out = (uint8_t *)CBS_data(fragment);
+ *out_len = CBS_len(fragment);
+
+ return 1;
+}
+
+static int
+tls12_record_layer_open_record_protected_aead(struct tls12_record_layer *rl,
+ uint8_t content_type, CBS *fragment, uint8_t **out, size_t *out_len)
+{
+ const SSL_AEAD_CTX *aead = rl->read_aead_ctx;
+ uint8_t *header = NULL, *nonce = NULL;
+ size_t header_len = 0, nonce_len = 0;
+ uint8_t *plain;
+ size_t plain_len;
+ uint16_t epoch = 0;
+ CBS var_nonce;
+ int ret = 0;
+
+ /* XXX - move to nonce allocated in record layer, matching TLSv1.3 */
+ if (aead->xor_fixed_nonce) {
+ if (!tls12_record_layer_aead_xored_nonce(rl, aead,
+ rl->read_seq_num, &nonce, &nonce_len))
+ goto err;
+ } else if (aead->variable_nonce_in_record) {
+ if (!CBS_get_bytes(fragment, &var_nonce,
+ aead->variable_nonce_len))
+ goto err;
+ if (!tls12_record_layer_aead_concat_nonce(rl, aead,
+ CBS_data(&var_nonce), &nonce, &nonce_len))
+ goto err;
+ } else {
+ if (!tls12_record_layer_aead_concat_nonce(rl, aead,
+ rl->read_seq_num, &nonce, &nonce_len))
+ goto err;
+ }
+
+ /* XXX EVP_AEAD_max_tag_len vs EVP_AEAD_CTX_tag_len. */
+ if (CBS_len(fragment) < aead->tag_len) {
+ rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
+ goto err;
+ }
+ if (CBS_len(fragment) > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+ rl->alert_desc = SSL_AD_RECORD_OVERFLOW;
+ goto err;
+ }
+
+ /* XXX - decrypt/process in place for now. */
+ plain = (uint8_t *)CBS_data(fragment);
+ plain_len = CBS_len(fragment) - aead->tag_len;
+
+ if (!tls12_record_layer_pseudo_header(rl, content_type, plain_len,
+ epoch, rl->read_seq_num, SSL3_SEQUENCE_SIZE, &header, &header_len))
+ goto err;
+
+ if (!EVP_AEAD_CTX_open(&aead->ctx, plain, out_len, plain_len,
+ nonce, nonce_len, CBS_data(fragment), CBS_len(fragment),
+ header, header_len)) {
+ rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
+ goto err;
+ }
+
+ if (*out_len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ rl->alert_desc = SSL_AD_RECORD_OVERFLOW;
+ goto err;
+ }
+
+ if (*out_len != plain_len)
+ goto err;
+
+ *out = plain;
+
+ ret = 1;
+
+ err:
+ freezero(header, header_len);
+ freezero(nonce, nonce_len);
+
+ return ret;
+}
+
+static int
+tls12_record_layer_open_record_protected_cipher(struct tls12_record_layer *rl,
+ uint8_t content_type, CBS *fragment, uint8_t **out, size_t *out_len)
+{
+ EVP_CIPHER_CTX *enc = rl->read_cipher_ctx;
+ SSL3_RECORD_INTERNAL rrec;
+ int block_size, eiv_len;
+ uint8_t *mac = NULL;
+ int mac_len = 0;
+ uint8_t *out_mac = NULL;
+ size_t out_mac_len = 0;
+ uint8_t *plain;
+ size_t plain_len;
+ size_t min_len;
+ CBB cbb_mac;
+ int ret = 0;
+
+ memset(&cbb_mac, 0, sizeof(cbb_mac));
+
+ block_size = EVP_CIPHER_CTX_block_size(enc);
+ if (block_size < 0 || block_size > EVP_MAX_BLOCK_LENGTH)
+ goto err;
+
+ /* Determine explicit IV length. */
+ eiv_len = 0;
+ if (rl->version != TLS1_VERSION &&
+ EVP_CIPHER_CTX_mode(enc) == EVP_CIPH_CBC_MODE)
+ eiv_len = EVP_CIPHER_CTX_iv_length(enc);
+ if (eiv_len < 0 || eiv_len > EVP_MAX_IV_LENGTH)
+ goto err;
+
+ mac_len = 0;
+ if (rl->read_hash_ctx != NULL) {
+ mac_len = EVP_MD_CTX_size(rl->read_hash_ctx);
+ if (mac_len <= 0 || mac_len > EVP_MAX_MD_SIZE)
+ goto err;
+ }
+
+ /* CBC has at least one padding byte. */
+ min_len = eiv_len + mac_len;
+ if (EVP_CIPHER_CTX_mode(enc) == EVP_CIPH_CBC_MODE)
+ min_len += 1;
+
+ if (CBS_len(fragment) < min_len) {
+ rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
+ goto err;
+ }
+ if (CBS_len(fragment) > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+ rl->alert_desc = SSL_AD_RECORD_OVERFLOW;
+ goto err;
+ }
+ if (CBS_len(fragment) % block_size != 0) {
+ rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
+ goto err;
+ }
+
+ /* XXX - decrypt/process in place for now. */
+ plain = (uint8_t *)CBS_data(fragment);
+ plain_len = CBS_len(fragment);
+
+ if (!EVP_Cipher(enc, plain, CBS_data(fragment), plain_len))
+ goto err;
+
+ rrec.data = plain;
+ rrec.input = plain;
+ rrec.length = plain_len;
+
+ /*
+ * We now have to remove padding, extract MAC, calculate MAC
+ * and compare MAC in constant time.
+ */
+ if (block_size > 1)
+ ssl3_cbc_remove_padding(&rrec, eiv_len, mac_len);
+
+ if ((mac = calloc(1, mac_len)) == NULL)
+ goto err;
+
+ if (!CBB_init(&cbb_mac, EVP_MAX_MD_SIZE))
+ goto err;
+ if (EVP_CIPHER_CTX_mode(enc) == EVP_CIPH_CBC_MODE) {
+ ssl3_cbc_copy_mac(mac, &rrec, mac_len, rrec.length +
+ rrec.padding_length);
+ rrec.length -= mac_len;
+ if (!tls12_record_layer_read_mac_cbc(rl, &cbb_mac, content_type,
+ rrec.input, rrec.length, mac_len, rrec.padding_length))
+ goto err;
+ } else {
+ rrec.length -= mac_len;
+ memcpy(mac, rrec.data + rrec.length, mac_len);
+ if (!tls12_record_layer_read_mac(rl, &cbb_mac, content_type,
+ rrec.input, rrec.length))
+ goto err;
+ }
+ if (!CBB_finish(&cbb_mac, &out_mac, &out_mac_len))
+ goto err;
+ if (mac_len != out_mac_len)
+ goto err;
+
+ if (timingsafe_memcmp(mac, out_mac, mac_len) != 0) {
+ rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
+ goto err;
+ }
+
+ if (rrec.length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_len) {
+ rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
+ goto err;
+ }
+ if (rrec.length > SSL3_RT_MAX_PLAIN_LENGTH) {
+ rl->alert_desc = SSL_AD_RECORD_OVERFLOW;
+ goto err;
+ }
+
+ *out = rrec.data;
+ *out_len = rrec.length;
+
+ ret = 1;
+
+ err:
+ CBB_cleanup(&cbb_mac);
+ freezero(mac, mac_len);
+ freezero(out_mac, out_mac_len);
+
+ return ret;
+}
+
+int
+tls12_record_layer_open_record(struct tls12_record_layer *rl, uint8_t *buf,
+ size_t buf_len, uint8_t **out, size_t *out_len)
+{
+ CBS cbs, fragment, seq_no;
+ uint16_t epoch, version;
+ uint8_t content_type;
+
+ CBS_init(&cbs, buf, buf_len);
+
+ if (!CBS_get_u8(&cbs, &content_type))
+ return 0;
+ if (!CBS_get_u16(&cbs, &version))
+ return 0;
+ if (rl->dtls) {
+ if (!CBS_get_u16(&cbs, &epoch))
+ return 0;
+ if (!CBS_get_bytes(&cbs, &seq_no, 6))
+ return 0;
+ }
+ if (!CBS_get_u16_length_prefixed(&cbs, &fragment))
+ return 0;
+
+ if (rl->read_aead_ctx != NULL) {
+ if (!tls12_record_layer_open_record_protected_aead(rl,
+ content_type, &fragment, out, out_len))
+ return 0;
+ } else if (rl->read_cipher_ctx != NULL) {
+ if (!tls12_record_layer_open_record_protected_cipher(rl,
+ content_type, &fragment, out, out_len))
+ return 0;
+ } else {
+ if (!tls12_record_layer_open_record_plaintext(rl,
+ content_type, &fragment, out, out_len))
+ return 0;
+ }
+
+ if (!rl->dtls)
+ tls1_record_sequence_increment(rl->read_seq_num);
+
+ return 1;
+}
+
+static int
tls12_record_layer_seal_record_plaintext(struct tls12_record_layer *rl,
uint8_t content_type, const uint8_t *content, size_t content_len, CBB *out)
{