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