LCOV - code coverage report
Current view: top level - g10 - pkglue.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 131 189 69.3 %
Date: 2016-11-29 15:00:56 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 <https://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             : 
      27             : #include "gpg.h"
      28             : #include "util.h"
      29             : #include "pkglue.h"
      30             : #include "main.h"
      31             : #include "options.h"
      32             : 
      33             : /* FIXME: Better change the function name because mpi_ is used by
      34             :    gcrypt macros.  */
      35             : gcry_mpi_t
      36         761 : get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
      37             : {
      38             :   gcry_sexp_t list;
      39             :   gcry_mpi_t data;
      40             : 
      41         761 :   list = gcry_sexp_find_token (sexp, item, 0);
      42         761 :   log_assert (list);
      43         761 :   data = gcry_sexp_nth_mpi (list, 1, mpifmt);
      44         761 :   log_assert (data);
      45         761 :   gcry_sexp_release (list);
      46         761 :   return data;
      47             : }
      48             : 
      49             : 
      50             : 
      51             : /****************
      52             :  * Emulate our old PK interface here - sometime in the future we might
      53             :  * change the internal design to directly fit to libgcrypt.
      54             :  */
      55             : int
      56        1192 : pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
      57             :            gcry_mpi_t *data, gcry_mpi_t *pkey)
      58             : {
      59             :   gcry_sexp_t s_sig, s_hash, s_pkey;
      60             :   int rc;
      61        1192 :   unsigned int neededfixedlen = 0;
      62             : 
      63             :   /* Make a sexp from pkey.  */
      64        1192 :   if (pkalgo == PUBKEY_ALGO_DSA)
      65             :     {
      66         939 :       rc = gcry_sexp_build (&s_pkey, NULL,
      67             :                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
      68         939 :                             pkey[0], pkey[1], pkey[2], pkey[3]);
      69             :     }
      70         879 :   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         879 :   else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
      77             :     {
      78         832 :       rc = gcry_sexp_build (&s_pkey, NULL,
      79         832 :                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
      80             :     }
      81          47 :   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          10 :   else if (pkalgo == PUBKEY_ALGO_EDDSA)
      95             :     {
      96          10 :       char *curve = openpgp_oid_to_str (pkey[0]);
      97          10 :       if (!curve)
      98           0 :         rc = gpg_error_from_syserror ();
      99             :       else
     100             :         {
     101          10 :           rc = gcry_sexp_build (&s_pkey, NULL,
     102             :                                 "(public-key(ecc(curve %s)"
     103             :                                 "(flags eddsa)(q%m)))",
     104          10 :                                 curve, pkey[1]);
     105          10 :           xfree (curve);
     106             :         }
     107             : 
     108          10 :       if (openpgp_oid_is_ed25519 (pkey[0]))
     109          10 :         neededfixedlen = 256 / 8;
     110             :     }
     111             :   else
     112           0 :     return GPG_ERR_PUBKEY_ALGO;
     113             : 
     114        1192 :   if (rc)
     115           0 :     BUG ();  /* gcry_sexp_build should never fail.  */
     116             : 
     117             :   /* Put hash into a S-Exp s_hash. */
     118        1192 :   if (pkalgo == PUBKEY_ALGO_EDDSA)
     119             :     {
     120          10 :       if (gcry_sexp_build (&s_hash, NULL,
     121             :                            "(data(flags eddsa)(hash-algo sha512)(value %m))",
     122             :                            hash))
     123           0 :         BUG (); /* gcry_sexp_build should never fail.  */
     124             :     }
     125             :   else
     126             :     {
     127        1182 :       if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
     128           0 :         BUG (); /* gcry_sexp_build should never fail.  */
     129             :     }
     130             : 
     131             :   /* Put data into a S-Exp s_sig. */
     132        1192 :   s_sig = NULL;
     133        1192 :   if (pkalgo == PUBKEY_ALGO_DSA)
     134             :     {
     135         313 :       if (!data[0] || !data[1])
     136           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     137             :       else
     138         313 :         rc = gcry_sexp_build (&s_sig, NULL,
     139         313 :                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
     140             :     }
     141         879 :   else if (pkalgo == PUBKEY_ALGO_ECDSA)
     142             :     {
     143          37 :       if (!data[0] || !data[1])
     144           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     145             :       else
     146          37 :         rc = gcry_sexp_build (&s_sig, NULL,
     147          37 :                               "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
     148             :     }
     149         842 :   else if (pkalgo == PUBKEY_ALGO_EDDSA)
     150             :     {
     151          10 :       gcry_mpi_t r = data[0];
     152          10 :       gcry_mpi_t s = data[1];
     153             :       size_t rlen, slen, n;  /* (bytes) */
     154             :       char buf[64];
     155             : 
     156          10 :       log_assert (neededfixedlen <= sizeof buf);
     157             : 
     158          10 :       if (!r || !s)
     159           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     160          10 :       else if ((rlen = (gcry_mpi_get_nbits (r)+7)/8) > neededfixedlen || !rlen)
     161           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     162          10 :       else if ((slen = (gcry_mpi_get_nbits (s)+7)/8) > neededfixedlen || !slen)
     163           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     164             :       else
     165             :         {
     166             :           /* We need to fixup the length in case of leading zeroes.
     167             :            * OpenPGP does not allow leading zeroes and the parser for
     168             :            * the signature packet has no information on the use curve,
     169             :            * thus we need to do it here.  We won't do it for opaque
     170             :            * MPIs under the assumption that they are known to be fine;
     171             :            * we won't see them here anyway but the check is anyway
     172             :            * required.  Fixme: A nifty feature for gcry_sexp_build
     173             :            * would be a format to left pad the value (e.g. "%*M"). */
     174          10 :           rc = 0;
     175             : 
     176          10 :           if (rlen < neededfixedlen
     177           1 :               && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)
     178           1 :               && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r)))
     179             :             {
     180           1 :               log_assert (n < neededfixedlen);
     181           1 :               memmove (buf + (neededfixedlen - n), buf, n);
     182           1 :               memset (buf, 0, neededfixedlen - n);
     183           1 :               r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8);
     184             :             }
     185          10 :           if (slen < neededfixedlen
     186           1 :               && !gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)
     187           1 :               && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, s)))
     188             :             {
     189           1 :               log_assert (n < neededfixedlen);
     190           1 :               memmove (buf + (neededfixedlen - n), buf, n);
     191           1 :               memset (buf, 0, neededfixedlen - n);
     192           1 :               s = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8);
     193             :             }
     194             : 
     195          10 :           if (!rc)
     196          10 :             rc = gcry_sexp_build (&s_sig, NULL,
     197             :                                   "(sig-val(eddsa(r%M)(s%M)))", r, s);
     198             : 
     199          10 :           if (r != data[0])
     200           1 :             gcry_mpi_release (r);
     201          10 :           if (s != data[1])
     202           1 :             gcry_mpi_release (s);
     203             :         }
     204             :     }
     205         832 :   else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
     206             :     {
     207           0 :       if (!data[0] || !data[1])
     208           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     209             :       else
     210           0 :         rc = gcry_sexp_build (&s_sig, NULL,
     211           0 :                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
     212             :     }
     213         832 :   else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
     214             :     {
     215        1664 :       if (!data[0])
     216           0 :         rc = gpg_error (GPG_ERR_BAD_MPI);
     217             :       else
     218         832 :         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
     219             :     }
     220             :   else
     221           0 :     BUG ();
     222             : 
     223        1192 :   if (!rc)
     224        1192 :     rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
     225             : 
     226        1192 :   gcry_sexp_release (s_sig);
     227        1192 :   gcry_sexp_release (s_hash);
     228        1192 :   gcry_sexp_release (s_pkey);
     229        1192 :   return rc;
     230             : }
     231             : 
     232             : 
     233             : 
     234             : 
     235             : /****************
     236             :  * Emulate our old PK interface here - sometime in the future we might
     237             :  * change the internal design to directly fit to libgcrypt.
     238             :  * PK is only required to compute the fingerprint for ECDH.
     239             :  */
     240             : int
     241         255 : pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
     242             :             PKT_public_key *pk, gcry_mpi_t *pkey)
     243             : {
     244         255 :   gcry_sexp_t s_ciph = NULL;
     245         255 :   gcry_sexp_t s_data = NULL;
     246         255 :   gcry_sexp_t s_pkey = NULL;
     247             :   int rc;
     248             : 
     249             :   /* Make a sexp from pkey.  */
     250         255 :   if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
     251             :     {
     252         446 :       rc = gcry_sexp_build (&s_pkey, NULL,
     253             :                             "(public-key(elg(p%m)(g%m)(y%m)))",
     254         446 :                             pkey[0], pkey[1], pkey[2]);
     255             :       /* Put DATA into a simplified S-expression.  */
     256         446 :       if (!rc)
     257         223 :         rc = gcry_sexp_build (&s_data, NULL, "%m", data);
     258             :     }
     259          32 :   else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
     260             :     {
     261           8 :       rc = gcry_sexp_build (&s_pkey, NULL,
     262             :                             "(public-key(rsa(n%m)(e%m)))",
     263           8 :                             pkey[0], pkey[1]);
     264             :       /* Put DATA into a simplified S-expression.  */
     265          16 :       if (!rc)
     266           8 :         rc = gcry_sexp_build (&s_data, NULL, "%m", data);
     267             :     }
     268          24 :   else if (algo == PUBKEY_ALGO_ECDH)
     269             :     {
     270             :       gcry_mpi_t k;
     271             : 
     272          24 :       rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
     273          24 :       if (!rc)
     274             :         {
     275             :           char *curve;
     276             : 
     277          24 :           curve = openpgp_oid_to_str (pkey[0]);
     278          24 :           if (!curve)
     279           0 :             rc = gpg_error_from_syserror ();
     280             :           else
     281             :             {
     282          24 :               int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]);
     283             : 
     284             :               /* Now use the ephemeral secret to compute the shared point.  */
     285          24 :               rc = gcry_sexp_build (&s_pkey, NULL,
     286             :                                     with_djb_tweak_flag ?
     287             :                                     "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))"
     288             :                                     : "(public-key(ecdh(curve%s)(q%m)))",
     289          24 :                                     curve, pkey[1]);
     290          24 :               xfree (curve);
     291             :               /* Put K into a simplified S-expression.  */
     292          24 :               if (!rc)
     293          24 :                 rc = gcry_sexp_build (&s_data, NULL, "%m", k);
     294             :             }
     295          24 :           gcry_mpi_release (k);
     296             :         }
     297             :     }
     298             :   else
     299           0 :     rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
     300             : 
     301             :   /* Pass it to libgcrypt. */
     302         255 :   if (!rc)
     303         255 :     rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
     304             : 
     305         255 :   gcry_sexp_release (s_data);
     306         255 :   gcry_sexp_release (s_pkey);
     307             : 
     308         255 :   if (rc)
     309             :     ;
     310         255 :   else if (algo == PUBKEY_ALGO_ECDH)
     311             :     {
     312             :       gcry_mpi_t shared, public, result;
     313             :       byte fp[MAX_FINGERPRINT_LEN];
     314             :       size_t fpn;
     315             : 
     316             :       /* Get the shared point and the ephemeral public key.  */
     317          24 :       shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
     318          24 :       public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
     319          24 :       gcry_sexp_release (s_ciph);
     320          24 :       s_ciph = NULL;
     321          24 :       if (DBG_CRYPTO)
     322             :         {
     323           0 :           log_debug ("ECDH ephemeral key:");
     324           0 :           gcry_mpi_dump (public);
     325           0 :           log_printf ("\n");
     326             :         }
     327             : 
     328          24 :       result = NULL;
     329          24 :       fingerprint_from_pk (pk, fp, &fpn);
     330          24 :       if (fpn != 20)
     331           0 :         rc = gpg_error (GPG_ERR_INV_LENGTH);
     332             :       else
     333          24 :         rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
     334             :                                                 fp, data, pkey, &result);
     335          24 :       gcry_mpi_release (shared);
     336          24 :       if (!rc)
     337             :         {
     338          24 :           resarr[0] = public;
     339          24 :           resarr[1] = result;
     340             :         }
     341             :       else
     342             :         {
     343           0 :           gcry_mpi_release (public);
     344           0 :           gcry_mpi_release (result);
     345             :         }
     346             :     }
     347             :   else /* Elgamal or RSA case.  */
     348             :     { /* Fixme: Add better error handling or make gnupg use
     349             :          S-expressions directly.  */
     350         231 :       resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
     351         231 :       if (!is_RSA (algo))
     352         223 :         resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
     353             :     }
     354             : 
     355         255 :   gcry_sexp_release (s_ciph);
     356         255 :   return rc;
     357             : }
     358             : 
     359             : 
     360             : /* Check whether SKEY is a suitable secret key. */
     361             : int
     362           0 : pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
     363             : {
     364             :   gcry_sexp_t s_skey;
     365             :   int rc;
     366             : 
     367           0 :   if (pkalgo == PUBKEY_ALGO_DSA)
     368             :     {
     369           0 :       rc = gcry_sexp_build (&s_skey, NULL,
     370             :                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
     371           0 :                             skey[0], skey[1], skey[2], skey[3], skey[4]);
     372             :     }
     373           0 :   else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
     374             :     {
     375           0 :       rc = gcry_sexp_build (&s_skey, NULL,
     376             :                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
     377           0 :                             skey[0], skey[1], skey[2], skey[3]);
     378             :     }
     379           0 :   else if (is_RSA (pkalgo))
     380             :     {
     381           0 :       rc = gcry_sexp_build (&s_skey, NULL,
     382             :                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
     383           0 :                             skey[0], skey[1], skey[2], skey[3], skey[4],
     384           0 :                             skey[5]);
     385             :     }
     386           0 :   else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH)
     387           0 :     {
     388           0 :       char *curve = openpgp_oid_to_str (skey[0]);
     389           0 :       if (!curve)
     390           0 :         rc = gpg_error_from_syserror ();
     391             :       else
     392             :         {
     393           0 :           rc = gcry_sexp_build (&s_skey, NULL,
     394             :                                 "(private-key(ecc(curve%s)(q%m)(d%m)))",
     395           0 :                                 curve, skey[1], skey[2]);
     396           0 :           xfree (curve);
     397             :         }
     398             :     }
     399           0 :   else if (pkalgo == PUBKEY_ALGO_EDDSA)
     400             :     {
     401           0 :       char *curve = openpgp_oid_to_str (skey[0]);
     402           0 :       if (!curve)
     403           0 :         rc = gpg_error_from_syserror ();
     404             :       else
     405             :         {
     406           0 :           rc = gcry_sexp_build (&s_skey, NULL,
     407             :                                 "(private-key(ecc(curve %s)"
     408             :                                 "(flags eddsa)(q%m)(d%m)))",
     409           0 :                                 curve, skey[1], skey[2]);
     410           0 :           xfree (curve);
     411             :         }
     412             :     }
     413             :   else
     414           0 :     return GPG_ERR_PUBKEY_ALGO;
     415             : 
     416           0 :   if (!rc)
     417             :     {
     418           0 :       rc = gcry_pk_testkey (s_skey);
     419           0 :       gcry_sexp_release (s_skey);
     420             :     }
     421           0 :   return rc;
     422             : }

Generated by: LCOV version 1.11