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