11cb0ef41Sopenharmony_ci/* 21cb0ef41Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 31cb0ef41Sopenharmony_ci * 41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 51cb0ef41Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at 71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html 81cb0ef41Sopenharmony_ci */ 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include <stdio.h> 111cb0ef41Sopenharmony_ci#include <errno.h> 121cb0ef41Sopenharmony_ci#include "internal/cryptlib.h" 131cb0ef41Sopenharmony_ci#include <openssl/buffer.h> 141cb0ef41Sopenharmony_ci#include <openssl/evp.h> 151cb0ef41Sopenharmony_ci#include "internal/bio.h" 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cistatic int b64_write(BIO *h, const char *buf, int num); 181cb0ef41Sopenharmony_cistatic int b64_read(BIO *h, char *buf, int size); 191cb0ef41Sopenharmony_cistatic int b64_puts(BIO *h, const char *str); 201cb0ef41Sopenharmony_cistatic long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2); 211cb0ef41Sopenharmony_cistatic int b64_new(BIO *h); 221cb0ef41Sopenharmony_cistatic int b64_free(BIO *data); 231cb0ef41Sopenharmony_cistatic long b64_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); 241cb0ef41Sopenharmony_ci#define B64_BLOCK_SIZE 1024 251cb0ef41Sopenharmony_ci#define B64_BLOCK_SIZE2 768 261cb0ef41Sopenharmony_ci#define B64_NONE 0 271cb0ef41Sopenharmony_ci#define B64_ENCODE 1 281cb0ef41Sopenharmony_ci#define B64_DECODE 2 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_citypedef struct b64_struct { 311cb0ef41Sopenharmony_ci /* 321cb0ef41Sopenharmony_ci * BIO *bio; moved to the BIO structure 331cb0ef41Sopenharmony_ci */ 341cb0ef41Sopenharmony_ci int buf_len; 351cb0ef41Sopenharmony_ci int buf_off; 361cb0ef41Sopenharmony_ci int tmp_len; /* used to find the start when decoding */ 371cb0ef41Sopenharmony_ci int tmp_nl; /* If true, scan until '\n' */ 381cb0ef41Sopenharmony_ci int encode; 391cb0ef41Sopenharmony_ci int start; /* have we started decoding yet? */ 401cb0ef41Sopenharmony_ci int cont; /* <= 0 when finished */ 411cb0ef41Sopenharmony_ci EVP_ENCODE_CTX *base64; 421cb0ef41Sopenharmony_ci char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10]; 431cb0ef41Sopenharmony_ci char tmp[B64_BLOCK_SIZE]; 441cb0ef41Sopenharmony_ci} BIO_B64_CTX; 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_cistatic const BIO_METHOD methods_b64 = { 471cb0ef41Sopenharmony_ci BIO_TYPE_BASE64, 481cb0ef41Sopenharmony_ci "base64 encoding", 491cb0ef41Sopenharmony_ci bwrite_conv, 501cb0ef41Sopenharmony_ci b64_write, 511cb0ef41Sopenharmony_ci bread_conv, 521cb0ef41Sopenharmony_ci b64_read, 531cb0ef41Sopenharmony_ci b64_puts, 541cb0ef41Sopenharmony_ci NULL, /* b64_gets, */ 551cb0ef41Sopenharmony_ci b64_ctrl, 561cb0ef41Sopenharmony_ci b64_new, 571cb0ef41Sopenharmony_ci b64_free, 581cb0ef41Sopenharmony_ci b64_callback_ctrl, 591cb0ef41Sopenharmony_ci}; 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ciconst BIO_METHOD *BIO_f_base64(void) 631cb0ef41Sopenharmony_ci{ 641cb0ef41Sopenharmony_ci return &methods_b64; 651cb0ef41Sopenharmony_ci} 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_cistatic int b64_new(BIO *bi) 681cb0ef41Sopenharmony_ci{ 691cb0ef41Sopenharmony_ci BIO_B64_CTX *ctx; 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { 721cb0ef41Sopenharmony_ci ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); 731cb0ef41Sopenharmony_ci return 0; 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci ctx->cont = 1; 771cb0ef41Sopenharmony_ci ctx->start = 1; 781cb0ef41Sopenharmony_ci ctx->base64 = EVP_ENCODE_CTX_new(); 791cb0ef41Sopenharmony_ci if (ctx->base64 == NULL) { 801cb0ef41Sopenharmony_ci OPENSSL_free(ctx); 811cb0ef41Sopenharmony_ci return 0; 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci BIO_set_data(bi, ctx); 851cb0ef41Sopenharmony_ci BIO_set_init(bi, 1); 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci return 1; 881cb0ef41Sopenharmony_ci} 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_cistatic int b64_free(BIO *a) 911cb0ef41Sopenharmony_ci{ 921cb0ef41Sopenharmony_ci BIO_B64_CTX *ctx; 931cb0ef41Sopenharmony_ci if (a == NULL) 941cb0ef41Sopenharmony_ci return 0; 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci ctx = BIO_get_data(a); 971cb0ef41Sopenharmony_ci if (ctx == NULL) 981cb0ef41Sopenharmony_ci return 0; 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci EVP_ENCODE_CTX_free(ctx->base64); 1011cb0ef41Sopenharmony_ci OPENSSL_free(ctx); 1021cb0ef41Sopenharmony_ci BIO_set_data(a, NULL); 1031cb0ef41Sopenharmony_ci BIO_set_init(a, 0); 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci return 1; 1061cb0ef41Sopenharmony_ci} 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_cistatic int b64_read(BIO *b, char *out, int outl) 1091cb0ef41Sopenharmony_ci{ 1101cb0ef41Sopenharmony_ci int ret = 0, i, ii, j, k, x, n, num, ret_code = 0; 1111cb0ef41Sopenharmony_ci BIO_B64_CTX *ctx; 1121cb0ef41Sopenharmony_ci unsigned char *p, *q; 1131cb0ef41Sopenharmony_ci BIO *next; 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci if (out == NULL) 1161cb0ef41Sopenharmony_ci return 0; 1171cb0ef41Sopenharmony_ci ctx = (BIO_B64_CTX *)BIO_get_data(b); 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci next = BIO_next(b); 1201cb0ef41Sopenharmony_ci if ((ctx == NULL) || (next == NULL)) 1211cb0ef41Sopenharmony_ci return 0; 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci BIO_clear_retry_flags(b); 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci if (ctx->encode != B64_DECODE) { 1261cb0ef41Sopenharmony_ci ctx->encode = B64_DECODE; 1271cb0ef41Sopenharmony_ci ctx->buf_len = 0; 1281cb0ef41Sopenharmony_ci ctx->buf_off = 0; 1291cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 1301cb0ef41Sopenharmony_ci EVP_DecodeInit(ctx->base64); 1311cb0ef41Sopenharmony_ci } 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci /* First check if there are bytes decoded/encoded */ 1341cb0ef41Sopenharmony_ci if (ctx->buf_len > 0) { 1351cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 1361cb0ef41Sopenharmony_ci i = ctx->buf_len - ctx->buf_off; 1371cb0ef41Sopenharmony_ci if (i > outl) 1381cb0ef41Sopenharmony_ci i = outl; 1391cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_off + i < (int)sizeof(ctx->buf)); 1401cb0ef41Sopenharmony_ci memcpy(out, &(ctx->buf[ctx->buf_off]), i); 1411cb0ef41Sopenharmony_ci ret = i; 1421cb0ef41Sopenharmony_ci out += i; 1431cb0ef41Sopenharmony_ci outl -= i; 1441cb0ef41Sopenharmony_ci ctx->buf_off += i; 1451cb0ef41Sopenharmony_ci if (ctx->buf_len == ctx->buf_off) { 1461cb0ef41Sopenharmony_ci ctx->buf_len = 0; 1471cb0ef41Sopenharmony_ci ctx->buf_off = 0; 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci } 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci /* 1521cb0ef41Sopenharmony_ci * At this point, we have room of outl bytes and an empty buffer, so we 1531cb0ef41Sopenharmony_ci * should read in some more. 1541cb0ef41Sopenharmony_ci */ 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci ret_code = 0; 1571cb0ef41Sopenharmony_ci while (outl > 0) { 1581cb0ef41Sopenharmony_ci if (ctx->cont <= 0) 1591cb0ef41Sopenharmony_ci break; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci i = BIO_read(next, &(ctx->tmp[ctx->tmp_len]), 1621cb0ef41Sopenharmony_ci B64_BLOCK_SIZE - ctx->tmp_len); 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci if (i <= 0) { 1651cb0ef41Sopenharmony_ci ret_code = i; 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci /* Should we continue next time we are called? */ 1681cb0ef41Sopenharmony_ci if (!BIO_should_retry(next)) { 1691cb0ef41Sopenharmony_ci ctx->cont = i; 1701cb0ef41Sopenharmony_ci /* If buffer empty break */ 1711cb0ef41Sopenharmony_ci if (ctx->tmp_len == 0) 1721cb0ef41Sopenharmony_ci break; 1731cb0ef41Sopenharmony_ci /* Fall through and process what we have */ 1741cb0ef41Sopenharmony_ci else 1751cb0ef41Sopenharmony_ci i = 0; 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci /* else we retry and add more data to buffer */ 1781cb0ef41Sopenharmony_ci else 1791cb0ef41Sopenharmony_ci break; 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci i += ctx->tmp_len; 1821cb0ef41Sopenharmony_ci ctx->tmp_len = i; 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci /* 1851cb0ef41Sopenharmony_ci * We need to scan, a line at a time until we have a valid line if we 1861cb0ef41Sopenharmony_ci * are starting. 1871cb0ef41Sopenharmony_ci */ 1881cb0ef41Sopenharmony_ci if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) { 1891cb0ef41Sopenharmony_ci /* ctx->start=1; */ 1901cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 1911cb0ef41Sopenharmony_ci } else if (ctx->start) { 1921cb0ef41Sopenharmony_ci q = p = (unsigned char *)ctx->tmp; 1931cb0ef41Sopenharmony_ci num = 0; 1941cb0ef41Sopenharmony_ci for (j = 0; j < i; j++) { 1951cb0ef41Sopenharmony_ci if (*(q++) != '\n') 1961cb0ef41Sopenharmony_ci continue; 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci /* 1991cb0ef41Sopenharmony_ci * due to a previous very long line, we need to keep on 2001cb0ef41Sopenharmony_ci * scanning for a '\n' before we even start looking for 2011cb0ef41Sopenharmony_ci * base64 encoded stuff. 2021cb0ef41Sopenharmony_ci */ 2031cb0ef41Sopenharmony_ci if (ctx->tmp_nl) { 2041cb0ef41Sopenharmony_ci p = q; 2051cb0ef41Sopenharmony_ci ctx->tmp_nl = 0; 2061cb0ef41Sopenharmony_ci continue; 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci k = EVP_DecodeUpdate(ctx->base64, 2101cb0ef41Sopenharmony_ci (unsigned char *)ctx->buf, 2111cb0ef41Sopenharmony_ci &num, p, q - p); 2121cb0ef41Sopenharmony_ci if ((k <= 0) && (num == 0) && (ctx->start)) 2131cb0ef41Sopenharmony_ci EVP_DecodeInit(ctx->base64); 2141cb0ef41Sopenharmony_ci else { 2151cb0ef41Sopenharmony_ci if (p != (unsigned char *) 2161cb0ef41Sopenharmony_ci &(ctx->tmp[0])) { 2171cb0ef41Sopenharmony_ci i -= (p - (unsigned char *) 2181cb0ef41Sopenharmony_ci &(ctx->tmp[0])); 2191cb0ef41Sopenharmony_ci for (x = 0; x < i; x++) 2201cb0ef41Sopenharmony_ci ctx->tmp[x] = p[x]; 2211cb0ef41Sopenharmony_ci } 2221cb0ef41Sopenharmony_ci EVP_DecodeInit(ctx->base64); 2231cb0ef41Sopenharmony_ci ctx->start = 0; 2241cb0ef41Sopenharmony_ci break; 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci p = q; 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci /* we fell off the end without starting */ 2301cb0ef41Sopenharmony_ci if ((j == i) && (num == 0)) { 2311cb0ef41Sopenharmony_ci /* 2321cb0ef41Sopenharmony_ci * Is this is one long chunk?, if so, keep on reading until a 2331cb0ef41Sopenharmony_ci * new line. 2341cb0ef41Sopenharmony_ci */ 2351cb0ef41Sopenharmony_ci if (p == (unsigned char *)&(ctx->tmp[0])) { 2361cb0ef41Sopenharmony_ci /* Check buffer full */ 2371cb0ef41Sopenharmony_ci if (i == B64_BLOCK_SIZE) { 2381cb0ef41Sopenharmony_ci ctx->tmp_nl = 1; 2391cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci } else if (p != q) { /* finished on a '\n' */ 2421cb0ef41Sopenharmony_ci n = q - p; 2431cb0ef41Sopenharmony_ci for (ii = 0; ii < n; ii++) 2441cb0ef41Sopenharmony_ci ctx->tmp[ii] = p[ii]; 2451cb0ef41Sopenharmony_ci ctx->tmp_len = n; 2461cb0ef41Sopenharmony_ci } 2471cb0ef41Sopenharmony_ci /* else finished on a '\n' */ 2481cb0ef41Sopenharmony_ci continue; 2491cb0ef41Sopenharmony_ci } else { 2501cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci } else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) { 2531cb0ef41Sopenharmony_ci /* 2541cb0ef41Sopenharmony_ci * If buffer isn't full and we can retry then restart to read in 2551cb0ef41Sopenharmony_ci * more data. 2561cb0ef41Sopenharmony_ci */ 2571cb0ef41Sopenharmony_ci continue; 2581cb0ef41Sopenharmony_ci } 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 2611cb0ef41Sopenharmony_ci int z, jj; 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci jj = i & ~3; /* process per 4 */ 2641cb0ef41Sopenharmony_ci z = EVP_DecodeBlock((unsigned char *)ctx->buf, 2651cb0ef41Sopenharmony_ci (unsigned char *)ctx->tmp, jj); 2661cb0ef41Sopenharmony_ci if (jj > 2) { 2671cb0ef41Sopenharmony_ci if (ctx->tmp[jj - 1] == '=') { 2681cb0ef41Sopenharmony_ci z--; 2691cb0ef41Sopenharmony_ci if (ctx->tmp[jj - 2] == '=') 2701cb0ef41Sopenharmony_ci z--; 2711cb0ef41Sopenharmony_ci } 2721cb0ef41Sopenharmony_ci } 2731cb0ef41Sopenharmony_ci /* 2741cb0ef41Sopenharmony_ci * z is now number of output bytes and jj is the number consumed 2751cb0ef41Sopenharmony_ci */ 2761cb0ef41Sopenharmony_ci if (jj != i) { 2771cb0ef41Sopenharmony_ci memmove(ctx->tmp, &ctx->tmp[jj], i - jj); 2781cb0ef41Sopenharmony_ci ctx->tmp_len = i - jj; 2791cb0ef41Sopenharmony_ci } 2801cb0ef41Sopenharmony_ci ctx->buf_len = 0; 2811cb0ef41Sopenharmony_ci if (z > 0) { 2821cb0ef41Sopenharmony_ci ctx->buf_len = z; 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci i = z; 2851cb0ef41Sopenharmony_ci } else { 2861cb0ef41Sopenharmony_ci i = EVP_DecodeUpdate(ctx->base64, 2871cb0ef41Sopenharmony_ci (unsigned char *)ctx->buf, &ctx->buf_len, 2881cb0ef41Sopenharmony_ci (unsigned char *)ctx->tmp, i); 2891cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 2901cb0ef41Sopenharmony_ci } 2911cb0ef41Sopenharmony_ci /* 2921cb0ef41Sopenharmony_ci * If eof or an error was signalled, then the condition 2931cb0ef41Sopenharmony_ci * 'ctx->cont <= 0' will prevent b64_read() from reading 2941cb0ef41Sopenharmony_ci * more data on subsequent calls. This assignment was 2951cb0ef41Sopenharmony_ci * deleted accidentally in commit 5562cfaca4f3. 2961cb0ef41Sopenharmony_ci */ 2971cb0ef41Sopenharmony_ci ctx->cont = i; 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci ctx->buf_off = 0; 3001cb0ef41Sopenharmony_ci if (i < 0) { 3011cb0ef41Sopenharmony_ci ret_code = 0; 3021cb0ef41Sopenharmony_ci ctx->buf_len = 0; 3031cb0ef41Sopenharmony_ci break; 3041cb0ef41Sopenharmony_ci } 3051cb0ef41Sopenharmony_ci 3061cb0ef41Sopenharmony_ci if (ctx->buf_len <= outl) 3071cb0ef41Sopenharmony_ci i = ctx->buf_len; 3081cb0ef41Sopenharmony_ci else 3091cb0ef41Sopenharmony_ci i = outl; 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci memcpy(out, ctx->buf, i); 3121cb0ef41Sopenharmony_ci ret += i; 3131cb0ef41Sopenharmony_ci ctx->buf_off = i; 3141cb0ef41Sopenharmony_ci if (ctx->buf_off == ctx->buf_len) { 3151cb0ef41Sopenharmony_ci ctx->buf_len = 0; 3161cb0ef41Sopenharmony_ci ctx->buf_off = 0; 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci outl -= i; 3191cb0ef41Sopenharmony_ci out += i; 3201cb0ef41Sopenharmony_ci } 3211cb0ef41Sopenharmony_ci /* BIO_clear_retry_flags(b); */ 3221cb0ef41Sopenharmony_ci BIO_copy_next_retry(b); 3231cb0ef41Sopenharmony_ci return ((ret == 0) ? ret_code : ret); 3241cb0ef41Sopenharmony_ci} 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_cistatic int b64_write(BIO *b, const char *in, int inl) 3271cb0ef41Sopenharmony_ci{ 3281cb0ef41Sopenharmony_ci int ret = 0; 3291cb0ef41Sopenharmony_ci int n; 3301cb0ef41Sopenharmony_ci int i; 3311cb0ef41Sopenharmony_ci BIO_B64_CTX *ctx; 3321cb0ef41Sopenharmony_ci BIO *next; 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci ctx = (BIO_B64_CTX *)BIO_get_data(b); 3351cb0ef41Sopenharmony_ci next = BIO_next(b); 3361cb0ef41Sopenharmony_ci if ((ctx == NULL) || (next == NULL)) 3371cb0ef41Sopenharmony_ci return 0; 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci BIO_clear_retry_flags(b); 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci if (ctx->encode != B64_ENCODE) { 3421cb0ef41Sopenharmony_ci ctx->encode = B64_ENCODE; 3431cb0ef41Sopenharmony_ci ctx->buf_len = 0; 3441cb0ef41Sopenharmony_ci ctx->buf_off = 0; 3451cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 3461cb0ef41Sopenharmony_ci EVP_EncodeInit(ctx->base64); 3471cb0ef41Sopenharmony_ci } 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf)); 3501cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 3511cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 3521cb0ef41Sopenharmony_ci n = ctx->buf_len - ctx->buf_off; 3531cb0ef41Sopenharmony_ci while (n > 0) { 3541cb0ef41Sopenharmony_ci i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); 3551cb0ef41Sopenharmony_ci if (i <= 0) { 3561cb0ef41Sopenharmony_ci BIO_copy_next_retry(b); 3571cb0ef41Sopenharmony_ci return i; 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci OPENSSL_assert(i <= n); 3601cb0ef41Sopenharmony_ci ctx->buf_off += i; 3611cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); 3621cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 3631cb0ef41Sopenharmony_ci n -= i; 3641cb0ef41Sopenharmony_ci } 3651cb0ef41Sopenharmony_ci /* at this point all pending data has been written */ 3661cb0ef41Sopenharmony_ci ctx->buf_off = 0; 3671cb0ef41Sopenharmony_ci ctx->buf_len = 0; 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ci if ((in == NULL) || (inl <= 0)) 3701cb0ef41Sopenharmony_ci return 0; 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci while (inl > 0) { 3731cb0ef41Sopenharmony_ci n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl; 3741cb0ef41Sopenharmony_ci 3751cb0ef41Sopenharmony_ci if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 3761cb0ef41Sopenharmony_ci if (ctx->tmp_len > 0) { 3771cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->tmp_len <= 3); 3781cb0ef41Sopenharmony_ci n = 3 - ctx->tmp_len; 3791cb0ef41Sopenharmony_ci /* 3801cb0ef41Sopenharmony_ci * There's a theoretical possibility for this 3811cb0ef41Sopenharmony_ci */ 3821cb0ef41Sopenharmony_ci if (n > inl) 3831cb0ef41Sopenharmony_ci n = inl; 3841cb0ef41Sopenharmony_ci memcpy(&(ctx->tmp[ctx->tmp_len]), in, n); 3851cb0ef41Sopenharmony_ci ctx->tmp_len += n; 3861cb0ef41Sopenharmony_ci ret += n; 3871cb0ef41Sopenharmony_ci if (ctx->tmp_len < 3) 3881cb0ef41Sopenharmony_ci break; 3891cb0ef41Sopenharmony_ci ctx->buf_len = 3901cb0ef41Sopenharmony_ci EVP_EncodeBlock((unsigned char *)ctx->buf, 3911cb0ef41Sopenharmony_ci (unsigned char *)ctx->tmp, ctx->tmp_len); 3921cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 3931cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 3941cb0ef41Sopenharmony_ci /* 3951cb0ef41Sopenharmony_ci * Since we're now done using the temporary buffer, the 3961cb0ef41Sopenharmony_ci * length should be 0'd 3971cb0ef41Sopenharmony_ci */ 3981cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 3991cb0ef41Sopenharmony_ci } else { 4001cb0ef41Sopenharmony_ci if (n < 3) { 4011cb0ef41Sopenharmony_ci memcpy(ctx->tmp, in, n); 4021cb0ef41Sopenharmony_ci ctx->tmp_len = n; 4031cb0ef41Sopenharmony_ci ret += n; 4041cb0ef41Sopenharmony_ci break; 4051cb0ef41Sopenharmony_ci } 4061cb0ef41Sopenharmony_ci n -= n % 3; 4071cb0ef41Sopenharmony_ci ctx->buf_len = 4081cb0ef41Sopenharmony_ci EVP_EncodeBlock((unsigned char *)ctx->buf, 4091cb0ef41Sopenharmony_ci (const unsigned char *)in, n); 4101cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 4111cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 4121cb0ef41Sopenharmony_ci ret += n; 4131cb0ef41Sopenharmony_ci } 4141cb0ef41Sopenharmony_ci } else { 4151cb0ef41Sopenharmony_ci if (!EVP_EncodeUpdate(ctx->base64, 4161cb0ef41Sopenharmony_ci (unsigned char *)ctx->buf, &ctx->buf_len, 4171cb0ef41Sopenharmony_ci (unsigned char *)in, n)) 4181cb0ef41Sopenharmony_ci return ((ret == 0) ? -1 : ret); 4191cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf)); 4201cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 4211cb0ef41Sopenharmony_ci ret += n; 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci inl -= n; 4241cb0ef41Sopenharmony_ci in += n; 4251cb0ef41Sopenharmony_ci 4261cb0ef41Sopenharmony_ci ctx->buf_off = 0; 4271cb0ef41Sopenharmony_ci n = ctx->buf_len; 4281cb0ef41Sopenharmony_ci while (n > 0) { 4291cb0ef41Sopenharmony_ci i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); 4301cb0ef41Sopenharmony_ci if (i <= 0) { 4311cb0ef41Sopenharmony_ci BIO_copy_next_retry(b); 4321cb0ef41Sopenharmony_ci return ((ret == 0) ? i : ret); 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci OPENSSL_assert(i <= n); 4351cb0ef41Sopenharmony_ci n -= i; 4361cb0ef41Sopenharmony_ci ctx->buf_off += i; 4371cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf)); 4381cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci ctx->buf_len = 0; 4411cb0ef41Sopenharmony_ci ctx->buf_off = 0; 4421cb0ef41Sopenharmony_ci } 4431cb0ef41Sopenharmony_ci return ret; 4441cb0ef41Sopenharmony_ci} 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_cistatic long b64_ctrl(BIO *b, int cmd, long num, void *ptr) 4471cb0ef41Sopenharmony_ci{ 4481cb0ef41Sopenharmony_ci BIO_B64_CTX *ctx; 4491cb0ef41Sopenharmony_ci long ret = 1; 4501cb0ef41Sopenharmony_ci int i; 4511cb0ef41Sopenharmony_ci BIO *next; 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci ctx = (BIO_B64_CTX *)BIO_get_data(b); 4541cb0ef41Sopenharmony_ci next = BIO_next(b); 4551cb0ef41Sopenharmony_ci if ((ctx == NULL) || (next == NULL)) 4561cb0ef41Sopenharmony_ci return 0; 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci switch (cmd) { 4591cb0ef41Sopenharmony_ci case BIO_CTRL_RESET: 4601cb0ef41Sopenharmony_ci ctx->cont = 1; 4611cb0ef41Sopenharmony_ci ctx->start = 1; 4621cb0ef41Sopenharmony_ci ctx->encode = B64_NONE; 4631cb0ef41Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 4641cb0ef41Sopenharmony_ci break; 4651cb0ef41Sopenharmony_ci case BIO_CTRL_EOF: /* More to read */ 4661cb0ef41Sopenharmony_ci if (ctx->cont <= 0) 4671cb0ef41Sopenharmony_ci ret = 1; 4681cb0ef41Sopenharmony_ci else 4691cb0ef41Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 4701cb0ef41Sopenharmony_ci break; 4711cb0ef41Sopenharmony_ci case BIO_CTRL_WPENDING: /* More to write in buffer */ 4721cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 4731cb0ef41Sopenharmony_ci ret = ctx->buf_len - ctx->buf_off; 4741cb0ef41Sopenharmony_ci if ((ret == 0) && (ctx->encode != B64_NONE) 4751cb0ef41Sopenharmony_ci && (EVP_ENCODE_CTX_num(ctx->base64) != 0)) 4761cb0ef41Sopenharmony_ci ret = 1; 4771cb0ef41Sopenharmony_ci else if (ret <= 0) 4781cb0ef41Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 4791cb0ef41Sopenharmony_ci break; 4801cb0ef41Sopenharmony_ci case BIO_CTRL_PENDING: /* More to read in buffer */ 4811cb0ef41Sopenharmony_ci OPENSSL_assert(ctx->buf_len >= ctx->buf_off); 4821cb0ef41Sopenharmony_ci ret = ctx->buf_len - ctx->buf_off; 4831cb0ef41Sopenharmony_ci if (ret <= 0) 4841cb0ef41Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 4851cb0ef41Sopenharmony_ci break; 4861cb0ef41Sopenharmony_ci case BIO_CTRL_FLUSH: 4871cb0ef41Sopenharmony_ci /* do a final write */ 4881cb0ef41Sopenharmony_ci again: 4891cb0ef41Sopenharmony_ci while (ctx->buf_len != ctx->buf_off) { 4901cb0ef41Sopenharmony_ci i = b64_write(b, NULL, 0); 4911cb0ef41Sopenharmony_ci if (i < 0) 4921cb0ef41Sopenharmony_ci return i; 4931cb0ef41Sopenharmony_ci } 4941cb0ef41Sopenharmony_ci if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) { 4951cb0ef41Sopenharmony_ci if (ctx->tmp_len != 0) { 4961cb0ef41Sopenharmony_ci ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf, 4971cb0ef41Sopenharmony_ci (unsigned char *)ctx->tmp, 4981cb0ef41Sopenharmony_ci ctx->tmp_len); 4991cb0ef41Sopenharmony_ci ctx->buf_off = 0; 5001cb0ef41Sopenharmony_ci ctx->tmp_len = 0; 5011cb0ef41Sopenharmony_ci goto again; 5021cb0ef41Sopenharmony_ci } 5031cb0ef41Sopenharmony_ci } else if (ctx->encode != B64_NONE 5041cb0ef41Sopenharmony_ci && EVP_ENCODE_CTX_num(ctx->base64) != 0) { 5051cb0ef41Sopenharmony_ci ctx->buf_off = 0; 5061cb0ef41Sopenharmony_ci EVP_EncodeFinal(ctx->base64, 5071cb0ef41Sopenharmony_ci (unsigned char *)ctx->buf, &(ctx->buf_len)); 5081cb0ef41Sopenharmony_ci /* push out the bytes */ 5091cb0ef41Sopenharmony_ci goto again; 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci /* Finally flush the underlying BIO */ 5121cb0ef41Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 5131cb0ef41Sopenharmony_ci break; 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_ci case BIO_C_DO_STATE_MACHINE: 5161cb0ef41Sopenharmony_ci BIO_clear_retry_flags(b); 5171cb0ef41Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 5181cb0ef41Sopenharmony_ci BIO_copy_next_retry(b); 5191cb0ef41Sopenharmony_ci break; 5201cb0ef41Sopenharmony_ci 5211cb0ef41Sopenharmony_ci case BIO_CTRL_DUP: 5221cb0ef41Sopenharmony_ci break; 5231cb0ef41Sopenharmony_ci case BIO_CTRL_INFO: 5241cb0ef41Sopenharmony_ci case BIO_CTRL_GET: 5251cb0ef41Sopenharmony_ci case BIO_CTRL_SET: 5261cb0ef41Sopenharmony_ci default: 5271cb0ef41Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 5281cb0ef41Sopenharmony_ci break; 5291cb0ef41Sopenharmony_ci } 5301cb0ef41Sopenharmony_ci return ret; 5311cb0ef41Sopenharmony_ci} 5321cb0ef41Sopenharmony_ci 5331cb0ef41Sopenharmony_cistatic long b64_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 5341cb0ef41Sopenharmony_ci{ 5351cb0ef41Sopenharmony_ci BIO *next = BIO_next(b); 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_ci if (next == NULL) 5381cb0ef41Sopenharmony_ci return 0; 5391cb0ef41Sopenharmony_ci 5401cb0ef41Sopenharmony_ci return BIO_callback_ctrl(next, cmd, fp); 5411cb0ef41Sopenharmony_ci} 5421cb0ef41Sopenharmony_ci 5431cb0ef41Sopenharmony_cistatic int b64_puts(BIO *b, const char *str) 5441cb0ef41Sopenharmony_ci{ 5451cb0ef41Sopenharmony_ci return b64_write(b, str, strlen(str)); 5461cb0ef41Sopenharmony_ci} 547