#include "tls13_internal.h"
#include "tls13_record.h"
#include "tls_content.h"
static ssize_t tls13_record_layer_write_chunk(struct tls13_record_layer *rl,
uint8_t content_type, const uint8_t *buf, size_t n);
static ssize_t tls13_record_layer_write_record(struct tls13_record_layer *rl,
uint8_t content_type, const uint8_t *content, size_t content_len);
struct tls13_record_protection {
EVP_AEAD_CTX *aead_ctx;
struct tls13_secret iv;
struct tls13_secret nonce;
uint8_t seq_num[TLS13_RECORD_SEQ_NUM_LEN];
};
struct tls13_record_protection *
tls13_record_protection_new(void)
{
return calloc(1, sizeof(struct tls13_record_protection));
}
void
tls13_record_protection_clear(struct tls13_record_protection *rp)
{
EVP_AEAD_CTX_free(rp->aead_ctx);
tls13_secret_cleanup(&rp->iv);
tls13_secret_cleanup(&rp->nonce);
memset(rp, 0, sizeof(*rp));
}
void
tls13_record_protection_free(struct tls13_record_protection *rp)
{
if (rp == NULL)
return;
tls13_record_protection_clear(rp);
freezero(rp, sizeof(struct tls13_record_protection));
}
struct tls13_record_layer {
uint16_t legacy_version;
int ccs_allowed;
int ccs_seen;
int ccs_sent;
int handshake_completed;
int legacy_alerts_allowed;
int phh;
int phh_retry;
int read_closed;
int write_closed;
struct tls13_record *rrec;
struct tls13_record *wrec;
uint8_t wrec_content_type;
size_t wrec_appdata_len;
size_t wrec_content_len;
uint8_t alert;
uint8_t *alert_data;
size_t alert_len;
uint8_t alert_level;
uint8_t alert_desc;
CBS phh_cbs;
uint8_t *phh_data;
size_t phh_len;
struct tls_content *rcontent;
const EVP_MD *hash;
const EVP_AEAD *aead;
struct tls13_record_protection *read;
struct tls13_record_protection *write;
struct tls13_record_layer_callbacks cb;
void *cb_arg;
};
static void
tls13_record_layer_rrec_free(struct tls13_record_layer *rl)
{
tls13_record_free(rl->rrec);
rl->rrec = NULL;
}
static void
tls13_record_layer_wrec_free(struct tls13_record_layer *rl)
{
tls13_record_free(rl->wrec);
rl->wrec = NULL;
}
struct tls13_record_layer *
tls13_record_layer_new(const struct tls13_record_layer_callbacks *callbacks,
void *cb_arg)
{
struct tls13_record_layer *rl;
if ((rl = calloc(1, sizeof(struct tls13_record_layer))) == NULL)
goto err;
if ((rl->rcontent = tls_content_new()) == NULL)
goto err;
if ((rl->read = tls13_record_protection_new()) == NULL)
goto err;
if ((rl->write = tls13_record_protection_new()) == NULL)
goto err;
rl->legacy_version = TLS1_2_VERSION;
tls13_record_layer_set_callbacks(rl, callbacks, cb_arg);
return rl;
err:
tls13_record_layer_free(rl);
return NULL;
}
void
tls13_record_layer_free(struct tls13_record_layer *rl)
{
if (rl == NULL)
return;
tls13_record_layer_rrec_free(rl);
tls13_record_layer_wrec_free(rl);
freezero(rl->alert_data, rl->alert_len);
freezero(rl->phh_data, rl->phh_len);
tls_content_free(rl->rcontent);
tls13_record_protection_free(rl->read);
tls13_record_protection_free(rl->write);
freezero(rl, sizeof(struct tls13_record_layer));
}
void
tls13_record_layer_set_callbacks(struct tls13_record_layer *rl,
const struct tls13_record_layer_callbacks *callbacks, void *cb_arg)
{
rl->cb = *callbacks;
rl->cb_arg = cb_arg;
}
void
tls13_record_layer_rcontent(struct tls13_record_layer *rl, CBS *cbs)
{
CBS_dup(tls_content_cbs(rl->rcontent), cbs);
}
static const uint8_t tls13_max_seq_num[TLS13_RECORD_SEQ_NUM_LEN] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
int
tls13_record_layer_inc_seq_num(uint8_t *seq_num)
{
int i;
if (memcmp(seq_num, tls13_max_seq_num, TLS13_RECORD_SEQ_NUM_LEN) == 0)
return 0;
for (i = TLS13_RECORD_SEQ_NUM_LEN - 1; i >= 0; i--) {
if (++seq_num[i] != 0)
break;
}
return 1;
}
static int
tls13_record_layer_update_nonce(struct tls13_secret *nonce,
struct tls13_secret *iv, uint8_t *seq_num)
{
ssize_t i, j;
if (nonce->len != iv->len)
return 0;
for (i = nonce->len - 1, j = TLS13_RECORD_SEQ_NUM_LEN - 1; i >= 0; i--, j--)
nonce->data[i] = iv->data[i] ^ (j >= 0 ? seq_num[j] : 0);
return 1;
}
void
tls13_record_layer_allow_ccs(struct tls13_record_layer *rl, int allow)
{
rl->ccs_allowed = allow;
}
void
tls13_record_layer_allow_legacy_alerts(struct tls13_record_layer *rl, int allow)
{
rl->legacy_alerts_allowed = allow;
}
void
tls13_record_layer_set_aead(struct tls13_record_layer *rl,
const EVP_AEAD *aead)
{
rl->aead = aead;
}
void
tls13_record_layer_set_hash(struct tls13_record_layer *rl,
const EVP_MD *hash)
{
rl->hash = hash;
}
void
tls13_record_layer_set_legacy_version(struct tls13_record_layer *rl,
uint16_t version)
{
rl->legacy_version = version;
}
void
tls13_record_layer_handshake_completed(struct tls13_record_layer *rl)
{
rl->handshake_completed = 1;
}
void
tls13_record_layer_set_retry_after_phh(struct tls13_record_layer *rl, int retry)
{
rl->phh_retry = retry;
}
static ssize_t
tls13_record_layer_process_alert(struct tls13_record_layer *rl)
{
uint8_t alert_level, alert_desc;
ssize_t ret = TLS13_IO_FAILURE;
if (tls_content_type(rl->rcontent) != SSL3_RT_ALERT)
return TLS13_IO_FAILURE;
if (!CBS_get_u8(tls_content_cbs(rl->rcontent), &alert_level))
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
if (!CBS_get_u8(tls_content_cbs(rl->rcontent), &alert_desc))
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
if (tls_content_remaining(rl->rcontent) != 0)
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
tls_content_clear(rl->rcontent);
if (alert_desc == TLS13_ALERT_CLOSE_NOTIFY) {
rl->read_closed = 1;
ret = TLS13_IO_EOF;
} else if (alert_desc == TLS13_ALERT_USER_CANCELED) {
ret = TLS13_IO_WANT_RETRY;
} else if (alert_level == TLS13_ALERT_LEVEL_FATAL) {
rl->read_closed = 1;
rl->write_closed = 1;
ret = TLS13_IO_ALERT;
} else if (rl->legacy_alerts_allowed &&
alert_level == TLS13_ALERT_LEVEL_WARNING) {
return TLS13_IO_WANT_RETRY;
} else {
return tls13_send_alert(rl, TLS13_ALERT_ILLEGAL_PARAMETER);
}
rl->cb.alert_recv(alert_level, alert_desc, rl->cb_arg);
return ret;
}
void
tls13_record_layer_alert_sent(struct tls13_record_layer *rl,
uint8_t alert_level, uint8_t alert_desc)
{
rl->cb.alert_sent(alert_level, alert_desc, rl->cb_arg);
}
static ssize_t
tls13_record_layer_send_alert(struct tls13_record_layer *rl)
{
ssize_t ret;
if ((ret = tls13_record_layer_write_record(rl, SSL3_RT_ALERT,
rl->alert_data, rl->alert_len)) != rl->alert_len) {
if (ret == TLS13_IO_EOF)
ret = TLS13_IO_ALERT;
return ret;
}
freezero(rl->alert_data, rl->alert_len);
rl->alert_data = NULL;
rl->alert_len = 0;
if (rl->alert_desc == TLS13_ALERT_CLOSE_NOTIFY) {
rl->write_closed = 1;
ret = TLS13_IO_SUCCESS;
} else if (rl->alert_desc == TLS13_ALERT_USER_CANCELED) {
ret = TLS13_IO_SUCCESS;
} else {
rl->read_closed = 1;
rl->write_closed = 1;
ret = TLS13_IO_ALERT;
}
tls13_record_layer_alert_sent(rl, rl->alert_level, rl->alert_desc);
return ret;
}
static ssize_t
tls13_record_layer_send_phh(struct tls13_record_layer *rl)
{
ssize_t ret;
if ((ret = tls13_record_layer_write_chunk(rl, SSL3_RT_HANDSHAKE,
CBS_data(&rl->phh_cbs), CBS_len(&rl->phh_cbs))) <= 0)
return ret;
if (!CBS_skip(&rl->phh_cbs, ret))
return TLS13_IO_FAILURE;
if (CBS_len(&rl->phh_cbs) != 0)
return TLS13_IO_WANT_RETRY;
freezero(rl->phh_data, rl->phh_len);
rl->phh_data = NULL;
rl->phh_len = 0;
CBS_init(&rl->phh_cbs, rl->phh_data, rl->phh_len);
rl->cb.phh_sent(rl->cb_arg);
return TLS13_IO_SUCCESS;
}
ssize_t
tls13_record_layer_send_pending(struct tls13_record_layer *rl)
{
if (rl->phh_data != NULL && CBS_len(&rl->phh_cbs) != rl->phh_len)
return tls13_record_layer_send_phh(rl);
if (rl->alert_data != NULL)
return tls13_record_layer_send_alert(rl);
if (rl->phh_data != NULL)
return tls13_record_layer_send_phh(rl);
return TLS13_IO_SUCCESS;
}
static ssize_t
tls13_record_layer_enqueue_alert(struct tls13_record_layer *rl,
uint8_t alert_level, uint8_t alert_desc)
{
CBB cbb;
if (rl->alert_data != NULL)
return TLS13_IO_FAILURE;
if (!CBB_init(&cbb, 0))
goto err;
if (!CBB_add_u8(&cbb, alert_level))
goto err;
if (!CBB_add_u8(&cbb, alert_desc))
goto err;
if (!CBB_finish(&cbb, &rl->alert_data, &rl->alert_len))
goto err;
rl->alert_level = alert_level;
rl->alert_desc = alert_desc;
return tls13_record_layer_send_pending(rl);
err:
CBB_cleanup(&cbb);
return TLS13_IO_FAILURE;
}
ssize_t
tls13_record_layer_phh(struct tls13_record_layer *rl, CBS *cbs)
{
if (rl->phh_data != NULL)
return TLS13_IO_FAILURE;
if (!CBS_stow(cbs, &rl->phh_data, &rl->phh_len))
return TLS13_IO_FAILURE;
CBS_init(&rl->phh_cbs, rl->phh_data, rl->phh_len);
return tls13_record_layer_send_pending(rl);
}
static int
tls13_record_layer_set_traffic_key(const EVP_AEAD *aead, const EVP_MD *hash,
struct tls13_record_protection *rp, struct tls13_secret *traffic_key)
{
struct tls13_secret context = { .data = "", .len = 0 };
struct tls13_secret key = { .data = NULL, .len = 0 };
int ret = 0;
tls13_record_protection_clear(rp);
if ((rp->aead_ctx = EVP_AEAD_CTX_new()) == NULL)
return 0;
if (!tls13_secret_init(&rp->iv, EVP_AEAD_nonce_length(aead)))
goto err;
if (!tls13_secret_init(&rp->nonce, EVP_AEAD_nonce_length(aead)))
goto err;
if (!tls13_secret_init(&key, EVP_AEAD_key_length(aead)))
goto err;
if (!tls13_hkdf_expand_label(&rp->iv, hash, traffic_key, "iv", &context))
goto err;
if (!tls13_hkdf_expand_label(&key, hash, traffic_key, "key", &context))
goto err;
if (!EVP_AEAD_CTX_init(rp->aead_ctx, aead, key.data, key.len,
EVP_AEAD_DEFAULT_TAG_LENGTH, NULL))
goto err;
ret = 1;
err:
tls13_secret_cleanup(&key);
return ret;
}
int
tls13_record_layer_set_read_traffic_key(struct tls13_record_layer *rl,
struct tls13_secret *read_key, enum ssl_encryption_level_t read_level)
{
if (rl->cb.set_read_traffic_key != NULL)
return rl->cb.set_read_traffic_key(read_key, read_level,
rl->cb_arg);
return tls13_record_layer_set_traffic_key(rl->aead, rl->hash,
rl->read, read_key);
}
int
tls13_record_layer_set_write_traffic_key(struct tls13_record_layer *rl,
struct tls13_secret *write_key, enum ssl_encryption_level_t write_level)
{
if (rl->cb.set_write_traffic_key != NULL)
return rl->cb.set_write_traffic_key(write_key, write_level,
rl->cb_arg);
return tls13_record_layer_set_traffic_key(rl->aead, rl->hash,
rl->write, write_key);
}
static int
tls13_record_layer_open_record_plaintext(struct tls13_record_layer *rl)
{
CBS cbs;
if (rl->aead != NULL)
return 0;
if (!tls13_record_content(rl->rrec, &cbs))
return 0;
if (CBS_len(&cbs) > TLS13_RECORD_MAX_PLAINTEXT_LEN) {
rl->alert = TLS13_ALERT_RECORD_OVERFLOW;
return 0;
}
if (!tls_content_dup_data(rl->rcontent,
tls13_record_content_type(rl->rrec), CBS_data(&cbs), CBS_len(&cbs)))
return 0;
return 1;
}
static int
tls13_record_layer_open_record_protected(struct tls13_record_layer *rl)
{
CBS header, enc_record, inner;
uint8_t *content = NULL;
size_t content_len = 0;
uint8_t content_type;
size_t out_len;
if (rl->aead == NULL)
goto err;
if (!tls13_record_header(rl->rrec, &header))
goto err;
if (!tls13_record_content(rl->rrec, &enc_record))
goto err;
if ((content = calloc(1, CBS_len(&enc_record))) == NULL)
goto err;
content_len = CBS_len(&enc_record);
if (!tls13_record_layer_update_nonce(&rl->read->nonce, &rl->read->iv,
rl->read->seq_num))
goto err;
if (!EVP_AEAD_CTX_open(rl->read->aead_ctx,
content, &out_len, content_len,
rl->read->nonce.data, rl->read->nonce.len,
CBS_data(&enc_record), CBS_len(&enc_record),
CBS_data(&header), CBS_len(&header)))
goto err;
if (out_len > TLS13_RECORD_MAX_INNER_PLAINTEXT_LEN) {
rl->alert = TLS13_ALERT_RECORD_OVERFLOW;
goto err;
}
if (!tls13_record_layer_inc_seq_num(rl->read->seq_num))
goto err;
CBS_init(&inner, content, out_len);
content_type = 0;
while (CBS_get_last_u8(&inner, &content_type)) {
if (content_type != 0)
break;
}
if (content_type == 0) {
rl->alert = TLS13_ALERT_UNEXPECTED_MESSAGE;
goto err;
}
if (CBS_len(&inner) > TLS13_RECORD_MAX_PLAINTEXT_LEN) {
rl->alert = TLS13_ALERT_RECORD_OVERFLOW;
goto err;
}
tls_content_set_data(rl->rcontent, content_type, CBS_data(&inner),
CBS_len(&inner));
return 1;
err:
freezero(content, content_len);
return 0;
}
static int
tls13_record_layer_open_record(struct tls13_record_layer *rl)
{
if (rl->handshake_completed && rl->aead == NULL)
return 0;
if (rl->aead == NULL)
return tls13_record_layer_open_record_plaintext(rl);
return tls13_record_layer_open_record_protected(rl);
}
static int
tls13_record_layer_seal_record_plaintext(struct tls13_record_layer *rl,
uint8_t content_type, const uint8_t *content, size_t content_len)
{
uint8_t *data = NULL;
size_t data_len = 0;
CBB cbb, body;
if (rl->handshake_completed)
return 0;
if (rl->aead != NULL && content_type != SSL3_RT_CHANGE_CIPHER_SPEC)
return 0;
if (!CBB_init(&cbb, TLS13_RECORD_HEADER_LEN + content_len))
goto err;
if (!CBB_add_u8(&cbb, content_type))
goto err;
if (!CBB_add_u16(&cbb, rl->legacy_version))
goto err;
if (!CBB_add_u16_length_prefixed(&cbb, &body))
goto err;
if (!CBB_add_bytes(&body, content, content_len))
goto err;
if (!CBB_finish(&cbb, &data, &data_len))
goto err;
if (!tls13_record_set_data(rl->wrec, data, data_len))
goto err;
rl->wrec_content_len = content_len;
rl->wrec_content_type = content_type;
return 1;
err:
CBB_cleanup(&cbb);
freezero(data, data_len);
return 0;
}
static int
tls13_record_layer_seal_record_protected(struct tls13_record_layer *rl,
uint8_t content_type, const uint8_t *content, size_t content_len)
{
uint8_t *data = NULL, *header = NULL, *inner = NULL;
size_t data_len = 0, header_len = 0, inner_len = 0;
uint8_t *enc_record;
size_t enc_record_len;
ssize_t ret = 0;
size_t out_len;
CBB cbb;
if (rl->aead == NULL)
return 0;
memset(&cbb, 0, sizeof(cbb));
if (!CBB_init(&cbb, content_len + 1))
goto err;
if (!CBB_add_bytes(&cbb, content, content_len))
goto err;
if (!CBB_add_u8(&cbb, content_type))
goto err;
if (!CBB_finish(&cbb, &inner, &inner_len))
goto err;
if (inner_len > TLS13_RECORD_MAX_INNER_PLAINTEXT_LEN)
goto err;
enc_record_len = inner_len + EVP_AEAD_max_tag_len(rl->aead);
if (enc_record_len > TLS13_RECORD_MAX_CIPHERTEXT_LEN)
goto err;
if (!CBB_init(&cbb, TLS13_RECORD_HEADER_LEN))
goto err;
if (!CBB_add_u8(&cbb, SSL3_RT_APPLICATION_DATA))
goto err;
if (!CBB_add_u16(&cbb, TLS1_2_VERSION))
goto err;
if (!CBB_add_u16(&cbb, enc_record_len))
goto err;
if (!CBB_finish(&cbb, &header, &header_len))
goto err;
if (!CBB_init(&cbb, TLS13_RECORD_HEADER_LEN + enc_record_len))
goto err;
if (!CBB_add_bytes(&cbb, header, header_len))
goto err;
if (!CBB_add_space(&cbb, &enc_record, enc_record_len))
goto err;
if (!CBB_finish(&cbb, &data, &data_len))
goto err;
if (!tls13_record_layer_update_nonce(&rl->write->nonce,
&rl->write->iv, rl->write->seq_num))
goto err;
if (!EVP_AEAD_CTX_seal(rl->write->aead_ctx,
enc_record, &out_len, enc_record_len,
rl->write->nonce.data, rl->write->nonce.len,
inner, inner_len, header, header_len))
goto err;
if (out_len != enc_record_len)
goto err;
if (!tls13_record_layer_inc_seq_num(rl->write->seq_num))
goto err;
if (!tls13_record_set_data(rl->wrec, data, data_len))
goto err;
rl->wrec_content_len = content_len;
rl->wrec_content_type = content_type;
data = NULL;
data_len = 0;
ret = 1;
err:
CBB_cleanup(&cbb);
freezero(data, data_len);
freezero(header, header_len);
freezero(inner, inner_len);
return ret;
}
static int
tls13_record_layer_seal_record(struct tls13_record_layer *rl,
uint8_t content_type, const uint8_t *content, size_t content_len)
{
if (rl->handshake_completed && rl->aead == NULL)
return 0;
tls13_record_layer_wrec_free(rl);
if ((rl->wrec = tls13_record_new()) == NULL)
return 0;
if (rl->aead == NULL || content_type == SSL3_RT_CHANGE_CIPHER_SPEC)
return tls13_record_layer_seal_record_plaintext(rl,
content_type, content, content_len);
return tls13_record_layer_seal_record_protected(rl, content_type,
content, content_len);
}
static ssize_t
tls13_record_layer_read_record(struct tls13_record_layer *rl)
{
uint8_t content_type, ccs;
ssize_t ret;
CBS cbs;
if (rl->rrec == NULL) {
if ((rl->rrec = tls13_record_new()) == NULL)
goto err;
}
if ((ret = tls13_record_recv(rl->rrec, rl->cb.wire_read, rl->cb_arg)) <= 0) {
switch (ret) {
case TLS13_IO_RECORD_VERSION:
return tls13_send_alert(rl, TLS13_ALERT_PROTOCOL_VERSION);
case TLS13_IO_RECORD_OVERFLOW:
return tls13_send_alert(rl, TLS13_ALERT_RECORD_OVERFLOW);
}
return ret;
}
content_type = tls13_record_content_type(rl->rrec);
if (rl->legacy_version == TLS1_2_VERSION &&
tls13_record_version(rl->rrec) != TLS1_2_VERSION &&
(content_type != SSL3_RT_ALERT || !rl->legacy_alerts_allowed))
return tls13_send_alert(rl, TLS13_ALERT_PROTOCOL_VERSION);
if (content_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
if (!rl->ccs_allowed || rl->ccs_seen >= 2)
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
if (!tls13_record_content(rl->rrec, &cbs))
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
if (!CBS_get_u8(&cbs, &ccs))
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
if (ccs != 1)
return tls13_send_alert(rl, TLS13_ALERT_ILLEGAL_PARAMETER);
if (CBS_len(&cbs) != 0)
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
rl->ccs_seen++;
tls13_record_layer_rrec_free(rl);
return TLS13_IO_WANT_RETRY;
}
if (rl->aead != NULL && content_type != SSL3_RT_APPLICATION_DATA)
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
if (!tls13_record_layer_open_record(rl))
goto err;
tls13_record_layer_rrec_free(rl);
if (tls_content_remaining(rl->rcontent) == 0 &&
(tls_content_type(rl->rcontent) == SSL3_RT_ALERT ||
tls_content_type(rl->rcontent) == SSL3_RT_HANDSHAKE))
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
switch (tls_content_type(rl->rcontent)) {
case SSL3_RT_ALERT:
return tls13_record_layer_process_alert(rl);
case SSL3_RT_HANDSHAKE:
break;
case SSL3_RT_APPLICATION_DATA:
if (!rl->handshake_completed)
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
break;
default:
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
}
return TLS13_IO_SUCCESS;
err:
return TLS13_IO_FAILURE;
}
static ssize_t
tls13_record_layer_pending(struct tls13_record_layer *rl, uint8_t content_type)
{
if (tls_content_type(rl->rcontent) != content_type)
return 0;
return tls_content_remaining(rl->rcontent);
}
static ssize_t
tls13_record_layer_recv_phh(struct tls13_record_layer *rl)
{
ssize_t ret = TLS13_IO_FAILURE;
rl->phh = 1;
if (rl->cb.phh_recv != NULL)
ret = rl->cb.phh_recv(rl->cb_arg);
tls_content_clear(rl->rcontent);
if (ret != TLS13_IO_WANT_POLLIN)
rl->phh = 0;
if (ret == TLS13_IO_SUCCESS) {
if (rl->phh_retry)
return TLS13_IO_WANT_RETRY;
return TLS13_IO_WANT_POLLIN;
}
return ret;
}
static ssize_t
tls13_record_layer_read_internal(struct tls13_record_layer *rl,
uint8_t content_type, uint8_t *buf, size_t n, int peek)
{
ssize_t ret;
if ((ret = tls13_record_layer_send_pending(rl)) != TLS13_IO_SUCCESS)
return ret;
if (rl->read_closed)
return TLS13_IO_EOF;
if (tls_content_remaining(rl->rcontent) == 0) {
if ((ret = tls13_record_layer_read_record(rl)) <= 0)
return ret;
if (tls_content_remaining(rl->rcontent) == 0)
return TLS13_IO_WANT_POLLIN;
}
if (rl->phh && tls_content_type(rl->rcontent) != SSL3_RT_HANDSHAKE)
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
if (tls_content_type(rl->rcontent) != content_type) {
if (tls_content_type(rl->rcontent) == SSL3_RT_HANDSHAKE) {
if (rl->handshake_completed)
return tls13_record_layer_recv_phh(rl);
}
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
}
if (peek)
return tls_content_peek(rl->rcontent, buf, n);
return tls_content_read(rl->rcontent, buf, n);
}
static ssize_t
tls13_record_layer_peek(struct tls13_record_layer *rl, uint8_t content_type,
uint8_t *buf, size_t n)
{
ssize_t ret;
do {
ret = tls13_record_layer_read_internal(rl, content_type, buf, n, 1);
} while (ret == TLS13_IO_WANT_RETRY);
if (rl->alert != 0)
return tls13_send_alert(rl, rl->alert);
return ret;
}
static ssize_t
tls13_record_layer_read(struct tls13_record_layer *rl, uint8_t content_type,
uint8_t *buf, size_t n)
{
ssize_t ret;
do {
ret = tls13_record_layer_read_internal(rl, content_type, buf, n, 0);
} while (ret == TLS13_IO_WANT_RETRY);
if (rl->alert != 0)
return tls13_send_alert(rl, rl->alert);
return ret;
}
static ssize_t
tls13_record_layer_write_record(struct tls13_record_layer *rl,
uint8_t content_type, const uint8_t *content, size_t content_len)
{
ssize_t ret;
if (rl->write_closed)
return TLS13_IO_EOF;
if (content_type == SSL3_RT_APPLICATION_DATA &&
rl->wrec_appdata_len != 0) {
ret = rl->wrec_appdata_len;
rl->wrec_appdata_len = 0;
return ret;
}
if (rl->wrec != NULL) {
if ((ret = tls13_record_send(rl->wrec, rl->cb.wire_write,
rl->cb_arg)) <= 0)
return ret;
tls13_record_layer_wrec_free(rl);
if (rl->wrec_content_type == content_type) {
ret = rl->wrec_content_len;
rl->wrec_content_len = 0;
rl->wrec_content_type = 0;
return ret;
}
if (rl->wrec_content_type != SSL3_RT_APPLICATION_DATA)
return TLS13_IO_FAILURE;
rl->wrec_appdata_len = rl->wrec_content_len;
}
if (content_len > TLS13_RECORD_MAX_PLAINTEXT_LEN)
goto err;
if (!tls13_record_layer_seal_record(rl, content_type, content, content_len))
goto err;
if ((ret = tls13_record_send(rl->wrec, rl->cb.wire_write, rl->cb_arg)) <= 0)
return ret;
tls13_record_layer_wrec_free(rl);
return content_len;
err:
return TLS13_IO_FAILURE;
}
static ssize_t
tls13_record_layer_write_chunk(struct tls13_record_layer *rl,
uint8_t content_type, const uint8_t *buf, size_t n)
{
if (n > TLS13_RECORD_MAX_PLAINTEXT_LEN)
n = TLS13_RECORD_MAX_PLAINTEXT_LEN;
return tls13_record_layer_write_record(rl, content_type, buf, n);
}
static ssize_t
tls13_record_layer_write(struct tls13_record_layer *rl, uint8_t content_type,
const uint8_t *buf, size_t n)
{
ssize_t ret;
do {
ret = tls13_record_layer_send_pending(rl);
} while (ret == TLS13_IO_WANT_RETRY);
if (ret != TLS13_IO_SUCCESS)
return ret;
do {
ret = tls13_record_layer_write_chunk(rl, content_type, buf, n);
} while (ret == TLS13_IO_WANT_RETRY);
return ret;
}
ssize_t
tls13_record_layer_flush(struct tls13_record_layer *rl)
{
return rl->cb.wire_flush(rl->cb_arg);
}
static const uint8_t tls13_dummy_ccs[] = { 0x01 };
ssize_t
tls13_send_dummy_ccs(struct tls13_record_layer *rl)
{
ssize_t ret;
if (rl->ccs_sent)
return TLS13_IO_FAILURE;
if ((ret = tls13_record_layer_write(rl, SSL3_RT_CHANGE_CIPHER_SPEC,
tls13_dummy_ccs, sizeof(tls13_dummy_ccs))) <= 0)
return ret;
rl->ccs_sent = 1;
return TLS13_IO_SUCCESS;
}
ssize_t
tls13_read_handshake_data(struct tls13_record_layer *rl, uint8_t *buf, size_t n)
{
if (rl->cb.handshake_read != NULL)
return rl->cb.handshake_read(buf, n, rl->cb_arg);
return tls13_record_layer_read(rl, SSL3_RT_HANDSHAKE, buf, n);
}
ssize_t
tls13_write_handshake_data(struct tls13_record_layer *rl, const uint8_t *buf,
size_t n)
{
if (rl->cb.handshake_write != NULL)
return rl->cb.handshake_write(buf, n, rl->cb_arg);
return tls13_record_layer_write(rl, SSL3_RT_HANDSHAKE, buf, n);
}
ssize_t
tls13_pending_application_data(struct tls13_record_layer *rl)
{
if (!rl->handshake_completed)
return 0;
return tls13_record_layer_pending(rl, SSL3_RT_APPLICATION_DATA);
}
ssize_t
tls13_peek_application_data(struct tls13_record_layer *rl, uint8_t *buf, size_t n)
{
if (!rl->handshake_completed)
return TLS13_IO_FAILURE;
return tls13_record_layer_peek(rl, SSL3_RT_APPLICATION_DATA, buf, n);
}
ssize_t
tls13_read_application_data(struct tls13_record_layer *rl, uint8_t *buf, size_t n)
{
if (!rl->handshake_completed)
return TLS13_IO_FAILURE;
return tls13_record_layer_read(rl, SSL3_RT_APPLICATION_DATA, buf, n);
}
ssize_t
tls13_write_application_data(struct tls13_record_layer *rl, const uint8_t *buf,
size_t n)
{
if (!rl->handshake_completed)
return TLS13_IO_FAILURE;
return tls13_record_layer_write(rl, SSL3_RT_APPLICATION_DATA, buf, n);
}
ssize_t
tls13_send_alert(struct tls13_record_layer *rl, uint8_t alert_desc)
{
uint8_t alert_level = TLS13_ALERT_LEVEL_FATAL;
ssize_t ret;
if (rl->cb.alert_send != NULL)
return rl->cb.alert_send(alert_desc, rl->cb_arg);
if (alert_desc == TLS13_ALERT_CLOSE_NOTIFY ||
alert_desc == TLS13_ALERT_USER_CANCELED)
alert_level = TLS13_ALERT_LEVEL_WARNING;
do {
ret = tls13_record_layer_enqueue_alert(rl, alert_level,
alert_desc);
} while (ret == TLS13_IO_WANT_RETRY);
return ret;
}