gnutls_pk.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 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 functions needed for RSA/DSA public key
00026  * encryption and signatures.
00027  */
00028 
00029 #include <gnutls_int.h>
00030 #include <gnutls_mpi.h>
00031 #include <gnutls_pk.h>
00032 #include <gnutls_errors.h>
00033 #include <gnutls_datum.h>
00034 #include <gnutls_global.h>
00035 #include <gnutls_num.h>
00036 #include "debug.h"
00037 #include <gc.h>
00038 
00039 /* x509 */
00040 #include "common.h"
00041 #include "mpi.h"
00042 
00043 static int MHD__gnutls_pk_encrypt (int algo, mpi_t * resarr, mpi_t data,
00044                                    mpi_t * pkey, int pkey_len);
00045 static int MHD__gnutls_pk_sign (int algo, mpi_t * data, mpi_t hash,
00046                                 mpi_t * pkey, int);
00047 static int MHD__gnutls_pk_decrypt (int algo, mpi_t * resarr, mpi_t data,
00048                                    mpi_t * pkey, int);
00049 
00050 
00051 /* Do PKCS-1 RSA encryption.
00052  * params is modulus, public exp.
00053  */
00054 int
00055 MHD_gtls_pkcs1_rsa_encrypt (MHD_gnutls_datum_t * ciphertext,
00056                             const MHD_gnutls_datum_t * plaintext,
00057                             mpi_t * params, unsigned params_len,
00058                             unsigned btype)
00059 {
00060   unsigned int i, pad;
00061   int ret;
00062   mpi_t m, res;
00063   opaque *edata, *ps;
00064   size_t k, psize;
00065   size_t mod_bits;
00066 
00067   mod_bits = MHD__gnutls_mpi_get_nbits (params[0]);
00068   k = mod_bits / 8;
00069   if (mod_bits % 8 != 0)
00070     k++;
00071 
00072   if (plaintext->size > k - 11)
00073     {
00074       MHD_gnutls_assert ();
00075       return GNUTLS_E_PK_ENCRYPTION_FAILED;
00076     }
00077 
00078   edata = MHD_gnutls_alloca (k);
00079   if (edata == NULL)
00080     {
00081       MHD_gnutls_assert ();
00082       return GNUTLS_E_MEMORY_ERROR;
00083     }
00084 
00085   /* EB = 00||BT||PS||00||D
00086    * (use block type 'btype')
00087    */
00088 
00089   edata[0] = 0;
00090   edata[1] = btype;
00091   psize = k - 3 - plaintext->size;
00092 
00093   ps = &edata[2];
00094   switch (btype)
00095     {
00096     case 2:
00097       /* using public key */
00098       if (params_len < RSA_PUBLIC_PARAMS)
00099         {
00100           MHD_gnutls_assert ();
00101           MHD_gnutls_afree (edata);
00102           return GNUTLS_E_INTERNAL_ERROR;
00103         }
00104 
00105       if (MHD_gc_pseudo_random ((char *) ps, psize) != GC_OK)
00106         {
00107           MHD_gnutls_assert ();
00108           MHD_gnutls_afree (edata);
00109           return GNUTLS_E_RANDOM_FAILED;
00110         }
00111       for (i = 0; i < psize; i++)
00112         while (ps[i] == 0)
00113           {
00114             if (MHD_gc_pseudo_random ((char *) &ps[i], 1) != GC_OK)
00115               {
00116                 MHD_gnutls_assert ();
00117                 MHD_gnutls_afree (edata);
00118                 return GNUTLS_E_RANDOM_FAILED;
00119               }
00120           }
00121       break;
00122     case 1:
00123       /* using private key */
00124 
00125       if (params_len < RSA_PRIVATE_PARAMS)
00126         {
00127           MHD_gnutls_assert ();
00128           MHD_gnutls_afree (edata);
00129           return GNUTLS_E_INTERNAL_ERROR;
00130         }
00131 
00132       for (i = 0; i < psize; i++)
00133         ps[i] = 0xff;
00134       break;
00135     default:
00136       MHD_gnutls_assert ();
00137       MHD_gnutls_afree (edata);
00138       return GNUTLS_E_INTERNAL_ERROR;
00139     }
00140 
00141   ps[psize] = 0;
00142   memcpy (&ps[psize + 1], plaintext->data, plaintext->size);
00143 
00144   if (MHD_gtls_mpi_scan_nz (&m, edata, &k) != 0)
00145     {
00146       MHD_gnutls_assert ();
00147       MHD_gnutls_afree (edata);
00148       return GNUTLS_E_MPI_SCAN_FAILED;
00149     }
00150   MHD_gnutls_afree (edata);
00151 
00152   if (btype == 2)               /* encrypt */
00153     ret = MHD__gnutls_pk_encrypt (GCRY_PK_RSA, &res, m, params, params_len);
00154   else                          /* sign */
00155     ret = MHD__gnutls_pk_sign (GCRY_PK_RSA, &res, m, params, params_len);
00156 
00157   MHD_gtls_mpi_release (&m);
00158 
00159   if (ret < 0)
00160     {
00161       MHD_gnutls_assert ();
00162       return ret;
00163     }
00164 
00165   MHD_gtls_mpi_print (NULL, &psize, res);
00166 
00167   if (psize < k)
00168     {
00169       /* padding psize */
00170       pad = k - psize;
00171       psize = k;
00172     }
00173   else if (psize == k)
00174     {
00175       pad = 0;
00176     }
00177   else
00178     {                           /* psize > k !!! */
00179       /* This is an impossible situation */
00180       MHD_gnutls_assert ();
00181       MHD_gtls_mpi_release (&res);
00182       return GNUTLS_E_INTERNAL_ERROR;
00183     }
00184 
00185   ciphertext->data = MHD_gnutls_malloc (psize);
00186   if (ciphertext->data == NULL)
00187     {
00188       MHD_gnutls_assert ();
00189       MHD_gtls_mpi_release (&res);
00190       return GNUTLS_E_MEMORY_ERROR;
00191     }
00192   MHD_gtls_mpi_print (&ciphertext->data[pad], &psize, res);
00193   for (i = 0; i < pad; i++)
00194     ciphertext->data[i] = 0;
00195 
00196   ciphertext->size = k;
00197 
00198   MHD_gtls_mpi_release (&res);
00199 
00200   return 0;
00201 }
00202 
00203 
00204 /* Do PKCS-1 RSA decryption.
00205  * params is modulus, public exp., private key
00206  * Can decrypt block type 1 and type 2 packets.
00207  */
00208 int
00209 MHD_gtls_pkcs1_rsa_decrypt (MHD_gnutls_datum_t * plaintext,
00210                             const MHD_gnutls_datum_t * ciphertext,
00211                             mpi_t * params, unsigned params_len,
00212                             unsigned btype)
00213 {
00214   unsigned k, i;
00215   int ret;
00216   mpi_t c, res;
00217   opaque *edata;
00218   size_t esize, mod_bits;
00219 
00220   mod_bits = MHD__gnutls_mpi_get_nbits (params[0]);
00221   k = mod_bits / 8;
00222   if (mod_bits % 8 != 0)
00223     k++;
00224 
00225   esize = ciphertext->size;
00226 
00227   if (esize != k)
00228     {
00229       MHD_gnutls_assert ();
00230       return GNUTLS_E_PK_DECRYPTION_FAILED;
00231     }
00232 
00233   if (MHD_gtls_mpi_scan_nz (&c, ciphertext->data, &esize) != 0)
00234     {
00235       MHD_gnutls_assert ();
00236       return GNUTLS_E_MPI_SCAN_FAILED;
00237     }
00238 
00239   /* we can use btype to see if the private key is
00240    * available.
00241    */
00242   if (btype == 2)
00243     ret = MHD__gnutls_pk_decrypt (GCRY_PK_RSA, &res, c, params, params_len);
00244   else
00245     {
00246       ret = MHD__gnutls_pk_encrypt (GCRY_PK_RSA, &res, c, params, params_len);
00247     }
00248   MHD_gtls_mpi_release (&c);
00249 
00250   if (ret < 0)
00251     {
00252       MHD_gnutls_assert ();
00253       return ret;
00254     }
00255 
00256   MHD_gtls_mpi_print (NULL, &esize, res);
00257   edata = MHD_gnutls_alloca (esize + 1);
00258   if (edata == NULL)
00259     {
00260       MHD_gnutls_assert ();
00261       MHD_gtls_mpi_release (&res);
00262       return GNUTLS_E_MEMORY_ERROR;
00263     }
00264   MHD_gtls_mpi_print (&edata[1], &esize, res);
00265 
00266   MHD_gtls_mpi_release (&res);
00267 
00268   /* EB = 00||BT||PS||00||D
00269    * (use block type 'btype')
00270    *
00271    * From now on, return GNUTLS_E_DECRYPTION_FAILED on errors, to
00272    * avoid attacks similar to the one described by Bleichenbacher in:
00273    * "Chosen Ciphertext Attacks against Protocols Based on RSA
00274    * Encryption Standard PKCS #1".
00275    */
00276 
00277 
00278   edata[0] = 0;
00279   esize++;
00280 
00281   if (edata[0] != 0 || edata[1] != btype)
00282     {
00283       MHD_gnutls_assert ();
00284       MHD_gnutls_afree (edata);
00285       return GNUTLS_E_DECRYPTION_FAILED;
00286     }
00287 
00288   ret = GNUTLS_E_DECRYPTION_FAILED;
00289   switch (btype)
00290     {
00291     case 2:
00292       for (i = 2; i < esize; i++)
00293         {
00294           if (edata[i] == 0)
00295             {
00296               ret = 0;
00297               break;
00298             }
00299         }
00300       break;
00301     case 1:
00302       for (i = 2; i < esize; i++)
00303         {
00304           if (edata[i] == 0 && i > 2)
00305             {
00306               ret = 0;
00307               break;
00308             }
00309           if (edata[i] != 0xff)
00310             {
00311               MHD__gnutls_handshake_log ("PKCS #1 padding error");
00312               /* PKCS #1 padding error.  Don't use
00313                  GNUTLS_E_PKCS1_WRONG_PAD here.  */
00314               break;
00315             }
00316         }
00317       break;
00318     default:
00319       MHD_gnutls_assert ();
00320       MHD_gnutls_afree (edata);
00321       return GNUTLS_E_DECRYPTION_FAILED;
00322     }
00323   i++;
00324 
00325   if (ret < 0)
00326     {
00327       MHD_gnutls_assert ();
00328       MHD_gnutls_afree (edata);
00329       return GNUTLS_E_DECRYPTION_FAILED;
00330     }
00331 
00332   if (MHD__gnutls_sset_datum (plaintext, &edata[i], esize - i) < 0)
00333     {
00334       MHD_gnutls_assert ();
00335       MHD_gnutls_afree (edata);
00336       return GNUTLS_E_MEMORY_ERROR;
00337     }
00338 
00339   MHD_gnutls_afree (edata);
00340 
00341   return 0;
00342 }
00343 
00344 
00345 int
00346 MHD_gtls_rsa_verify (const MHD_gnutls_datum_t * vdata,
00347                      const MHD_gnutls_datum_t * ciphertext, mpi_t * params,
00348                      int params_len, int btype)
00349 {
00350 
00351   MHD_gnutls_datum_t plain;
00352   int ret;
00353 
00354   /* decrypt signature */
00355   if ((ret =
00356        MHD_gtls_pkcs1_rsa_decrypt (&plain, ciphertext, params, params_len,
00357                                    btype)) < 0)
00358     {
00359       MHD_gnutls_assert ();
00360       return ret;
00361     }
00362 
00363   if (plain.size != vdata->size)
00364     {
00365       MHD_gnutls_assert ();
00366       MHD__gnutls_free_datum (&plain);
00367       return GNUTLS_E_PK_SIG_VERIFY_FAILED;
00368     }
00369 
00370   if (memcmp (plain.data, vdata->data, plain.size) != 0)
00371     {
00372       MHD_gnutls_assert ();
00373       MHD__gnutls_free_datum (&plain);
00374       return GNUTLS_E_PK_SIG_VERIFY_FAILED;
00375     }
00376 
00377   MHD__gnutls_free_datum (&plain);
00378 
00379   return 0;                     /* ok */
00380 }
00381 
00382 
00383 /* this is taken from gnupg
00384  */
00385 
00386 /****************
00387  * Emulate our old PK interface here - sometime in the future we might
00388  * change the internal design to directly fit to libgcrypt.
00389  */
00390 static int
00391 MHD__gnutls_pk_encrypt (int algo, mpi_t * resarr, mpi_t data,
00392                         mpi_t * pkey, int pkey_len)
00393 {
00394   gcry_sexp_t s_ciph, s_data, s_pkey;
00395   int rc = -1;
00396 
00397   /* make a sexp from pkey */
00398   switch (algo)
00399     {
00400     case GCRY_PK_RSA:
00401       if (pkey_len >= 2)
00402         rc = gcry_sexp_build (&s_pkey, NULL,
00403                               "(public-key(rsa(n%m)(e%m)))",
00404                               pkey[0], pkey[1]);
00405       break;
00406 
00407     default:
00408       MHD_gnutls_assert ();
00409       return GNUTLS_E_INTERNAL_ERROR;
00410     }
00411 
00412   if (rc != 0)
00413     {
00414       MHD_gnutls_assert ();
00415       return GNUTLS_E_INTERNAL_ERROR;
00416     }
00417 
00418   /* put the data into a simple list */
00419   if (gcry_sexp_build (&s_data, NULL, "%m", data))
00420     {
00421       MHD_gnutls_assert ();
00422       gcry_sexp_release (s_pkey);
00423       return GNUTLS_E_INTERNAL_ERROR;
00424     }
00425 
00426   /* pass it to libgcrypt */
00427   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
00428   gcry_sexp_release (s_data);
00429   gcry_sexp_release (s_pkey);
00430 
00431   if (rc != 0)
00432     {
00433       MHD_gnutls_assert ();
00434       return GNUTLS_E_PK_ENCRYPTION_FAILED;
00435 
00436     }
00437   else
00438     {                           /* add better error handling or make gnupg use S-Exp directly */
00439       gcry_sexp_t list = gcry_sexp_find_token (s_ciph, "a", 0);
00440       if (list == NULL)
00441         {
00442           MHD_gnutls_assert ();
00443           gcry_sexp_release (s_ciph);
00444           return GNUTLS_E_INTERNAL_ERROR;
00445         }
00446 
00447       resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
00448       gcry_sexp_release (list);
00449 
00450       if (resarr[0] == NULL)
00451         {
00452           MHD_gnutls_assert ();
00453           gcry_sexp_release (s_ciph);
00454           return GNUTLS_E_INTERNAL_ERROR;
00455         }
00456     }
00457 
00458   gcry_sexp_release (s_ciph);
00459   return rc;
00460 }
00461 
00462 static int
00463 MHD__gnutls_pk_decrypt (int algo, mpi_t * resarr, mpi_t data, mpi_t * pkey,
00464                         int pkey_len)
00465 {
00466   gcry_sexp_t s_plain, s_data, s_pkey;
00467   int rc = -1;
00468 
00469   /* make a sexp from pkey */
00470   switch (algo)
00471     {
00472     case GCRY_PK_RSA:
00473       if (pkey_len >= 6)
00474         rc = gcry_sexp_build (&s_pkey, NULL,
00475                               "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
00476                               pkey[0], pkey[1], pkey[2], pkey[3],
00477                               pkey[4], pkey[5]);
00478       break;
00479 
00480     default:
00481       MHD_gnutls_assert ();
00482       return GNUTLS_E_INTERNAL_ERROR;
00483     }
00484 
00485   if (rc != 0)
00486     {
00487       MHD_gnutls_assert ();
00488       return GNUTLS_E_INTERNAL_ERROR;
00489     }
00490 
00491   /* put the data into a simple list */
00492   if (gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data))
00493     {
00494       MHD_gnutls_assert ();
00495       gcry_sexp_release (s_pkey);
00496       return GNUTLS_E_INTERNAL_ERROR;
00497     }
00498 
00499   /* pass it to libgcrypt */
00500   rc = gcry_pk_decrypt (&s_plain, s_data, s_pkey);
00501   gcry_sexp_release (s_data);
00502   gcry_sexp_release (s_pkey);
00503 
00504   if (rc != 0)
00505     {
00506       MHD_gnutls_assert ();
00507       return GNUTLS_E_PK_DECRYPTION_FAILED;
00508 
00509     }
00510   else
00511     {                           /* add better error handling or make gnupg use S-Exp directly */
00512       resarr[0] = gcry_sexp_nth_mpi (s_plain, 0, 0);
00513 
00514       if (resarr[0] == NULL)
00515         {
00516           MHD_gnutls_assert ();
00517           gcry_sexp_release (s_plain);
00518           return GNUTLS_E_INTERNAL_ERROR;
00519         }
00520     }
00521 
00522   gcry_sexp_release (s_plain);
00523   return rc;
00524 }
00525 
00526 
00527 /* in case of DSA puts into data, r,s
00528  */
00529 static int
00530 MHD__gnutls_pk_sign (int algo, mpi_t * data, mpi_t hash, mpi_t * pkey,
00531                      int pkey_len)
00532 {
00533   gcry_sexp_t s_hash, s_key, s_sig;
00534   int rc = -1;
00535 
00536   /* make a sexp from pkey */
00537   switch (algo)
00538     {
00539     case GCRY_PK_DSA:
00540       if (pkey_len >= 5)
00541         rc = gcry_sexp_build (&s_key, NULL,
00542                               "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
00543                               pkey[0], pkey[1], pkey[2], pkey[3], pkey[4]);
00544       else
00545         {
00546           MHD_gnutls_assert ();
00547         }
00548 
00549       break;
00550     case GCRY_PK_RSA:
00551       if (pkey_len >= 6)
00552         rc = gcry_sexp_build (&s_key, NULL,
00553                               "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
00554                               pkey[0], pkey[1], pkey[2], pkey[3],
00555                               pkey[4], pkey[5]);
00556       else
00557         {
00558           MHD_gnutls_assert ();
00559         }
00560       break;
00561 
00562     default:
00563       MHD_gnutls_assert ();
00564       return GNUTLS_E_INTERNAL_ERROR;
00565     }
00566 
00567   if (rc != 0)
00568     {
00569       MHD_gnutls_assert ();
00570       return GNUTLS_E_INTERNAL_ERROR;
00571     }
00572 
00573   /* put the data into a simple list */
00574   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
00575     {
00576       MHD_gnutls_assert ();
00577       return GNUTLS_E_INTERNAL_ERROR;
00578     }
00579 
00580   /* pass it to libgcrypt */
00581   rc = gcry_pk_sign (&s_sig, s_hash, s_key);
00582   gcry_sexp_release (s_hash);
00583   gcry_sexp_release (s_key);
00584 
00585   if (rc != 0)
00586     {
00587       MHD_gnutls_assert ();
00588       return GNUTLS_E_PK_SIGN_FAILED;
00589 
00590     }
00591   else
00592     {
00593       gcry_sexp_t list;
00594 
00595       if (algo == GCRY_PK_DSA)
00596         {
00597           list = gcry_sexp_find_token (s_sig, "r", 0);
00598           if (list == NULL)
00599             {
00600               MHD_gnutls_assert ();
00601               gcry_sexp_release (s_sig);
00602               return GNUTLS_E_INTERNAL_ERROR;
00603             }
00604 
00605           data[0] = gcry_sexp_nth_mpi (list, 1, 0);
00606           gcry_sexp_release (list);
00607 
00608           list = gcry_sexp_find_token (s_sig, "s", 0);
00609           if (list == NULL)
00610             {
00611               MHD_gnutls_assert ();
00612               gcry_sexp_release (s_sig);
00613               return GNUTLS_E_INTERNAL_ERROR;
00614             }
00615 
00616           data[1] = gcry_sexp_nth_mpi (list, 1, 0);
00617           gcry_sexp_release (list);
00618         }
00619       else
00620         {                       /* GCRY_PK_RSA */
00621           list = gcry_sexp_find_token (s_sig, "s", 0);
00622           if (list == NULL)
00623             {
00624               MHD_gnutls_assert ();
00625               gcry_sexp_release (s_sig);
00626               return GNUTLS_E_INTERNAL_ERROR;
00627             }
00628 
00629           data[0] = gcry_sexp_nth_mpi (list, 1, 0);
00630           gcry_sexp_release (list);
00631         }
00632     }
00633 
00634   gcry_sexp_release (s_sig);
00635   return 0;
00636 }

Generated on Fri Feb 27 18:18:40 2009 for GNU libmicrohttpd by  doxygen 1.5.8