gnutls_x509.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 #include <gnutls_int.h>
00026 #include "gnutls_auth_int.h"
00027 #include "gnutls_errors.h"
00028 #include <gnutls_cert.h>
00029 #include <auth_cert.h>
00030 #include "gnutls_dh.h"
00031 #include "gnutls_num.h"
00032 #include "gnutls_datum.h"
00033 #include <gnutls_pk.h>
00034 #include <gnutls_algorithms.h>
00035 #include <gnutls_global.h>
00036 #include <gnutls_record.h>
00037 #include <gnutls_sig.h>
00038 #include <gnutls_state.h>
00039 #include <gnutls_pk.h>
00040 #include <gnutls_str.h>
00041 #include <debug.h>
00042 #include <x509_b64.h>
00043 #include <gnutls_x509.h>
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046 #include <fcntl.h>
00047 
00048 /* x509 */
00049 #include "common.h"
00050 #include "x509.h"
00051 #include "mpi.h"
00052 #include "privkey.h"
00053 
00054 
00055 /*
00056  * some x509 certificate parsing functions.
00057  */
00058 
00059 /* Check if the number of bits of the key in the certificate
00060  * is unacceptable.
00061   */
00062 inline static int
00063 check_bits (MHD_gnutls_x509_crt_t crt, unsigned int max_bits)
00064 {
00065   int ret;
00066   unsigned int bits;
00067 
00068   ret = MHD_gnutls_x509_crt_get_pk_algorithm (crt, &bits);
00069   if (ret < 0)
00070     {
00071       MHD_gnutls_assert ();
00072       return ret;
00073     }
00074 
00075   if (bits > max_bits && max_bits > 0)
00076     {
00077       MHD_gnutls_assert ();
00078       return GNUTLS_E_CONSTRAINT_ERROR;
00079     }
00080 
00081   return 0;
00082 }
00083 
00084 
00085 #define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) { \
00086         if (peer_certificate_list[x]) \
00087                 MHD_gnutls_x509_crt_deinit(peer_certificate_list[x]); \
00088         } \
00089         MHD_gnutls_free( peer_certificate_list)
00090 
00091 /*
00092  * Read certificates and private keys, from memory etc.
00093  */
00094 
00095 /* returns error if the certificate has different algorithm than
00096  * the given key parameters.
00097  */
00098 static int
00099 MHD__gnutls_check_key_cert_match (MHD_gtls_cert_credentials_t res)
00100 {
00101   MHD_gnutls_datum_t cid;
00102   MHD_gnutls_datum_t kid;
00103   unsigned pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm;
00104 
00105   if (res->pkey[res->ncerts - 1].pk_algorithm != pk)
00106     {
00107       MHD_gnutls_assert ();
00108       return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
00109     }
00110 
00111   MHD__gnutls_x509_write_rsa_params (res->pkey[res->ncerts - 1].params,
00112                                      res->pkey[res->ncerts -
00113                                                1].params_size, &kid);
00114 
00115 
00116   MHD__gnutls_x509_write_rsa_params (res->
00117                                      cert_list[res->ncerts - 1][0].params,
00118                                      res->cert_list[res->ncerts -
00119                                                     1][0].params_size, &cid);
00120 
00121   if (cid.size != kid.size)
00122     {
00123       MHD_gnutls_assert ();
00124       MHD__gnutls_free_datum (&kid);
00125       MHD__gnutls_free_datum (&cid);
00126       return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
00127     }
00128 
00129   if (memcmp (kid.data, cid.data, kid.size) != 0)
00130     {
00131       MHD_gnutls_assert ();
00132       MHD__gnutls_free_datum (&kid);
00133       MHD__gnutls_free_datum (&cid);
00134       return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
00135     }
00136 
00137   MHD__gnutls_free_datum (&kid);
00138   MHD__gnutls_free_datum (&cid);
00139   return 0;
00140 }
00141 
00142 /* Reads a DER encoded certificate list from memory and stores it to
00143  * a MHD_gnutls_cert structure.
00144  * Returns the number of certificates parsed.
00145  */
00146 static int
00147 parse_crt_mem (MHD_gnutls_cert ** cert_list, unsigned *ncerts,
00148                MHD_gnutls_x509_crt_t cert)
00149 {
00150   int i;
00151   int ret;
00152 
00153   i = *ncerts + 1;
00154 
00155   *cert_list =
00156     (MHD_gnutls_cert *) MHD_gtls_realloc_fast (*cert_list,
00157                                                i * sizeof (MHD_gnutls_cert));
00158 
00159   if (*cert_list == NULL)
00160     {
00161       MHD_gnutls_assert ();
00162       return GNUTLS_E_MEMORY_ERROR;
00163     }
00164 
00165   ret = MHD_gtls_x509_crt_to_gcert (&cert_list[0][i - 1], cert, 0);
00166   if (ret < 0)
00167     {
00168       MHD_gnutls_assert ();
00169       return ret;
00170     }
00171 
00172   *ncerts = i;
00173 
00174   return 1;                     /* one certificate parsed */
00175 }
00176 
00177 /* Reads a DER encoded certificate list from memory and stores it to
00178  * a MHD_gnutls_cert structure.
00179  * Returns the number of certificates parsed.
00180  */
00181 static int
00182 parse_der_cert_mem (MHD_gnutls_cert ** cert_list, unsigned *ncerts,
00183                     const void *input_cert, int input_cert_size)
00184 {
00185   MHD_gnutls_datum_t tmp;
00186   MHD_gnutls_x509_crt_t cert;
00187   int ret;
00188 
00189   ret = MHD_gnutls_x509_crt_init (&cert);
00190   if (ret < 0)
00191     {
00192       MHD_gnutls_assert ();
00193       return ret;
00194     }
00195 
00196   tmp.data = (opaque *) input_cert;
00197   tmp.size = input_cert_size;
00198 
00199   ret = MHD_gnutls_x509_crt_import (cert, &tmp, GNUTLS_X509_FMT_DER);
00200   if (ret < 0)
00201     {
00202       MHD_gnutls_assert ();
00203       MHD_gnutls_x509_crt_deinit (cert);
00204       return ret;
00205     }
00206 
00207   ret = parse_crt_mem (cert_list, ncerts, cert);
00208   MHD_gnutls_x509_crt_deinit (cert);
00209 
00210   return ret;
00211 }
00212 
00213 /* Reads a base64 encoded certificate list from memory and stores it to
00214  * a MHD_gnutls_cert structure. Returns the number of certificate parsed.
00215  */
00216 static int
00217 parse_pem_cert_mem (MHD_gnutls_cert ** cert_list, unsigned *ncerts,
00218                     const char *input_cert, int input_cert_size)
00219 {
00220   int size, siz2, i;
00221   const char *ptr;
00222   opaque *ptr2;
00223   MHD_gnutls_datum_t tmp;
00224   int ret, count;
00225 
00226   /* move to the certificate
00227    */
00228   ptr = memmem (input_cert, input_cert_size,
00229                 PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1);
00230   if (ptr == NULL)
00231     ptr = memmem (input_cert, input_cert_size,
00232                   PEM_CERT_SEP2, sizeof (PEM_CERT_SEP2) - 1);
00233 
00234   if (ptr == NULL)
00235     {
00236       MHD_gnutls_assert ();
00237       return GNUTLS_E_BASE64_DECODING_ERROR;
00238     }
00239   size = input_cert_size - (ptr - input_cert);
00240 
00241   i = *ncerts + 1;
00242   count = 0;
00243 
00244   do
00245     {
00246 
00247       siz2 =
00248         MHD__gnutls_fbase64_decode (NULL, (const unsigned char *) ptr, size,
00249                                     &ptr2);
00250 
00251       if (siz2 < 0)
00252         {
00253           MHD_gnutls_assert ();
00254           return GNUTLS_E_BASE64_DECODING_ERROR;
00255         }
00256 
00257       *cert_list =
00258         (MHD_gnutls_cert *) MHD_gtls_realloc_fast (*cert_list,
00259                                                    i *
00260                                                    sizeof (MHD_gnutls_cert));
00261 
00262       if (*cert_list == NULL)
00263         {
00264           MHD_gnutls_assert ();
00265           return GNUTLS_E_MEMORY_ERROR;
00266         }
00267 
00268       tmp.data = ptr2;
00269       tmp.size = siz2;
00270 
00271       ret = MHD_gtls_x509_raw_cert_to_gcert (&cert_list[0][i - 1], &tmp, 0);
00272       if (ret < 0)
00273         {
00274           MHD_gnutls_assert ();
00275           return ret;
00276         }
00277       MHD__gnutls_free_datum (&tmp);    /* free ptr2 */
00278 
00279       /* now we move ptr after the pem header
00280        */
00281       ptr++;
00282       /* find the next certificate (if any)
00283        */
00284       size = input_cert_size - (ptr - input_cert);
00285 
00286       if (size > 0)
00287         {
00288           char *ptr3;
00289 
00290           ptr3 = memmem (ptr, size, PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1);
00291           if (ptr3 == NULL)
00292             ptr3 = memmem (ptr, size, PEM_CERT_SEP2,
00293                            sizeof (PEM_CERT_SEP2) - 1);
00294 
00295           ptr = ptr3;
00296         }
00297       else
00298         ptr = NULL;
00299 
00300       i++;
00301       count++;
00302 
00303     }
00304   while (ptr != NULL);
00305 
00306   *ncerts = i - 1;
00307 
00308   return count;
00309 }
00310 
00311 
00312 
00313 /* Reads a DER or PEM certificate from memory
00314  */
00315 static int
00316 read_cert_mem (MHD_gtls_cert_credentials_t res, const void *cert,
00317                int cert_size, MHD_gnutls_x509_crt_fmt_t type)
00318 {
00319   int ret;
00320 
00321   /* allocate space for the certificate to add
00322    */
00323   res->cert_list = MHD_gtls_realloc_fast (res->cert_list,
00324                                           (1 +
00325                                            res->ncerts) *
00326                                           sizeof (MHD_gnutls_cert *));
00327   if (res->cert_list == NULL)
00328     {
00329       MHD_gnutls_assert ();
00330       return GNUTLS_E_MEMORY_ERROR;
00331     }
00332 
00333   res->cert_list_length = MHD_gtls_realloc_fast (res->cert_list_length,
00334                                                  (1 +
00335                                                   res->ncerts) *
00336                                                  sizeof (int));
00337   if (res->cert_list_length == NULL)
00338     {
00339       MHD_gnutls_assert ();
00340       return GNUTLS_E_MEMORY_ERROR;
00341     }
00342 
00343   res->cert_list[res->ncerts] = NULL;   /* for realloc */
00344   res->cert_list_length[res->ncerts] = 0;
00345 
00346   if (type == GNUTLS_X509_FMT_DER)
00347     ret = parse_der_cert_mem (&res->cert_list[res->ncerts],
00348                               &res->cert_list_length[res->ncerts],
00349                               cert, cert_size);
00350   else
00351     ret =
00352       parse_pem_cert_mem (&res->cert_list[res->ncerts],
00353                           &res->cert_list_length[res->ncerts], cert,
00354                           cert_size);
00355 
00356   if (ret < 0)
00357     {
00358       MHD_gnutls_assert ();
00359       return ret;
00360     }
00361 
00362   return ret;
00363 }
00364 
00365 
00366 int
00367 MHD__gnutls_x509_privkey_to_gkey (MHD_gnutls_privkey * dest,
00368                                   MHD_gnutls_x509_privkey_t src)
00369 {
00370   int i, ret;
00371 
00372   memset (dest, 0, sizeof (MHD_gnutls_privkey));
00373 
00374   for (i = 0; i < src->params_size; i++)
00375     {
00376       dest->params[i] = MHD__gnutls_mpi_copy (src->params[i]);
00377       if (dest->params[i] == NULL)
00378         {
00379           MHD_gnutls_assert ();
00380           ret = GNUTLS_E_MEMORY_ERROR;
00381           goto cleanup;
00382         }
00383     }
00384 
00385   dest->pk_algorithm = src->pk_algorithm;
00386   dest->params_size = src->params_size;
00387 
00388   return 0;
00389 
00390 cleanup:
00391 
00392   for (i = 0; i < src->params_size; i++)
00393     {
00394       MHD_gtls_mpi_release (&dest->params[i]);
00395     }
00396   return ret;
00397 }
00398 
00399 void
00400 MHD_gtls_gkey_deinit (MHD_gnutls_privkey * key)
00401 {
00402   int i;
00403   if (key == NULL)
00404     return;
00405 
00406   for (i = 0; i < key->params_size; i++)
00407     {
00408       MHD_gtls_mpi_release (&key->params[i]);
00409     }
00410 }
00411 
00412 int
00413 MHD__gnutls_x509_raw_privkey_to_gkey (MHD_gnutls_privkey * privkey,
00414                                       const MHD_gnutls_datum_t * raw_key,
00415                                       MHD_gnutls_x509_crt_fmt_t type)
00416 {
00417   MHD_gnutls_x509_privkey_t tmpkey;
00418   int ret;
00419 
00420   ret = MHD_gnutls_x509_privkey_init (&tmpkey);
00421   if (ret < 0)
00422     {
00423       MHD_gnutls_assert ();
00424       return ret;
00425     }
00426 
00427   ret = MHD_gnutls_x509_privkey_import (tmpkey, raw_key, type);
00428   if (ret < 0)
00429     {
00430       MHD_gnutls_assert ();
00431       MHD_gnutls_x509_privkey_deinit (tmpkey);
00432       return ret;
00433     }
00434 
00435   ret = MHD__gnutls_x509_privkey_to_gkey (privkey, tmpkey);
00436   if (ret < 0)
00437     {
00438       MHD_gnutls_assert ();
00439       MHD_gnutls_x509_privkey_deinit (tmpkey);
00440       return ret;
00441     }
00442 
00443   MHD_gnutls_x509_privkey_deinit (tmpkey);
00444 
00445   return 0;
00446 }
00447 
00448 /* Reads a PEM encoded PKCS-1 RSA/DSA private key from memory.  Type
00449  * indicates the certificate format.  KEY can be NULL, to indicate
00450  * that GnuTLS doesn't know the private key.
00451  */
00452 static int
00453 read_key_mem (MHD_gtls_cert_credentials_t res,
00454               const void *key, int key_size, MHD_gnutls_x509_crt_fmt_t type)
00455 {
00456   int ret;
00457   MHD_gnutls_datum_t tmp;
00458 
00459   /* allocate space for the pkey list
00460    */
00461   res->pkey =
00462     MHD_gtls_realloc_fast (res->pkey,
00463                            (res->ncerts + 1) * sizeof (MHD_gnutls_privkey));
00464   if (res->pkey == NULL)
00465     {
00466       MHD_gnutls_assert ();
00467       return GNUTLS_E_MEMORY_ERROR;
00468     }
00469 
00470   if (key)
00471     {
00472       tmp.data = (opaque *) key;
00473       tmp.size = key_size;
00474 
00475       ret =
00476         MHD__gnutls_x509_raw_privkey_to_gkey (&res->pkey[res->ncerts], &tmp,
00477                                               type);
00478       if (ret < 0)
00479         {
00480           MHD_gnutls_assert ();
00481           return ret;
00482         }
00483     }
00484   else
00485     memset (&res->pkey[res->ncerts], 0, sizeof (MHD_gnutls_privkey));
00486 
00487   return 0;
00488 }
00489 
00520 int
00521 MHD__gnutls_certificate_set_x509_key_mem (MHD_gtls_cert_credentials_t
00522                                           res,
00523                                           const MHD_gnutls_datum_t * cert,
00524                                           const MHD_gnutls_datum_t * key,
00525                                           MHD_gnutls_x509_crt_fmt_t type)
00526 {
00527   int ret;
00528 
00529   /* this should be first
00530    */
00531   if ((ret = read_key_mem (res, key ? key->data : NULL,
00532                            key ? key->size : 0, type)) < 0)
00533     return ret;
00534 
00535   if ((ret = read_cert_mem (res, cert->data, cert->size, type)) < 0)
00536     return ret;
00537 
00538   res->ncerts++;
00539 
00540   if (key && (ret = MHD__gnutls_check_key_cert_match (res)) < 0)
00541     {
00542       MHD_gnutls_assert ();
00543       return ret;
00544     }
00545 
00546   return 0;
00547 }
00548 
00549 /* Returns 0 if it's ok to use the enum MHD_GNUTLS_KeyExchangeAlgorithm with this
00550  * certificate (uses the KeyUsage field).
00551  */
00552 int
00553 MHD__gnutls_check_key_usage (const MHD_gnutls_cert * cert,
00554                              enum MHD_GNUTLS_KeyExchangeAlgorithm alg)
00555 {
00556   unsigned int key_usage = 0;
00557   int encipher_type;
00558 
00559   if (cert == NULL)
00560     {
00561       MHD_gnutls_assert ();
00562       return GNUTLS_E_INTERNAL_ERROR;
00563     }
00564 
00565   if (MHD_gtls_map_kx_get_cred (alg, 1) == MHD_GNUTLS_CRD_CERTIFICATE ||
00566       MHD_gtls_map_kx_get_cred (alg, 0) == MHD_GNUTLS_CRD_CERTIFICATE)
00567     {
00568 
00569       key_usage = cert->key_usage;
00570 
00571       encipher_type = MHD_gtls_kx_encipher_type (alg);
00572 
00573       if (key_usage != 0 && encipher_type != CIPHER_IGN)
00574         {
00575           /* If key_usage has been set in the certificate
00576            */
00577 
00578           if (encipher_type == CIPHER_ENCRYPT)
00579             {
00580               /* If the key exchange method requires an encipher
00581                * type algorithm, and key's usage does not permit
00582                * encipherment, then fail.
00583                */
00584               if (!(key_usage & KEY_KEY_ENCIPHERMENT))
00585                 {
00586                   MHD_gnutls_assert ();
00587                   return GNUTLS_E_KEY_USAGE_VIOLATION;
00588                 }
00589             }
00590 
00591           if (encipher_type == CIPHER_SIGN)
00592             {
00593               /* The same as above, but for sign only keys
00594                */
00595               if (!(key_usage & KEY_DIGITAL_SIGNATURE))
00596                 {
00597                   MHD_gnutls_assert ();
00598                   return GNUTLS_E_KEY_USAGE_VIOLATION;
00599                 }
00600             }
00601         }
00602     }
00603   return 0;
00604 }

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