x509_b64.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation
00003  *
00004  * Author: Nikos Mavrogiannopoulos
00005  *
00006  * This file is part of GNUTLS.
00007  *
00008  * The GNUTLS library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00021  * USA
00022  *
00023  */
00024 
00025 /* Functions that relate to base64 encoding and decoding.
00026  */
00027 
00028 #include "gnutls_int.h"
00029 #include "gnutls_errors.h"
00030 #include <gnutls_datum.h>
00031 #include <x509_b64.h>
00032 
00033 static const uint8_t b64table[] =
00034   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00035 
00036 static const uint8_t asciitable[128] = {
00037   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00038   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00039   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00040   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00041   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00042   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00043   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00044   0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
00045   0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
00046   0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
00047   0xff, 0xf1, 0xff, 0xff, 0xff, 0x00,   /* 0xf1 for '=' */
00048   0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
00049   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
00050   0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
00051   0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
00052   0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
00053   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
00054   0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
00055   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
00056   0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
00057   0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
00058   0xff, 0xff
00059 };
00060 
00061 #define INCR(what, size) \
00062        do { \
00063        what+=size; \
00064        if (what > ret) { \
00065                MHD_gnutls_assert(); \
00066                MHD_gnutls_free( (*result)); *result = NULL; \
00067                return GNUTLS_E_INTERNAL_ERROR; \
00068        } \
00069        } while(0)
00070 
00071 
00072 inline static int
00073 encode (char *result, const uint8_t * data, int left)
00074 {
00075 
00076   int data_len;
00077 
00078   if (left > 3)
00079     data_len = 3;
00080   else
00081     data_len = left;
00082 
00083   switch (data_len)
00084     {
00085     case 3:
00086       result[0] = b64table[(data[0] >> 2)];
00087       result[1] =
00088         b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
00089                   (data[1] >> 4))];
00090       result[2] =
00091         b64table[((((data[1] & 0x0f) << 2) & 0xff) | (data[2] >> 6))];
00092       result[3] = b64table[(((data[2] << 2) & 0xff) >> 2)];
00093       break;
00094     case 2:
00095       result[0] = b64table[(data[0] >> 2)];
00096       result[1] =
00097         b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
00098                   (data[1] >> 4))];
00099       result[2] = b64table[(((data[1] << 4) & 0xff) >> 2)];
00100       result[3] = '=';
00101       break;
00102     case 1:
00103       result[0] = b64table[(data[0] >> 2)];
00104       result[1] = b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff))];
00105       result[2] = '=';
00106       result[3] = '=';
00107       break;
00108     default:
00109       return -1;
00110     }
00111 
00112   return 4;
00113 
00114 }
00115 
00116 /* data must be 4 bytes
00117  * result should be 3 bytes
00118  */
00119 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
00120 inline static int
00121 decode (uint8_t * result, const opaque * data)
00122 {
00123   uint8_t a1, a2;
00124   int ret = 3;
00125 
00126   a1 = TOASCII (data[0]);
00127   a2 = TOASCII (data[1]);
00128   if (a1 == 0xff || a2 == 0xff)
00129     return -1;
00130   result[0] = ((a1 << 2) & 0xff) | ((a2 >> 4) & 0xff);
00131 
00132   a1 = a2;
00133   a2 = TOASCII (data[2]);
00134   if (a2 == 0xff)
00135     return -1;
00136   result[1] = ((a1 << 4) & 0xff) | ((a2 >> 2) & 0xff);
00137 
00138   a1 = a2;
00139   a2 = TOASCII (data[3]);
00140   if (a2 == 0xff)
00141     return -1;
00142   result[2] = ((a1 << 6) & 0xff) | (a2 & 0xff);
00143 
00144   if (data[2] == '=')
00145     ret--;
00146 
00147   if (data[3] == '=')
00148     ret--;
00149   return ret;
00150 }
00151 
00152 /* encodes data and puts the result into result (locally allocated)
00153  * The result_size (including the null terminator) is the return value.
00154  */
00155 int
00156 MHD__gnutls_fbase64_encode (const char *msg, const uint8_t * data,
00157                             int data_size, uint8_t ** result)
00158 {
00159   int i, ret, tmp, j;
00160   char tmpres[4];
00161   uint8_t *ptr;
00162   uint8_t top[80];
00163   uint8_t bottom[80];
00164   int pos, bytes, top_len, bottom_len;
00165   size_t msglen = strlen (msg);
00166 
00167   if (msglen > 50)
00168     {
00169       MHD_gnutls_assert ();
00170       return GNUTLS_E_BASE64_ENCODING_ERROR;
00171     }
00172 
00173   memset (bottom, 0, sizeof (bottom));
00174   memset (top, 0, sizeof (top));
00175 
00176   strcat ((char *) top, "-----BEGIN "); /* Flawfinder: ignore */
00177   strcat ((char *) top, msg);   /* Flawfinder: ignore */
00178   strcat ((char *) top, "-----");       /* Flawfinder: ignore */
00179 
00180   strcat ((char *) bottom, "\n-----END ");      /* Flawfinder: ignore */
00181   strcat ((char *) bottom, msg);        /* Flawfinder: ignore */
00182   strcat ((char *) bottom, "-----\n");  /* Flawfinder: ignore */
00183 
00184   top_len = strlen ((char *) top);
00185   bottom_len = strlen ((char *) bottom);
00186 
00187   ret = B64FSIZE (msglen, data_size);
00188 
00189   (*result) = MHD_gnutls_calloc (1, ret + 1);
00190   if ((*result) == NULL)
00191     {
00192       MHD_gnutls_assert ();
00193       return GNUTLS_E_MEMORY_ERROR;
00194     }
00195 
00196   bytes = pos = 0;
00197   INCR (bytes, top_len);
00198   pos = top_len;
00199 
00200   strcpy ((char *) *result, (char *) top);      /* Flawfinder: ignore */
00201 
00202   for (i = j = 0; i < data_size; i += 3, j += 4)
00203     {
00204 
00205       tmp = encode (tmpres, &data[i], data_size - i);
00206       if (tmp == -1)
00207         {
00208           MHD_gnutls_assert ();
00209           MHD_gnutls_free ((*result));
00210           *result = NULL;
00211           return GNUTLS_E_BASE64_ENCODING_ERROR;
00212         }
00213 
00214       INCR (bytes, 4);
00215       ptr = &(*result)[j + pos];
00216 
00217       if ((j) % 64 == 0)
00218         {
00219           INCR (bytes, 1);
00220           pos++;
00221           *ptr++ = '\n';
00222         }
00223       *ptr++ = tmpres[0];
00224 
00225       if ((j + 1) % 64 == 0)
00226         {
00227           INCR (bytes, 1);
00228           pos++;
00229           *ptr++ = '\n';
00230         }
00231       *ptr++ = tmpres[1];
00232 
00233       if ((j + 2) % 64 == 0)
00234         {
00235           INCR (bytes, 1);
00236           pos++;
00237           *ptr++ = '\n';
00238         }
00239       *ptr++ = tmpres[2];
00240 
00241       if ((j + 3) % 64 == 0)
00242         {
00243           INCR (bytes, 1);
00244           pos++;
00245           *ptr++ = '\n';
00246         }
00247       *ptr++ = tmpres[3];
00248     }
00249 
00250   INCR (bytes, bottom_len);
00251 
00252   memcpy (&(*result)[bytes - bottom_len], bottom, bottom_len);
00253   (*result)[bytes] = 0;
00254 
00255   return ret + 1;
00256 }
00257 
00258 /* decodes data and puts the result into result (locally allocated)
00259  * The result_size is the return value
00260  */
00261 int
00262 MHD__gnutls_base64_decode (const uint8_t * data, size_t data_size,
00263                            uint8_t ** result)
00264 {
00265   unsigned int i, j;
00266   int ret, tmp, est;
00267   uint8_t tmpres[3];
00268 
00269   est = ((data_size * 3) / 4) + 1;
00270   (*result) = MHD_gnutls_malloc (est);
00271   if ((*result) == NULL)
00272     return GNUTLS_E_MEMORY_ERROR;
00273 
00274   ret = 0;
00275   for (i = j = 0; i < data_size; i += 4, j += 3)
00276     {
00277       tmp = decode (tmpres, &data[i]);
00278       if (tmp < 0)
00279         {
00280           MHD_gnutls_free (*result);
00281           *result = NULL;
00282           return tmp;
00283         }
00284       memcpy (&(*result)[j], tmpres, tmp);
00285       ret += tmp;
00286     }
00287   return ret;
00288 }
00289 
00290 /* copies data to result but removes newlines and <CR>
00291  * returns the size of the data copied.
00292  */
00293 inline static int
00294 cpydata (const uint8_t * data, int data_size, uint8_t ** result)
00295 {
00296   int i, j;
00297 
00298   (*result) = MHD_gnutls_malloc (data_size);
00299   if (*result == NULL)
00300     return GNUTLS_E_MEMORY_ERROR;
00301 
00302   for (j = i = 0; i < data_size; i++)
00303     {
00304       if (data[i] == '\n' || data[i] == '\r')
00305         continue;
00306       (*result)[j] = data[i];
00307       j++;
00308     }
00309   return j;
00310 }
00311 
00312 /* Searches the given string for ONE PEM encoded certificate, and
00313  * stores it in the result.
00314  *
00315  * The result_size is the return value
00316  */
00317 #define ENDSTR "-----\n"
00318 #define ENDSTR2 "-----\r"
00319 int
00320 MHD__gnutls_fbase64_decode (const char *header, const opaque * data,
00321                             size_t data_size, uint8_t ** result)
00322 {
00323   int ret;
00324   static const char top[] = "-----BEGIN ";
00325   static const char bottom[] = "\n-----END ";
00326   uint8_t *rdata;
00327   int rdata_size;
00328   uint8_t *kdata;
00329   int kdata_size;
00330   char pem_header[128];
00331 
00332   MHD_gtls_str_cpy (pem_header, sizeof (pem_header), top);
00333   if (header != NULL)
00334     MHD_gtls_str_cat (pem_header, sizeof (pem_header), header);
00335 
00336   rdata = memmem (data, data_size, pem_header, strlen (pem_header));
00337 
00338   if (rdata == NULL)
00339     {
00340       MHD_gnutls_assert ();
00341       MHD__gnutls_debug_log ("Could not find '%s'\n", pem_header);
00342       return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
00343     }
00344 
00345   data_size -= (unsigned long int) rdata - (unsigned long int) data;
00346 
00347   if (data_size < 4 + strlen (bottom))
00348     {
00349       MHD_gnutls_assert ();
00350       return GNUTLS_E_BASE64_DECODING_ERROR;
00351     }
00352 
00353   kdata = memmem (rdata, data_size, ENDSTR, sizeof (ENDSTR) - 1);
00354   /* allow CR as well.
00355    */
00356   if (kdata == NULL)
00357     kdata = memmem (rdata, data_size, ENDSTR2, sizeof (ENDSTR2) - 1);
00358 
00359   if (kdata == NULL)
00360     {
00361       MHD_gnutls_assert ();
00362       MHD__gnutls_x509_log ("Could not find '%s'\n", ENDSTR);
00363       return GNUTLS_E_BASE64_DECODING_ERROR;
00364     }
00365   data_size -= strlen (ENDSTR);
00366   data_size -= (unsigned long int) kdata - (unsigned long int) rdata;
00367 
00368   rdata = kdata + strlen (ENDSTR);
00369 
00370   /* position is now after the ---BEGIN--- headers */
00371 
00372   kdata = memmem (rdata, data_size, bottom, strlen (bottom));
00373   if (kdata == NULL)
00374     {
00375       MHD_gnutls_assert ();
00376       return GNUTLS_E_BASE64_DECODING_ERROR;
00377     }
00378 
00379   /* position of kdata is before the ----END--- footer
00380    */
00381   rdata_size = (unsigned long int) kdata - (unsigned long int) rdata;
00382 
00383   if (rdata_size < 4)
00384     {
00385       MHD_gnutls_assert ();
00386       return GNUTLS_E_BASE64_DECODING_ERROR;
00387     }
00388 
00389   kdata_size = cpydata (rdata, rdata_size, &kdata);
00390 
00391   if (kdata_size < 0)
00392     {
00393       MHD_gnutls_assert ();
00394       return kdata_size;
00395     }
00396 
00397   if (kdata_size < 4)
00398     {
00399       MHD_gnutls_assert ();
00400       MHD_gnutls_free (kdata);
00401       return GNUTLS_E_BASE64_DECODING_ERROR;
00402     }
00403 
00404   if ((ret = MHD__gnutls_base64_decode (kdata, kdata_size, result)) < 0)
00405     {
00406       MHD_gnutls_free (kdata);
00407       MHD_gnutls_assert ();
00408       return GNUTLS_E_BASE64_DECODING_ERROR;
00409     }
00410   MHD_gnutls_free (kdata);
00411 
00412   return ret;
00413 }

Generated on Sun Jul 26 17:20:56 2009 for GNU libmicrohttpd by  doxygen 1.5.9