LCOV - code coverage report
Current view: top level - agent - cvt-openpgp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 309 644 48.0 %
Date: 2015-11-05 17:10:59 Functions: 11 15 73.3 %

          Line data    Source code
       1             : /* cvt-openpgp.c - Convert an OpenPGP key to our internal format.
       2             :  * Copyright (C) 1998-2002, 2006, 2009, 2010 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2013, 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 <assert.h>
      26             : 
      27             : #include "agent.h"
      28             : #include "i18n.h"
      29             : #include "cvt-openpgp.h"
      30             : #include "host2net.h"
      31             : 
      32             : 
      33             : /* Helper to pass data via the callback to do_unprotect. */
      34             : struct try_do_unprotect_arg_s
      35             : {
      36             :   int  is_v4;
      37             :   int  is_protected;
      38             :   int  pubkey_algo;
      39             :   const char *curve;
      40             :   int  protect_algo;
      41             :   char *iv;
      42             :   int  ivlen;
      43             :   int  s2k_mode;
      44             :   int  s2k_algo;
      45             :   byte *s2k_salt;
      46             :   u32  s2k_count;
      47             :   u16 desired_csum;
      48             :   gcry_mpi_t *skey;
      49             :   size_t skeysize;
      50             :   int skeyidx;
      51             :   gcry_sexp_t *r_key;
      52             : };
      53             : 
      54             : 
      55             : 
      56             : /* Compute the keygrip from the public key and store it at GRIP.  */
      57             : static gpg_error_t
      58          20 : get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey,
      59             :              unsigned char *grip)
      60             : {
      61             :   gpg_error_t err;
      62          20 :   gcry_sexp_t s_pkey = NULL;
      63             : 
      64          20 :   switch (pubkey_algo)
      65             :     {
      66             :     case GCRY_PK_DSA:
      67           3 :       err = gcry_sexp_build (&s_pkey, NULL,
      68             :                              "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
      69           3 :                              pkey[0], pkey[1], pkey[2], pkey[3]);
      70           1 :       break;
      71             : 
      72             :     case GCRY_PK_ELG:
      73           2 :       err = gcry_sexp_build (&s_pkey, NULL,
      74             :                              "(public-key(elg(p%m)(g%m)(y%m)))",
      75           2 :                              pkey[0], pkey[1], pkey[2]);
      76           1 :       break;
      77             : 
      78             :     case GCRY_PK_RSA:
      79           0 :       err = gcry_sexp_build (&s_pkey, NULL,
      80           0 :                              "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
      81           0 :       break;
      82             : 
      83             :     case GCRY_PK_ECC:
      84          18 :       if (!curve)
      85           0 :         err = gpg_error (GPG_ERR_BAD_SECKEY);
      86             :       else
      87             :         {
      88             :           const char *format;
      89             : 
      90          18 :           if (!strcmp (curve, "Ed25519"))
      91           0 :             format = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))";
      92          18 :           else if (!strcmp (curve, "Curve25519"))
      93           0 :             format = "(public-key(ecc(curve %s)(flags djb-tweak)(q%m)))";
      94             :           else
      95          18 :             format = "(public-key(ecc(curve %s)(q%m)))";
      96             : 
      97          18 :           err = gcry_sexp_build (&s_pkey, NULL, format, curve, pkey[0]);
      98             :         }
      99          18 :       break;
     100             : 
     101             :     default:
     102           0 :       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
     103           0 :       break;
     104             :     }
     105             : 
     106          20 :   if (!err && !gcry_pk_get_keygrip (s_pkey, grip))
     107           0 :     err = gpg_error (GPG_ERR_INTERNAL);
     108             : 
     109          20 :   gcry_sexp_release (s_pkey);
     110          20 :   return err;
     111             : }
     112             : 
     113             : 
     114             : /* Convert a secret key given as algorithm id and an array of key
     115             :    parameters into our s-expression based format.  Note that
     116             :    PUBKEY_ALGO has an gcrypt algorithm number. */
     117             : static gpg_error_t
     118           6 : convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
     119             :                     const char *curve)
     120             : {
     121             :   gpg_error_t err;
     122           6 :   gcry_sexp_t s_skey = NULL;
     123             : 
     124           6 :   *r_key = NULL;
     125             : 
     126           6 :   switch (pubkey_algo)
     127             :     {
     128             :     case GCRY_PK_DSA:
     129           0 :       err = gcry_sexp_build (&s_skey, NULL,
     130             :                              "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
     131           0 :                              skey[0], skey[1], skey[2], skey[3], skey[4]);
     132           0 :       break;
     133             : 
     134             :     case GCRY_PK_ELG:
     135             :     case GCRY_PK_ELG_E:
     136           0 :       err = gcry_sexp_build (&s_skey, NULL,
     137             :                              "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
     138           0 :                              skey[0], skey[1], skey[2], skey[3]);
     139           0 :       break;
     140             : 
     141             : 
     142             :     case GCRY_PK_RSA:
     143             :     case GCRY_PK_RSA_E:
     144             :     case GCRY_PK_RSA_S:
     145           0 :       err = gcry_sexp_build (&s_skey, NULL,
     146             :                              "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
     147           0 :                              skey[0], skey[1], skey[2], skey[3], skey[4],
     148           0 :                              skey[5]);
     149           0 :       break;
     150             : 
     151             :     case GCRY_PK_ECC:
     152           6 :       if (!curve)
     153           0 :         err = gpg_error (GPG_ERR_BAD_SECKEY);
     154             :       else
     155             :         {
     156             :           const char *format;
     157             : 
     158           6 :           if (!strcmp (curve, "Ed25519"))
     159             :             /* Do not store the OID as name but the real name and the
     160             :                EdDSA flag.  */
     161           0 :             format = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))";
     162           6 :           else if (!strcmp (curve, "Curve25519"))
     163           0 :             format = "(private-key(ecc(curve %s)(flags djb-tweak)(q%m)(d%m)))";
     164             :           else
     165           6 :             format = "(private-key(ecc(curve %s)(q%m)(d%m)))";
     166             : 
     167           6 :           err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], skey[1]);
     168             :         }
     169           6 :       break;
     170             : 
     171             :     default:
     172           0 :       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
     173           0 :       break;
     174             :     }
     175             : 
     176           6 :   if (!err)
     177           6 :     *r_key = s_skey;
     178           6 :   return err;
     179             : }
     180             : 
     181             : 
     182             : /* Convert a secret key given as algorithm id, an array of key
     183             :    parameters, and an S-expression of the original OpenPGP transfer
     184             :    key into our s-expression based format.  This is a variant of
     185             :    convert_secret_key which is used for the openpgp-native protection
     186             :    mode.  Note that PUBKEY_ALGO has an gcrypt algorithm number. */
     187             : static gpg_error_t
     188          12 : convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
     189             :                       const char *curve, gcry_sexp_t transfer_key)
     190             : {
     191             :   gpg_error_t err;
     192          12 :   gcry_sexp_t s_skey = NULL;
     193             : 
     194          12 :   *r_key = NULL;
     195             : 
     196          12 :   switch (pubkey_algo)
     197             :     {
     198             :     case GCRY_PK_DSA:
     199           0 :       err = gcry_sexp_build
     200             :         (&s_skey, NULL,
     201             :          "(protected-private-key(dsa(p%m)(q%m)(g%m)(y%m)"
     202             :          "(protected openpgp-native%S)))",
     203           0 :          skey[0], skey[1], skey[2], skey[3], transfer_key);
     204           0 :       break;
     205             : 
     206             :     case GCRY_PK_ELG:
     207           0 :       err = gcry_sexp_build
     208             :         (&s_skey, NULL,
     209             :          "(protected-private-key(elg(p%m)(g%m)(y%m)"
     210             :          "(protected openpgp-native%S)))",
     211           0 :          skey[0], skey[1], skey[2], transfer_key);
     212           0 :       break;
     213             : 
     214             : 
     215             :     case GCRY_PK_RSA:
     216           0 :       err = gcry_sexp_build
     217             :         (&s_skey, NULL,
     218             :          "(protected-private-key(rsa(n%m)(e%m)"
     219             :          "(protected openpgp-native%S)))",
     220           0 :          skey[0], skey[1], transfer_key );
     221           0 :       break;
     222             : 
     223             :     case GCRY_PK_ECC:
     224          12 :       if (!curve)
     225           0 :         err = gpg_error (GPG_ERR_BAD_SECKEY);
     226             :       else
     227             :         {
     228             :           const char *format;
     229             : 
     230          12 :           if (!strcmp (curve, "Ed25519"))
     231             :             /* Do not store the OID as name but the real name and the
     232             :                EdDSA flag.  */
     233           0 :             format = "(protected-private-key(ecc(curve %s)(flags eddsa)(q%m)"
     234             :               "(protected openpgp-native%S)))";
     235          12 :           else if (!strcmp (curve, "Curve25519"))
     236           0 :             format = "(protected-private-key(ecc(curve %s)(flags djb-tweak)(q%m)"
     237             :               "(protected openpgp-native%S)))";
     238             :           else
     239          12 :             format = "(protected-private-key(ecc(curve %s)(q%m)"
     240             :               "(protected openpgp-native%S)))";
     241             : 
     242          12 :           err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], transfer_key);
     243             :         }
     244          12 :       break;
     245             : 
     246             :     default:
     247           0 :       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
     248           0 :       break;
     249             :     }
     250             : 
     251          12 :   if (!err)
     252          12 :     *r_key = s_skey;
     253          12 :   return err;
     254             : }
     255             : 
     256             : 
     257             : /* Hash the passphrase and set the key. */
     258             : static gpg_error_t
     259           6 : hash_passphrase_and_set_key (const char *passphrase,
     260             :                              gcry_cipher_hd_t hd, int protect_algo,
     261             :                              int s2k_mode, int s2k_algo,
     262             :                              byte *s2k_salt, u32 s2k_count)
     263             : {
     264             :   gpg_error_t err;
     265             :   unsigned char *key;
     266             :   size_t keylen;
     267             : 
     268           6 :   keylen = gcry_cipher_get_algo_keylen (protect_algo);
     269           6 :   if (!keylen)
     270           0 :     return gpg_error (GPG_ERR_INTERNAL);
     271             : 
     272           6 :   key = xtrymalloc_secure (keylen);
     273           6 :   if (!key)
     274           0 :     return gpg_error_from_syserror ();
     275             : 
     276           6 :   err = s2k_hash_passphrase (passphrase,
     277             :                              s2k_algo, s2k_mode, s2k_salt, s2k_count,
     278             :                              key, keylen);
     279           6 :   if (!err)
     280           6 :     err = gcry_cipher_setkey (hd, key, keylen);
     281             : 
     282           6 :   xfree (key);
     283           6 :   return err;
     284             : }
     285             : 
     286             : 
     287             : static u16
     288           0 : checksum (const unsigned char *p, unsigned int n)
     289             : {
     290             :   u16 a;
     291             : 
     292           0 :   for (a=0; n; n-- )
     293           0 :     a += *p++;
     294           0 :   return a;
     295             : }
     296             : 
     297             : 
     298             : /* Return the number of expected key parameters.  */
     299             : static void
     300          38 : get_npkey_nskey (int pubkey_algo, size_t *npkey, size_t *nskey)
     301             : {
     302          38 :   switch (pubkey_algo)
     303             :     {
     304           0 :     case GCRY_PK_RSA:   *npkey = 2; *nskey = 6; break;
     305           1 :     case GCRY_PK_ELG:   *npkey = 3; *nskey = 4; break;
     306           0 :     case GCRY_PK_ELG_E: *npkey = 3; *nskey = 4; break;
     307           1 :     case GCRY_PK_DSA:   *npkey = 4; *nskey = 5; break;
     308          36 :     case GCRY_PK_ECC:   *npkey = 1; *nskey = 2; break;
     309           0 :     default:            *npkey = 0; *nskey = 0; break;
     310             :     }
     311          38 : }
     312             : 
     313             : 
     314             : /* Helper for do_unprotect.  PUBKEY_ALOGO is the gcrypt algo number.
     315             :    On success R_NPKEY and R_NSKEY receive the number or parameters for
     316             :    the algorithm PUBKEY_ALGO and R_SKEYLEN the used length of
     317             :    SKEY.  */
     318             : static int
     319          18 : prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
     320             :                    int s2k_mode,
     321             :                    unsigned int *r_npkey, unsigned int *r_nskey,
     322             :                    unsigned int *r_skeylen)
     323             : {
     324             :   size_t npkey, nskey, skeylen;
     325             :   int i;
     326             : 
     327             :   /* Count the actual number of MPIs is in the array and set the
     328             :      remainder to NULL for easier processing later on.  */
     329          18 :   for (skeylen = 0; skey[skeylen]; skeylen++)
     330             :     ;
     331         162 :   for (i=skeylen; i < skeysize; i++)
     332         144 :     skey[i] = NULL;
     333             : 
     334             :   /* Check some args.  */
     335          18 :   if (s2k_mode == 1001)
     336             :     {
     337             :       /* Stub key.  */
     338           0 :       log_info (_("secret key parts are not available\n"));
     339           0 :       return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
     340             :     }
     341             : 
     342          18 :   if (gcry_pk_test_algo (pubkey_algo))
     343             :     {
     344           0 :       log_info (_("public key algorithm %d (%s) is not supported\n"),
     345             :                 pubkey_algo, gcry_pk_algo_name (pubkey_algo));
     346           0 :       return gpg_error (GPG_ERR_PUBKEY_ALGO);
     347             :     }
     348             : 
     349             :   /* Get properties of the public key algorithm and do some
     350             :      consistency checks.  Note that we need at least NPKEY+1 elements
     351             :      in the SKEY array. */
     352          18 :   get_npkey_nskey (pubkey_algo, &npkey, &nskey);
     353          18 :   if (!npkey || !nskey || npkey >= nskey)
     354           0 :     return gpg_error (GPG_ERR_INTERNAL);
     355          18 :   if (skeylen <= npkey)
     356           0 :     return gpg_error (GPG_ERR_MISSING_VALUE);
     357          18 :   if (nskey+1 >= skeysize)
     358           0 :     return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
     359             : 
     360             :   /* Check that the public key parameters are all available and not
     361             :      encrypted.  */
     362          36 :   for (i=0; i < npkey; i++)
     363             :     {
     364          18 :       if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
     365           0 :         return gpg_error (GPG_ERR_BAD_SECKEY);
     366             :     }
     367             : 
     368          18 :   if (r_npkey)
     369           6 :     *r_npkey = npkey;
     370          18 :   if (r_nskey)
     371           6 :     *r_nskey = nskey;
     372          18 :   if (r_skeylen)
     373           6 :     *r_skeylen = skeylen;
     374          18 :   return 0;
     375             : }
     376             : 
     377             : 
     378             : /* Note that this function modifies SKEY.  SKEYSIZE is the allocated
     379             :    size of the array including the NULL item; this is used for a
     380             :    bounds check.  On success a converted key is stored at R_KEY.  */
     381             : static int
     382           6 : do_unprotect (const char *passphrase,
     383             :               int pkt_version, int pubkey_algo, int is_protected,
     384             :               const char *curve, gcry_mpi_t *skey, size_t skeysize,
     385             :               int protect_algo, void *protect_iv, size_t protect_ivlen,
     386             :               int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count,
     387             :               u16 desired_csum, gcry_sexp_t *r_key)
     388             : {
     389             :   gpg_error_t err;
     390             :   unsigned int npkey, nskey, skeylen;
     391           6 :   gcry_cipher_hd_t cipher_hd = NULL;
     392             :   u16 actual_csum;
     393             :   size_t nbytes;
     394             :   int i;
     395             :   gcry_mpi_t tmpmpi;
     396             : 
     397           6 :   *r_key = NULL;
     398             : 
     399           6 :   err = prepare_unprotect (pubkey_algo, skey, skeysize, s2k_mode,
     400             :                            &npkey, &nskey, &skeylen);
     401           6 :   if (err)
     402           0 :     return err;
     403             : 
     404             :   /* Check whether SKEY is at all protected.  If it is not protected
     405             :      merely verify the checksum.  */
     406           6 :   if (!is_protected)
     407             :     {
     408           0 :       actual_csum = 0;
     409           0 :       for (i=npkey; i < nskey; i++)
     410             :         {
     411           0 :           if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
     412           0 :             return gpg_error (GPG_ERR_BAD_SECKEY);
     413             : 
     414           0 :           if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
     415             :             {
     416             :               unsigned int nbits;
     417             :               const unsigned char *buffer;
     418           0 :               buffer = gcry_mpi_get_opaque (skey[i], &nbits);
     419           0 :               nbytes = (nbits+7)/8;
     420           0 :               actual_csum += checksum (buffer, nbytes);
     421             :             }
     422             :           else
     423             :             {
     424             :               unsigned char *buffer;
     425             : 
     426           0 :               err = gcry_mpi_aprint (GCRYMPI_FMT_PGP, &buffer, &nbytes,
     427           0 :                                      skey[i]);
     428           0 :               if (!err)
     429           0 :                 actual_csum += checksum (buffer, nbytes);
     430           0 :               xfree (buffer);
     431             :             }
     432           0 :           if (err)
     433           0 :             return err;
     434             :         }
     435             : 
     436           0 :       if (actual_csum != desired_csum)
     437           0 :         return gpg_error (GPG_ERR_CHECKSUM);
     438             : 
     439           0 :       goto do_convert;
     440             :     }
     441             : 
     442             : 
     443           6 :   if (gcry_cipher_test_algo (protect_algo))
     444             :     {
     445             :       /* The algorithm numbers are Libgcrypt numbers but fortunately
     446             :          the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
     447             :          numbers.  */
     448           0 :       log_info (_("protection algorithm %d (%s) is not supported\n"),
     449             :                 protect_algo, gnupg_cipher_algo_name (protect_algo));
     450           0 :       return gpg_error (GPG_ERR_CIPHER_ALGO);
     451             :     }
     452             : 
     453           6 :   if (gcry_md_test_algo (s2k_algo))
     454             :     {
     455           0 :       log_info (_("protection hash algorithm %d (%s) is not supported\n"),
     456             :                 s2k_algo, gcry_md_algo_name (s2k_algo));
     457           0 :       return gpg_error (GPG_ERR_DIGEST_ALGO);
     458             :     }
     459             : 
     460           6 :   err = gcry_cipher_open (&cipher_hd, protect_algo,
     461             :                           GCRY_CIPHER_MODE_CFB,
     462             :                           (GCRY_CIPHER_SECURE
     463             :                            | (protect_algo >= 100 ?
     464             :                               0 : GCRY_CIPHER_ENABLE_SYNC)));
     465           6 :   if (err)
     466             :     {
     467           0 :       log_error ("failed to open cipher_algo %d: %s\n",
     468             :                  protect_algo, gpg_strerror (err));
     469           0 :       return err;
     470             :     }
     471             : 
     472           6 :   err = hash_passphrase_and_set_key (passphrase, cipher_hd, protect_algo,
     473             :                                      s2k_mode, s2k_algo, s2k_salt, s2k_count);
     474           6 :   if (err)
     475             :     {
     476           0 :       gcry_cipher_close (cipher_hd);
     477           0 :       return err;
     478             :     }
     479             : 
     480           6 :   gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen);
     481             : 
     482           6 :   actual_csum = 0;
     483           6 :   if (pkt_version >= 4)
     484             :     {
     485             :       int ndata;
     486             :       unsigned int ndatabits;
     487             :       const unsigned char *p;
     488             :       unsigned char *data;
     489           6 :       u16 csum_pgp7 = 0;
     490             : 
     491           6 :       if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE ))
     492             :         {
     493           0 :           gcry_cipher_close (cipher_hd);
     494           0 :           return gpg_error (GPG_ERR_BAD_SECKEY);
     495             :         }
     496           6 :       p = gcry_mpi_get_opaque (skey[npkey], &ndatabits);
     497           6 :       ndata = (ndatabits+7)/8;
     498             : 
     499           6 :       if (ndata > 1)
     500           6 :         csum_pgp7 = buf16_to_u16 (p+ndata-2);
     501           6 :       data = xtrymalloc_secure (ndata);
     502           6 :       if (!data)
     503             :         {
     504           0 :           err = gpg_error_from_syserror ();
     505           0 :           gcry_cipher_close (cipher_hd);
     506           0 :           return err;
     507             :         }
     508           6 :       gcry_cipher_decrypt (cipher_hd, data, ndata, p, ndata);
     509             : 
     510           6 :       p = data;
     511           6 :       if (is_protected == 2)
     512             :         {
     513             :           /* This is the new SHA1 checksum method to detect tampering
     514             :              with the key as used by the Klima/Rosa attack.  */
     515           6 :           desired_csum = 0;
     516           6 :           actual_csum = 1;  /* Default to bad checksum.  */
     517             : 
     518           6 :           if (ndata < 20)
     519           0 :             log_error ("not enough bytes for SHA-1 checksum\n");
     520             :           else
     521             :             {
     522             :               gcry_md_hd_t h;
     523             : 
     524           6 :               if (gcry_md_open (&h, GCRY_MD_SHA1, 1))
     525           0 :                 BUG(); /* Algo not available. */
     526           6 :               gcry_md_write (h, data, ndata - 20);
     527           6 :               gcry_md_final (h);
     528           6 :               if (!memcmp (gcry_md_read (h, GCRY_MD_SHA1), data+ndata-20, 20))
     529           6 :                 actual_csum = 0; /* Digest does match.  */
     530           6 :               gcry_md_close (h);
     531             :             }
     532             :         }
     533             :       else
     534             :         {
     535             :           /* Old 16 bit checksum method.  */
     536           0 :           if (ndata < 2)
     537             :             {
     538           0 :               log_error ("not enough bytes for checksum\n");
     539           0 :               desired_csum = 0;
     540           0 :               actual_csum = 1;  /* Mark checksum bad.  */
     541             :             }
     542             :           else
     543             :             {
     544           0 :               desired_csum = buf16_to_u16 (data+ndata-2);
     545           0 :               actual_csum = checksum (data, ndata-2);
     546           0 :               if (desired_csum != actual_csum)
     547             :                 {
     548             :                   /* This is a PGP 7.0.0 workaround */
     549           0 :                   desired_csum = csum_pgp7; /* Take the encrypted one.  */
     550             :                 }
     551             :             }
     552             :         }
     553             : 
     554             :       /* Better check it here.  Otherwise the gcry_mpi_scan would fail
     555             :          because the length may have an arbitrary value.  */
     556           6 :       if (desired_csum == actual_csum)
     557             :         {
     558          12 :           for (i=npkey; i < nskey; i++ )
     559             :             {
     560           6 :               if (gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, p, ndata, &nbytes))
     561             :                 {
     562             :                   /* Checksum was okay, but not correctly decrypted.  */
     563           0 :                   desired_csum = 0;
     564           0 :                   actual_csum = 1;   /* Mark checksum bad.  */
     565           0 :                   break;
     566             :                 }
     567           6 :               gcry_mpi_release (skey[i]);
     568           6 :               skey[i] = tmpmpi;
     569           6 :               ndata -= nbytes;
     570           6 :               p += nbytes;
     571             :             }
     572           6 :           skey[i] = NULL;
     573           6 :           skeylen = i;
     574           6 :           assert (skeylen <= skeysize);
     575             : 
     576             :           /* Note: at this point NDATA should be 2 for a simple
     577             :              checksum or 20 for the sha1 digest.  */
     578             :         }
     579           6 :       xfree(data);
     580             :     }
     581             :   else /* Packet version <= 3.  */
     582             :     {
     583             :       unsigned char *buffer;
     584             : 
     585           0 :       for (i = npkey; i < nskey; i++)
     586             :         {
     587             :           const unsigned char *p;
     588             :           size_t ndata;
     589             :           unsigned int ndatabits;
     590             : 
     591           0 :           if (!skey[i] || !gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
     592             :             {
     593           0 :               gcry_cipher_close (cipher_hd);
     594           0 :               return gpg_error (GPG_ERR_BAD_SECKEY);
     595             :             }
     596           0 :           p = gcry_mpi_get_opaque (skey[i], &ndatabits);
     597           0 :           ndata = (ndatabits+7)/8;
     598             : 
     599           0 :           if (!(ndata >= 2) || !(ndata == (buf16_to_ushort (p) + 7)/8 + 2))
     600             :             {
     601           0 :               gcry_cipher_close (cipher_hd);
     602           0 :               return gpg_error (GPG_ERR_BAD_SECKEY);
     603             :             }
     604             : 
     605           0 :           buffer = xtrymalloc_secure (ndata);
     606           0 :           if (!buffer)
     607             :             {
     608           0 :               err = gpg_error_from_syserror ();
     609           0 :               gcry_cipher_close (cipher_hd);
     610           0 :               return err;
     611             :             }
     612             : 
     613           0 :           gcry_cipher_sync (cipher_hd);
     614           0 :           buffer[0] = p[0];
     615           0 :           buffer[1] = p[1];
     616           0 :           gcry_cipher_decrypt (cipher_hd, buffer+2, ndata-2, p+2, ndata-2);
     617           0 :           actual_csum += checksum (buffer, ndata);
     618           0 :           err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, buffer, ndata, &ndata);
     619           0 :           xfree (buffer);
     620           0 :           if (err)
     621             :             {
     622             :               /* Checksum was okay, but not correctly decrypted.  */
     623           0 :               desired_csum = 0;
     624           0 :               actual_csum = 1;   /* Mark checksum bad.  */
     625           0 :               break;
     626             :             }
     627           0 :           gcry_mpi_release (skey[i]);
     628           0 :           skey[i] = tmpmpi;
     629             :         }
     630             :     }
     631           6 :   gcry_cipher_close (cipher_hd);
     632             : 
     633             :   /* Now let's see whether we have used the correct passphrase. */
     634           6 :   if (actual_csum != desired_csum)
     635           0 :     return gpg_error (GPG_ERR_BAD_PASSPHRASE);
     636             : 
     637             :  do_convert:
     638           6 :   if (nskey != skeylen)
     639           0 :     err = gpg_error (GPG_ERR_BAD_SECKEY);
     640             :   else
     641           6 :     err = convert_secret_key (r_key, pubkey_algo, skey, curve);
     642           6 :   if (err)
     643           0 :     return err;
     644             : 
     645             :   /* The checksum may fail, thus we also check the key itself.  */
     646           6 :   err = gcry_pk_testkey (*r_key);
     647           6 :   if (err)
     648             :     {
     649           0 :       gcry_sexp_release (*r_key);
     650           0 :       *r_key = NULL;
     651           0 :       return gpg_error (GPG_ERR_BAD_PASSPHRASE);
     652             :     }
     653             : 
     654           6 :   return 0;
     655             : }
     656             : 
     657             : 
     658             : /* Callback function to try the unprotection from the passphrase query
     659             :    code.  */
     660             : static gpg_error_t
     661           6 : try_do_unprotect_cb (struct pin_entry_info_s *pi)
     662             : {
     663             :   gpg_error_t err;
     664           6 :   struct try_do_unprotect_arg_s *arg = pi->check_cb_arg;
     665             : 
     666          30 :   err = do_unprotect (pi->pin,
     667           6 :                       arg->is_v4? 4:3,
     668             :                       arg->pubkey_algo, arg->is_protected,
     669             :                       arg->curve,
     670             :                       arg->skey, arg->skeysize,
     671          12 :                       arg->protect_algo, arg->iv, arg->ivlen,
     672             :                       arg->s2k_mode, arg->s2k_algo,
     673             :                       arg->s2k_salt, arg->s2k_count,
     674           6 :                       arg->desired_csum, arg->r_key);
     675             :   /* SKEY may be modified now, thus we need to re-compute SKEYIDX.  */
     676          24 :   for (arg->skeyidx = 0; (arg->skeyidx < arg->skeysize
     677          30 :                           && arg->skey[arg->skeyidx]); arg->skeyidx++)
     678             :     ;
     679           6 :   return err;
     680             : }
     681             : 
     682             : 
     683             : /* See convert_from_openpgp for the core of the description.  This
     684             :    function adds an optional PASSPHRASE argument and uses this to
     685             :    silently decrypt the key; CACHE_NONCE and R_PASSPHRASE must both be
     686             :    NULL in this mode.  */
     687             : static gpg_error_t
     688          20 : convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
     689             :                            unsigned char *grip, const char *prompt,
     690             :                            const char *cache_nonce, const char *passphrase,
     691             :                            unsigned char **r_key, char **r_passphrase)
     692             : {
     693             :   gpg_error_t err;
     694             :   int unattended;
     695             :   int from_native;
     696             :   gcry_sexp_t top_list;
     697          20 :   gcry_sexp_t list = NULL;
     698             :   const char *value;
     699             :   size_t valuelen;
     700             :   char *string;
     701             :   int  idx;
     702             :   int  is_v4, is_protected;
     703             :   int  pubkey_algo;
     704          20 :   int  protect_algo = 0;
     705             :   char iv[16];
     706          20 :   int  ivlen = 0;
     707          20 :   int  s2k_mode = 0;
     708          20 :   int  s2k_algo = 0;
     709             :   byte s2k_salt[8];
     710          20 :   u32  s2k_count = 0;
     711             :   size_t npkey, nskey;
     712             :   gcry_mpi_t skey[10];  /* We support up to 9 parameters.  */
     713          20 :   char *curve = NULL;
     714             :   u16 desired_csum;
     715          20 :   int skeyidx = 0;
     716          20 :   gcry_sexp_t s_skey = NULL;
     717             : 
     718          20 :   *r_key = NULL;
     719          20 :   if (r_passphrase)
     720           0 :     *r_passphrase = NULL;
     721          20 :   unattended = !r_passphrase;
     722          20 :   from_native = (!cache_nonce && passphrase && !r_passphrase);
     723             : 
     724          20 :   top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
     725          20 :   if (!top_list)
     726           0 :     goto bad_seckey;
     727             : 
     728          20 :   list = gcry_sexp_find_token (top_list, "version", 0);
     729          20 :   if (!list)
     730           0 :     goto bad_seckey;
     731          20 :   value = gcry_sexp_nth_data (list, 1, &valuelen);
     732          20 :   if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4'))
     733             :     goto bad_seckey;
     734          20 :   is_v4 = (value[0] == '4');
     735             : 
     736          20 :   gcry_sexp_release (list);
     737          20 :   list = gcry_sexp_find_token (top_list, "protection", 0);
     738          20 :   if (!list)
     739           0 :     goto bad_seckey;
     740          20 :   value = gcry_sexp_nth_data (list, 1, &valuelen);
     741          20 :   if (!value)
     742           0 :     goto bad_seckey;
     743          20 :   if (valuelen == 4 && !memcmp (value, "sha1", 4))
     744          20 :     is_protected = 2;
     745           0 :   else if (valuelen == 3 && !memcmp (value, "sum", 3))
     746           0 :     is_protected = 1;
     747           0 :   else if (valuelen == 4 && !memcmp (value, "none", 4))
     748           0 :     is_protected = 0;
     749             :   else
     750             :     goto bad_seckey;
     751             : 
     752          20 :   if (is_protected)
     753             :     {
     754          20 :       string = gcry_sexp_nth_string (list, 2);
     755          20 :       if (!string)
     756           0 :         goto bad_seckey;
     757          20 :       protect_algo = gcry_cipher_map_name (string);
     758          20 :       xfree (string);
     759             : 
     760          20 :       value = gcry_sexp_nth_data (list, 3, &valuelen);
     761          20 :       if (!value || !valuelen || valuelen > sizeof iv)
     762             :         goto bad_seckey;
     763          20 :       memcpy (iv, value, valuelen);
     764          20 :       ivlen = valuelen;
     765             : 
     766          20 :       string = gcry_sexp_nth_string (list, 4);
     767          20 :       if (!string)
     768           0 :         goto bad_seckey;
     769          20 :       s2k_mode = strtol (string, NULL, 10);
     770          20 :       xfree (string);
     771             : 
     772          20 :       string = gcry_sexp_nth_string (list, 5);
     773          20 :       if (!string)
     774           0 :         goto bad_seckey;
     775          20 :       s2k_algo = gcry_md_map_name (string);
     776          20 :       xfree (string);
     777             : 
     778          20 :       value = gcry_sexp_nth_data (list, 6, &valuelen);
     779          20 :       if (!value || !valuelen || valuelen > sizeof s2k_salt)
     780             :         goto bad_seckey;
     781          20 :       memcpy (s2k_salt, value, valuelen);
     782             : 
     783          20 :       string = gcry_sexp_nth_string (list, 7);
     784          20 :       if (!string)
     785           0 :         goto bad_seckey;
     786          20 :       s2k_count = strtoul (string, NULL, 10);
     787          20 :       xfree (string);
     788             :     }
     789             : 
     790          20 :   gcry_sexp_release (list);
     791          20 :   list = gcry_sexp_find_token (top_list, "algo", 0);
     792          20 :   if (!list)
     793           0 :     goto bad_seckey;
     794          20 :   string = gcry_sexp_nth_string (list, 1);
     795          20 :   if (!string)
     796           0 :     goto bad_seckey;
     797          20 :   pubkey_algo = gcry_pk_map_name (string);
     798          20 :   xfree (string);
     799             : 
     800          20 :   get_npkey_nskey (pubkey_algo, &npkey, &nskey);
     801          20 :   if (!npkey || !nskey || npkey >= nskey)
     802             :     goto bad_seckey;
     803             : 
     804          20 :   if (npkey == 1) /* This is ECC */
     805             :     {
     806          18 :       gcry_sexp_release (list);
     807          18 :       list = gcry_sexp_find_token (top_list, "curve", 0);
     808          18 :       if (!list)
     809           0 :         goto bad_seckey;
     810          18 :       curve = gcry_sexp_nth_string (list, 1);
     811          18 :       if (!curve)
     812           0 :         goto bad_seckey;
     813             :     }
     814             : 
     815          20 :   gcry_sexp_release (list);
     816          20 :   list = gcry_sexp_find_token (top_list, "skey", 0);
     817          20 :   if (!list)
     818           0 :     goto bad_seckey;
     819          20 :   for (idx=0;;)
     820             :     {
     821             :       int is_enc;
     822             : 
     823          65 :       value = gcry_sexp_nth_data (list, ++idx, &valuelen);
     824          65 :       if (!value && skeyidx >= npkey)
     825          20 :         break;  /* Ready.  */
     826             : 
     827             :       /* Check for too many parameters.  Note that depending on the
     828             :          protection mode and version number we may see less than NSKEY
     829             :          (but at least NPKEY+1) parameters.  */
     830          45 :       if (idx >= 2*nskey)
     831           0 :         goto bad_seckey;
     832          45 :       if (skeyidx >= DIM (skey)-1)
     833           0 :         goto bad_seckey;
     834             : 
     835          45 :       if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e'))
     836             :         goto bad_seckey;
     837          45 :       is_enc = (value[0] == 'e');
     838          45 :       value = gcry_sexp_nth_data (list, ++idx, &valuelen);
     839          45 :       if (!value || !valuelen)
     840             :         goto bad_seckey;
     841          45 :       if (is_enc)
     842             :         {
     843             :           /* Encrypted parameters need to be stored as opaque.  */
     844          20 :           skey[skeyidx] = gcry_mpi_set_opaque_copy (NULL, value, valuelen*8);
     845          20 :           if (!skey[skeyidx])
     846           0 :             goto outofmem;
     847          20 :           gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1);
     848             :         }
     849             :       else
     850             :         {
     851          25 :           if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD,
     852             :                              value, valuelen, NULL))
     853           0 :             goto bad_seckey;
     854             :         }
     855          45 :       skeyidx++;
     856          45 :     }
     857          20 :   skey[skeyidx++] = NULL;
     858             : 
     859          20 :   gcry_sexp_release (list);
     860          20 :   list = gcry_sexp_find_token (top_list, "csum", 0);
     861          20 :   if (list)
     862             :     {
     863          20 :       string = gcry_sexp_nth_string (list, 1);
     864          20 :       if (!string)
     865           0 :         goto bad_seckey;
     866          20 :       desired_csum = strtoul (string, NULL, 10);
     867          20 :       xfree (string);
     868             :     }
     869             :   else
     870           0 :     desired_csum = 0;
     871             : 
     872             : 
     873          20 :   gcry_sexp_release (list); list = NULL;
     874          20 :   gcry_sexp_release (top_list); top_list = NULL;
     875             : 
     876             : #if 0
     877             :   log_debug ("XXX is_v4=%d\n", is_v4);
     878             :   log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
     879             :   log_debug ("XXX is_protected=%d\n", is_protected);
     880             :   log_debug ("XXX protect_algo=%d\n", protect_algo);
     881             :   log_printhex ("XXX iv", iv, ivlen);
     882             :   log_debug ("XXX ivlen=%d\n", ivlen);
     883             :   log_debug ("XXX s2k_mode=%d\n", s2k_mode);
     884             :   log_debug ("XXX s2k_algo=%d\n", s2k_algo);
     885             :   log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt);
     886             :   log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count);
     887             :   log_debug ("XXX curve='%s'\n", curve);
     888             :   for (idx=0; skey[idx]; idx++)
     889             :     gcry_log_debugmpi (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_USER1)
     890             :                        ? "skey(e)" : "skey(_)", skey[idx]);
     891             : #endif /*0*/
     892             : 
     893          20 :   err = get_keygrip (pubkey_algo, curve, skey, grip);
     894          20 :   if (err)
     895           0 :     goto leave;
     896             : 
     897          20 :   if (!from_native && !agent_key_available (grip))
     898             :     {
     899           2 :       err = gpg_error (GPG_ERR_EEXIST);
     900           2 :       goto leave;
     901             :     }
     902             : 
     903          18 :   if (unattended && !from_native)
     904             :     {
     905          12 :       err = prepare_unprotect (pubkey_algo, skey, DIM(skey), s2k_mode,
     906             :                                NULL, NULL, NULL);
     907          12 :       if (err)
     908           0 :         goto leave;
     909             : 
     910          12 :       err = convert_transfer_key (&s_skey, pubkey_algo, skey, curve, s_pgp);
     911          24 :       if (err)
     912           0 :         goto leave;
     913             :     }
     914             :   else
     915             :     {
     916             :       struct pin_entry_info_s *pi;
     917             :       struct try_do_unprotect_arg_s pi_arg;
     918             : 
     919           6 :       pi = xtrycalloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
     920           6 :       if (!pi)
     921           0 :         return gpg_error_from_syserror ();
     922           6 :       pi->max_length = MAX_PASSPHRASE_LEN + 1;
     923           6 :       pi->min_digits = 0;  /* We want a real passphrase.  */
     924           6 :       pi->max_digits = 16;
     925           6 :       pi->max_tries = 3;
     926           6 :       pi->check_cb = try_do_unprotect_cb;
     927           6 :       pi->check_cb_arg = &pi_arg;
     928           6 :       pi_arg.is_v4 = is_v4;
     929           6 :       pi_arg.is_protected = is_protected;
     930           6 :       pi_arg.pubkey_algo = pubkey_algo;
     931           6 :       pi_arg.curve = curve;
     932           6 :       pi_arg.protect_algo = protect_algo;
     933           6 :       pi_arg.iv = iv;
     934           6 :       pi_arg.ivlen = ivlen;
     935           6 :       pi_arg.s2k_mode = s2k_mode;
     936           6 :       pi_arg.s2k_algo = s2k_algo;
     937           6 :       pi_arg.s2k_salt = s2k_salt;
     938           6 :       pi_arg.s2k_count = s2k_count;
     939           6 :       pi_arg.desired_csum = desired_csum;
     940           6 :       pi_arg.skey = skey;
     941           6 :       pi_arg.skeysize = DIM (skey);
     942           6 :       pi_arg.skeyidx = skeyidx;
     943           6 :       pi_arg.r_key = &s_skey;
     944             : 
     945           6 :       err = gpg_error (GPG_ERR_BAD_PASSPHRASE);
     946           6 :       if (!is_protected)
     947             :         {
     948           0 :           err = try_do_unprotect_cb (pi);
     949             :         }
     950           6 :       else if (cache_nonce)
     951             :         {
     952             :           char *cache_value;
     953             : 
     954           0 :           cache_value = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
     955           0 :           if (cache_value)
     956             :             {
     957           0 :               if (strlen (cache_value) < pi->max_length)
     958           0 :                 strcpy (pi->pin, cache_value);
     959           0 :               xfree (cache_value);
     960             :             }
     961           0 :           if (*pi->pin)
     962           0 :             err = try_do_unprotect_cb (pi);
     963             :         }
     964           6 :       else if (from_native)
     965             :         {
     966           6 :           if (strlen (passphrase) < pi->max_length)
     967           6 :             strcpy (pi->pin, passphrase);
     968           6 :           err = try_do_unprotect_cb (pi);
     969             :         }
     970           6 :       if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE && !from_native)
     971           0 :         err = agent_askpin (ctrl, prompt, NULL, NULL, pi, NULL, 0);
     972           6 :       skeyidx = pi_arg.skeyidx;
     973           6 :       if (!err && r_passphrase && is_protected)
     974             :         {
     975           0 :           *r_passphrase = xtrystrdup (pi->pin);
     976           0 :           if (!*r_passphrase)
     977           0 :             err = gpg_error_from_syserror ();
     978             :         }
     979           6 :       xfree (pi);
     980           6 :       if (err)
     981           0 :         goto leave;
     982             :     }
     983             : 
     984             :   /* Save some memory and get rid of the SKEY array now.  */
     985          66 :   for (idx=0; idx < skeyidx; idx++)
     986          48 :     gcry_mpi_release (skey[idx]);
     987          18 :   skeyidx = 0;
     988             : 
     989             :   /* Note that the padding is not required - we use it only because
     990             :      that function allows us to create the result in secure memory.  */
     991          18 :   err = make_canon_sexp_pad (s_skey, 1, r_key, NULL);
     992             : 
     993             :  leave:
     994          20 :   xfree (curve);
     995          20 :   gcry_sexp_release (s_skey);
     996          20 :   gcry_sexp_release (list);
     997          20 :   gcry_sexp_release (top_list);
     998          31 :   for (idx=0; idx < skeyidx; idx++)
     999          11 :     gcry_mpi_release (skey[idx]);
    1000          20 :   if (err && r_passphrase)
    1001             :     {
    1002           0 :       xfree (*r_passphrase);
    1003           0 :       *r_passphrase = NULL;
    1004             :     }
    1005          20 :   return err;
    1006             : 
    1007             :  bad_seckey:
    1008           0 :   err = gpg_error (GPG_ERR_BAD_SECKEY);
    1009           0 :   goto leave;
    1010             : 
    1011             :  outofmem:
    1012           0 :   err = gpg_error (GPG_ERR_ENOMEM);
    1013           0 :   goto leave;
    1014             : 
    1015             : }
    1016             : 
    1017             : 
    1018             : /* Convert an OpenPGP transfer key into our internal format.  Before
    1019             :    asking for a passphrase we check whether the key already exists in
    1020             :    our key storage.  S_PGP is the OpenPGP key in transfer format.  If
    1021             :    CACHE_NONCE is given the passphrase will be looked up in the cache.
    1022             :    On success R_KEY will receive a canonical encoded S-expression with
    1023             :    the unprotected key in our internal format; the caller needs to
    1024             :    release that memory.  The passphrase used to decrypt the OpenPGP
    1025             :    key will be returned at R_PASSPHRASE; the caller must release this
    1026             :    passphrase.  If R_PASSPHRASE is NULL the unattended conversion mode
    1027             :    will be used which uses the openpgp-native protection format for
    1028             :    the key.  The keygrip will be stored at the 20 byte buffer pointed
    1029             :    to by GRIP.  On error NULL is stored at all return arguments.  */
    1030             : gpg_error_t
    1031          14 : convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
    1032             :                       unsigned char *grip, const char *prompt,
    1033             :                       const char *cache_nonce,
    1034             :                       unsigned char **r_key, char **r_passphrase)
    1035             : {
    1036          14 :   return convert_from_openpgp_main (ctrl, s_pgp, grip, prompt,
    1037             :                                     cache_nonce, NULL,
    1038             :                                     r_key, r_passphrase);
    1039             : }
    1040             : 
    1041             : /* This function is called by agent_unprotect to re-protect an
    1042             :    openpgp-native protected private-key into the standard private-key
    1043             :    protection format.  */
    1044             : gpg_error_t
    1045           6 : convert_from_openpgp_native (ctrl_t ctrl,
    1046             :                              gcry_sexp_t s_pgp, const char *passphrase,
    1047             :                              unsigned char **r_key)
    1048             : {
    1049             :   gpg_error_t err;
    1050             :   unsigned char grip[20];
    1051             : 
    1052           6 :   if (!passphrase)
    1053           0 :     return gpg_error (GPG_ERR_INTERNAL);
    1054             : 
    1055           6 :   err = convert_from_openpgp_main (ctrl, s_pgp, grip, NULL,
    1056             :                                    NULL, passphrase,
    1057             :                                    r_key, NULL);
    1058             : 
    1059             :   /* On success try to re-write the key.  */
    1060           6 :   if (!err)
    1061             :     {
    1062           6 :       if (*passphrase)
    1063             :         {
    1064           6 :           unsigned char *protectedkey = NULL;
    1065             :           size_t protectedkeylen;
    1066             : 
    1067           6 :           if (!agent_protect (*r_key, passphrase,
    1068             :                               &protectedkey, &protectedkeylen,
    1069             :                               ctrl->s2k_count))
    1070           6 :             agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
    1071           6 :           xfree (protectedkey);
    1072             :         }
    1073             :       else
    1074             :         {
    1075             :           /* Empty passphrase: write key without protection.  */
    1076           0 :           agent_write_private_key (grip,
    1077             :                                    *r_key,
    1078             :                                    gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
    1079             :                                    1);
    1080             :         }
    1081             :     }
    1082             : 
    1083           6 :   return err;
    1084             : }
    1085             : 
    1086             : 
    1087             : /* Given an ARRAY of mpis with the key parameters, protect the secret
    1088             :    parameters in that array and replace them by one opaque encoded
    1089             :    mpi.  NPKEY is the number of public key parameters and NSKEY is
    1090             :    the number of secret key parameters (including the public ones).
    1091             :    On success the array will have NPKEY+1 elements.  */
    1092             : static gpg_error_t
    1093           0 : apply_protection (gcry_mpi_t *array, int npkey, int nskey,
    1094             :                   const char *passphrase,
    1095             :                   int protect_algo, void *protect_iv, size_t protect_ivlen,
    1096             :                   int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count)
    1097             : {
    1098             :   gpg_error_t err;
    1099             :   int i, j;
    1100             :   gcry_cipher_hd_t cipherhd;
    1101             :   unsigned char *bufarr[10];
    1102             :   size_t narr[10];
    1103             :   unsigned int nbits[10];
    1104             :   int ndata;
    1105             :   unsigned char *p, *data;
    1106             : 
    1107           0 :   assert (npkey < nskey);
    1108           0 :   assert (nskey < DIM (bufarr));
    1109             : 
    1110             :   /* Collect only the secret key parameters into BUFARR et al and
    1111             :      compute the required size of the data buffer.  */
    1112           0 :   ndata = 20; /* Space for the SHA-1 checksum.  */
    1113           0 :   for (i = npkey, j = 0; i < nskey; i++, j++ )
    1114             :     {
    1115           0 :       err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]);
    1116           0 :       if (err)
    1117             :         {
    1118           0 :           for (i = 0; i < j; i++)
    1119           0 :             xfree (bufarr[i]);
    1120           0 :           return err;
    1121             :         }
    1122           0 :       nbits[j] = gcry_mpi_get_nbits (array[i]);
    1123           0 :       ndata += 2 + narr[j];
    1124             :     }
    1125             : 
    1126             :   /* Allocate data buffer and stuff it with the secret key parameters.  */
    1127           0 :   data = xtrymalloc_secure (ndata);
    1128           0 :   if (!data)
    1129             :     {
    1130           0 :       err = gpg_error_from_syserror ();
    1131           0 :       for (i = 0; i < (nskey-npkey); i++ )
    1132           0 :         xfree (bufarr[i]);
    1133           0 :       return err;
    1134             :     }
    1135           0 :   p = data;
    1136           0 :   for (i = 0; i < (nskey-npkey); i++ )
    1137             :     {
    1138           0 :       *p++ = nbits[i] >> 8 ;
    1139           0 :       *p++ = nbits[i];
    1140           0 :       memcpy (p, bufarr[i], narr[i]);
    1141           0 :       p += narr[i];
    1142           0 :       xfree (bufarr[i]);
    1143           0 :       bufarr[i] = NULL;
    1144             :     }
    1145           0 :   assert (p == data + ndata - 20);
    1146             : 
    1147             :   /* Append a hash of the secret key parameters.  */
    1148           0 :   gcry_md_hash_buffer (GCRY_MD_SHA1, p, data, ndata - 20);
    1149             : 
    1150             :   /* Encrypt it.  */
    1151           0 :   err = gcry_cipher_open (&cipherhd, protect_algo,
    1152             :                           GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
    1153           0 :   if (!err)
    1154           0 :     err = hash_passphrase_and_set_key (passphrase, cipherhd, protect_algo,
    1155             :                                        s2k_mode, s2k_algo, s2k_salt, s2k_count);
    1156           0 :   if (!err)
    1157           0 :     err = gcry_cipher_setiv (cipherhd, protect_iv, protect_ivlen);
    1158           0 :   if (!err)
    1159           0 :     err = gcry_cipher_encrypt (cipherhd, data, ndata, NULL, 0);
    1160           0 :   gcry_cipher_close (cipherhd);
    1161           0 :   if (err)
    1162             :     {
    1163           0 :       xfree (data);
    1164           0 :       return err;
    1165             :     }
    1166             : 
    1167             :   /* Replace the secret key parameters in the array by one opaque value.  */
    1168           0 :   for (i = npkey; i < nskey; i++ )
    1169             :     {
    1170           0 :       gcry_mpi_release (array[i]);
    1171           0 :       array[i] = NULL;
    1172             :     }
    1173           0 :   array[npkey] = gcry_mpi_set_opaque (NULL, data, ndata*8);
    1174           0 :   return 0;
    1175             : }
    1176             : 
    1177             : 
    1178             : /*
    1179             :  * Examining S_KEY in S-Expression and extract data.
    1180             :  * When REQ_PRIVATE_KEY_DATA == 1, S_KEY's CAR should be 'private-key',
    1181             :  * but it also allows shadowed or protected versions.
    1182             :  * On success, it returns 0, otherwise error number.
    1183             :  * R_ALGONAME is static string which is no need to free by caller.
    1184             :  * R_NPKEY is pointer to number of public key data.
    1185             :  * R_NSKEY is pointer to number of private key data.
    1186             :  * R_ELEMS is static string which is no need to free by caller.
    1187             :  * ARRAY contains public and private key data.
    1188             :  * ARRAYSIZE is the allocated size of the array for cross-checking.
    1189             :  * R_CURVE is pointer to S-Expression of the curve (can be NULL).
    1190             :  * R_FLAGS is pointer to S-Expression of the flags (can be NULL).
    1191             :  */
    1192             : gpg_error_t
    1193           0 : extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
    1194             :                      const char **r_algoname, int *r_npkey, int *r_nskey,
    1195             :                      const char **r_elems,
    1196             :                      gcry_mpi_t *array, int arraysize,
    1197             :                      gcry_sexp_t *r_curve, gcry_sexp_t *r_flags)
    1198             : {
    1199             :   gpg_error_t err;
    1200             :   gcry_sexp_t list, l2;
    1201             :   char *name;
    1202             :   const char *algoname, *format;
    1203             :   int npkey, nskey;
    1204           0 :   gcry_sexp_t curve = NULL;
    1205           0 :   gcry_sexp_t flags = NULL;
    1206             : 
    1207           0 :   *r_curve = NULL;
    1208           0 :   *r_flags = NULL;
    1209             : 
    1210           0 :   if (!req_private_key_data)
    1211             :     {
    1212           0 :       list = gcry_sexp_find_token (s_key, "shadowed-private-key", 0 );
    1213           0 :       if (!list)
    1214           0 :         list = gcry_sexp_find_token (s_key, "protected-private-key", 0 );
    1215           0 :       if (!list)
    1216           0 :         list = gcry_sexp_find_token (s_key, "private-key", 0 );
    1217             :     }
    1218             :   else
    1219           0 :     list = gcry_sexp_find_token (s_key, "private-key", 0);
    1220             : 
    1221           0 :   if (!list)
    1222             :     {
    1223           0 :       log_error ("invalid private key format\n");
    1224           0 :       return gpg_error (GPG_ERR_BAD_SECKEY);
    1225             :     }
    1226             : 
    1227           0 :   l2 = gcry_sexp_cadr (list);
    1228           0 :   gcry_sexp_release (list);
    1229           0 :   list = l2;
    1230           0 :   name = gcry_sexp_nth_string (list, 0);
    1231           0 :   if (!name)
    1232             :     {
    1233           0 :       gcry_sexp_release (list);
    1234           0 :       return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */
    1235             :     }
    1236             : 
    1237           0 :   if (arraysize < 7)
    1238           0 :     BUG ();
    1239             : 
    1240             :   /* Map NAME to a name as used by Libgcrypt.  We do not use the
    1241             :      Libgcrypt function here because we need a lowercase name and
    1242             :      require special treatment for some algorithms.  */
    1243           0 :   strlwr (name);
    1244           0 :   if (!strcmp (name, "rsa"))
    1245             :     {
    1246           0 :       algoname = "rsa";
    1247           0 :       format = "ned?p?q?u?";
    1248           0 :       npkey = 2;
    1249           0 :       nskey = 6;
    1250           0 :       err = gcry_sexp_extract_param (list, NULL, format,
    1251             :                                      array+0, array+1, array+2, array+3,
    1252             :                                      array+4, array+5, NULL);
    1253             :     }
    1254           0 :   else if (!strcmp (name, "elg"))
    1255             :     {
    1256           0 :       algoname = "elg";
    1257           0 :       format = "pgyx?";
    1258           0 :       npkey = 3;
    1259           0 :       nskey = 4;
    1260           0 :       err = gcry_sexp_extract_param (list, NULL, format,
    1261             :                                      array+0, array+1, array+2, array+3,
    1262             :                                      NULL);
    1263             :     }
    1264           0 :   else if (!strcmp (name, "dsa"))
    1265             :     {
    1266           0 :       algoname = "dsa";
    1267           0 :       format = "pqgyx?";
    1268           0 :       npkey = 4;
    1269           0 :       nskey = 5;
    1270           0 :       err = gcry_sexp_extract_param (list, NULL, format,
    1271             :                                      array+0, array+1, array+2, array+3,
    1272             :                                      array+4, NULL);
    1273             :     }
    1274           0 :   else if (!strcmp (name, "ecc"))
    1275             :     {
    1276           0 :       algoname = "ecc";
    1277           0 :       format = "qd?";
    1278           0 :       npkey = 1;
    1279           0 :       nskey = 2;
    1280           0 :       curve = gcry_sexp_find_token (list, "curve", 0);
    1281           0 :       flags = gcry_sexp_find_token (list, "flags", 0);
    1282           0 :       err = gcry_sexp_extract_param (list, NULL, format,
    1283             :                                      array+0, array+1, NULL);
    1284             :     }
    1285             :   else
    1286             :     {
    1287           0 :       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
    1288             :     }
    1289           0 :   xfree (name);
    1290           0 :   gcry_sexp_release (list);
    1291           0 :   if (err)
    1292             :     {
    1293           0 :       gcry_sexp_release (curve);
    1294           0 :       gcry_sexp_release (flags);
    1295           0 :       return err;
    1296             :     }
    1297             :   else
    1298             :     {
    1299           0 :       *r_algoname = algoname;
    1300           0 :       if (r_elems)
    1301           0 :         *r_elems = format;
    1302           0 :       *r_npkey = npkey;
    1303           0 :       if (r_nskey)
    1304           0 :         *r_nskey = nskey;
    1305           0 :       *r_curve = curve;
    1306           0 :       *r_flags = flags;
    1307             : 
    1308           0 :       return 0;
    1309             :     }
    1310             : }
    1311             : 
    1312             : /* Convert our key S_KEY into an OpenPGP key transfer format.  On
    1313             :    success a canonical encoded S-expression is stored at R_TRANSFERKEY
    1314             :    and its length at R_TRANSFERKEYLEN; this S-expression is also
    1315             :    padded to a multiple of 64 bits.  */
    1316             : gpg_error_t
    1317           0 : convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
    1318             :                     unsigned char **r_transferkey, size_t *r_transferkeylen)
    1319             : {
    1320             :   gpg_error_t err;
    1321             :   const char *algoname;
    1322             :   int npkey, nskey;
    1323             :   gcry_mpi_t array[10];
    1324           0 :   gcry_sexp_t curve = NULL;
    1325           0 :   gcry_sexp_t flags = NULL;
    1326             :   char protect_iv[16];
    1327             :   char salt[8];
    1328             :   unsigned long s2k_count;
    1329             :   int i, j;
    1330             : 
    1331             :   (void)ctrl;
    1332             : 
    1333           0 :   *r_transferkey = NULL;
    1334             : 
    1335           0 :   for (i=0; i < DIM (array); i++)
    1336           0 :     array[i] = NULL;
    1337             : 
    1338           0 :   err = extract_private_key (s_key, 1, &algoname, &npkey, &nskey, NULL,
    1339             :                              array, DIM (array), &curve, &flags);
    1340           0 :   if (err)
    1341           0 :     return err;
    1342             : 
    1343           0 :   gcry_create_nonce (protect_iv, sizeof protect_iv);
    1344           0 :   gcry_create_nonce (salt, sizeof salt);
    1345             :   /* We need to use the encoded S2k count.  It is not possible to
    1346             :      encode it after it has been used because the encoding procedure
    1347             :      may round the value up.  */
    1348           0 :   s2k_count = get_standard_s2k_count_rfc4880 ();
    1349           0 :   err = apply_protection (array, npkey, nskey, passphrase,
    1350             :                           GCRY_CIPHER_AES, protect_iv, sizeof protect_iv,
    1351             :                           3, GCRY_MD_SHA1, salt, s2k_count);
    1352             :   /* Turn it into the transfer key S-expression.  Note that we always
    1353             :      return a protected key.  */
    1354           0 :   if (!err)
    1355             :     {
    1356             :       char countbuf[35];
    1357             :       membuf_t mbuf;
    1358             :       void *format_args[10+2];
    1359             :       gcry_sexp_t tmpkey;
    1360           0 :       gcry_sexp_t tmpsexp = NULL;
    1361             : 
    1362           0 :       snprintf (countbuf, sizeof countbuf, "%lu", s2k_count);
    1363             : 
    1364           0 :       init_membuf (&mbuf, 50);
    1365           0 :       put_membuf_str (&mbuf, "(skey");
    1366           0 :       for (i=j=0; i < npkey; i++)
    1367             :         {
    1368           0 :           put_membuf_str (&mbuf, " _ %m");
    1369           0 :           format_args[j++] = array + i;
    1370             :         }
    1371           0 :       put_membuf_str (&mbuf, " e %m");
    1372           0 :       format_args[j++] = array + npkey;
    1373           0 :       put_membuf_str (&mbuf, ")\n");
    1374           0 :       put_membuf (&mbuf, "", 1);
    1375             : 
    1376           0 :       tmpkey = NULL;
    1377             :       {
    1378           0 :         char *format = get_membuf (&mbuf, NULL);
    1379           0 :         if (!format)
    1380           0 :           err = gpg_error_from_syserror ();
    1381             :         else
    1382           0 :           err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args);
    1383           0 :         xfree (format);
    1384             :       }
    1385           0 :       if (!err)
    1386           0 :         err = gcry_sexp_build (&tmpsexp, NULL,
    1387             :                                "(openpgp-private-key\n"
    1388             :                                " (version 1:4)\n"
    1389             :                                " (algo %s)\n"
    1390             :                                " %S%S\n"
    1391             :                                " (protection sha1 aes %b 1:3 sha1 %b %s))\n",
    1392             :                                algoname,
    1393             :                                curve,
    1394             :                                tmpkey,
    1395             :                                (int)sizeof protect_iv, protect_iv,
    1396             :                                (int)sizeof salt, salt,
    1397             :                                countbuf);
    1398           0 :       gcry_sexp_release (tmpkey);
    1399           0 :       if (!err)
    1400           0 :         err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen);
    1401           0 :       gcry_sexp_release (tmpsexp);
    1402             :     }
    1403             : 
    1404           0 :   for (i=0; i < DIM (array); i++)
    1405           0 :     gcry_mpi_release (array[i]);
    1406           0 :   gcry_sexp_release (curve);
    1407           0 :   gcry_sexp_release (flags);
    1408             : 
    1409           0 :   return err;
    1410             : }

Generated by: LCOV version 1.11