Coverage Report

Created: 2022-08-24 06:31

/src/libressl/ssl/tls_buffer.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: tls_buffer.c,v 1.3 2022/07/22 19:33:53 jsing Exp $ */
2
/*
3
 * Copyright (c) 2018, 2019, 2022 Joel Sing <jsing@openbsd.org>
4
 *
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.
8
 *
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.
16
 */
17
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include "bytestring.h"
22
#include "tls_internal.h"
23
24
41.4k
#define TLS_BUFFER_CAPACITY_LIMIT (1024 * 1024)
25
26
struct tls_buffer {
27
  size_t capacity;
28
  size_t capacity_limit;
29
  uint8_t *data;
30
  size_t len;
31
  size_t offset;
32
};
33
34
static int tls_buffer_resize(struct tls_buffer *buf, size_t capacity);
35
36
struct tls_buffer *
37
tls_buffer_new(size_t init_size)
38
41.4k
{
39
41.4k
  struct tls_buffer *buf = NULL;
40
41
41.4k
  if ((buf = calloc(1, sizeof(struct tls_buffer))) == NULL)
42
0
    goto err;
43
44
41.4k
  buf->capacity_limit = TLS_BUFFER_CAPACITY_LIMIT;
45
46
41.4k
  if (!tls_buffer_resize(buf, init_size))
47
0
    goto err;
48
49
41.4k
  return buf;
50
51
0
 err:
52
0
  tls_buffer_free(buf);
53
54
0
  return NULL;
55
41.4k
}
56
57
void
58
tls_buffer_clear(struct tls_buffer *buf)
59
48.2k
{
60
48.2k
  freezero(buf->data, buf->capacity);
61
62
48.2k
  buf->data = NULL;
63
48.2k
  buf->capacity = 0;
64
48.2k
  buf->len = 0;
65
48.2k
  buf->offset = 0;
66
48.2k
}
67
68
void
69
tls_buffer_free(struct tls_buffer *buf)
70
65.3k
{
71
65.3k
  if (buf == NULL)
72
23.9k
    return;
73
74
41.4k
  tls_buffer_clear(buf);
75
76
41.4k
  freezero(buf, sizeof(struct tls_buffer));
77
41.4k
}
78
79
static int
80
tls_buffer_grow(struct tls_buffer *buf, size_t capacity)
81
19.4k
{
82
19.4k
  if (buf->capacity >= capacity)
83
0
    return 1;
84
85
19.4k
  return tls_buffer_resize(buf, capacity);
86
19.4k
}
87
88
static int
89
tls_buffer_resize(struct tls_buffer *buf, size_t capacity)
90
102k
{
91
102k
  uint8_t *data;
92
93
  /*
94
   * XXX - Consider maintaining a minimum size and growing more
95
   * intelligently (rather than exactly).
96
   */
97
102k
  if (buf->capacity == capacity)
98
20.2k
    return 1;
99
100
82.0k
  if (capacity > buf->capacity_limit)
101
0
    return 0;
102
103
82.0k
  if ((data = recallocarray(buf->data, buf->capacity, capacity, 1)) == NULL)
104
0
    return 0;
105
106
82.0k
  buf->data = data;
107
82.0k
  buf->capacity = capacity;
108
109
  /* Ensure that len and offset are valid if capacity decreased. */
110
82.0k
  if (buf->len > buf->capacity)
111
0
    buf->len = buf->capacity;
112
82.0k
  if (buf->offset > buf->len)
113
0
    buf->offset = buf->len;
114
115
82.0k
  return 1;
116
82.0k
}
117
118
void
119
tls_buffer_set_capacity_limit(struct tls_buffer *buf, size_t limit)
120
0
{
121
  /*
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?
124
   */
125
0
  buf->capacity_limit = limit;
126
0
}
127
128
ssize_t
129
tls_buffer_extend(struct tls_buffer *buf, size_t len,
130
    tls_read_cb read_cb, void *cb_arg)
131
41.4k
{
132
41.4k
  ssize_t ret;
133
134
41.4k
  if (len == buf->len)
135
49
    return buf->len;
136
137
41.4k
  if (len < buf->len)
138
0
    return TLS_IO_FAILURE;
139
140
41.4k
  if (!tls_buffer_resize(buf, len))
141
0
    return TLS_IO_FAILURE;
142
143
47.4k
  for (;;) {
144
47.4k
    if ((ret = read_cb(&buf->data[buf->len],
145
47.4k
        buf->capacity - buf->len, cb_arg)) <= 0)
146
562
      return ret;
147
148
46.9k
    if (ret > buf->capacity - buf->len)
149
0
      return TLS_IO_FAILURE;
150
151
46.9k
    buf->len += ret;
152
153
46.9k
    if (buf->len == buf->capacity)
154
40.8k
      return buf->len;
155
46.9k
  }
156
41.4k
}
157
158
ssize_t
159
tls_buffer_read(struct tls_buffer *buf, uint8_t *rbuf, size_t n)
160
0
{
161
0
  if (buf->offset > buf->len)
162
0
    return TLS_IO_FAILURE;
163
164
0
  if (buf->offset == buf->len)
165
0
    return TLS_IO_WANT_POLLIN;
166
167
0
  if (n > buf->len - buf->offset)
168
0
    n = buf->len - buf->offset;
169
170
0
  memcpy(rbuf, &buf->data[buf->offset], n);
171
172
0
  buf->offset += n;
173
174
0
  return n;
175
0
}
176
177
ssize_t
178
tls_buffer_write(struct tls_buffer *buf, const uint8_t *wbuf, size_t n)
179
19.4k
{
180
19.4k
  if (buf->offset > buf->len)
181
0
    return TLS_IO_FAILURE;
182
183
  /*
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.
188
   */
189
19.4k
  if (buf->offset == buf->len) {
190
6.76k
    buf->len = 0;
191
6.76k
    buf->offset = 0;
192
6.76k
  }
193
19.4k
  if (buf->offset >= 4096) {
194
0
    memmove(buf->data, &buf->data[buf->offset],
195
0
        buf->len - buf->offset);
196
0
    buf->len -= buf->offset;
197
0
    buf->offset = 0;
198
0
  }
199
200
19.4k
  if (buf->len > SIZE_MAX - n)
201
0
    return TLS_IO_FAILURE;
202
19.4k
  if (!tls_buffer_grow(buf, buf->len + n))
203
0
    return TLS_IO_FAILURE;
204
205
19.4k
  memcpy(&buf->data[buf->len], wbuf, n);
206
207
19.4k
  buf->len += n;
208
209
19.4k
  return n;
210
19.4k
}
211
212
int
213
tls_buffer_append(struct tls_buffer *buf, const uint8_t *wbuf, size_t n)
214
19.4k
{
215
19.4k
  return tls_buffer_write(buf, wbuf, n) == n;
216
19.4k
}
217
218
int
219
tls_buffer_data(struct tls_buffer *buf, CBS *out_cbs)
220
26.7k
{
221
26.7k
  CBS cbs;
222
223
26.7k
  CBS_init(&cbs, buf->data, buf->len);
224
225
26.7k
  if (!CBS_skip(&cbs, buf->offset))
226
0
    return 0;
227
228
26.7k
  CBS_dup(&cbs, out_cbs);
229
230
26.7k
  return 1;
231
26.7k
}
232
233
int
234
tls_buffer_finish(struct tls_buffer *buf, uint8_t **out, size_t *out_len)
235
20.3k
{
236
20.3k
  if (out == NULL || out_len == NULL)
237
0
    return 0;
238
239
20.3k
  *out = buf->data;
240
20.3k
  *out_len = buf->len;
241
242
20.3k
  buf->data = NULL;
243
20.3k
  buf->capacity = 0;
244
20.3k
  buf->len = 0;
245
20.3k
  buf->offset = 0;
246
247
20.3k
  return 1;
248
20.3k
}