bf_buff.c revision 68651
155714Skris/* crypto/bio/bf_buff.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/bio.h> 6355714Skris#include <openssl/evp.h> 6455714Skris 6568651Skrisstatic int buffer_write(BIO *h, const char *buf,int num); 6668651Skrisstatic int buffer_read(BIO *h, char *buf, int size); 6768651Skrisstatic int buffer_puts(BIO *h, const char *str); 6868651Skrisstatic int buffer_gets(BIO *h, char *str, int size); 6968651Skrisstatic long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 7055714Skrisstatic int buffer_new(BIO *h); 7155714Skrisstatic int buffer_free(BIO *data); 7268651Skrisstatic long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 7355714Skris#define DEFAULT_BUFFER_SIZE 1024 7455714Skris 7555714Skrisstatic BIO_METHOD methods_buffer= 7655714Skris { 7755714Skris BIO_TYPE_BUFFER, 7855714Skris "buffer", 7955714Skris buffer_write, 8055714Skris buffer_read, 8155714Skris buffer_puts, 8255714Skris buffer_gets, 8355714Skris buffer_ctrl, 8455714Skris buffer_new, 8555714Skris buffer_free, 8659191Skris buffer_callback_ctrl, 8755714Skris }; 8855714Skris 8955714SkrisBIO_METHOD *BIO_f_buffer(void) 9055714Skris { 9155714Skris return(&methods_buffer); 9255714Skris } 9355714Skris 9455714Skrisstatic int buffer_new(BIO *bi) 9555714Skris { 9655714Skris BIO_F_BUFFER_CTX *ctx; 9755714Skris 9868651Skris ctx=(BIO_F_BUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); 9955714Skris if (ctx == NULL) return(0); 10068651Skris ctx->ibuf=(char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 10168651Skris if (ctx->ibuf == NULL) { OPENSSL_free(ctx); return(0); } 10268651Skris ctx->obuf=(char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 10368651Skris if (ctx->obuf == NULL) { OPENSSL_free(ctx->ibuf); OPENSSL_free(ctx); return(0); } 10455714Skris ctx->ibuf_size=DEFAULT_BUFFER_SIZE; 10555714Skris ctx->obuf_size=DEFAULT_BUFFER_SIZE; 10655714Skris ctx->ibuf_len=0; 10755714Skris ctx->ibuf_off=0; 10855714Skris ctx->obuf_len=0; 10955714Skris ctx->obuf_off=0; 11055714Skris 11155714Skris bi->init=1; 11255714Skris bi->ptr=(char *)ctx; 11355714Skris bi->flags=0; 11455714Skris return(1); 11555714Skris } 11655714Skris 11755714Skrisstatic int buffer_free(BIO *a) 11855714Skris { 11955714Skris BIO_F_BUFFER_CTX *b; 12055714Skris 12155714Skris if (a == NULL) return(0); 12255714Skris b=(BIO_F_BUFFER_CTX *)a->ptr; 12368651Skris if (b->ibuf != NULL) OPENSSL_free(b->ibuf); 12468651Skris if (b->obuf != NULL) OPENSSL_free(b->obuf); 12568651Skris OPENSSL_free(a->ptr); 12655714Skris a->ptr=NULL; 12755714Skris a->init=0; 12855714Skris a->flags=0; 12955714Skris return(1); 13055714Skris } 13155714Skris 13255714Skrisstatic int buffer_read(BIO *b, char *out, int outl) 13355714Skris { 13455714Skris int i,num=0; 13555714Skris BIO_F_BUFFER_CTX *ctx; 13655714Skris 13755714Skris if (out == NULL) return(0); 13855714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 13955714Skris 14055714Skris if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 14155714Skris num=0; 14255714Skris BIO_clear_retry_flags(b); 14355714Skris 14455714Skrisstart: 14555714Skris i=ctx->ibuf_len; 14655714Skris /* If there is stuff left over, grab it */ 14755714Skris if (i != 0) 14855714Skris { 14955714Skris if (i > outl) i=outl; 15055714Skris memcpy(out,&(ctx->ibuf[ctx->ibuf_off]),i); 15155714Skris ctx->ibuf_off+=i; 15255714Skris ctx->ibuf_len-=i; 15355714Skris num+=i; 15455714Skris if (outl == i) return(num); 15555714Skris outl-=i; 15655714Skris out+=i; 15755714Skris } 15855714Skris 15955714Skris /* We may have done a partial read. try to do more. 16055714Skris * We have nothing in the buffer. 16155714Skris * If we get an error and have read some data, just return it 16255714Skris * and let them retry to get the error again. 16355714Skris * copy direct to parent address space */ 16455714Skris if (outl > ctx->ibuf_size) 16555714Skris { 16655714Skris for (;;) 16755714Skris { 16855714Skris i=BIO_read(b->next_bio,out,outl); 16955714Skris if (i <= 0) 17055714Skris { 17155714Skris BIO_copy_next_retry(b); 17255714Skris if (i < 0) return((num > 0)?num:i); 17355714Skris if (i == 0) return(num); 17455714Skris } 17555714Skris num+=i; 17655714Skris if (outl == i) return(num); 17755714Skris out+=i; 17855714Skris outl-=i; 17955714Skris } 18055714Skris } 18155714Skris /* else */ 18255714Skris 18355714Skris /* we are going to be doing some buffering */ 18455714Skris i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size); 18555714Skris if (i <= 0) 18655714Skris { 18755714Skris BIO_copy_next_retry(b); 18855714Skris if (i < 0) return((num > 0)?num:i); 18955714Skris if (i == 0) return(num); 19055714Skris } 19155714Skris ctx->ibuf_off=0; 19255714Skris ctx->ibuf_len=i; 19355714Skris 19455714Skris /* Lets re-read using ourselves :-) */ 19555714Skris goto start; 19655714Skris } 19755714Skris 19868651Skrisstatic int buffer_write(BIO *b, const char *in, int inl) 19955714Skris { 20055714Skris int i,num=0; 20155714Skris BIO_F_BUFFER_CTX *ctx; 20255714Skris 20355714Skris if ((in == NULL) || (inl <= 0)) return(0); 20455714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 20555714Skris if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 20655714Skris 20755714Skris BIO_clear_retry_flags(b); 20855714Skrisstart: 20955714Skris i=ctx->obuf_size-(ctx->obuf_len+ctx->obuf_off); 21055714Skris /* add to buffer and return */ 21155714Skris if (i >= inl) 21255714Skris { 21355714Skris memcpy(&(ctx->obuf[ctx->obuf_len]),in,inl); 21455714Skris ctx->obuf_len+=inl; 21555714Skris return(num+inl); 21655714Skris } 21755714Skris /* else */ 21855714Skris /* stuff already in buffer, so add to it first, then flush */ 21955714Skris if (ctx->obuf_len != 0) 22055714Skris { 22155714Skris if (i > 0) /* lets fill it up if we can */ 22255714Skris { 22355714Skris memcpy(&(ctx->obuf[ctx->obuf_len]),in,i); 22455714Skris in+=i; 22555714Skris inl-=i; 22655714Skris num+=i; 22755714Skris ctx->obuf_len+=i; 22855714Skris } 22955714Skris /* we now have a full buffer needing flushing */ 23055714Skris for (;;) 23155714Skris { 23255714Skris i=BIO_write(b->next_bio,&(ctx->obuf[ctx->obuf_off]), 23355714Skris ctx->obuf_len); 23455714Skris if (i <= 0) 23555714Skris { 23655714Skris BIO_copy_next_retry(b); 23755714Skris 23855714Skris if (i < 0) return((num > 0)?num:i); 23955714Skris if (i == 0) return(num); 24055714Skris } 24155714Skris ctx->obuf_off+=i; 24255714Skris ctx->obuf_len-=i; 24355714Skris if (ctx->obuf_len == 0) break; 24455714Skris } 24555714Skris } 24655714Skris /* we only get here if the buffer has been flushed and we 24755714Skris * still have stuff to write */ 24855714Skris ctx->obuf_off=0; 24955714Skris 25055714Skris /* we now have inl bytes to write */ 25155714Skris while (inl >= ctx->obuf_size) 25255714Skris { 25355714Skris i=BIO_write(b->next_bio,in,inl); 25455714Skris if (i <= 0) 25555714Skris { 25655714Skris BIO_copy_next_retry(b); 25755714Skris if (i < 0) return((num > 0)?num:i); 25855714Skris if (i == 0) return(num); 25955714Skris } 26055714Skris num+=i; 26155714Skris in+=i; 26255714Skris inl-=i; 26355714Skris if (inl == 0) return(num); 26455714Skris } 26555714Skris 26655714Skris /* copy the rest into the buffer since we have only a small 26755714Skris * amount left */ 26855714Skris goto start; 26955714Skris } 27055714Skris 27168651Skrisstatic long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) 27255714Skris { 27355714Skris BIO *dbio; 27455714Skris BIO_F_BUFFER_CTX *ctx; 27555714Skris long ret=1; 27655714Skris char *p1,*p2; 27755714Skris int r,i,*ip; 27855714Skris int ibs,obs; 27955714Skris 28055714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 28155714Skris 28255714Skris switch (cmd) 28355714Skris { 28455714Skris case BIO_CTRL_RESET: 28555714Skris ctx->ibuf_off=0; 28655714Skris ctx->ibuf_len=0; 28755714Skris ctx->obuf_off=0; 28855714Skris ctx->obuf_len=0; 28959191Skris if (b->next_bio == NULL) return(0); 29055714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 29155714Skris break; 29255714Skris case BIO_CTRL_INFO: 29355714Skris ret=(long)ctx->obuf_len; 29455714Skris break; 29555714Skris case BIO_C_GET_BUFF_NUM_LINES: 29655714Skris ret=0; 29755714Skris p1=ctx->ibuf; 29855714Skris for (i=ctx->ibuf_off; i<ctx->ibuf_len; i++) 29955714Skris { 30055714Skris if (p1[i] == '\n') ret++; 30155714Skris } 30255714Skris break; 30355714Skris case BIO_CTRL_WPENDING: 30455714Skris ret=(long)ctx->obuf_len; 30555714Skris if (ret == 0) 30659191Skris { 30759191Skris if (b->next_bio == NULL) return(0); 30855714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 30959191Skris } 31055714Skris break; 31155714Skris case BIO_CTRL_PENDING: 31255714Skris ret=(long)ctx->ibuf_len; 31355714Skris if (ret == 0) 31459191Skris { 31559191Skris if (b->next_bio == NULL) return(0); 31655714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 31759191Skris } 31855714Skris break; 31955714Skris case BIO_C_SET_BUFF_READ_DATA: 32055714Skris if (num > ctx->ibuf_size) 32155714Skris { 32268651Skris p1=OPENSSL_malloc((int)num); 32355714Skris if (p1 == NULL) goto malloc_error; 32468651Skris if (ctx->ibuf != NULL) OPENSSL_free(ctx->ibuf); 32555714Skris ctx->ibuf=p1; 32655714Skris } 32755714Skris ctx->ibuf_off=0; 32855714Skris ctx->ibuf_len=(int)num; 32955714Skris memcpy(ctx->ibuf,ptr,(int)num); 33055714Skris ret=1; 33155714Skris break; 33255714Skris case BIO_C_SET_BUFF_SIZE: 33355714Skris if (ptr != NULL) 33455714Skris { 33555714Skris ip=(int *)ptr; 33655714Skris if (*ip == 0) 33755714Skris { 33855714Skris ibs=(int)num; 33955714Skris obs=ctx->obuf_size; 34055714Skris } 34155714Skris else /* if (*ip == 1) */ 34255714Skris { 34355714Skris ibs=ctx->ibuf_size; 34455714Skris obs=(int)num; 34555714Skris } 34655714Skris } 34755714Skris else 34855714Skris { 34955714Skris ibs=(int)num; 35055714Skris obs=(int)num; 35155714Skris } 35255714Skris p1=ctx->ibuf; 35355714Skris p2=ctx->obuf; 35455714Skris if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) 35555714Skris { 35668651Skris p1=(char *)OPENSSL_malloc((int)num); 35755714Skris if (p1 == NULL) goto malloc_error; 35855714Skris } 35955714Skris if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) 36055714Skris { 36168651Skris p2=(char *)OPENSSL_malloc((int)num); 36255714Skris if (p2 == NULL) 36355714Skris { 36468651Skris if (p1 != ctx->ibuf) OPENSSL_free(p1); 36555714Skris goto malloc_error; 36655714Skris } 36755714Skris } 36855714Skris if (ctx->ibuf != p1) 36955714Skris { 37068651Skris OPENSSL_free(ctx->ibuf); 37155714Skris ctx->ibuf=p1; 37255714Skris ctx->ibuf_off=0; 37355714Skris ctx->ibuf_len=0; 37455714Skris ctx->ibuf_size=ibs; 37555714Skris } 37655714Skris if (ctx->obuf != p2) 37755714Skris { 37868651Skris OPENSSL_free(ctx->obuf); 37955714Skris ctx->obuf=p2; 38055714Skris ctx->obuf_off=0; 38155714Skris ctx->obuf_len=0; 38255714Skris ctx->obuf_size=obs; 38355714Skris } 38455714Skris break; 38555714Skris case BIO_C_DO_STATE_MACHINE: 38659191Skris if (b->next_bio == NULL) return(0); 38755714Skris BIO_clear_retry_flags(b); 38855714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 38955714Skris BIO_copy_next_retry(b); 39055714Skris break; 39155714Skris 39255714Skris case BIO_CTRL_FLUSH: 39359191Skris if (b->next_bio == NULL) return(0); 39455714Skris if (ctx->obuf_len <= 0) 39555714Skris { 39655714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 39755714Skris break; 39855714Skris } 39955714Skris 40055714Skris for (;;) 40155714Skris { 40255714Skris BIO_clear_retry_flags(b); 40355714Skris if (ctx->obuf_len > ctx->obuf_off) 40455714Skris { 40555714Skris r=BIO_write(b->next_bio, 40655714Skris &(ctx->obuf[ctx->obuf_off]), 40755714Skris ctx->obuf_len-ctx->obuf_off); 40855714Skris#if 0 40955714Skrisfprintf(stderr,"FLUSH [%3d] %3d -> %3d\n",ctx->obuf_off,ctx->obuf_len-ctx->obuf_off,r); 41055714Skris#endif 41155714Skris BIO_copy_next_retry(b); 41255714Skris if (r <= 0) return((long)r); 41355714Skris ctx->obuf_off+=r; 41455714Skris } 41555714Skris else 41655714Skris { 41755714Skris ctx->obuf_len=0; 41855714Skris ctx->obuf_off=0; 41955714Skris ret=1; 42055714Skris break; 42155714Skris } 42255714Skris } 42355714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 42455714Skris break; 42555714Skris case BIO_CTRL_DUP: 42655714Skris dbio=(BIO *)ptr; 42755714Skris if ( !BIO_set_read_buffer_size(dbio,ctx->ibuf_size) || 42855714Skris !BIO_set_write_buffer_size(dbio,ctx->obuf_size)) 42955714Skris ret=0; 43055714Skris break; 43155714Skris default: 43259191Skris if (b->next_bio == NULL) return(0); 43355714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 43455714Skris break; 43555714Skris } 43655714Skris return(ret); 43755714Skrismalloc_error: 43855714Skris BIOerr(BIO_F_BUFFER_CTRL,ERR_R_MALLOC_FAILURE); 43955714Skris return(0); 44055714Skris } 44155714Skris 44268651Skrisstatic long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 44359191Skris { 44459191Skris long ret=1; 44559191Skris 44659191Skris if (b->next_bio == NULL) return(0); 44759191Skris switch (cmd) 44859191Skris { 44959191Skris default: 45059191Skris ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 45159191Skris break; 45259191Skris } 45359191Skris return(ret); 45459191Skris } 45559191Skris 45655714Skrisstatic int buffer_gets(BIO *b, char *buf, int size) 45755714Skris { 45855714Skris BIO_F_BUFFER_CTX *ctx; 45955714Skris int num=0,i,flag; 46055714Skris char *p; 46155714Skris 46255714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 46355714Skris size--; /* reserve space for a '\0' */ 46455714Skris BIO_clear_retry_flags(b); 46555714Skris 46655714Skris for (;;) 46755714Skris { 46855714Skris if (ctx->ibuf_len > 0) 46955714Skris { 47055714Skris p= &(ctx->ibuf[ctx->ibuf_off]); 47155714Skris flag=0; 47255714Skris for (i=0; (i<ctx->ibuf_len) && (i<size); i++) 47355714Skris { 47455714Skris *(buf++)=p[i]; 47555714Skris if (p[i] == '\n') 47655714Skris { 47755714Skris flag=1; 47855714Skris i++; 47955714Skris break; 48055714Skris } 48155714Skris } 48255714Skris num+=i; 48355714Skris size-=i; 48455714Skris ctx->ibuf_len-=i; 48555714Skris ctx->ibuf_off+=i; 48655714Skris if ((flag) || (i == size)) 48755714Skris { 48855714Skris *buf='\0'; 48955714Skris return(num); 49055714Skris } 49155714Skris } 49255714Skris else /* read another chunk */ 49355714Skris { 49455714Skris i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size); 49555714Skris if (i <= 0) 49655714Skris { 49755714Skris BIO_copy_next_retry(b); 49855714Skris if (i < 0) return((num > 0)?num:i); 49955714Skris if (i == 0) return(num); 50055714Skris } 50155714Skris ctx->ibuf_len=i; 50255714Skris ctx->ibuf_off=0; 50355714Skris } 50455714Skris } 50555714Skris } 50655714Skris 50768651Skrisstatic int buffer_puts(BIO *b, const char *str) 50855714Skris { 50968651Skris return(buffer_write(b,str,strlen(str))); 51055714Skris } 51155714Skris 512