• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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