xref: /openbsd-src/lib/libcrypto/bio/bss_mem.c (revision 4c6baae929199f9c0d038e355789ef6c5e1be7a0)
1 /* $OpenBSD: bss_mem.c,v 1.19 2022/02/18 17:30:13 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 static int mem_new(BIO *bio);
71 static int mem_free(BIO *bio);
72 static int mem_write(BIO *bio, const char *in, int in_len);
73 static int mem_read(BIO *bio, char *out, int out_len);
74 static int mem_puts(BIO *bio, const char *in);
75 static int mem_gets(BIO *bio, char *out, int out_len);
76 static long mem_ctrl(BIO *bio, int cmd, long arg1, void *arg2);
77 
78 static const BIO_METHOD mem_method = {
79 	.type = BIO_TYPE_MEM,
80 	.name = "memory buffer",
81 	.bwrite = mem_write,
82 	.bread = mem_read,
83 	.bputs = mem_puts,
84 	.bgets = mem_gets,
85 	.ctrl = mem_ctrl,
86 	.create = mem_new,
87 	.destroy = mem_free
88 };
89 
90 /*
91  * bio->num is used to hold the value to return on 'empty', if it is
92  * 0, should_retry is not set.
93  */
94 
95 const BIO_METHOD *
96 BIO_s_mem(void)
97 {
98 	return &mem_method;
99 }
100 
101 BIO *
102 BIO_new_mem_buf(const void *buf, int buf_len)
103 {
104 	BIO *bio;
105 	BUF_MEM *b;
106 
107 	if (buf == NULL) {
108 		BIOerror(BIO_R_NULL_PARAMETER);
109 		return NULL;
110 	}
111 	if (buf_len == -1)
112 		buf_len = strlen(buf);
113 	if (buf_len < 0) {
114 		BIOerror(BIO_R_INVALID_ARGUMENT);
115 		return NULL;
116 	}
117 
118 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
119 		return NULL;
120 
121 	b = bio->ptr;
122 	b->data = (void *)buf;	/* Trust in the BIO_FLAGS_MEM_RDONLY flag. */
123 	b->length = buf_len;
124 	b->max = buf_len;
125 	bio->flags |= BIO_FLAGS_MEM_RDONLY;
126 	/* Since this is static data retrying will not help. */
127 	bio->num = 0;
128 
129 	return bio;
130 }
131 
132 static int
133 mem_new(BIO *bio)
134 {
135 	BUF_MEM *b;
136 
137 	if ((b = BUF_MEM_new()) == NULL)
138 		return 0;
139 
140 	bio->shutdown = 1;
141 	bio->init = 1;
142 	bio->num = -1;
143 	bio->ptr = b;
144 
145 	return 1;
146 }
147 
148 static int
149 mem_free(BIO *bio)
150 {
151 	BUF_MEM *b;
152 
153 	if (bio == NULL)
154 		return 0;
155 	if (!bio->shutdown || !bio->init || bio->ptr == NULL)
156 		return 1;
157 
158 	b = bio->ptr;
159 	if (bio->flags & BIO_FLAGS_MEM_RDONLY)
160 		b->data = NULL;
161 	BUF_MEM_free(b);
162 	bio->ptr = NULL;
163 
164 	return 1;
165 }
166 
167 static int
168 mem_read(BIO *bio, char *out, int out_len)
169 {
170 	BUF_MEM *bm = bio->ptr;
171 
172 	BIO_clear_retry_flags(bio);
173 
174 	if (out == NULL || out_len <= 0)
175 		return 0;
176 
177 	if ((size_t)out_len > bm->length)
178 		out_len = bm->length;
179 
180 	if (out_len == 0) {
181 		if (bio->num != 0)
182 			BIO_set_retry_read(bio);
183 		return bio->num;
184 	}
185 
186 	memcpy(out, bm->data, out_len);
187 	bm->length -= out_len;
188 	if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
189 		bm->data += out_len;
190 	} else {
191 		memmove(&(bm->data[0]), &(bm->data[out_len]),
192 		    bm->length);
193 	}
194 	return out_len;
195 }
196 
197 static int
198 mem_write(BIO *bio, const char *in, int in_len)
199 {
200 	BUF_MEM *bm = bio->ptr;
201 	size_t buf_len;
202 
203 	BIO_clear_retry_flags(bio);
204 
205 	if (in == NULL || in_len <= 0)
206 		return 0;
207 
208 	if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
209 		BIOerror(BIO_R_WRITE_TO_READ_ONLY_BIO);
210 		return -1;
211 	}
212 
213 	/*
214 	 * Check for overflow and ensure we do not exceed an int, otherwise we
215 	 * cannot tell if BUF_MEM_grow_clean() succeeded.
216 	 */
217 	buf_len = bm->length + in_len;
218 	if (buf_len < bm->length || buf_len > INT_MAX)
219 		return -1;
220 
221 	if (BUF_MEM_grow_clean(bm, buf_len) != buf_len)
222 		return -1;
223 
224 	memcpy(&bm->data[buf_len - in_len], in, in_len);
225 
226 	return in_len;
227 }
228 
229 static long
230 mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
231 {
232 	BUF_MEM *bm = bio->ptr;
233 	long ret = 1;
234 	char **pptr;
235 
236 	switch (cmd) {
237 	case BIO_CTRL_RESET:
238 		if (bm->data != NULL) {
239 			/* For read only case reset to the start again */
240 			if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
241 				bm->data -= bm->max - bm->length;
242 				bm->length = bm->max;
243 			} else {
244 				memset(bm->data, 0, bm->max);
245 				bm->length = 0;
246 			}
247 		}
248 		break;
249 	case BIO_CTRL_EOF:
250 		ret = (long)(bm->length == 0);
251 		break;
252 	case BIO_C_SET_BUF_MEM_EOF_RETURN:
253 		bio->num = (int)num;
254 		break;
255 	case BIO_CTRL_INFO:
256 		if (ptr != NULL) {
257 			pptr = (char **)ptr;
258 			*pptr = (char *)bm->data;
259 		}
260 		ret = (long)bm->length;
261 		break;
262 	case BIO_C_SET_BUF_MEM:
263 		mem_free(bio);
264 		bio->shutdown = (int)num;
265 		bio->ptr = ptr;
266 		break;
267 	case BIO_C_GET_BUF_MEM_PTR:
268 		if (ptr != NULL) {
269 			pptr = (char **)ptr;
270 			*pptr = (char *)bm;
271 		}
272 		break;
273 	case BIO_CTRL_GET_CLOSE:
274 		ret = (long)bio->shutdown;
275 		break;
276 	case BIO_CTRL_SET_CLOSE:
277 		bio->shutdown = (int)num;
278 		break;
279 	case BIO_CTRL_WPENDING:
280 		ret = 0L;
281 		break;
282 	case BIO_CTRL_PENDING:
283 		ret = (long)bm->length;
284 		break;
285 	case BIO_CTRL_DUP:
286 	case BIO_CTRL_FLUSH:
287 		ret = 1;
288 		break;
289 	case BIO_CTRL_PUSH:
290 	case BIO_CTRL_POP:
291 	default:
292 		ret = 0;
293 		break;
294 	}
295 	return ret;
296 }
297 
298 static int
299 mem_gets(BIO *bio, char *out, int out_len)
300 {
301 	BUF_MEM *bm = bio->ptr;
302 	int i, out_max;
303 	char *p;
304 	int ret = -1;
305 
306 	BIO_clear_retry_flags(bio);
307 
308 	out_max = bm->length;
309 	if (out_len - 1 < out_max)
310 		out_max = out_len - 1;
311 	if (out_max <= 0) {
312 		*out = '\0';
313 		return 0;
314 	}
315 
316 	p = bm->data;
317 	for (i = 0; i < out_max; i++) {
318 		if (p[i] == '\n') {
319 			i++;
320 			break;
321 		}
322 	}
323 
324 	/*
325 	 * i is now the max num of bytes to copy, either out_max or up to and
326 	 * including the first newline
327 	 */
328 	if ((ret = mem_read(bio, out, i)) > 0)
329 		out[ret] = '\0';
330 
331 	return ret;
332 }
333 
334 static int
335 mem_puts(BIO *bio, const char *in)
336 {
337 	return mem_write(bio, in, strlen(in));
338 }
339