Coverage Report

Created: 2025-09-27 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mbedtls/library/base64.c
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
53.4M
{
44
53.4M
    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
53.4M
    val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' +  0 + 1);
50
53.4M
    val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
51
53.4M
    val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
52
53.4M
    val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
53
53.4M
    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
53.4M
    return val - 1;
57
53.4M
}
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
114k
{
132
114k
    size_t i; /* index in source */
133
114k
    size_t n; /* number of digits or trailing = in source */
134
114k
    uint32_t x; /* value accumulator */
135
114k
    unsigned accumulated_digits = 0;
136
114k
    unsigned equals = 0;
137
114k
    int spaces_present = 0;
138
114k
    unsigned char *p;
139
140
    /* First pass: check for validity and get output length */
141
36.1M
    for (i = n = 0; i < slen; i++) {
142
        /* Skip spaces before checking for EOL */
143
36.0M
        spaces_present = 0;
144
36.0M
        while (i < slen && src[i] == ' ') {
145
25.9k
            ++i;
146
25.9k
            spaces_present = 1;
147
25.9k
        }
148
149
        /* Spaces at end of buffer are OK */
150
36.0M
        if (i == slen) {
151
610
            break;
152
610
        }
153
154
36.0M
        if ((slen - i) >= 2 &&
155
35.9M
            src[i] == '\r' && src[i + 1] == '\n') {
156
6.16k
            continue;
157
6.16k
        }
158
159
36.0M
        if (src[i] == '\n') {
160
246k
            continue;
161
246k
        }
162
163
        /* Space inside a line is an error */
164
35.8M
        if (spaces_present) {
165
274
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
166
274
        }
167
168
35.8M
        if (src[i] > 127) {
169
605
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
170
605
        }
171
172
35.8M
        if (src[i] == '=') {
173
21.1k
            if (++equals > 2) {
174
199
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
175
199
            }
176
35.7M
        } else {
177
35.7M
            if (equals != 0) {
178
213
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
179
213
            }
180
35.7M
            if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
181
1.58k
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
182
1.58k
            }
183
35.7M
        }
184
35.8M
        n++;
185
35.8M
    }
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
111k
    if ((n - equals) % 4 == 1) {
191
1.12k
        return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
192
1.12k
    }
193
110k
    if (n % 4 != 0) {
194
2.02k
        return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
195
2.02k
    }
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
108k
    *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
108k
    if ((*olen != 0 && dst == NULL) || dlen < *olen) {
221
54.0k
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
222
54.0k
    }
223
224
17.8M
    for (x = 0, p = dst; i > 0; i--, src++) {
225
17.7M
        if (*src == '\r' || *src == '\n' || *src == ' ') {
226
129k
            continue;
227
129k
        }
228
17.6M
        if (*src == '=') {
229
            /* We already know from the first loop that equal signs are
230
             * only at the end. */
231
8.75k
            break;
232
8.75k
        }
233
17.6M
        x = x << 6;
234
17.6M
        x |= mbedtls_ct_base64_dec_value(*src);
235
236
17.6M
        if (++accumulated_digits == 4) {
237
4.39M
            accumulated_digits = 0;
238
4.39M
            *p++ = MBEDTLS_BYTE_2(x);
239
4.39M
            *p++ = MBEDTLS_BYTE_1(x);
240
4.39M
            *p++ = MBEDTLS_BYTE_0(x);
241
4.39M
        }
242
17.6M
    }
243
54.1k
    if (accumulated_digits == 3) {
244
7.51k
        *p++ = MBEDTLS_BYTE_2(x << 6);
245
7.51k
        *p++ = MBEDTLS_BYTE_1(x << 6);
246
46.6k
    } else if (accumulated_digits == 2) {
247
1.24k
        *p++ = MBEDTLS_BYTE_2(x << 12);
248
1.24k
    }
249
250
54.1k
    if (*olen != (size_t) (p - dst)) {
251
0
        return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
252
0
    }
253
254
54.1k
    return 0;
255
54.1k
}
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
0
{
280
0
    size_t len;
281
0
    const unsigned char *src;
282
0
    unsigned char buffer[128];
283
284
0
    if (verbose != 0) {
285
0
        mbedtls_printf("  Base64 encoding test: ");
286
0
    }
287
288
0
    src = base64_test_dec;
289
290
0
    if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
291
0
        memcmp(base64_test_enc, buffer, 88) != 0) {
292
0
        if (verbose != 0) {
293
0
            mbedtls_printf("failed\n");
294
0
        }
295
296
0
        return 1;
297
0
    }
298
299
0
    if (verbose != 0) {
300
0
        mbedtls_printf("passed\n  Base64 decoding test: ");
301
0
    }
302
303
0
    src = base64_test_enc;
304
305
0
    if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
306
0
        memcmp(base64_test_dec, buffer, 64) != 0) {
307
0
        if (verbose != 0) {
308
0
            mbedtls_printf("failed\n");
309
0
        }
310
311
0
        return 1;
312
0
    }
313
314
0
    if (verbose != 0) {
315
0
        mbedtls_printf("passed\n\n");
316
0
    }
317
318
0
    return 0;
319
0
}
320
321
#endif /* MBEDTLS_SELF_TEST */
322
323
#endif /* MBEDTLS_BASE64_C */