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