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