1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to. The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * "This product includes cryptographic software written by
33 * Eric Young (eay@cryptsoft.com)"
34 * The word 'cryptographic' can be left out if the rouines from the library
35 * being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 * the apps directory (application code) you must include an acknowledgement:
38 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed. i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.] */
56
57 #include <openssl/base64.h>
58
59 #include <assert.h>
60 #include <limits.h>
61 #include <string.h>
62
63
64 static const unsigned char data_bin2ascii[65] =
65 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
66
67 #define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
68
69 /* 64 char lines
70 * pad input with 0
71 * left over chars are set to =
72 * 1 byte => xx==
73 * 2 bytes => xxx=
74 * 3 bytes => xxxx
75 */
76 #define BIN_PER_LINE (64/4*3)
77 #define CHUNKS_PER_LINE (64/4)
78 #define CHAR_PER_LINE (64+1)
79
80 /* 0xF0 is a EOLN
81 * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
82 * 0xF2 is EOF
83 * 0xE0 is ignore at start of line.
84 * 0xFF is error */
85
86 #define B64_EOLN 0xF0
87 #define B64_CR 0xF1
88 #define B64_EOF 0xF2
89 #define B64_WS 0xE0
90 #define B64_ERROR 0xFF
91 #define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
92
93 static const uint8_t data_ascii2bin[128] = {
94 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF,
95 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
96 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF,
97 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
98 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
99 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
100 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
101 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
102 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
103 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
104 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
105 };
106
conv_ascii2bin(uint8_t a)107 static uint8_t conv_ascii2bin(uint8_t a) {
108 if (a >= 128) {
109 return 0xFF;
110 }
111 return data_ascii2bin[a];
112 }
113
EVP_EncodeInit(EVP_ENCODE_CTX * ctx)114 void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) {
115 ctx->length = 48;
116 ctx->num = 0;
117 ctx->line_num = 0;
118 }
119
EVP_EncodeUpdate(EVP_ENCODE_CTX * ctx,uint8_t * out,int * out_len,const uint8_t * in,size_t in_len)120 void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
121 const uint8_t *in, size_t in_len) {
122 unsigned i, j;
123 unsigned total = 0;
124
125 *out_len = 0;
126 if (in_len == 0) {
127 return;
128 }
129
130 assert(ctx->length <= sizeof(ctx->enc_data));
131
132 if (ctx->num + in_len < ctx->length) {
133 memcpy(&ctx->enc_data[ctx->num], in, in_len);
134 ctx->num += in_len;
135 return;
136 }
137 if (ctx->num != 0) {
138 i = ctx->length - ctx->num;
139 memcpy(&ctx->enc_data[ctx->num], in, i);
140 in += i;
141 in_len -= i;
142 j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length);
143 ctx->num = 0;
144 out += j;
145 *(out++) = '\n';
146 *out = '\0';
147 total = j + 1;
148 }
149 while (in_len >= ctx->length) {
150 j = EVP_EncodeBlock(out, in, ctx->length);
151 in += ctx->length;
152 in_len -= ctx->length;
153 out += j;
154 *(out++) = '\n';
155 *out = '\0';
156 total += j + 1;
157 }
158 if (in_len != 0) {
159 memcpy(&ctx->enc_data[0], in, in_len);
160 }
161 ctx->num = in_len;
162 *out_len = total;
163 }
164
EVP_EncodeFinal(EVP_ENCODE_CTX * ctx,uint8_t * out,int * out_len)165 void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
166 unsigned ret = 0;
167
168 if (ctx->num != 0) {
169 ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num);
170 out[ret++] = '\n';
171 out[ret] = '\0';
172 ctx->num = 0;
173 }
174 *out_len = ret;
175 }
176
EVP_EncodeBlock(uint8_t * dst,const uint8_t * src,size_t src_len)177 size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
178 uint32_t l;
179 size_t remaining = src_len, ret = 0;
180
181 while (remaining) {
182 if (remaining >= 3) {
183 l = (((uint32_t)src[0]) << 16L) | (((uint32_t)src[1]) << 8L) | src[2];
184 *(dst++) = conv_bin2ascii(l >> 18L);
185 *(dst++) = conv_bin2ascii(l >> 12L);
186 *(dst++) = conv_bin2ascii(l >> 6L);
187 *(dst++) = conv_bin2ascii(l);
188 remaining -= 3;
189 } else {
190 l = ((uint32_t)src[0]) << 16L;
191 if (remaining == 2) {
192 l |= ((uint32_t)src[1] << 8L);
193 }
194
195 *(dst++) = conv_bin2ascii(l >> 18L);
196 *(dst++) = conv_bin2ascii(l >> 12L);
197 *(dst++) = (remaining == 1) ? '=' : conv_bin2ascii(l >> 6L);
198 *(dst++) = '=';
199 remaining = 0;
200 }
201 ret += 4;
202 src += 3;
203 }
204
205 *dst = '\0';
206 return ret;
207 }
208
EVP_DecodedLength(size_t * out_len,size_t len)209 int EVP_DecodedLength(size_t *out_len, size_t len) {
210 if (len % 4 != 0) {
211 return 0;
212 }
213 *out_len = (len / 4) * 3;
214 return 1;
215 }
216
EVP_DecodeBase64(uint8_t * out,size_t * out_len,size_t max_out,const uint8_t * in,size_t in_len)217 int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out,
218 const uint8_t *in, size_t in_len) {
219 uint8_t a, b, c, d;
220 size_t pad_len = 0, len = 0, max_len, i;
221 uint32_t l;
222
223 if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) {
224 return 0;
225 }
226
227 for (i = 0; i < in_len; i += 4) {
228 a = conv_ascii2bin(*(in++));
229 b = conv_ascii2bin(*(in++));
230 if (i + 4 == in_len && in[1] == '=') {
231 if (in[0] == '=') {
232 pad_len = 2;
233 } else {
234 pad_len = 1;
235 }
236 }
237 if (pad_len < 2) {
238 c = conv_ascii2bin(*(in++));
239 } else {
240 c = 0;
241 }
242 if (pad_len < 1) {
243 d = conv_ascii2bin(*(in++));
244 } else {
245 d = 0;
246 }
247 if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
248 return 0;
249 }
250 l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
251 (((uint32_t)c) << 6L) | (((uint32_t)d)));
252 *(out++) = (uint8_t)(l >> 16L) & 0xff;
253 if (pad_len < 2) {
254 *(out++) = (uint8_t)(l >> 8L) & 0xff;
255 }
256 if (pad_len < 1) {
257 *(out++) = (uint8_t)(l) & 0xff;
258 }
259 len += 3 - pad_len;
260 }
261 *out_len = len;
262 return 1;
263 }
264
EVP_DecodeInit(EVP_ENCODE_CTX * ctx)265 void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
266 ctx->length = 30;
267 ctx->num = 0;
268 ctx->line_num = 0;
269 ctx->expect_nl = 0;
270 }
271
EVP_DecodeUpdate(EVP_ENCODE_CTX * ctx,uint8_t * out,int * out_len,const uint8_t * in,size_t in_len)272 int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
273 const uint8_t *in, size_t in_len) {
274 int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl;
275 uint8_t *d;
276 unsigned i, n, ln, ret = 0;
277
278 n = ctx->num;
279 d = ctx->enc_data;
280 ln = ctx->line_num;
281 exp_nl = ctx->expect_nl;
282
283 /* last line of input. */
284 if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) {
285 rv = 0;
286 goto end;
287 }
288
289 /* We parse the input data */
290 for (i = 0; i < in_len; i++) {
291 /* If the current line is > 80 characters, scream alot */
292 if (ln >= 80) {
293 rv = -1;
294 goto end;
295 }
296
297 /* Get char and put it into the buffer */
298 tmp = *(in++);
299 v = conv_ascii2bin(tmp);
300 /* only save the good data :-) */
301 if (!B64_NOT_BASE64(v)) {
302 assert(n < sizeof(ctx->enc_data));
303 d[n++] = tmp;
304 ln++;
305 } else if (v == B64_ERROR) {
306 rv = -1;
307 goto end;
308 }
309
310 /* have we seen a '=' which is 'definitly' the last
311 * input line. seof will point to the character that
312 * holds it. and eof will hold how many characters to
313 * chop off. */
314 if (tmp == '=') {
315 if (seof == -1) {
316 seof = n;
317 }
318 eof++;
319 if (eof > 2) {
320 /* There are, at most, two equals signs at the end of base64 data. */
321 rv = -1;
322 goto end;
323 }
324 }
325
326 if (v == B64_CR) {
327 ln = 0;
328 if (exp_nl) {
329 continue;
330 }
331 }
332
333 /* eoln */
334 if (v == B64_EOLN) {
335 ln = 0;
336 if (exp_nl) {
337 exp_nl = 0;
338 continue;
339 }
340 }
341 exp_nl = 0;
342
343 /* If we are at the end of input and it looks like a
344 * line, process it. */
345 if ((i + 1) == in_len && (((n & 3) == 0) || eof)) {
346 v = B64_EOF;
347 /* In case things were given us in really small
348 records (so two '=' were given in separate
349 updates), eof may contain the incorrect number
350 of ending bytes to skip, so let's redo the count */
351 eof = 0;
352 if (d[n - 1] == '=') {
353 eof++;
354 }
355 if (d[n - 2] == '=') {
356 eof++;
357 }
358 /* There will never be more than two '=' */
359 }
360
361 if ((v == B64_EOF && (n & 3) == 0) || n >= 64) {
362 /* This is needed to work correctly on 64 byte input
363 * lines. We process the line and then need to
364 * accept the '\n' */
365 if (v != B64_EOF && n >= 64) {
366 exp_nl = 1;
367 }
368 if (n > 0) {
369 /* TODO(davidben): Switch this to EVP_DecodeBase64. */
370 v = EVP_DecodeBlock(out, d, n);
371 n = 0;
372 if (v < 0) {
373 rv = 0;
374 goto end;
375 }
376 if (eof > v) {
377 rv = -1;
378 goto end;
379 }
380 ret += (v - eof);
381 } else {
382 eof = 1;
383 v = 0;
384 }
385
386 /* This is the case where we have had a short
387 * but valid input line */
388 if (v < (int)ctx->length && eof) {
389 rv = 0;
390 goto end;
391 } else {
392 ctx->length = v;
393 }
394
395 if (seof >= 0) {
396 rv = 0;
397 goto end;
398 }
399 out += v;
400 }
401 }
402 rv = 1;
403
404 end:
405 *out_len = ret;
406 ctx->num = n;
407 ctx->line_num = ln;
408 ctx->expect_nl = exp_nl;
409 return rv;
410 }
411
EVP_DecodeFinal(EVP_ENCODE_CTX * ctx,uint8_t * out,int * outl)412 int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) {
413 int i;
414
415 *outl = 0;
416 if (ctx->num != 0) {
417 /* TODO(davidben): Switch this to EVP_DecodeBase64. */
418 i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
419 if (i < 0) {
420 return -1;
421 }
422 ctx->num = 0;
423 *outl = i;
424 return 1;
425 } else {
426 return 1;
427 }
428 }
429
EVP_DecodeBlock(uint8_t * dst,const uint8_t * src,size_t src_len)430 int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
431 size_t dst_len;
432
433 /* trim white space from the start of the line. */
434 while (conv_ascii2bin(*src) == B64_WS && src_len > 0) {
435 src++;
436 src_len--;
437 }
438
439 /* strip off stuff at the end of the line
440 * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
441 while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) {
442 src_len--;
443 }
444
445 if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) {
446 return -1;
447 }
448 if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
449 return -1;
450 }
451
452 /* EVP_DecodeBlock does not take padding into account, so put the
453 * NULs back in... so the caller can strip them back out. */
454 while (dst_len % 3 != 0) {
455 dst[dst_len++] = '\0';
456 }
457 assert(dst_len <= INT_MAX);
458
459 return dst_len;
460 }
461
EVP_EncodedLength(size_t * out_len,size_t len)462 int EVP_EncodedLength(size_t *out_len, size_t len) {
463 if (len + 2 < len) {
464 return 0;
465 }
466 len += 2;
467 len /= 3;
468 if (((len << 2) >> 2) != len) {
469 return 0;
470 }
471 len <<= 2;
472 if (len + 1 < len) {
473 return 0;
474 }
475 len++;
476 *out_len = len;
477 return 1;
478 }
479