Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libspdm/os_stub/mbedtlslib/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
1.92M
{
44
1.92M
    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
1.92M
    val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' +  0 + 1);
50
1.92M
    val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
51
1.92M
    val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
52
1.92M
    val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
53
1.92M
    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
1.92M
    return val - 1;
57
1.92M
}
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
1.40k
{
132
1.40k
    size_t i; /* index in source */
133
1.40k
    size_t n; /* number of digits or trailing = in source */
134
1.40k
    uint32_t x; /* value accumulator */
135
1.40k
    unsigned accumulated_digits = 0;
136
1.40k
    unsigned equals = 0;
137
1.40k
    int spaces_present = 0;
138
1.40k
    unsigned char *p;
139
140
    /* First pass: check for validity and get output length */
141
1.32M
    for (i = n = 0; i < slen; i++) {
142
        /* Skip spaces before checking for EOL */
143
1.32M
        spaces_present = 0;
144
1.32M
        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
1.32M
        if (i == slen) {
151
0
            break;
152
0
        }
153
154
1.32M
        if ((slen - i) >= 2 &&
155
1.31M
            src[i] == '\r' && src[i + 1] == '\n') {
156
20.5k
            continue;
157
20.5k
        }
158
159
1.30M
        if (src[i] == '\n') {
160
20.5k
            continue;
161
20.5k
        }
162
163
        /* Space inside a line is an error */
164
1.28M
        if (spaces_present) {
165
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
166
0
        }
167
168
1.28M
        if (src[i] > 127) {
169
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
170
0
        }
171
172
1.28M
        if (src[i] == '=') {
173
0
            if (++equals > 2) {
174
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
175
0
            }
176
1.28M
        } else {
177
1.28M
            if (equals != 0) {
178
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
179
0
            }
180
1.28M
            if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
181
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
182
0
            }
183
1.28M
        }
184
1.28M
        n++;
185
1.28M
    }
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
1.40k
    if ((n - equals) % 4 == 1) {
191
0
        return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
192
0
    }
193
1.40k
    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
1.40k
    *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
1.40k
    if ((*olen != 0 && dst == NULL) || dlen < *olen) {
221
700
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
222
700
    }
223
224
661k
    for (x = 0, p = dst; i > 0; i--, src++) {
225
660k
        if (*src == '\r' || *src == '\n' || *src == ' ') {
226
20.5k
            continue;
227
20.5k
        }
228
640k
        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
640k
        x = x << 6;
234
640k
        x |= mbedtls_ct_base64_dec_value(*src);
235
236
640k
        if (++accumulated_digits == 4) {
237
160k
            accumulated_digits = 0;
238
160k
            *p++ = MBEDTLS_BYTE_2(x);
239
160k
            *p++ = MBEDTLS_BYTE_1(x);
240
160k
            *p++ = MBEDTLS_BYTE_0(x);
241
160k
        }
242
640k
    }
243
700
    if (accumulated_digits == 3) {
244
0
        *p++ = MBEDTLS_BYTE_2(x << 6);
245
0
        *p++ = MBEDTLS_BYTE_1(x << 6);
246
700
    } else if (accumulated_digits == 2) {
247
0
        *p++ = MBEDTLS_BYTE_2(x << 12);
248
0
    }
249
250
700
    if (*olen != (size_t) (p - dst)) {
251
0
        return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
252
0
    }
253
254
700
    return 0;
255
700
}
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 */