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