summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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)
{