bio_b64.c revision 68651
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); 6768651Skris/*static 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, 9955714Skris NULL, /* 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; 13055714Skris return(1); 13155714Skris } 13255714Skris 13355714Skrisstatic int b64_free(BIO *a) 13455714Skris { 13555714Skris if (a == NULL) return(0); 13668651Skris OPENSSL_free(a->ptr); 13755714Skris a->ptr=NULL; 13855714Skris a->init=0; 13955714Skris a->flags=0; 14055714Skris return(1); 14155714Skris } 14255714Skris 14355714Skrisstatic int b64_read(BIO *b, char *out, int outl) 14455714Skris { 14555714Skris int ret=0,i,ii,j,k,x,n,num,ret_code=0; 14655714Skris BIO_B64_CTX *ctx; 14755714Skris unsigned char *p,*q; 14855714Skris 14955714Skris if (out == NULL) return(0); 15055714Skris ctx=(BIO_B64_CTX *)b->ptr; 15155714Skris 15255714Skris if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 15355714Skris 15455714Skris if (ctx->encode != B64_DECODE) 15555714Skris { 15655714Skris ctx->encode=B64_DECODE; 15755714Skris ctx->buf_len=0; 15855714Skris ctx->buf_off=0; 15955714Skris ctx->tmp_len=0; 16055714Skris EVP_DecodeInit(&(ctx->base64)); 16155714Skris } 16255714Skris 16355714Skris /* First check if there are bytes decoded/encoded */ 16455714Skris if (ctx->buf_len > 0) 16555714Skris { 16655714Skris i=ctx->buf_len-ctx->buf_off; 16755714Skris if (i > outl) i=outl; 16855714Skris memcpy(out,&(ctx->buf[ctx->buf_off]),i); 16955714Skris ret=i; 17055714Skris out+=i; 17155714Skris outl-=i; 17255714Skris ctx->buf_off+=i; 17355714Skris if (ctx->buf_len == ctx->buf_off) 17455714Skris { 17555714Skris ctx->buf_len=0; 17655714Skris ctx->buf_off=0; 17755714Skris } 17855714Skris } 17955714Skris 18055714Skris /* At this point, we have room of outl bytes and an empty 18155714Skris * buffer, so we should read in some more. */ 18255714Skris 18355714Skris ret_code=0; 18455714Skris while (outl > 0) 18555714Skris { 18655714Skris if (ctx->cont <= 0) break; 18755714Skris 18855714Skris i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]), 18955714Skris B64_BLOCK_SIZE-ctx->tmp_len); 19055714Skris 19155714Skris if (i <= 0) 19255714Skris { 19355714Skris ret_code=i; 19455714Skris 19555714Skris /* Should be continue next time we are called? */ 19655714Skris if (!BIO_should_retry(b->next_bio)) 19755714Skris ctx->cont=i; 19855714Skris /* else we should continue when called again */ 19955714Skris break; 20055714Skris } 20155714Skris i+=ctx->tmp_len; 20255714Skris 20355714Skris /* We need to scan, a line at a time until we 20455714Skris * have a valid line if we are starting. */ 20555714Skris if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) 20655714Skris { 20755714Skris /* ctx->start=1; */ 20855714Skris ctx->tmp_len=0; 20955714Skris } 21055714Skris else if (ctx->start) 21155714Skris { 21255714Skris q=p=(unsigned char *)ctx->tmp; 21355714Skris for (j=0; j<i; j++) 21455714Skris { 21555714Skris if (*(q++) != '\n') continue; 21655714Skris 21755714Skris /* due to a previous very long line, 21855714Skris * we need to keep on scanning for a '\n' 21955714Skris * before we even start looking for 22055714Skris * base64 encoded stuff. */ 22155714Skris if (ctx->tmp_nl) 22255714Skris { 22355714Skris p=q; 22455714Skris ctx->tmp_nl=0; 22555714Skris continue; 22655714Skris } 22755714Skris 22855714Skris k=EVP_DecodeUpdate(&(ctx->base64), 22955714Skris (unsigned char *)ctx->buf, 23055714Skris &num,p,q-p); 23155714Skris if ((k <= 0) && (num == 0) && (ctx->start)) 23255714Skris EVP_DecodeInit(&ctx->base64); 23355714Skris else 23455714Skris { 23555714Skris if (p != (unsigned char *) 23655714Skris &(ctx->tmp[0])) 23755714Skris { 23855714Skris i-=(p- (unsigned char *) 23955714Skris &(ctx->tmp[0])); 24055714Skris for (x=0; x < i; x++) 24155714Skris ctx->tmp[x]=p[x]; 24255714Skris } 24359191Skris EVP_DecodeInit(&ctx->base64); 24455714Skris ctx->start=0; 24555714Skris break; 24655714Skris } 24755714Skris p=q; 24855714Skris } 24955714Skris 25055714Skris /* we fell off the end without starting */ 25155714Skris if (j == i) 25255714Skris { 25355714Skris /* Is this is one long chunk?, if so, keep on 25455714Skris * reading until a new line. */ 25555714Skris if (p == (unsigned char *)&(ctx->tmp[0])) 25655714Skris { 25755714Skris ctx->tmp_nl=1; 25855714Skris ctx->tmp_len=0; 25955714Skris } 26055714Skris else if (p != q) /* finished on a '\n' */ 26155714Skris { 26255714Skris n=q-p; 26355714Skris for (ii=0; ii<n; ii++) 26455714Skris ctx->tmp[ii]=p[ii]; 26555714Skris ctx->tmp_len=n; 26655714Skris } 26755714Skris /* else finished on a '\n' */ 26855714Skris continue; 26955714Skris } 27055714Skris else 27155714Skris ctx->tmp_len=0; 27255714Skris } 27355714Skris 27455714Skris if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) 27555714Skris { 27655714Skris int z,jj; 27755714Skris 27855714Skris jj=(i>>2)<<2; 27955714Skris z=EVP_DecodeBlock((unsigned char *)ctx->buf, 28055714Skris (unsigned char *)ctx->tmp,jj); 28155714Skris if (jj > 2) 28255714Skris { 28355714Skris if (ctx->tmp[jj-1] == '=') 28455714Skris { 28555714Skris z--; 28655714Skris if (ctx->tmp[jj-2] == '=') 28755714Skris z--; 28855714Skris } 28955714Skris } 29055714Skris /* z is now number of output bytes and jj is the 29155714Skris * number consumed */ 29255714Skris if (jj != i) 29355714Skris { 29455714Skris memcpy((unsigned char *)ctx->tmp, 29555714Skris (unsigned char *)&(ctx->tmp[jj]),i-jj); 29655714Skris ctx->tmp_len=i-jj; 29755714Skris } 29855714Skris ctx->buf_len=0; 29955714Skris if (z > 0) 30055714Skris { 30155714Skris ctx->buf_len=z; 30255714Skris i=1; 30355714Skris } 30455714Skris else 30555714Skris i=z; 30655714Skris } 30755714Skris else 30855714Skris { 30955714Skris i=EVP_DecodeUpdate(&(ctx->base64), 31055714Skris (unsigned char *)ctx->buf,&ctx->buf_len, 31155714Skris (unsigned char *)ctx->tmp,i); 31255714Skris } 31355714Skris ctx->cont=i; 31455714Skris ctx->buf_off=0; 31555714Skris if (i < 0) 31655714Skris { 31755714Skris ret_code=0; 31855714Skris ctx->buf_len=0; 31955714Skris break; 32055714Skris } 32155714Skris 32255714Skris if (ctx->buf_len <= outl) 32355714Skris i=ctx->buf_len; 32455714Skris else 32555714Skris i=outl; 32655714Skris 32755714Skris memcpy(out,ctx->buf,i); 32855714Skris ret+=i; 32955714Skris ctx->buf_off=i; 33055714Skris if (ctx->buf_off == ctx->buf_len) 33155714Skris { 33255714Skris ctx->buf_len=0; 33355714Skris ctx->buf_off=0; 33455714Skris } 33555714Skris outl-=i; 33655714Skris out+=i; 33755714Skris } 33855714Skris BIO_clear_retry_flags(b); 33955714Skris BIO_copy_next_retry(b); 34055714Skris return((ret == 0)?ret_code:ret); 34155714Skris } 34255714Skris 34368651Skrisstatic int b64_write(BIO *b, const char *in, int inl) 34455714Skris { 34555714Skris int ret=inl,n,i; 34655714Skris BIO_B64_CTX *ctx; 34755714Skris 34855714Skris ctx=(BIO_B64_CTX *)b->ptr; 34955714Skris BIO_clear_retry_flags(b); 35055714Skris 35155714Skris if (ctx->encode != B64_ENCODE) 35255714Skris { 35355714Skris ctx->encode=B64_ENCODE; 35455714Skris ctx->buf_len=0; 35555714Skris ctx->buf_off=0; 35655714Skris ctx->tmp_len=0; 35755714Skris EVP_EncodeInit(&(ctx->base64)); 35855714Skris } 35955714Skris 36055714Skris n=ctx->buf_len-ctx->buf_off; 36155714Skris while (n > 0) 36255714Skris { 36355714Skris i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); 36455714Skris if (i <= 0) 36555714Skris { 36655714Skris BIO_copy_next_retry(b); 36755714Skris return(i); 36855714Skris } 36955714Skris ctx->buf_off+=i; 37055714Skris n-=i; 37155714Skris } 37255714Skris /* at this point all pending data has been written */ 37368651Skris ctx->buf_off=0; 37468651Skris ctx->buf_len=0; 37555714Skris 37655714Skris if ((in == NULL) || (inl <= 0)) return(0); 37755714Skris 37855714Skris while (inl > 0) 37955714Skris { 38055714Skris n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl; 38155714Skris 38255714Skris if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) 38355714Skris { 38455714Skris if (ctx->tmp_len > 0) 38555714Skris { 38655714Skris n=3-ctx->tmp_len; 38768651Skris /* There's a teoretical possibility for this */ 38868651Skris if (n > inl) 38968651Skris n=inl; 39055714Skris memcpy(&(ctx->tmp[ctx->tmp_len]),in,n); 39155714Skris ctx->tmp_len+=n; 39268651Skris if (ctx->tmp_len < 3) 39355714Skris break; 39455714Skris ctx->buf_len=EVP_EncodeBlock( 39555714Skris (unsigned char *)ctx->buf, 39668651Skris (unsigned char *)ctx->tmp, 39768651Skris ctx->tmp_len); 39868651Skris /* Since we're now done using the temporary 39968651Skris buffer, the length should be 0'd */ 40068651Skris ctx->tmp_len=0; 40155714Skris } 40255714Skris else 40355714Skris { 40455714Skris if (n < 3) 40555714Skris { 40655714Skris memcpy(&(ctx->tmp[0]),in,n); 40755714Skris ctx->tmp_len=n; 40855714Skris break; 40955714Skris } 41055714Skris n-=n%3; 41155714Skris ctx->buf_len=EVP_EncodeBlock( 41255714Skris (unsigned char *)ctx->buf, 41355714Skris (unsigned char *)in,n); 41455714Skris } 41555714Skris } 41655714Skris else 41755714Skris { 41855714Skris EVP_EncodeUpdate(&(ctx->base64), 41955714Skris (unsigned char *)ctx->buf,&ctx->buf_len, 42055714Skris (unsigned char *)in,n); 42155714Skris } 42255714Skris inl-=n; 42355714Skris in+=n; 42455714Skris 42555714Skris ctx->buf_off=0; 42655714Skris n=ctx->buf_len; 42755714Skris while (n > 0) 42855714Skris { 42955714Skris i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); 43055714Skris if (i <= 0) 43155714Skris { 43255714Skris BIO_copy_next_retry(b); 43355714Skris return((ret == 0)?i:ret); 43455714Skris } 43555714Skris n-=i; 43655714Skris ctx->buf_off+=i; 43755714Skris } 43855714Skris ctx->buf_len=0; 43955714Skris ctx->buf_off=0; 44055714Skris } 44155714Skris return(ret); 44255714Skris } 44355714Skris 44468651Skrisstatic long b64_ctrl(BIO *b, int cmd, long num, void *ptr) 44555714Skris { 44655714Skris BIO_B64_CTX *ctx; 44755714Skris long ret=1; 44855714Skris int i; 44955714Skris 45055714Skris ctx=(BIO_B64_CTX *)b->ptr; 45155714Skris 45255714Skris switch (cmd) 45355714Skris { 45455714Skris case BIO_CTRL_RESET: 45555714Skris ctx->cont=1; 45655714Skris ctx->start=1; 45755714Skris ctx->encode=B64_NONE; 45855714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 45955714Skris break; 46055714Skris case BIO_CTRL_EOF: /* More to read */ 46155714Skris if (ctx->cont <= 0) 46255714Skris ret=1; 46355714Skris else 46455714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 46555714Skris break; 46655714Skris case BIO_CTRL_WPENDING: /* More to write in buffer */ 46755714Skris ret=ctx->buf_len-ctx->buf_off; 46855714Skris if ((ret == 0) && (ctx->base64.num != 0)) 46955714Skris ret=1; 47055714Skris else if (ret <= 0) 47155714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 47255714Skris break; 47355714Skris case BIO_CTRL_PENDING: /* More to read in buffer */ 47455714Skris ret=ctx->buf_len-ctx->buf_off; 47555714Skris if (ret <= 0) 47655714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 47755714Skris break; 47855714Skris case BIO_CTRL_FLUSH: 47955714Skris /* do a final write */ 48055714Skrisagain: 48155714Skris while (ctx->buf_len != ctx->buf_off) 48255714Skris { 48355714Skris i=b64_write(b,NULL,0); 48455714Skris if (i < 0) 48555714Skris { 48655714Skris ret=i; 48755714Skris break; 48855714Skris } 48955714Skris } 49055714Skris if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) 49155714Skris { 49255714Skris if (ctx->tmp_len != 0) 49355714Skris { 49455714Skris ctx->buf_len=EVP_EncodeBlock( 49555714Skris (unsigned char *)ctx->buf, 49655714Skris (unsigned char *)ctx->tmp, 49755714Skris ctx->tmp_len); 49855714Skris ctx->buf_off=0; 49955714Skris ctx->tmp_len=0; 50055714Skris goto again; 50155714Skris } 50255714Skris } 50355714Skris else if (ctx->base64.num != 0) 50455714Skris { 50555714Skris ctx->buf_off=0; 50655714Skris EVP_EncodeFinal(&(ctx->base64), 50755714Skris (unsigned char *)ctx->buf, 50855714Skris &(ctx->buf_len)); 50955714Skris /* push out the bytes */ 51055714Skris goto again; 51155714Skris } 51255714Skris /* Finally flush the underlying BIO */ 51355714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 51455714Skris break; 51555714Skris 51655714Skris case BIO_C_DO_STATE_MACHINE: 51755714Skris BIO_clear_retry_flags(b); 51855714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 51955714Skris BIO_copy_next_retry(b); 52055714Skris break; 52155714Skris 52255714Skris case BIO_CTRL_DUP: 52355714Skris break; 52455714Skris case BIO_CTRL_INFO: 52555714Skris case BIO_CTRL_GET: 52655714Skris case BIO_CTRL_SET: 52755714Skris default: 52855714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 52955714Skris break; 53055714Skris } 53155714Skris return(ret); 53255714Skris } 53355714Skris 53468651Skrisstatic long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 53559191Skris { 53659191Skris long ret=1; 53759191Skris 53859191Skris if (b->next_bio == NULL) return(0); 53959191Skris switch (cmd) 54059191Skris { 54159191Skris default: 54259191Skris ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 54359191Skris break; 54459191Skris } 54559191Skris return(ret); 54659191Skris } 54759191Skris 548