xref: /optee_os/lib/libmbedtls/mbedtls/library/base64.c (revision 3d0429ac12cd2ab11c047b0814ac2f833471bbfb)
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 {
29     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     digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);
34     digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);
35     digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);
36     digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');
37     digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');
38     return digit;
39 }
40 
41 MBEDTLS_STATIC_TESTABLE
42 signed char mbedtls_ct_base64_dec_value(unsigned char c)
43 {
44     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     val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' +  0 + 1);
50     val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
51     val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
52     val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
53     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     return val - 1;
57 }
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 {
65     size_t i, n;
66     int C1, C2, C3;
67     unsigned char *p;
68 
69     if (slen == 0) {
70         *olen = 0;
71         return 0;
72     }
73 
74     n = slen / 3 + (slen % 3 != 0);
75 
76     if (n > (SIZE_MAX - 1) / 4) {
77         *olen = SIZE_MAX;
78         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
79     }
80 
81     n *= 4;
82 
83     if ((dlen < n + 1) || (NULL == dst)) {
84         *olen = n + 1;
85         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
86     }
87 
88     n = (slen / 3) * 3;
89 
90     for (i = 0, p = dst; i < n; i += 3) {
91         C1 = *src++;
92         C2 = *src++;
93         C3 = *src++;
94 
95         *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
96         *p++ = mbedtls_ct_base64_enc_char((((C1 &  3) << 4) + (C2 >> 4))
97                                           & 0x3F);
98         *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
99                                           & 0x3F);
100         *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
101     }
102 
103     if (i < slen) {
104         C1 = *src++;
105         C2 = ((i + 1) < slen) ? *src++ : 0;
106 
107         *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
108         *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
109                                           & 0x3F);
110 
111         if ((i + 1) < slen) {
112             *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
113         } else {
114             *p++ = '=';
115         }
116 
117         *p++ = '=';
118     }
119 
120     *olen = (size_t) (p - dst);
121     *p = 0;
122 
123     return 0;
124 }
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 {
132     size_t i; /* index in source */
133     size_t n; /* number of digits or trailing = in source */
134     uint32_t x; /* value accumulator */
135     unsigned accumulated_digits = 0;
136     unsigned equals = 0;
137     int spaces_present = 0;
138     unsigned char *p;
139 
140     /* First pass: check for validity and get output length */
141     for (i = n = 0; i < slen; i++) {
142         /* Skip spaces before checking for EOL */
143         spaces_present = 0;
144         while (i < slen && src[i] == ' ') {
145             ++i;
146             spaces_present = 1;
147         }
148 
149         /* Spaces at end of buffer are OK */
150         if (i == slen) {
151             break;
152         }
153 
154         if ((slen - i) >= 2 &&
155             src[i] == '\r' && src[i + 1] == '\n') {
156             continue;
157         }
158 
159         if (src[i] == '\n') {
160             continue;
161         }
162 
163         /* Space inside a line is an error */
164         if (spaces_present) {
165             return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
166         }
167 
168         if (src[i] > 127) {
169             return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
170         }
171 
172         if (src[i] == '=') {
173             if (++equals > 2) {
174                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
175             }
176         } else {
177             if (equals != 0) {
178                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
179             }
180             if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
181                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
182             }
183         }
184         n++;
185     }
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     if ((n - equals) % 4 == 1) {
191         return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
192     }
193     if (n % 4 != 0) {
194         return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
195     }
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     *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     if ((*olen != 0 && dst == NULL) || dlen < *olen) {
221         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
222     }
223 
224     for (x = 0, p = dst; i > 0; i--, src++) {
225         if (*src == '\r' || *src == '\n' || *src == ' ') {
226             continue;
227         }
228         if (*src == '=') {
229             /* We already know from the first loop that equal signs are
230              * only at the end. */
231             break;
232         }
233         x = x << 6;
234         x |= mbedtls_ct_base64_dec_value(*src);
235 
236         if (++accumulated_digits == 4) {
237             accumulated_digits = 0;
238             *p++ = MBEDTLS_BYTE_2(x);
239             *p++ = MBEDTLS_BYTE_1(x);
240             *p++ = MBEDTLS_BYTE_0(x);
241         }
242     }
243     if (accumulated_digits == 3) {
244         *p++ = MBEDTLS_BYTE_2(x << 6);
245         *p++ = MBEDTLS_BYTE_1(x << 6);
246     } else if (accumulated_digits == 2) {
247         *p++ = MBEDTLS_BYTE_2(x << 12);
248     }
249 
250     if (*olen != (size_t) (p - dst)) {
251         return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
252     }
253 
254     return 0;
255 }
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 {
280     size_t len;
281     const unsigned char *src;
282     unsigned char buffer[128];
283 
284     if (verbose != 0) {
285         mbedtls_printf("  Base64 encoding test: ");
286     }
287 
288     src = base64_test_dec;
289 
290     if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
291         memcmp(base64_test_enc, buffer, 88) != 0) {
292         if (verbose != 0) {
293             mbedtls_printf("failed\n");
294         }
295 
296         return 1;
297     }
298 
299     if (verbose != 0) {
300         mbedtls_printf("passed\n  Base64 decoding test: ");
301     }
302 
303     src = base64_test_enc;
304 
305     if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
306         memcmp(base64_test_dec, buffer, 64) != 0) {
307         if (verbose != 0) {
308             mbedtls_printf("failed\n");
309         }
310 
311         return 1;
312     }
313 
314     if (verbose != 0) {
315         mbedtls_printf("passed\n\n");
316     }
317 
318     return 0;
319 }
320 
321 #endif /* MBEDTLS_SELF_TEST */
322 
323 #endif /* MBEDTLS_BASE64_C */
324