Coverage Report

Created: 2026-03-12 07:05

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