Coverage Report

Created: 2023-03-26 10:06

/src/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
6
 *
7
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8
 *  not use this file except in compliance with the License.
9
 *  You may obtain a copy of the License at
10
 *
11
 *  http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 *  Unless required by applicable law or agreed to in writing, software
14
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 *  See the License for the specific language governing permissions and
17
 *  limitations under the License.
18
 */
19
20
#include "common.h"
21
22
#if defined(MBEDTLS_BASE64_C)
23
24
#include "mbedtls/base64.h"
25
#include "constant_time_internal.h"
26
27
#include <stdint.h>
28
29
#if defined(MBEDTLS_SELF_TEST)
30
#include <string.h>
31
#include "mbedtls/platform.h"
32
#endif /* MBEDTLS_SELF_TEST */
33
34
0
#define BASE64_SIZE_T_MAX   ((size_t) -1)   /* SIZE_T_MAX is not standard */
35
36
/*
37
 * Encode a buffer into base64 format
38
 */
39
int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
40
                          const unsigned char *src, size_t slen)
41
0
{
42
0
    size_t i, n;
43
0
    int C1, C2, C3;
44
0
    unsigned char *p;
45
46
0
    if (slen == 0) {
47
0
        *olen = 0;
48
0
        return 0;
49
0
    }
50
51
0
    n = slen / 3 + (slen % 3 != 0);
52
53
0
    if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
54
0
        *olen = BASE64_SIZE_T_MAX;
55
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
56
0
    }
57
58
0
    n *= 4;
59
60
0
    if ((dlen < n + 1) || (NULL == dst)) {
61
0
        *olen = n + 1;
62
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
63
0
    }
64
65
0
    n = (slen / 3) * 3;
66
67
0
    for (i = 0, p = dst; i < n; i += 3) {
68
0
        C1 = *src++;
69
0
        C2 = *src++;
70
0
        C3 = *src++;
71
72
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
73
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 &  3) << 4) + (C2 >> 4))
74
0
                                          & 0x3F);
75
0
        *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
76
0
                                          & 0x3F);
77
0
        *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
78
0
    }
79
80
0
    if (i < slen) {
81
0
        C1 = *src++;
82
0
        C2 = ((i + 1) < slen) ? *src++ : 0;
83
84
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
85
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
86
0
                                          & 0x3F);
87
88
0
        if ((i + 1) < slen) {
89
0
            *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
90
0
        } else {
91
0
            *p++ = '=';
92
0
        }
93
94
0
        *p++ = '=';
95
0
    }
96
97
0
    *olen = p - dst;
98
0
    *p = 0;
99
100
0
    return 0;
101
0
}
102
103
/*
104
 * Decode a base64-formatted buffer
105
 */
106
int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
107
                          const unsigned char *src, size_t slen)
108
10.8k
{
109
10.8k
    size_t i; /* index in source */
110
10.8k
    size_t n; /* number of digits or trailing = in source */
111
10.8k
    uint32_t x; /* value accumulator */
112
10.8k
    unsigned accumulated_digits = 0;
113
10.8k
    unsigned equals = 0;
114
10.8k
    int spaces_present = 0;
115
10.8k
    unsigned char *p;
116
117
    /* First pass: check for validity and get output length */
118
10.9M
    for (i = n = 0; i < slen; i++) {
119
        /* Skip spaces before checking for EOL */
120
10.8M
        spaces_present = 0;
121
10.8M
        while (i < slen && src[i] == ' ') {
122
0
            ++i;
123
0
            spaces_present = 1;
124
0
        }
125
126
        /* Spaces at end of buffer are OK */
127
10.8M
        if (i == slen) {
128
0
            break;
129
0
        }
130
131
10.8M
        if ((slen - i) >= 2 &&
132
10.8M
            src[i] == '\r' && src[i + 1] == '\n') {
133
169k
            continue;
134
169k
        }
135
136
10.7M
        if (src[i] == '\n') {
137
169k
            continue;
138
169k
        }
139
140
        /* Space inside a line is an error */
141
10.5M
        if (spaces_present) {
142
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
143
0
        }
144
145
10.5M
        if (src[i] > 127) {
146
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
147
0
        }
148
149
10.5M
        if (src[i] == '=') {
150
7.21k
            if (++equals > 2) {
151
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
152
0
            }
153
10.5M
        } else {
154
10.5M
            if (equals != 0) {
155
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
156
0
            }
157
10.5M
            if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
158
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
159
0
            }
160
10.5M
        }
161
10.5M
        n++;
162
10.5M
    }
163
164
10.8k
    if (n == 0) {
165
0
        *olen = 0;
166
0
        return 0;
167
0
    }
168
169
    /* The following expression is to calculate the following formula without
170
     * risk of integer overflow in n:
171
     *     n = ( ( n * 6 ) + 7 ) >> 3;
172
     */
173
10.8k
    n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
174
10.8k
    n -= equals;
175
176
10.8k
    if (dst == NULL || dlen < n) {
177
5.40k
        *olen = n;
178
5.40k
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
179
5.40k
    }
180
181
5.40k
    equals = 0;
182
5.45M
    for (x = 0, p = dst; i > 0; i--, src++) {
183
5.44M
        if (*src == '\r' || *src == '\n' || *src == ' ') {
184
169k
            continue;
185
169k
        }
186
187
5.27M
        x = x << 6;
188
5.27M
        if (*src == '=') {
189
3.60k
            ++equals;
190
5.27M
        } else {
191
5.27M
            x |= mbedtls_ct_base64_dec_value(*src);
192
5.27M
        }
193
194
5.27M
        if (++accumulated_digits == 4) {
195
1.31M
            accumulated_digits = 0;
196
1.31M
            *p++ = MBEDTLS_BYTE_2(x);
197
1.31M
            if (equals <= 1) {
198
1.31M
                *p++ = MBEDTLS_BYTE_1(x);
199
1.31M
            }
200
1.31M
            if (equals <= 0) {
201
1.31M
                *p++ = MBEDTLS_BYTE_0(x);
202
1.31M
            }
203
1.31M
        }
204
5.27M
    }
205
206
5.40k
    *olen = p - dst;
207
208
5.40k
    return 0;
209
10.8k
}
210
211
#if defined(MBEDTLS_SELF_TEST)
212
213
static const unsigned char base64_test_dec[64] =
214
{
215
    0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
216
    0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
217
    0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
218
    0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
219
    0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
220
    0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
221
    0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
222
    0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
223
};
224
225
static const unsigned char base64_test_enc[] =
226
    "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
227
    "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
228
229
/*
230
 * Checkup routine
231
 */
232
int mbedtls_base64_self_test(int verbose)
233
0
{
234
0
    size_t len;
235
0
    const unsigned char *src;
236
0
    unsigned char buffer[128];
237
238
0
    if (verbose != 0) {
239
0
        mbedtls_printf("  Base64 encoding test: ");
240
0
    }
241
242
0
    src = base64_test_dec;
243
244
0
    if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
245
0
        memcmp(base64_test_enc, buffer, 88) != 0) {
246
0
        if (verbose != 0) {
247
0
            mbedtls_printf("failed\n");
248
0
        }
249
250
0
        return 1;
251
0
    }
252
253
0
    if (verbose != 0) {
254
0
        mbedtls_printf("passed\n  Base64 decoding test: ");
255
0
    }
256
257
0
    src = base64_test_enc;
258
259
0
    if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
260
0
        memcmp(base64_test_dec, buffer, 64) != 0) {
261
0
        if (verbose != 0) {
262
0
            mbedtls_printf("failed\n");
263
0
        }
264
265
0
        return 1;
266
0
    }
267
268
0
    if (verbose != 0) {
269
0
        mbedtls_printf("passed\n\n");
270
0
    }
271
272
0
    return 0;
273
0
}
274
275
#endif /* MBEDTLS_SELF_TEST */
276
277
#endif /* MBEDTLS_BASE64_C */