xref: /freebsd/crypto/openssl/crypto/bio/bss_mem.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
1 /*
2  * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <stdio.h>
11 #include <errno.h>
12 #include "bio_local.h"
13 #include "internal/cryptlib.h"
14 
15 static int mem_write(BIO *h, const char *buf, int num);
16 static int mem_read(BIO *h, char *buf, int size);
17 static int mem_puts(BIO *h, const char *str);
18 static int mem_gets(BIO *h, char *str, int size);
19 static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2);
20 static int mem_new(BIO *h);
21 static int secmem_new(BIO *h);
22 static int mem_free(BIO *data);
23 static int mem_buf_free(BIO *data);
24 static int mem_buf_sync(BIO *h);
25 
26 static const BIO_METHOD mem_method = {
27     BIO_TYPE_MEM,
28     "memory buffer",
29     bwrite_conv,
30     mem_write,
31     bread_conv,
32     mem_read,
33     mem_puts,
34     mem_gets,
35     mem_ctrl,
36     mem_new,
37     mem_free,
38     NULL,                      /* mem_callback_ctrl */
39 };
40 
41 static const BIO_METHOD secmem_method = {
42     BIO_TYPE_MEM,
43     "secure memory buffer",
44     bwrite_conv,
45     mem_write,
46     bread_conv,
47     mem_read,
48     mem_puts,
49     mem_gets,
50     mem_ctrl,
51     secmem_new,
52     mem_free,
53     NULL,                      /* mem_callback_ctrl */
54 };
55 
56 /*
57  * BIO memory stores buffer and read pointer
58  * however the roles are different for read only BIOs.
59  * In that case the readp just stores the original state
60  * to be used for reset.
61  */
62 typedef struct bio_buf_mem_st {
63     struct buf_mem_st *buf;   /* allocated buffer */
64     struct buf_mem_st *readp; /* read pointer */
65 } BIO_BUF_MEM;
66 
67 /*
68  * bio->num is used to hold the value to return on 'empty', if it is 0,
69  * should_retry is not set
70  */
71 
BIO_s_mem(void)72 const BIO_METHOD *BIO_s_mem(void)
73 {
74     return &mem_method;
75 }
76 
BIO_s_secmem(void)77 const BIO_METHOD *BIO_s_secmem(void)
78 {
79     return(&secmem_method);
80 }
81 
BIO_new_mem_buf(const void * buf,int len)82 BIO *BIO_new_mem_buf(const void *buf, int len)
83 {
84     BIO *ret;
85     BUF_MEM *b;
86     BIO_BUF_MEM *bb;
87     size_t sz;
88 
89     if (buf == NULL) {
90         ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
91         return NULL;
92     }
93     sz = (len < 0) ? strlen(buf) : (size_t)len;
94     if ((ret = BIO_new(BIO_s_mem())) == NULL)
95         return NULL;
96     bb = (BIO_BUF_MEM *)ret->ptr;
97     b = bb->buf;
98     /* Cast away const and trust in the MEM_RDONLY flag. */
99     b->data = (void *)buf;
100     b->length = sz;
101     b->max = sz;
102     *bb->readp = *bb->buf;
103     ret->flags |= BIO_FLAGS_MEM_RDONLY;
104     /* Since this is static data retrying won't help */
105     ret->num = 0;
106     return ret;
107 }
108 
mem_init(BIO * bi,unsigned long flags)109 static int mem_init(BIO *bi, unsigned long flags)
110 {
111     BIO_BUF_MEM *bb = OPENSSL_zalloc(sizeof(*bb));
112 
113     if (bb == NULL)
114         return 0;
115     if ((bb->buf = BUF_MEM_new_ex(flags)) == NULL) {
116         OPENSSL_free(bb);
117         return 0;
118     }
119     if ((bb->readp = OPENSSL_zalloc(sizeof(*bb->readp))) == NULL) {
120         BUF_MEM_free(bb->buf);
121         OPENSSL_free(bb);
122         return 0;
123     }
124     *bb->readp = *bb->buf;
125     bi->shutdown = 1;
126     bi->init = 1;
127     bi->num = -1;
128     bi->ptr = (char *)bb;
129     return 1;
130 }
131 
mem_new(BIO * bi)132 static int mem_new(BIO *bi)
133 {
134     return mem_init(bi, 0L);
135 }
136 
secmem_new(BIO * bi)137 static int secmem_new(BIO *bi)
138 {
139     return mem_init(bi, BUF_MEM_FLAG_SECURE);
140 }
141 
mem_free(BIO * a)142 static int mem_free(BIO *a)
143 {
144     BIO_BUF_MEM *bb;
145 
146     if (a == NULL)
147         return 0;
148 
149     bb = (BIO_BUF_MEM *)a->ptr;
150     if (!mem_buf_free(a))
151         return 0;
152     OPENSSL_free(bb->readp);
153     OPENSSL_free(bb);
154     return 1;
155 }
156 
mem_buf_free(BIO * a)157 static int mem_buf_free(BIO *a)
158 {
159     if (a == NULL)
160         return 0;
161 
162     if (a->shutdown && a->init && a->ptr != NULL) {
163         BIO_BUF_MEM *bb = (BIO_BUF_MEM *)a->ptr;
164         BUF_MEM *b = bb->buf;
165 
166         if (a->flags & BIO_FLAGS_MEM_RDONLY)
167             b->data = NULL;
168         BUF_MEM_free(b);
169     }
170     return 1;
171 }
172 
173 /*
174  * Reallocate memory buffer if read pointer differs
175  * NOT FOR RDONLY
176  */
mem_buf_sync(BIO * b)177 static int mem_buf_sync(BIO *b)
178 {
179     if (b != NULL && b->init != 0 && b->ptr != NULL) {
180         BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
181 
182         if (bbm->readp->data != bbm->buf->data) {
183             memmove(bbm->buf->data, bbm->readp->data, bbm->readp->length);
184             bbm->buf->length = bbm->readp->length;
185             bbm->readp->data = bbm->buf->data;
186         }
187     }
188     return 0;
189 }
190 
mem_read(BIO * b,char * out,int outl)191 static int mem_read(BIO *b, char *out, int outl)
192 {
193     int ret = -1;
194     BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
195     BUF_MEM *bm = bbm->readp;
196 
197     if (b->flags & BIO_FLAGS_MEM_RDONLY)
198         bm = bbm->buf;
199     BIO_clear_retry_flags(b);
200     ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl;
201     if ((out != NULL) && (ret > 0)) {
202         memcpy(out, bm->data, ret);
203         bm->length -= ret;
204         bm->max -= ret;
205         bm->data += ret;
206     } else if (bm->length == 0) {
207         ret = b->num;
208         if (ret != 0)
209             BIO_set_retry_read(b);
210     }
211     return ret;
212 }
213 
mem_write(BIO * b,const char * in,int inl)214 static int mem_write(BIO *b, const char *in, int inl)
215 {
216     int ret = -1;
217     int blen;
218     BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
219 
220     if (b->flags & BIO_FLAGS_MEM_RDONLY) {
221         ERR_raise(ERR_LIB_BIO, BIO_R_WRITE_TO_READ_ONLY_BIO);
222         goto end;
223     }
224     BIO_clear_retry_flags(b);
225     if (inl == 0)
226         return 0;
227     if (in == NULL) {
228         ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
229         goto end;
230     }
231     blen = bbm->readp->length;
232     mem_buf_sync(b);
233     if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0)
234         goto end;
235     memcpy(bbm->buf->data + blen, in, inl);
236     *bbm->readp = *bbm->buf;
237     ret = inl;
238  end:
239     return ret;
240 }
241 
mem_ctrl(BIO * b,int cmd,long num,void * ptr)242 static long mem_ctrl(BIO *b, int cmd, long num, void *ptr)
243 {
244     long ret = 1;
245     char **pptr;
246     BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
247     BUF_MEM *bm, *bo;            /* bio_mem, bio_other */
248     long off, remain;
249 
250     if (b->flags & BIO_FLAGS_MEM_RDONLY) {
251         bm = bbm->buf;
252         bo = bbm->readp;
253     } else {
254         bm = bbm->readp;
255         bo = bbm->buf;
256     }
257     off = (bm->data == bo->data) ? 0 : bm->data - bo->data;
258     remain = bm->length;
259 
260     switch (cmd) {
261     case BIO_CTRL_RESET:
262         bm = bbm->buf;
263         if (bm->data != NULL) {
264             if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) {
265                 if (!(b->flags & BIO_FLAGS_NONCLEAR_RST)) {
266                     memset(bm->data, 0, bm->max);
267                     bm->length = 0;
268                 }
269                 *bbm->readp = *bbm->buf;
270             } else {
271                 /* For read only case just reset to the start again */
272                 *bbm->buf = *bbm->readp;
273             }
274         }
275         break;
276     case BIO_C_FILE_SEEK:
277         if (num < 0 || num > off + remain)
278             return -1;   /* Can't see outside of the current buffer */
279 
280         bm->data = (num != 0) ? bo->data + num : bo->data;
281         bm->length = bo->length - num;
282         bm->max = bo->max - num;
283         off = num;
284         /* FALLTHRU */
285     case BIO_C_FILE_TELL:
286         ret = off;
287         break;
288     case BIO_CTRL_EOF:
289         ret = (long)(bm->length == 0);
290         break;
291     case BIO_C_SET_BUF_MEM_EOF_RETURN:
292         b->num = (int)num;
293         break;
294     case BIO_CTRL_INFO:
295         ret = (long)bm->length;
296         if (ptr != NULL) {
297             pptr = (char **)ptr;
298             *pptr = (char *)(bm->data);
299         }
300         break;
301     case BIO_C_SET_BUF_MEM:
302         mem_buf_free(b);
303         b->shutdown = (int)num;
304         bbm->buf = ptr;
305         *bbm->readp = *bbm->buf;
306         break;
307     case BIO_C_GET_BUF_MEM_PTR:
308         if (ptr != NULL) {
309             if (!(b->flags & BIO_FLAGS_MEM_RDONLY))
310                 mem_buf_sync(b);
311             bm = bbm->buf;
312             pptr = (char **)ptr;
313             *pptr = (char *)bm;
314         }
315         break;
316     case BIO_CTRL_GET_CLOSE:
317         ret = (long)b->shutdown;
318         break;
319     case BIO_CTRL_SET_CLOSE:
320         b->shutdown = (int)num;
321         break;
322     case BIO_CTRL_WPENDING:
323         ret = 0L;
324         break;
325     case BIO_CTRL_PENDING:
326         ret = (long)bm->length;
327         break;
328     case BIO_CTRL_DUP:
329     case BIO_CTRL_FLUSH:
330         ret = 1;
331         break;
332     case BIO_CTRL_PUSH:
333     case BIO_CTRL_POP:
334     default:
335         ret = 0;
336         break;
337     }
338     return ret;
339 }
340 
mem_gets(BIO * bp,char * buf,int size)341 static int mem_gets(BIO *bp, char *buf, int size)
342 {
343     int i, j;
344     int ret = -1;
345     char *p;
346     BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr;
347     BUF_MEM *bm = bbm->readp;
348 
349     if (bp->flags & BIO_FLAGS_MEM_RDONLY)
350         bm = bbm->buf;
351     BIO_clear_retry_flags(bp);
352     j = bm->length;
353     if ((size - 1) < j)
354         j = size - 1;
355     if (j <= 0) {
356         *buf = '\0';
357         return 0;
358     }
359     p = bm->data;
360     for (i = 0; i < j; i++) {
361         if (p[i] == '\n') {
362             i++;
363             break;
364         }
365     }
366 
367     /*
368      * i is now the max num of bytes to copy, either j or up to
369      * and including the first newline
370      */
371 
372     i = mem_read(bp, buf, i);
373     if (i > 0)
374         buf[i] = '\0';
375     ret = i;
376     return ret;
377 }
378 
mem_puts(BIO * bp,const char * str)379 static int mem_puts(BIO *bp, const char *str)
380 {
381     int n, ret;
382 
383     n = strlen(str);
384     ret = mem_write(bp, str, n);
385     /* memory semantics is that it will always work */
386     return ret;
387 }
388