auth_cert.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001, 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 /* The certificate authentication functions which are needed in the handshake,
00026  * and are common to RSA and DHE key exchange, are in this file.
00027  */
00028 
00029 #include <gnutls_int.h>
00030 #include "gnutls_auth_int.h"
00031 #include "gnutls_errors.h"
00032 #include <gnutls_cert.h>
00033 #include <auth_cert.h>
00034 #include "gnutls_dh.h"
00035 #include "gnutls_num.h"
00036 #include "libtasn1.h"
00037 #include "gnutls_datum.h"
00038 #include <gnutls_pk.h>
00039 #include <gnutls_algorithms.h>
00040 #include <gnutls_global.h>
00041 #include <gnutls_record.h>
00042 #include <gnutls_sig.h>
00043 #include <gnutls_state.h>
00044 #include <gnutls_pk.h>
00045 #include <gnutls_x509.h>
00046 #include "debug.h"
00047 
00048 static MHD_gnutls_cert *alloc_and_load_x509_certs (MHD_gnutls_x509_crt_t *
00049                                                    certs, unsigned);
00050 static MHD_gnutls_privkey *alloc_and_load_x509_key (MHD_gnutls_x509_privkey_t
00051                                                     key);
00052 
00053 
00054 /* Copies data from a internal certificate struct (MHD_gnutls_cert) to
00055  * exported certificate struct (cert_auth_info_t)
00056  */
00057 static int
00058 MHD__gnutls_copy_certificate_auth_info (cert_auth_info_t info,
00059                                         MHD_gnutls_cert * cert, int ncerts)
00060 {
00061   /* Copy peer's information to auth_info_t
00062    */
00063   int ret, i, j;
00064 
00065   if (ncerts == 0)
00066     {
00067       info->raw_certificate_list = NULL;
00068       info->ncerts = 0;
00069       return 0;
00070     }
00071 
00072   info->raw_certificate_list =
00073     MHD_gnutls_calloc (1, sizeof (MHD_gnutls_datum_t) * ncerts);
00074   if (info->raw_certificate_list == NULL)
00075     {
00076       MHD_gnutls_assert ();
00077       return GNUTLS_E_MEMORY_ERROR;
00078     }
00079 
00080   for (i = 0; i < ncerts; i++)
00081     {
00082       if (cert->raw.size > 0)
00083         {
00084           ret =
00085             MHD__gnutls_set_datum (&info->raw_certificate_list[i],
00086                                    cert[i].raw.data, cert[i].raw.size);
00087           if (ret < 0)
00088             {
00089               MHD_gnutls_assert ();
00090               goto clear;
00091             }
00092         }
00093     }
00094   info->ncerts = ncerts;
00095 
00096   return 0;
00097 
00098 clear:
00099 
00100   for (j = 0; j < i; j++)
00101     MHD__gnutls_free_datum (&info->raw_certificate_list[j]);
00102 
00103   MHD_gnutls_free (info->raw_certificate_list);
00104   info->raw_certificate_list = NULL;
00105 
00106   return ret;
00107 }
00108 
00109 
00110 
00111 
00112 /* returns 0 if the algo_to-check exists in the pk_algos list,
00113  * -1 otherwise.
00114  */
00115 inline static int
00116 MHD__gnutls_check_pk_algo_in_list (const enum MHD_GNUTLS_PublicKeyAlgorithm
00117                                    *pk_algos, int pk_algos_length,
00118                                    enum MHD_GNUTLS_PublicKeyAlgorithm
00119                                    algo_to_check)
00120 {
00121   int i;
00122   for (i = 0; i < pk_algos_length; i++)
00123     {
00124       if (algo_to_check == pk_algos[i])
00125         {
00126           return 0;
00127         }
00128     }
00129   return -1;
00130 }
00131 
00132 
00133 /* Returns the issuer's Distinguished name in odn, of the certificate
00134  * specified in cert.
00135  */
00136 static int
00137 MHD__gnutls_cert_get_issuer_dn (MHD_gnutls_cert * cert,
00138                                 MHD_gnutls_datum_t * odn)
00139 {
00140   ASN1_TYPE dn;
00141   int len, result;
00142   int start, end;
00143 
00144   if ((result = MHD__asn1_create_element
00145        (MHD__gnutls_get_pkix (), "PKIX1.Certificate", &dn)) != ASN1_SUCCESS)
00146     {
00147       MHD_gnutls_assert ();
00148       return MHD_gtls_asn2err (result);
00149     }
00150 
00151   result = MHD__asn1_der_decoding (&dn, cert->raw.data, cert->raw.size, NULL);
00152   if (result != ASN1_SUCCESS)
00153     {
00154       /* couldn't decode DER */
00155       MHD_gnutls_assert ();
00156       MHD__asn1_delete_structure (&dn);
00157       return MHD_gtls_asn2err (result);
00158     }
00159 
00160   result =
00161     MHD__asn1_der_decoding_startEnd (dn, cert->raw.data, cert->raw.size,
00162                                      "tbsCertificate.issuer", &start, &end);
00163 
00164   if (result != ASN1_SUCCESS)
00165     {
00166       /* couldn't decode DER */
00167       MHD_gnutls_assert ();
00168       MHD__asn1_delete_structure (&dn);
00169       return MHD_gtls_asn2err (result);
00170     }
00171   MHD__asn1_delete_structure (&dn);
00172 
00173   len = end - start + 1;
00174 
00175   odn->size = len;
00176   odn->data = &cert->raw.data[start];
00177 
00178   return 0;
00179 }
00180 
00181 
00182 /* Locates the most appropriate x509 certificate using the
00183  * given DN. If indx == -1 then no certificate was found.
00184  *
00185  * That is to guess which certificate to use, based on the
00186  * CAs and sign algorithms supported by the peer server.
00187  */
00188 static int
00189 _find_x509_cert (const MHD_gtls_cert_credentials_t cred,
00190                  opaque * _data, size_t _data_size,
00191                  const enum MHD_GNUTLS_PublicKeyAlgorithm *pk_algos,
00192                  int pk_algos_length, int *indx)
00193 {
00194   unsigned size;
00195   MHD_gnutls_datum_t odn;
00196   opaque *data = _data;
00197   ssize_t data_size = _data_size;
00198   unsigned i, j;
00199   int result, cert_pk;
00200 
00201   *indx = -1;
00202   odn.size = 0;
00203   odn.data = NULL;
00204   do
00205     {
00206 
00207       DECR_LENGTH_RET (data_size, 2, 0);
00208       size = MHD_gtls_read_uint16 (data);
00209       DECR_LENGTH_RET (data_size, size, 0);
00210       data += 2;
00211 
00212       for (i = 0; i < cred->ncerts; i++)
00213         {
00214           for (j = 0; j < cred->cert_list_length[i]; j++)
00215             {
00216               if ((result =
00217                    MHD__gnutls_cert_get_issuer_dn (&cred->cert_list[i][j],
00218                                                    &odn)) != 0)
00219                 {
00220                   MHD_gnutls_assert ();
00221                   return result;
00222                 }
00223 
00224               if (odn.size != size)
00225                 continue;
00226 
00227               /* If the DN matches and
00228                * the *_SIGN algorithm matches
00229                * the cert is our cert!
00230                */
00231               cert_pk = cred->cert_list[i][0].subject_pk_algorithm;
00232 
00233               if ((memcmp (odn.data, data, size) == 0) &&
00234                   (MHD__gnutls_check_pk_algo_in_list
00235                    (pk_algos, pk_algos_length, cert_pk) == 0))
00236                 {
00237                   *indx = i;
00238                   break;
00239                 }
00240             }
00241           if (*indx != -1)
00242             break;
00243         }
00244 
00245       if (*indx != -1)
00246         break;
00247 
00248       /* move to next record */
00249       data += size;
00250 
00251     }
00252   while (1);
00253 
00254   return 0;
00255 
00256 }
00257 
00258 /* Returns the number of issuers in the server's
00259  * certificate request packet.
00260  */
00261 static int
00262 get_issuers_num (MHD_gtls_session_t session, opaque * data, ssize_t data_size)
00263 {
00264   int issuers_dn_len = 0, result;
00265   unsigned size;
00266 
00267   /* Count the number of the given issuers;
00268    * This is used to allocate the issuers_dn without
00269    * using realloc().
00270    */
00271 
00272   if (data_size == 0 || data == NULL)
00273     return 0;
00274 
00275   if (data_size > 0)
00276     do
00277       {
00278         /* This works like DECR_LEN()
00279          */
00280         result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
00281         DECR_LENGTH_COM (data_size, 2, goto error);
00282         size = MHD_gtls_read_uint16 (data);
00283 
00284         result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
00285         DECR_LENGTH_COM (data_size, size, goto error);
00286 
00287         data += 2;
00288 
00289         if (size > 0)
00290           {
00291             issuers_dn_len++;
00292             data += size;
00293           }
00294 
00295         if (data_size == 0)
00296           break;
00297 
00298       }
00299     while (1);
00300 
00301   return issuers_dn_len;
00302 
00303 error:
00304   return result;
00305 }
00306 
00307 /* Returns the issuers in the server's certificate request
00308  * packet.
00309  */
00310 static int
00311 get_issuers (MHD_gtls_session_t session,
00312              MHD_gnutls_datum_t * issuers_dn, int issuers_len,
00313              opaque * data, size_t data_size)
00314 {
00315   int i;
00316   unsigned size;
00317 
00318   if (MHD_gnutls_certificate_type_get (session) != MHD_GNUTLS_CRT_X509)
00319     return 0;
00320 
00321   /* put the requested DNs to req_dn, only in case
00322    * of X509 certificates.
00323    */
00324   if (issuers_len > 0)
00325     {
00326 
00327       for (i = 0; i < issuers_len; i++)
00328         {
00329           /* The checks here for the buffer boundaries
00330            * are not needed since the buffer has been
00331            * parsed above.
00332            */
00333           data_size -= 2;
00334 
00335           size = MHD_gtls_read_uint16 (data);
00336 
00337           data += 2;
00338 
00339           issuers_dn[i].data = data;
00340           issuers_dn[i].size = size;
00341 
00342           data += size;
00343         }
00344     }
00345 
00346   return 0;
00347 }
00348 
00349 /* Calls the client get callback.
00350  */
00351 static int
00352 call_get_cert_callback (MHD_gtls_session_t session,
00353                         MHD_gnutls_datum_t * issuers_dn,
00354                         int issuers_dn_length,
00355                         enum MHD_GNUTLS_PublicKeyAlgorithm *pk_algos,
00356                         int pk_algos_length)
00357 {
00358   unsigned i;
00359   MHD_gnutls_cert *local_certs = NULL;
00360   MHD_gnutls_privkey *local_key = NULL;
00361   MHD_gnutls_retr_st st;
00362   int ret;
00363   enum MHD_GNUTLS_CertificateType type =
00364     MHD_gnutls_certificate_type_get (session);
00365   MHD_gtls_cert_credentials_t cred;
00366 
00367   cred = (MHD_gtls_cert_credentials_t)
00368     MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
00369   if (cred == NULL)
00370     {
00371       MHD_gnutls_assert ();
00372       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00373     }
00374 
00375   memset (&st, 0, sizeof (st));
00376 
00377   if (session->security_parameters.entity == GNUTLS_SERVER)
00378     {
00379       ret = cred->server_get_cert_callback (session, &st);
00380     }
00381   else
00382     {                           /* CLIENT */
00383       ret =
00384         cred->client_get_cert_callback (session,
00385                                         issuers_dn, issuers_dn_length,
00386                                         pk_algos, pk_algos_length, &st);
00387     }
00388 
00389   if (ret < 0)
00390     {
00391       MHD_gnutls_assert ();
00392       return GNUTLS_E_INTERNAL_ERROR;
00393     }
00394 
00395   if (st.ncerts == 0)
00396     return 0;                   /* no certificate was selected */
00397 
00398   if (type != st.type)
00399     {
00400       MHD_gnutls_assert ();
00401       ret = GNUTLS_E_INVALID_REQUEST;
00402       goto cleanup;
00403     }
00404 
00405   if (type == MHD_GNUTLS_CRT_X509)
00406     {
00407       local_certs = alloc_and_load_x509_certs (st.cert.x509, st.ncerts);
00408       if (local_certs != NULL)
00409         local_key = alloc_and_load_x509_key (st.key.x509);
00410 
00411     }
00412   else
00413     {                           /* PGP */
00414       MHD_gnutls_assert ();
00415       ret = GNUTLS_E_INVALID_REQUEST;
00416       goto cleanup;
00417     }
00418 
00419   MHD_gtls_selected_certs_set (session, local_certs,
00420                                (local_certs != NULL) ? st.ncerts : 0,
00421                                local_key, 1);
00422 
00423   ret = 0;
00424 
00425 cleanup:
00426 
00427   if (st.type == MHD_GNUTLS_CRT_X509)
00428     {
00429       if (st.deinit_all)
00430         {
00431           for (i = 0; i < st.ncerts; i++)
00432             {
00433               MHD_gnutls_x509_crt_deinit (st.cert.x509[i]);
00434             }
00435           MHD_gnutls_free (st.cert.x509);
00436           MHD_gnutls_x509_privkey_deinit (st.key.x509);
00437         }
00438     }
00439   return ret;
00440 }
00441 
00442 /* Finds the appropriate certificate depending on the cA Distinguished name
00443  * advertized by the server. If none matches then returns 0 and -1 as index.
00444  * In case of an error a negative value, is returned.
00445  *
00446  * 20020128: added ability to select a certificate depending on the SIGN
00447  * algorithm (only in automatic mode).
00448  */
00449 static int
00450 _select_client_cert (MHD_gtls_session_t session,
00451                      opaque * _data, size_t _data_size,
00452                      enum MHD_GNUTLS_PublicKeyAlgorithm *pk_algos,
00453                      int pk_algos_length)
00454 {
00455   int result;
00456   int indx = -1;
00457   MHD_gtls_cert_credentials_t cred;
00458   opaque *data = _data;
00459   ssize_t data_size = _data_size;
00460   int issuers_dn_length;
00461   MHD_gnutls_datum_t *issuers_dn = NULL;
00462 
00463   cred = (MHD_gtls_cert_credentials_t)
00464     MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
00465   if (cred == NULL)
00466     {
00467       MHD_gnutls_assert ();
00468       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00469     }
00470 
00471   if (cred->client_get_cert_callback != NULL)
00472     {
00473 
00474       /* use a callback to get certificate
00475        */
00476       if (session->security_parameters.cert_type != MHD_GNUTLS_CRT_X509)
00477         issuers_dn_length = 0;
00478       else
00479         {
00480           issuers_dn_length = get_issuers_num (session, data, data_size);
00481           if (issuers_dn_length < 0)
00482             {
00483               MHD_gnutls_assert ();
00484               return issuers_dn_length;
00485             }
00486 
00487           if (issuers_dn_length > 0)
00488             {
00489               issuers_dn =
00490                 MHD_gnutls_malloc (sizeof (MHD_gnutls_datum_t) *
00491                                    issuers_dn_length);
00492               if (issuers_dn == NULL)
00493                 {
00494                   MHD_gnutls_assert ();
00495                   return GNUTLS_E_MEMORY_ERROR;
00496                 }
00497 
00498               result =
00499                 get_issuers (session, issuers_dn, issuers_dn_length,
00500                              data, data_size);
00501               if (result < 0)
00502                 {
00503                   MHD_gnutls_assert ();
00504                   goto cleanup;
00505                 }
00506             }
00507         }
00508 
00509       result =
00510         call_get_cert_callback (session, issuers_dn, issuers_dn_length,
00511                                 pk_algos, pk_algos_length);
00512       goto cleanup;
00513 
00514     }
00515   else
00516     {
00517       /* If we have no callbacks, try to guess.
00518        */
00519       result = 0;
00520 
00521       if (session->security_parameters.cert_type == MHD_GNUTLS_CRT_X509)
00522         result =
00523           _find_x509_cert (cred, _data, _data_size,
00524                            pk_algos, pk_algos_length, &indx);
00525       if (result < 0)
00526         {
00527           MHD_gnutls_assert ();
00528           return result;
00529         }
00530 
00531       if (indx >= 0)
00532         {
00533           MHD_gtls_selected_certs_set (session,
00534                                        &cred->cert_list[indx][0],
00535                                        cred->cert_list_length[indx],
00536                                        &cred->pkey[indx], 0);
00537         }
00538       else
00539         {
00540           MHD_gtls_selected_certs_set (session, NULL, 0, NULL, 0);
00541         }
00542 
00543       result = 0;
00544     }
00545 
00546 cleanup:
00547   MHD_gnutls_free (issuers_dn);
00548   return result;
00549 
00550 }
00551 
00552 /* Generate client certificate
00553  */
00554 static int
00555 MHD_gtls_gen_x509_crt (MHD_gtls_session_t session, opaque ** data)
00556 {
00557   int ret, i;
00558   opaque *pdata;
00559   MHD_gnutls_cert *apr_cert_list;
00560   MHD_gnutls_privkey *apr_pkey;
00561   int apr_cert_list_length;
00562 
00563   /* find the appropriate certificate
00564    */
00565   if ((ret =
00566        MHD_gtls_get_selected_cert (session, &apr_cert_list,
00567                                    &apr_cert_list_length, &apr_pkey)) < 0)
00568     {
00569       MHD_gnutls_assert ();
00570       return ret;
00571     }
00572 
00573   ret = 3;
00574   for (i = 0; i < apr_cert_list_length; i++)
00575     {
00576       ret += apr_cert_list[i].raw.size + 3;
00577       /* hold size
00578        * for uint24 */
00579     }
00580 
00581   /* if no certificates were found then send:
00582    * 0B 00 00 03 00 00 00    // Certificate with no certs
00583    * instead of:
00584    * 0B 00 00 00          // empty certificate handshake
00585    *
00586    * ( the above is the whole handshake message, not
00587    * the one produced here )
00588    */
00589 
00590   (*data) = MHD_gnutls_malloc (ret);
00591   pdata = (*data);
00592 
00593   if (pdata == NULL)
00594     {
00595       MHD_gnutls_assert ();
00596       return GNUTLS_E_MEMORY_ERROR;
00597     }
00598   MHD_gtls_write_uint24 (ret - 3, pdata);
00599   pdata += 3;
00600   for (i = 0; i < apr_cert_list_length; i++)
00601     {
00602       MHD_gtls_write_datum24 (pdata, apr_cert_list[i].raw);
00603       pdata += (3 + apr_cert_list[i].raw.size);
00604     }
00605 
00606   return ret;
00607 }
00608 
00609 int
00610 MHD_gtls_gen_cert_client_certificate (MHD_gtls_session_t session,
00611                                       opaque ** data)
00612 {
00613   switch (session->security_parameters.cert_type)
00614     {
00615     case MHD_GNUTLS_CRT_X509:
00616       return MHD_gtls_gen_x509_crt (session, data);
00617 
00618     default:
00619       MHD_gnutls_assert ();
00620       return GNUTLS_E_INTERNAL_ERROR;
00621     }
00622 }
00623 
00624 int
00625 MHD_gtls_gen_cert_server_certificate (MHD_gtls_session_t session,
00626                                       opaque ** data)
00627 {
00628   switch (session->security_parameters.cert_type)
00629     {
00630     case MHD_GNUTLS_CRT_X509:
00631       return MHD_gtls_gen_x509_crt (session, data);
00632     default:
00633       MHD_gnutls_assert ();
00634       return GNUTLS_E_INTERNAL_ERROR;
00635     }
00636 }
00637 
00638 /* Process server certificate
00639  */
00640 
00641 #define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) MHD_gtls_gcert_deinit(&peer_certificate_list[x])
00642 static int
00643 MHD_gtls_proc_x509_server_certificate (MHD_gtls_session_t session,
00644                                        opaque * data, size_t data_size)
00645 {
00646   int size, len, ret;
00647   opaque *p = data;
00648   cert_auth_info_t info;
00649   MHD_gtls_cert_credentials_t cred;
00650   ssize_t dsize = data_size;
00651   int i, j, x;
00652   MHD_gnutls_cert *peer_certificate_list;
00653   int peer_certificate_list_size = 0;
00654   MHD_gnutls_datum_t tmp;
00655 
00656   cred = (MHD_gtls_cert_credentials_t)
00657     MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
00658   if (cred == NULL)
00659     {
00660       MHD_gnutls_assert ();
00661       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00662     }
00663 
00664 
00665   if ((ret =
00666        MHD_gtls_auth_info_set (session, MHD_GNUTLS_CRD_CERTIFICATE,
00667                                sizeof (cert_auth_info_st), 1)) < 0)
00668     {
00669       MHD_gnutls_assert ();
00670       return ret;
00671     }
00672 
00673   info = MHD_gtls_get_auth_info (session);
00674 
00675   if (data == NULL || data_size == 0)
00676     {
00677       MHD_gnutls_assert ();
00678       /* no certificate was sent */
00679       return GNUTLS_E_NO_CERTIFICATE_FOUND;
00680     }
00681 
00682   DECR_LEN (dsize, 3);
00683   size = MHD_gtls_read_uint24 (p);
00684   p += 3;
00685 
00686   /* some implementations send 0B 00 00 06 00 00 03 00 00 00
00687    * instead of just 0B 00 00 03 00 00 00 as an empty certificate message.
00688    */
00689   if (size == 0 || size == 3)
00690     {
00691       MHD_gnutls_assert ();
00692       /* no certificate was sent */
00693       return GNUTLS_E_NO_CERTIFICATE_FOUND;
00694     }
00695 
00696   i = dsize;
00697   while (i > 0)
00698     {
00699       DECR_LEN (dsize, 3);
00700       len = MHD_gtls_read_uint24 (p);
00701       p += 3;
00702       DECR_LEN (dsize, len);
00703       peer_certificate_list_size++;
00704       p += len;
00705       i -= len + 3;
00706     }
00707 
00708   if (peer_certificate_list_size == 0)
00709     {
00710       MHD_gnutls_assert ();
00711       return GNUTLS_E_NO_CERTIFICATE_FOUND;
00712     }
00713 
00714   /* Ok we now allocate the memory to hold the
00715    * certificate list
00716    */
00717 
00718   peer_certificate_list =
00719     MHD_gnutls_malloc (sizeof (MHD_gnutls_cert) *
00720                        (peer_certificate_list_size));
00721 
00722   if (peer_certificate_list == NULL)
00723     {
00724       MHD_gnutls_assert ();
00725       return GNUTLS_E_MEMORY_ERROR;
00726     }
00727   memset (peer_certificate_list, 0, sizeof (MHD_gnutls_cert) *
00728           peer_certificate_list_size);
00729 
00730   p = data + 3;
00731 
00732   /* Now we start parsing the list (again).
00733    * We don't use DECR_LEN since the list has
00734    * been parsed before.
00735    */
00736 
00737   for (j = 0; j < peer_certificate_list_size; j++)
00738     {
00739       len = MHD_gtls_read_uint24 (p);
00740       p += 3;
00741 
00742       tmp.size = len;
00743       tmp.data = p;
00744 
00745       if ((ret =
00746            MHD_gtls_x509_raw_cert_to_gcert (&peer_certificate_list
00747                                             [j], &tmp,
00748                                             CERT_ONLY_EXTENSIONS)) < 0)
00749         {
00750           MHD_gnutls_assert ();
00751           goto cleanup;
00752         }
00753 
00754       p += len;
00755     }
00756 
00757 
00758   if ((ret =
00759        MHD__gnutls_copy_certificate_auth_info (info,
00760                                                peer_certificate_list,
00761                                                peer_certificate_list_size)) <
00762       0)
00763     {
00764       MHD_gnutls_assert ();
00765       goto cleanup;
00766     }
00767 
00768   if ((ret =
00769        MHD__gnutls_check_key_usage (&peer_certificate_list[0],
00770                                     MHD_gnutls_kx_get (session))) < 0)
00771     {
00772       MHD_gnutls_assert ();
00773       goto cleanup;
00774     }
00775 
00776   ret = 0;
00777 
00778 cleanup:
00779   CLEAR_CERTS;
00780   MHD_gnutls_free (peer_certificate_list);
00781   return ret;
00782 
00783 }
00784 
00785 #define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) MHD_gtls_gcert_deinit(&peer_certificate_list[x])
00786 
00787 int
00788 MHD_gtls_proc_cert_server_certificate (MHD_gtls_session_t session,
00789                                        opaque * data, size_t data_size)
00790 {
00791   switch (session->security_parameters.cert_type)
00792     {
00793     case MHD_GNUTLS_CRT_X509:
00794       return MHD_gtls_proc_x509_server_certificate (session, data, data_size);
00795     default:
00796       MHD_gnutls_assert ();
00797       return GNUTLS_E_INTERNAL_ERROR;
00798     }
00799 }
00800 
00801 #define MAX_SIGN_ALGOS 2
00802 typedef enum CertificateSigType
00803 { RSA_SIGN = 1, DSA_SIGN
00804 } CertificateSigType;
00805 
00806 /* Checks if we support the given signature algorithm
00807  * (RSA or DSA). Returns the corresponding enum MHD_GNUTLS_PublicKeyAlgorithm
00808  * if true;
00809  */
00810 inline static int
00811 MHD__gnutls_check_supported_sign_algo (CertificateSigType algo)
00812 {
00813   switch (algo)
00814     {
00815     case RSA_SIGN:
00816       return MHD_GNUTLS_PK_RSA;
00817     default:
00818       return -1;
00819     }
00820 }
00821 
00822 int
00823 MHD_gtls_proc_cert_cert_req (MHD_gtls_session_t session, opaque * data,
00824                              size_t data_size)
00825 {
00826   int size, ret;
00827   opaque *p;
00828   MHD_gtls_cert_credentials_t cred;
00829   ssize_t dsize;
00830   int i, j;
00831   enum MHD_GNUTLS_PublicKeyAlgorithm pk_algos[MAX_SIGN_ALGOS];
00832   int pk_algos_length;
00833   enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session);
00834 
00835   cred = (MHD_gtls_cert_credentials_t)
00836     MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
00837   if (cred == NULL)
00838     {
00839       MHD_gnutls_assert ();
00840       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00841     }
00842 
00843   if ((ret =
00844        MHD_gtls_auth_info_set (session, MHD_GNUTLS_CRD_CERTIFICATE,
00845                                sizeof (cert_auth_info_st), 0)) < 0)
00846     {
00847       MHD_gnutls_assert ();
00848       return ret;
00849     }
00850 
00851   p = data;
00852   dsize = data_size;
00853 
00854   DECR_LEN (dsize, 1);
00855   size = p[0];
00856   p++;
00857   /* check if the sign algorithm is supported.
00858    */
00859   pk_algos_length = j = 0;
00860   for (i = 0; i < size; i++, p++)
00861     {
00862       DECR_LEN (dsize, 1);
00863       if ((ret = MHD__gnutls_check_supported_sign_algo (*p)) > 0)
00864         {
00865           if (j < MAX_SIGN_ALGOS)
00866             {
00867               pk_algos[j++] = ret;
00868               pk_algos_length++;
00869             }
00870         }
00871     }
00872 
00873   if (pk_algos_length == 0)
00874     {
00875       MHD_gnutls_assert ();
00876       return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
00877     }
00878 
00879   if (ver == MHD_GNUTLS_PROTOCOL_TLS1_2)
00880     {
00881       /* read supported hashes */
00882       int hash_num;
00883       DECR_LEN (dsize, 1);
00884 
00885       hash_num = p[0] & 0xFF;
00886       p++;
00887 
00888       DECR_LEN (dsize, hash_num);
00889       p += hash_num;
00890     }
00891 
00892   /* read the certificate authorities */
00893   DECR_LEN (dsize, 2);
00894   size = MHD_gtls_read_uint16 (p);
00895   p += 2;
00896 
00897   DECR_LEN (dsize, size);
00898 
00899   /* now we ask the user to tell which one
00900    * he wants to use.
00901    */
00902   if ((ret =
00903        _select_client_cert (session, p, size, pk_algos, pk_algos_length)) < 0)
00904     {
00905       MHD_gnutls_assert ();
00906       return ret;
00907     }
00908 
00909   /* We should reply with a certificate message,
00910    * even if we have no certificate to send.
00911    */
00912   session->key->certificate_requested = 1;
00913 
00914   return 0;
00915 }
00916 
00917 int
00918 MHD_gtls_gen_cert_client_cert_vrfy (MHD_gtls_session_t session,
00919                                     opaque ** data)
00920 {
00921   int ret;
00922   MHD_gnutls_cert *apr_cert_list;
00923   MHD_gnutls_privkey *apr_pkey;
00924   int apr_cert_list_length, size;
00925   MHD_gnutls_datum_t signature;
00926 
00927   *data = NULL;
00928 
00929   /* find the appropriate certificate */
00930   if ((ret =
00931        MHD_gtls_get_selected_cert (session, &apr_cert_list,
00932                                    &apr_cert_list_length, &apr_pkey)) < 0)
00933     {
00934       MHD_gnutls_assert ();
00935       return ret;
00936     }
00937 
00938   if (apr_cert_list_length > 0)
00939     {
00940       if ((ret =
00941            MHD_gtls_tls_sign_hdata (session,
00942                                     &apr_cert_list[0],
00943                                     apr_pkey, &signature)) < 0)
00944         {
00945           MHD_gnutls_assert ();
00946           return ret;
00947         }
00948     }
00949   else
00950     {
00951       return 0;
00952     }
00953 
00954   *data = MHD_gnutls_malloc (signature.size + 2);
00955   if (*data == NULL)
00956     {
00957       MHD__gnutls_free_datum (&signature);
00958       return GNUTLS_E_MEMORY_ERROR;
00959     }
00960   size = signature.size;
00961   MHD_gtls_write_uint16 (size, *data);
00962 
00963   memcpy (&(*data)[2], signature.data, size);
00964 
00965   MHD__gnutls_free_datum (&signature);
00966 
00967   return size + 2;
00968 }
00969 
00970 int
00971 MHD_gtls_proc_cert_client_cert_vrfy (MHD_gtls_session_t session,
00972                                      opaque * data, size_t data_size)
00973 {
00974   int size, ret;
00975   ssize_t dsize = data_size;
00976   opaque *pdata = data;
00977   MHD_gnutls_datum_t sig;
00978   cert_auth_info_t info = MHD_gtls_get_auth_info (session);
00979   MHD_gnutls_cert peer_cert;
00980 
00981   if (info == NULL || info->ncerts == 0)
00982     {
00983       MHD_gnutls_assert ();
00984       /* we need this in order to get peer's certificate */
00985       return GNUTLS_E_INTERNAL_ERROR;
00986     }
00987 
00988   DECR_LEN (dsize, 2);
00989   size = MHD_gtls_read_uint16 (pdata);
00990   pdata += 2;
00991 
00992   DECR_LEN (dsize, size);
00993 
00994   sig.data = pdata;
00995   sig.size = size;
00996 
00997   ret = MHD_gtls_raw_cert_to_gcert (&peer_cert,
00998                                     session->security_parameters.cert_type,
00999                                     &info->raw_certificate_list[0],
01000                                     CERT_NO_COPY);
01001 
01002   if (ret < 0)
01003     {
01004       MHD_gnutls_assert ();
01005       return ret;
01006     }
01007 
01008   if ((ret = MHD_gtls_verify_sig_hdata (session, &peer_cert, &sig)) < 0)
01009     {
01010       MHD_gnutls_assert ();
01011       MHD_gtls_gcert_deinit (&peer_cert);
01012       return ret;
01013     }
01014   MHD_gtls_gcert_deinit (&peer_cert);
01015 
01016   return 0;
01017 }
01018 
01019 #define CERTTYPE_SIZE 3
01020 int
01021 MHD_gtls_gen_cert_server_cert_req (MHD_gtls_session_t session, opaque ** data)
01022 {
01023   MHD_gtls_cert_credentials_t cred;
01024   int size;
01025   opaque *pdata;
01026   enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session);
01027 
01028   /* Now we need to generate the RDN sequence. This is
01029    * already in the CERTIFICATE_CRED structure, to improve
01030    * performance.
01031    */
01032 
01033   cred = (MHD_gtls_cert_credentials_t)
01034     MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
01035   if (cred == NULL)
01036     {
01037       MHD_gnutls_assert ();
01038       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
01039     }
01040 
01041   size = CERTTYPE_SIZE + 2;     /* 2 for enum MHD_GNUTLS_CertificateType + 2 for size of rdn_seq
01042                                  */
01043 
01044   if (session->security_parameters.cert_type == MHD_GNUTLS_CRT_X509 &&
01045       session->internals.ignore_rdn_sequence == 0)
01046     size += cred->x509_rdn_sequence.size;
01047 
01048   if (ver == MHD_GNUTLS_PROTOCOL_TLS1_2)
01049     /* Need at least one byte to announce the number of supported hash
01050        functions (see below).  */
01051     size += 1;
01052 
01053   (*data) = MHD_gnutls_malloc (size);
01054   pdata = (*data);
01055 
01056   if (pdata == NULL)
01057     {
01058       MHD_gnutls_assert ();
01059       return GNUTLS_E_MEMORY_ERROR;
01060     }
01061 
01062   pdata[0] = CERTTYPE_SIZE - 1;
01063 
01064   pdata[1] = RSA_SIGN;
01065   pdata[2] = DSA_SIGN;          /* only these for now */
01066   pdata += CERTTYPE_SIZE;
01067 
01068   if (ver == MHD_GNUTLS_PROTOCOL_TLS1_2)
01069     {
01070       /* Supported hashes (nothing for now -- FIXME). */
01071       *pdata = 0;
01072       pdata++;
01073     }
01074 
01075   if (session->security_parameters.cert_type == MHD_GNUTLS_CRT_X509 &&
01076       session->internals.ignore_rdn_sequence == 0)
01077     {
01078       MHD_gtls_write_datum16 (pdata, cred->x509_rdn_sequence);
01079       /* pdata += cred->x509_rdn_sequence.size + 2; */
01080     }
01081   else
01082     {
01083       MHD_gtls_write_uint16 (0, pdata);
01084       /* pdata+=2; */
01085     }
01086 
01087   return size;
01088 }
01089 
01090 
01091 /* This function will return the appropriate certificate to use.
01092  * Fills in the apr_cert_list, apr_cert_list_length and apr_pkey.
01093  * The return value is a negative value on error.
01094  *
01095  * It is normal to return 0 with no certificates in client side.
01096  *
01097  */
01098 int
01099 MHD_gtls_get_selected_cert (MHD_gtls_session_t session,
01100                             MHD_gnutls_cert ** apr_cert_list,
01101                             int *apr_cert_list_length,
01102                             MHD_gnutls_privkey ** apr_pkey)
01103 {
01104   if (session->security_parameters.entity == GNUTLS_SERVER)
01105     {
01106 
01107       /* select_client_cert() has been called before.
01108        */
01109 
01110       *apr_cert_list = session->internals.selected_cert_list;
01111       *apr_pkey = session->internals.selected_key;
01112       *apr_cert_list_length = session->internals.selected_cert_list_length;
01113 
01114       if (*apr_cert_list_length == 0 || *apr_cert_list == NULL)
01115         {
01116           MHD_gnutls_assert ();
01117           return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
01118         }
01119 
01120     }
01121   else
01122     {                           /* CLIENT SIDE
01123                                  */
01124 
01125       /* we have already decided which certificate
01126        * to send.
01127        */
01128       *apr_cert_list = session->internals.selected_cert_list;
01129       *apr_cert_list_length = session->internals.selected_cert_list_length;
01130       *apr_pkey = session->internals.selected_key;
01131 
01132     }
01133 
01134   return 0;
01135 }
01136 
01137 /* converts the given x509 certificate to MHD_gnutls_cert* and allocates
01138  * space for them.
01139  */
01140 static MHD_gnutls_cert *
01141 alloc_and_load_x509_certs (MHD_gnutls_x509_crt_t * certs, unsigned ncerts)
01142 {
01143   MHD_gnutls_cert *local_certs;
01144   int ret = 0;
01145   unsigned i, j;
01146 
01147   if (certs == NULL)
01148     return NULL;
01149 
01150   local_certs = MHD_gnutls_malloc (sizeof (MHD_gnutls_cert) * ncerts);
01151   if (local_certs == NULL)
01152     {
01153       MHD_gnutls_assert ();
01154       return NULL;
01155     }
01156 
01157   for (i = 0; i < ncerts; i++)
01158     {
01159       ret = MHD_gtls_x509_crt_to_gcert (&local_certs[i], certs[i], 0);
01160       if (ret < 0)
01161         break;
01162     }
01163 
01164   if (ret < 0)
01165     {
01166       MHD_gnutls_assert ();
01167       for (j = 0; j < i; j++)
01168         {
01169           MHD_gtls_gcert_deinit (&local_certs[j]);
01170         }
01171       MHD_gnutls_free (local_certs);
01172       return NULL;
01173     }
01174 
01175   return local_certs;
01176 }
01177 
01178 /* converts the given x509 key to MHD_gnutls_privkey* and allocates
01179  * space for it.
01180  */
01181 static MHD_gnutls_privkey *
01182 alloc_and_load_x509_key (MHD_gnutls_x509_privkey_t key)
01183 {
01184   MHD_gnutls_privkey *local_key;
01185   int ret = 0;
01186 
01187   if (key == NULL)
01188     return NULL;
01189 
01190   local_key = MHD_gnutls_malloc (sizeof (MHD_gnutls_privkey));
01191   if (local_key == NULL)
01192     {
01193       MHD_gnutls_assert ();
01194       return NULL;
01195     }
01196 
01197   ret = MHD__gnutls_x509_privkey_to_gkey (local_key, key);
01198   if (ret < 0)
01199     {
01200       MHD_gnutls_assert ();
01201       return NULL;
01202     }
01203 
01204   return local_key;
01205 }
01206 
01207 void
01208 MHD_gtls_selected_certs_deinit (MHD_gtls_session_t session)
01209 {
01210   if (session->internals.selected_need_free != 0)
01211     {
01212       int i;
01213 
01214       for (i = 0; i < session->internals.selected_cert_list_length; i++)
01215         {
01216           MHD_gtls_gcert_deinit (&session->internals.selected_cert_list[i]);
01217         }
01218       MHD_gnutls_free (session->internals.selected_cert_list);
01219       session->internals.selected_cert_list = NULL;
01220       session->internals.selected_cert_list_length = 0;
01221 
01222       MHD_gtls_gkey_deinit (session->internals.selected_key);
01223       if (session->internals.selected_key)
01224         {
01225           MHD_gnutls_free (session->internals.selected_key);
01226           session->internals.selected_key = NULL;
01227         }
01228     }
01229 
01230   return;
01231 }
01232 
01233 void
01234 MHD_gtls_selected_certs_set (MHD_gtls_session_t session,
01235                              MHD_gnutls_cert * certs, int ncerts,
01236                              MHD_gnutls_privkey * key, int need_free)
01237 {
01238   MHD_gtls_selected_certs_deinit (session);
01239 
01240   session->internals.selected_cert_list = certs;
01241   session->internals.selected_cert_list_length = ncerts;
01242   session->internals.selected_key = key;
01243   session->internals.selected_need_free = need_free;
01244 
01245 }
01246 
01247 
01248 /* finds the most appropriate certificate in the cert list.
01249  * The 'appropriate' is defined by the user.
01250  *
01251  * requested_algo holds the parameters required by the peer (RSA, DSA
01252  * or -1 for any).
01253  *
01254  * Returns 0 on success and a negative value on error. The
01255  * selected certificate will be in session->internals.selected_*.
01256  *
01257  */
01258 int
01259 MHD_gtls_server_select_cert (MHD_gtls_session_t session,
01260                              enum MHD_GNUTLS_PublicKeyAlgorithm
01261                              requested_algo)
01262 {
01263   unsigned i;
01264   int idx, ret;
01265   MHD_gtls_cert_credentials_t cred;
01266 
01267   cred = (MHD_gtls_cert_credentials_t)
01268     MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
01269   if (cred == NULL)
01270     {
01271       MHD_gnutls_assert ();
01272       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
01273     }
01274 
01275   /* If the callback which retrieves certificate has been set,
01276    * use it and leave.
01277    */
01278   if (cred->server_get_cert_callback != NULL)
01279     return call_get_cert_callback (session, NULL, 0, NULL, 0);
01280 
01281   /* Otherwise... */
01282 
01283   ret = 0;
01284   idx = -1;                     /* default is use no certificate */
01285 
01286 
01287   for (i = 0; i < cred->ncerts; i++)
01288     {
01289       /* find one compatible certificate
01290        */
01291       if (requested_algo == GNUTLS_PK_ANY ||
01292           requested_algo == cred->cert_list[i][0].subject_pk_algorithm)
01293         {
01294           /* if cert type matches
01295            */
01296           if (session->security_parameters.cert_type ==
01297               cred->cert_list[i][0].cert_type)
01298             {
01299               idx = i;
01300               break;
01301             }
01302         }
01303     }
01304 
01305   /* store the certificate pointer for future use, in the handshake.
01306    * (This will allow not calling this callback again.)
01307    */
01308   if (idx >= 0 && ret == 0)
01309     {
01310       MHD_gtls_selected_certs_set (session,
01311                                    &cred->cert_list[idx][0],
01312                                    cred->cert_list_length[idx],
01313                                    &cred->pkey[idx], 0);
01314     }
01315   else
01316     /* Certificate does not support REQUESTED_ALGO.  */
01317     ret = GNUTLS_E_INSUFFICIENT_CREDENTIALS;
01318 
01319   return ret;
01320 }
01321 
01322 /* Frees the MHD_gtls_rsa_info_st structure.
01323  */
01324 void
01325 MHD_gtls_free_rsa_info (rsa_info_st * rsa)
01326 {
01327   MHD__gnutls_free_datum (&rsa->modulus);
01328   MHD__gnutls_free_datum (&rsa->exponent);
01329 }

Generated by  doxygen 1.6.2