Coverage Report

Created: 2022-11-30 06:20

/src/openssl/crypto/evp/bio_b64.c
Line
Count
Source (jump to first uncovered line)
1
/* crypto/evp/bio_b64.c */
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3
 * All rights reserved.
4
 *
5
 * This package is an SSL implementation written
6
 * by Eric Young (eay@cryptsoft.com).
7
 * The implementation was written so as to conform with Netscapes SSL.
8
 *
9
 * This library is free for commercial and non-commercial use as long as
10
 * the following conditions are aheared to.  The following conditions
11
 * apply to all code found in this distribution, be it the RC4, RSA,
12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13
 * included with this distribution is covered by the same copyright terms
14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15
 *
16
 * Copyright remains Eric Young's, and as such any Copyright notices in
17
 * the code are not to be removed.
18
 * If this package is used in a product, Eric Young should be given attribution
19
 * as the author of the parts of the library used.
20
 * This can be in the form of a textual message at program startup or
21
 * in documentation (online or textual) provided with the package.
22
 *
23
 * Redistribution and use in source and binary forms, with or without
24
 * modification, are permitted provided that the following conditions
25
 * are met:
26
 * 1. Redistributions of source code must retain the copyright
27
 *    notice, this list of conditions and the following disclaimer.
28
 * 2. Redistributions in binary form must reproduce the above copyright
29
 *    notice, this list of conditions and the following disclaimer in the
30
 *    documentation and/or other materials provided with the distribution.
31
 * 3. All advertising materials mentioning features or use of this software
32
 *    must display the following acknowledgement:
33
 *    "This product includes cryptographic software written by
34
 *     Eric Young (eay@cryptsoft.com)"
35
 *    The word 'cryptographic' can be left out if the rouines from the library
36
 *    being used are not cryptographic related :-).
37
 * 4. If you include any Windows specific code (or a derivative thereof) from
38
 *    the apps directory (application code) you must include an acknowledgement:
39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40
 *
41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51
 * SUCH DAMAGE.
52
 *
53
 * The licence and distribution terms for any publically available version or
54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55
 * copied and put under another distribution licence
56
 * [including the GNU Public Licence.]
57
 */
58
59
#include <stdio.h>
60
#include <errno.h>
61
#include "cryptlib.h"
62
#include <openssl/buffer.h>
63
#include <openssl/evp.h>
64
65
static int b64_write(BIO *h, const char *buf, int num);
66
static int b64_read(BIO *h, char *buf, int size);
67
static int b64_puts(BIO *h, const char *str);
68
/*
69
 * static int b64_gets(BIO *h, char *str, int size);
70
 */
71
static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
72
static int b64_new(BIO *h);
73
static int b64_free(BIO *data);
74
static long b64_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
75
0
#define B64_BLOCK_SIZE  1024
76
#define B64_BLOCK_SIZE2 768
77
0
#define B64_NONE        0
78
0
#define B64_ENCODE      1
79
0
#define B64_DECODE      2
80
81
typedef struct b64_struct {
82
    /*
83
     * BIO *bio; moved to the BIO structure
84
     */
85
    int buf_len;
86
    int buf_off;
87
    int tmp_len;                /* used to find the start when decoding */
88
    int tmp_nl;                 /* If true, scan until '\n' */
89
    int encode;
90
    int start;                  /* have we started decoding yet? */
91
    int cont;                   /* <= 0 when finished */
92
    EVP_ENCODE_CTX base64;
93
    char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10];
94
    char tmp[B64_BLOCK_SIZE];
95
} BIO_B64_CTX;
96
97
static BIO_METHOD methods_b64 = {
98
    BIO_TYPE_BASE64, "base64 encoding",
99
    b64_write,
100
    b64_read,
101
    b64_puts,
102
    NULL,                       /* b64_gets, */
103
    b64_ctrl,
104
    b64_new,
105
    b64_free,
106
    b64_callback_ctrl,
107
};
108
109
BIO_METHOD *BIO_f_base64(void)
110
0
{
111
0
    return (&methods_b64);
112
0
}
113
114
static int b64_new(BIO *bi)
115
0
{
116
0
    BIO_B64_CTX *ctx;
117
118
0
    ctx = (BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX));
119
0
    if (ctx == NULL)
120
0
        return (0);
121
122
0
    ctx->buf_len = 0;
123
0
    ctx->tmp_len = 0;
124
0
    ctx->tmp_nl = 0;
125
0
    ctx->buf_off = 0;
126
0
    ctx->cont = 1;
127
0
    ctx->start = 1;
128
0
    ctx->encode = 0;
129
130
0
    bi->init = 1;
131
0
    bi->ptr = (char *)ctx;
132
0
    bi->flags = 0;
133
0
    bi->num = 0;
134
0
    return (1);
135
0
}
136
137
static int b64_free(BIO *a)
138
0
{
139
0
    if (a == NULL)
140
0
        return (0);
141
0
    OPENSSL_free(a->ptr);
142
0
    a->ptr = NULL;
143
0
    a->init = 0;
144
0
    a->flags = 0;
145
0
    return (1);
146
0
}
147
148
static int b64_read(BIO *b, char *out, int outl)
149
0
{
150
0
    int ret = 0, i, ii, j, k, x, n, num, ret_code = 0;
151
0
    BIO_B64_CTX *ctx;
152
0
    unsigned char *p, *q;
153
154
0
    if (out == NULL)
155
0
        return (0);
156
0
    ctx = (BIO_B64_CTX *)b->ptr;
157
158
0
    if ((ctx == NULL) || (b->next_bio == NULL))
159
0
        return (0);
160
161
0
    BIO_clear_retry_flags(b);
162
163
0
    if (ctx->encode != B64_DECODE) {
164
0
        ctx->encode = B64_DECODE;
165
0
        ctx->buf_len = 0;
166
0
        ctx->buf_off = 0;
167
0
        ctx->tmp_len = 0;
168
0
        EVP_DecodeInit(&(ctx->base64));
169
0
    }
170
171
    /* First check if there are bytes decoded/encoded */
172
0
    if (ctx->buf_len > 0) {
173
0
        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
174
0
        i = ctx->buf_len - ctx->buf_off;
175
0
        if (i > outl)
176
0
            i = outl;
177
0
        OPENSSL_assert(ctx->buf_off + i < (int)sizeof(ctx->buf));
178
0
        memcpy(out, &(ctx->buf[ctx->buf_off]), i);
179
0
        ret = i;
180
0
        out += i;
181
0
        outl -= i;
182
0
        ctx->buf_off += i;
183
0
        if (ctx->buf_len == ctx->buf_off) {
184
0
            ctx->buf_len = 0;
185
0
            ctx->buf_off = 0;
186
0
        }
187
0
    }
188
189
    /*
190
     * At this point, we have room of outl bytes and an empty buffer, so we
191
     * should read in some more.
192
     */
193
194
0
    ret_code = 0;
195
0
    while (outl > 0) {
196
0
        if (ctx->cont <= 0)
197
0
            break;
198
199
0
        i = BIO_read(b->next_bio, &(ctx->tmp[ctx->tmp_len]),
200
0
                     B64_BLOCK_SIZE - ctx->tmp_len);
201
202
0
        if (i <= 0) {
203
0
            ret_code = i;
204
205
            /* Should we continue next time we are called? */
206
0
            if (!BIO_should_retry(b->next_bio)) {
207
0
                ctx->cont = i;
208
                /* If buffer empty break */
209
0
                if (ctx->tmp_len == 0)
210
0
                    break;
211
                /* Fall through and process what we have */
212
0
                else
213
0
                    i = 0;
214
0
            }
215
            /* else we retry and add more data to buffer */
216
0
            else
217
0
                break;
218
0
        }
219
0
        i += ctx->tmp_len;
220
0
        ctx->tmp_len = i;
221
222
        /*
223
         * We need to scan, a line at a time until we have a valid line if we
224
         * are starting.
225
         */
226
0
        if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) {
227
            /* ctx->start=1; */
228
0
            ctx->tmp_len = 0;
229
0
        } else if (ctx->start) {
230
0
            q = p = (unsigned char *)ctx->tmp;
231
0
            num = 0;
232
0
            for (j = 0; j < i; j++) {
233
0
                if (*(q++) != '\n')
234
0
                    continue;
235
236
                /*
237
                 * due to a previous very long line, we need to keep on
238
                 * scanning for a '\n' before we even start looking for
239
                 * base64 encoded stuff.
240
                 */
241
0
                if (ctx->tmp_nl) {
242
0
                    p = q;
243
0
                    ctx->tmp_nl = 0;
244
0
                    continue;
245
0
                }
246
247
0
                k = EVP_DecodeUpdate(&(ctx->base64),
248
0
                                     (unsigned char *)ctx->buf,
249
0
                                     &num, p, q - p);
250
0
                if ((k <= 0) && (num == 0) && (ctx->start))
251
0
                    EVP_DecodeInit(&ctx->base64);
252
0
                else {
253
0
                    if (p != (unsigned char *)
254
0
                        &(ctx->tmp[0])) {
255
0
                        i -= (p - (unsigned char *)
256
0
                              &(ctx->tmp[0]));
257
0
                        for (x = 0; x < i; x++)
258
0
                            ctx->tmp[x] = p[x];
259
0
                    }
260
0
                    EVP_DecodeInit(&ctx->base64);
261
0
                    ctx->start = 0;
262
0
                    break;
263
0
                }
264
0
                p = q;
265
0
            }
266
267
            /* we fell off the end without starting */
268
0
            if ((j == i) && (num == 0)) {
269
                /*
270
                 * Is this is one long chunk?, if so, keep on reading until a
271
                 * new line.
272
                 */
273
0
                if (p == (unsigned char *)&(ctx->tmp[0])) {
274
                    /* Check buffer full */
275
0
                    if (i == B64_BLOCK_SIZE) {
276
0
                        ctx->tmp_nl = 1;
277
0
                        ctx->tmp_len = 0;
278
0
                    }
279
0
                } else if (p != q) { /* finished on a '\n' */
280
0
                    n = q - p;
281
0
                    for (ii = 0; ii < n; ii++)
282
0
                        ctx->tmp[ii] = p[ii];
283
0
                    ctx->tmp_len = n;
284
0
                }
285
                /* else finished on a '\n' */
286
0
                continue;
287
0
            } else {
288
0
                ctx->tmp_len = 0;
289
0
            }
290
0
        } else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) {
291
            /*
292
             * If buffer isn't full and we can retry then restart to read in
293
             * more data.
294
             */
295
0
            continue;
296
0
        }
297
298
0
        if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
299
0
            int z, jj;
300
301
#if 0
302
            jj = (i >> 2) << 2;
303
#else
304
0
            jj = i & ~3;        /* process per 4 */
305
0
#endif
306
0
            z = EVP_DecodeBlock((unsigned char *)ctx->buf,
307
0
                                (unsigned char *)ctx->tmp, jj);
308
0
            if (jj > 2) {
309
0
                if (ctx->tmp[jj - 1] == '=') {
310
0
                    z--;
311
0
                    if (ctx->tmp[jj - 2] == '=')
312
0
                        z--;
313
0
                }
314
0
            }
315
            /*
316
             * z is now number of output bytes and jj is the number consumed
317
             */
318
0
            if (jj != i) {
319
0
                memmove(ctx->tmp, &ctx->tmp[jj], i - jj);
320
0
                ctx->tmp_len = i - jj;
321
0
            }
322
0
            ctx->buf_len = 0;
323
0
            if (z > 0) {
324
0
                ctx->buf_len = z;
325
0
            }
326
0
            i = z;
327
0
        } else {
328
0
            i = EVP_DecodeUpdate(&(ctx->base64),
329
0
                                 (unsigned char *)ctx->buf, &ctx->buf_len,
330
0
                                 (unsigned char *)ctx->tmp, i);
331
0
            ctx->tmp_len = 0;
332
0
        }
333
0
        ctx->buf_off = 0;
334
0
        if (i < 0) {
335
0
            ret_code = 0;
336
0
            ctx->buf_len = 0;
337
0
            break;
338
0
        }
339
340
0
        if (ctx->buf_len <= outl)
341
0
            i = ctx->buf_len;
342
0
        else
343
0
            i = outl;
344
345
0
        memcpy(out, ctx->buf, i);
346
0
        ret += i;
347
0
        ctx->buf_off = i;
348
0
        if (ctx->buf_off == ctx->buf_len) {
349
0
            ctx->buf_len = 0;
350
0
            ctx->buf_off = 0;
351
0
        }
352
0
        outl -= i;
353
0
        out += i;
354
0
    }
355
    /* BIO_clear_retry_flags(b); */
356
0
    BIO_copy_next_retry(b);
357
0
    return ((ret == 0) ? ret_code : ret);
358
0
}
359
360
static int b64_write(BIO *b, const char *in, int inl)
361
0
{
362
0
    int ret = 0;
363
0
    int n;
364
0
    int i;
365
0
    BIO_B64_CTX *ctx;
366
367
0
    ctx = (BIO_B64_CTX *)b->ptr;
368
0
    BIO_clear_retry_flags(b);
369
370
0
    if (ctx->encode != B64_ENCODE) {
371
0
        ctx->encode = B64_ENCODE;
372
0
        ctx->buf_len = 0;
373
0
        ctx->buf_off = 0;
374
0
        ctx->tmp_len = 0;
375
0
        EVP_EncodeInit(&(ctx->base64));
376
0
    }
377
378
0
    OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf));
379
0
    OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
380
0
    OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
381
0
    n = ctx->buf_len - ctx->buf_off;
382
0
    while (n > 0) {
383
0
        i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
384
0
        if (i <= 0) {
385
0
            BIO_copy_next_retry(b);
386
0
            return (i);
387
0
        }
388
0
        OPENSSL_assert(i <= n);
389
0
        ctx->buf_off += i;
390
0
        OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
391
0
        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
392
0
        n -= i;
393
0
    }
394
    /* at this point all pending data has been written */
395
0
    ctx->buf_off = 0;
396
0
    ctx->buf_len = 0;
397
398
0
    if ((in == NULL) || (inl <= 0))
399
0
        return (0);
400
401
0
    while (inl > 0) {
402
0
        n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl;
403
404
0
        if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
405
0
            if (ctx->tmp_len > 0) {
406
0
                OPENSSL_assert(ctx->tmp_len <= 3);
407
0
                n = 3 - ctx->tmp_len;
408
                /*
409
                 * There's a theoretical possibility for this
410
                 */
411
0
                if (n > inl)
412
0
                    n = inl;
413
0
                memcpy(&(ctx->tmp[ctx->tmp_len]), in, n);
414
0
                ctx->tmp_len += n;
415
0
                ret += n;
416
0
                if (ctx->tmp_len < 3)
417
0
                    break;
418
0
                ctx->buf_len =
419
0
                    EVP_EncodeBlock((unsigned char *)ctx->buf,
420
0
                                    (unsigned char *)ctx->tmp, ctx->tmp_len);
421
0
                OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
422
0
                OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
423
                /*
424
                 * Since we're now done using the temporary buffer, the
425
                 * length should be 0'd
426
                 */
427
0
                ctx->tmp_len = 0;
428
0
            } else {
429
0
                if (n < 3) {
430
0
                    memcpy(ctx->tmp, in, n);
431
0
                    ctx->tmp_len = n;
432
0
                    ret += n;
433
0
                    break;
434
0
                }
435
0
                n -= n % 3;
436
0
                ctx->buf_len =
437
0
                    EVP_EncodeBlock((unsigned char *)ctx->buf,
438
0
                                    (const unsigned char *)in, n);
439
0
                OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
440
0
                OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
441
0
                ret += n;
442
0
            }
443
0
        } else {
444
0
            EVP_EncodeUpdate(&(ctx->base64),
445
0
                             (unsigned char *)ctx->buf, &ctx->buf_len,
446
0
                             (unsigned char *)in, n);
447
0
            OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
448
0
            OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
449
0
            ret += n;
450
0
        }
451
0
        inl -= n;
452
0
        in += n;
453
454
0
        ctx->buf_off = 0;
455
0
        n = ctx->buf_len;
456
0
        while (n > 0) {
457
0
            i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
458
0
            if (i <= 0) {
459
0
                BIO_copy_next_retry(b);
460
0
                return ((ret == 0) ? i : ret);
461
0
            }
462
0
            OPENSSL_assert(i <= n);
463
0
            n -= i;
464
0
            ctx->buf_off += i;
465
0
            OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
466
0
            OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
467
0
        }
468
0
        ctx->buf_len = 0;
469
0
        ctx->buf_off = 0;
470
0
    }
471
0
    return (ret);
472
0
}
473
474
static long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
475
0
{
476
0
    BIO_B64_CTX *ctx;
477
0
    long ret = 1;
478
0
    int i;
479
480
0
    ctx = (BIO_B64_CTX *)b->ptr;
481
482
0
    switch (cmd) {
483
0
    case BIO_CTRL_RESET:
484
0
        ctx->cont = 1;
485
0
        ctx->start = 1;
486
0
        ctx->encode = B64_NONE;
487
0
        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
488
0
        break;
489
0
    case BIO_CTRL_EOF:         /* More to read */
490
0
        if (ctx->cont <= 0)
491
0
            ret = 1;
492
0
        else
493
0
            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
494
0
        break;
495
0
    case BIO_CTRL_WPENDING:    /* More to write in buffer */
496
0
        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
497
0
        ret = ctx->buf_len - ctx->buf_off;
498
0
        if ((ret == 0) && (ctx->encode != B64_NONE)
499
0
            && (ctx->base64.num != 0))
500
0
            ret = 1;
501
0
        else if (ret <= 0)
502
0
            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
503
0
        break;
504
0
    case BIO_CTRL_PENDING:     /* More to read in buffer */
505
0
        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
506
0
        ret = ctx->buf_len - ctx->buf_off;
507
0
        if (ret <= 0)
508
0
            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
509
0
        break;
510
0
    case BIO_CTRL_FLUSH:
511
        /* do a final write */
512
0
 again:
513
0
        while (ctx->buf_len != ctx->buf_off) {
514
0
            i = b64_write(b, NULL, 0);
515
0
            if (i < 0)
516
0
                return i;
517
0
        }
518
0
        if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
519
0
            if (ctx->tmp_len != 0) {
520
0
                ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf,
521
0
                                               (unsigned char *)ctx->tmp,
522
0
                                               ctx->tmp_len);
523
0
                ctx->buf_off = 0;
524
0
                ctx->tmp_len = 0;
525
0
                goto again;
526
0
            }
527
0
        } else if (ctx->encode != B64_NONE && ctx->base64.num != 0) {
528
0
            ctx->buf_off = 0;
529
0
            EVP_EncodeFinal(&(ctx->base64),
530
0
                            (unsigned char *)ctx->buf, &(ctx->buf_len));
531
            /* push out the bytes */
532
0
            goto again;
533
0
        }
534
        /* Finally flush the underlying BIO */
535
0
        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
536
0
        break;
537
538
0
    case BIO_C_DO_STATE_MACHINE:
539
0
        BIO_clear_retry_flags(b);
540
0
        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
541
0
        BIO_copy_next_retry(b);
542
0
        break;
543
544
0
    case BIO_CTRL_DUP:
545
0
        break;
546
0
    case BIO_CTRL_INFO:
547
0
    case BIO_CTRL_GET:
548
0
    case BIO_CTRL_SET:
549
0
    default:
550
0
        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
551
0
        break;
552
0
    }
553
0
    return (ret);
554
0
}
555
556
static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
557
0
{
558
0
    long ret = 1;
559
560
0
    if (b->next_bio == NULL)
561
0
        return (0);
562
0
    switch (cmd) {
563
0
    default:
564
0
        ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
565
0
        break;
566
0
    }
567
0
    return (ret);
568
0
}
569
570
static int b64_puts(BIO *b, const char *str)
571
0
{
572
0
    return b64_write(b, str, strlen(str));
573
0
}