1*0Sstevel@tonic-gate /* crypto/evp/bio_ok.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 /* 60*0Sstevel@tonic-gate From: Arne Ansper <arne@cyber.ee> 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate Why BIO_f_reliable? 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate I wrote function which took BIO* as argument, read data from it 65*0Sstevel@tonic-gate and processed it. Then I wanted to store the input file in 66*0Sstevel@tonic-gate encrypted form. OK I pushed BIO_f_cipher to the BIO stack 67*0Sstevel@tonic-gate and everything was OK. BUT if user types wrong password 68*0Sstevel@tonic-gate BIO_f_cipher outputs only garbage and my function crashes. Yes 69*0Sstevel@tonic-gate I can and I should fix my function, but BIO_f_cipher is 70*0Sstevel@tonic-gate easy way to add encryption support to many existing applications 71*0Sstevel@tonic-gate and it's hard to debug and fix them all. 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate So I wanted another BIO which would catch the incorrect passwords and 74*0Sstevel@tonic-gate file damages which cause garbage on BIO_f_cipher's output. 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate The easy way is to push the BIO_f_md and save the checksum at 77*0Sstevel@tonic-gate the end of the file. However there are several problems with this 78*0Sstevel@tonic-gate approach: 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate 1) you must somehow separate checksum from actual data. 81*0Sstevel@tonic-gate 2) you need lot's of memory when reading the file, because you 82*0Sstevel@tonic-gate must read to the end of the file and verify the checksum before 83*0Sstevel@tonic-gate letting the application to read the data. 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate BIO_f_reliable tries to solve both problems, so that you can 86*0Sstevel@tonic-gate read and write arbitrary long streams using only fixed amount 87*0Sstevel@tonic-gate of memory. 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate BIO_f_reliable splits data stream into blocks. Each block is prefixed 90*0Sstevel@tonic-gate with it's length and suffixed with it's digest. So you need only 91*0Sstevel@tonic-gate several Kbytes of memory to buffer single block before verifying 92*0Sstevel@tonic-gate it's digest. 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate BIO_f_reliable goes further and adds several important capabilities: 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate 1) the digest of the block is computed over the whole stream 97*0Sstevel@tonic-gate -- so nobody can rearrange the blocks or remove or replace them. 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate 2) to detect invalid passwords right at the start BIO_f_reliable 100*0Sstevel@tonic-gate adds special prefix to the stream. In order to avoid known plain-text 101*0Sstevel@tonic-gate attacks this prefix is generated as follows: 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate *) digest is initialized with random seed instead of 104*0Sstevel@tonic-gate standardized one. 105*0Sstevel@tonic-gate *) same seed is written to output 106*0Sstevel@tonic-gate *) well-known text is then hashed and the output 107*0Sstevel@tonic-gate of the digest is also written to output. 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate reader can now read the seed from stream, hash the same string 110*0Sstevel@tonic-gate and then compare the digest output. 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I 113*0Sstevel@tonic-gate initially wrote and tested this code on x86 machine and wrote the 114*0Sstevel@tonic-gate digests out in machine-dependent order :( There are people using 115*0Sstevel@tonic-gate this code and I cannot change this easily without making existing 116*0Sstevel@tonic-gate data files unreadable. 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate #include <stdio.h> 121*0Sstevel@tonic-gate #include <errno.h> 122*0Sstevel@tonic-gate #include "cryptlib.h" 123*0Sstevel@tonic-gate #include <openssl/buffer.h> 124*0Sstevel@tonic-gate #include <openssl/bio.h> 125*0Sstevel@tonic-gate #include <openssl/evp.h> 126*0Sstevel@tonic-gate #include <openssl/rand.h> 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate static int ok_write(BIO *h, const char *buf, int num); 129*0Sstevel@tonic-gate static int ok_read(BIO *h, char *buf, int size); 130*0Sstevel@tonic-gate static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2); 131*0Sstevel@tonic-gate static int ok_new(BIO *h); 132*0Sstevel@tonic-gate static int ok_free(BIO *data); 133*0Sstevel@tonic-gate static long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate static void sig_out(BIO* b); 136*0Sstevel@tonic-gate static void sig_in(BIO* b); 137*0Sstevel@tonic-gate static void block_out(BIO* b); 138*0Sstevel@tonic-gate static void block_in(BIO* b); 139*0Sstevel@tonic-gate #define OK_BLOCK_SIZE (1024*4) 140*0Sstevel@tonic-gate #define OK_BLOCK_BLOCK 4 141*0Sstevel@tonic-gate #define IOBS (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE) 142*0Sstevel@tonic-gate #define WELLKNOWN "The quick brown fox jumped over the lazy dog's back." 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate #ifndef L_ENDIAN 145*0Sstevel@tonic-gate #define swapem(x) \ 146*0Sstevel@tonic-gate ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ 147*0Sstevel@tonic-gate (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ 148*0Sstevel@tonic-gate (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ 149*0Sstevel@tonic-gate (((unsigned long int)(x) & 0xff000000U) >> 24))) 150*0Sstevel@tonic-gate #else 151*0Sstevel@tonic-gate #define swapem(x) (x) 152*0Sstevel@tonic-gate #endif 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate typedef struct ok_struct 155*0Sstevel@tonic-gate { 156*0Sstevel@tonic-gate int buf_len; 157*0Sstevel@tonic-gate int buf_off; 158*0Sstevel@tonic-gate int buf_len_save; 159*0Sstevel@tonic-gate int buf_off_save; 160*0Sstevel@tonic-gate int cont; /* <= 0 when finished */ 161*0Sstevel@tonic-gate int finished; 162*0Sstevel@tonic-gate EVP_MD_CTX md; 163*0Sstevel@tonic-gate int blockout; /* output block is ready */ 164*0Sstevel@tonic-gate int sigio; /* must process signature */ 165*0Sstevel@tonic-gate unsigned char buf[IOBS]; 166*0Sstevel@tonic-gate } BIO_OK_CTX; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate static BIO_METHOD methods_ok= 169*0Sstevel@tonic-gate { 170*0Sstevel@tonic-gate BIO_TYPE_CIPHER,"reliable", 171*0Sstevel@tonic-gate ok_write, 172*0Sstevel@tonic-gate ok_read, 173*0Sstevel@tonic-gate NULL, /* ok_puts, */ 174*0Sstevel@tonic-gate NULL, /* ok_gets, */ 175*0Sstevel@tonic-gate ok_ctrl, 176*0Sstevel@tonic-gate ok_new, 177*0Sstevel@tonic-gate ok_free, 178*0Sstevel@tonic-gate ok_callback_ctrl, 179*0Sstevel@tonic-gate }; 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate BIO_METHOD *BIO_f_reliable(void) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate return(&methods_ok); 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate static int ok_new(BIO *bi) 187*0Sstevel@tonic-gate { 188*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate ctx=(BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX)); 191*0Sstevel@tonic-gate if (ctx == NULL) return(0); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate ctx->buf_len=0; 194*0Sstevel@tonic-gate ctx->buf_off=0; 195*0Sstevel@tonic-gate ctx->buf_len_save=0; 196*0Sstevel@tonic-gate ctx->buf_off_save=0; 197*0Sstevel@tonic-gate ctx->cont=1; 198*0Sstevel@tonic-gate ctx->finished=0; 199*0Sstevel@tonic-gate ctx->blockout= 0; 200*0Sstevel@tonic-gate ctx->sigio=1; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate EVP_MD_CTX_init(&ctx->md); 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate bi->init=0; 205*0Sstevel@tonic-gate bi->ptr=(char *)ctx; 206*0Sstevel@tonic-gate bi->flags=0; 207*0Sstevel@tonic-gate return(1); 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate static int ok_free(BIO *a) 211*0Sstevel@tonic-gate { 212*0Sstevel@tonic-gate if (a == NULL) return(0); 213*0Sstevel@tonic-gate EVP_MD_CTX_cleanup(&((BIO_OK_CTX *)a->ptr)->md); 214*0Sstevel@tonic-gate OPENSSL_cleanse(a->ptr,sizeof(BIO_OK_CTX)); 215*0Sstevel@tonic-gate OPENSSL_free(a->ptr); 216*0Sstevel@tonic-gate a->ptr=NULL; 217*0Sstevel@tonic-gate a->init=0; 218*0Sstevel@tonic-gate a->flags=0; 219*0Sstevel@tonic-gate return(1); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate static int ok_read(BIO *b, char *out, int outl) 223*0Sstevel@tonic-gate { 224*0Sstevel@tonic-gate int ret=0,i,n; 225*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate if (out == NULL) return(0); 228*0Sstevel@tonic-gate ctx=(BIO_OK_CTX *)b->ptr; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) return(0); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate while(outl > 0) 233*0Sstevel@tonic-gate { 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /* copy clean bytes to output buffer */ 236*0Sstevel@tonic-gate if (ctx->blockout) 237*0Sstevel@tonic-gate { 238*0Sstevel@tonic-gate i=ctx->buf_len-ctx->buf_off; 239*0Sstevel@tonic-gate if (i > outl) i=outl; 240*0Sstevel@tonic-gate memcpy(out,&(ctx->buf[ctx->buf_off]),i); 241*0Sstevel@tonic-gate ret+=i; 242*0Sstevel@tonic-gate out+=i; 243*0Sstevel@tonic-gate outl-=i; 244*0Sstevel@tonic-gate ctx->buf_off+=i; 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* all clean bytes are out */ 247*0Sstevel@tonic-gate if (ctx->buf_len == ctx->buf_off) 248*0Sstevel@tonic-gate { 249*0Sstevel@tonic-gate ctx->buf_off=0; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* copy start of the next block into proper place */ 252*0Sstevel@tonic-gate if(ctx->buf_len_save- ctx->buf_off_save > 0) 253*0Sstevel@tonic-gate { 254*0Sstevel@tonic-gate ctx->buf_len= ctx->buf_len_save- ctx->buf_off_save; 255*0Sstevel@tonic-gate memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]), 256*0Sstevel@tonic-gate ctx->buf_len); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate else 259*0Sstevel@tonic-gate { 260*0Sstevel@tonic-gate ctx->buf_len=0; 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate ctx->blockout= 0; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* output buffer full -- cancel */ 267*0Sstevel@tonic-gate if (outl == 0) break; 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate /* no clean bytes in buffer -- fill it */ 270*0Sstevel@tonic-gate n=IOBS- ctx->buf_len; 271*0Sstevel@tonic-gate i=BIO_read(b->next_bio,&(ctx->buf[ctx->buf_len]),n); 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate if (i <= 0) break; /* nothing new */ 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate ctx->buf_len+= i; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* no signature yet -- check if we got one */ 278*0Sstevel@tonic-gate if (ctx->sigio == 1) sig_in(b); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate /* signature ok -- check if we got block */ 281*0Sstevel@tonic-gate if (ctx->sigio == 0) block_in(b); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* invalid block -- cancel */ 284*0Sstevel@tonic-gate if (ctx->cont <= 0) break; 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate BIO_clear_retry_flags(b); 289*0Sstevel@tonic-gate BIO_copy_next_retry(b); 290*0Sstevel@tonic-gate return(ret); 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate static int ok_write(BIO *b, const char *in, int inl) 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate int ret=0,n,i; 296*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate ctx=(BIO_OK_CTX *)b->ptr; 299*0Sstevel@tonic-gate ret=inl; 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) return(0); 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate if(ctx->sigio) sig_out(b); 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate do{ 306*0Sstevel@tonic-gate BIO_clear_retry_flags(b); 307*0Sstevel@tonic-gate n=ctx->buf_len-ctx->buf_off; 308*0Sstevel@tonic-gate while (ctx->blockout && n > 0) 309*0Sstevel@tonic-gate { 310*0Sstevel@tonic-gate i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); 311*0Sstevel@tonic-gate if (i <= 0) 312*0Sstevel@tonic-gate { 313*0Sstevel@tonic-gate BIO_copy_next_retry(b); 314*0Sstevel@tonic-gate if(!BIO_should_retry(b)) 315*0Sstevel@tonic-gate ctx->cont= 0; 316*0Sstevel@tonic-gate return(i); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate ctx->buf_off+=i; 319*0Sstevel@tonic-gate n-=i; 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* at this point all pending data has been written */ 323*0Sstevel@tonic-gate ctx->blockout= 0; 324*0Sstevel@tonic-gate if (ctx->buf_len == ctx->buf_off) 325*0Sstevel@tonic-gate { 326*0Sstevel@tonic-gate ctx->buf_len=OK_BLOCK_BLOCK; 327*0Sstevel@tonic-gate ctx->buf_off=0; 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if ((in == NULL) || (inl <= 0)) return(0); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate n= (inl+ ctx->buf_len > OK_BLOCK_SIZE+ OK_BLOCK_BLOCK) ? 333*0Sstevel@tonic-gate OK_BLOCK_SIZE+ OK_BLOCK_BLOCK- ctx->buf_len : inl; 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])),(unsigned char *)in,n); 336*0Sstevel@tonic-gate ctx->buf_len+= n; 337*0Sstevel@tonic-gate inl-=n; 338*0Sstevel@tonic-gate in+=n; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate if(ctx->buf_len >= OK_BLOCK_SIZE+ OK_BLOCK_BLOCK) 341*0Sstevel@tonic-gate { 342*0Sstevel@tonic-gate block_out(b); 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate }while(inl > 0); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate BIO_clear_retry_flags(b); 347*0Sstevel@tonic-gate BIO_copy_next_retry(b); 348*0Sstevel@tonic-gate return(ret); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate static long ok_ctrl(BIO *b, int cmd, long num, void *ptr) 352*0Sstevel@tonic-gate { 353*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 354*0Sstevel@tonic-gate EVP_MD *md; 355*0Sstevel@tonic-gate const EVP_MD **ppmd; 356*0Sstevel@tonic-gate long ret=1; 357*0Sstevel@tonic-gate int i; 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate ctx=b->ptr; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate switch (cmd) 362*0Sstevel@tonic-gate { 363*0Sstevel@tonic-gate case BIO_CTRL_RESET: 364*0Sstevel@tonic-gate ctx->buf_len=0; 365*0Sstevel@tonic-gate ctx->buf_off=0; 366*0Sstevel@tonic-gate ctx->buf_len_save=0; 367*0Sstevel@tonic-gate ctx->buf_off_save=0; 368*0Sstevel@tonic-gate ctx->cont=1; 369*0Sstevel@tonic-gate ctx->finished=0; 370*0Sstevel@tonic-gate ctx->blockout= 0; 371*0Sstevel@tonic-gate ctx->sigio=1; 372*0Sstevel@tonic-gate ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 373*0Sstevel@tonic-gate break; 374*0Sstevel@tonic-gate case BIO_CTRL_EOF: /* More to read */ 375*0Sstevel@tonic-gate if (ctx->cont <= 0) 376*0Sstevel@tonic-gate ret=1; 377*0Sstevel@tonic-gate else 378*0Sstevel@tonic-gate ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 379*0Sstevel@tonic-gate break; 380*0Sstevel@tonic-gate case BIO_CTRL_PENDING: /* More to read in buffer */ 381*0Sstevel@tonic-gate case BIO_CTRL_WPENDING: /* More to read in buffer */ 382*0Sstevel@tonic-gate ret=ctx->blockout ? ctx->buf_len-ctx->buf_off : 0; 383*0Sstevel@tonic-gate if (ret <= 0) 384*0Sstevel@tonic-gate ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 385*0Sstevel@tonic-gate break; 386*0Sstevel@tonic-gate case BIO_CTRL_FLUSH: 387*0Sstevel@tonic-gate /* do a final write */ 388*0Sstevel@tonic-gate if(ctx->blockout == 0) 389*0Sstevel@tonic-gate block_out(b); 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate while (ctx->blockout) 392*0Sstevel@tonic-gate { 393*0Sstevel@tonic-gate i=ok_write(b,NULL,0); 394*0Sstevel@tonic-gate if (i < 0) 395*0Sstevel@tonic-gate { 396*0Sstevel@tonic-gate ret=i; 397*0Sstevel@tonic-gate break; 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate ctx->finished=1; 402*0Sstevel@tonic-gate ctx->buf_off=ctx->buf_len=0; 403*0Sstevel@tonic-gate ctx->cont=(int)ret; 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate /* Finally flush the underlying BIO */ 406*0Sstevel@tonic-gate ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 407*0Sstevel@tonic-gate break; 408*0Sstevel@tonic-gate case BIO_C_DO_STATE_MACHINE: 409*0Sstevel@tonic-gate BIO_clear_retry_flags(b); 410*0Sstevel@tonic-gate ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 411*0Sstevel@tonic-gate BIO_copy_next_retry(b); 412*0Sstevel@tonic-gate break; 413*0Sstevel@tonic-gate case BIO_CTRL_INFO: 414*0Sstevel@tonic-gate ret=(long)ctx->cont; 415*0Sstevel@tonic-gate break; 416*0Sstevel@tonic-gate case BIO_C_SET_MD: 417*0Sstevel@tonic-gate md=ptr; 418*0Sstevel@tonic-gate EVP_DigestInit_ex(&ctx->md, md, NULL); 419*0Sstevel@tonic-gate b->init=1; 420*0Sstevel@tonic-gate break; 421*0Sstevel@tonic-gate case BIO_C_GET_MD: 422*0Sstevel@tonic-gate if (b->init) 423*0Sstevel@tonic-gate { 424*0Sstevel@tonic-gate ppmd=ptr; 425*0Sstevel@tonic-gate *ppmd=ctx->md.digest; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate else 428*0Sstevel@tonic-gate ret=0; 429*0Sstevel@tonic-gate break; 430*0Sstevel@tonic-gate default: 431*0Sstevel@tonic-gate ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 432*0Sstevel@tonic-gate break; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate return(ret); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 438*0Sstevel@tonic-gate { 439*0Sstevel@tonic-gate long ret=1; 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate if (b->next_bio == NULL) return(0); 442*0Sstevel@tonic-gate switch (cmd) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate default: 445*0Sstevel@tonic-gate ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 446*0Sstevel@tonic-gate break; 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate return(ret); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate static void longswap(void *_ptr, int len) 452*0Sstevel@tonic-gate { 453*0Sstevel@tonic-gate #ifndef L_ENDIAN 454*0Sstevel@tonic-gate int i; 455*0Sstevel@tonic-gate char *ptr=_ptr; 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate for(i= 0;i < len;i+= 4){ 458*0Sstevel@tonic-gate *((unsigned long *)&(ptr[i]))= swapem(*((unsigned long *)&(ptr[i]))); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate #endif 461*0Sstevel@tonic-gate } 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate static void sig_out(BIO* b) 464*0Sstevel@tonic-gate { 465*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 466*0Sstevel@tonic-gate EVP_MD_CTX *md; 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate ctx=b->ptr; 469*0Sstevel@tonic-gate md=&ctx->md; 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate if(ctx->buf_len+ 2* md->digest->md_size > OK_BLOCK_SIZE) return; 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate EVP_DigestInit_ex(md, md->digest, NULL); 474*0Sstevel@tonic-gate /* FIXME: there's absolutely no guarantee this makes any sense at all, 475*0Sstevel@tonic-gate * particularly now EVP_MD_CTX has been restructured. 476*0Sstevel@tonic-gate */ 477*0Sstevel@tonic-gate RAND_pseudo_bytes(md->md_data, md->digest->md_size); 478*0Sstevel@tonic-gate memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size); 479*0Sstevel@tonic-gate longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size); 480*0Sstevel@tonic-gate ctx->buf_len+= md->digest->md_size; 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)); 483*0Sstevel@tonic-gate EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL); 484*0Sstevel@tonic-gate ctx->buf_len+= md->digest->md_size; 485*0Sstevel@tonic-gate ctx->blockout= 1; 486*0Sstevel@tonic-gate ctx->sigio= 0; 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate static void sig_in(BIO* b) 490*0Sstevel@tonic-gate { 491*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 492*0Sstevel@tonic-gate EVP_MD_CTX *md; 493*0Sstevel@tonic-gate unsigned char tmp[EVP_MAX_MD_SIZE]; 494*0Sstevel@tonic-gate int ret= 0; 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate ctx=b->ptr; 497*0Sstevel@tonic-gate md=&ctx->md; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate if(ctx->buf_len- ctx->buf_off < 2* md->digest->md_size) return; 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate EVP_DigestInit_ex(md, md->digest, NULL); 502*0Sstevel@tonic-gate memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size); 503*0Sstevel@tonic-gate longswap(md->md_data, md->digest->md_size); 504*0Sstevel@tonic-gate ctx->buf_off+= md->digest->md_size; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)); 507*0Sstevel@tonic-gate EVP_DigestFinal_ex(md, tmp, NULL); 508*0Sstevel@tonic-gate ret= memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0; 509*0Sstevel@tonic-gate ctx->buf_off+= md->digest->md_size; 510*0Sstevel@tonic-gate if(ret == 1) 511*0Sstevel@tonic-gate { 512*0Sstevel@tonic-gate ctx->sigio= 0; 513*0Sstevel@tonic-gate if(ctx->buf_len != ctx->buf_off) 514*0Sstevel@tonic-gate { 515*0Sstevel@tonic-gate memmove(ctx->buf, &(ctx->buf[ctx->buf_off]), ctx->buf_len- ctx->buf_off); 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate ctx->buf_len-= ctx->buf_off; 518*0Sstevel@tonic-gate ctx->buf_off= 0; 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate else 521*0Sstevel@tonic-gate { 522*0Sstevel@tonic-gate ctx->cont= 0; 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate static void block_out(BIO* b) 527*0Sstevel@tonic-gate { 528*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 529*0Sstevel@tonic-gate EVP_MD_CTX *md; 530*0Sstevel@tonic-gate unsigned long tl; 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate ctx=b->ptr; 533*0Sstevel@tonic-gate md=&ctx->md; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate tl= ctx->buf_len- OK_BLOCK_BLOCK; 536*0Sstevel@tonic-gate tl= swapem(tl); 537*0Sstevel@tonic-gate memcpy(ctx->buf, &tl, OK_BLOCK_BLOCK); 538*0Sstevel@tonic-gate tl= swapem(tl); 539*0Sstevel@tonic-gate EVP_DigestUpdate(md, (unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl); 540*0Sstevel@tonic-gate EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL); 541*0Sstevel@tonic-gate ctx->buf_len+= md->digest->md_size; 542*0Sstevel@tonic-gate ctx->blockout= 1; 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate static void block_in(BIO* b) 546*0Sstevel@tonic-gate { 547*0Sstevel@tonic-gate BIO_OK_CTX *ctx; 548*0Sstevel@tonic-gate EVP_MD_CTX *md; 549*0Sstevel@tonic-gate long tl= 0; 550*0Sstevel@tonic-gate unsigned char tmp[EVP_MAX_MD_SIZE]; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate ctx=b->ptr; 553*0Sstevel@tonic-gate md=&ctx->md; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate memcpy(&tl, ctx->buf, OK_BLOCK_BLOCK); 556*0Sstevel@tonic-gate tl= swapem(tl); 557*0Sstevel@tonic-gate if (ctx->buf_len < tl+ OK_BLOCK_BLOCK+ md->digest->md_size) return; 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate EVP_DigestUpdate(md, (unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl); 560*0Sstevel@tonic-gate EVP_DigestFinal_ex(md, tmp, NULL); 561*0Sstevel@tonic-gate if(memcmp(&(ctx->buf[tl+ OK_BLOCK_BLOCK]), tmp, md->digest->md_size) == 0) 562*0Sstevel@tonic-gate { 563*0Sstevel@tonic-gate /* there might be parts from next block lurking around ! */ 564*0Sstevel@tonic-gate ctx->buf_off_save= tl+ OK_BLOCK_BLOCK+ md->digest->md_size; 565*0Sstevel@tonic-gate ctx->buf_len_save= ctx->buf_len; 566*0Sstevel@tonic-gate ctx->buf_off= OK_BLOCK_BLOCK; 567*0Sstevel@tonic-gate ctx->buf_len= tl+ OK_BLOCK_BLOCK; 568*0Sstevel@tonic-gate ctx->blockout= 1; 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate else 571*0Sstevel@tonic-gate { 572*0Sstevel@tonic-gate ctx->cont= 0; 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate 576