155714Skris/* crypto/evp/bio_b64.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8280304Sjkim * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15280304Sjkim * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22280304Sjkim * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40280304Sjkim * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52280304Sjkim * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include <errno.h> 6155714Skris#include "cryptlib.h" 6255714Skris#include <openssl/buffer.h> 6355714Skris#include <openssl/evp.h> 6455714Skris 6568651Skrisstatic int b64_write(BIO *h, const char *buf, int num); 6668651Skrisstatic int b64_read(BIO *h, char *buf, int size); 67215697Ssimonstatic int b64_puts(BIO *h, const char *str); 68280304Sjkim/* 69280304Sjkim * static int b64_gets(BIO *h, char *str, int size); 70280304Sjkim */ 7168651Skrisstatic long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2); 7255714Skrisstatic int b64_new(BIO *h); 7355714Skrisstatic int b64_free(BIO *data); 74280304Sjkimstatic long b64_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 75280304Sjkim#define B64_BLOCK_SIZE 1024 76280304Sjkim#define B64_BLOCK_SIZE2 768 77280304Sjkim#define B64_NONE 0 78280304Sjkim#define B64_ENCODE 1 79280304Sjkim#define B64_DECODE 2 8055714Skris 81280304Sjkimtypedef struct b64_struct { 82280304Sjkim /* 83280304Sjkim * BIO *bio; moved to the BIO structure 84280304Sjkim */ 85280304Sjkim int buf_len; 86280304Sjkim int buf_off; 87280304Sjkim int tmp_len; /* used to find the start when decoding */ 88280304Sjkim int tmp_nl; /* If true, scan until '\n' */ 89280304Sjkim int encode; 90280304Sjkim int start; /* have we started decoding yet? */ 91280304Sjkim int cont; /* <= 0 when finished */ 92280304Sjkim EVP_ENCODE_CTX base64; 93280304Sjkim char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10]; 94280304Sjkim char tmp[B64_BLOCK_SIZE]; 95280304Sjkim} BIO_B64_CTX; 9655714Skris 97280304Sjkimstatic BIO_METHOD methods_b64 = { 98280304Sjkim BIO_TYPE_BASE64, "base64 encoding", 99280304Sjkim b64_write, 100280304Sjkim b64_read, 101280304Sjkim b64_puts, 102280304Sjkim NULL, /* b64_gets, */ 103280304Sjkim b64_ctrl, 104280304Sjkim b64_new, 105280304Sjkim b64_free, 106280304Sjkim b64_callback_ctrl, 107280304Sjkim}; 10855714Skris 10955714SkrisBIO_METHOD *BIO_f_base64(void) 110280304Sjkim{ 111280304Sjkim return (&methods_b64); 112280304Sjkim} 11355714Skris 11455714Skrisstatic int b64_new(BIO *bi) 115280304Sjkim{ 116280304Sjkim BIO_B64_CTX *ctx; 11755714Skris 118280304Sjkim ctx = (BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX)); 119280304Sjkim if (ctx == NULL) 120280304Sjkim return (0); 12155714Skris 122280304Sjkim ctx->buf_len = 0; 123280304Sjkim ctx->tmp_len = 0; 124280304Sjkim ctx->tmp_nl = 0; 125280304Sjkim ctx->buf_off = 0; 126280304Sjkim ctx->cont = 1; 127280304Sjkim ctx->start = 1; 128280304Sjkim ctx->encode = 0; 12955714Skris 130280304Sjkim bi->init = 1; 131280304Sjkim bi->ptr = (char *)ctx; 132280304Sjkim bi->flags = 0; 133280304Sjkim bi->num = 0; 134280304Sjkim return (1); 135280304Sjkim} 13655714Skris 13755714Skrisstatic int b64_free(BIO *a) 138280304Sjkim{ 139280304Sjkim if (a == NULL) 140280304Sjkim return (0); 141280304Sjkim OPENSSL_free(a->ptr); 142280304Sjkim a->ptr = NULL; 143280304Sjkim a->init = 0; 144280304Sjkim a->flags = 0; 145280304Sjkim return (1); 146280304Sjkim} 147280304Sjkim 14855714Skrisstatic int b64_read(BIO *b, char *out, int outl) 149280304Sjkim{ 150280304Sjkim int ret = 0, i, ii, j, k, x, n, num, ret_code = 0; 151280304Sjkim BIO_B64_CTX *ctx; 152280304Sjkim unsigned char *p, *q; 15355714Skris 154280304Sjkim if (out == NULL) 155280304Sjkim return (0); 156280304Sjkim ctx = (BIO_B64_CTX *)b->ptr; 15755714Skris 158280304Sjkim if ((ctx == NULL) || (b->next_bio == NULL)) 159280304Sjkim return (0); 16055714Skris 161280304Sjkim BIO_clear_retry_flags(b); 162215697Ssimon 163280304Sjkim if (ctx->encode != B64_DECODE) { 164280304Sjkim ctx->encode = B64_DECODE; 165280304Sjkim ctx->buf_len = 0; 166280304Sjkim ctx->buf_off = 0; 167280304Sjkim ctx->tmp_len = 0; 168280304Sjkim EVP_DecodeInit(&(ctx->base64)); 169280304Sjkim } 17055714Skris 171280304Sjkim /* First check if there are bytes decoded/encoded */ 172280304Sjkim if (ctx->buf_len > 0) { 173280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 174280304Sjkim i = ctx->buf_len - ctx->buf_off; 175280304Sjkim if (i > outl) 176280304Sjkim i = outl; 177280304Sjkim OPENSSL_assert(ctx->buf_off + i < (int)sizeof(ctx->buf)); 178280304Sjkim memcpy(out, &(ctx->buf[ctx->buf_off]), i); 179280304Sjkim ret = i; 180280304Sjkim out += i; 181280304Sjkim outl -= i; 182280304Sjkim ctx->buf_off += i; 183280304Sjkim if (ctx->buf_len == ctx->buf_off) { 184280304Sjkim ctx->buf_len = 0; 185280304Sjkim ctx->buf_off = 0; 186280304Sjkim } 187280304Sjkim } 18855714Skris 189280304Sjkim /* 190280304Sjkim * At this point, we have room of outl bytes and an empty buffer, so we 191280304Sjkim * should read in some more. 192280304Sjkim */ 19355714Skris 194280304Sjkim ret_code = 0; 195280304Sjkim while (outl > 0) { 196280304Sjkim if (ctx->cont <= 0) 197280304Sjkim break; 198120631Snectar 199280304Sjkim i = BIO_read(b->next_bio, &(ctx->tmp[ctx->tmp_len]), 200280304Sjkim B64_BLOCK_SIZE - ctx->tmp_len); 20155714Skris 202280304Sjkim if (i <= 0) { 203280304Sjkim ret_code = i; 20455714Skris 205280304Sjkim /* Should we continue next time we are called? */ 206280304Sjkim if (!BIO_should_retry(b->next_bio)) { 207280304Sjkim ctx->cont = i; 208280304Sjkim /* If buffer empty break */ 209280304Sjkim if (ctx->tmp_len == 0) 210280304Sjkim break; 211280304Sjkim /* Fall through and process what we have */ 212280304Sjkim else 213280304Sjkim i = 0; 214280304Sjkim } 215280304Sjkim /* else we retry and add more data to buffer */ 216280304Sjkim else 217280304Sjkim break; 218280304Sjkim } 219280304Sjkim i += ctx->tmp_len; 220280304Sjkim ctx->tmp_len = i; 22155714Skris 222280304Sjkim /* 223280304Sjkim * We need to scan, a line at a time until we have a valid line if we 224280304Sjkim * are starting. 225280304Sjkim */ 226280304Sjkim if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) { 227280304Sjkim /* ctx->start=1; */ 228280304Sjkim ctx->tmp_len = 0; 229280304Sjkim } else if (ctx->start) { 230280304Sjkim q = p = (unsigned char *)ctx->tmp; 231280304Sjkim num = 0; 232280304Sjkim for (j = 0; j < i; j++) { 233280304Sjkim if (*(q++) != '\n') 234280304Sjkim continue; 23555714Skris 236280304Sjkim /* 237280304Sjkim * due to a previous very long line, we need to keep on 238280304Sjkim * scanning for a '\n' before we even start looking for 239280304Sjkim * base64 encoded stuff. 240280304Sjkim */ 241280304Sjkim if (ctx->tmp_nl) { 242280304Sjkim p = q; 243280304Sjkim ctx->tmp_nl = 0; 244280304Sjkim continue; 245280304Sjkim } 24655714Skris 247280304Sjkim k = EVP_DecodeUpdate(&(ctx->base64), 248280304Sjkim (unsigned char *)ctx->buf, 249280304Sjkim &num, p, q - p); 250280304Sjkim if ((k <= 0) && (num == 0) && (ctx->start)) 251280304Sjkim EVP_DecodeInit(&ctx->base64); 252280304Sjkim else { 253280304Sjkim if (p != (unsigned char *) 254280304Sjkim &(ctx->tmp[0])) { 255280304Sjkim i -= (p - (unsigned char *) 256280304Sjkim &(ctx->tmp[0])); 257280304Sjkim for (x = 0; x < i; x++) 258280304Sjkim ctx->tmp[x] = p[x]; 259280304Sjkim } 260280304Sjkim EVP_DecodeInit(&ctx->base64); 261280304Sjkim ctx->start = 0; 262280304Sjkim break; 263280304Sjkim } 264280304Sjkim p = q; 265280304Sjkim } 26655714Skris 267280304Sjkim /* we fell off the end without starting */ 268280304Sjkim if ((j == i) && (num == 0)) { 269280304Sjkim /* 270280304Sjkim * Is this is one long chunk?, if so, keep on reading until a 271280304Sjkim * new line. 272280304Sjkim */ 273280304Sjkim if (p == (unsigned char *)&(ctx->tmp[0])) { 274280304Sjkim /* Check buffer full */ 275280304Sjkim if (i == B64_BLOCK_SIZE) { 276280304Sjkim ctx->tmp_nl = 1; 277280304Sjkim ctx->tmp_len = 0; 278280304Sjkim } 279280304Sjkim } else if (p != q) { /* finished on a '\n' */ 280280304Sjkim n = q - p; 281280304Sjkim for (ii = 0; ii < n; ii++) 282280304Sjkim ctx->tmp[ii] = p[ii]; 283280304Sjkim ctx->tmp_len = n; 284280304Sjkim } 285280304Sjkim /* else finished on a '\n' */ 286280304Sjkim continue; 287280304Sjkim } else { 288280304Sjkim ctx->tmp_len = 0; 289280304Sjkim } 290280304Sjkim } else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) { 291280304Sjkim /* 292280304Sjkim * If buffer isn't full and we can retry then restart to read in 293280304Sjkim * more data. 294280304Sjkim */ 295280304Sjkim continue; 296280304Sjkim } 29755714Skris 298280304Sjkim if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 299280304Sjkim int z, jj; 30055714Skris 301215697Ssimon#if 0 302280304Sjkim jj = (i >> 2) << 2; 303215697Ssimon#else 304280304Sjkim jj = i & ~3; /* process per 4 */ 305215697Ssimon#endif 306280304Sjkim z = EVP_DecodeBlock((unsigned char *)ctx->buf, 307280304Sjkim (unsigned char *)ctx->tmp, jj); 308280304Sjkim if (jj > 2) { 309280304Sjkim if (ctx->tmp[jj - 1] == '=') { 310280304Sjkim z--; 311280304Sjkim if (ctx->tmp[jj - 2] == '=') 312280304Sjkim z--; 313280304Sjkim } 314280304Sjkim } 315280304Sjkim /* 316280304Sjkim * z is now number of output bytes and jj is the number consumed 317280304Sjkim */ 318280304Sjkim if (jj != i) { 319280304Sjkim memmove(ctx->tmp, &ctx->tmp[jj], i - jj); 320280304Sjkim ctx->tmp_len = i - jj; 321280304Sjkim } 322280304Sjkim ctx->buf_len = 0; 323280304Sjkim if (z > 0) { 324280304Sjkim ctx->buf_len = z; 325280304Sjkim } 326280304Sjkim i = z; 327280304Sjkim } else { 328280304Sjkim i = EVP_DecodeUpdate(&(ctx->base64), 329280304Sjkim (unsigned char *)ctx->buf, &ctx->buf_len, 330280304Sjkim (unsigned char *)ctx->tmp, i); 331280304Sjkim ctx->tmp_len = 0; 332280304Sjkim } 333280304Sjkim ctx->buf_off = 0; 334280304Sjkim if (i < 0) { 335280304Sjkim ret_code = 0; 336280304Sjkim ctx->buf_len = 0; 337280304Sjkim break; 338280304Sjkim } 33955714Skris 340280304Sjkim if (ctx->buf_len <= outl) 341280304Sjkim i = ctx->buf_len; 342280304Sjkim else 343280304Sjkim i = outl; 34455714Skris 345280304Sjkim memcpy(out, ctx->buf, i); 346280304Sjkim ret += i; 347280304Sjkim ctx->buf_off = i; 348280304Sjkim if (ctx->buf_off == ctx->buf_len) { 349280304Sjkim ctx->buf_len = 0; 350280304Sjkim ctx->buf_off = 0; 351280304Sjkim } 352280304Sjkim outl -= i; 353280304Sjkim out += i; 354280304Sjkim } 355280304Sjkim /* BIO_clear_retry_flags(b); */ 356280304Sjkim BIO_copy_next_retry(b); 357280304Sjkim return ((ret == 0) ? ret_code : ret); 358280304Sjkim} 35955714Skris 36068651Skrisstatic int b64_write(BIO *b, const char *in, int inl) 361280304Sjkim{ 362280304Sjkim int ret = 0; 363280304Sjkim int n; 364280304Sjkim int i; 365280304Sjkim BIO_B64_CTX *ctx; 36655714Skris 367280304Sjkim ctx = (BIO_B64_CTX *)b->ptr; 368280304Sjkim BIO_clear_retry_flags(b); 36955714Skris 370280304Sjkim if (ctx->encode != B64_ENCODE) { 371280304Sjkim ctx->encode = B64_ENCODE; 372280304Sjkim ctx->buf_len = 0; 373280304Sjkim ctx->buf_off = 0; 374280304Sjkim ctx->tmp_len = 0; 375280304Sjkim EVP_EncodeInit(&(ctx->base64)); 376280304Sjkim } 37755714Skris 378280304Sjkim OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf)); 379280304Sjkim OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 380280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 381280304Sjkim n = ctx->buf_len - ctx->buf_off; 382280304Sjkim while (n > 0) { 383280304Sjkim i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 384280304Sjkim if (i <= 0) { 385280304Sjkim BIO_copy_next_retry(b); 386280304Sjkim return (i); 387280304Sjkim } 388280304Sjkim OPENSSL_assert(i <= n); 389280304Sjkim ctx->buf_off += i; 390280304Sjkim OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); 391280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 392280304Sjkim n -= i; 393280304Sjkim } 394280304Sjkim /* at this point all pending data has been written */ 395280304Sjkim ctx->buf_off = 0; 396280304Sjkim ctx->buf_len = 0; 39755714Skris 398280304Sjkim if ((in == NULL) || (inl <= 0)) 399280304Sjkim return (0); 40055714Skris 401280304Sjkim while (inl > 0) { 402280304Sjkim n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl; 40355714Skris 404280304Sjkim if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 405280304Sjkim if (ctx->tmp_len > 0) { 406280304Sjkim OPENSSL_assert(ctx->tmp_len <= 3); 407280304Sjkim n = 3 - ctx->tmp_len; 408280304Sjkim /* 409280304Sjkim * There's a theoretical possibility for this 410280304Sjkim */ 411280304Sjkim if (n > inl) 412280304Sjkim n = inl; 413280304Sjkim memcpy(&(ctx->tmp[ctx->tmp_len]), in, n); 414280304Sjkim ctx->tmp_len += n; 415280304Sjkim ret += n; 416280304Sjkim if (ctx->tmp_len < 3) 417280304Sjkim break; 418280304Sjkim ctx->buf_len = 419280304Sjkim EVP_EncodeBlock((unsigned char *)ctx->buf, 420280304Sjkim (unsigned char *)ctx->tmp, ctx->tmp_len); 421280304Sjkim OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 422280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 423280304Sjkim /* 424280304Sjkim * Since we're now done using the temporary buffer, the 425280304Sjkim * length should be 0'd 426280304Sjkim */ 427280304Sjkim ctx->tmp_len = 0; 428280304Sjkim } else { 429280304Sjkim if (n < 3) { 430280304Sjkim memcpy(ctx->tmp, in, n); 431280304Sjkim ctx->tmp_len = n; 432280304Sjkim ret += n; 433280304Sjkim break; 434280304Sjkim } 435280304Sjkim n -= n % 3; 436280304Sjkim ctx->buf_len = 437280304Sjkim EVP_EncodeBlock((unsigned char *)ctx->buf, 438280304Sjkim (const unsigned char *)in, n); 439280304Sjkim OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 440280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 441280304Sjkim ret += n; 442280304Sjkim } 443280304Sjkim } else { 444280304Sjkim EVP_EncodeUpdate(&(ctx->base64), 445280304Sjkim (unsigned char *)ctx->buf, &ctx->buf_len, 446280304Sjkim (unsigned char *)in, n); 447280304Sjkim OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 448280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 449280304Sjkim ret += n; 450280304Sjkim } 451280304Sjkim inl -= n; 452280304Sjkim in += n; 45355714Skris 454280304Sjkim ctx->buf_off = 0; 455280304Sjkim n = ctx->buf_len; 456280304Sjkim while (n > 0) { 457280304Sjkim i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 458280304Sjkim if (i <= 0) { 459280304Sjkim BIO_copy_next_retry(b); 460280304Sjkim return ((ret == 0) ? i : ret); 461280304Sjkim } 462280304Sjkim OPENSSL_assert(i <= n); 463280304Sjkim n -= i; 464280304Sjkim ctx->buf_off += i; 465280304Sjkim OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); 466280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 467280304Sjkim } 468280304Sjkim ctx->buf_len = 0; 469280304Sjkim ctx->buf_off = 0; 470280304Sjkim } 471280304Sjkim return (ret); 472280304Sjkim} 47355714Skris 47468651Skrisstatic long b64_ctrl(BIO *b, int cmd, long num, void *ptr) 475280304Sjkim{ 476280304Sjkim BIO_B64_CTX *ctx; 477280304Sjkim long ret = 1; 478280304Sjkim int i; 47955714Skris 480280304Sjkim ctx = (BIO_B64_CTX *)b->ptr; 48155714Skris 482280304Sjkim switch (cmd) { 483280304Sjkim case BIO_CTRL_RESET: 484280304Sjkim ctx->cont = 1; 485280304Sjkim ctx->start = 1; 486280304Sjkim ctx->encode = B64_NONE; 487280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 488280304Sjkim break; 489280304Sjkim case BIO_CTRL_EOF: /* More to read */ 490280304Sjkim if (ctx->cont <= 0) 491280304Sjkim ret = 1; 492280304Sjkim else 493280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 494280304Sjkim break; 495280304Sjkim case BIO_CTRL_WPENDING: /* More to write in buffer */ 496280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 497280304Sjkim ret = ctx->buf_len - ctx->buf_off; 498280304Sjkim if ((ret == 0) && (ctx->encode != B64_NONE) 499280304Sjkim && (ctx->base64.num != 0)) 500280304Sjkim ret = 1; 501280304Sjkim else if (ret <= 0) 502280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 503280304Sjkim break; 504280304Sjkim case BIO_CTRL_PENDING: /* More to read in buffer */ 505280304Sjkim OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 506280304Sjkim ret = ctx->buf_len - ctx->buf_off; 507280304Sjkim if (ret <= 0) 508280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 509280304Sjkim break; 510280304Sjkim case BIO_CTRL_FLUSH: 511280304Sjkim /* do a final write */ 512280304Sjkim again: 513280304Sjkim while (ctx->buf_len != ctx->buf_off) { 514280304Sjkim i = b64_write(b, NULL, 0); 515280304Sjkim if (i < 0) 516280304Sjkim return i; 517280304Sjkim } 518280304Sjkim if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 519280304Sjkim if (ctx->tmp_len != 0) { 520280304Sjkim ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf, 521280304Sjkim (unsigned char *)ctx->tmp, 522280304Sjkim ctx->tmp_len); 523280304Sjkim ctx->buf_off = 0; 524280304Sjkim ctx->tmp_len = 0; 525280304Sjkim goto again; 526280304Sjkim } 527280304Sjkim } else if (ctx->encode != B64_NONE && ctx->base64.num != 0) { 528280304Sjkim ctx->buf_off = 0; 529280304Sjkim EVP_EncodeFinal(&(ctx->base64), 530280304Sjkim (unsigned char *)ctx->buf, &(ctx->buf_len)); 531280304Sjkim /* push out the bytes */ 532280304Sjkim goto again; 533280304Sjkim } 534280304Sjkim /* Finally flush the underlying BIO */ 535280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 536280304Sjkim break; 53755714Skris 538280304Sjkim case BIO_C_DO_STATE_MACHINE: 539280304Sjkim BIO_clear_retry_flags(b); 540280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 541280304Sjkim BIO_copy_next_retry(b); 542280304Sjkim break; 54355714Skris 544280304Sjkim case BIO_CTRL_DUP: 545280304Sjkim break; 546280304Sjkim case BIO_CTRL_INFO: 547280304Sjkim case BIO_CTRL_GET: 548280304Sjkim case BIO_CTRL_SET: 549280304Sjkim default: 550280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 551280304Sjkim break; 552280304Sjkim } 553280304Sjkim return (ret); 554280304Sjkim} 55555714Skris 55668651Skrisstatic long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 557280304Sjkim{ 558280304Sjkim long ret = 1; 55959191Skris 560280304Sjkim if (b->next_bio == NULL) 561280304Sjkim return (0); 562280304Sjkim switch (cmd) { 563280304Sjkim default: 564280304Sjkim ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 565280304Sjkim break; 566280304Sjkim } 567280304Sjkim return (ret); 568280304Sjkim} 56959191Skris 570215697Ssimonstatic int b64_puts(BIO *b, const char *str) 571280304Sjkim{ 572280304Sjkim return b64_write(b, str, strlen(str)); 573280304Sjkim} 574