1 /* $OpenBSD: tls_buffer.c,v 1.3 2022/07/22 19:33:53 jsing Exp $ */
3 * Copyright (c) 2018, 2019, 2022 Joel Sing <jsing@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "bytestring.h"
22 #include "tls_internal.h"
24 #define TLS_BUFFER_CAPACITY_LIMIT (1024 * 1024)
28 size_t capacity_limit
;
34 static int tls_buffer_resize(struct tls_buffer
*buf
, size_t capacity
);
37 tls_buffer_new(size_t init_size
)
39 struct tls_buffer
*buf
= NULL
;
41 if ((buf
= calloc(1, sizeof(struct tls_buffer
))) == NULL
)
44 buf
->capacity_limit
= TLS_BUFFER_CAPACITY_LIMIT
;
46 if (!tls_buffer_resize(buf
, init_size
))
58 tls_buffer_clear(struct tls_buffer
*buf
)
60 freezero(buf
->data
, buf
->capacity
);
69 tls_buffer_free(struct tls_buffer
*buf
)
74 tls_buffer_clear(buf
);
76 freezero(buf
, sizeof(struct tls_buffer
));
80 tls_buffer_grow(struct tls_buffer
*buf
, size_t capacity
)
82 if (buf
->capacity
>= capacity
)
85 return tls_buffer_resize(buf
, capacity
);
89 tls_buffer_resize(struct tls_buffer
*buf
, size_t capacity
)
94 * XXX - Consider maintaining a minimum size and growing more
95 * intelligently (rather than exactly).
97 if (buf
->capacity
== capacity
)
100 if (capacity
> buf
->capacity_limit
)
103 if ((data
= recallocarray(buf
->data
, buf
->capacity
, capacity
, 1)) == NULL
)
107 buf
->capacity
= capacity
;
109 /* Ensure that len and offset are valid if capacity decreased. */
110 if (buf
->len
> buf
->capacity
)
111 buf
->len
= buf
->capacity
;
112 if (buf
->offset
> buf
->len
)
113 buf
->offset
= buf
->len
;
119 tls_buffer_set_capacity_limit(struct tls_buffer
*buf
, size_t limit
)
122 * XXX - do we want to force a resize if this limit is less than current
123 * capacity... and what do we do with existing data? Force a clear?
125 buf
->capacity_limit
= limit
;
129 tls_buffer_extend(struct tls_buffer
*buf
, size_t len
,
130 tls_read_cb read_cb
, void *cb_arg
)
138 return TLS_IO_FAILURE
;
140 if (!tls_buffer_resize(buf
, len
))
141 return TLS_IO_FAILURE
;
144 if ((ret
= read_cb(&buf
->data
[buf
->len
],
145 buf
->capacity
- buf
->len
, cb_arg
)) <= 0)
148 if (ret
> buf
->capacity
- buf
->len
)
149 return TLS_IO_FAILURE
;
153 if (buf
->len
== buf
->capacity
)
159 tls_buffer_read(struct tls_buffer
*buf
, uint8_t *rbuf
, size_t n
)
161 if (buf
->offset
> buf
->len
)
162 return TLS_IO_FAILURE
;
164 if (buf
->offset
== buf
->len
)
165 return TLS_IO_WANT_POLLIN
;
167 if (n
> buf
->len
- buf
->offset
)
168 n
= buf
->len
- buf
->offset
;
170 memcpy(rbuf
, &buf
->data
[buf
->offset
], n
);
178 tls_buffer_write(struct tls_buffer
*buf
, const uint8_t *wbuf
, size_t n
)
180 if (buf
->offset
> buf
->len
)
181 return TLS_IO_FAILURE
;
184 * To avoid continually growing the buffer, pull data up to the
185 * start of the buffer. If all data has been read then we can simply
186 * reset, otherwise wait until we're going to save at least 4KB of
187 * memory to reduce overhead.
189 if (buf
->offset
== buf
->len
) {
193 if (buf
->offset
>= 4096) {
194 memmove(buf
->data
, &buf
->data
[buf
->offset
],
195 buf
->len
- buf
->offset
);
196 buf
->len
-= buf
->offset
;
200 if (buf
->len
> SIZE_MAX
- n
)
201 return TLS_IO_FAILURE
;
202 if (!tls_buffer_grow(buf
, buf
->len
+ n
))
203 return TLS_IO_FAILURE
;
205 memcpy(&buf
->data
[buf
->len
], wbuf
, n
);
213 tls_buffer_append(struct tls_buffer
*buf
, const uint8_t *wbuf
, size_t n
)
215 return tls_buffer_write(buf
, wbuf
, n
) == n
;
219 tls_buffer_data(struct tls_buffer
*buf
, CBS
*out_cbs
)
223 CBS_init(&cbs
, buf
->data
, buf
->len
);
225 if (!CBS_skip(&cbs
, buf
->offset
))
228 CBS_dup(&cbs
, out_cbs
);
234 tls_buffer_finish(struct tls_buffer
*buf
, uint8_t **out
, size_t *out_len
)
236 if (out
== NULL
|| out_len
== NULL
)