]>
Commit | Line | Data |
---|---|---|
b1322259 | 1 | /* |
da1c088f | 2 | * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
09abbca1 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
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 | |
d02b48c6 RE |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
11 | #include <errno.h> | |
706457b7 | 12 | #include "bio_local.h" |
b39fc560 | 13 | #include "internal/cryptlib.h" |
d02b48c6 | 14 | |
0e1c0612 UM |
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); | |
d02b48c6 | 20 | static int mem_new(BIO *h); |
74924dcb | 21 | static int secmem_new(BIO *h); |
d02b48c6 | 22 | static int mem_free(BIO *data); |
c6048af2 | 23 | static int mem_buf_free(BIO *data); |
9fe9d046 | 24 | static int mem_buf_sync(BIO *h); |
d3e6d6bc | 25 | |
04f6b0fd | 26 | static const BIO_METHOD mem_method = { |
0f113f3e MC |
27 | BIO_TYPE_MEM, |
28 | "memory buffer", | |
3befffa3 | 29 | bwrite_conv, |
0f113f3e | 30 | mem_write, |
d07aee2c | 31 | bread_conv, |
0f113f3e MC |
32 | mem_read, |
33 | mem_puts, | |
34 | mem_gets, | |
35 | mem_ctrl, | |
36 | mem_new, | |
37 | mem_free, | |
b4ff6622 | 38 | NULL, /* mem_callback_ctrl */ |
0f113f3e | 39 | }; |
d3e6d6bc | 40 | |
04f6b0fd | 41 | static const BIO_METHOD secmem_method = { |
74924dcb RS |
42 | BIO_TYPE_MEM, |
43 | "secure memory buffer", | |
3befffa3 | 44 | bwrite_conv, |
74924dcb | 45 | mem_write, |
d07aee2c | 46 | bread_conv, |
74924dcb RS |
47 | mem_read, |
48 | mem_puts, | |
49 | mem_gets, | |
50 | mem_ctrl, | |
51 | secmem_new, | |
52 | mem_free, | |
b4ff6622 | 53 | NULL, /* mem_callback_ctrl */ |
74924dcb | 54 | }; |
d02b48c6 | 55 | |
b238fb79 TM |
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 | */ | |
d3e6d6bc KM |
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 | ||
0f113f3e MC |
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 | */ | |
dfeab068 | 71 | |
04f6b0fd | 72 | const BIO_METHOD *BIO_s_mem(void) |
0f113f3e | 73 | { |
26a7d938 | 74 | return &mem_method; |
0f113f3e | 75 | } |
d02b48c6 | 76 | |
04f6b0fd | 77 | const BIO_METHOD *BIO_s_secmem(void) |
74924dcb RS |
78 | { |
79 | return(&secmem_method); | |
80 | } | |
81 | ||
8ab31975 | 82 | BIO *BIO_new_mem_buf(const void *buf, int len) |
8484721a | 83 | { |
0f113f3e MC |
84 | BIO *ret; |
85 | BUF_MEM *b; | |
9fe9d046 | 86 | BIO_BUF_MEM *bb; |
0f113f3e | 87 | size_t sz; |
ae1552ee | 88 | |
75ebbd9a | 89 | if (buf == NULL) { |
ed4a9b15 | 90 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
0f113f3e MC |
91 | return NULL; |
92 | } | |
93 | sz = (len < 0) ? strlen(buf) : (size_t)len; | |
75ebbd9a | 94 | if ((ret = BIO_new(BIO_s_mem())) == NULL) |
0f113f3e | 95 | return NULL; |
9fe9d046 KM |
96 | bb = (BIO_BUF_MEM *)ret->ptr; |
97 | b = bb->buf; | |
8ab31975 DKG |
98 | /* Cast away const and trust in the MEM_RDONLY flag. */ |
99 | b->data = (void *)buf; | |
0f113f3e MC |
100 | b->length = sz; |
101 | b->max = sz; | |
9fe9d046 | 102 | *bb->readp = *bb->buf; |
0f113f3e | 103 | ret->flags |= BIO_FLAGS_MEM_RDONLY; |
60250017 | 104 | /* Since this is static data retrying won't help */ |
0f113f3e MC |
105 | ret->num = 0; |
106 | return ret; | |
8484721a DSH |
107 | } |
108 | ||
74924dcb | 109 | static int mem_init(BIO *bi, unsigned long flags) |
0f113f3e | 110 | { |
fc9755ee | 111 | BIO_BUF_MEM *bb = OPENSSL_zalloc(sizeof(*bb)); |
d02b48c6 | 112 | |
9fe9d046 | 113 | if (bb == NULL) |
b0b6ba2d MC |
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 | } | |
9fe9d046 | 124 | *bb->readp = *bb->buf; |
0f113f3e MC |
125 | bi->shutdown = 1; |
126 | bi->init = 1; | |
127 | bi->num = -1; | |
9fe9d046 | 128 | bi->ptr = (char *)bb; |
b0b6ba2d | 129 | return 1; |
74924dcb RS |
130 | } |
131 | ||
132 | static int mem_new(BIO *bi) | |
133 | { | |
26a7d938 | 134 | return mem_init(bi, 0L); |
74924dcb RS |
135 | } |
136 | ||
137 | static int secmem_new(BIO *bi) | |
138 | { | |
26a7d938 | 139 | return mem_init(bi, BUF_MEM_FLAG_SECURE); |
0f113f3e | 140 | } |
d02b48c6 | 141 | |
6b691a5c | 142 | static int mem_free(BIO *a) |
9fe9d046 | 143 | { |
c6048af2 CM |
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; | |
9fe9d046 KM |
155 | } |
156 | ||
c6048af2 | 157 | static int mem_buf_free(BIO *a) |
0f113f3e MC |
158 | { |
159 | if (a == NULL) | |
26a7d938 | 160 | return 0; |
a0fda2cf F |
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); | |
0f113f3e | 169 | } |
208fb891 | 170 | return 1; |
0f113f3e MC |
171 | } |
172 | ||
9fe9d046 KM |
173 | /* |
174 | * Reallocate memory buffer if read pointer differs | |
1dbf4537 | 175 | * NOT FOR RDONLY |
9fe9d046 KM |
176 | */ |
177 | static int mem_buf_sync(BIO *b) | |
178 | { | |
e8aa8b6c | 179 | if (b != NULL && b->init != 0 && b->ptr != NULL) { |
9fe9d046 KM |
180 | BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; |
181 | ||
e8aa8b6c | 182 | if (bbm->readp->data != bbm->buf->data) { |
9fe9d046 KM |
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 | } | |
26a7d938 | 188 | return 0; |
9fe9d046 KM |
189 | } |
190 | ||
6b691a5c | 191 | static int mem_read(BIO *b, char *out, int outl) |
0f113f3e MC |
192 | { |
193 | int ret = -1; | |
9fe9d046 KM |
194 | BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; |
195 | BUF_MEM *bm = bbm->readp; | |
d02b48c6 | 196 | |
b238fb79 TM |
197 | if (b->flags & BIO_FLAGS_MEM_RDONLY) |
198 | bm = bbm->buf; | |
0f113f3e | 199 | BIO_clear_retry_flags(b); |
6e193d4d | 200 | ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl; |
0f113f3e MC |
201 | if ((out != NULL) && (ret > 0)) { |
202 | memcpy(out, bm->data, ret); | |
6e193d4d TM |
203 | bm->length -= ret; |
204 | bm->max -= ret; | |
205 | bm->data += ret; | |
206 | } else if (bm->length == 0) { | |
0f113f3e MC |
207 | ret = b->num; |
208 | if (ret != 0) | |
209 | BIO_set_retry_read(b); | |
210 | } | |
26a7d938 | 211 | return ret; |
0f113f3e | 212 | } |
d02b48c6 | 213 | |
0e1c0612 | 214 | static int mem_write(BIO *b, const char *in, int inl) |
0f113f3e MC |
215 | { |
216 | int ret = -1; | |
217 | int blen; | |
9fe9d046 | 218 | BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; |
d02b48c6 | 219 | |
0f113f3e | 220 | if (b->flags & BIO_FLAGS_MEM_RDONLY) { |
9311d0c4 | 221 | ERR_raise(ERR_LIB_BIO, BIO_R_WRITE_TO_READ_ONLY_BIO); |
0f113f3e MC |
222 | goto end; |
223 | } | |
0f113f3e | 224 | BIO_clear_retry_flags(b); |
0d94212a RL |
225 | if (inl == 0) |
226 | return 0; | |
daa86f9e | 227 | if (in == NULL) { |
228 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); | |
229 | goto end; | |
230 | } | |
9fe9d046 KM |
231 | blen = bbm->readp->length; |
232 | mem_buf_sync(b); | |
233 | if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0) | |
0f113f3e | 234 | goto end; |
9fe9d046 KM |
235 | memcpy(bbm->buf->data + blen, in, inl); |
236 | *bbm->readp = *bbm->buf; | |
0f113f3e MC |
237 | ret = inl; |
238 | end: | |
26a7d938 | 239 | return ret; |
0f113f3e | 240 | } |
d02b48c6 | 241 | |
0e1c0612 | 242 | static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) |
0f113f3e MC |
243 | { |
244 | long ret = 1; | |
245 | char **pptr; | |
9fe9d046 | 246 | BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; |
1dbf4537 RL |
247 | BUF_MEM *bm, *bo; /* bio_mem, bio_other */ |
248 | long off, remain; | |
d02b48c6 | 249 | |
1dbf4537 | 250 | if (b->flags & BIO_FLAGS_MEM_RDONLY) { |
b238fb79 | 251 | bm = bbm->buf; |
1dbf4537 RL |
252 | bo = bbm->readp; |
253 | } else { | |
b238fb79 | 254 | bm = bbm->readp; |
1dbf4537 RL |
255 | bo = bbm->buf; |
256 | } | |
a98b2658 | 257 | off = (bm->data == bo->data) ? 0 : bm->data - bo->data; |
1dbf4537 | 258 | remain = bm->length; |
b238fb79 | 259 | |
0f113f3e MC |
260 | switch (cmd) { |
261 | case BIO_CTRL_RESET: | |
9fe9d046 | 262 | bm = bbm->buf; |
0f113f3e | 263 | if (bm->data != NULL) { |
b238fb79 | 264 | if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) { |
8b7b3292 | 265 | if (!(b->flags & BIO_FLAGS_NONCLEAR_RST)) { |
b238fb79 TM |
266 | memset(bm->data, 0, bm->max); |
267 | bm->length = 0; | |
268 | } | |
269 | *bbm->readp = *bbm->buf; | |
0f113f3e | 270 | } else { |
b238fb79 TM |
271 | /* For read only case just reset to the start again */ |
272 | *bbm->buf = *bbm->readp; | |
0f113f3e MC |
273 | } |
274 | } | |
275 | break; | |
1dbf4537 RL |
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 | ||
a98b2658 | 280 | bm->data = (num != 0) ? bo->data + num : bo->data; |
1dbf4537 RL |
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; | |
0f113f3e | 288 | case BIO_CTRL_EOF: |
6e193d4d | 289 | ret = (long)(bm->length == 0); |
0f113f3e MC |
290 | break; |
291 | case BIO_C_SET_BUF_MEM_EOF_RETURN: | |
6e193d4d | 292 | b->num = (int)num; |
0f113f3e MC |
293 | break; |
294 | case BIO_CTRL_INFO: | |
295 | ret = (long)bm->length; | |
296 | if (ptr != NULL) { | |
297 | pptr = (char **)ptr; | |
a07dc816 | 298 | *pptr = (char *)(bm->data); |
0f113f3e MC |
299 | } |
300 | break; | |
301 | case BIO_C_SET_BUF_MEM: | |
c6048af2 | 302 | mem_buf_free(b); |
0f113f3e | 303 | b->shutdown = (int)num; |
9fe9d046 KM |
304 | bbm->buf = ptr; |
305 | *bbm->readp = *bbm->buf; | |
0f113f3e MC |
306 | break; |
307 | case BIO_C_GET_BUF_MEM_PTR: | |
308 | if (ptr != NULL) { | |
b238fb79 TM |
309 | if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) |
310 | mem_buf_sync(b); | |
311 | bm = bbm->buf; | |
0f113f3e MC |
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; | |
0f113f3e MC |
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 | } | |
26a7d938 | 338 | return ret; |
0f113f3e | 339 | } |
d02b48c6 | 340 | |
6b691a5c | 341 | static int mem_gets(BIO *bp, char *buf, int size) |
0f113f3e MC |
342 | { |
343 | int i, j; | |
344 | int ret = -1; | |
345 | char *p; | |
9fe9d046 KM |
346 | BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr; |
347 | BUF_MEM *bm = bbm->readp; | |
d02b48c6 | 348 | |
b238fb79 TM |
349 | if (bp->flags & BIO_FLAGS_MEM_RDONLY) |
350 | bm = bbm->buf; | |
0f113f3e | 351 | BIO_clear_retry_flags(bp); |
6e193d4d | 352 | j = bm->length; |
0f113f3e MC |
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 | } | |
77202a85 | 366 | |
0f113f3e MC |
367 | /* |
368 | * i is now the max num of bytes to copy, either j or up to | |
369 | * and including the first newline | |
370 | */ | |
77202a85 | 371 | |
0f113f3e MC |
372 | i = mem_read(bp, buf, i); |
373 | if (i > 0) | |
374 | buf[i] = '\0'; | |
375 | ret = i; | |
26a7d938 | 376 | return ret; |
0f113f3e | 377 | } |
d02b48c6 | 378 | |
0e1c0612 | 379 | static int mem_puts(BIO *bp, const char *str) |
0f113f3e MC |
380 | { |
381 | int n, ret; | |
d02b48c6 | 382 | |
0f113f3e MC |
383 | n = strlen(str); |
384 | ret = mem_write(bp, str, n); | |
385 | /* memory semantics is that it will always work */ | |
26a7d938 | 386 | return ret; |
0f113f3e | 387 | } |