Coverage Report

Created: 2026-10-16 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/evp/bio_b64.c
Line
Count
Source
1
/*
2
 * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <stdio.h>
11
#include <errno.h>
12
#include "internal/cryptlib.h"
13
#include <openssl/buffer.h>
14
#include <openssl/evp.h>
15
#include "internal/bio.h"
16
#include "crypto/evp.h"
17
18
static int b64_write(BIO *h, const char *buf, int num);
19
static int b64_read(BIO *h, char *buf, int size);
20
static int b64_puts(BIO *h, const char *str);
21
static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
22
static int b64_new(BIO *h);
23
static int b64_free(BIO *data);
24
static long b64_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
25
0
#define B64_BLOCK_SIZE 1024
26
#define B64_BLOCK_SIZE2 768
27
0
#define B64_NONE 0
28
0
#define B64_ENCODE 1
29
0
#define B64_DECODE 2
30
31
typedef struct b64_struct {
32
    /*
33
     * BIO *bio; moved to the BIO structure
34
     */
35
    int buf_len;
36
    int buf_off;
37
    int tmp_len; /* used to find the start when decoding */
38
    int tmp_nl; /* If true, scan until '\n' */
39
    int encode;
40
    int start; /* have we started decoding yet? */
41
    int cont; /* <= 0 when finished */
42
    EVP_ENCODE_CTX *base64;
43
    unsigned char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10];
44
    unsigned char tmp[B64_BLOCK_SIZE];
45
    unsigned char *encoded_buf;
46
    size_t encoded_buf_len;
47
    size_t encoded_len;
48
    size_t encoded_off;
49
} BIO_B64_CTX;
50
51
static const BIO_METHOD methods_b64 = {
52
    BIO_TYPE_BASE64,
53
    "base64 encoding",
54
    bwrite_conv,
55
    b64_write,
56
    bread_conv,
57
    b64_read,
58
    b64_puts,
59
    NULL, /* b64_gets, */
60
    b64_ctrl,
61
    b64_new,
62
    b64_free,
63
    b64_callback_ctrl,
64
};
65
66
const BIO_METHOD *BIO_f_base64(void)
67
0
{
68
0
    return &methods_b64;
69
0
}
70
71
static int b64_new(BIO *bi)
72
0
{
73
0
    BIO_B64_CTX *ctx;
74
75
0
    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
76
0
        return 0;
77
78
0
    ctx->cont = 1;
79
0
    ctx->start = 1;
80
0
    ctx->encoded_buf = NULL;
81
0
    ctx->encoded_buf_len = 0;
82
0
    ctx->base64 = EVP_ENCODE_CTX_new();
83
0
    if (ctx->base64 == NULL) {
84
0
        OPENSSL_free(ctx);
85
0
        return 0;
86
0
    }
87
88
0
    BIO_set_data(bi, ctx);
89
0
    BIO_set_init(bi, 1);
90
91
0
    return 1;
92
0
}
93
94
static int b64_free(BIO *a)
95
0
{
96
0
    BIO_B64_CTX *ctx;
97
98
0
    if (a == NULL)
99
0
        return 0;
100
101
0
    ctx = BIO_get_data(a);
102
0
    if (ctx == NULL)
103
0
        return 0;
104
105
0
    OPENSSL_free(ctx->encoded_buf);
106
0
    ctx->encoded_buf = NULL;
107
0
    ctx->encoded_buf_len = 0;
108
0
    EVP_ENCODE_CTX_free(ctx->base64);
109
0
    OPENSSL_free(ctx);
110
0
    BIO_set_data(a, NULL);
111
0
    BIO_set_init(a, 0);
112
113
0
    return 1;
114
0
}
115
116
static int b64_write_buffer(BIO *b, BIO *next, unsigned char *buf,
117
    size_t *buf_len, size_t *buf_off)
118
0
{
119
0
    size_t n;
120
0
    int i, dlen;
121
122
0
    if (!ossl_assert(*buf_len >= *buf_off)) {
123
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
124
0
        return -1;
125
0
    }
126
127
0
    n = *buf_len - *buf_off;
128
0
    if (n > 0 && !ossl_assert(buf != NULL)) {
129
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
130
0
        return -1;
131
0
    }
132
0
    while (n > 0) {
133
0
        if (n > INT_MAX)
134
0
            dlen = INT_MAX;
135
0
        else
136
0
            dlen = (int)n;
137
0
        i = BIO_write(next, &(buf[*buf_off]), dlen);
138
0
        if (i <= 0) {
139
0
            BIO_copy_next_retry(b);
140
0
            return i;
141
0
        }
142
0
        if (!ossl_assert((size_t)i <= n)) {
143
0
            ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
144
0
            return -1;
145
0
        }
146
0
        *buf_off += (size_t)i;
147
0
        n -= (size_t)i;
148
0
    }
149
0
    *buf_off = 0;
150
0
    *buf_len = 0;
151
152
0
    return 1;
153
0
}
154
155
static int b64_write_buffer_int(BIO *b, BIO *next, unsigned char *buf,
156
    int *buf_len, int *buf_off)
157
0
{
158
0
    int ret;
159
0
    size_t len;
160
0
    size_t off;
161
162
0
    if (!ossl_assert(*buf_off >= 0)) {
163
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
164
0
        return -1;
165
0
    }
166
167
0
    len = (size_t)*buf_len;
168
0
    off = (size_t)*buf_off;
169
0
    ret = b64_write_buffer(b, next, buf, &len, &off);
170
171
0
    *buf_len = (int)len;
172
0
    *buf_off = (int)off;
173
0
    return ret;
174
0
}
175
176
static int b64_write_pending(BIO_B64_CTX *ctx)
177
0
{
178
0
    return ctx->encoded_len != ctx->encoded_off
179
0
        || ctx->buf_len != ctx->buf_off;
180
0
}
181
182
/*
183
 * Unless `BIO_FLAGS_BASE64_NO_NL` is set, this BIO ignores leading lines that
184
 * aren't exclusively composed of valid Base64 characters (followed by <CRLF>
185
 * or <LF>).  Once a valid Base64 line is found, `ctx->start` is set to 0 and
186
 * lines are processed until EOF or the first line that contains invalid Base64
187
 * characters.  In a nod to PEM, lines that start with a '-' (hyphen) are
188
 * treated as a soft EOF, rather than an error.
189
 */
190
static int b64_read(BIO *b, char *out, int outl)
191
0
{
192
0
    int ret = 0, i, ii, j, k, x, n, num, ret_code;
193
0
    BIO_B64_CTX *ctx;
194
0
    unsigned char *p, *q;
195
0
    BIO *next;
196
197
0
    if (out == NULL)
198
0
        return 0;
199
0
    ctx = (BIO_B64_CTX *)BIO_get_data(b);
200
201
0
    next = BIO_next(b);
202
0
    if (ctx == NULL || next == NULL)
203
0
        return 0;
204
205
0
    BIO_clear_retry_flags(b);
206
207
0
    if (ctx->encode != B64_DECODE) {
208
0
        ctx->encode = B64_DECODE;
209
0
        ctx->buf_len = 0;
210
0
        ctx->buf_off = 0;
211
0
        ctx->tmp_len = 0;
212
0
        ctx->encoded_len = 0;
213
0
        ctx->encoded_off = 0;
214
0
        EVP_DecodeInit(ctx->base64);
215
0
    }
216
217
    /* First check if there are buffered bytes already decoded */
218
0
    if (ctx->buf_len > 0) {
219
0
        if (!ossl_assert(ctx->buf_len >= ctx->buf_off)) {
220
0
            ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
221
0
            return -1;
222
0
        }
223
0
        i = ctx->buf_len - ctx->buf_off;
224
0
        if (i > outl)
225
0
            i = outl;
226
0
        if (!ossl_assert(ctx->buf_off + i < (int)sizeof(ctx->buf))) {
227
0
            ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
228
0
            return -1;
229
0
        }
230
0
        memcpy(out, &(ctx->buf[ctx->buf_off]), i);
231
0
        ret = i;
232
0
        out += i;
233
0
        outl -= i;
234
0
        ctx->buf_off += i;
235
0
        if (ctx->buf_len == ctx->buf_off) {
236
0
            ctx->buf_len = 0;
237
0
            ctx->buf_off = 0;
238
0
        }
239
0
    }
240
241
    /* Restore any non-retriable error condition (ctx->cont < 0) */
242
0
    ret_code = ctx->cont < 0 ? ctx->cont : 0;
243
244
    /*
245
     * At this point, we have room of outl bytes and an either an empty buffer,
246
     * or outl == 0, so we'll attempt to read in some more.
247
     */
248
0
    while (outl > 0) {
249
0
        int again = ctx->cont;
250
251
0
        if (again <= 0)
252
0
            break;
253
254
0
        i = BIO_read(next, &(ctx->tmp[ctx->tmp_len]),
255
0
            B64_BLOCK_SIZE - ctx->tmp_len);
256
257
0
        if (i <= 0) {
258
0
            ret_code = i;
259
260
            /* Should we continue next time we are called? */
261
0
            if (!BIO_should_retry(next)) {
262
                /* Incomplete final Base64 chunk in the decoder is an error */
263
0
                if (ctx->tmp_len == 0) {
264
0
                    if (EVP_DecodeFinal(ctx->base64, NULL, &num) < 0)
265
0
                        ret_code = -1;
266
0
                    EVP_DecodeInit(ctx->base64);
267
0
                }
268
0
                ctx->cont = ret_code;
269
0
            }
270
0
            if (ctx->tmp_len == 0)
271
0
                break;
272
            /* Fall through and process what we have */
273
0
            i = 0;
274
            /* But don't loop to top-up even if the buffer is not full! */
275
0
            again = 0;
276
0
        }
277
278
0
        i += ctx->tmp_len;
279
0
        ctx->tmp_len = i;
280
281
        /*
282
         * We need to scan, a line at a time until we have a valid line if we
283
         * are starting.
284
         */
285
0
        if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) != 0) {
286
0
            ctx->tmp_len = 0;
287
0
        } else if (ctx->start) {
288
0
            q = p = ctx->tmp;
289
0
            num = 0;
290
0
            for (j = 0; j < i; j++) {
291
0
                if (*(q++) != '\n')
292
0
                    continue;
293
294
                /*
295
                 * due to a previous very long line, we need to keep on
296
                 * scanning for a '\n' before we even start looking for
297
                 * base64 encoded stuff.
298
                 */
299
0
                if (ctx->tmp_nl) {
300
0
                    p = q;
301
0
                    ctx->tmp_nl = 0;
302
0
                    continue;
303
0
                }
304
305
0
                k = EVP_DecodeUpdate(ctx->base64, ctx->buf, &num, p, (int)(q - p));
306
0
                EVP_DecodeInit(ctx->base64);
307
0
                if (k <= 0 && num == 0) {
308
0
                    p = q;
309
0
                    continue;
310
0
                }
311
312
0
                ctx->start = 0;
313
0
                if (p != ctx->tmp) {
314
0
                    i -= (int)(p - ctx->tmp);
315
0
                    for (x = 0; x < i; x++)
316
0
                        ctx->tmp[x] = p[x];
317
0
                }
318
0
                break;
319
0
            }
320
321
            /* we fell off the end without starting */
322
0
            if (ctx->start) {
323
                /*
324
                 * Is this is one long chunk?, if so, keep on reading until a
325
                 * new line.
326
                 */
327
0
                if (p == ctx->tmp) {
328
                    /* Check buffer full */
329
0
                    if (i == B64_BLOCK_SIZE) {
330
0
                        ctx->tmp_nl = 1;
331
0
                        ctx->tmp_len = 0;
332
0
                    }
333
0
                } else if (p != q) {
334
                    /* Retain partial line at end of buffer */
335
0
                    n = (int)(q - p);
336
0
                    for (ii = 0; ii < n; ii++)
337
0
                        ctx->tmp[ii] = p[ii];
338
0
                    ctx->tmp_len = n;
339
0
                } else {
340
                    /* All we have is newline terminated non-start data */
341
0
                    ctx->tmp_len = 0;
342
0
                }
343
                /*
344
                 * Try to read more if possible, otherwise we can't make
345
                 * progress unless the underlying BIO is retriable and may
346
                 * produce more data next time we're called.
347
                 */
348
0
                if (again > 0)
349
0
                    continue;
350
0
                else
351
0
                    break;
352
0
            } else {
353
0
                ctx->tmp_len = 0;
354
0
            }
355
0
        } else if (i < B64_BLOCK_SIZE && again > 0) {
356
            /*
357
             * If buffer isn't full and we can retry then restart to read in
358
             * more data.
359
             */
360
0
            continue;
361
0
        }
362
363
0
        i = EVP_DecodeUpdate(ctx->base64, ctx->buf, &ctx->buf_len,
364
0
            ctx->tmp, i);
365
0
        ctx->tmp_len = 0;
366
        /*
367
         * If eof or an error was signalled, then the condition
368
         * 'ctx->cont <= 0' will prevent b64_read() from reading
369
         * more data on subsequent calls. This assignment was
370
         * deleted accidentally in commit 5562cfaca4f3.
371
         */
372
0
        ctx->cont = i;
373
374
0
        ctx->buf_off = 0;
375
0
        if (i < 0) {
376
0
            ret_code = ctx->start ? 0 : i;
377
0
            ctx->buf_len = 0;
378
0
            break;
379
0
        }
380
381
0
        if (ctx->buf_len <= outl)
382
0
            i = ctx->buf_len;
383
0
        else
384
0
            i = outl;
385
386
0
        memcpy(out, ctx->buf, i);
387
0
        ret += i;
388
0
        ctx->buf_off = i;
389
0
        if (ctx->buf_off == ctx->buf_len) {
390
0
            ctx->buf_len = 0;
391
0
            ctx->buf_off = 0;
392
0
        }
393
0
        outl -= i;
394
0
        out += i;
395
0
    }
396
0
    BIO_copy_next_retry(b);
397
0
    return ret == 0 ? ret_code : ret;
398
0
}
399
400
static int b64_write(BIO *b, const char *in, int inl)
401
0
{
402
0
    int ret = 0;
403
0
    int i;
404
0
    BIO_B64_CTX *ctx;
405
0
    BIO *next;
406
0
    size_t encoded_length;
407
0
    unsigned char *encoded;
408
0
    int n_bytes_enc;
409
410
0
    ctx = (BIO_B64_CTX *)BIO_get_data(b);
411
0
    next = BIO_next(b);
412
0
    if (ctx == NULL || next == NULL)
413
0
        return 0;
414
415
0
    BIO_clear_retry_flags(b);
416
417
0
    if (ctx->encode != B64_ENCODE) {
418
0
        ctx->encode = B64_ENCODE;
419
0
        ctx->buf_len = 0;
420
0
        ctx->buf_off = 0;
421
0
        ctx->tmp_len = 0;
422
0
        ctx->encoded_len = 0;
423
0
        ctx->encoded_off = 0;
424
0
        EVP_EncodeInit(ctx->base64);
425
0
        if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
426
0
            evp_encode_ctx_set_flags(ctx->base64, EVP_ENCODE_CTX_NO_NEWLINES);
427
0
    }
428
0
    if (!ossl_assert(ctx->buf_off < (int)sizeof(ctx->buf))) {
429
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
430
0
        return -1;
431
0
    }
432
0
    if (!ossl_assert(ctx->buf_len <= (int)sizeof(ctx->buf))) {
433
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
434
0
        return -1;
435
0
    }
436
0
    if (!ossl_assert(ctx->buf_len >= ctx->buf_off)) {
437
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
438
0
        return -1;
439
0
    }
440
0
    if (!ossl_assert(ctx->encoded_len >= ctx->encoded_off)) {
441
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
442
0
        return -1;
443
0
    }
444
0
    if (!ossl_assert(ctx->encoded_len <= ctx->encoded_buf_len)) {
445
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
446
0
        return -1;
447
0
    }
448
449
0
    i = b64_write_buffer(b, next, ctx->encoded_buf, &ctx->encoded_len,
450
0
        &ctx->encoded_off);
451
0
    if (i <= 0)
452
0
        return i;
453
0
    i = b64_write_buffer_int(b, next, ctx->buf, &ctx->buf_len, &ctx->buf_off);
454
0
    if (i <= 0)
455
0
        return i;
456
0
    if (!ossl_assert(ctx->buf_off <= (int)sizeof(ctx->buf))) {
457
0
        ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
458
0
        return -1;
459
0
    }
460
461
0
    if (in == NULL || inl <= 0)
462
0
        return 0;
463
464
0
    encoded_length = EVP_ENCODE_LENGTH(inl);
465
466
0
    if (encoded_length > SIZE_MAX / 2) {
467
0
        ERR_raise(ERR_LIB_BIO, BIO_R_LENGTH_TOO_LONG);
468
0
        return -1;
469
0
    }
470
471
0
    if (ctx->encoded_buf == NULL || encoded_length > ctx->encoded_buf_len) {
472
0
        OPENSSL_free(ctx->encoded_buf);
473
0
        ctx->encoded_buf = NULL;
474
0
        ctx->encoded_buf_len = 0;
475
0
        ctx->encoded_buf = OPENSSL_malloc(encoded_length);
476
0
        if (ctx->encoded_buf == NULL) {
477
0
            ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
478
0
            return -1;
479
0
        }
480
0
        ctx->encoded_buf_len = encoded_length;
481
0
    }
482
483
0
    encoded = ctx->encoded_buf;
484
485
0
    if (encoded == NULL) {
486
0
        ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
487
0
        return -1;
488
0
    }
489
0
    n_bytes_enc = 0;
490
0
    if (!EVP_EncodeUpdate(ctx->base64, encoded, &n_bytes_enc,
491
0
            (unsigned char *)in, inl)) {
492
0
        return -1;
493
0
    }
494
    /*
495
     * The encoder state has consumed the input.  Keep any unwritten encoded
496
     * output pending so a later retry or flush can complete it.
497
     */
498
0
    ret += inl;
499
0
    ctx->encoded_len = (size_t)n_bytes_enc;
500
0
    ctx->encoded_off = 0;
501
    /*
502
     * Try to write it now, but the input is consumed into encoder state, so
503
     * report it as written even if downstream cannot accept all encoded output.
504
     */
505
0
    (void)b64_write_buffer(b, next, ctx->encoded_buf, &ctx->encoded_len,
506
0
        &ctx->encoded_off);
507
0
    return ret;
508
0
}
509
510
static long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
511
0
{
512
0
    BIO_B64_CTX *ctx;
513
0
    long ret = 1;
514
0
    int i;
515
0
    BIO *next;
516
517
0
    ctx = (BIO_B64_CTX *)BIO_get_data(b);
518
0
    next = BIO_next(b);
519
    /*
520
     * If there is no ctx or no next BIO, BIO_read() returns 0, which means EOF.
521
     * BIO_eof() should return 1 in this case.
522
     */
523
0
    if (ctx == NULL || next == NULL)
524
0
        return cmd == BIO_CTRL_EOF;
525
526
0
    switch (cmd) {
527
0
    case BIO_CTRL_RESET:
528
0
        ctx->cont = 1;
529
0
        ctx->start = 1;
530
0
        ctx->encode = B64_NONE;
531
0
        ctx->encoded_len = 0;
532
0
        ctx->encoded_off = 0;
533
0
        ret = BIO_ctrl(next, cmd, num, ptr);
534
0
        break;
535
0
    case BIO_CTRL_EOF: /* More to read */
536
0
        if (ctx->cont <= 0)
537
0
            ret = 1;
538
0
        else
539
0
            ret = BIO_ctrl(next, cmd, num, ptr);
540
0
        break;
541
0
    case BIO_CTRL_WPENDING: /* More to write in buffer */
542
0
        if (!ossl_assert(ctx->encoded_len >= ctx->encoded_off)) {
543
0
            ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
544
0
            return -1;
545
0
        }
546
0
        if (!ossl_assert(ctx->buf_len >= ctx->buf_off)) {
547
0
            ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
548
0
            return -1;
549
0
        }
550
0
        ret = (long)(ctx->encoded_len - ctx->encoded_off)
551
0
            + (ctx->buf_len - ctx->buf_off);
552
0
        if (ret == 0 && ctx->encode != B64_NONE
553
0
            && EVP_ENCODE_CTX_num(ctx->base64) != 0)
554
0
            ret = 1;
555
0
        else if (ret <= 0)
556
0
            ret = BIO_ctrl(next, cmd, num, ptr);
557
0
        break;
558
0
    case BIO_CTRL_PENDING: /* More to read in buffer */
559
0
        if (!ossl_assert(ctx->buf_len >= ctx->buf_off)) {
560
0
            ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
561
0
            return -1;
562
0
        }
563
0
        ret = ctx->buf_len - ctx->buf_off;
564
0
        if (ret <= 0)
565
0
            ret = BIO_ctrl(next, cmd, num, ptr);
566
0
        break;
567
0
    case BIO_CTRL_FLUSH:
568
0
        if (ctx->encode == B64_ENCODE) {
569
            /* do a final write */
570
0
        again:
571
0
            while (b64_write_pending(ctx)) {
572
0
                i = b64_write(b, NULL, 0);
573
0
                if (i < 0 || (i == 0 && b64_write_pending(ctx)))
574
0
                    return i;
575
0
            }
576
0
            if (EVP_ENCODE_CTX_num(ctx->base64) != 0) {
577
0
                ctx->buf_off = 0;
578
0
                EVP_EncodeFinal(ctx->base64, ctx->buf, &(ctx->buf_len));
579
                /* push out the bytes */
580
0
                goto again;
581
0
            }
582
0
        }
583
        /* Finally flush the underlying BIO */
584
0
        BIO_clear_retry_flags(b);
585
0
        ret = BIO_ctrl(next, cmd, num, ptr);
586
0
        BIO_copy_next_retry(b);
587
0
        break;
588
589
0
    case BIO_C_DO_STATE_MACHINE:
590
0
        BIO_clear_retry_flags(b);
591
0
        ret = BIO_ctrl(next, cmd, num, ptr);
592
0
        BIO_copy_next_retry(b);
593
0
        break;
594
595
0
    case BIO_CTRL_DUP:
596
0
        break;
597
0
    case BIO_CTRL_INFO:
598
0
    case BIO_CTRL_GET:
599
0
    case BIO_CTRL_SET:
600
0
    default:
601
0
        ret = BIO_ctrl(next, cmd, num, ptr);
602
0
        break;
603
0
    }
604
0
    return ret;
605
0
}
606
607
static long b64_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
608
0
{
609
0
    BIO *next = BIO_next(b);
610
611
0
    if (next == NULL)
612
0
        return 0;
613
614
0
    return BIO_callback_ctrl(next, cmd, fp);
615
0
}
616
617
static int b64_puts(BIO *b, const char *str)
618
0
{
619
0
    size_t len = strlen(str);
620
621
0
    if (len > INT_MAX)
622
0
        return -1;
623
0
    return b64_write(b, str, (int)len);
624
0
}