xref: /openbsd-src/lib/libcrypto/evp/bio_b64.c (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
1 /* $OpenBSD: bio_b64.c,v 1.23 2021/12/12 21:30:13 tb 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 <stdio.h>
61 #include <string.h>
62 
63 #include <openssl/buffer.h>
64 #include <openssl/evp.h>
65 
66 #include "evp_locl.h"
67 
68 static int b64_write(BIO *h, const char *buf, int num);
69 static int b64_read(BIO *h, char *buf, int size);
70 static int b64_puts(BIO *h, const char *str);
71 /*static int b64_gets(BIO *h, char *str, int size); */
72 static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
73 static int b64_new(BIO *h);
74 static int b64_free(BIO *data);
75 static long b64_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
76 #define B64_BLOCK_SIZE	1024
77 #define B64_BLOCK_SIZE2	768
78 #define B64_NONE	0
79 #define B64_ENCODE	1
80 #define B64_DECODE	2
81 
82 typedef struct b64_struct {
83 	/*BIO *bio; moved to the BIO structure */
84 	int buf_len;
85 	int buf_off;
86 	int tmp_len;		/* used to find the start when decoding */
87 	int tmp_nl;		/* If true, scan until '\n' */
88 	int encode;
89 	int start;		/* have we started decoding yet? */
90 	int cont;		/* <= 0 when finished */
91 	EVP_ENCODE_CTX base64;
92 	char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10];
93 	char tmp[B64_BLOCK_SIZE];
94 } BIO_B64_CTX;
95 
96 static const BIO_METHOD methods_b64 = {
97 	.type = BIO_TYPE_BASE64,
98 	.name = "base64 encoding",
99 	.bwrite = b64_write,
100 	.bread = b64_read,
101 	.bputs = b64_puts,
102 	.ctrl = b64_ctrl,
103 	.create = b64_new,
104 	.destroy = b64_free,
105 	.callback_ctrl = b64_callback_ctrl
106 };
107 
108 const BIO_METHOD *
109 BIO_f_base64(void)
110 {
111 	return (&methods_b64);
112 }
113 
114 static int
115 b64_new(BIO *bi)
116 {
117 	BIO_B64_CTX *ctx;
118 
119 	ctx = malloc(sizeof(BIO_B64_CTX));
120 	if (ctx == NULL)
121 		return (0);
122 
123 	ctx->buf_len = 0;
124 	ctx->tmp_len = 0;
125 	ctx->tmp_nl = 0;
126 	ctx->buf_off = 0;
127 	ctx->cont = 1;
128 	ctx->start = 1;
129 	ctx->encode = 0;
130 
131 	bi->init = 1;
132 	bi->ptr = (char *)ctx;
133 	bi->flags = 0;
134 	bi->num = 0;
135 	return (1);
136 }
137 
138 static int
139 b64_free(BIO *a)
140 {
141 	if (a == NULL)
142 		return (0);
143 	free(a->ptr);
144 	a->ptr = NULL;
145 	a->init = 0;
146 	a->flags = 0;
147 	return (1);
148 }
149 
150 static int
151 b64_read(BIO *b, char *out, int outl)
152 {
153 	int ret = 0, i, ii, j, k, x, n, num, ret_code = 0;
154 	BIO_B64_CTX *ctx;
155 	unsigned char *p, *q;
156 
157 	if (out == NULL)
158 		return (0);
159 	ctx = (BIO_B64_CTX *)b->ptr;
160 
161 	if ((ctx == NULL) || (b->next_bio == NULL))
162 		return (0);
163 
164 	BIO_clear_retry_flags(b);
165 
166 	if (ctx->encode != B64_DECODE) {
167 		ctx->encode = B64_DECODE;
168 		ctx->buf_len = 0;
169 		ctx->buf_off = 0;
170 		ctx->tmp_len = 0;
171 		EVP_DecodeInit(&(ctx->base64));
172 	}
173 
174 	/* First check if there are bytes decoded/encoded */
175 	if (ctx->buf_len > 0) {
176 		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
177 		i = ctx->buf_len - ctx->buf_off;
178 		if (i > outl)
179 			i = outl;
180 		OPENSSL_assert(ctx->buf_off + i < (int)sizeof(ctx->buf));
181 		memcpy(out, &(ctx->buf[ctx->buf_off]), i);
182 		ret = i;
183 		out += i;
184 		outl -= i;
185 		ctx->buf_off += i;
186 		if (ctx->buf_len == ctx->buf_off) {
187 			ctx->buf_len = 0;
188 			ctx->buf_off = 0;
189 		}
190 	}
191 
192 	/* At this point, we have room of outl bytes and an empty
193 	 * buffer, so we should read in some more. */
194 
195 	ret_code = 0;
196 	while (outl > 0) {
197 		if (ctx->cont <= 0)
198 			break;
199 
200 		i = BIO_read(b->next_bio, &(ctx->tmp[ctx->tmp_len]),
201 		    B64_BLOCK_SIZE - ctx->tmp_len);
202 
203 		if (i <= 0) {
204 			ret_code = i;
205 
206 			/* Should we continue next time we are called? */
207 			if (!BIO_should_retry(b->next_bio)) {
208 				ctx->cont = i;
209 				/* If buffer empty break */
210 				if (ctx->tmp_len == 0)
211 					break;
212 				/* Fall through and process what we have */
213 				else
214 					i = 0;
215 			}
216 			/* else we retry and add more data to buffer */
217 			else
218 				break;
219 		}
220 		i += ctx->tmp_len;
221 		ctx->tmp_len = i;
222 
223 		/* We need to scan, a line at a time until we
224 		 * have a valid line if we are starting. */
225 		if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) {
226 			/* ctx->start=1; */
227 			ctx->tmp_len = 0;
228 		} else if (ctx->start) {
229 			q = p =(unsigned char *)ctx->tmp;
230 			num = 0;
231 			for (j = 0; j < i; j++) {
232 				if (*(q++) != '\n')
233 					continue;
234 
235 				/* due to a previous very long line,
236 				 * we need to keep on scanning for a '\n'
237 				 * before we even start looking for
238 				 * base64 encoded stuff. */
239 				if (ctx->tmp_nl) {
240 					p = q;
241 					ctx->tmp_nl = 0;
242 					continue;
243 				}
244 
245 				k = EVP_DecodeUpdate(&(ctx->base64),
246 				    (unsigned char *)ctx->buf,
247 				    &num, p, q - p);
248 				if ((k <= 0) && (num == 0) && (ctx->start))
249 					EVP_DecodeInit(&ctx->base64);
250 				else {
251 					if (p != (unsigned char *)
252 						&(ctx->tmp[0])) {
253 						i -= (p - (unsigned char *)
254 						&(ctx->tmp[0]));
255 						for (x = 0; x < i; x++)
256 							ctx->tmp[x] = p[x];
257 					}
258 					EVP_DecodeInit(&ctx->base64);
259 					ctx->start = 0;
260 					break;
261 				}
262 				p = q;
263 			}
264 
265 			/* we fell off the end without starting */
266 			if ((j == i) && (num == 0)) {
267 				/* Is this is one long chunk?, if so, keep on
268 				 * reading until a new line. */
269 				if (p == (unsigned char *)&(ctx->tmp[0])) {
270 					/* Check buffer full */
271 					if (i == B64_BLOCK_SIZE) {
272 						ctx->tmp_nl = 1;
273 						ctx->tmp_len = 0;
274 					}
275 				}
276 				else if (p != q) /* finished on a '\n' */
277 				{
278 					n = q - p;
279 					for (ii = 0; ii < n; ii++)
280 						ctx->tmp[ii] = p[ii];
281 					ctx->tmp_len = n;
282 				}
283 				/* else finished on a '\n' */
284 				continue;
285 			} else {
286 				ctx->tmp_len = 0;
287 			}
288 		} else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) {
289 			/* If buffer isn't full and we can retry then
290 			 * restart to read in more data.
291 			 */
292 			continue;
293 		}
294 
295 		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
296 			int z, jj;
297 
298 			jj = i & ~3; /* process per 4 */
299 			z = EVP_DecodeBlock((unsigned char *)ctx->buf,
300 			    (unsigned char *)ctx->tmp, jj);
301 			if (jj > 2) {
302 				if (ctx->tmp[jj-1] == '=') {
303 					z--;
304 					if (ctx->tmp[jj-2] == '=')
305 						z--;
306 				}
307 			}
308 			/* z is now number of output bytes and jj is the
309 			 * number consumed */
310 			if (jj != i) {
311 				memmove(ctx->tmp, &ctx->tmp[jj], i - jj);
312 				ctx->tmp_len = i - jj;
313 			}
314 			ctx->buf_len = 0;
315 			if (z > 0) {
316 				ctx->buf_len = z;
317 			}
318 			i = z;
319 		} else {
320 			i = EVP_DecodeUpdate(&(ctx->base64),
321 			    (unsigned char *)ctx->buf, &ctx->buf_len,
322 			    (unsigned char *)ctx->tmp, i);
323 			ctx->tmp_len = 0;
324 		}
325 		ctx->buf_off = 0;
326 		if (i < 0) {
327 			ret_code = 0;
328 			ctx->buf_len = 0;
329 			break;
330 		}
331 
332 		if (ctx->buf_len <= outl)
333 			i = ctx->buf_len;
334 		else
335 			i = outl;
336 
337 		memcpy(out, ctx->buf, i);
338 		ret += i;
339 		ctx->buf_off = i;
340 		if (ctx->buf_off == ctx->buf_len) {
341 			ctx->buf_len = 0;
342 			ctx->buf_off = 0;
343 		}
344 		outl -= i;
345 		out += i;
346 	}
347 	/* BIO_clear_retry_flags(b); */
348 	BIO_copy_next_retry(b);
349 	return ((ret == 0) ? ret_code : ret);
350 }
351 
352 static int
353 b64_write(BIO *b, const char *in, int inl)
354 {
355 	int ret = 0;
356 	int n;
357 	int i;
358 	BIO_B64_CTX *ctx;
359 
360 	ctx = (BIO_B64_CTX *)b->ptr;
361 	BIO_clear_retry_flags(b);
362 
363 	if (ctx->encode != B64_ENCODE) {
364 		ctx->encode = B64_ENCODE;
365 		ctx->buf_len = 0;
366 		ctx->buf_off = 0;
367 		ctx->tmp_len = 0;
368 		EVP_EncodeInit(&(ctx->base64));
369 	}
370 
371 	OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf));
372 	OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
373 	OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
374 	n = ctx->buf_len - ctx->buf_off;
375 	while (n > 0) {
376 		i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
377 		if (i <= 0) {
378 			BIO_copy_next_retry(b);
379 			return (i);
380 		}
381 		OPENSSL_assert(i <= n);
382 		ctx->buf_off += i;
383 		OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
384 		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
385 		n -= i;
386 	}
387 	/* at this point all pending data has been written */
388 	ctx->buf_off = 0;
389 	ctx->buf_len = 0;
390 
391 	if ((in == NULL) || (inl <= 0))
392 		return (0);
393 
394 	while (inl > 0) {
395 		n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl;
396 
397 		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
398 			if (ctx->tmp_len > 0) {
399 				OPENSSL_assert(ctx->tmp_len <= 3);
400 				n = 3 - ctx->tmp_len;
401 				/* There's a theoretical possibility for this */
402 				if (n > inl)
403 					n = inl;
404 				memcpy(&(ctx->tmp[ctx->tmp_len]), in, n);
405 				ctx->tmp_len += n;
406 				ret += n;
407 				if (ctx->tmp_len < 3)
408 					break;
409 				ctx->buf_len = EVP_EncodeBlock(
410 				    (unsigned char *)ctx->buf,
411 				    (unsigned char *)ctx->tmp, ctx->tmp_len);
412 				OPENSSL_assert(ctx->buf_len <=
413 				    (int)sizeof(ctx->buf));
414 				OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
415 				/* Since we're now done using the temporary
416 				   buffer, the length should be 0'd */
417 				ctx->tmp_len = 0;
418 			} else {
419 				if (n < 3) {
420 					memcpy(ctx->tmp, in, n);
421 					ctx->tmp_len = n;
422 					ret += n;
423 					break;
424 				}
425 				n -= n % 3;
426 				ctx->buf_len = EVP_EncodeBlock(
427 				    (unsigned char *)ctx->buf,
428 				    (const unsigned char *)in, n);
429 				OPENSSL_assert(ctx->buf_len <=
430 				    (int)sizeof(ctx->buf));
431 				OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
432 				ret += n;
433 			}
434 		} else {
435 			if (!EVP_EncodeUpdate(&(ctx->base64),
436 			    (unsigned char *)ctx->buf, &ctx->buf_len,
437 			    (unsigned char *)in, n))
438 				return ((ret == 0) ? -1 : ret);
439 			OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
440 			OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
441 			ret += n;
442 		}
443 		inl -= n;
444 		in += n;
445 
446 		ctx->buf_off = 0;
447 		n = ctx->buf_len;
448 		while (n > 0) {
449 			i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
450 			if (i <= 0) {
451 				BIO_copy_next_retry(b);
452 				return ((ret == 0) ? i : ret);
453 			}
454 			OPENSSL_assert(i <= n);
455 			n -= i;
456 			ctx->buf_off += i;
457 			OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
458 			OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
459 		}
460 		ctx->buf_len = 0;
461 		ctx->buf_off = 0;
462 	}
463 	return (ret);
464 }
465 
466 static long
467 b64_ctrl(BIO *b, int cmd, long num, void *ptr)
468 {
469 	BIO_B64_CTX *ctx;
470 	long ret = 1;
471 	int i;
472 
473 	ctx = (BIO_B64_CTX *)b->ptr;
474 
475 	switch (cmd) {
476 	case BIO_CTRL_RESET:
477 		ctx->cont = 1;
478 		ctx->start = 1;
479 		ctx->encode = B64_NONE;
480 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
481 		break;
482 	case BIO_CTRL_EOF:	/* More to read */
483 		if (ctx->cont <= 0)
484 			ret = 1;
485 		else
486 			ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
487 		break;
488 	case BIO_CTRL_WPENDING: /* More to write in buffer */
489 		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
490 		ret = ctx->buf_len - ctx->buf_off;
491 		if ((ret == 0) && (ctx->encode != B64_NONE) &&
492 		    (ctx->base64.num != 0))
493 			ret = 1;
494 		else if (ret <= 0)
495 			ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
496 		break;
497 	case BIO_CTRL_PENDING: /* More to read in buffer */
498 		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
499 		ret = ctx->buf_len - ctx->buf_off;
500 		if (ret <= 0)
501 			ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
502 		break;
503 	case BIO_CTRL_FLUSH:
504 		/* do a final write */
505 again:
506 		while (ctx->buf_len != ctx->buf_off) {
507 			i = b64_write(b, NULL, 0);
508 			if (i < 0)
509 				return i;
510 		}
511 		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
512 			if (ctx->tmp_len != 0) {
513 				ctx->buf_len = EVP_EncodeBlock(
514 				    (unsigned char *)ctx->buf,
515 				    (unsigned char *)ctx->tmp,
516 				    ctx->tmp_len);
517 				ctx->buf_off = 0;
518 				ctx->tmp_len = 0;
519 				goto again;
520 			}
521 		} else if (ctx->encode != B64_NONE && ctx->base64.num != 0) {
522 			ctx->buf_off = 0;
523 			EVP_EncodeFinal(&(ctx->base64),
524 			    (unsigned char *)ctx->buf,
525 			    &(ctx->buf_len));
526 			/* push out the bytes */
527 			goto again;
528 		}
529 		/* Finally flush the underlying BIO */
530 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
531 		break;
532 
533 	case BIO_C_DO_STATE_MACHINE:
534 		BIO_clear_retry_flags(b);
535 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
536 		BIO_copy_next_retry(b);
537 		break;
538 
539 	case BIO_CTRL_DUP:
540 		break;
541 	case BIO_CTRL_INFO:
542 	case BIO_CTRL_GET:
543 	case BIO_CTRL_SET:
544 	default:
545 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
546 		break;
547 	}
548 	return (ret);
549 }
550 
551 static long
552 b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
553 {
554 	long ret = 1;
555 
556 	if (b->next_bio == NULL)
557 		return (0);
558 	switch (cmd) {
559 	default:
560 		ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
561 		break;
562 	}
563 	return (ret);
564 }
565 
566 static int
567 b64_puts(BIO *b, const char *str)
568 {
569 	return b64_write(b, str, strlen(str));
570 }
571