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