-/* $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
#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;
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;
return NULL;
}
+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)
}
}
-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
*out = buf->data;
*out_len = buf->len;
- buf->capacity = 0;
buf->data = NULL;
+ buf->capacity = 0;
buf->len = 0;
+ buf->offset = 0;
return 1;
}
-/* $OpenBSD: tls_internal.h,v 1.7 2022/07/20 06:32:24 jsing Exp $ */
+/* $OpenBSD: tls_internal.h,v 1.8 2022/07/22 19:33:53 jsing Exp $ */
/*
* Copyright (c) 2018, 2019, 2021 Joel Sing <jsing@openbsd.org>
*
struct tls_buffer;
struct tls_buffer *tls_buffer_new(size_t init_size);
+void tls_buffer_clear(struct tls_buffer *buf);
void tls_buffer_free(struct tls_buffer *buf);
+void tls_buffer_set_capacity_limit(struct tls_buffer *buf, size_t limit);
ssize_t tls_buffer_extend(struct tls_buffer *buf, size_t len,
tls_read_cb read_cb, void *cb_arg);
-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);
+ssize_t tls_buffer_write(struct tls_buffer *buf, const uint8_t *wbuf, size_t n);
+int tls_buffer_append(struct tls_buffer *buf, const uint8_t *wbuf, size_t n);
+int tls_buffer_data(struct tls_buffer *buf, CBS *cbs);
int tls_buffer_finish(struct tls_buffer *buf, uint8_t **out, size_t *out_len);
/*