blob: 8415bfedb40e2d6240b5d6b1091c10845bf203bf [file] [log] [blame]
Kenny Rootb8494592015-09-25 02:29:14 +00001/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to. The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * "This product includes cryptographic software written by
33 * Eric Young (eay@cryptsoft.com)"
34 * The word 'cryptographic' can be left out if the rouines from the library
35 * being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 * the apps directory (application code) you must include an acknowledgement:
38 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed. i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.] */
56
57#include <assert.h>
58#include <errno.h>
59#include <stdio.h>
60#include <string.h>
61
62#include <openssl/base64.h>
63#include <openssl/bio.h>
64#include <openssl/buffer.h>
65#include <openssl/evp.h>
66#include <openssl/mem.h>
67
68
69#define B64_BLOCK_SIZE 1024
70#define B64_BLOCK_SIZE2 768
71#define B64_NONE 0
72#define B64_ENCODE 1
73#define B64_DECODE 2
74#define EVP_ENCODE_LENGTH(l) (((l+2)/3*4)+(l/48+1)*2+80)
75
76typedef struct b64_struct {
77 int buf_len;
78 int buf_off;
79 int tmp_len; /* used to find the start when decoding */
80 int tmp_nl; /* If true, scan until '\n' */
81 int encode;
82 int start; /* have we started decoding yet? */
83 int cont; /* <= 0 when finished */
84 EVP_ENCODE_CTX base64;
85 char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10];
86 char tmp[B64_BLOCK_SIZE];
87} BIO_B64_CTX;
88
89static int b64_new(BIO *bio) {
90 BIO_B64_CTX *ctx;
91
92 ctx = OPENSSL_malloc(sizeof(*ctx));
93 if (ctx == NULL) {
94 return 0;
95 }
96
97 memset(ctx, 0, sizeof(*ctx));
98
99 ctx->cont = 1;
100 ctx->start = 1;
101
102 bio->init = 1;
103 bio->ptr = (char *)ctx;
104 return 1;
105}
106
107static int b64_free(BIO *bio) {
108 if (bio == NULL) {
109 return 0;
110 }
111 OPENSSL_free(bio->ptr);
112 bio->ptr = NULL;
113 bio->init = 0;
114 bio->flags = 0;
115 return 1;
116}
117
118static int b64_read(BIO *b, char *out, int outl) {
119 int ret = 0, i, ii, j, k, x, n, num, ret_code = 0;
120 BIO_B64_CTX *ctx;
121 uint8_t *p, *q;
122
123 if (out == NULL) {
124 return 0;
125 }
126 ctx = (BIO_B64_CTX *) b->ptr;
127
128 if (ctx == NULL || b->next_bio == NULL) {
129 return 0;
130 }
131
132 BIO_clear_retry_flags(b);
133
134 if (ctx->encode != B64_DECODE) {
135 ctx->encode = B64_DECODE;
136 ctx->buf_len = 0;
137 ctx->buf_off = 0;
138 ctx->tmp_len = 0;
139 EVP_DecodeInit(&ctx->base64);
140 }
141
142 /* First check if there are bytes decoded/encoded */
143 if (ctx->buf_len > 0) {
144 assert(ctx->buf_len >= ctx->buf_off);
145 i = ctx->buf_len - ctx->buf_off;
146 if (i > outl) {
147 i = outl;
148 }
149 assert(ctx->buf_off + i < (int)sizeof(ctx->buf));
150 memcpy(out, &ctx->buf[ctx->buf_off], i);
151 ret = i;
152 out += i;
153 outl -= i;
154 ctx->buf_off += i;
155 if (ctx->buf_len == ctx->buf_off) {
156 ctx->buf_len = 0;
157 ctx->buf_off = 0;
158 }
159 }
160
161 /* At this point, we have room of outl bytes and an empty buffer, so we
162 * should read in some more. */
163
164 ret_code = 0;
165 while (outl > 0) {
166 if (ctx->cont <= 0) {
167 break;
168 }
169
170 i = BIO_read(b->next_bio, &(ctx->tmp[ctx->tmp_len]),
171 B64_BLOCK_SIZE - ctx->tmp_len);
172
173 if (i <= 0) {
174 ret_code = i;
175
176 /* Should we continue next time we are called? */
177 if (!BIO_should_retry(b->next_bio)) {
178 ctx->cont = i;
179 /* If buffer empty break */
180 if (ctx->tmp_len == 0) {
181 break;
182 } else {
183 /* Fall through and process what we have */
184 i = 0;
185 }
186 } else {
187 /* else we retry and add more data to buffer */
188 break;
189 }
190 }
191 i += ctx->tmp_len;
192 ctx->tmp_len = i;
193
194 /* We need to scan, a line at a time until we have a valid line if we are
195 * starting. */
196 if (ctx->start && (BIO_test_flags(b, BIO_FLAGS_BASE64_NO_NL))) {
197 /* ctx->start = 1; */
198 ctx->tmp_len = 0;
199 } else if (ctx->start) {
200 q = p = (uint8_t *)ctx->tmp;
201 num = 0;
202 for (j = 0; j < i; j++) {
203 if (*(q++) != '\n') {
204 continue;
205 }
206
207 /* due to a previous very long line, we need to keep on scanning for a
208 * '\n' before we even start looking for base64 encoded stuff. */
209 if (ctx->tmp_nl) {
210 p = q;
211 ctx->tmp_nl = 0;
212 continue;
213 }
214
215 k = EVP_DecodeUpdate(&(ctx->base64), (uint8_t *)ctx->buf, &num, p,
216 q - p);
217
218 if (k <= 0 && num == 0 && ctx->start) {
219 EVP_DecodeInit(&ctx->base64);
220 } else {
221 if (p != (uint8_t *)&(ctx->tmp[0])) {
222 i -= (p - (uint8_t *)&(ctx->tmp[0]));
223 for (x = 0; x < i; x++) {
224 ctx->tmp[x] = p[x];
225 }
226 }
227 EVP_DecodeInit(&ctx->base64);
228 ctx->start = 0;
229 break;
230 }
231 p = q;
232 }
233
234 /* we fell off the end without starting */
235 if (j == i && num == 0) {
236 /* Is this is one long chunk?, if so, keep on reading until a new
237 * line. */
238 if (p == (uint8_t *)&(ctx->tmp[0])) {
239 /* Check buffer full */
240 if (i == B64_BLOCK_SIZE) {
241 ctx->tmp_nl = 1;
242 ctx->tmp_len = 0;
243 }
244 } else if (p != q) { /* finished on a '\n' */
245 n = q - p;
246 for (ii = 0; ii < n; ii++) {
247 ctx->tmp[ii] = p[ii];
248 }
249 ctx->tmp_len = n;
250 }
251 /* else finished on a '\n' */
252 continue;
253 } else {
254 ctx->tmp_len = 0;
255 }
256 } else if (i < B64_BLOCK_SIZE && ctx->cont > 0) {
257 /* If buffer isn't full and we can retry then restart to read in more
258 * data. */
259 continue;
260 }
261
262 if (BIO_test_flags(b, BIO_FLAGS_BASE64_NO_NL)) {
263 int z, jj;
264
265 jj = i & ~3; /* process per 4 */
266 z = EVP_DecodeBlock((uint8_t *)ctx->buf, (uint8_t *)ctx->tmp, jj);
267 if (jj > 2) {
268 if (ctx->tmp[jj - 1] == '=') {
269 z--;
270 if (ctx->tmp[jj - 2] == '=') {
271 z--;
272 }
273 }
274 }
275 /* z is now number of output bytes and jj is the number consumed. */
276 if (jj != i) {
277 memmove(ctx->tmp, &ctx->tmp[jj], i - jj);
278 ctx->tmp_len = i - jj;
279 }
280 ctx->buf_len = 0;
281 if (z > 0) {
282 ctx->buf_len = z;
283 }
284 i = z;
285 } else {
286 i = EVP_DecodeUpdate(&(ctx->base64), (uint8_t *)ctx->buf,
287 &ctx->buf_len, (uint8_t *)ctx->tmp, i);
288 ctx->tmp_len = 0;
289 }
290 ctx->buf_off = 0;
291 if (i < 0) {
292 ret_code = 0;
293 ctx->buf_len = 0;
294 break;
295 }
296
297 if (ctx->buf_len <= outl) {
298 i = ctx->buf_len;
299 } else {
300 i = outl;
301 }
302
303 memcpy(out, ctx->buf, i);
304 ret += i;
305 ctx->buf_off = i;
306 if (ctx->buf_off == ctx->buf_len) {
307 ctx->buf_len = 0;
308 ctx->buf_off = 0;
309 }
310 outl -= i;
311 out += i;
312 }
313
314 BIO_copy_next_retry(b);
315 return ret == 0 ? ret_code : ret;
316}
317
318static int b64_write(BIO *b, const char *in, int inl) {
319 int ret = 0, n, i;
320 BIO_B64_CTX *ctx;
321
322 ctx = (BIO_B64_CTX *)b->ptr;
323 BIO_clear_retry_flags(b);
324
325 if (ctx->encode != B64_ENCODE) {
326 ctx->encode = B64_ENCODE;
327 ctx->buf_len = 0;
328 ctx->buf_off = 0;
329 ctx->tmp_len = 0;
330 EVP_EncodeInit(&(ctx->base64));
331 }
332
333 assert(ctx->buf_off < (int)sizeof(ctx->buf));
334 assert(ctx->buf_len <= (int)sizeof(ctx->buf));
335 assert(ctx->buf_len >= ctx->buf_off);
336
337 n = ctx->buf_len - ctx->buf_off;
338 while (n > 0) {
339 i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
340 if (i <= 0) {
341 BIO_copy_next_retry(b);
342 return i;
343 }
344 assert(i <= n);
345 ctx->buf_off += i;
346 assert(ctx->buf_off <= (int)sizeof(ctx->buf));
347 assert(ctx->buf_len >= ctx->buf_off);
348 n -= i;
349 }
350
351 /* at this point all pending data has been written. */
352 ctx->buf_off = 0;
353 ctx->buf_len = 0;
354
355 if (in == NULL || inl <= 0) {
356 return 0;
357 }
358
359 while (inl > 0) {
360 n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl;
361
362 if (BIO_test_flags(b, BIO_FLAGS_BASE64_NO_NL)) {
363 if (ctx->tmp_len > 0) {
364 assert(ctx->tmp_len <= 3);
365 n = 3 - ctx->tmp_len;
366 /* There's a theoretical possibility of this. */
367 if (n > inl) {
368 n = inl;
369 }
370 memcpy(&(ctx->tmp[ctx->tmp_len]), in, n);
371 ctx->tmp_len += n;
372 ret += n;
373 if (ctx->tmp_len < 3) {
374 break;
375 }
376 ctx->buf_len = EVP_EncodeBlock((uint8_t *)ctx->buf, (uint8_t *)ctx->tmp,
377 ctx->tmp_len);
378 assert(ctx->buf_len <= (int)sizeof(ctx->buf));
379 assert(ctx->buf_len >= ctx->buf_off);
380
381 /* Since we're now done using the temporary buffer, the length should
382 * be zeroed. */
383 ctx->tmp_len = 0;
384 } else {
385 if (n < 3) {
386 memcpy(ctx->tmp, in, n);
387 ctx->tmp_len = n;
388 ret += n;
389 break;
390 }
391 n -= n % 3;
392 ctx->buf_len =
393 EVP_EncodeBlock((uint8_t *)ctx->buf, (const uint8_t *)in, n);
394 assert(ctx->buf_len <= (int)sizeof(ctx->buf));
395 assert(ctx->buf_len >= ctx->buf_off);
396 ret += n;
397 }
398 } else {
399 EVP_EncodeUpdate(&(ctx->base64), (uint8_t *)ctx->buf, &ctx->buf_len,
400 (uint8_t *)in, n);
401 assert(ctx->buf_len <= (int)sizeof(ctx->buf));
402 assert(ctx->buf_len >= ctx->buf_off);
403 ret += n;
404 }
405 inl -= n;
406 in += n;
407
408 ctx->buf_off = 0;
409 n = ctx->buf_len;
410
411 while (n > 0) {
412 i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
413 if (i <= 0) {
414 BIO_copy_next_retry(b);
415 return ret == 0 ? i : ret;
416 }
417 assert(i <= n);
418 n -= i;
419 ctx->buf_off += i;
420 assert(ctx->buf_off <= (int)sizeof(ctx->buf));
421 assert(ctx->buf_len >= ctx->buf_off);
422 }
423 ctx->buf_len = 0;
424 ctx->buf_off = 0;
425 }
426 return ret;
427}
428
429static long b64_ctrl(BIO *b, int cmd, long num, void *ptr) {
430 BIO_B64_CTX *ctx;
431 long ret = 1;
432 int i;
433
434 ctx = (BIO_B64_CTX *)b->ptr;
435
436 switch (cmd) {
437 case BIO_CTRL_RESET:
438 ctx->cont = 1;
439 ctx->start = 1;
440 ctx->encode = B64_NONE;
441 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
442 break;
443
444 case BIO_CTRL_EOF: /* More to read */
445 if (ctx->cont <= 0) {
446 ret = 1;
447 } else {
448 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
449 }
450 break;
451
452 case BIO_CTRL_WPENDING: /* More to write in buffer */
453 assert(ctx->buf_len >= ctx->buf_off);
454 ret = ctx->buf_len - ctx->buf_off;
David Benjamind316cba2016-06-02 16:17:39 -0400455 if ((ret == 0) && (ctx->encode != B64_NONE) && (ctx->base64.data_used != 0)) {
Kenny Rootb8494592015-09-25 02:29:14 +0000456 ret = 1;
457 } else if (ret <= 0) {
458 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
459 }
460 break;
461
462 case BIO_CTRL_PENDING: /* More to read in buffer */
463 assert(ctx->buf_len >= ctx->buf_off);
464 ret = ctx->buf_len - ctx->buf_off;
465 if (ret <= 0) {
466 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
467 }
468 break;
469
470 case BIO_CTRL_FLUSH:
471 /* do a final write */
472 again:
473 while (ctx->buf_len != ctx->buf_off) {
474 i = b64_write(b, NULL, 0);
475 if (i < 0) {
476 return i;
477 }
478 }
479 if (BIO_test_flags(b, BIO_FLAGS_BASE64_NO_NL)) {
480 if (ctx->tmp_len != 0) {
481 ctx->buf_len = EVP_EncodeBlock((uint8_t *)ctx->buf,
482 (uint8_t *)ctx->tmp, ctx->tmp_len);
483 ctx->buf_off = 0;
484 ctx->tmp_len = 0;
485 goto again;
486 }
David Benjamind316cba2016-06-02 16:17:39 -0400487 } else if (ctx->encode != B64_NONE && ctx->base64.data_used != 0) {
Kenny Rootb8494592015-09-25 02:29:14 +0000488 ctx->buf_off = 0;
489 EVP_EncodeFinal(&(ctx->base64), (uint8_t *)ctx->buf, &(ctx->buf_len));
490 /* push out the bytes */
491 goto again;
492 }
493 /* Finally flush the underlying BIO */
494 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
495 break;
496
497 case BIO_C_DO_STATE_MACHINE:
498 BIO_clear_retry_flags(b);
499 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
500 BIO_copy_next_retry(b);
501 break;
502
503 case BIO_CTRL_INFO:
504 case BIO_CTRL_GET:
505 case BIO_CTRL_SET:
506 default:
507 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
508 break;
509 }
510 return ret;
511}
512
513static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) {
514 long ret = 1;
515
516 if (b->next_bio == NULL) {
517 return 0;
518 }
519 switch (cmd) {
520 default:
521 ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
522 break;
523 }
524 return ret;
525}
526
527static int b64_puts(BIO *b, const char *str) {
528 return b64_write(b, str, strlen(str));
529}
530
531static const BIO_METHOD b64_method = {
532 BIO_TYPE_BASE64, "base64 encoding", b64_write, b64_read, b64_puts,
533 NULL /* gets */, b64_ctrl, b64_new, b64_free, b64_callback_ctrl,
534};
535
536const BIO_METHOD *BIO_f_base64(void) { return &b64_method; }