summaryrefslogtreecommitdiff
path: root/lib/libssl/tls_buffer.c
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2022-07-22 19:33:54 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2022-07-22 19:33:54 +0000
commit9456d4e8735197d76f5563cceb5fb86d15325cab (patch)
tree9db0c2c6d75046f24eb8fea1c3aae9cf41ca9f00 /lib/libssl/tls_buffer.c
parentbe16e4e9292d4af770db9010d1876934399e5a90 (diff)
Add read and write support to tls_buffer.
tls_buffer was original created for a specific use case, namely reading in length prefixed messages. This adds read and write support, along with a capacity limit, allowing it to be used in additional use cases. ok beck@ tb@
Diffstat (limited to 'lib/libssl/tls_buffer.c')
-rw-r--r--lib/libssl/tls_buffer.c133
1 files changed, 126 insertions, 7 deletions
diff --git a/lib/libssl/tls_buffer.c b/lib/libssl/tls_buffer.c
index 9bb6b62e511..f70cfbc1a0d 100644
--- a/lib/libssl/tls_buffer.c
+++ b/lib/libssl/tls_buffer.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: tls_buffer.c,v 1.2 2022/07/20 06:32:24 jsing Exp $ */
+/* $OpenBSD: tls_buffer.c,v 1.3 2022/07/22 19:33:53 jsing Exp $ */
/*
- * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org>
+ * Copyright (c) 2018, 2019, 2022 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
@@ -21,8 +21,11 @@
#include "bytestring.h"
#include "tls_internal.h"
+#define TLS_BUFFER_CAPACITY_LIMIT (1024 * 1024)
+
struct tls_buffer {
size_t capacity;
+ size_t capacity_limit;
uint8_t *data;
size_t len;
size_t offset;
@@ -38,6 +41,8 @@ tls_buffer_new(size_t init_size)
if ((buf = calloc(1, sizeof(struct tls_buffer))) == NULL)
goto err;
+ buf->capacity_limit = TLS_BUFFER_CAPACITY_LIMIT;
+
if (!tls_buffer_resize(buf, init_size))
goto err;
@@ -50,32 +55,76 @@ tls_buffer_new(size_t init_size)
}
void
+tls_buffer_clear(struct tls_buffer *buf)
+{
+ freezero(buf->data, buf->capacity);
+
+ buf->data = NULL;
+ buf->capacity = 0;
+ buf->len = 0;
+ buf->offset = 0;
+}
+
+void
tls_buffer_free(struct tls_buffer *buf)
{
if (buf == NULL)
return;
- freezero(buf->data, buf->capacity);
+ tls_buffer_clear(buf);
+
freezero(buf, sizeof(struct tls_buffer));
}
static int
+tls_buffer_grow(struct tls_buffer *buf, size_t capacity)
+{
+ if (buf->capacity >= capacity)
+ return 1;
+
+ return tls_buffer_resize(buf, capacity);
+}
+
+static int
tls_buffer_resize(struct tls_buffer *buf, size_t capacity)
{
uint8_t *data;
+ /*
+ * XXX - Consider maintaining a minimum size and growing more
+ * intelligently (rather than exactly).
+ */
if (buf->capacity == capacity)
return 1;
+ if (capacity > buf->capacity_limit)
+ return 0;
+
if ((data = recallocarray(buf->data, buf->capacity, capacity, 1)) == NULL)
return 0;
buf->data = data;
buf->capacity = capacity;
+ /* Ensure that len and offset are valid if capacity decreased. */
+ if (buf->len > buf->capacity)
+ buf->len = buf->capacity;
+ if (buf->offset > buf->len)
+ buf->offset = buf->len;
+
return 1;
}
+void
+tls_buffer_set_capacity_limit(struct tls_buffer *buf, size_t limit)
+{
+ /*
+ * XXX - do we want to force a resize if this limit is less than current
+ * capacity... and what do we do with existing data? Force a clear?
+ */
+ buf->capacity_limit = limit;
+}
+
ssize_t
tls_buffer_extend(struct tls_buffer *buf, size_t len,
tls_read_cb read_cb, void *cb_arg)
@@ -106,10 +155,79 @@ tls_buffer_extend(struct tls_buffer *buf, size_t len,
}
}
-void
-tls_buffer_cbs(struct tls_buffer *buf, CBS *cbs)
+ssize_t
+tls_buffer_read(struct tls_buffer *buf, uint8_t *rbuf, size_t n)
+{
+ if (buf->offset > buf->len)
+ return TLS_IO_FAILURE;
+
+ if (buf->offset == buf->len)
+ return TLS_IO_WANT_POLLIN;
+
+ if (n > buf->len - buf->offset)
+ n = buf->len - buf->offset;
+
+ memcpy(rbuf, &buf->data[buf->offset], n);
+
+ buf->offset += n;
+
+ return n;
+}
+
+ssize_t
+tls_buffer_write(struct tls_buffer *buf, const uint8_t *wbuf, size_t n)
+{
+ if (buf->offset > buf->len)
+ return TLS_IO_FAILURE;
+
+ /*
+ * To avoid continually growing the buffer, pull data up to the
+ * start of the buffer. If all data has been read then we can simply
+ * reset, otherwise wait until we're going to save at least 4KB of
+ * memory to reduce overhead.
+ */
+ if (buf->offset == buf->len) {
+ buf->len = 0;
+ buf->offset = 0;
+ }
+ if (buf->offset >= 4096) {
+ memmove(buf->data, &buf->data[buf->offset],
+ buf->len - buf->offset);
+ buf->len -= buf->offset;
+ buf->offset = 0;
+ }
+
+ if (buf->len > SIZE_MAX - n)
+ return TLS_IO_FAILURE;
+ if (!tls_buffer_grow(buf, buf->len + n))
+ return TLS_IO_FAILURE;
+
+ memcpy(&buf->data[buf->len], wbuf, n);
+
+ buf->len += n;
+
+ return n;
+}
+
+int
+tls_buffer_append(struct tls_buffer *buf, const uint8_t *wbuf, size_t n)
+{
+ return tls_buffer_write(buf, wbuf, n) == n;
+}
+
+int
+tls_buffer_data(struct tls_buffer *buf, CBS *out_cbs)
{
- CBS_init(cbs, buf->data, buf->len);
+ CBS cbs;
+
+ CBS_init(&cbs, buf->data, buf->len);
+
+ if (!CBS_skip(&cbs, buf->offset))
+ return 0;
+
+ CBS_dup(&cbs, out_cbs);
+
+ return 1;
}
int
@@ -121,9 +239,10 @@ tls_buffer_finish(struct tls_buffer *buf, uint8_t **out, size_t *out_len)
*out = buf->data;
*out_len = buf->len;
- buf->capacity = 0;
buf->data = NULL;
+ buf->capacity = 0;
buf->len = 0;
+ buf->offset = 0;
return 1;
}