1 /* crypto/evp/bio_ber.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay (at) cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh (at) cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay (at) cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <stdio.h> 60 #include <errno.h> 61 #include "cryptlib.h" 62 #include <openssl/buffer.h> 63 #include <openssl/evp.h> 64 65 static int ber_write(BIO *h,char *buf,int num); 66 static int ber_read(BIO *h,char *buf,int size); 67 /*static int ber_puts(BIO *h,char *str); */ 68 /*static int ber_gets(BIO *h,char *str,int size); */ 69 static long ber_ctrl(BIO *h,int cmd,long arg1,char *arg2); 70 static int ber_new(BIO *h); 71 static int ber_free(BIO *data); 72 static long ber_callback_ctrl(BIO *h,int cmd,void *(*fp)()); 73 #define BER_BUF_SIZE (32) 74 75 /* This is used to hold the state of the BER objects being read. */ 76 typedef struct ber_struct 77 { 78 int tag; 79 int class; 80 long length; 81 int inf; 82 int num_left; 83 int depth; 84 } BER_CTX; 85 86 typedef struct bio_ber_struct 87 { 88 int tag; 89 int class; 90 long length; 91 int inf; 92 93 /* most of the following are used when doing non-blocking IO */ 94 /* reading */ 95 long num_left; /* number of bytes still to read/write in block */ 96 int depth; /* used with indefinite encoding. */ 97 int finished; /* No more read data */ 98 99 /* writting */ 100 char *w_addr; 101 int w_offset; 102 int w_left; 103 104 int buf_len; 105 int buf_off; 106 unsigned char buf[BER_BUF_SIZE]; 107 } BIO_BER_CTX; 108 109 static BIO_METHOD methods_ber= 110 { 111 BIO_TYPE_CIPHER,"cipher", 112 ber_write, 113 ber_read, 114 NULL, /* ber_puts, */ 115 NULL, /* ber_gets, */ 116 ber_ctrl, 117 ber_new, 118 ber_free, 119 ber_callback_ctrl, 120 }; 121 122 BIO_METHOD *BIO_f_ber(void) 123 { 124 return(&methods_ber); 125 } 126 127 static int ber_new(BIO *bi) 128 { 129 BIO_BER_CTX *ctx; 130 131 ctx=(BIO_BER_CTX *)OPENSSL_malloc(sizeof(BIO_BER_CTX)); 132 if (ctx == NULL) return(0); 133 134 memset((char *)ctx,0,sizeof(BIO_BER_CTX)); 135 136 bi->init=0; 137 bi->ptr=(char *)ctx; 138 bi->flags=0; 139 return(1); 140 } 141 142 static int ber_free(BIO *a) 143 { 144 BIO_BER_CTX *b; 145 146 if (a == NULL) return(0); 147 b=(BIO_BER_CTX *)a->ptr; 148 OPENSSL_cleanse(a->ptr,sizeof(BIO_BER_CTX)); 149 OPENSSL_free(a->ptr); 150 a->ptr=NULL; 151 a->init=0; 152 a->flags=0; 153 return(1); 154 } 155 156 int bio_ber_get_header(BIO *bio, BIO_BER_CTX *ctx) 157 { 158 char buf[64]; 159 int i,j,n; 160 int ret; 161 unsigned char *p; 162 unsigned long length 163 int tag; 164 int class; 165 long max; 166 167 BIO_clear_retry_flags(b); 168 169 /* Pack the buffer down if there is a hole at the front */ 170 if (ctx->buf_off != 0) 171 { 172 p=ctx->buf; 173 j=ctx->buf_off; 174 n=ctx->buf_len-j; 175 for (i=0; i<n; i++) 176 { 177 p[0]=p[j]; 178 p++; 179 } 180 ctx->buf_len-j; 181 ctx->buf_off=0; 182 } 183 184 /* If there is more room, read some more data */ 185 i=BER_BUF_SIZE-ctx->buf_len; 186 if (i) 187 { 188 i=BIO_read(bio->next_bio,&(ctx->buf[ctx->buf_len]),i); 189 if (i <= 0) 190 { 191 BIO_copy_next_retry(b); 192 return(i); 193 } 194 else 195 ctx->buf_len+=i; 196 } 197 198 max=ctx->buf_len; 199 p=ctx->buf; 200 ret=ASN1_get_object(&p,&length,&tag,&class,max); 201 202 if (ret & 0x80) 203 { 204 if ((ctx->buf_len < BER_BUF_SIZE) && 205 (ERR_GET_REASON(ERR_peek_error()) == ASN1_R_TOO_LONG)) 206 { 207 ERR_clear_error(); /* clear the error */ 208 BIO_set_retry_read(b); 209 } 210 return(-1); 211 } 212 213 /* We have no error, we have a header, so make use of it */ 214 215 if ((ctx->tag >= 0) && (ctx->tag != tag)) 216 { 217 BIOerr(BIO_F_BIO_BER_GET_HEADER,BIO_R_TAG_MISMATCH); 218 sprintf(buf,"tag=%d, got %d",ctx->tag,tag); 219 ERR_add_error_data(1,buf); 220 return(-1); 221 } 222 if (ret & 0x01) 223 if (ret & V_ASN1_CONSTRUCTED) 224 } 225 226 static int ber_read(BIO *b, char *out, int outl) 227 { 228 int ret=0,i,n; 229 BIO_BER_CTX *ctx; 230 231 BIO_clear_retry_flags(b); 232 233 if (out == NULL) return(0); 234 ctx=(BIO_BER_CTX *)b->ptr; 235 236 if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 237 238 if (ctx->finished) return(0); 239 240 again: 241 /* First see if we are half way through reading a block */ 242 if (ctx->num_left > 0) 243 { 244 if (ctx->num_left < outl) 245 n=ctx->num_left; 246 else 247 n=outl; 248 i=BIO_read(b->next_bio,out,n); 249 if (i <= 0) 250 { 251 BIO_copy_next_retry(b); 252 return(i); 253 } 254 ctx->num_left-=i; 255 outl-=i; 256 ret+=i; 257 if (ctx->num_left <= 0) 258 { 259 ctx->depth--; 260 if (ctx->depth <= 0) 261 ctx->finished=1; 262 } 263 if (outl <= 0) 264 return(ret); 265 else 266 goto again; 267 } 268 else /* we need to read another BER header */ 269 { 270 } 271 } 272 273 static int ber_write(BIO *b, char *in, int inl) 274 { 275 int ret=0,n,i; 276 BIO_ENC_CTX *ctx; 277 278 ctx=(BIO_ENC_CTX *)b->ptr; 279 ret=inl; 280 281 BIO_clear_retry_flags(b); 282 n=ctx->buf_len-ctx->buf_off; 283 while (n > 0) 284 { 285 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); 286 if (i <= 0) 287 { 288 BIO_copy_next_retry(b); 289 return(i); 290 } 291 ctx->buf_off+=i; 292 n-=i; 293 } 294 /* at this point all pending data has been written */ 295 296 if ((in == NULL) || (inl <= 0)) return(0); 297 298 ctx->buf_off=0; 299 while (inl > 0) 300 { 301 n=(inl > ENC_BLOCK_SIZE)?ENC_BLOCK_SIZE:inl; 302 EVP_CipherUpdate(&(ctx->cipher), 303 (unsigned char *)ctx->buf,&ctx->buf_len, 304 (unsigned char *)in,n); 305 inl-=n; 306 in+=n; 307 308 ctx->buf_off=0; 309 n=ctx->buf_len; 310 while (n > 0) 311 { 312 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); 313 if (i <= 0) 314 { 315 BIO_copy_next_retry(b); 316 return(i); 317 } 318 n-=i; 319 ctx->buf_off+=i; 320 } 321 ctx->buf_len=0; 322 ctx->buf_off=0; 323 } 324 BIO_copy_next_retry(b); 325 return(ret); 326 } 327 328 static long ber_ctrl(BIO *b, int cmd, long num, char *ptr) 329 { 330 BIO *dbio; 331 BIO_ENC_CTX *ctx,*dctx; 332 long ret=1; 333 int i; 334 335 ctx=(BIO_ENC_CTX *)b->ptr; 336 337 switch (cmd) 338 { 339 case BIO_CTRL_RESET: 340 ctx->ok=1; 341 ctx->finished=0; 342 EVP_CipherInit_ex(&(ctx->cipher),NULL,NULL,NULL,NULL, 343 ctx->cipher.berrypt); 344 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 345 break; 346 case BIO_CTRL_EOF: /* More to read */ 347 if (ctx->cont <= 0) 348 ret=1; 349 else 350 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 351 break; 352 case BIO_CTRL_WPENDING: 353 ret=ctx->buf_len-ctx->buf_off; 354 if (ret <= 0) 355 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 356 break; 357 case BIO_CTRL_PENDING: /* More to read in buffer */ 358 ret=ctx->buf_len-ctx->buf_off; 359 if (ret <= 0) 360 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 361 break; 362 case BIO_CTRL_FLUSH: 363 /* do a final write */ 364 again: 365 while (ctx->buf_len != ctx->buf_off) 366 { 367 i=ber_write(b,NULL,0); 368 if (i < 0) 369 { 370 ret=i; 371 break; 372 } 373 } 374 375 if (!ctx->finished) 376 { 377 ctx->finished=1; 378 ctx->buf_off=0; 379 ret=EVP_CipherFinal_ex(&(ctx->cipher), 380 (unsigned char *)ctx->buf, 381 &(ctx->buf_len)); 382 ctx->ok=(int)ret; 383 if (ret <= 0) break; 384 385 /* push out the bytes */ 386 goto again; 387 } 388 389 /* Finally flush the underlying BIO */ 390 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 391 break; 392 case BIO_C_GET_CIPHER_STATUS: 393 ret=(long)ctx->ok; 394 break; 395 case BIO_C_DO_STATE_MACHINE: 396 BIO_clear_retry_flags(b); 397 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 398 BIO_copy_next_retry(b); 399 break; 400 401 case BIO_CTRL_DUP: 402 dbio=(BIO *)ptr; 403 dctx=(BIO_ENC_CTX *)dbio->ptr; 404 memcpy(&(dctx->cipher),&(ctx->cipher),sizeof(ctx->cipher)); 405 dbio->init=1; 406 break; 407 default: 408 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 409 break; 410 } 411 return(ret); 412 } 413 414 static long ber_callback_ctrl(BIO *b, int cmd, void *(*fp)()) 415 { 416 long ret=1; 417 418 if (b->next_bio == NULL) return(0); 419 switch (cmd) 420 { 421 default: 422 ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 423 break; 424 } 425 return(ret); 426 } 427 428 /* 429 void BIO_set_cipher_ctx(b,c) 430 BIO *b; 431 EVP_CIPHER_ctx *c; 432 { 433 if (b == NULL) return; 434 435 if ((b->callback != NULL) && 436 (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0)) 437 return; 438 439 b->init=1; 440 ctx=(BIO_ENC_CTX *)b->ptr; 441 memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX)); 442 443 if (b->callback != NULL) 444 b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L); 445 } 446 */ 447 448 void BIO_set_cipher(BIO *b, EVP_CIPHER *c, unsigned char *k, unsigned char *i, 449 int e) 450 { 451 BIO_ENC_CTX *ctx; 452 453 if (b == NULL) return; 454 455 if ((b->callback != NULL) && 456 (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0)) 457 return; 458 459 b->init=1; 460 ctx=(BIO_ENC_CTX *)b->ptr; 461 EVP_CipherInit_ex(&(ctx->cipher),c,NULL,k,i,e); 462 463 if (b->callback != NULL) 464 b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L); 465 } 466 467