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