Coverage Report

Created: 2025-06-13 06:23

/src/libspdm/os_stub/mbedtlslib/mbedtls/library/base64.c
Line
Count
Source (jump to first uncovered line)
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
18
#include <stdint.h>
19
20
#if defined(MBEDTLS_SELF_TEST)
21
#include <string.h>
22
#include "mbedtls/platform.h"
23
#endif /* MBEDTLS_SELF_TEST */
24
25
MBEDTLS_STATIC_TESTABLE
26
unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
27
0
{
28
0
    unsigned char digit = 0;
29
    /* For each range of values, if value is in that range, mask digit with
30
     * the corresponding value. Since value can only be in a single range,
31
     * only at most one masking will change digit. */
32
0
    digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);
33
0
    digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);
34
0
    digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);
35
0
    digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');
36
0
    digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');
37
0
    return digit;
38
0
}
39
40
MBEDTLS_STATIC_TESTABLE
41
signed char mbedtls_ct_base64_dec_value(unsigned char c)
42
1.96M
{
43
1.96M
    unsigned char val = 0;
44
    /* For each range of digits, if c is in that range, mask val with
45
     * the corresponding value. Since c can only be in a single range,
46
     * only at most one masking will change val. Set val to one plus
47
     * the desired value so that it stays 0 if c is in none of the ranges. */
48
1.96M
    val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' +  0 + 1);
49
1.96M
    val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
50
1.96M
    val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
51
1.96M
    val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
52
1.96M
    val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1);
53
    /* At this point, val is 0 if c is an invalid digit and v+1 if c is
54
     * a digit with the value v. */
55
1.96M
    return val - 1;
56
1.96M
}
57
58
/*
59
 * Encode a buffer into base64 format
60
 */
61
int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
62
                          const unsigned char *src, size_t slen)
63
0
{
64
0
    size_t i, n;
65
0
    int C1, C2, C3;
66
0
    unsigned char *p;
67
68
0
    if (slen == 0) {
69
0
        *olen = 0;
70
0
        return 0;
71
0
    }
72
73
0
    n = slen / 3 + (slen % 3 != 0);
74
75
0
    if (n > (SIZE_MAX - 1) / 4) {
76
0
        *olen = SIZE_MAX;
77
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
78
0
    }
79
80
0
    n *= 4;
81
82
0
    if ((dlen < n + 1) || (NULL == dst)) {
83
0
        *olen = n + 1;
84
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
85
0
    }
86
87
0
    n = (slen / 3) * 3;
88
89
0
    for (i = 0, p = dst; i < n; i += 3) {
90
0
        C1 = *src++;
91
0
        C2 = *src++;
92
0
        C3 = *src++;
93
94
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
95
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 &  3) << 4) + (C2 >> 4))
96
0
                                          & 0x3F);
97
0
        *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
98
0
                                          & 0x3F);
99
0
        *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
100
0
    }
101
102
0
    if (i < slen) {
103
0
        C1 = *src++;
104
0
        C2 = ((i + 1) < slen) ? *src++ : 0;
105
106
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
107
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
108
0
                                          & 0x3F);
109
110
0
        if ((i + 1) < slen) {
111
0
            *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
112
0
        } else {
113
0
            *p++ = '=';
114
0
        }
115
116
0
        *p++ = '=';
117
0
    }
118
119
0
    *olen = (size_t) (p - dst);
120
0
    *p = 0;
121
122
0
    return 0;
123
0
}
124
125
/*
126
 * Decode a base64-formatted buffer
127
 */
128
int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
129
                          const unsigned char *src, size_t slen)
130
1.36k
{
131
1.36k
    size_t i; /* index in source */
132
1.36k
    size_t n; /* number of digits or trailing = in source */
133
1.36k
    uint32_t x; /* value accumulator */
134
1.36k
    unsigned accumulated_digits = 0;
135
1.36k
    unsigned equals = 0;
136
1.36k
    int spaces_present = 0;
137
1.36k
    unsigned char *p;
138
139
    /* First pass: check for validity and get output length */
140
1.35M
    for (i = n = 0; i < slen; i++) {
141
        /* Skip spaces before checking for EOL */
142
1.34M
        spaces_present = 0;
143
1.34M
        while (i < slen && src[i] == ' ') {
144
0
            ++i;
145
0
            spaces_present = 1;
146
0
        }
147
148
        /* Spaces at end of buffer are OK */
149
1.34M
        if (i == slen) {
150
0
            break;
151
0
        }
152
153
1.34M
        if ((slen - i) >= 2 &&
154
1.34M
            src[i] == '\r' && src[i + 1] == '\n') {
155
20.9k
            continue;
156
20.9k
        }
157
158
1.32M
        if (src[i] == '\n') {
159
20.9k
            continue;
160
20.9k
        }
161
162
        /* Space inside a line is an error */
163
1.30M
        if (spaces_present) {
164
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
165
0
        }
166
167
1.30M
        if (src[i] > 127) {
168
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
169
0
        }
170
171
1.30M
        if (src[i] == '=') {
172
0
            if (++equals > 2) {
173
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
174
0
            }
175
1.30M
        } else {
176
1.30M
            if (equals != 0) {
177
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
178
0
            }
179
1.30M
            if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
180
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
181
0
            }
182
1.30M
        }
183
1.30M
        n++;
184
1.30M
    }
185
186
1.36k
    if (n == 0) {
187
0
        *olen = 0;
188
0
        return 0;
189
0
    }
190
191
    /* The following expression is to calculate the following formula without
192
     * risk of integer overflow in n:
193
     *     n = ( ( n * 6 ) + 7 ) >> 3;
194
     */
195
1.36k
    n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
196
1.36k
    n -= equals;
197
198
1.36k
    if (dst == NULL || dlen < n) {
199
682
        *olen = n;
200
682
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
201
682
    }
202
203
682
    equals = 0;
204
675k
    for (x = 0, p = dst; i > 0; i--, src++) {
205
674k
        if (*src == '\r' || *src == '\n' || *src == ' ') {
206
20.9k
            continue;
207
20.9k
        }
208
209
653k
        x = x << 6;
210
653k
        if (*src == '=') {
211
0
            ++equals;
212
653k
        } else {
213
653k
            x |= mbedtls_ct_base64_dec_value(*src);
214
653k
        }
215
216
653k
        if (++accumulated_digits == 4) {
217
163k
            accumulated_digits = 0;
218
163k
            *p++ = MBEDTLS_BYTE_2(x);
219
163k
            if (equals <= 1) {
220
163k
                *p++ = MBEDTLS_BYTE_1(x);
221
163k
            }
222
163k
            if (equals <= 0) {
223
163k
                *p++ = MBEDTLS_BYTE_0(x);
224
163k
            }
225
163k
        }
226
653k
    }
227
228
682
    *olen = (size_t) (p - dst);
229
230
682
    return 0;
231
1.36k
}
232
233
#if defined(MBEDTLS_SELF_TEST)
234
235
static const unsigned char base64_test_dec[64] =
236
{
237
    0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
238
    0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
239
    0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
240
    0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
241
    0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
242
    0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
243
    0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
244
    0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
245
};
246
247
static const unsigned char base64_test_enc[] =
248
    "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
249
    "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
250
251
/*
252
 * Checkup routine
253
 */
254
int mbedtls_base64_self_test(int verbose)
255
0
{
256
0
    size_t len;
257
0
    const unsigned char *src;
258
0
    unsigned char buffer[128];
259
260
0
    if (verbose != 0) {
261
0
        mbedtls_printf("  Base64 encoding test: ");
262
0
    }
263
264
0
    src = base64_test_dec;
265
266
0
    if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
267
0
        memcmp(base64_test_enc, buffer, 88) != 0) {
268
0
        if (verbose != 0) {
269
0
            mbedtls_printf("failed\n");
270
0
        }
271
272
0
        return 1;
273
0
    }
274
275
0
    if (verbose != 0) {
276
0
        mbedtls_printf("passed\n  Base64 decoding test: ");
277
0
    }
278
279
0
    src = base64_test_enc;
280
281
0
    if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
282
0
        memcmp(base64_test_dec, buffer, 64) != 0) {
283
0
        if (verbose != 0) {
284
0
            mbedtls_printf("failed\n");
285
0
        }
286
287
0
        return 1;
288
0
    }
289
290
0
    if (verbose != 0) {
291
0
        mbedtls_printf("passed\n\n");
292
0
    }
293
294
0
    return 0;
295
0
}
296
297
#endif /* MBEDTLS_SELF_TEST */
298
299
#endif /* MBEDTLS_BASE64_C */