Coverage Report

Created: 2022-08-24 06:30

/src/libressl/crypto/bio/bss_mem.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: bss_mem.c,v 1.21 2022/02/19 15:59:12 jsing Exp $ */
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3
 * All rights reserved.
4
 *
5
 * This package is an SSL implementation written
6
 * by Eric Young (eay@cryptsoft.com).
7
 * The implementation was written so as to conform with Netscapes SSL.
8
 * 
9
 * This library is free for commercial and non-commercial use as long as
10
 * the following conditions are aheared to.  The following conditions
11
 * apply to all code found in this distribution, be it the RC4, RSA,
12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13
 * included with this distribution is covered by the same copyright terms
14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15
 * 
16
 * Copyright remains Eric Young's, and as such any Copyright notices in
17
 * the code are not to be removed.
18
 * If this package is used in a product, Eric Young should be given attribution
19
 * as the author of the parts of the library used.
20
 * This can be in the form of a textual message at program startup or
21
 * in documentation (online or textual) provided with the package.
22
 * 
23
 * Redistribution and use in source and binary forms, with or without
24
 * modification, are permitted provided that the following conditions
25
 * are met:
26
 * 1. Redistributions of source code must retain the copyright
27
 *    notice, this list of conditions and the following disclaimer.
28
 * 2. Redistributions in binary form must reproduce the above copyright
29
 *    notice, this list of conditions and the following disclaimer in the
30
 *    documentation and/or other materials provided with the distribution.
31
 * 3. All advertising materials mentioning features or use of this software
32
 *    must display the following acknowledgement:
33
 *    "This product includes cryptographic software written by
34
 *     Eric Young (eay@cryptsoft.com)"
35
 *    The word 'cryptographic' can be left out if the rouines from the library
36
 *    being used are not cryptographic related :-).
37
 * 4. If you include any Windows specific code (or a derivative thereof) from 
38
 *    the apps directory (application code) you must include an acknowledgement:
39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40
 * 
41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51
 * SUCH DAMAGE.
52
 * 
53
 * The licence and distribution terms for any publically available version or
54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55
 * copied and put under another distribution licence
56
 * [including the GNU Public Licence.]
57
 */
58
59
#include <errno.h>
60
#include <limits.h>
61
#include <stdio.h>
62
#include <string.h>
63
64
#include <openssl/bio.h>
65
#include <openssl/err.h>
66
#include <openssl/buffer.h>
67
68
#include "bio_local.h"
69
70
struct bio_mem {
71
  BUF_MEM *buf;
72
  size_t read_offset;
73
};
74
75
static size_t
76
bio_mem_pending(struct bio_mem *bm)
77
280k
{
78
280k
  if (bm->read_offset > bm->buf->length)
79
0
    return 0;
80
81
280k
  return bm->buf->length - bm->read_offset;
82
280k
}
83
84
static uint8_t *
85
bio_mem_read_ptr(struct bio_mem *bm)
86
277k
{
87
277k
  return &bm->buf->data[bm->read_offset];
88
277k
}
89
90
static int mem_new(BIO *bio);
91
static int mem_free(BIO *bio);
92
static int mem_write(BIO *bio, const char *in, int in_len);
93
static int mem_read(BIO *bio, char *out, int out_len);
94
static int mem_puts(BIO *bio, const char *in);
95
static int mem_gets(BIO *bio, char *out, int out_len);
96
static long mem_ctrl(BIO *bio, int cmd, long arg1, void *arg2);
97
98
static const BIO_METHOD mem_method = {
99
  .type = BIO_TYPE_MEM,
100
  .name = "memory buffer",
101
  .bwrite = mem_write,
102
  .bread = mem_read,
103
  .bputs = mem_puts,
104
  .bgets = mem_gets,
105
  .ctrl = mem_ctrl,
106
  .create = mem_new,
107
  .destroy = mem_free
108
};
109
110
/*
111
 * bio->num is used to hold the value to return on 'empty', if it is
112
 * 0, should_retry is not set.
113
 */
114
115
const BIO_METHOD *
116
BIO_s_mem(void)
117
2.16k
{
118
2.16k
  return &mem_method;
119
2.16k
}
120
121
BIO *
122
BIO_new_mem_buf(const void *buf, int buf_len)
123
0
{
124
0
  struct bio_mem *bm;
125
0
  BIO *bio;
126
127
0
  if (buf == NULL) {
128
0
    BIOerror(BIO_R_NULL_PARAMETER);
129
0
    return NULL;
130
0
  }
131
0
  if (buf_len == -1)
132
0
    buf_len = strlen(buf);
133
0
  if (buf_len < 0) {
134
0
    BIOerror(BIO_R_INVALID_ARGUMENT);
135
0
    return NULL;
136
0
  }
137
138
0
  if ((bio = BIO_new(BIO_s_mem())) == NULL)
139
0
    return NULL;
140
141
0
  bm = bio->ptr;
142
0
  bm->buf->data = (void *)buf; /* Trust in the BIO_FLAGS_MEM_RDONLY flag. */
143
0
  bm->buf->length = buf_len;
144
0
  bm->buf->max = buf_len;
145
0
  bio->flags |= BIO_FLAGS_MEM_RDONLY;
146
  /* Since this is static data retrying will not help. */
147
0
  bio->num = 0;
148
149
0
  return bio;
150
0
}
151
152
static int
153
mem_new(BIO *bio)
154
2.16k
{
155
2.16k
  struct bio_mem *bm;
156
157
2.16k
  if ((bm = calloc(1, sizeof(*bm))) == NULL)
158
0
    return 0;
159
2.16k
  if ((bm->buf = BUF_MEM_new()) == NULL) {
160
0
    free(bm);
161
0
    return 0;
162
0
  }
163
164
2.16k
  bio->shutdown = 1;
165
2.16k
  bio->init = 1;
166
2.16k
  bio->num = -1;
167
2.16k
  bio->ptr = bm;
168
169
2.16k
  return 1;
170
2.16k
}
171
172
static int
173
mem_free(BIO *bio)
174
2.16k
{
175
2.16k
  struct bio_mem *bm;
176
177
2.16k
  if (bio == NULL)
178
0
    return 0;
179
2.16k
  if (!bio->init || bio->ptr == NULL)
180
0
    return 1;
181
182
2.16k
  bm = bio->ptr;
183
2.16k
  if (bio->shutdown) {
184
2.16k
    if (bio->flags & BIO_FLAGS_MEM_RDONLY)
185
0
      bm->buf->data = NULL;
186
2.16k
    BUF_MEM_free(bm->buf);
187
2.16k
  }
188
2.16k
  free(bm);
189
2.16k
  bio->ptr = NULL;
190
191
2.16k
  return 1;
192
2.16k
}
193
194
static int
195
mem_read(BIO *bio, char *out, int out_len)
196
138k
{
197
138k
  struct bio_mem *bm = bio->ptr;
198
199
138k
  BIO_clear_retry_flags(bio);
200
201
138k
  if (out == NULL || out_len <= 0)
202
0
    return 0;
203
204
138k
  if ((size_t)out_len > bio_mem_pending(bm))
205
0
    out_len = bio_mem_pending(bm);
206
207
138k
  if (out_len == 0) {
208
0
    if (bio->num != 0)
209
0
      BIO_set_retry_read(bio);
210
0
    return bio->num;
211
0
  }
212
213
138k
  memcpy(out, bio_mem_read_ptr(bm), out_len);
214
138k
  bm->read_offset += out_len;
215
216
138k
  return out_len;
217
138k
}
218
219
static int
220
mem_write(BIO *bio, const char *in, int in_len)
221
2.16k
{
222
2.16k
  struct bio_mem *bm = bio->ptr;
223
2.16k
  size_t buf_len;
224
225
2.16k
  BIO_clear_retry_flags(bio);
226
227
2.16k
  if (in == NULL || in_len <= 0)
228
0
    return 0;
229
230
2.16k
  if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
231
0
    BIOerror(BIO_R_WRITE_TO_READ_ONLY_BIO);
232
0
    return -1;
233
0
  }
234
235
2.16k
  if (bm->read_offset > 4096) {
236
0
    memmove(bm->buf->data, bio_mem_read_ptr(bm),
237
0
        bio_mem_pending(bm));
238
0
    bm->buf->length = bio_mem_pending(bm);
239
0
    bm->read_offset = 0;
240
0
  }
241
242
  /*
243
   * Check for overflow and ensure we do not exceed an int, otherwise we
244
   * cannot tell if BUF_MEM_grow_clean() succeeded.
245
   */
246
2.16k
  buf_len = bm->buf->length + in_len;
247
2.16k
  if (buf_len < bm->buf->length || buf_len > INT_MAX)
248
0
    return -1;
249
250
2.16k
  if (BUF_MEM_grow_clean(bm->buf, buf_len) != buf_len)
251
0
    return -1;
252
253
2.16k
  memcpy(&bm->buf->data[buf_len - in_len], in, in_len);
254
255
2.16k
  return in_len;
256
2.16k
}
257
258
static long
259
mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
260
0
{
261
0
  struct bio_mem *bm = bio->ptr;
262
0
  void **pptr;
263
0
  long ret = 1;
264
265
0
  switch (cmd) {
266
0
  case BIO_CTRL_RESET:
267
0
    if (bm->buf->data != NULL) {
268
0
      if (!(bio->flags & BIO_FLAGS_MEM_RDONLY)) {
269
0
        memset(bm->buf->data, 0, bm->buf->max);
270
0
        bm->buf->length = 0;
271
0
      }
272
0
      bm->read_offset = 0;
273
0
    }
274
0
    break;
275
0
  case BIO_CTRL_EOF:
276
0
    ret = (long)(bio_mem_pending(bm) == 0);
277
0
    break;
278
0
  case BIO_C_SET_BUF_MEM_EOF_RETURN:
279
0
    bio->num = (int)num;
280
0
    break;
281
0
  case BIO_CTRL_INFO:
282
0
    if (ptr != NULL) {
283
0
      pptr = (void **)ptr;
284
0
      *pptr = bio_mem_read_ptr(bm);
285
0
    }
286
0
    ret = (long)bio_mem_pending(bm);
287
0
    break;
288
0
  case BIO_C_SET_BUF_MEM:
289
0
    BUF_MEM_free(bm->buf);
290
0
    bio->shutdown = (int)num;
291
0
    bm->buf = ptr;
292
0
    bm->read_offset = 0;
293
0
    break;
294
0
  case BIO_C_GET_BUF_MEM_PTR:
295
0
    if (ptr != NULL) {
296
0
      pptr = (void **)ptr;
297
0
      *pptr = bm->buf;
298
0
    }
299
0
    break;
300
0
  case BIO_CTRL_GET_CLOSE:
301
0
    ret = (long)bio->shutdown;
302
0
    break;
303
0
  case BIO_CTRL_SET_CLOSE:
304
0
    bio->shutdown = (int)num;
305
0
    break;
306
0
  case BIO_CTRL_WPENDING:
307
0
    ret = 0L;
308
0
    break;
309
0
  case BIO_CTRL_PENDING:
310
0
    ret = (long)bio_mem_pending(bm);
311
0
    break;
312
0
  case BIO_CTRL_DUP:
313
0
  case BIO_CTRL_FLUSH:
314
0
    ret = 1;
315
0
    break;
316
0
  case BIO_CTRL_PUSH:
317
0
  case BIO_CTRL_POP:
318
0
  default:
319
0
    ret = 0;
320
0
    break;
321
0
  }
322
0
  return ret;
323
0
}
324
325
static int
326
mem_gets(BIO *bio, char *out, int out_len)
327
142k
{
328
142k
  struct bio_mem *bm = bio->ptr;
329
142k
  int i, out_max;
330
142k
  char *p;
331
142k
  int ret = -1;
332
333
142k
  BIO_clear_retry_flags(bio);
334
335
142k
  out_max = bio_mem_pending(bm);
336
142k
  if (out_len - 1 < out_max)
337
116k
    out_max = out_len - 1;
338
142k
  if (out_max <= 0) {
339
3.52k
    *out = '\0';
340
3.52k
    return 0;
341
3.52k
  }
342
343
138k
  p = bio_mem_read_ptr(bm);
344
41.5M
  for (i = 0; i < out_max; i++) {
345
41.4M
    if (p[i] == '\n') {
346
57.2k
      i++;
347
57.2k
      break;
348
57.2k
    }
349
41.4M
  }
350
351
  /*
352
   * i is now the max num of bytes to copy, either out_max or up to and
353
   * including the first newline
354
   */ 
355
138k
  if ((ret = mem_read(bio, out, i)) > 0)
356
138k
    out[ret] = '\0';
357
358
138k
  return ret;
359
142k
}
360
361
static int
362
mem_puts(BIO *bio, const char *in)
363
0
{
364
0
  return mem_write(bio, in, strlen(in));
365
0
}