1 /* crypto/evp/bio_b64.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@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@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@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@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 b64_write(BIO *h, const char *buf, int num); 66 static int b64_read(BIO *h, char *buf, int size); 67 /*static int b64_puts(BIO *h, const char *str); */ 68 /*static int b64_gets(BIO *h, char *str, int size); */ 69 static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2); 70 static int b64_new(BIO *h); 71 static int b64_free(BIO *data); 72 static long b64_callback_ctrl(BIO *h,int cmd,bio_info_cb *fp); 73 #define B64_BLOCK_SIZE 1024 74 #define B64_BLOCK_SIZE2 768 75 #define B64_NONE 0 76 #define B64_ENCODE 1 77 #define B64_DECODE 2 78 79 typedef struct b64_struct 80 { 81 /*BIO *bio; moved to the BIO structure */ 82 int buf_len; 83 int buf_off; 84 int tmp_len; /* used to find the start when decoding */ 85 int tmp_nl; /* If true, scan until '\n' */ 86 int encode; 87 int start; /* have we started decoding yet? */ 88 int cont; /* <= 0 when finished */ 89 EVP_ENCODE_CTX base64; 90 char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE)+10]; 91 char tmp[B64_BLOCK_SIZE]; 92 } BIO_B64_CTX; 93 94 static BIO_METHOD methods_b64= 95 { 96 BIO_TYPE_BASE64,"base64 encoding", 97 b64_write, 98 b64_read, 99 NULL, /* b64_puts, */ 100 NULL, /* b64_gets, */ 101 b64_ctrl, 102 b64_new, 103 b64_free, 104 b64_callback_ctrl, 105 }; 106 107 BIO_METHOD *BIO_f_base64(void) 108 { 109 return(&methods_b64); 110 } 111 112 static int b64_new(BIO *bi) 113 { 114 BIO_B64_CTX *ctx; 115 116 ctx=(BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX)); 117 if (ctx == NULL) return(0); 118 119 ctx->buf_len=0; 120 ctx->tmp_len=0; 121 ctx->tmp_nl=0; 122 ctx->buf_off=0; 123 ctx->cont=1; 124 ctx->start=1; 125 ctx->encode=0; 126 127 bi->init=1; 128 bi->ptr=(char *)ctx; 129 bi->flags=0; 130 return(1); 131 } 132 133 static int b64_free(BIO *a) 134 { 135 if (a == NULL) return(0); 136 OPENSSL_free(a->ptr); 137 a->ptr=NULL; 138 a->init=0; 139 a->flags=0; 140 return(1); 141 } 142 143 static int b64_read(BIO *b, char *out, int outl) 144 { 145 int ret=0,i,ii,j,k,x,n,num,ret_code=0; 146 BIO_B64_CTX *ctx; 147 unsigned char *p,*q; 148 149 if (out == NULL) return(0); 150 ctx=(BIO_B64_CTX *)b->ptr; 151 152 if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 153 154 if (ctx->encode != B64_DECODE) 155 { 156 ctx->encode=B64_DECODE; 157 ctx->buf_len=0; 158 ctx->buf_off=0; 159 ctx->tmp_len=0; 160 EVP_DecodeInit(&(ctx->base64)); 161 } 162 163 /* First check if there are bytes decoded/encoded */ 164 if (ctx->buf_len > 0) 165 { 166 i=ctx->buf_len-ctx->buf_off; 167 if (i > outl) i=outl; 168 OPENSSL_assert(ctx->buf_off+i < sizeof ctx->buf); 169 memcpy(out,&(ctx->buf[ctx->buf_off]),i); 170 ret=i; 171 out+=i; 172 outl-=i; 173 ctx->buf_off+=i; 174 if (ctx->buf_len == ctx->buf_off) 175 { 176 ctx->buf_len=0; 177 ctx->buf_off=0; 178 } 179 } 180 181 /* At this point, we have room of outl bytes and an empty 182 * buffer, so we should read in some more. */ 183 184 ret_code=0; 185 while (outl > 0) 186 { 187 if (ctx->cont <= 0) break; 188 189 i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]), 190 B64_BLOCK_SIZE-ctx->tmp_len); 191 192 if (i <= 0) 193 { 194 ret_code=i; 195 196 /* Should be continue next time we are called? */ 197 if (!BIO_should_retry(b->next_bio)) 198 ctx->cont=i; 199 /* else we should continue when called again */ 200 break; 201 } 202 i+=ctx->tmp_len; 203 204 /* We need to scan, a line at a time until we 205 * have a valid line if we are starting. */ 206 if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) 207 { 208 /* ctx->start=1; */ 209 ctx->tmp_len=0; 210 } 211 else if (ctx->start) 212 { 213 q=p=(unsigned char *)ctx->tmp; 214 for (j=0; j<i; j++) 215 { 216 if (*(q++) != '\n') continue; 217 218 /* due to a previous very long line, 219 * we need to keep on scanning for a '\n' 220 * before we even start looking for 221 * base64 encoded stuff. */ 222 if (ctx->tmp_nl) 223 { 224 p=q; 225 ctx->tmp_nl=0; 226 continue; 227 } 228 229 k=EVP_DecodeUpdate(&(ctx->base64), 230 (unsigned char *)ctx->buf, 231 &num,p,q-p); 232 if ((k <= 0) && (num == 0) && (ctx->start)) 233 EVP_DecodeInit(&ctx->base64); 234 else 235 { 236 if (p != (unsigned char *) 237 &(ctx->tmp[0])) 238 { 239 i-=(p- (unsigned char *) 240 &(ctx->tmp[0])); 241 for (x=0; x < i; x++) 242 ctx->tmp[x]=p[x]; 243 } 244 EVP_DecodeInit(&ctx->base64); 245 ctx->start=0; 246 break; 247 } 248 p=q; 249 } 250 251 /* we fell off the end without starting */ 252 if (j == i) 253 { 254 /* Is this is one long chunk?, if so, keep on 255 * reading until a new line. */ 256 if (p == (unsigned char *)&(ctx->tmp[0])) 257 { 258 ctx->tmp_nl=1; 259 ctx->tmp_len=0; 260 } 261 else if (p != q) /* finished on a '\n' */ 262 { 263 n=q-p; 264 for (ii=0; ii<n; ii++) 265 ctx->tmp[ii]=p[ii]; 266 ctx->tmp_len=n; 267 } 268 /* else finished on a '\n' */ 269 continue; 270 } 271 else 272 ctx->tmp_len=0; 273 } 274 275 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) 276 { 277 int z,jj; 278 279 jj=(i>>2)<<2; 280 z=EVP_DecodeBlock((unsigned char *)ctx->buf, 281 (unsigned char *)ctx->tmp,jj); 282 if (jj > 2) 283 { 284 if (ctx->tmp[jj-1] == '=') 285 { 286 z--; 287 if (ctx->tmp[jj-2] == '=') 288 z--; 289 } 290 } 291 /* z is now number of output bytes and jj is the 292 * number consumed */ 293 if (jj != i) 294 { 295 memcpy((unsigned char *)ctx->tmp, 296 (unsigned char *)&(ctx->tmp[jj]),i-jj); 297 ctx->tmp_len=i-jj; 298 } 299 ctx->buf_len=0; 300 if (z > 0) 301 { 302 ctx->buf_len=z; 303 i=1; 304 } 305 else 306 i=z; 307 } 308 else 309 { 310 i=EVP_DecodeUpdate(&(ctx->base64), 311 (unsigned char *)ctx->buf,&ctx->buf_len, 312 (unsigned char *)ctx->tmp,i); 313 } 314 ctx->cont=i; 315 ctx->buf_off=0; 316 if (i < 0) 317 { 318 ret_code=0; 319 ctx->buf_len=0; 320 break; 321 } 322 323 if (ctx->buf_len <= outl) 324 i=ctx->buf_len; 325 else 326 i=outl; 327 328 memcpy(out,ctx->buf,i); 329 ret+=i; 330 ctx->buf_off=i; 331 if (ctx->buf_off == ctx->buf_len) 332 { 333 ctx->buf_len=0; 334 ctx->buf_off=0; 335 } 336 outl-=i; 337 out+=i; 338 } 339 BIO_clear_retry_flags(b); 340 BIO_copy_next_retry(b); 341 return((ret == 0)?ret_code:ret); 342 } 343 344 static int b64_write(BIO *b, const char *in, int inl) 345 { 346 int ret=inl,n,i; 347 BIO_B64_CTX *ctx; 348 349 ctx=(BIO_B64_CTX *)b->ptr; 350 BIO_clear_retry_flags(b); 351 352 if (ctx->encode != B64_ENCODE) 353 { 354 ctx->encode=B64_ENCODE; 355 ctx->buf_len=0; 356 ctx->buf_off=0; 357 ctx->tmp_len=0; 358 EVP_EncodeInit(&(ctx->base64)); 359 } 360 361 n=ctx->buf_len-ctx->buf_off; 362 while (n > 0) 363 { 364 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); 365 if (i <= 0) 366 { 367 BIO_copy_next_retry(b); 368 return(i); 369 } 370 ctx->buf_off+=i; 371 n-=i; 372 } 373 /* at this point all pending data has been written */ 374 ctx->buf_off=0; 375 ctx->buf_len=0; 376 377 if ((in == NULL) || (inl <= 0)) return(0); 378 379 while (inl > 0) 380 { 381 n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl; 382 383 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) 384 { 385 if (ctx->tmp_len > 0) 386 { 387 n=3-ctx->tmp_len; 388 /* There's a teoretical possibility for this */ 389 if (n > inl) 390 n=inl; 391 memcpy(&(ctx->tmp[ctx->tmp_len]),in,n); 392 ctx->tmp_len+=n; 393 if (ctx->tmp_len < 3) 394 break; 395 ctx->buf_len=EVP_EncodeBlock( 396 (unsigned char *)ctx->buf, 397 (unsigned char *)ctx->tmp, 398 ctx->tmp_len); 399 /* Since we're now done using the temporary 400 buffer, the length should be 0'd */ 401 ctx->tmp_len=0; 402 } 403 else 404 { 405 if (n < 3) 406 { 407 memcpy(&(ctx->tmp[0]),in,n); 408 ctx->tmp_len=n; 409 break; 410 } 411 n-=n%3; 412 ctx->buf_len=EVP_EncodeBlock( 413 (unsigned char *)ctx->buf, 414 (unsigned char *)in,n); 415 } 416 } 417 else 418 { 419 EVP_EncodeUpdate(&(ctx->base64), 420 (unsigned char *)ctx->buf,&ctx->buf_len, 421 (unsigned char *)in,n); 422 } 423 inl-=n; 424 in+=n; 425 426 ctx->buf_off=0; 427 n=ctx->buf_len; 428 while (n > 0) 429 { 430 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); 431 if (i <= 0) 432 { 433 BIO_copy_next_retry(b); 434 return((ret == 0)?i:ret); 435 } 436 n-=i; 437 ctx->buf_off+=i; 438 } 439 ctx->buf_len=0; 440 ctx->buf_off=0; 441 } 442 return(ret); 443 } 444 445 static long b64_ctrl(BIO *b, int cmd, long num, void *ptr) 446 { 447 BIO_B64_CTX *ctx; 448 long ret=1; 449 int i; 450 451 ctx=(BIO_B64_CTX *)b->ptr; 452 453 switch (cmd) 454 { 455 case BIO_CTRL_RESET: 456 ctx->cont=1; 457 ctx->start=1; 458 ctx->encode=B64_NONE; 459 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 460 break; 461 case BIO_CTRL_EOF: /* More to read */ 462 if (ctx->cont <= 0) 463 ret=1; 464 else 465 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 466 break; 467 case BIO_CTRL_WPENDING: /* More to write in buffer */ 468 ret=ctx->buf_len-ctx->buf_off; 469 if ((ret == 0) && (ctx->encode != B64_NONE) 470 && (ctx->base64.num != 0)) 471 ret=1; 472 else if (ret <= 0) 473 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 474 break; 475 case BIO_CTRL_PENDING: /* More to read in buffer */ 476 ret=ctx->buf_len-ctx->buf_off; 477 if (ret <= 0) 478 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 479 break; 480 case BIO_CTRL_FLUSH: 481 /* do a final write */ 482 again: 483 while (ctx->buf_len != ctx->buf_off) 484 { 485 i=b64_write(b,NULL,0); 486 if (i < 0) 487 { 488 ret=i; 489 break; 490 } 491 } 492 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) 493 { 494 if (ctx->tmp_len != 0) 495 { 496 ctx->buf_len=EVP_EncodeBlock( 497 (unsigned char *)ctx->buf, 498 (unsigned char *)ctx->tmp, 499 ctx->tmp_len); 500 ctx->buf_off=0; 501 ctx->tmp_len=0; 502 goto again; 503 } 504 } 505 else if (ctx->encode != B64_NONE && ctx->base64.num != 0) 506 { 507 ctx->buf_off=0; 508 EVP_EncodeFinal(&(ctx->base64), 509 (unsigned char *)ctx->buf, 510 &(ctx->buf_len)); 511 /* push out the bytes */ 512 goto again; 513 } 514 /* Finally flush the underlying BIO */ 515 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 516 break; 517 518 case BIO_C_DO_STATE_MACHINE: 519 BIO_clear_retry_flags(b); 520 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 521 BIO_copy_next_retry(b); 522 break; 523 524 case BIO_CTRL_DUP: 525 break; 526 case BIO_CTRL_INFO: 527 case BIO_CTRL_GET: 528 case BIO_CTRL_SET: 529 default: 530 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 531 break; 532 } 533 return(ret); 534 } 535 536 static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 537 { 538 long ret=1; 539 540 if (b->next_bio == NULL) return(0); 541 switch (cmd) 542 { 543 default: 544 ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 545 break; 546 } 547 return(ret); 548 } 549 550