LCOV - code coverage report
Current view: top level - g10 - pkglue.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 90 160 56.2 %
Date: 2015-11-05 17:10:59 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* pkglue.c - public key operations glue code
       2             :  * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2014 Werner Koch
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * GnuPG is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : #include <errno.h>
      26             : #include <assert.h>
      27             : 
      28             : #include "gpg.h"
      29             : #include "util.h"
      30             : #include "pkglue.h"
      31             : #include "main.h"
      32             : #include "options.h"
      33             : 
      34             : /* FIXME: Better chnage the fucntion name because mpi_ is used by
      35             :    gcrypt macros.  */
      36             : gcry_mpi_t
      37         704 : get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
      38             : {
      39             :   gcry_sexp_t list;
      40             :   gcry_mpi_t data;
      41             : 
      42         704 :   list = gcry_sexp_find_token (sexp, item, 0);
      43         704 :   assert (list);
      44         704 :   data = gcry_sexp_nth_mpi (list, 1, mpifmt);
      45         704 :   assert (data);
      46         704 :   gcry_sexp_release (list);
      47         704 :   return data;
      48             : }
      49             : 
      50             : 
      51             : 
      52             : /****************
      53             :  * Emulate our old PK interface here - sometime in the future we might
      54             :  * change the internal design to directly fit to libgcrypt.
      55             :  */
      56             : int
      57         367 : pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
      58             :            gcry_mpi_t *data, gcry_mpi_t *pkey)
      59             : {
      60             :   gcry_sexp_t s_sig, s_hash, s_pkey;
      61             :   int rc;
      62             : 
      63             :   /* Make a sexp from pkey.  */
      64         367 :   if (pkalgo == PUBKEY_ALGO_DSA)
      65             :     {
      66         882 :       rc = gcry_sexp_build (&s_pkey, NULL,
      67             :                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
      68         882 :                             pkey[0], pkey[1], pkey[2], pkey[3]);
      69             :     }
      70          73 :   else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL)
      71             :     {
      72           0 :       rc = gcry_sexp_build (&s_pkey, NULL,
      73             :                             "(public-key(elg(p%m)(g%m)(y%m)))",
      74           0 :                             pkey[0], pkey[1], pkey[2]);
      75             :     }
      76          73 :   else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
      77             :     {
      78          36 :       rc = gcry_sexp_build (&s_pkey, NULL,
      79          36 :                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
      80             :     }
      81          37 :   else if (pkalgo == PUBKEY_ALGO_ECDSA)
      82             :     {
      83          37 :       char *curve = openpgp_oid_to_str (pkey[0]);
      84          37 :       if (!curve)
      85           0 :         rc = gpg_error_from_syserror ();
      86             :       else
      87             :         {
      88          37 :           rc = gcry_sexp_build (&s_pkey, NULL,
      89             :                                 "(public-key(ecdsa(curve %s)(q%m)))",
      90          37 :                                 curve, pkey[1]);
      91          37 :           xfree (curve);
      92             :         }
      93             :     }
      94           0 :   else if (pkalgo == PUBKEY_ALGO_EDDSA)
      95             :     {
      96           0 :       char *curve = openpgp_oid_to_str (pkey[0]);
      97           0 :       if (!curve)
      98           0 :         rc = gpg_error_from_syserror ();
      99             :       else
     100             :         {
     101           0 :           rc = gcry_sexp_build (&s_pkey, NULL,
     102             :                                 "(public-key(ecc(curve %s)"
     103             :                                 "(flags eddsa)(q%m)))",
     104           0 :                                 curve, pkey[1]);
     105           0 :           xfree (curve);
     106             :         }
     107             :     }
     108             :   else
     109           0 :     return GPG_ERR_PUBKEY_ALGO;
     110             : 
     111         367 :   if (rc)
     112           0 :     BUG ();  /* gcry_sexp_build should never fail.  */
     113             : 
     114             :   /* Put hash into a S-Exp s_hash. */
     115         367 :   if (pkalgo == PUBKEY_ALGO_EDDSA)
     116             :     {
     117           0 :       if (gcry_sexp_build (&s_hash, NULL,
     118             :                            "(data(flags eddsa)(hash-algo sha512)(value %m))",
     119             :                            hash))
     120           0 :         BUG (); /* gcry_sexp_build should never fail.  */
     121             :     }
     122             :   else
     123             :     {
     124         367 :       if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
     125           0 :         BUG (); /* gcry_sexp_build should never fail.  */
     126             :     }
     127             : 
     128             :   /* Put data into a S-Exp s_sig. */
     129         367 :   s_sig = NULL;
     130         367 :   if (pkalgo == PUBKEY_ALGO_DSA)
     131             :     {
     132         294 :       if (!data[0] || !data[1])
     133           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     134             :       else
     135         294 :         rc = gcry_sexp_build (&s_sig, NULL,
     136         294 :                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
     137             :     }
     138          73 :   else if (pkalgo == PUBKEY_ALGO_ECDSA)
     139             :     {
     140          37 :       if (!data[0] || !data[1])
     141           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     142             :       else
     143          37 :         rc = gcry_sexp_build (&s_sig, NULL,
     144          37 :                               "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
     145             :     }
     146          36 :   else if (pkalgo == PUBKEY_ALGO_EDDSA)
     147             :     {
     148           0 :       if (!data[0] || !data[1])
     149           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     150             :       else
     151           0 :         rc = gcry_sexp_build (&s_sig, NULL,
     152           0 :                               "(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]);
     153             :     }
     154          36 :   else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
     155             :     {
     156           0 :       if (!data[0] || !data[1])
     157           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     158             :       else
     159           0 :         rc = gcry_sexp_build (&s_sig, NULL,
     160           0 :                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
     161             :     }
     162          36 :   else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
     163             :     {
     164          72 :       if (!data[0])
     165           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     166             :       else
     167          36 :         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
     168             :     }
     169             :   else
     170           0 :     BUG ();
     171             : 
     172         367 :   if (!rc)
     173         367 :     rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
     174             : 
     175         367 :   gcry_sexp_release (s_sig);
     176         367 :   gcry_sexp_release (s_hash);
     177         367 :   gcry_sexp_release (s_pkey);
     178         367 :   return rc;
     179             : }
     180             : 
     181             : 
     182             : 
     183             : 
     184             : /****************
     185             :  * Emulate our old PK interface here - sometime in the future we might
     186             :  * change the internal design to directly fit to libgcrypt.
     187             :  * PK is only required to compute the fingerprint for ECDH.
     188             :  */
     189             : int
     190         236 : pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
     191             :             PKT_public_key *pk, gcry_mpi_t *pkey)
     192             : {
     193         236 :   gcry_sexp_t s_ciph = NULL;
     194         236 :   gcry_sexp_t s_data = NULL;
     195         236 :   gcry_sexp_t s_pkey = NULL;
     196             :   int rc;
     197             : 
     198             :   /* Make a sexp from pkey.  */
     199         236 :   if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
     200             :     {
     201         430 :       rc = gcry_sexp_build (&s_pkey, NULL,
     202             :                             "(public-key(elg(p%m)(g%m)(y%m)))",
     203         430 :                             pkey[0], pkey[1], pkey[2]);
     204             :       /* Put DATA into a simplified S-expression.  */
     205         430 :       if (!rc)
     206         215 :         rc = gcry_sexp_build (&s_data, NULL, "%m", data);
     207             :     }
     208          21 :   else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
     209             :     {
     210           0 :       rc = gcry_sexp_build (&s_pkey, NULL,
     211             :                             "(public-key(rsa(n%m)(e%m)))",
     212           0 :                             pkey[0], pkey[1]);
     213             :       /* Put DATA into a simplified S-expression.  */
     214           0 :       if (!rc)
     215           0 :         rc = gcry_sexp_build (&s_data, NULL, "%m", data);
     216             :     }
     217          21 :   else if (algo == PUBKEY_ALGO_ECDH)
     218             :     {
     219             :       gcry_mpi_t k;
     220             : 
     221          21 :       rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
     222          21 :       if (!rc)
     223             :         {
     224             :           char *curve;
     225             : 
     226          21 :           curve = openpgp_oid_to_str (pkey[0]);
     227          21 :           if (!curve)
     228           0 :             rc = gpg_error_from_syserror ();
     229             :           else
     230             :             {
     231          21 :               int with_djb_tweak_flag = openpgp_oid_is_crv25519 (pkey[0]);
     232             : 
     233             :               /* Now use the ephemeral secret to compute the shared point.  */
     234          21 :               rc = gcry_sexp_build (&s_pkey, NULL,
     235             :                                     with_djb_tweak_flag ?
     236             :                                     "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))"
     237             :                                     : "(public-key(ecdh(curve%s)(q%m)))",
     238          21 :                                     curve, pkey[1]);
     239          21 :               xfree (curve);
     240             :               /* Put K into a simplified S-expression.  */
     241          21 :               if (!rc)
     242          21 :                 rc = gcry_sexp_build (&s_data, NULL, "%m", k);
     243             :             }
     244          21 :           gcry_mpi_release (k);
     245             :         }
     246             :     }
     247             :   else
     248           0 :     rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
     249             : 
     250             :   /* Pass it to libgcrypt. */
     251         236 :   if (!rc)
     252         236 :     rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
     253             : 
     254         236 :   gcry_sexp_release (s_data);
     255         236 :   gcry_sexp_release (s_pkey);
     256             : 
     257         236 :   if (rc)
     258             :     ;
     259         236 :   else if (algo == PUBKEY_ALGO_ECDH)
     260             :     {
     261             :       gcry_mpi_t shared, public, result;
     262             :       byte fp[MAX_FINGERPRINT_LEN];
     263             :       size_t fpn;
     264             : 
     265             :       /* Get the shared point and the ephemeral public key.  */
     266          21 :       shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
     267          21 :       public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
     268          21 :       gcry_sexp_release (s_ciph);
     269          21 :       s_ciph = NULL;
     270          21 :       if (DBG_CRYPTO)
     271             :         {
     272           0 :           log_debug ("ECDH ephemeral key:");
     273           0 :           gcry_mpi_dump (public);
     274           0 :           log_printf ("\n");
     275             :         }
     276             : 
     277          21 :       result = NULL;
     278          21 :       fingerprint_from_pk (pk, fp, &fpn);
     279          21 :       if (fpn != 20)
     280           0 :         rc = gpg_error (GPG_ERR_INV_LENGTH);
     281             :       else
     282          21 :         rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
     283             :                                                 fp, data, pkey, &result);
     284          21 :       gcry_mpi_release (shared);
     285          21 :       if (!rc)
     286             :         {
     287          21 :           resarr[0] = public;
     288          21 :           resarr[1] = result;
     289             :         }
     290             :       else
     291             :         {
     292           0 :           gcry_mpi_release (public);
     293           0 :           gcry_mpi_release (result);
     294             :         }
     295             :     }
     296             :   else /* Elgamal or RSA case.  */
     297             :     { /* Fixme: Add better error handling or make gnupg use
     298             :          S-expressions directly.  */
     299         215 :       resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
     300         215 :       if (!is_RSA (algo))
     301         215 :         resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
     302             :     }
     303             : 
     304         236 :   gcry_sexp_release (s_ciph);
     305         236 :   return rc;
     306             : }
     307             : 
     308             : 
     309             : /* Check whether SKEY is a suitable secret key. */
     310             : int
     311           0 : pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
     312             : {
     313             :   gcry_sexp_t s_skey;
     314             :   int rc;
     315             : 
     316           0 :   if (pkalgo == PUBKEY_ALGO_DSA)
     317             :     {
     318           0 :       rc = gcry_sexp_build (&s_skey, NULL,
     319             :                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
     320           0 :                             skey[0], skey[1], skey[2], skey[3], skey[4]);
     321             :     }
     322           0 :   else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
     323             :     {
     324           0 :       rc = gcry_sexp_build (&s_skey, NULL,
     325             :                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
     326           0 :                             skey[0], skey[1], skey[2], skey[3]);
     327             :     }
     328           0 :   else if (is_RSA (pkalgo))
     329             :     {
     330           0 :       rc = gcry_sexp_build (&s_skey, NULL,
     331             :                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
     332           0 :                             skey[0], skey[1], skey[2], skey[3], skey[4],
     333           0 :                             skey[5]);
     334             :     }
     335           0 :   else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH)
     336           0 :     {
     337           0 :       char *curve = openpgp_oid_to_str (skey[0]);
     338           0 :       if (!curve)
     339           0 :         rc = gpg_error_from_syserror ();
     340             :       else
     341             :         {
     342           0 :           rc = gcry_sexp_build (&s_skey, NULL,
     343             :                                 "(private-key(ecc(curve%s)(q%m)(d%m)))",
     344           0 :                                 curve, skey[1], skey[2]);
     345           0 :           xfree (curve);
     346             :         }
     347             :     }
     348           0 :   else if (pkalgo == PUBKEY_ALGO_EDDSA)
     349             :     {
     350           0 :       char *curve = openpgp_oid_to_str (skey[0]);
     351           0 :       if (!curve)
     352           0 :         rc = gpg_error_from_syserror ();
     353             :       else
     354             :         {
     355           0 :           rc = gcry_sexp_build (&s_skey, NULL,
     356             :                                 "(private-key(ecc(curve %s)"
     357             :                                 "(flags eddsa)(q%m)(d%m)))",
     358           0 :                                 curve, skey[1], skey[2]);
     359           0 :           xfree (curve);
     360             :         }
     361             :     }
     362             :   else
     363           0 :     return GPG_ERR_PUBKEY_ALGO;
     364             : 
     365           0 :   if (!rc)
     366             :     {
     367           0 :       rc = gcry_pk_testkey (s_skey);
     368           0 :       gcry_sexp_release (s_skey);
     369             :     }
     370           0 :   return rc;
     371             : }

Generated by: LCOV version 1.11