155714Skris/* crypto/evp/bio_b64.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
855714Skris *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1555714Skris *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
2255714Skris *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
3755714Skris * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4055714Skris *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
5255714Skris *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include <errno.h>
6155714Skris#include "cryptlib.h"
6255714Skris#include <openssl/buffer.h>
6355714Skris#include <openssl/evp.h>
6455714Skris
6568651Skrisstatic int b64_write(BIO *h, const char *buf, int num);
6668651Skrisstatic int b64_read(BIO *h, char *buf, int size);
67215697Ssimonstatic int b64_puts(BIO *h, const char *str);
6868651Skris/*static int b64_gets(BIO *h, char *str, int size); */
6968651Skrisstatic long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
7055714Skrisstatic int b64_new(BIO *h);
7155714Skrisstatic int b64_free(BIO *data);
7268651Skrisstatic long b64_callback_ctrl(BIO *h,int cmd,bio_info_cb *fp);
7355714Skris#define B64_BLOCK_SIZE	1024
7455714Skris#define B64_BLOCK_SIZE2	768
7555714Skris#define B64_NONE	0
7655714Skris#define B64_ENCODE	1
7755714Skris#define B64_DECODE	2
7855714Skris
7955714Skristypedef struct b64_struct
8055714Skris	{
8155714Skris	/*BIO *bio; moved to the BIO structure */
8255714Skris	int buf_len;
8355714Skris	int buf_off;
8455714Skris	int tmp_len;		/* used to find the start when decoding */
8555714Skris	int tmp_nl;		/* If true, scan until '\n' */
8655714Skris	int encode;
8755714Skris	int start;		/* have we started decoding yet? */
8855714Skris	int cont;		/* <= 0 when finished */
8955714Skris	EVP_ENCODE_CTX base64;
9055714Skris	char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE)+10];
9155714Skris	char tmp[B64_BLOCK_SIZE];
9255714Skris	} BIO_B64_CTX;
9355714Skris
9455714Skrisstatic BIO_METHOD methods_b64=
9555714Skris	{
9655714Skris	BIO_TYPE_BASE64,"base64 encoding",
9755714Skris	b64_write,
9855714Skris	b64_read,
99215697Ssimon	b64_puts,
10055714Skris	NULL, /* b64_gets, */
10155714Skris	b64_ctrl,
10255714Skris	b64_new,
10355714Skris	b64_free,
10459191Skris	b64_callback_ctrl,
10555714Skris	};
10655714Skris
10755714SkrisBIO_METHOD *BIO_f_base64(void)
10855714Skris	{
10955714Skris	return(&methods_b64);
11055714Skris	}
11155714Skris
11255714Skrisstatic int b64_new(BIO *bi)
11355714Skris	{
11455714Skris	BIO_B64_CTX *ctx;
11555714Skris
11668651Skris	ctx=(BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX));
11755714Skris	if (ctx == NULL) return(0);
11855714Skris
11955714Skris	ctx->buf_len=0;
12055714Skris	ctx->tmp_len=0;
12155714Skris	ctx->tmp_nl=0;
12255714Skris	ctx->buf_off=0;
12355714Skris	ctx->cont=1;
12455714Skris	ctx->start=1;
12555714Skris	ctx->encode=0;
12655714Skris
12755714Skris	bi->init=1;
12855714Skris	bi->ptr=(char *)ctx;
12955714Skris	bi->flags=0;
130215697Ssimon	bi->num = 0;
13155714Skris	return(1);
13255714Skris	}
13355714Skris
13455714Skrisstatic int b64_free(BIO *a)
13555714Skris	{
13655714Skris	if (a == NULL) return(0);
13768651Skris	OPENSSL_free(a->ptr);
13855714Skris	a->ptr=NULL;
13955714Skris	a->init=0;
14055714Skris	a->flags=0;
14155714Skris	return(1);
14255714Skris	}
14355714Skris
14455714Skrisstatic int b64_read(BIO *b, char *out, int outl)
14555714Skris	{
14655714Skris	int ret=0,i,ii,j,k,x,n,num,ret_code=0;
14755714Skris	BIO_B64_CTX *ctx;
14855714Skris	unsigned char *p,*q;
14955714Skris
15055714Skris	if (out == NULL) return(0);
15155714Skris	ctx=(BIO_B64_CTX *)b->ptr;
15255714Skris
15355714Skris	if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
15455714Skris
155215697Ssimon	BIO_clear_retry_flags(b);
156215697Ssimon
15755714Skris	if (ctx->encode != B64_DECODE)
15855714Skris		{
15955714Skris		ctx->encode=B64_DECODE;
16055714Skris		ctx->buf_len=0;
16155714Skris		ctx->buf_off=0;
16255714Skris		ctx->tmp_len=0;
16355714Skris		EVP_DecodeInit(&(ctx->base64));
16455714Skris		}
16555714Skris
16655714Skris	/* First check if there are bytes decoded/encoded */
16755714Skris	if (ctx->buf_len > 0)
16855714Skris		{
169215697Ssimon		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
17055714Skris		i=ctx->buf_len-ctx->buf_off;
17155714Skris		if (i > outl) i=outl;
172160814Ssimon		OPENSSL_assert(ctx->buf_off+i < (int)sizeof(ctx->buf));
17355714Skris		memcpy(out,&(ctx->buf[ctx->buf_off]),i);
17455714Skris		ret=i;
17555714Skris		out+=i;
17655714Skris		outl-=i;
17755714Skris		ctx->buf_off+=i;
17855714Skris		if (ctx->buf_len == ctx->buf_off)
17955714Skris			{
18055714Skris			ctx->buf_len=0;
18155714Skris			ctx->buf_off=0;
18255714Skris			}
18355714Skris		}
18455714Skris
18555714Skris	/* At this point, we have room of outl bytes and an empty
18655714Skris	 * buffer, so we should read in some more. */
18755714Skris
18855714Skris	ret_code=0;
18955714Skris	while (outl > 0)
19055714Skris		{
191120631Snectar		if (ctx->cont <= 0)
192120631Snectar			break;
193120631Snectar
19455714Skris		i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]),
19555714Skris			B64_BLOCK_SIZE-ctx->tmp_len);
19655714Skris
19755714Skris		if (i <= 0)
19855714Skris			{
19955714Skris			ret_code=i;
20055714Skris
201215697Ssimon			/* Should we continue next time we are called? */
20255714Skris			if (!BIO_should_retry(b->next_bio))
203120631Snectar				{
20455714Skris				ctx->cont=i;
205120631Snectar				/* If buffer empty break */
206120631Snectar				if(ctx->tmp_len == 0)
207120631Snectar					break;
208120631Snectar				/* Fall through and process what we have */
209120631Snectar				else
210120631Snectar					i = 0;
211120631Snectar				}
212120631Snectar			/* else we retry and add more data to buffer */
213120631Snectar			else
214120631Snectar				break;
21555714Skris			}
21655714Skris		i+=ctx->tmp_len;
217120631Snectar		ctx->tmp_len = i;
21855714Skris
21955714Skris		/* We need to scan, a line at a time until we
22055714Skris		 * have a valid line if we are starting. */
22155714Skris		if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL))
22255714Skris			{
22355714Skris			/* ctx->start=1; */
22455714Skris			ctx->tmp_len=0;
22555714Skris			}
22655714Skris		else if (ctx->start)
22755714Skris			{
22855714Skris			q=p=(unsigned char *)ctx->tmp;
229279264Sdelphij			num = 0;
23055714Skris			for (j=0; j<i; j++)
23155714Skris				{
23255714Skris				if (*(q++) != '\n') continue;
23355714Skris
23455714Skris				/* due to a previous very long line,
23555714Skris				 * we need to keep on scanning for a '\n'
23655714Skris				 * before we even start looking for
23755714Skris				 * base64 encoded stuff. */
23855714Skris				if (ctx->tmp_nl)
23955714Skris					{
24055714Skris					p=q;
24155714Skris					ctx->tmp_nl=0;
24255714Skris					continue;
24355714Skris					}
24455714Skris
24555714Skris				k=EVP_DecodeUpdate(&(ctx->base64),
24655714Skris					(unsigned char *)ctx->buf,
24755714Skris					&num,p,q-p);
24855714Skris				if ((k <= 0) && (num == 0) && (ctx->start))
24955714Skris					EVP_DecodeInit(&ctx->base64);
25055714Skris				else
25155714Skris					{
25255714Skris					if (p != (unsigned char *)
25355714Skris						&(ctx->tmp[0]))
25455714Skris						{
25555714Skris						i-=(p- (unsigned char *)
25655714Skris							&(ctx->tmp[0]));
25755714Skris						for (x=0; x < i; x++)
25855714Skris							ctx->tmp[x]=p[x];
25955714Skris						}
26059191Skris					EVP_DecodeInit(&ctx->base64);
26155714Skris					ctx->start=0;
26255714Skris					break;
26355714Skris					}
26455714Skris				p=q;
26555714Skris				}
26655714Skris
26755714Skris			/* we fell off the end without starting */
268279264Sdelphij			if ((j == i) && (num == 0))
26955714Skris				{
27055714Skris				/* Is this is one long chunk?, if so, keep on
27155714Skris				 * reading until a new line. */
27255714Skris				if (p == (unsigned char *)&(ctx->tmp[0]))
27355714Skris					{
274120631Snectar					/* Check buffer full */
275120631Snectar					if (i == B64_BLOCK_SIZE)
276120631Snectar						{
277120631Snectar						ctx->tmp_nl=1;
278120631Snectar						ctx->tmp_len=0;
279120631Snectar						}
28055714Skris					}
28155714Skris				else if (p != q) /* finished on a '\n' */
28255714Skris					{
28355714Skris					n=q-p;
28455714Skris					for (ii=0; ii<n; ii++)
28555714Skris						ctx->tmp[ii]=p[ii];
28655714Skris					ctx->tmp_len=n;
28755714Skris					}
28855714Skris				/* else finished on a '\n' */
28955714Skris				continue;
29055714Skris				}
29155714Skris			else
292215697Ssimon			{
29355714Skris				ctx->tmp_len=0;
29455714Skris			}
295215697Ssimon		}
296120631Snectar		else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0))
297215697Ssimon		{
298215697Ssimon			/* If buffer isn't full and we can retry then
299215697Ssimon			 * restart to read in more data.
300215697Ssimon			 */
301120631Snectar			continue;
302215697Ssimon		}
30355714Skris
30455714Skris		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
30555714Skris			{
30655714Skris			int z,jj;
30755714Skris
308215697Ssimon#if 0
30955714Skris			jj=(i>>2)<<2;
310215697Ssimon#else
311215697Ssimon			jj = i & ~3; /* process per 4 */
312215697Ssimon#endif
31355714Skris			z=EVP_DecodeBlock((unsigned char *)ctx->buf,
31455714Skris				(unsigned char *)ctx->tmp,jj);
31555714Skris			if (jj > 2)
31655714Skris				{
31755714Skris				if (ctx->tmp[jj-1] == '=')
31855714Skris					{
31955714Skris					z--;
32055714Skris					if (ctx->tmp[jj-2] == '=')
32155714Skris						z--;
32255714Skris					}
32355714Skris				}
32455714Skris			/* z is now number of output bytes and jj is the
32555714Skris			 * number consumed */
32655714Skris			if (jj != i)
32755714Skris				{
328215697Ssimon				memmove(ctx->tmp, &ctx->tmp[jj], i-jj);
32955714Skris				ctx->tmp_len=i-jj;
33055714Skris				}
33155714Skris			ctx->buf_len=0;
33255714Skris			if (z > 0)
33355714Skris				{
33455714Skris				ctx->buf_len=z;
33555714Skris				}
336215697Ssimon			i=z;
33755714Skris			}
33855714Skris		else
33955714Skris			{
34055714Skris			i=EVP_DecodeUpdate(&(ctx->base64),
34155714Skris				(unsigned char *)ctx->buf,&ctx->buf_len,
34255714Skris				(unsigned char *)ctx->tmp,i);
343120631Snectar			ctx->tmp_len = 0;
34455714Skris			}
34555714Skris		ctx->buf_off=0;
34655714Skris		if (i < 0)
34755714Skris			{
34855714Skris			ret_code=0;
34955714Skris			ctx->buf_len=0;
35055714Skris			break;
35155714Skris			}
35255714Skris
35355714Skris		if (ctx->buf_len <= outl)
35455714Skris			i=ctx->buf_len;
35555714Skris		else
35655714Skris			i=outl;
35755714Skris
35855714Skris		memcpy(out,ctx->buf,i);
35955714Skris		ret+=i;
36055714Skris		ctx->buf_off=i;
36155714Skris		if (ctx->buf_off == ctx->buf_len)
36255714Skris			{
36355714Skris			ctx->buf_len=0;
36455714Skris			ctx->buf_off=0;
36555714Skris			}
36655714Skris		outl-=i;
36755714Skris		out+=i;
36855714Skris		}
369215697Ssimon	/* BIO_clear_retry_flags(b); */
37055714Skris	BIO_copy_next_retry(b);
37155714Skris	return((ret == 0)?ret_code:ret);
37255714Skris	}
37355714Skris
37468651Skrisstatic int b64_write(BIO *b, const char *in, int inl)
37555714Skris	{
376215697Ssimon	int ret=0;
377215697Ssimon	int n;
378215697Ssimon	int i;
37955714Skris	BIO_B64_CTX *ctx;
38055714Skris
38155714Skris	ctx=(BIO_B64_CTX *)b->ptr;
38255714Skris	BIO_clear_retry_flags(b);
38355714Skris
38455714Skris	if (ctx->encode != B64_ENCODE)
38555714Skris		{
38655714Skris		ctx->encode=B64_ENCODE;
38755714Skris		ctx->buf_len=0;
38855714Skris		ctx->buf_off=0;
38955714Skris		ctx->tmp_len=0;
39055714Skris		EVP_EncodeInit(&(ctx->base64));
39155714Skris		}
39255714Skris
393215697Ssimon	OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf));
394215697Ssimon	OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
395215697Ssimon	OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
39655714Skris	n=ctx->buf_len-ctx->buf_off;
39755714Skris	while (n > 0)
39855714Skris		{
39955714Skris		i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
40055714Skris		if (i <= 0)
40155714Skris			{
40255714Skris			BIO_copy_next_retry(b);
40355714Skris			return(i);
40455714Skris			}
405215697Ssimon		OPENSSL_assert(i <= n);
40655714Skris		ctx->buf_off+=i;
407215697Ssimon		OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
408215697Ssimon		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
40955714Skris		n-=i;
41055714Skris		}
41155714Skris	/* at this point all pending data has been written */
41268651Skris	ctx->buf_off=0;
41368651Skris	ctx->buf_len=0;
41455714Skris
41555714Skris	if ((in == NULL) || (inl <= 0)) return(0);
41655714Skris
41755714Skris	while (inl > 0)
41855714Skris		{
41955714Skris		n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl;
42055714Skris
42155714Skris		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
42255714Skris			{
42355714Skris			if (ctx->tmp_len > 0)
42455714Skris				{
425215697Ssimon				OPENSSL_assert(ctx->tmp_len <= 3);
42655714Skris				n=3-ctx->tmp_len;
427215697Ssimon				/* There's a theoretical possibility for this */
42868651Skris				if (n > inl)
42968651Skris					n=inl;
43055714Skris				memcpy(&(ctx->tmp[ctx->tmp_len]),in,n);
43155714Skris				ctx->tmp_len+=n;
432215697Ssimon				ret += n;
43368651Skris				if (ctx->tmp_len < 3)
43455714Skris					break;
435215697Ssimon				ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(unsigned char *)ctx->tmp,ctx->tmp_len);
436215697Ssimon				OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
437215697Ssimon				OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
43868651Skris				/* Since we're now done using the temporary
43968651Skris				   buffer, the length should be 0'd */
44068651Skris				ctx->tmp_len=0;
44155714Skris				}
44255714Skris			else
44355714Skris				{
44455714Skris				if (n < 3)
44555714Skris					{
446215697Ssimon					memcpy(ctx->tmp,in,n);
44755714Skris					ctx->tmp_len=n;
448215697Ssimon					ret += n;
44955714Skris					break;
45055714Skris					}
45155714Skris				n-=n%3;
452215697Ssimon				ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(const unsigned char *)in,n);
453215697Ssimon				OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
454215697Ssimon				OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
455215697Ssimon				ret += n;
45655714Skris				}
45755714Skris			}
45855714Skris		else
45955714Skris			{
46055714Skris			EVP_EncodeUpdate(&(ctx->base64),
46155714Skris				(unsigned char *)ctx->buf,&ctx->buf_len,
46255714Skris				(unsigned char *)in,n);
463215697Ssimon			OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
464215697Ssimon			OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
465215697Ssimon			ret += n;
46655714Skris			}
46755714Skris		inl-=n;
46855714Skris		in+=n;
46955714Skris
47055714Skris		ctx->buf_off=0;
47155714Skris		n=ctx->buf_len;
47255714Skris		while (n > 0)
47355714Skris			{
47455714Skris			i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
47555714Skris			if (i <= 0)
47655714Skris				{
47755714Skris				BIO_copy_next_retry(b);
47855714Skris				return((ret == 0)?i:ret);
47955714Skris				}
480215697Ssimon			OPENSSL_assert(i <= n);
48155714Skris			n-=i;
48255714Skris			ctx->buf_off+=i;
483215697Ssimon			OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
484215697Ssimon			OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
48555714Skris			}
48655714Skris		ctx->buf_len=0;
48755714Skris		ctx->buf_off=0;
48855714Skris		}
48955714Skris	return(ret);
49055714Skris	}
49155714Skris
49268651Skrisstatic long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
49355714Skris	{
49455714Skris	BIO_B64_CTX *ctx;
49555714Skris	long ret=1;
49655714Skris	int i;
49755714Skris
49855714Skris	ctx=(BIO_B64_CTX *)b->ptr;
49955714Skris
50055714Skris	switch (cmd)
50155714Skris		{
50255714Skris	case BIO_CTRL_RESET:
50355714Skris		ctx->cont=1;
50455714Skris		ctx->start=1;
50555714Skris		ctx->encode=B64_NONE;
50655714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
50755714Skris		break;
50855714Skris	case BIO_CTRL_EOF:	/* More to read */
50955714Skris		if (ctx->cont <= 0)
51055714Skris			ret=1;
51155714Skris		else
51255714Skris			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
51355714Skris		break;
51455714Skris	case BIO_CTRL_WPENDING: /* More to write in buffer */
515215697Ssimon		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
51655714Skris		ret=ctx->buf_len-ctx->buf_off;
51789837Skris		if ((ret == 0) && (ctx->encode != B64_NONE)
51889837Skris			&& (ctx->base64.num != 0))
51955714Skris			ret=1;
52055714Skris		else if (ret <= 0)
52155714Skris			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
52255714Skris		break;
52355714Skris	case BIO_CTRL_PENDING: /* More to read in buffer */
524215697Ssimon		OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
52555714Skris		ret=ctx->buf_len-ctx->buf_off;
52655714Skris		if (ret <= 0)
52755714Skris			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
52855714Skris		break;
52955714Skris	case BIO_CTRL_FLUSH:
53055714Skris		/* do a final write */
53155714Skrisagain:
53255714Skris		while (ctx->buf_len != ctx->buf_off)
53355714Skris			{
53455714Skris			i=b64_write(b,NULL,0);
53555714Skris			if (i < 0)
536120631Snectar				return i;
53755714Skris			}
53855714Skris		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
53955714Skris			{
54055714Skris			if (ctx->tmp_len != 0)
54155714Skris				{
54255714Skris				ctx->buf_len=EVP_EncodeBlock(
54355714Skris					(unsigned char *)ctx->buf,
54455714Skris					(unsigned char *)ctx->tmp,
54555714Skris					ctx->tmp_len);
54655714Skris				ctx->buf_off=0;
54755714Skris				ctx->tmp_len=0;
54855714Skris				goto again;
54955714Skris				}
55055714Skris			}
55189837Skris		else if (ctx->encode != B64_NONE && ctx->base64.num != 0)
55255714Skris			{
55355714Skris			ctx->buf_off=0;
55455714Skris			EVP_EncodeFinal(&(ctx->base64),
55555714Skris				(unsigned char *)ctx->buf,
55655714Skris				&(ctx->buf_len));
55755714Skris			/* push out the bytes */
55855714Skris			goto again;
55955714Skris			}
56055714Skris		/* Finally flush the underlying BIO */
56155714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
56255714Skris		break;
56355714Skris
56455714Skris	case BIO_C_DO_STATE_MACHINE:
56555714Skris		BIO_clear_retry_flags(b);
56655714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
56755714Skris		BIO_copy_next_retry(b);
56855714Skris		break;
56955714Skris
57055714Skris	case BIO_CTRL_DUP:
57155714Skris		break;
57255714Skris	case BIO_CTRL_INFO:
57355714Skris	case BIO_CTRL_GET:
57455714Skris	case BIO_CTRL_SET:
57555714Skris	default:
57655714Skris		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
57755714Skris		break;
57855714Skris		}
57955714Skris	return(ret);
58055714Skris	}
58155714Skris
58268651Skrisstatic long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
58359191Skris	{
58459191Skris	long ret=1;
58559191Skris
58659191Skris	if (b->next_bio == NULL) return(0);
58759191Skris	switch (cmd)
58859191Skris		{
58959191Skris	default:
59059191Skris		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
59159191Skris		break;
59259191Skris		}
59359191Skris	return(ret);
59459191Skris	}
59559191Skris
596215697Ssimonstatic int b64_puts(BIO *b, const char *str)
597215697Ssimon	{
598215697Ssimon	return b64_write(b,str,strlen(str));
599215697Ssimon	}
600