Tizen 2.0 Release
[external/libgnutls26.git] / lib / x509_b64.c
1 /*
2  * Copyright (C) 2000, 2001, 2003, 2004, 2005, 2008, 2010 Free Software
3  * Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 /* Functions that relate to base64 encoding and decoding.
27  */
28
29 #include "gnutls_int.h"
30 #include "gnutls_errors.h"
31 #include <gnutls_datum.h>
32 #include <x509_b64.h>
33
34 static const uint8_t b64table[] =
35   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36
37 static const uint8_t asciitable[128] = {
38   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45   0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
46   0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
47   0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
48   0xff, 0xf1, 0xff, 0xff, 0xff, 0x00,   /* 0xf1 for '=' */
49   0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
50   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
51   0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
52   0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
53   0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
54   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
55   0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
56   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
57   0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
58   0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
59   0xff, 0xff
60 };
61
62 inline static int
63 encode (char *result, const uint8_t * data, int left)
64 {
65
66   int data_len;
67
68   if (left > 3)
69     data_len = 3;
70   else
71     data_len = left;
72
73   switch (data_len)
74     {
75     case 3:
76       result[0] = b64table[(data[0] >> 2)];
77       result[1] =
78         b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
79                   (data[1] >> 4))];
80       result[2] =
81         b64table[((((data[1] & 0x0f) << 2) & 0xff) | (data[2] >> 6))];
82       result[3] = b64table[(((data[2] << 2) & 0xff) >> 2)];
83       break;
84     case 2:
85       result[0] = b64table[(data[0] >> 2)];
86       result[1] =
87         b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
88                   (data[1] >> 4))];
89       result[2] = b64table[(((data[1] << 4) & 0xff) >> 2)];
90       result[3] = '=';
91       break;
92     case 1:
93       result[0] = b64table[(data[0] >> 2)];
94       result[1] = b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff))];
95       result[2] = '=';
96       result[3] = '=';
97       break;
98     default:
99       return -1;
100     }
101
102   return 4;
103
104 }
105
106 /* data must be 4 bytes
107  * result should be 3 bytes
108  */
109 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
110 inline static int
111 decode (uint8_t * result, const opaque * data)
112 {
113   uint8_t a1, a2;
114   int ret = 3;
115
116   a1 = TOASCII (data[0]);
117   a2 = TOASCII (data[1]);
118   if (a1 == 0xff || a2 == 0xff)
119     return -1;
120   result[0] = ((a1 << 2) & 0xff) | ((a2 >> 4) & 0xff);
121
122   a1 = a2;
123   a2 = TOASCII (data[2]);
124   if (a2 == 0xff)
125     return -1;
126   result[1] = ((a1 << 4) & 0xff) | ((a2 >> 2) & 0xff);
127
128   a1 = a2;
129   a2 = TOASCII (data[3]);
130   if (a2 == 0xff)
131     return -1;
132   result[2] = ((a1 << 6) & 0xff) | (a2 & 0xff);
133
134   if (data[2] == '=')
135     ret--;
136
137   if (data[3] == '=')
138     ret--;
139   return ret;
140 }
141
142 /* encodes data and puts the result into result (locally allocated)
143  * The result_size is the return value
144  */
145 int
146 _gnutls_base64_encode (const uint8_t * data, size_t data_size,
147                        uint8_t ** result)
148 {
149   unsigned int i, j;
150   int ret, tmp;
151   char tmpres[4];
152
153   ret = B64SIZE (data_size);
154
155   (*result) = gnutls_malloc (ret + 1);
156   if ((*result) == NULL)
157     return GNUTLS_E_MEMORY_ERROR;
158
159   for (i = j = 0; i < data_size; i += 3, j += 4)
160     {
161       tmp = encode (tmpres, &data[i], data_size - i);
162       if (tmp == -1)
163         {
164           gnutls_free ((*result));
165           return GNUTLS_E_MEMORY_ERROR;
166         }
167       memcpy (&(*result)[j], tmpres, tmp);
168     }
169   (*result)[ret] = 0;           /* null terminated */
170
171   return ret;
172 }
173
174 #define INCR(what, size) \
175         do { \
176         what+=size; \
177         if (what > ret) { \
178                 gnutls_assert(); \
179                 gnutls_free( (*result)); *result = NULL; \
180                 return GNUTLS_E_INTERNAL_ERROR; \
181         } \
182         } while(0)
183
184 /* encodes data and puts the result into result (locally allocated)
185  * The result_size (including the null terminator) is the return value.
186  */
187 int
188 _gnutls_fbase64_encode (const char *msg, const uint8_t * data,
189                         int data_size, uint8_t ** result)
190 {
191   int i, ret, tmp, j;
192   char tmpres[4];
193   uint8_t *ptr;
194   uint8_t top[80];
195   uint8_t bottom[80];
196   int pos, bytes, top_len, bottom_len;
197   size_t msglen = strlen (msg);
198
199   if (msglen > 50)
200     {
201       gnutls_assert ();
202       return GNUTLS_E_BASE64_ENCODING_ERROR;
203     }
204
205   memset (bottom, 0, sizeof (bottom));
206   memset (top, 0, sizeof (top));
207
208   strcat (top, "-----BEGIN ");  /* Flawfinder: ignore */
209   strcat (top, msg);            /* Flawfinder: ignore */
210   strcat (top, "-----");        /* Flawfinder: ignore */
211
212   strcat (bottom, "\n-----END ");       /* Flawfinder: ignore */
213   strcat (bottom, msg);         /* Flawfinder: ignore */
214   strcat (bottom, "-----\n");   /* Flawfinder: ignore */
215
216   top_len = strlen (top);
217   bottom_len = strlen (bottom);
218
219   ret = B64FSIZE (msglen, data_size);
220
221   (*result) = gnutls_calloc (1, ret + 1);
222   if ((*result) == NULL)
223     {
224       gnutls_assert ();
225       return GNUTLS_E_MEMORY_ERROR;
226     }
227
228   bytes = pos = 0;
229   INCR (bytes, top_len);
230   pos = top_len;
231
232   strcpy (*result, top);        /* Flawfinder: ignore */
233
234   for (i = j = 0; i < data_size; i += 3, j += 4)
235     {
236
237       tmp = encode (tmpres, &data[i], data_size - i);
238       if (tmp == -1)
239         {
240           gnutls_assert ();
241           gnutls_free ((*result));
242           *result = NULL;
243           return GNUTLS_E_BASE64_ENCODING_ERROR;
244         }
245
246       INCR (bytes, 4);
247       ptr = &(*result)[j + pos];
248
249       if ((j) % 64 == 0)
250         {
251           INCR (bytes, 1);
252           pos++;
253           *ptr++ = '\n';
254         }
255       *ptr++ = tmpres[0];
256
257       if ((j + 1) % 64 == 0)
258         {
259           INCR (bytes, 1);
260           pos++;
261           *ptr++ = '\n';
262         }
263       *ptr++ = tmpres[1];
264
265       if ((j + 2) % 64 == 0)
266         {
267           INCR (bytes, 1);
268           pos++;
269           *ptr++ = '\n';
270         }
271       *ptr++ = tmpres[2];
272
273       if ((j + 3) % 64 == 0)
274         {
275           INCR (bytes, 1);
276           pos++;
277           *ptr++ = '\n';
278         }
279       *ptr++ = tmpres[3];
280     }
281
282   INCR (bytes, bottom_len);
283
284   memcpy (&(*result)[bytes - bottom_len], bottom, bottom_len);
285   (*result)[bytes] = 0;
286
287   return ret + 1;
288 }
289
290 /**
291  * gnutls_pem_base64_encode:
292  * @msg: is a message to be put in the header
293  * @data: contain the raw data
294  * @result: the place where base64 data will be copied
295  * @result_size: holds the size of the result
296  *
297  * This function will convert the given data to printable data, using
298  * the base64 encoding. This is the encoding used in PEM messages.
299  *
300  * The output string will be null terminated, although the size will
301  * not include the terminating null.
302  *
303  * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
304  *   %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
305  *   not long enough, or 0 on success.
306  **/
307 int
308 gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data,
309                           char *result, size_t * result_size)
310 {
311   opaque *ret;
312   int size;
313
314   size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
315   if (size < 0)
316     return size;
317
318   if (result == NULL || *result_size < (unsigned) size)
319     {
320       gnutls_free (ret);
321       *result_size = size;
322       return GNUTLS_E_SHORT_MEMORY_BUFFER;
323     }
324   else
325     {
326       memcpy (result, ret, size);
327       gnutls_free (ret);
328       *result_size = size - 1;
329     }
330
331   return 0;
332 }
333
334 /**
335  * gnutls_pem_base64_encode_alloc:
336  * @msg: is a message to be put in the encoded header
337  * @data: contains the raw data
338  * @result: will hold the newly allocated encoded data
339  *
340  * This function will convert the given data to printable data, using
341  * the base64 encoding.  This is the encoding used in PEM messages.
342  * This function will allocate the required memory to hold the encoded
343  * data.
344  *
345  * You should use gnutls_free() to free the returned data.
346  *
347  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
348  *   an error code is returned.
349  **/
350 int
351 gnutls_pem_base64_encode_alloc (const char *msg,
352                                 const gnutls_datum_t * data,
353                                 gnutls_datum_t * result)
354 {
355   opaque *ret;
356   int size;
357
358   if (result == NULL)
359     return GNUTLS_E_INVALID_REQUEST;
360
361   size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
362   if (size < 0)
363     return size;
364
365   result->data = ret;
366   result->size = size - 1;
367   return 0;
368 }
369
370
371 /* decodes data and puts the result into result (locally allocated)
372  * The result_size is the return value
373  */
374 int
375 _gnutls_base64_decode (const uint8_t * data, size_t data_size,
376                        uint8_t ** result)
377 {
378   unsigned int i, j;
379   int ret, tmp, est;
380   uint8_t tmpres[3];
381
382   est = ((data_size * 3) / 4) + 1;
383   (*result) = gnutls_malloc (est);
384   if ((*result) == NULL)
385     return GNUTLS_E_MEMORY_ERROR;
386
387   ret = 0;
388   for (i = j = 0; i < data_size; i += 4, j += 3)
389     {
390       tmp = decode (tmpres, &data[i]);
391       if (tmp < 0)
392         {
393           gnutls_free (*result);
394           *result = NULL;
395           return tmp;
396         }
397       memcpy (&(*result)[j], tmpres, tmp);
398       ret += tmp;
399     }
400   return ret;
401 }
402
403 /* copies data to result but removes newlines and <CR>
404  * returns the size of the data copied.
405  */
406 inline static int
407 cpydata (const uint8_t * data, int data_size, uint8_t ** result)
408 {
409   int i, j;
410
411   (*result) = gnutls_malloc (data_size);
412   if (*result == NULL)
413     return GNUTLS_E_MEMORY_ERROR;
414
415   for (j = i = 0; i < data_size; i++)
416     {
417       if (data[i] == '\n' || data[i] == '\r' || data[i] == ' '
418           || data[i] == '\t')
419         continue;
420       (*result)[j] = data[i];
421       j++;
422     }
423   return j;
424 }
425
426 /* Searches the given string for ONE PEM encoded certificate, and
427  * stores it in the result.
428  *
429  * The result_size is the return value
430  */
431 #define ENDSTR "-----"
432 int
433 _gnutls_fbase64_decode (const char *header, const opaque * data,
434                         size_t data_size, uint8_t ** result)
435 {
436   int ret;
437   static const char top[] = "-----BEGIN ";
438   static const char bottom[] = "-----END ";
439   uint8_t *rdata;
440   int rdata_size;
441   uint8_t *kdata;
442   int kdata_size;
443   char pem_header[128];
444
445   _gnutls_str_cpy (pem_header, sizeof (pem_header), top);
446   if (header != NULL)
447     _gnutls_str_cat (pem_header, sizeof (pem_header), header);
448
449   rdata = memmem (data, data_size, pem_header, strlen (pem_header));
450
451   if (rdata == NULL)
452     {
453       gnutls_assert ();
454       _gnutls_debug_log ("Could not find '%s'\n", pem_header);
455       return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
456     }
457
458   data_size -= (unsigned long int) rdata - (unsigned long int) data;
459
460   if (data_size < 4 + strlen (bottom))
461     {
462       gnutls_assert ();
463       return GNUTLS_E_BASE64_DECODING_ERROR;
464     }
465
466   kdata = memmem (rdata + 1, data_size - 1, ENDSTR, sizeof (ENDSTR) - 1);
467   /* allow CR as well.
468    */
469   if (kdata == NULL)
470     {
471       gnutls_assert ();
472       _gnutls_x509_log ("Could not find '%s'\n", ENDSTR);
473       return GNUTLS_E_BASE64_DECODING_ERROR;
474     }
475   data_size -= strlen (ENDSTR);
476   data_size -= (unsigned long int) kdata - (unsigned long int) rdata;
477
478   rdata = kdata + strlen (ENDSTR);
479
480   /* position is now after the ---BEGIN--- headers */
481
482   kdata = memmem (rdata, data_size, bottom, strlen (bottom));
483   if (kdata == NULL)
484     {
485       gnutls_assert ();
486       return GNUTLS_E_BASE64_DECODING_ERROR;
487     }
488
489   /* position of kdata is before the ----END--- footer 
490    */
491   rdata_size = (unsigned long int) kdata - (unsigned long int) rdata;
492
493   if (rdata_size < 4)
494     {
495       gnutls_assert ();
496       return GNUTLS_E_BASE64_DECODING_ERROR;
497     }
498
499   kdata_size = cpydata (rdata, rdata_size, &kdata);
500
501   if (kdata_size < 0)
502     {
503       gnutls_assert ();
504       return kdata_size;
505     }
506
507   if (kdata_size < 4)
508     {
509       gnutls_assert ();
510       gnutls_free (kdata);
511       return GNUTLS_E_BASE64_DECODING_ERROR;
512     }
513
514   if ((ret = _gnutls_base64_decode (kdata, kdata_size, result)) < 0)
515     {
516       gnutls_free (kdata);
517       gnutls_assert ();
518       return GNUTLS_E_BASE64_DECODING_ERROR;
519     }
520   gnutls_free (kdata);
521
522   return ret;
523 }
524
525 /**
526  * gnutls_pem_base64_decode:
527  * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
528  * @b64_data: contain the encoded data
529  * @result: the place where decoded data will be copied
530  * @result_size: holds the size of the result
531  *
532  * This function will decode the given encoded data.  If the header
533  * given is non null this function will search for "-----BEGIN header"
534  * and decode only this part.  Otherwise it will decode the first PEM
535  * packet found.
536  *
537  * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
538  *   %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
539  *   not long enough, or 0 on success.
540  **/
541 int
542 gnutls_pem_base64_decode (const char *header,
543                           const gnutls_datum_t * b64_data,
544                           unsigned char *result, size_t * result_size)
545 {
546   opaque *ret;
547   int size;
548
549   size =
550     _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
551   if (size < 0)
552     return size;
553
554   if (result == NULL || *result_size < (unsigned) size)
555     {
556       gnutls_free (ret);
557       *result_size = size;
558       return GNUTLS_E_SHORT_MEMORY_BUFFER;
559     }
560   else
561     {
562       memcpy (result, ret, size);
563       gnutls_free (ret);
564       *result_size = size;
565     }
566
567   return 0;
568 }
569
570 /**
571  * gnutls_pem_base64_decode_alloc:
572  * @header: The PEM header (eg. CERTIFICATE)
573  * @b64_data: contains the encoded data
574  * @result: the place where decoded data lie
575  *
576  * This function will decode the given encoded data. The decoded data
577  * will be allocated, and stored into result.  If the header given is
578  * non null this function will search for "-----BEGIN header" and
579  * decode only this part. Otherwise it will decode the first PEM
580  * packet found.
581  *
582  * You should use gnutls_free() to free the returned data.
583  *
584  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
585  *   an error code is returned.
586  **/
587 int
588 gnutls_pem_base64_decode_alloc (const char *header,
589                                 const gnutls_datum_t * b64_data,
590                                 gnutls_datum_t * result)
591 {
592   opaque *ret;
593   int size;
594
595   if (result == NULL)
596     return GNUTLS_E_INVALID_REQUEST;
597
598   size =
599     _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
600   if (size < 0)
601     return size;
602
603   result->data = ret;
604   result->size = size;
605   return 0;
606 }