auth_rsa.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 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 /* This file contains the RSA key exchange part of the certificate
00026  * authentication.
00027  */
00028 
00029 #include "gnutls_int.h"
00030 #include "gnutls_auth_int.h"
00031 #include "gnutls_errors.h"
00032 #include "gnutls_dh.h"
00033 #include "gnutls_num.h"
00034 #include "gnutls_datum.h"
00035 #include "auth_cert.h"
00036 #include <gnutls_pk.h>
00037 #include <gnutls_algorithms.h>
00038 #include <gnutls_global.h>
00039 #include "debug.h"
00040 #include <gnutls_sig.h>
00041 #include <gnutls_x509.h>
00042 #include <gc.h>
00043 
00044 int MHD__gnutls_gen_rsa_client_kx (MHD_gtls_session_t, opaque **);
00045 int MHD__gnutls_proc_rsa_client_kx (MHD_gtls_session_t, opaque *, size_t);
00046 
00047 const MHD_gtls_mod_auth_st MHD_gtls_rsa_auth_struct = {
00048   "RSA",
00049   MHD_gtls_gen_cert_server_certificate,
00050   MHD_gtls_gen_cert_client_certificate,
00051   NULL,                         /* gen server kx */
00052   MHD__gnutls_gen_rsa_client_kx,
00053   MHD_gtls_gen_cert_client_cert_vrfy,   /* gen client cert vrfy */
00054   MHD_gtls_gen_cert_server_cert_req,    /* server cert request */
00055 
00056   MHD_gtls_proc_cert_server_certificate,
00057   MHD__gnutls_proc_cert_client_certificate,
00058   NULL,                         /* proc server kx */
00059   MHD__gnutls_proc_rsa_client_kx,       /* proc client kx */
00060   MHD_gtls_proc_cert_client_cert_vrfy,  /* proc client cert vrfy */
00061   MHD_gtls_proc_cert_cert_req   /* proc server cert request */
00062 };
00063 
00064 /* This function reads the RSA parameters from peer's certificate;
00065  */
00066 int
00067 MHD__gnutls_get_public_rsa_params (MHD_gtls_session_t session,
00068                                    mpi_t params[MAX_PUBLIC_PARAMS_SIZE],
00069                                    int *params_len)
00070 {
00071   int ret;
00072   cert_auth_info_t info;
00073   MHD_gnutls_cert peer_cert;
00074   int i;
00075 
00076   /* normal non export case */
00077 
00078   info = MHD_gtls_get_auth_info (session);
00079 
00080   if (info == NULL || info->ncerts == 0)
00081     {
00082       MHD_gnutls_assert ();
00083       return GNUTLS_E_INTERNAL_ERROR;
00084     }
00085 
00086   ret =
00087     MHD_gtls_raw_cert_to_gcert (&peer_cert,
00088                                 session->security_parameters.cert_type,
00089                                 &info->raw_certificate_list[0],
00090                                 CERT_ONLY_PUBKEY | CERT_NO_COPY);
00091 
00092   if (ret < 0)
00093     {
00094       MHD_gnutls_assert ();
00095       return ret;
00096     }
00097 
00098 
00099   /* EXPORT case: */
00100   if (MHD_gtls_cipher_suite_get_kx_algo
00101       (&session->security_parameters.current_cipher_suite)
00102       == MHD_GNUTLS_KX_RSA_EXPORT
00103       && MHD__gnutls_mpi_get_nbits (peer_cert.params[0]) > 512)
00104     {
00105 
00106       MHD_gtls_gcert_deinit (&peer_cert);
00107 
00108       if (session->key->rsa[0] == NULL || session->key->rsa[1] == NULL)
00109         {
00110           MHD_gnutls_assert ();
00111           return GNUTLS_E_INTERNAL_ERROR;
00112         }
00113 
00114       if (*params_len < 2)
00115         {
00116           MHD_gnutls_assert ();
00117           return GNUTLS_E_INTERNAL_ERROR;
00118         }
00119       *params_len = 2;
00120       for (i = 0; i < *params_len; i++)
00121         {
00122           params[i] = MHD__gnutls_mpi_copy (session->key->rsa[i]);
00123         }
00124 
00125       return 0;
00126     }
00127 
00128   /* end of export case */
00129 
00130   if (*params_len < peer_cert.params_size)
00131     {
00132       MHD_gnutls_assert ();
00133       return GNUTLS_E_INTERNAL_ERROR;
00134     }
00135   *params_len = peer_cert.params_size;
00136 
00137   for (i = 0; i < *params_len; i++)
00138     {
00139       params[i] = MHD__gnutls_mpi_copy (peer_cert.params[i]);
00140     }
00141   MHD_gtls_gcert_deinit (&peer_cert);
00142 
00143   return 0;
00144 }
00145 
00146 /* This function reads the RSA parameters from the private key
00147  */
00148 int
00149 MHD__gnutls_get_private_rsa_params (MHD_gtls_session_t session,
00150                                     mpi_t ** params, int *params_size)
00151 {
00152   int bits;
00153   MHD_gtls_cert_credentials_t cred;
00154   MHD_gtls_rsa_params_t rsa_params;
00155 
00156   cred = (MHD_gtls_cert_credentials_t)
00157     MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
00158   if (cred == NULL)
00159     {
00160       MHD_gnutls_assert ();
00161       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00162     }
00163 
00164   if (session->internals.selected_cert_list == NULL)
00165     {
00166       MHD_gnutls_assert ();
00167       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00168     }
00169 
00170   bits =
00171     MHD__gnutls_mpi_get_nbits (session->internals.selected_cert_list[0].
00172                                params[0]);
00173 
00174   if (MHD_gtls_cipher_suite_get_kx_algo
00175       (&session->security_parameters.current_cipher_suite)
00176       == MHD_GNUTLS_KX_RSA_EXPORT && bits > 512)
00177     {
00178 
00179       rsa_params =
00180         MHD_gtls_certificate_get_rsa_params (cred->rsa_params,
00181                                              cred->params_func, session);
00182       /* EXPORT case: */
00183       if (rsa_params == NULL)
00184         {
00185           MHD_gnutls_assert ();
00186           return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
00187         }
00188 
00189       /* In the export case, we do use temporary RSA params
00190        * of 512 bits size. The params in the certificate are
00191        * used to sign this temporary stuff.
00192        */
00193       *params_size = RSA_PRIVATE_PARAMS;
00194       *params = rsa_params->params;
00195 
00196       return 0;
00197     }
00198 
00199   /* non export cipher suites. */
00200 
00201   *params_size = session->internals.selected_key->params_size;
00202   *params = session->internals.selected_key->params;
00203 
00204   return 0;
00205 }
00206 
00207 int
00208 MHD__gnutls_proc_rsa_client_kx (MHD_gtls_session_t session, opaque * data,
00209                                 size_t _data_size)
00210 {
00211   MHD_gnutls_datum_t plaintext;
00212   MHD_gnutls_datum_t ciphertext;
00213   int ret, dsize;
00214   mpi_t *params;
00215   int params_len;
00216   int randomize_key = 0;
00217   ssize_t data_size = _data_size;
00218 
00219   if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3)
00220     {
00221       /* SSL 3.0
00222        */
00223       ciphertext.data = data;
00224       ciphertext.size = data_size;
00225     }
00226   else
00227     {
00228       /* TLS 1.0
00229        */
00230       DECR_LEN (data_size, 2);
00231       ciphertext.data = &data[2];
00232       dsize = MHD_gtls_read_uint16 (data);
00233 
00234       if (dsize != data_size)
00235         {
00236           MHD_gnutls_assert ();
00237           return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
00238         }
00239       ciphertext.size = dsize;
00240     }
00241 
00242   ret = MHD__gnutls_get_private_rsa_params (session, &params, &params_len);
00243   if (ret < 0)
00244     {
00245       MHD_gnutls_assert ();
00246       return ret;
00247     }
00248 
00249   ret = MHD_gtls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2);    /* btype==2 */
00250 
00251   if (ret < 0 || plaintext.size != TLS_MASTER_SIZE)
00252     {
00253       /* In case decryption fails then don't inform
00254        * the peer. Just use a random key. (in order to avoid
00255        * attack against pkcs-1 formating).
00256        */
00257       MHD_gnutls_assert ();
00258       MHD__gnutls_x509_log ("auth_rsa: Possible PKCS #1 format attack\n");
00259       randomize_key = 1;
00260     }
00261   else
00262     {
00263       /* If the secret was properly formatted, then
00264        * check the version number.
00265        */
00266       if (MHD__gnutls_get_adv_version_major (session) != plaintext.data[0]
00267           || MHD__gnutls_get_adv_version_minor (session) != plaintext.data[1])
00268         {
00269           /* No error is returned here, if the version number check
00270            * fails. We proceed normally.
00271            * That is to defend against the attack described in the paper
00272            * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
00273            * Ondej Pokorny and Tomas Rosa.
00274            */
00275           MHD_gnutls_assert ();
00276           MHD__gnutls_x509_log
00277             ("auth_rsa: Possible PKCS #1 version check format attack\n");
00278         }
00279     }
00280 
00281   if (randomize_key != 0)
00282     {
00283       session->key->key.size = TLS_MASTER_SIZE;
00284       session->key->key.data = MHD_gnutls_malloc (session->key->key.size);
00285       if (session->key->key.data == NULL)
00286         {
00287           MHD_gnutls_assert ();
00288           return GNUTLS_E_MEMORY_ERROR;
00289         }
00290 
00291       /* we do not need strong random numbers here.
00292        */
00293       if (MHD_gc_nonce
00294           ((char *) session->key->key.data, session->key->key.size) != GC_OK)
00295         {
00296           MHD_gnutls_assert ();
00297           return GNUTLS_E_RANDOM_FAILED;
00298         }
00299 
00300     }
00301   else
00302     {
00303       session->key->key.data = plaintext.data;
00304       session->key->key.size = plaintext.size;
00305     }
00306 
00307   /* This is here to avoid the version check attack
00308    * discussed above.
00309    */
00310   session->key->key.data[0] = MHD__gnutls_get_adv_version_major (session);
00311   session->key->key.data[1] = MHD__gnutls_get_adv_version_minor (session);
00312 
00313   return 0;
00314 }
00315 
00316 
00317 
00318 /* return RSA(random) using the peers public key
00319  */
00320 int
00321 MHD__gnutls_gen_rsa_client_kx (MHD_gtls_session_t session, opaque ** data)
00322 {
00323   cert_auth_info_t auth;
00324   MHD_gnutls_datum_t sdata;     /* data to send */
00325   mpi_t params[MAX_PUBLIC_PARAMS_SIZE];
00326   int params_len = MAX_PUBLIC_PARAMS_SIZE;
00327   int ret, i;
00328   enum MHD_GNUTLS_Protocol ver;
00329 
00330   if (session->key == NULL)
00331     {
00332       MHD_gnutls_assert ();
00333       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00334     }
00335 
00336   auth = session->key->auth_info;
00337   if (auth == NULL)
00338     {
00339       /* this shouldn't have happened. The proc_certificate
00340        * function should have detected that.
00341        */
00342       MHD_gnutls_assert ();
00343       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00344     }
00345 
00346   session->key->key.size = TLS_MASTER_SIZE;
00347   session->key->key.data = MHD_gnutls_secure_malloc (session->key->key.size);
00348 
00349   if (session->key->key.data == NULL)
00350     {
00351       MHD_gnutls_assert ();
00352       return GNUTLS_E_MEMORY_ERROR;
00353     }
00354 
00355   if (MHD_gc_pseudo_random ((char *) session->key->key.data,
00356                             session->key->key.size) != GC_OK)
00357     {
00358       MHD_gnutls_assert ();
00359       return GNUTLS_E_RANDOM_FAILED;
00360     }
00361 
00362   ver = MHD_gtls_get_adv_version (session);
00363 
00364   if (session->internals.rsa_pms_version[0] == 0)
00365     {
00366       session->key->key.data[0] = MHD_gtls_version_get_major (ver);
00367       session->key->key.data[1] = MHD_gtls_version_get_minor (ver);
00368     }
00369   else
00370     {                           /* use the version provided */
00371       session->key->key.data[0] = session->internals.rsa_pms_version[0];
00372       session->key->key.data[1] = session->internals.rsa_pms_version[1];
00373     }
00374 
00375   /* move RSA parameters to key (session).
00376    */
00377   if ((ret =
00378        MHD__gnutls_get_public_rsa_params (session, params, &params_len)) < 0)
00379     {
00380       MHD_gnutls_assert ();
00381       return ret;
00382     }
00383 
00384   if ((ret =
00385        MHD_gtls_pkcs1_rsa_encrypt (&sdata, &session->key->key,
00386                                    params, params_len, 2)) < 0)
00387     {
00388       MHD_gnutls_assert ();
00389       return ret;
00390     }
00391 
00392   for (i = 0; i < params_len; i++)
00393     MHD_gtls_mpi_release (&params[i]);
00394 
00395   if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3)
00396     {
00397       /* SSL 3.0 */
00398       *data = sdata.data;
00399       return sdata.size;
00400     }
00401   else
00402     {                           /* TLS 1 */
00403       *data = MHD_gnutls_malloc (sdata.size + 2);
00404       if (*data == NULL)
00405         {
00406           MHD__gnutls_free_datum (&sdata);
00407           return GNUTLS_E_MEMORY_ERROR;
00408         }
00409       MHD_gtls_write_datum16 (*data, sdata);
00410       ret = sdata.size + 2;
00411       MHD__gnutls_free_datum (&sdata);
00412       return ret;
00413     }
00414 
00415 }

Generated on Fri Feb 27 18:31:58 2009 for GNU libmicrohttpd by  doxygen 1.5.7.1