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