xref: /dragonfly/crypto/libressl/crypto/bio/bss_mem.c (revision 6f5ec8b5)
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 {
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 *
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 *
116 BIO_s_mem(void)
117 {
118 	return &mem_method;
119 }
120 
121 BIO *
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
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
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
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
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
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
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
362 mem_puts(BIO *bio, const char *in)
363 {
364 	return mem_write(bio, in, strlen(in));
365 }
366