Coverage Report

Created: 2026-03-31 07:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/third_party/mbedtls/library/base64.cpp
Line
Count
Source
1
/*
2
 *  RFC 1521 base64 encoding/decoding
3
 *
4
 *  Copyright The Mbed TLS Contributors
5
 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6
 */
7
8
#include <limits.h>
9
10
#include "common.h"
11
12
#if defined(MBEDTLS_BASE64_C)
13
14
#include "mbedtls/base64.h"
15
#include "base64_internal.h"
16
#include "constant_time_internal.h"
17
#include "mbedtls/error.h"
18
19
#include <stdint.h>
20
21
#if defined(MBEDTLS_SELF_TEST)
22
#include <string.h>
23
#include "mbedtls/platform.h"
24
#endif /* MBEDTLS_SELF_TEST */
25
26
MBEDTLS_STATIC_TESTABLE
27
unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
28
0
{
29
0
    unsigned char digit = 0;
30
    /* For each range of values, if value is in that range, mask digit with
31
     * the corresponding value. Since value can only be in a single range,
32
     * only at most one masking will change digit. */
33
0
    digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);
34
0
    digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);
35
0
    digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);
36
0
    digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');
37
0
    digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');
38
0
    return digit;
39
0
}
40
41
MBEDTLS_STATIC_TESTABLE
42
signed char mbedtls_ct_base64_dec_value(unsigned char c)
43
0
{
44
0
    unsigned char val = 0;
45
    /* For each range of digits, if c is in that range, mask val with
46
     * the corresponding value. Since c can only be in a single range,
47
     * only at most one masking will change val. Set val to one plus
48
     * the desired value so that it stays 0 if c is in none of the ranges. */
49
0
    val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' +  0 + 1);
50
0
    val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
51
0
    val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
52
0
    val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
53
0
    val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1);
54
    /* At this point, val is 0 if c is an invalid digit and v+1 if c is
55
     * a digit with the value v. */
56
0
    return val - 1;
57
0
}
58
59
/*
60
 * Encode a buffer into base64 format
61
 */
62
int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
63
                          const unsigned char *src, size_t slen)
64
0
{
65
0
    size_t i, n;
66
0
    int C1, C2, C3;
67
0
    unsigned char *p;
68
69
0
    if (slen == 0) {
70
0
        *olen = 0;
71
0
        return 0;
72
0
    }
73
74
0
    n = slen / 3 + (slen % 3 != 0);
75
76
0
    if (n > (SIZE_MAX - 1) / 4) {
77
0
        *olen = SIZE_MAX;
78
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
79
0
    }
80
81
0
    n *= 4;
82
83
0
    if ((dlen < n + 1) || (NULL == dst)) {
84
0
        *olen = n + 1;
85
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
86
0
    }
87
88
0
    n = (slen / 3) * 3;
89
90
0
    for (i = 0, p = dst; i < n; i += 3) {
91
0
        C1 = *src++;
92
0
        C2 = *src++;
93
0
        C3 = *src++;
94
95
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
96
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 &  3) << 4) + (C2 >> 4))
97
0
                                          & 0x3F);
98
0
        *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
99
0
                                          & 0x3F);
100
0
        *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
101
0
    }
102
103
0
    if (i < slen) {
104
0
        C1 = *src++;
105
0
        C2 = ((i + 1) < slen) ? *src++ : 0;
106
107
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
108
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
109
0
                                          & 0x3F);
110
111
0
        if ((i + 1) < slen) {
112
0
            *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
113
0
        } else {
114
0
            *p++ = '=';
115
0
        }
116
117
0
        *p++ = '=';
118
0
    }
119
120
0
    *olen = (size_t) (p - dst);
121
0
    *p = 0;
122
123
0
    return 0;
124
0
}
125
126
/*
127
 * Decode a base64-formatted buffer
128
 */
129
int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
130
                          const unsigned char *src, size_t slen)
131
0
{
132
0
    size_t i; /* index in source */
133
0
    size_t n; /* number of digits or trailing = in source */
134
0
    uint32_t x; /* value accumulator */
135
0
    unsigned accumulated_digits = 0;
136
0
    unsigned equals = 0;
137
0
    int spaces_present = 0;
138
0
    unsigned char *p;
139
140
    /* First pass: check for validity and get output length */
141
0
    for (i = n = 0; i < slen; i++) {
142
        /* Skip spaces before checking for EOL */
143
0
        spaces_present = 0;
144
0
        while (i < slen && src[i] == ' ') {
145
0
            ++i;
146
0
            spaces_present = 1;
147
0
        }
148
149
        /* Spaces at end of buffer are OK */
150
0
        if (i == slen) {
151
0
            break;
152
0
        }
153
154
0
        if ((slen - i) >= 2 &&
155
0
            src[i] == '\r' && src[i + 1] == '\n') {
156
0
            continue;
157
0
        }
158
159
0
        if (src[i] == '\n') {
160
0
            continue;
161
0
        }
162
163
        /* Space inside a line is an error */
164
0
        if (spaces_present) {
165
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
166
0
        }
167
168
0
        if (src[i] > 127) {
169
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
170
0
        }
171
172
0
        if (src[i] == '=') {
173
0
            if (++equals > 2) {
174
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
175
0
            }
176
0
        } else {
177
0
            if (equals != 0) {
178
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
179
0
            }
180
0
            if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
181
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
182
0
            }
183
0
        }
184
0
        n++;
185
0
    }
186
187
    /* In valid base64, the number of digits (n-equals) is always of the form
188
     * 4*k, 4*k+2 or *4k+3. Also, the number n of digits plus the number of
189
     * equal signs at the end is always a multiple of 4. */
190
0
    if ((n - equals) % 4 == 1) {
191
0
        return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
192
0
    }
193
0
    if (n % 4 != 0) {
194
0
        return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
195
0
    }
196
197
    /* We've determined that the input is valid, and that it contains
198
     * exactly k blocks of digits-or-equals, with n = 4 * k,
199
     * and equals only present at the end of the last block if at all.
200
     * Now we can calculate the length of the output.
201
     *
202
     * Each block of 4 digits in the input map to 3 bytes of output.
203
     * For the last block:
204
     * - abcd (where abcd are digits) is a full 3-byte block;
205
     * - abc= means 1 byte less than a full 3-byte block of output;
206
     * - ab== means 2 bytes less than a full 3-byte block of output;
207
     * - a==== and ==== is rejected above.
208
     */
209
0
    *olen = (n / 4) * 3 - equals;
210
211
    /* If the output buffer is too small, signal this and stop here.
212
     * Also, as documented, stop here if `dst` is null, independently of
213
     * `dlen`.
214
     *
215
     * There is an edge case when the output is empty: in this case,
216
     * `dlen == 0` with `dst == NULL` is valid (on some platforms,
217
     * `malloc(0)` returns `NULL`). Since the call is valid, we return
218
     * 0 in this case.
219
     */
220
0
    if ((*olen != 0 && dst == NULL) || dlen < *olen) {
221
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
222
0
    }
223
224
0
    for (x = 0, p = dst; i > 0; i--, src++) {
225
0
        if (*src == '\r' || *src == '\n' || *src == ' ') {
226
0
            continue;
227
0
        }
228
0
        if (*src == '=') {
229
            /* We already know from the first loop that equal signs are
230
             * only at the end. */
231
0
            break;
232
0
        }
233
0
        x = x << 6;
234
0
        x |= mbedtls_ct_base64_dec_value(*src);
235
236
0
        if (++accumulated_digits == 4) {
237
0
            accumulated_digits = 0;
238
0
            *p++ = MBEDTLS_BYTE_2(x);
239
0
            *p++ = MBEDTLS_BYTE_1(x);
240
0
            *p++ = MBEDTLS_BYTE_0(x);
241
0
        }
242
0
    }
243
0
    if (accumulated_digits == 3) {
244
0
        *p++ = MBEDTLS_BYTE_2(x << 6);
245
0
        *p++ = MBEDTLS_BYTE_1(x << 6);
246
0
    } else if (accumulated_digits == 2) {
247
0
        *p++ = MBEDTLS_BYTE_2(x << 12);
248
0
    }
249
250
0
    if (*olen != (size_t) (p - dst)) {
251
0
        return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
252
0
    }
253
254
0
    return 0;
255
0
}
256
257
#if defined(MBEDTLS_SELF_TEST)
258
259
static const unsigned char base64_test_dec[64] =
260
{
261
    0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
262
    0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
263
    0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
264
    0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
265
    0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
266
    0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
267
    0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
268
    0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
269
};
270
271
static const unsigned char base64_test_enc[] =
272
    "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
273
    "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
274
275
/*
276
 * Checkup routine
277
 */
278
int mbedtls_base64_self_test(int verbose)
279
{
280
    size_t len;
281
    const unsigned char *src;
282
    unsigned char buffer[128];
283
284
    if (verbose != 0) {
285
        mbedtls_printf("  Base64 encoding test: ");
286
    }
287
288
    src = base64_test_dec;
289
290
    if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
291
        memcmp(base64_test_enc, buffer, 88) != 0) {
292
        if (verbose != 0) {
293
            mbedtls_printf("failed\n");
294
        }
295
296
        return 1;
297
    }
298
299
    if (verbose != 0) {
300
        mbedtls_printf("passed\n  Base64 decoding test: ");
301
    }
302
303
    src = base64_test_enc;
304
305
    if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
306
        memcmp(base64_test_dec, buffer, 64) != 0) {
307
        if (verbose != 0) {
308
            mbedtls_printf("failed\n");
309
        }
310
311
        return 1;
312
    }
313
314
    if (verbose != 0) {
315
        mbedtls_printf("passed\n\n");
316
    }
317
318
    return 0;
319
}
320
321
#endif /* MBEDTLS_SELF_TEST */
322
323
#endif /* MBEDTLS_BASE64_C */