bio_b64.c revision 59191
11638Srgrimes/* crypto/evp/bio_b64.c */
21638Srgrimes/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
31638Srgrimes * All rights reserved.
41638Srgrimes *
51638Srgrimes * This package is an SSL implementation written
61638Srgrimes * by Eric Young (eay@cryptsoft.com).
71638Srgrimes * The implementation was written so as to conform with Netscapes SSL.
81638Srgrimes *
91638Srgrimes * This library is free for commercial and non-commercial use as long as
101638Srgrimes * the following conditions are aheared to.  The following conditions
111638Srgrimes * apply to all code found in this distribution, be it the RC4, RSA,
121638Srgrimes * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
131638Srgrimes * included with this distribution is covered by the same copyright terms
141638Srgrimes * except that the holder is Tim Hudson (tjh@cryptsoft.com).
151638Srgrimes *
161638Srgrimes * Copyright remains Eric Young's, and as such any Copyright notices in
171638Srgrimes * the code are not to be removed.
181638Srgrimes * If this package is used in a product, Eric Young should be given attribution
191638Srgrimes * as the author of the parts of the library used.
201638Srgrimes * This can be in the form of a textual message at program startup or
211638Srgrimes * in documentation (online or textual) provided with the package.
221638Srgrimes *
231638Srgrimes * Redistribution and use in source and binary forms, with or without
241638Srgrimes * modification, are permitted provided that the following conditions
251638Srgrimes * are met:
261638Srgrimes * 1. Redistributions of source code must retain the copyright
271638Srgrimes *    notice, this list of conditions and the following disclaimer.
281638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
291638Srgrimes *    notice, this list of conditions and the following disclaimer in the
301638Srgrimes *    documentation and/or other materials provided with the distribution.
311638Srgrimes * 3. All advertising materials mentioning features or use of this software
321638Srgrimes *    must display the following acknowledgement:
331638Srgrimes *    "This product includes cryptographic software written by
34108533Sschweikh *     Eric Young (eay@cryptsoft.com)"
35108533Sschweikh *    The word 'cryptographic' can be left out if the rouines from the library
361638Srgrimes *    being used are not cryptographic related :-).
371638Srgrimes * 4. If you include any Windows specific code (or a derivative thereof) from
381638Srgrimes *    the apps directory (application code) you must include an acknowledgement:
391638Srgrimes *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
401638Srgrimes *
411638Srgrimes * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
421638Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
431638Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
441638Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
451638Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
461638Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
471638Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
481638Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
491638Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
501638Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
511638Srgrimes * SUCH DAMAGE.
521638Srgrimes *
531638Srgrimes * The licence and distribution terms for any publically available version or
5445319Sgrog * derivative of this code cannot be changed.  i.e. this code cannot simply be
5545319Sgrog * copied and put under another distribution licence
5645319Sgrog * [including the GNU Public Licence.]
571638Srgrimes */
581638Srgrimes
591638Srgrimes#include <stdio.h>
60108533Sschweikh#include <errno.h>
611638Srgrimes#include "cryptlib.h"
621638Srgrimes#include <openssl/buffer.h>
631638Srgrimes#include <openssl/evp.h>
641638Srgrimes
651638Srgrimesstatic int b64_write(BIO *h,char *buf,int num);
661638Srgrimesstatic int b64_read(BIO *h,char *buf,int size);
671638Srgrimes/*static int b64_puts(BIO *h,char *str); */
681638Srgrimes/*static int b64_gets(BIO *h,char *str,int size); */
691638Srgrimesstatic long b64_ctrl(BIO *h,int cmd,long arg1,char *arg2);
701638Srgrimesstatic int b64_new(BIO *h);
711638Srgrimesstatic int b64_free(BIO *data);
721638Srgrimesstatic long b64_callback_ctrl(BIO *h,int cmd,void (*fp)());
731638Srgrimes#define B64_BLOCK_SIZE	1024
741638Srgrimes#define B64_BLOCK_SIZE2	768
751638Srgrimes#define B64_NONE	0
761638Srgrimes#define B64_ENCODE	1
771638Srgrimes#define B64_DECODE	2
781638Srgrimes
791638Srgrimestypedef struct b64_struct
801638Srgrimes	{
811638Srgrimes	/*BIO *bio; moved to the BIO structure */
821638Srgrimes	int buf_len;
831638Srgrimes	int buf_off;
841638Srgrimes	int tmp_len;		/* used to find the start when decoding */
85108533Sschweikh	int tmp_nl;		/* If true, scan until '\n' */
861638Srgrimes	int encode;
871638Srgrimes	int start;		/* have we started decoding yet? */
881638Srgrimes	int cont;		/* <= 0 when finished */
891638Srgrimes	EVP_ENCODE_CTX base64;
901638Srgrimes	char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE)+10];
911638Srgrimes	char tmp[B64_BLOCK_SIZE];
921638Srgrimes	} BIO_B64_CTX;
931638Srgrimes
941638Srgrimesstatic BIO_METHOD methods_b64=
951638Srgrimes	{
961638Srgrimes	BIO_TYPE_BASE64,"base64 encoding",
971638Srgrimes	b64_write,
981638Srgrimes	b64_read,
991638Srgrimes	NULL, /* b64_puts, */
1001638Srgrimes	NULL, /* b64_gets, */
1011638Srgrimes	b64_ctrl,
1021638Srgrimes	b64_new,
1031638Srgrimes	b64_free,
1041638Srgrimes	b64_callback_ctrl,
1051638Srgrimes	};
1061638Srgrimes
1071638SrgrimesBIO_METHOD *BIO_f_base64(void)
1081638Srgrimes	{
1091638Srgrimes	return(&methods_b64);
1101638Srgrimes	}
1111638Srgrimes
1121638Srgrimesstatic int b64_new(BIO *bi)
1131638Srgrimes	{
114108533Sschweikh	BIO_B64_CTX *ctx;
1151638Srgrimes
1161638Srgrimes	ctx=(BIO_B64_CTX *)Malloc(sizeof(BIO_B64_CTX));
1171638Srgrimes	if (ctx == NULL) return(0);
1181638Srgrimes
1191638Srgrimes	ctx->buf_len=0;
1201638Srgrimes	ctx->tmp_len=0;
1211638Srgrimes	ctx->tmp_nl=0;
1221638Srgrimes	ctx->buf_off=0;
1231638Srgrimes	ctx->cont=1;
1241638Srgrimes	ctx->start=1;
1251638Srgrimes	ctx->encode=0;
1261638Srgrimes
1271638Srgrimes	bi->init=1;
1281638Srgrimes	bi->ptr=(char *)ctx;
1291638Srgrimes	bi->flags=0;
1301638Srgrimes	return(1);
1311638Srgrimes	}
1321638Srgrimes
1331638Srgrimesstatic int b64_free(BIO *a)
1341638Srgrimes	{
1351638Srgrimes	if (a == NULL) return(0);
136108533Sschweikh	Free(a->ptr);
1371638Srgrimes	a->ptr=NULL;
1381638Srgrimes	a->init=0;
1391638Srgrimes	a->flags=0;
1401638Srgrimes	return(1);
1411638Srgrimes	}
1421638Srgrimes
1431638Srgrimesstatic int b64_read(BIO *b, char *out, int outl)
1441638Srgrimes	{
1451638Srgrimes	int ret=0,i,ii,j,k,x,n,num,ret_code=0;
1461638Srgrimes	BIO_B64_CTX *ctx;
1471638Srgrimes	unsigned char *p,*q;
1481638Srgrimes
1491638Srgrimes	if (out == NULL) return(0);
1501638Srgrimes	ctx=(BIO_B64_CTX *)b->ptr;
1511638Srgrimes
1521638Srgrimes	if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
1531638Srgrimes
1541638Srgrimes	if (ctx->encode != B64_DECODE)
1551638Srgrimes		{
1561638Srgrimes		ctx->encode=B64_DECODE;
1571638Srgrimes		ctx->buf_len=0;
1581638Srgrimes		ctx->buf_off=0;
1591638Srgrimes		ctx->tmp_len=0;
1601638Srgrimes		EVP_DecodeInit(&(ctx->base64));
1611638Srgrimes		}
1621638Srgrimes
1631638Srgrimes	/* First check if there are bytes decoded/encoded */
1641638Srgrimes	if (ctx->buf_len > 0)
1651638Srgrimes		{
1661638Srgrimes		i=ctx->buf_len-ctx->buf_off;
1671638Srgrimes		if (i > outl) i=outl;
1681638Srgrimes		memcpy(out,&(ctx->buf[ctx->buf_off]),i);
1691638Srgrimes		ret=i;
1701638Srgrimes		out+=i;
1711638Srgrimes		outl-=i;
1721638Srgrimes		ctx->buf_off+=i;
1731638Srgrimes		if (ctx->buf_len == ctx->buf_off)
1741638Srgrimes			{
1751638Srgrimes			ctx->buf_len=0;
1761638Srgrimes			ctx->buf_off=0;
1771638Srgrimes			}
1781638Srgrimes		}
1791638Srgrimes
1801638Srgrimes	/* At this point, we have room of outl bytes and an empty
1811638Srgrimes	 * buffer, so we should read in some more. */
1821638Srgrimes
1831638Srgrimes	ret_code=0;
1841638Srgrimes	while (outl > 0)
1851638Srgrimes		{
1861638Srgrimes		if (ctx->cont <= 0) break;
1871638Srgrimes
1881638Srgrimes		i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]),
1891638Srgrimes			B64_BLOCK_SIZE-ctx->tmp_len);
1901638Srgrimes
1911638Srgrimes		if (i <= 0)
1921638Srgrimes			{
1931638Srgrimes			ret_code=i;
1941638Srgrimes
1951638Srgrimes			/* Should be continue next time we are called? */
1961638Srgrimes			if (!BIO_should_retry(b->next_bio))
1971638Srgrimes				ctx->cont=i;
1981638Srgrimes			/* else we should continue when called again */
1991638Srgrimes			break;
2001638Srgrimes			}
2011638Srgrimes		i+=ctx->tmp_len;
202108533Sschweikh
2031638Srgrimes		/* We need to scan, a line at a time until we
2041638Srgrimes		 * have a valid line if we are starting. */
2051638Srgrimes		if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL))
2061638Srgrimes			{
2071638Srgrimes			/* ctx->start=1; */
2081638Srgrimes			ctx->tmp_len=0;
2091638Srgrimes			}
2101638Srgrimes		else if (ctx->start)
2111638Srgrimes			{
2121638Srgrimes			q=p=(unsigned char *)ctx->tmp;
2131638Srgrimes			for (j=0; j<i; j++)
2141638Srgrimes				{
2151638Srgrimes				if (*(q++) != '\n') continue;
2161638Srgrimes
2171638Srgrimes				/* due to a previous very long line,
2181638Srgrimes				 * we need to keep on scanning for a '\n'
2191638Srgrimes				 * before we even start looking for
2201638Srgrimes				 * base64 encoded stuff. */
2211638Srgrimes				if (ctx->tmp_nl)
2221638Srgrimes					{
2231638Srgrimes					p=q;
2241638Srgrimes					ctx->tmp_nl=0;
2251638Srgrimes					continue;
2261638Srgrimes					}
2271638Srgrimes
2281638Srgrimes				k=EVP_DecodeUpdate(&(ctx->base64),
2291638Srgrimes					(unsigned char *)ctx->buf,
2301638Srgrimes					&num,p,q-p);
2311638Srgrimes				if ((k <= 0) && (num == 0) && (ctx->start))
2321638Srgrimes					EVP_DecodeInit(&ctx->base64);
2331638Srgrimes				else
2341638Srgrimes					{
2351638Srgrimes					if (p != (unsigned char *)
2361638Srgrimes						&(ctx->tmp[0]))
2371638Srgrimes						{
2381638Srgrimes						i-=(p- (unsigned char *)
2391638Srgrimes							&(ctx->tmp[0]));
2401638Srgrimes						for (x=0; x < i; x++)
2411638Srgrimes							ctx->tmp[x]=p[x];
2421638Srgrimes						}
2431638Srgrimes					EVP_DecodeInit(&ctx->base64);
2441638Srgrimes					ctx->start=0;
2451638Srgrimes					break;
2461638Srgrimes					}
2471638Srgrimes				p=q;
2481638Srgrimes				}
2491638Srgrimes
2501638Srgrimes			/* we fell off the end without starting */
2511638Srgrimes			if (j == i)
2521638Srgrimes				{
2531638Srgrimes				/* Is this is one long chunk?, if so, keep on
2541638Srgrimes				 * reading until a new line. */
2551638Srgrimes				if (p == (unsigned char *)&(ctx->tmp[0]))
2561638Srgrimes					{
2571638Srgrimes					ctx->tmp_nl=1;
2581638Srgrimes					ctx->tmp_len=0;
2591638Srgrimes					}
2601638Srgrimes				else if (p != q) /* finished on a '\n' */
261108533Sschweikh					{
2621638Srgrimes					n=q-p;
2631638Srgrimes					for (ii=0; ii<n; ii++)
2641638Srgrimes						ctx->tmp[ii]=p[ii];
2651638Srgrimes					ctx->tmp_len=n;
2661638Srgrimes					}
2671638Srgrimes				/* else finished on a '\n' */
2681638Srgrimes				continue;
2691638Srgrimes				}
2701638Srgrimes			else
2711638Srgrimes				ctx->tmp_len=0;
2721638Srgrimes			}
2731638Srgrimes
2741638Srgrimes		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
2751638Srgrimes			{
2761638Srgrimes			int z,jj;
2771638Srgrimes
2781638Srgrimes			jj=(i>>2)<<2;
279108533Sschweikh			z=EVP_DecodeBlock((unsigned char *)ctx->buf,
2801638Srgrimes				(unsigned char *)ctx->tmp,jj);
2811638Srgrimes			if (jj > 2)
2821638Srgrimes				{
2831638Srgrimes				if (ctx->tmp[jj-1] == '=')
2841638Srgrimes					{
2851638Srgrimes					z--;
2861638Srgrimes					if (ctx->tmp[jj-2] == '=')
2871638Srgrimes						z--;
2881638Srgrimes					}
2891638Srgrimes				}
2901638Srgrimes			/* z is now number of output bytes and jj is the
2911638Srgrimes			 * number consumed */
2921638Srgrimes			if (jj != i)
2931638Srgrimes				{
2941638Srgrimes				memcpy((unsigned char *)ctx->tmp,
2951638Srgrimes					(unsigned char *)&(ctx->tmp[jj]),i-jj);
2961638Srgrimes				ctx->tmp_len=i-jj;
2971638Srgrimes				}
2981638Srgrimes			ctx->buf_len=0;
2991638Srgrimes			if (z > 0)
3001638Srgrimes				{
3011638Srgrimes				ctx->buf_len=z;
3021638Srgrimes				i=1;
3031638Srgrimes				}
3041638Srgrimes			else
3051638Srgrimes				i=z;
3061638Srgrimes			}
3071638Srgrimes		else
3081638Srgrimes			{
3091638Srgrimes			i=EVP_DecodeUpdate(&(ctx->base64),
3101638Srgrimes				(unsigned char *)ctx->buf,&ctx->buf_len,
3111638Srgrimes				(unsigned char *)ctx->tmp,i);
3121638Srgrimes			}
3131638Srgrimes		ctx->cont=i;
3141638Srgrimes		ctx->buf_off=0;
3151638Srgrimes		if (i < 0)
3161638Srgrimes			{
3171638Srgrimes			ret_code=0;
3181638Srgrimes			ctx->buf_len=0;
3191638Srgrimes			break;
3201638Srgrimes			}
3211638Srgrimes
3221638Srgrimes		if (ctx->buf_len <= outl)
3231638Srgrimes			i=ctx->buf_len;
3241638Srgrimes		else
3251638Srgrimes			i=outl;
3261638Srgrimes
3271638Srgrimes		memcpy(out,ctx->buf,i);
3281638Srgrimes		ret+=i;
3291638Srgrimes		ctx->buf_off=i;
3301638Srgrimes		if (ctx->buf_off == ctx->buf_len)
3311638Srgrimes			{
3321638Srgrimes			ctx->buf_len=0;
3331638Srgrimes			ctx->buf_off=0;
3341638Srgrimes			}
3351638Srgrimes		outl-=i;
3361638Srgrimes		out+=i;
3371638Srgrimes		}
3381638Srgrimes	BIO_clear_retry_flags(b);
3391638Srgrimes	BIO_copy_next_retry(b);
3401638Srgrimes	return((ret == 0)?ret_code:ret);
3411638Srgrimes	}
3421638Srgrimes
3431638Srgrimesstatic int b64_write(BIO *b, char *in, int inl)
3441638Srgrimes	{
3451638Srgrimes	int ret=inl,n,i;
3461638Srgrimes	BIO_B64_CTX *ctx;
3471638Srgrimes
3481638Srgrimes	ctx=(BIO_B64_CTX *)b->ptr;
3491638Srgrimes	BIO_clear_retry_flags(b);
350108533Sschweikh
3511638Srgrimes	if (ctx->encode != B64_ENCODE)
3521638Srgrimes		{
3531638Srgrimes		ctx->encode=B64_ENCODE;
3541638Srgrimes		ctx->buf_len=0;
3551638Srgrimes		ctx->buf_off=0;
3561638Srgrimes		ctx->tmp_len=0;
3571638Srgrimes		EVP_EncodeInit(&(ctx->base64));
358108533Sschweikh		}
3591638Srgrimes
3601638Srgrimes	n=ctx->buf_len-ctx->buf_off;
3611638Srgrimes	while (n > 0)
362108533Sschweikh		{
3631638Srgrimes		i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
3641638Srgrimes		if (i <= 0)
3651638Srgrimes			{
3661638Srgrimes			BIO_copy_next_retry(b);
3671638Srgrimes			return(i);
3681638Srgrimes			}
3691638Srgrimes		ctx->buf_off+=i;
3701638Srgrimes		n-=i;
3711638Srgrimes		}
3721638Srgrimes	/* at this point all pending data has been written */
3731638Srgrimes
3741638Srgrimes	if ((in == NULL) || (inl <= 0)) return(0);
375108533Sschweikh
376108533Sschweikh	ctx->buf_off=0;
3771638Srgrimes	while (inl > 0)
3781638Srgrimes		{
3791638Srgrimes		n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl;
3801638Srgrimes
3811638Srgrimes		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
3821638Srgrimes			{
3831638Srgrimes			if (ctx->tmp_len > 0)
3841638Srgrimes				{
3851638Srgrimes				n=3-ctx->tmp_len;
3861638Srgrimes				memcpy(&(ctx->tmp[ctx->tmp_len]),in,n);
3871638Srgrimes				ctx->tmp_len+=n;
3881638Srgrimes				n=ctx->tmp_len;
3891638Srgrimes				if (n < 3)
3901638Srgrimes					break;
3911638Srgrimes				ctx->buf_len=EVP_EncodeBlock(
3921638Srgrimes					(unsigned char *)ctx->buf,
3931638Srgrimes					(unsigned char *)ctx->tmp,n);
3941638Srgrimes				}
3951638Srgrimes			else
3961638Srgrimes				{
3971638Srgrimes				if (n < 3)
3981638Srgrimes					{
3991638Srgrimes					memcpy(&(ctx->tmp[0]),in,n);
4001638Srgrimes					ctx->tmp_len=n;
4011638Srgrimes					break;
4021638Srgrimes					}
4031638Srgrimes				n-=n%3;
4041638Srgrimes				ctx->buf_len=EVP_EncodeBlock(
4051638Srgrimes					(unsigned char *)ctx->buf,
4061638Srgrimes					(unsigned char *)in,n);
4071638Srgrimes				}
4081638Srgrimes			}
4091638Srgrimes		else
4101638Srgrimes			{
4111638Srgrimes			EVP_EncodeUpdate(&(ctx->base64),
4121638Srgrimes				(unsigned char *)ctx->buf,&ctx->buf_len,
4131638Srgrimes				(unsigned char *)in,n);
4141638Srgrimes			}
4151638Srgrimes		inl-=n;
4161638Srgrimes		in+=n;
4171638Srgrimes
4181638Srgrimes		ctx->buf_off=0;
4191638Srgrimes		n=ctx->buf_len;
4201638Srgrimes		while (n > 0)
4211638Srgrimes			{
4221638Srgrimes			i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
4231638Srgrimes			if (i <= 0)
4241638Srgrimes				{
4251638Srgrimes				BIO_copy_next_retry(b);
4261638Srgrimes				return((ret == 0)?i:ret);
4271638Srgrimes				}
4281638Srgrimes			n-=i;
4291638Srgrimes			ctx->buf_off+=i;
4301638Srgrimes			}
4311638Srgrimes		ctx->buf_len=0;
4321638Srgrimes		ctx->buf_off=0;
4331638Srgrimes		}
4341638Srgrimes	return(ret);
4351638Srgrimes	}
4361638Srgrimes
4371638Srgrimesstatic long b64_ctrl(BIO *b, int cmd, long num, char *ptr)
4381638Srgrimes	{
4391638Srgrimes	BIO_B64_CTX *ctx;
4401638Srgrimes	long ret=1;
4411638Srgrimes	int i;
4421638Srgrimes
4431638Srgrimes	ctx=(BIO_B64_CTX *)b->ptr;
444108533Sschweikh
4451638Srgrimes	switch (cmd)
4461638Srgrimes		{
4471638Srgrimes	case BIO_CTRL_RESET:
4481638Srgrimes		ctx->cont=1;
4491638Srgrimes		ctx->start=1;
4501638Srgrimes		ctx->encode=B64_NONE;
4511638Srgrimes		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
4521638Srgrimes		break;
4531638Srgrimes	case BIO_CTRL_EOF:	/* More to read */
4541638Srgrimes		if (ctx->cont <= 0)
4551638Srgrimes			ret=1;
4561638Srgrimes		else
4571638Srgrimes			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
4581638Srgrimes		break;
4591638Srgrimes	case BIO_CTRL_WPENDING: /* More to write in buffer */
4601638Srgrimes		ret=ctx->buf_len-ctx->buf_off;
4611638Srgrimes		if ((ret == 0) && (ctx->base64.num != 0))
4621638Srgrimes			ret=1;
4631638Srgrimes		else if (ret <= 0)
4641638Srgrimes			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
4651638Srgrimes		break;
4661638Srgrimes	case BIO_CTRL_PENDING: /* More to read in buffer */
4671638Srgrimes		ret=ctx->buf_len-ctx->buf_off;
4681638Srgrimes		if (ret <= 0)
469108533Sschweikh			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
4701638Srgrimes		break;
4711638Srgrimes	case BIO_CTRL_FLUSH:
4721638Srgrimes		/* do a final write */
4731638Srgrimesagain:
4741638Srgrimes		while (ctx->buf_len != ctx->buf_off)
4751638Srgrimes			{
4761638Srgrimes			i=b64_write(b,NULL,0);
4771638Srgrimes			if (i < 0)
4781638Srgrimes				{
4791638Srgrimes				ret=i;
4801638Srgrimes				break;
4811638Srgrimes				}
4821638Srgrimes			}
4831638Srgrimes		if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
4841638Srgrimes			{
4851638Srgrimes			if (ctx->tmp_len != 0)
4861638Srgrimes				{
4871638Srgrimes				ctx->buf_len=EVP_EncodeBlock(
4881638Srgrimes					(unsigned char *)ctx->buf,
4891638Srgrimes					(unsigned char *)ctx->tmp,
4901638Srgrimes					ctx->tmp_len);
491108533Sschweikh				ctx->buf_off=0;
4921638Srgrimes				ctx->tmp_len=0;
4931638Srgrimes				goto again;
4941638Srgrimes				}
4951638Srgrimes			}
4961638Srgrimes		else if (ctx->base64.num != 0)
4971638Srgrimes			{
4981638Srgrimes			ctx->buf_off=0;
4991638Srgrimes			EVP_EncodeFinal(&(ctx->base64),
5001638Srgrimes				(unsigned char *)ctx->buf,
5011638Srgrimes				&(ctx->buf_len));
5021638Srgrimes			/* push out the bytes */
5031638Srgrimes			goto again;
5041638Srgrimes			}
5051638Srgrimes		/* Finally flush the underlying BIO */
5061638Srgrimes		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
5071638Srgrimes		break;
5081638Srgrimes
5091638Srgrimes	case BIO_C_DO_STATE_MACHINE:
5101638Srgrimes		BIO_clear_retry_flags(b);
5111638Srgrimes		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
5121638Srgrimes		BIO_copy_next_retry(b);
5131638Srgrimes		break;
5141638Srgrimes
5151638Srgrimes	case BIO_CTRL_DUP:
5161638Srgrimes		break;
5171638Srgrimes	case BIO_CTRL_INFO:
5181638Srgrimes	case BIO_CTRL_GET:
5191638Srgrimes	case BIO_CTRL_SET:
5201638Srgrimes	default:
5211638Srgrimes		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
5221638Srgrimes		break;
5231638Srgrimes		}
5241638Srgrimes	return(ret);
5251638Srgrimes	}
5261638Srgrimes
5271638Srgrimesstatic long b64_callback_ctrl(BIO *b, int cmd, void (*fp)())
5281638Srgrimes	{
5291638Srgrimes	long ret=1;
5301638Srgrimes
5311638Srgrimes	if (b->next_bio == NULL) return(0);
5321638Srgrimes	switch (cmd)
5331638Srgrimes		{
5341638Srgrimes	default:
5351638Srgrimes		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
5361638Srgrimes		break;
5371638Srgrimes		}
5381638Srgrimes	return(ret);
5391638Srgrimes	}
5401638Srgrimes
5411638Srgrimes