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 ctx->buf_off = 0; 334 if (i < 0) { 335 ret_code = 0; 336 ctx->buf_len = 0; 337 break; 338 } 339 340 if (ctx->buf_len <= outl) 341 i = ctx->buf_len; 342 else 343 i = outl; 344 345 memcpy(out, ctx->buf, i); 346 ret += i; 347 ctx->buf_off = i; 348 if (ctx->buf_off == ctx->buf_len) { 349 ctx->buf_len = 0; 350 ctx->buf_off = 0; 351 } 352 outl -= i; 353 out += i; 354 } 355 /* BIO_clear_retry_flags(b); */ 356 BIO_copy_next_retry(b); 357 return ((ret == 0) ? ret_code : ret); 358} 359 360static int b64_write(BIO *b, const char *in, int inl) 361{ 362 int ret = 0; 363 int n; 364 int i; 365 BIO_B64_CTX *ctx; 366 367 ctx = (BIO_B64_CTX *)b->ptr; 368 BIO_clear_retry_flags(b); 369 370 if (ctx->encode != B64_ENCODE) { 371 ctx->encode = B64_ENCODE; 372 ctx->buf_len = 0; 373 ctx->buf_off = 0; 374 ctx->tmp_len = 0; 375 EVP_EncodeInit(&(ctx->base64)); 376 } 377 378 OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf)); 379 OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 380 OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 381 n = ctx->buf_len - ctx->buf_off; 382 while (n > 0) { 383 i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 384 if (i <= 0) { 385 BIO_copy_next_retry(b); 386 return (i); 387 } 388 OPENSSL_assert(i <= n); 389 ctx->buf_off += i; 390 OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); 391 OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 392 n -= i; 393 } 394 /* at this point all pending data has been written */ 395 ctx->buf_off = 0; 396 ctx->buf_len = 0; 397 398 if ((in == NULL) || (inl <= 0)) 399 return (0); 400 401 while (inl > 0) { 402 n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl; 403 404 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 405 if (ctx->tmp_len > 0) { 406 OPENSSL_assert(ctx->tmp_len <= 3); 407 n = 3 - ctx->tmp_len; 408 /* 409 * There's a theoretical possibility for this 410 */ 411 if (n > inl) 412 n = inl; 413 memcpy(&(ctx->tmp[ctx->tmp_len]), in, n); 414 ctx->tmp_len += n; 415 ret += n; 416 if (ctx->tmp_len < 3) 417 break; 418 ctx->buf_len = 419 EVP_EncodeBlock((unsigned char *)ctx->buf, 420 (unsigned char *)ctx->tmp, ctx->tmp_len); 421 OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 422 OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 423 /* 424 * Since we're now done using the temporary buffer, the 425 * length should be 0'd 426 */ 427 ctx->tmp_len = 0; 428 } else { 429 if (n < 3) { 430 memcpy(ctx->tmp, in, n); 431 ctx->tmp_len = n; 432 ret += n; 433 break; 434 } 435 n -= n % 3; 436 ctx->buf_len = 437 EVP_EncodeBlock((unsigned char *)ctx->buf, 438 (const unsigned char *)in, n); 439 OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 440 OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 441 ret += n; 442 } 443 } else { 444 EVP_EncodeUpdate(&(ctx->base64), 445 (unsigned char *)ctx->buf, &ctx->buf_len, 446 (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 inl -= n; 452 in += n; 453 454 ctx->buf_off = 0; 455 n = ctx->buf_len; 456 while (n > 0) { 457 i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 458 if (i <= 0) { 459 BIO_copy_next_retry(b); 460 return ((ret == 0) ? i : ret); 461 } 462 OPENSSL_assert(i <= n); 463 n -= i; 464 ctx->buf_off += i; 465 OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); 466 OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 467 } 468 ctx->buf_len = 0; 469 ctx->buf_off = 0; 470 } 471 return (ret); 472} 473 474static long b64_ctrl(BIO *b, int cmd, long num, void *ptr) 475{ 476 BIO_B64_CTX *ctx; 477 long ret = 1; 478 int i; 479 480 ctx = (BIO_B64_CTX *)b->ptr; 481 482 switch (cmd) { 483 case BIO_CTRL_RESET: 484 ctx->cont = 1; 485 ctx->start = 1; 486 ctx->encode = B64_NONE; 487 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 488 break; 489 case BIO_CTRL_EOF: /* More to read */ 490 if (ctx->cont <= 0) 491 ret = 1; 492 else 493 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 494 break; 495 case BIO_CTRL_WPENDING: /* More to write in buffer */ 496 OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 497 ret = ctx->buf_len - ctx->buf_off; 498 if ((ret == 0) && (ctx->encode != B64_NONE) 499 && (ctx->base64.num != 0)) 500 ret = 1; 501 else if (ret <= 0) 502 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 503 break; 504 case BIO_CTRL_PENDING: /* More to read in buffer */ 505 OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 506 ret = ctx->buf_len - ctx->buf_off; 507 if (ret <= 0) 508 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 509 break; 510 case BIO_CTRL_FLUSH: 511 /* do a final write */ 512 again: 513 while (ctx->buf_len != ctx->buf_off) { 514 i = b64_write(b, NULL, 0); 515 if (i < 0) 516 return i; 517 } 518 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 519 if (ctx->tmp_len != 0) { 520 ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf, 521 (unsigned char *)ctx->tmp, 522 ctx->tmp_len); 523 ctx->buf_off = 0; 524 ctx->tmp_len = 0; 525 goto again; 526 } 527 } else if (ctx->encode != B64_NONE && ctx->base64.num != 0) { 528 ctx->buf_off = 0; 529 EVP_EncodeFinal(&(ctx->base64), 530 (unsigned char *)ctx->buf, &(ctx->buf_len)); 531 /* push out the bytes */ 532 goto again; 533 } 534 /* Finally flush the underlying BIO */ 535 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 536 break; 537 538 case BIO_C_DO_STATE_MACHINE: 539 BIO_clear_retry_flags(b); 540 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 541 BIO_copy_next_retry(b); 542 break; 543 544 case BIO_CTRL_DUP: 545 break; 546 case BIO_CTRL_INFO: 547 case BIO_CTRL_GET: 548 case BIO_CTRL_SET: 549 default: 550 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 551 break; 552 } 553 return (ret); 554} 555 556static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 557{ 558 long ret = 1; 559 560 if (b->next_bio == NULL) 561 return (0); 562 switch (cmd) { 563 default: 564 ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 565 break; 566 } 567 return (ret); 568} 569 570static int b64_puts(BIO *b, const char *str) 571{ 572 return b64_write(b, str, strlen(str)); 573} 574