-/* $OpenBSD: tls13_record_layer.c,v 1.62 2021/06/08 18:05:47 tb Exp $ */
+/* $OpenBSD: tls13_record_layer.c,v 1.63 2021/09/04 16:26:12 jsing Exp $ */
/*
* Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org>
*
#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);
uint8_t *phh_data;
size_t phh_len;
- /* Buffer containing plaintext from opened records. */
- uint8_t rbuf_content_type;
- uint8_t *rbuf;
- size_t rbuf_len;
- CBS rbuf_cbs;
+ /* Content from opened records. */
+ struct tls_content *rcontent;
/* Record protection. */
const EVP_MD *hash;
void *cb_arg;
};
-static void
-tls13_record_layer_rbuf_free(struct tls13_record_layer *rl)
-{
- CBS_init(&rl->rbuf_cbs, NULL, 0);
- freezero(rl->rbuf, rl->rbuf_len);
- rl->rbuf = NULL;
- rl->rbuf_len = 0;
- rl->rbuf_content_type = 0;
-}
-
static void
tls13_record_layer_rrec_free(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)
freezero(rl->alert_data, rl->alert_len);
freezero(rl->phh_data, rl->phh_len);
- tls13_record_layer_rbuf_free(rl);
+ tls_content_free(rl->rcontent);
tls13_record_protection_free(rl->read);
tls13_record_protection_free(rl->write);
}
void
-tls13_record_layer_rbuf(struct tls13_record_layer *rl, CBS *cbs)
+tls13_record_layer_rcontent(struct tls13_record_layer *rl, CBS *cbs)
{
- CBS_dup(&rl->rbuf_cbs, cbs);
+ CBS_dup(tls_content_cbs(rl->rcontent), cbs);
}
static const uint8_t tls13_max_seq_num[TLS13_RECORD_SEQ_NUM_LEN] = {
* will result in one of three things - continuation (user_cancelled),
* read channel closure (close_notify) or termination (all others).
*/
- if (rl->rbuf == NULL)
+ if (tls_content_type(rl->rcontent) != SSL3_RT_ALERT)
return TLS13_IO_FAILURE;
- if (rl->rbuf_content_type != SSL3_RT_ALERT)
- return TLS13_IO_FAILURE;
-
- if (!CBS_get_u8(&rl->rbuf_cbs, &alert_level))
+ if (!CBS_get_u8(tls_content_cbs(rl->rcontent), &alert_level))
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
-
- if (!CBS_get_u8(&rl->rbuf_cbs, &alert_desc))
+ if (!CBS_get_u8(tls_content_cbs(rl->rcontent), &alert_desc))
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
- if (CBS_len(&rl->rbuf_cbs) != 0)
+ if (tls_content_remaining(rl->rcontent) != 0)
return tls13_send_alert(rl, TLS13_ALERT_DECODE_ERROR);
- tls13_record_layer_rbuf_free(rl);
+ tls_content_clear(rl->rcontent);
/*
* Alert level is ignored for closure alerts (RFC 8446 section 6.1),
return 0;
}
- tls13_record_layer_rbuf_free(rl);
-
- if (!CBS_stow(&cbs, &rl->rbuf, &rl->rbuf_len))
+ if (!tls_content_dup_data(rl->rcontent,
+ tls13_record_content_type(rl->rrec), CBS_data(&cbs), CBS_len(&cbs)))
return 0;
- rl->rbuf_content_type = tls13_record_content_type(rl->rrec);
-
- CBS_init(&rl->rbuf_cbs, rl->rbuf, rl->rbuf_len);
-
return 1;
}
}
content_type = content[inner_len];
- tls13_record_layer_rbuf_free(rl);
-
- rl->rbuf_content_type = content_type;
- rl->rbuf = content;
- rl->rbuf_len = inner_len;
-
- CBS_init(&rl->rbuf_cbs, rl->rbuf, rl->rbuf_len);
+ tls_content_set_data(rl->rcontent, content_type, content, inner_len);
return 1;
* we must terminate the connection with an unexpected_message alert.
* See RFC 8446 section 5.4.
*/
- if (CBS_len(&rl->rbuf_cbs) == 0 &&
- (rl->rbuf_content_type == SSL3_RT_ALERT ||
- rl->rbuf_content_type == SSL3_RT_HANDSHAKE))
+ 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 (rl->rbuf_content_type) {
+ switch (tls_content_type(rl->rcontent)) {
case SSL3_RT_ALERT:
return tls13_record_layer_process_alert(rl);
static ssize_t
tls13_record_layer_pending(struct tls13_record_layer *rl, uint8_t content_type)
{
- if (rl->rbuf_content_type != content_type)
+ if (tls_content_type(rl->rcontent) != content_type)
return 0;
- return CBS_len(&rl->rbuf_cbs);
+ return tls_content_remaining(rl->rcontent);
}
static ssize_t
* TLS13_IO_FAILURE something broke.
*/
if (rl->cb.phh_recv != NULL)
- ret = rl->cb.phh_recv(rl->cb_arg, &rl->rbuf_cbs);
+ ret = rl->cb.phh_recv(rl->cb_arg, tls_content_cbs(rl->rcontent));
- tls13_record_layer_rbuf_free(rl);
+ tls_content_clear(rl->rcontent);
/* Leave post handshake handshake mode unless we need more data. */
if (ret != TLS13_IO_WANT_POLLIN)
return TLS13_IO_EOF;
/* If necessary, pull up the next record. */
- if (CBS_len(&rl->rbuf_cbs) == 0) {
+ if (tls_content_remaining(rl->rcontent) == 0) {
if ((ret = tls13_record_layer_read_record(rl)) <= 0)
return ret;
* We may have read a valid 0-byte application data record,
* in which case we need to read the next record.
*/
- if (CBS_len(&rl->rbuf_cbs) == 0) {
- tls13_record_layer_rbuf_free(rl);
+ if (tls_content_remaining(rl->rcontent) == 0)
return TLS13_IO_WANT_POLLIN;
- }
}
/*
* If we are in post handshake handshake mode, we must not see
* any record type that isn't a handshake until we are done.
*/
- if (rl->phh && rl->rbuf_content_type != SSL3_RT_HANDSHAKE)
+ if (rl->phh && tls_content_type(rl->rcontent) != SSL3_RT_HANDSHAKE)
return tls13_send_alert(rl, TLS13_ALERT_UNEXPECTED_MESSAGE);
/*
* be trying to read application data and need to handle a
* post-handshake handshake message instead...
*/
- if (rl->rbuf_content_type != content_type) {
- if (rl->rbuf_content_type == SSL3_RT_HANDSHAKE) {
+ 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 (n > CBS_len(&rl->rbuf_cbs))
- n = CBS_len(&rl->rbuf_cbs);
+ if (peek)
+ return tls_content_peek(rl->rcontent, buf, n);
- /* XXX - CBS_memcpy? CBS_copy_bytes? */
- memcpy(buf, CBS_data(&rl->rbuf_cbs), n);
-
- if (!peek) {
- if (!CBS_skip(&rl->rbuf_cbs, n))
- goto err;
- }
-
- if (CBS_len(&rl->rbuf_cbs) == 0)
- tls13_record_layer_rbuf_free(rl);
-
- return n;
-
- err:
- return TLS13_IO_FAILURE;
+ return tls_content_read(rl->rcontent, buf, n);
}
static ssize_t
--- /dev/null
+/* $OpenBSD: tls_content.c,v 1.1 2021/09/04 16:26:12 jsing Exp $ */
+/*
+ * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tls_content.h"
+
+/* Content from a TLS record. */
+struct tls_content {
+ uint8_t type;
+ uint16_t epoch;
+
+ const uint8_t *data;
+ size_t len;
+ CBS cbs;
+};
+
+struct tls_content *
+tls_content_new(void)
+{
+ return calloc(1, sizeof(struct tls_content));
+}
+
+void
+tls_content_clear(struct tls_content *content)
+{
+ freezero((void *)content->data, content->len);
+ memset(content, 0, sizeof(*content));
+}
+
+void
+tls_content_free(struct tls_content *content)
+{
+ if (content == NULL)
+ return;
+
+ tls_content_clear(content);
+
+ freezero(content, sizeof(struct tls_content));
+}
+
+CBS *
+tls_content_cbs(struct tls_content *content)
+{
+ return &content->cbs;
+}
+
+int
+tls_content_equal(struct tls_content *content, const uint8_t *buf, size_t n)
+{
+ return CBS_mem_equal(&content->cbs, buf, n);
+}
+
+size_t
+tls_content_remaining(struct tls_content *content)
+{
+ return CBS_len(&content->cbs);
+}
+
+uint8_t
+tls_content_type(struct tls_content *content)
+{
+ return content->type;
+}
+
+int
+tls_content_dup_data(struct tls_content *content, uint8_t type,
+ const uint8_t *data, size_t data_len)
+{
+ uint8_t *dup;
+
+ if ((dup = calloc(1, data_len)) == NULL)
+ return 0;
+ memcpy(dup, data, data_len);
+
+ tls_content_set_data(content, type, dup, data_len);
+
+ return 1;
+}
+
+uint16_t
+tls_content_epoch(struct tls_content *content)
+{
+ return content->epoch;
+}
+
+void
+tls_content_set_epoch(struct tls_content *content, uint16_t epoch)
+{
+ content->epoch = epoch;
+}
+
+void
+tls_content_set_data(struct tls_content *content, uint8_t type,
+ const uint8_t *data, size_t data_len)
+{
+ tls_content_clear(content);
+
+ content->type = type;
+ content->data = data;
+ content->len = data_len;
+
+ CBS_init(&content->cbs, content->data, content->len);
+}
+
+static ssize_t
+tls_content_read_internal(struct tls_content *content, uint8_t *buf, size_t n,
+ int peek)
+{
+ if (n > CBS_len(&content->cbs))
+ n = CBS_len(&content->cbs);
+
+ /* XXX - CBS_memcpy? CBS_copy_bytes? */
+ memcpy(buf, CBS_data(&content->cbs), n);
+
+ if (!peek) {
+ if (!CBS_skip(&content->cbs, n))
+ return -1;
+ }
+
+ return n;
+}
+
+ssize_t
+tls_content_peek(struct tls_content *content, uint8_t *buf, size_t n)
+{
+ return tls_content_read_internal(content, buf, n, 1);
+}
+
+ssize_t
+tls_content_read(struct tls_content *content, uint8_t *buf, size_t n)
+{
+ return tls_content_read_internal(content, buf, n, 0);
+}
--- /dev/null
+/* $OpenBSD: tls_content.h,v 1.1 2021/09/04 16:26:12 jsing Exp $ */
+/*
+ * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HEADER_TLS_CONTENT_H
+#define HEADER_TLS_CONTENT_H
+
+#include "bytestring.h"
+
+__BEGIN_HIDDEN_DECLS
+
+struct tls_content;
+
+struct tls_content *tls_content_new(void);
+void tls_content_clear(struct tls_content *content);
+void tls_content_free(struct tls_content *content);
+
+CBS *tls_content_cbs(struct tls_content *content);
+int tls_content_equal(struct tls_content *content, const uint8_t *buf, size_t n);
+size_t tls_content_remaining(struct tls_content *content);
+uint8_t tls_content_type(struct tls_content *content);
+uint16_t tls_content_epoch(struct tls_content *content);
+
+int tls_content_dup_data(struct tls_content *content, uint8_t type,
+ const uint8_t *data, size_t data_len);
+void tls_content_set_data(struct tls_content *content, uint8_t type,
+ const uint8_t *data, size_t data_len);
+void tls_content_set_epoch(struct tls_content *content, uint16_t epoch);
+
+ssize_t tls_content_peek(struct tls_content *content, uint8_t *buf, size_t n);
+ssize_t tls_content_read(struct tls_content *content, uint8_t *buf, size_t n);
+
+__END_HIDDEN_DECLS
+
+#endif