xref: /dragonfly/crypto/libressl/crypto/bio/bss_mem.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
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
bio_mem_pending(struct bio_mem * bm)76 bio_mem_pending(struct bio_mem *bm)
77 {
78           if (bm->read_offset > bm->buf->length)
79                     return 0;
80 
81           return bm->buf->length - bm->read_offset;
82 }
83 
84 static uint8_t *
bio_mem_read_ptr(struct bio_mem * bm)85 bio_mem_read_ptr(struct bio_mem *bm)
86 {
87           return &bm->buf->data[bm->read_offset];
88 }
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 *
BIO_s_mem(void)116 BIO_s_mem(void)
117 {
118           return &mem_method;
119 }
120 
121 BIO *
BIO_new_mem_buf(const void * buf,int buf_len)122 BIO_new_mem_buf(const void *buf, int buf_len)
123 {
124           struct bio_mem *bm;
125           BIO *bio;
126 
127           if (buf == NULL) {
128                     BIOerror(BIO_R_NULL_PARAMETER);
129                     return NULL;
130           }
131           if (buf_len == -1)
132                     buf_len = strlen(buf);
133           if (buf_len < 0) {
134                     BIOerror(BIO_R_INVALID_ARGUMENT);
135                     return NULL;
136           }
137 
138           if ((bio = BIO_new(BIO_s_mem())) == NULL)
139                     return NULL;
140 
141           bm = bio->ptr;
142           bm->buf->data = (void *)buf; /* Trust in the BIO_FLAGS_MEM_RDONLY flag. */
143           bm->buf->length = buf_len;
144           bm->buf->max = buf_len;
145           bio->flags |= BIO_FLAGS_MEM_RDONLY;
146           /* Since this is static data retrying will not help. */
147           bio->num = 0;
148 
149           return bio;
150 }
151 
152 static int
mem_new(BIO * bio)153 mem_new(BIO *bio)
154 {
155           struct bio_mem *bm;
156 
157           if ((bm = calloc(1, sizeof(*bm))) == NULL)
158                     return 0;
159           if ((bm->buf = BUF_MEM_new()) == NULL) {
160                     free(bm);
161                     return 0;
162           }
163 
164           bio->shutdown = 1;
165           bio->init = 1;
166           bio->num = -1;
167           bio->ptr = bm;
168 
169           return 1;
170 }
171 
172 static int
mem_free(BIO * bio)173 mem_free(BIO *bio)
174 {
175           struct bio_mem *bm;
176 
177           if (bio == NULL)
178                     return 0;
179           if (!bio->init || bio->ptr == NULL)
180                     return 1;
181 
182           bm = bio->ptr;
183           if (bio->shutdown) {
184                     if (bio->flags & BIO_FLAGS_MEM_RDONLY)
185                               bm->buf->data = NULL;
186                     BUF_MEM_free(bm->buf);
187           }
188           free(bm);
189           bio->ptr = NULL;
190 
191           return 1;
192 }
193 
194 static int
mem_read(BIO * bio,char * out,int out_len)195 mem_read(BIO *bio, char *out, int out_len)
196 {
197           struct bio_mem *bm = bio->ptr;
198 
199           BIO_clear_retry_flags(bio);
200 
201           if (out == NULL || out_len <= 0)
202                     return 0;
203 
204           if ((size_t)out_len > bio_mem_pending(bm))
205                     out_len = bio_mem_pending(bm);
206 
207           if (out_len == 0) {
208                     if (bio->num != 0)
209                               BIO_set_retry_read(bio);
210                     return bio->num;
211           }
212 
213           memcpy(out, bio_mem_read_ptr(bm), out_len);
214           bm->read_offset += out_len;
215 
216           return out_len;
217 }
218 
219 static int
mem_write(BIO * bio,const char * in,int in_len)220 mem_write(BIO *bio, const char *in, int in_len)
221 {
222           struct bio_mem *bm = bio->ptr;
223           size_t buf_len;
224 
225           BIO_clear_retry_flags(bio);
226 
227           if (in == NULL || in_len <= 0)
228                     return 0;
229 
230           if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
231                     BIOerror(BIO_R_WRITE_TO_READ_ONLY_BIO);
232                     return -1;
233           }
234 
235           if (bm->read_offset > 4096) {
236                     memmove(bm->buf->data, bio_mem_read_ptr(bm),
237                         bio_mem_pending(bm));
238                     bm->buf->length = bio_mem_pending(bm);
239                     bm->read_offset = 0;
240           }
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           buf_len = bm->buf->length + in_len;
247           if (buf_len < bm->buf->length || buf_len > INT_MAX)
248                     return -1;
249 
250           if (BUF_MEM_grow_clean(bm->buf, buf_len) != buf_len)
251                     return -1;
252 
253           memcpy(&bm->buf->data[buf_len - in_len], in, in_len);
254 
255           return in_len;
256 }
257 
258 static long
mem_ctrl(BIO * bio,int cmd,long num,void * ptr)259 mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
260 {
261           struct bio_mem *bm = bio->ptr;
262           void **pptr;
263           long ret = 1;
264 
265           switch (cmd) {
266           case BIO_CTRL_RESET:
267                     if (bm->buf->data != NULL) {
268                               if (!(bio->flags & BIO_FLAGS_MEM_RDONLY)) {
269                                         memset(bm->buf->data, 0, bm->buf->max);
270                                         bm->buf->length = 0;
271                               }
272                               bm->read_offset = 0;
273                     }
274                     break;
275           case BIO_CTRL_EOF:
276                     ret = (long)(bio_mem_pending(bm) == 0);
277                     break;
278           case BIO_C_SET_BUF_MEM_EOF_RETURN:
279                     bio->num = (int)num;
280                     break;
281           case BIO_CTRL_INFO:
282                     if (ptr != NULL) {
283                               pptr = (void **)ptr;
284                               *pptr = bio_mem_read_ptr(bm);
285                     }
286                     ret = (long)bio_mem_pending(bm);
287                     break;
288           case BIO_C_SET_BUF_MEM:
289                     BUF_MEM_free(bm->buf);
290                     bio->shutdown = (int)num;
291                     bm->buf = ptr;
292                     bm->read_offset = 0;
293                     break;
294           case BIO_C_GET_BUF_MEM_PTR:
295                     if (ptr != NULL) {
296                               pptr = (void **)ptr;
297                               *pptr = bm->buf;
298                     }
299                     break;
300           case BIO_CTRL_GET_CLOSE:
301                     ret = (long)bio->shutdown;
302                     break;
303           case BIO_CTRL_SET_CLOSE:
304                     bio->shutdown = (int)num;
305                     break;
306           case BIO_CTRL_WPENDING:
307                     ret = 0L;
308                     break;
309           case BIO_CTRL_PENDING:
310                     ret = (long)bio_mem_pending(bm);
311                     break;
312           case BIO_CTRL_DUP:
313           case BIO_CTRL_FLUSH:
314                     ret = 1;
315                     break;
316           case BIO_CTRL_PUSH:
317           case BIO_CTRL_POP:
318           default:
319                     ret = 0;
320                     break;
321           }
322           return ret;
323 }
324 
325 static int
mem_gets(BIO * bio,char * out,int out_len)326 mem_gets(BIO *bio, char *out, int out_len)
327 {
328           struct bio_mem *bm = bio->ptr;
329           int i, out_max;
330           char *p;
331           int ret = -1;
332 
333           BIO_clear_retry_flags(bio);
334 
335           out_max = bio_mem_pending(bm);
336           if (out_len - 1 < out_max)
337                     out_max = out_len - 1;
338           if (out_max <= 0) {
339                     *out = '\0';
340                     return 0;
341           }
342 
343           p = bio_mem_read_ptr(bm);
344           for (i = 0; i < out_max; i++) {
345                     if (p[i] == '\n') {
346                               i++;
347                               break;
348                     }
349           }
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           if ((ret = mem_read(bio, out, i)) > 0)
356                     out[ret] = '\0';
357 
358           return ret;
359 }
360 
361 static int
mem_puts(BIO * bio,const char * in)362 mem_puts(BIO *bio, const char *in)
363 {
364           return mem_write(bio, in, strlen(in));
365 }
366