X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=crypto%2Fevp%2Fbio_b64.c;h=72a2a67277a32e9b470fe24a8eec7b68fb1d5850;hb=a6bbbf2ff5580addb917a8b4f1160f90af91d268;hp=e362dc3bfeb9174a492db54ef357689641c216ec;hpb=b7896b3cb86d80206af14a14d69b0717786f2729;p=openssl.git diff --git a/crypto/evp/bio_b64.c b/crypto/evp/bio_b64.c index e362dc3bfe..72a2a67277 100644 --- a/crypto/evp/bio_b64.c +++ b/crypto/evp/bio_b64.c @@ -1,5 +1,5 @@ /* crypto/evp/bio_b64.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written @@ -59,28 +59,19 @@ #include #include #include "cryptlib.h" -#include "buffer.h" -#include "evp.h" - -#ifndef NOPROTO -static int b64_write(BIO *h,char *buf,int num); -static int b64_read(BIO *h,char *buf,int size); -/*static int b64_puts(BIO *h,char *str); */ -/*static int b64_gets(BIO *h,char *str,int size); */ -static long b64_ctrl(BIO *h,int cmd,long arg1,char *arg2); +#include +#include + +static int b64_write(BIO *h, const char *buf, int num); +static int b64_read(BIO *h, char *buf, int size); +static int b64_puts(BIO *h, const char *str); +/*static int b64_gets(BIO *h, char *str, int size); */ +static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2); static int b64_new(BIO *h); static int b64_free(BIO *data); -#else -static int b64_write(); -static int b64_read(); -/*static int b64_puts(); */ -/*static int b64_gets(); */ -static long b64_ctrl(); -static int b64_new(); -static int b64_free(); -#endif - +static long b64_callback_ctrl(BIO *h,int cmd,bio_info_cb *fp); #define B64_BLOCK_SIZE 1024 +#define B64_BLOCK_SIZE2 768 #define B64_NONE 0 #define B64_ENCODE 1 #define B64_DECODE 2 @@ -105,24 +96,24 @@ static BIO_METHOD methods_b64= BIO_TYPE_BASE64,"base64 encoding", b64_write, b64_read, - NULL, /* b64_puts, */ + b64_puts, NULL, /* b64_gets, */ b64_ctrl, b64_new, b64_free, + b64_callback_ctrl, }; -BIO_METHOD *BIO_f_base64() +BIO_METHOD *BIO_f_base64(void) { return(&methods_b64); } -static int b64_new(bi) -BIO *bi; +static int b64_new(BIO *bi) { BIO_B64_CTX *ctx; - ctx=(BIO_B64_CTX *)Malloc(sizeof(BIO_B64_CTX)); + ctx=(BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX)); if (ctx == NULL) return(0); ctx->buf_len=0; @@ -136,26 +127,23 @@ BIO *bi; bi->init=1; bi->ptr=(char *)ctx; bi->flags=0; + bi->num = 0; return(1); } -static int b64_free(a) -BIO *a; +static int b64_free(BIO *a) { if (a == NULL) return(0); - Free(a->ptr); + OPENSSL_free(a->ptr); a->ptr=NULL; a->init=0; a->flags=0; return(1); } -static int b64_read(b,out,outl) -BIO *b; -char *out; -int outl; +static int b64_read(BIO *b, char *out, int outl) { - int ret=0,i,ii,j,k,x,n,num; + int ret=0,i,ii,j,k,x,n,num,ret_code=0; BIO_B64_CTX *ctx; unsigned char *p,*q; @@ -164,19 +152,24 @@ int outl; if ((ctx == NULL) || (b->next_bio == NULL)) return(0); + BIO_clear_retry_flags(b); + if (ctx->encode != B64_DECODE) { ctx->encode=B64_DECODE; ctx->buf_len=0; ctx->buf_off=0; + ctx->tmp_len=0; EVP_DecodeInit(&(ctx->base64)); } /* First check if there are bytes decoded/encoded */ if (ctx->buf_len > 0) { + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); i=ctx->buf_len-ctx->buf_off; if (i > outl) i=outl; + OPENSSL_assert(ctx->buf_off+i < (int)sizeof(ctx->buf)); memcpy(out,&(ctx->buf[ctx->buf_off]),i); ret=i; out+=i; @@ -192,25 +185,45 @@ int outl; /* At this point, we have room of outl bytes and an empty * buffer, so we should read in some more. */ + ret_code=0; while (outl > 0) { - if (ctx->cont <= 0) break; + if (ctx->cont <= 0) + break; i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]), B64_BLOCK_SIZE-ctx->tmp_len); if (i <= 0) { - /* Should be continue next time we are called? */ + ret_code=i; + + /* Should we continue next time we are called? */ if (!BIO_should_retry(b->next_bio)) + { ctx->cont=i; - break; + /* If buffer empty break */ + if(ctx->tmp_len == 0) + break; + /* Fall through and process what we have */ + else + i = 0; + } + /* else we retry and add more data to buffer */ + else + break; } i+=ctx->tmp_len; + ctx->tmp_len = i; /* We need to scan, a line at a time until we * have a valid line if we are starting. */ - if (ctx->start) + if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) + { + /* ctx->start=1; */ + ctx->tmp_len=0; + } + else if (ctx->start) { q=p=(unsigned char *)ctx->tmp; for (j=0; jtmp[0])); for (x=0; x < i; x++) ctx->tmp[x]=p[x]; - EVP_DecodeInit(&ctx->base64); } + EVP_DecodeInit(&ctx->base64); ctx->start=0; break; } @@ -257,8 +270,12 @@ int outl; * reading until a new line. */ if (p == (unsigned char *)&(ctx->tmp[0])) { - ctx->tmp_nl=1; - ctx->tmp_len=0; + /* Check buffer full */ + if (i == B64_BLOCK_SIZE) + { + ctx->tmp_nl=1; + ctx->tmp_len=0; + } } else if (p != q) /* finished on a '\n' */ { @@ -271,15 +288,63 @@ int outl; continue; } else + { ctx->tmp_len=0; } - i=EVP_DecodeUpdate(&(ctx->base64), - (unsigned char *)ctx->buf,&ctx->buf_len, - (unsigned char *)ctx->tmp,i); - ctx->cont=i; + } + else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) + { + /* If buffer isn't full and we can retry then + * restart to read in more data. + */ + continue; + } + + if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) + { + int z,jj; + +#if 0 + jj=(i>>2)<<2; +#else + jj = i & ~3; /* process per 4 */ +#endif + z=EVP_DecodeBlock((unsigned char *)ctx->buf, + (unsigned char *)ctx->tmp,jj); + if (jj > 2) + { + if (ctx->tmp[jj-1] == '=') + { + z--; + if (ctx->tmp[jj-2] == '=') + z--; + } + } + /* z is now number of output bytes and jj is the + * number consumed */ + if (jj != i) + { + memmove(ctx->tmp, &ctx->tmp[jj], i-jj); + ctx->tmp_len=i-jj; + } + ctx->buf_len=0; + if (z > 0) + { + ctx->buf_len=z; + } + i=z; + } + else + { + i=EVP_DecodeUpdate(&(ctx->base64), + (unsigned char *)ctx->buf,&ctx->buf_len, + (unsigned char *)ctx->tmp,i); + ctx->tmp_len = 0; + } ctx->buf_off=0; if (i < 0) { + ret_code=0; ctx->buf_len=0; break; } @@ -300,17 +365,16 @@ int outl; outl-=i; out+=i; } - BIO_clear_retry_flags(b); + /* BIO_clear_retry_flags(b); */ BIO_copy_next_retry(b); - return((ret == 0)?ctx->cont:ret); + return((ret == 0)?ret_code:ret); } -static int b64_write(b,in,inl) -BIO *b; -char *in; -int inl; +static int b64_write(BIO *b, const char *in, int inl) { - int ret=inl,n,i; + int ret=0; + int n; + int i; BIO_B64_CTX *ctx; ctx=(BIO_B64_CTX *)b->ptr; @@ -321,9 +385,13 @@ int inl; ctx->encode=B64_ENCODE; ctx->buf_len=0; ctx->buf_off=0; + ctx->tmp_len=0; EVP_EncodeInit(&(ctx->base64)); } + OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf)); + OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); n=ctx->buf_len-ctx->buf_off; while (n > 0) { @@ -333,20 +401,68 @@ int inl; BIO_copy_next_retry(b); return(i); } + OPENSSL_assert(i <= n); ctx->buf_off+=i; + OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); n-=i; } /* at this point all pending data has been written */ + ctx->buf_off=0; + ctx->buf_len=0; if ((in == NULL) || (inl <= 0)) return(0); - ctx->buf_off=0; while (inl > 0) { n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl; - EVP_EncodeUpdate(&(ctx->base64), - (unsigned char *)ctx->buf,&ctx->buf_len, - (unsigned char *)in,n); + + if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) + { + if (ctx->tmp_len > 0) + { + OPENSSL_assert(ctx->tmp_len <= 3); + n=3-ctx->tmp_len; + /* There's a theoretical possibility for this */ + if (n > inl) + n=inl; + memcpy(&(ctx->tmp[ctx->tmp_len]),in,n); + ctx->tmp_len+=n; + ret += n; + if (ctx->tmp_len < 3) + break; + ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(unsigned char *)ctx->tmp,ctx->tmp_len); + OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); + /* Since we're now done using the temporary + buffer, the length should be 0'd */ + ctx->tmp_len=0; + } + else + { + if (n < 3) + { + memcpy(ctx->tmp,in,n); + ctx->tmp_len=n; + ret += n; + break; + } + n-=n%3; + ctx->buf_len=EVP_EncodeBlock((unsigned char *)ctx->buf,(const unsigned char *)in,n); + OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); + ret += n; + } + } + else + { + EVP_EncodeUpdate(&(ctx->base64), + (unsigned char *)ctx->buf,&ctx->buf_len, + (unsigned char *)in,n); + OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); + ret += n; + } inl-=n; in+=n; @@ -360,8 +476,11 @@ int inl; BIO_copy_next_retry(b); return((ret == 0)?i:ret); } + OPENSSL_assert(i <= n); n-=i; ctx->buf_off+=i; + OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); } ctx->buf_len=0; ctx->buf_off=0; @@ -369,11 +488,7 @@ int inl; return(ret); } -static long b64_ctrl(b,cmd,num,ptr) -BIO *b; -int cmd; -long num; -char *ptr; +static long b64_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO_B64_CTX *ctx; long ret=1; @@ -396,13 +511,16 @@ char *ptr; ret=BIO_ctrl(b->next_bio,cmd,num,ptr); break; case BIO_CTRL_WPENDING: /* More to write in buffer */ + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); ret=ctx->buf_len-ctx->buf_off; - if ((ret == 0) && (ctx->base64.num != 0)) + if ((ret == 0) && (ctx->encode != B64_NONE) + && (ctx->base64.num != 0)) ret=1; else if (ret <= 0) ret=BIO_ctrl(b->next_bio,cmd,num,ptr); break; case BIO_CTRL_PENDING: /* More to read in buffer */ + OPENSSL_assert(ctx->buf_len >= ctx->buf_off); ret=ctx->buf_len-ctx->buf_off; if (ret <= 0) ret=BIO_ctrl(b->next_bio,cmd,num,ptr); @@ -414,12 +532,22 @@ again: { i=b64_write(b,NULL,0); if (i < 0) + return i; + } + if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) + { + if (ctx->tmp_len != 0) { - ret=i; - break; + ctx->buf_len=EVP_EncodeBlock( + (unsigned char *)ctx->buf, + (unsigned char *)ctx->tmp, + ctx->tmp_len); + ctx->buf_off=0; + ctx->tmp_len=0; + goto again; } } - if (ctx->base64.num != 0) + else if (ctx->encode != B64_NONE && ctx->base64.num != 0) { ctx->buf_off=0; EVP_EncodeFinal(&(ctx->base64), @@ -450,3 +578,21 @@ again: return(ret); } +static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) + { + long ret=1; + + if (b->next_bio == NULL) return(0); + switch (cmd) + { + default: + ret=BIO_callback_ctrl(b->next_bio,cmd,fp); + break; + } + return(ret); + } + +static int b64_puts(BIO *b, const char *str) + { + return b64_write(b,str,strlen(str)); + }