LCOV - code coverage report
Current view: top level - agent - findkey.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 172 601 28.6 %
Date: 2015-11-05 17:10:59 Functions: 10 16 62.5 %

          Line data    Source code
       1             : /* findkey.c - Locate the secret key
       2             :  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
       3             :  *               2010, 2011 Free Software Foundation, Inc.
       4             :  * Copyright (C) 2014 Werner Koch
       5             :  *
       6             :  * This file is part of GnuPG.
       7             :  *
       8             :  * GnuPG is free software; you can redistribute it and/or modify
       9             :  * it under the terms of the GNU General Public License as published by
      10             :  * the Free Software Foundation; either version 3 of the License, or
      11             :  * (at your option) any later version.
      12             :  *
      13             :  * GnuPG is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  * GNU General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License
      19             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : #include <config.h>
      23             : #include <errno.h>
      24             : #include <stdio.h>
      25             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <ctype.h>
      28             : #include <fcntl.h>
      29             : #include <assert.h>
      30             : #include <unistd.h>
      31             : #include <sys/stat.h>
      32             : #include <assert.h>
      33             : #include <npth.h> /* (we use pth_sleep) */
      34             : 
      35             : #include "agent.h"
      36             : #include "i18n.h"
      37             : #include "../common/ssh-utils.h"
      38             : 
      39             : #ifndef O_BINARY
      40             : #define O_BINARY 0
      41             : #endif
      42             : 
      43             : /* Helper to pass data to the check callback of the unprotect function. */
      44             : struct try_unprotect_arg_s
      45             : {
      46             :   ctrl_t ctrl;
      47             :   const unsigned char *protected_key;
      48             :   unsigned char *unprotected_key;
      49             :   int change_required; /* Set by the callback to indicate that the
      50             :                           user should change the passphrase.  */
      51             : };
      52             : 
      53             : 
      54             : /* Write an S-expression formatted key to our key storage.  With FORCE
      55             :    passed as true an existing key with the given GRIP will get
      56             :    overwritten.  */
      57             : int
      58          21 : agent_write_private_key (const unsigned char *grip,
      59             :                          const void *buffer, size_t length, int force)
      60             : {
      61             :   char *fname;
      62             :   estream_t fp;
      63             :   char hexgrip[40+4+1];
      64             : 
      65          21 :   bin2hex (grip, 20, hexgrip);
      66          21 :   strcpy (hexgrip+40, ".key");
      67             : 
      68          21 :   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
      69             : 
      70             :   /* FIXME: Write to a temp file first so that write failures during
      71             :      key updates won't lead to a key loss.  */
      72             : 
      73          21 :   if (!force && !access (fname, F_OK))
      74             :     {
      75           0 :       log_error ("secret key file '%s' already exists\n", fname);
      76           0 :       xfree (fname);
      77           0 :       return gpg_error (GPG_ERR_EEXIST);
      78             :     }
      79             : 
      80          21 :   fp = es_fopen (fname, force? "wb,mode=-rw" : "wbx,mode=-rw");
      81          21 :   if (!fp)
      82             :     {
      83           0 :       gpg_error_t tmperr = gpg_error_from_syserror ();
      84           0 :       log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
      85           0 :       xfree (fname);
      86           0 :       return tmperr;
      87             :     }
      88             : 
      89          21 :   if (es_fwrite (buffer, length, 1, fp) != 1)
      90             :     {
      91           0 :       gpg_error_t tmperr = gpg_error_from_syserror ();
      92           0 :       log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
      93           0 :       es_fclose (fp);
      94           0 :       gnupg_remove (fname);
      95           0 :       xfree (fname);
      96           0 :       return tmperr;
      97             :     }
      98          21 :   if (es_fclose (fp))
      99             :     {
     100           0 :       gpg_error_t tmperr = gpg_error_from_syserror ();
     101           0 :       log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
     102           0 :       gnupg_remove (fname);
     103           0 :       xfree (fname);
     104           0 :       return tmperr;
     105             :     }
     106          21 :   bump_key_eventcounter ();
     107          21 :   xfree (fname);
     108          21 :   return 0;
     109             : }
     110             : 
     111             : 
     112             : /* Callback function to try the unprotection from the passphrase query
     113             :    code. */
     114             : static gpg_error_t
     115           0 : try_unprotect_cb (struct pin_entry_info_s *pi)
     116             : {
     117           0 :   struct try_unprotect_arg_s *arg = pi->check_cb_arg;
     118           0 :   ctrl_t ctrl = arg->ctrl;
     119             :   size_t dummy;
     120             :   gpg_error_t err;
     121             :   gnupg_isotime_t now, protected_at, tmptime;
     122           0 :   char *desc = NULL;
     123             : 
     124           0 :   assert (!arg->unprotected_key);
     125             : 
     126           0 :   arg->change_required = 0;
     127           0 :   err = agent_unprotect (ctrl, arg->protected_key, pi->pin, protected_at,
     128             :                          &arg->unprotected_key, &dummy);
     129           0 :   if (err)
     130           0 :     return err;
     131           0 :   if (!opt.max_passphrase_days || ctrl->in_passwd)
     132           0 :     return 0;  /* No regular passphrase change required.  */
     133             : 
     134           0 :   if (!*protected_at)
     135             :     {
     136             :       /* No protection date known - must force passphrase change.  */
     137           0 :       desc = xtrystrdup (L_("Note: This passphrase has never been changed.%0A"
     138             :                             "Please change it now."));
     139           0 :       if (!desc)
     140           0 :         return gpg_error_from_syserror ();
     141             :     }
     142             :   else
     143             :     {
     144           0 :       gnupg_get_isotime (now);
     145           0 :       gnupg_copy_time (tmptime, protected_at);
     146           0 :       err = add_days_to_isotime (tmptime, opt.max_passphrase_days);
     147           0 :       if (err)
     148           0 :         return err;
     149           0 :       if (strcmp (now, tmptime) > 0 )
     150             :         {
     151             :           /* Passphrase "expired".  */
     152           0 :           desc = xtryasprintf
     153             :             (L_("This passphrase has not been changed%%0A"
     154             :                 "since %.4s-%.2s-%.2s.  Please change it now."),
     155             :              protected_at, protected_at+4, protected_at+6);
     156           0 :           if (!desc)
     157           0 :             return gpg_error_from_syserror ();
     158             :         }
     159             :     }
     160             : 
     161           0 :   if (desc)
     162             :     {
     163             :       /* Change required.  */
     164           0 :       if (opt.enforce_passphrase_constraints)
     165             :         {
     166           0 :           err = agent_get_confirmation (ctrl, desc,
     167             :                                         L_("Change passphrase"), NULL, 0);
     168           0 :           if (!err)
     169           0 :             arg->change_required = 1;
     170             :         }
     171             :       else
     172             :         {
     173           0 :           err = agent_get_confirmation (ctrl, desc,
     174             :                                         L_("Change passphrase"),
     175             :                                         L_("I'll change it later"), 0);
     176           0 :           if (!err)
     177           0 :             arg->change_required = 1;
     178           0 :           else if (gpg_err_code (err) == GPG_ERR_CANCELED
     179           0 :                    || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
     180           0 :             err = 0;
     181             :         }
     182           0 :       xfree (desc);
     183             :     }
     184             : 
     185           0 :   return 0;
     186             : }
     187             : 
     188             : 
     189             : /* Modify a Key description, replacing certain special format
     190             :    characters.  List of currently supported replacements:
     191             : 
     192             :    %% - Replaced by a single %
     193             :    %c - Replaced by the content of COMMENT.
     194             :    %C - Same as %c but put into parentheses.
     195             :    %F - Replaced by an ssh style fingerprint computed from KEY.
     196             : 
     197             :    The functions returns 0 on success or an error code.  On success a
     198             :    newly allocated string is stored at the address of RESULT.
     199             :  */
     200             : static gpg_error_t
     201         120 : modify_description (const char *in, const char *comment, const gcry_sexp_t key,
     202             :                     char **result)
     203             : {
     204             :   size_t comment_length;
     205             :   size_t in_len;
     206             :   size_t out_len;
     207             :   char *out;
     208             :   size_t i;
     209             :   int special, pass;
     210         120 :   char *ssh_fpr = NULL;
     211             : 
     212         120 :   comment_length = strlen (comment);
     213         120 :   in_len  = strlen (in);
     214             : 
     215             :   /* First pass calculates the length, second pass does the actual
     216             :      copying.  */
     217         120 :   out = NULL;
     218         120 :   out_len = 0;
     219         360 :   for (pass=0; pass < 2; pass++)
     220             :     {
     221         240 :       special = 0;
     222       41394 :       for (i = 0; i < in_len; i++)
     223             :         {
     224       41154 :           if (special)
     225             :             {
     226        1440 :               special = 0;
     227        1440 :               switch (in[i])
     228             :                 {
     229             :                 case '%':
     230           0 :                   if (out)
     231           0 :                     *out++ = '%';
     232             :                   else
     233           0 :                     out_len++;
     234           0 :                   break;
     235             : 
     236             :                 case 'c': /* Comment.  */
     237           0 :                   if (out)
     238             :                     {
     239           0 :                       memcpy (out, comment, comment_length);
     240           0 :                       out += comment_length;
     241             :                     }
     242             :                   else
     243           0 :                     out_len += comment_length;
     244           0 :                   break;
     245             : 
     246             :                 case 'C': /* Comment.  */
     247           0 :                   if (!comment_length)
     248             :                     ;
     249           0 :                   else if (out)
     250             :                     {
     251           0 :                       *out++ = '(';
     252           0 :                       memcpy (out, comment, comment_length);
     253           0 :                       out += comment_length;
     254           0 :                       *out++ = ')';
     255             :                     }
     256             :                   else
     257           0 :                     out_len += comment_length + 2;
     258           0 :                   break;
     259             : 
     260             :                 case 'F': /* SSH style fingerprint.  */
     261           0 :                   if (!ssh_fpr && key)
     262           0 :                     ssh_get_fingerprint_string (key, &ssh_fpr);
     263           0 :                   if (ssh_fpr)
     264             :                     {
     265           0 :                       if (out)
     266           0 :                         out = stpcpy (out, ssh_fpr);
     267             :                       else
     268           0 :                         out_len += strlen (ssh_fpr);
     269             :                     }
     270           0 :                   break;
     271             : 
     272             :                 default: /* Invalid special sequences are kept as they are. */
     273        1440 :                   if (out)
     274             :                     {
     275         720 :                       *out++ = '%';
     276         720 :                       *out++ = in[i];
     277             :                     }
     278             :                   else
     279         720 :                     out_len+=2;
     280        1440 :                   break;
     281             :                 }
     282             :             }
     283       39714 :           else if (in[i] == '%')
     284        1440 :             special = 1;
     285             :           else
     286             :             {
     287       38274 :               if (out)
     288       19137 :                 *out++ = in[i];
     289             :               else
     290       19137 :                 out_len++;
     291             :             }
     292             :         }
     293             : 
     294         240 :       if (!pass)
     295             :         {
     296         120 :           *result = out = xtrymalloc (out_len + 1);
     297         120 :           if (!out)
     298             :             {
     299           0 :               xfree (ssh_fpr);
     300           0 :               return gpg_error_from_syserror ();
     301             :             }
     302             :         }
     303             :     }
     304             : 
     305         120 :   *out = 0;
     306         120 :   assert (*result + out_len == out);
     307         120 :   xfree (ssh_fpr);
     308         120 :   return 0;
     309             : }
     310             : 
     311             : 
     312             : 
     313             : /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
     314             :    should be the hex encoded keygrip of that key to be used with the
     315             :    caching mechanism. DESC_TEXT may be set to override the default
     316             :    description used for the pinentry.  If LOOKUP_TTL is given this
     317             :    function is used to lookup the default ttl.  If R_PASSPHRASE is not
     318             :    NULL, the function succeeded and the key was protected the used
     319             :    passphrase (entered or from the cache) is stored there; if not NULL
     320             :    will be stored.  The caller needs to free the returned
     321             :    passphrase. */
     322             : static int
     323         120 : unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
     324             :            unsigned char **keybuf, const unsigned char *grip,
     325             :            cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
     326             :            char **r_passphrase)
     327             : {
     328             :   struct pin_entry_info_s *pi;
     329             :   struct try_unprotect_arg_s arg;
     330             :   int rc;
     331             :   unsigned char *result;
     332             :   size_t resultlen;
     333             :   char hexgrip[40+1];
     334             : 
     335         120 :   if (r_passphrase)
     336           0 :     *r_passphrase = NULL;
     337             : 
     338         120 :   bin2hex (grip, 20, hexgrip);
     339             : 
     340             :   /* Initially try to get it using a cache nonce.  */
     341         120 :   if (cache_nonce)
     342             :     {
     343             :       char *pw;
     344             : 
     345           0 :       pw = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
     346           0 :       if (pw)
     347             :         {
     348           0 :           rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
     349           0 :           if (!rc)
     350             :             {
     351           0 :               if (r_passphrase)
     352           0 :                 *r_passphrase = pw;
     353             :               else
     354           0 :                 xfree (pw);
     355           0 :               xfree (*keybuf);
     356           0 :               *keybuf = result;
     357           0 :               return 0;
     358             :             }
     359           0 :           xfree (pw);
     360             :         }
     361             :     }
     362             : 
     363             :   /* First try to get it from the cache - if there is none or we can't
     364             :      unprotect it, we fall back to ask the user */
     365         120 :   if (cache_mode != CACHE_MODE_IGNORE)
     366             :     {
     367             :       char *pw;
     368             : 
     369             :     retry:
     370         120 :       pw = agent_get_cache (hexgrip, cache_mode);
     371         120 :       if (pw)
     372             :         {
     373         120 :           rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
     374         120 :           if (!rc)
     375             :             {
     376         120 :               if (cache_mode == CACHE_MODE_NORMAL)
     377         120 :                 agent_store_cache_hit (hexgrip);
     378         120 :               if (r_passphrase)
     379           0 :                 *r_passphrase = pw;
     380             :               else
     381         120 :                 xfree (pw);
     382         120 :               xfree (*keybuf);
     383         120 :               *keybuf = result;
     384         120 :               return 0;
     385             :             }
     386           0 :           xfree (pw);
     387           0 :           rc  = 0;
     388             :         }
     389           0 :       else if (cache_mode == CACHE_MODE_NORMAL)
     390             :         {
     391             :           /* The standard use of GPG keys is to have a signing and an
     392             :              encryption subkey.  Commonly both use the same
     393             :              passphrase.  We try to help the user to enter the
     394             :              passphrase only once by silently trying the last
     395             :              correctly entered passphrase.  Checking one additional
     396             :              passphrase should be acceptable; despite the S2K
     397             :              introduced delays. The assumed workflow is:
     398             : 
     399             :                1. Read encrypted message in a MUA and thus enter a
     400             :                   passphrase for the encryption subkey.
     401             : 
     402             :                2. Reply to that mail with an encrypted and signed
     403             :                   mail, thus entering the passphrase for the signing
     404             :                   subkey.
     405             : 
     406             :              We can often avoid the passphrase entry in the second
     407             :              step.  We do this only in normal mode, so not to
     408             :              interfere with unrelated cache entries.  */
     409           0 :           pw = agent_get_cache (NULL, cache_mode);
     410           0 :           if (pw)
     411             :             {
     412           0 :               rc = agent_unprotect (ctrl, *keybuf, pw, NULL,
     413             :                                     &result, &resultlen);
     414           0 :               if (!rc)
     415             :                 {
     416           0 :                   if (r_passphrase)
     417           0 :                     *r_passphrase = pw;
     418             :                   else
     419           0 :                     xfree (pw);
     420           0 :                   xfree (*keybuf);
     421           0 :                   *keybuf = result;
     422           0 :                   return 0;
     423             :                 }
     424           0 :               xfree (pw);
     425           0 :               rc  = 0;
     426             :             }
     427             :         }
     428             : 
     429             :       /* If the pinentry is currently in use, we wait up to 60 seconds
     430             :          for it to close and check the cache again.  This solves a common
     431             :          situation where several requests for unprotecting a key have
     432             :          been made but the user is still entering the passphrase for
     433             :          the first request.  Because all requests to agent_askpin are
     434             :          serialized they would then pop up one after the other to
     435             :          request the passphrase - despite that the user has already
     436             :          entered it and is then available in the cache.  This
     437             :          implementation is not race free but in the worst case the
     438             :          user has to enter the passphrase only once more. */
     439           0 :       if (pinentry_active_p (ctrl, 0))
     440             :         {
     441             :           /* Active - wait */
     442           0 :           if (!pinentry_active_p (ctrl, 60))
     443             :             {
     444             :               /* We need to give the other thread a chance to actually put
     445             :                  it into the cache. */
     446           0 :               npth_sleep (1);
     447           0 :               goto retry;
     448             :             }
     449             :           /* Timeout - better call pinentry now the plain way. */
     450             :         }
     451             :     }
     452             : 
     453           0 :   pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
     454           0 :   if (!pi)
     455           0 :     return gpg_error_from_syserror ();
     456           0 :   pi->max_length = MAX_PASSPHRASE_LEN + 1;
     457           0 :   pi->min_digits = 0;  /* we want a real passphrase */
     458           0 :   pi->max_digits = 16;
     459           0 :   pi->max_tries = 3;
     460           0 :   pi->check_cb = try_unprotect_cb;
     461           0 :   arg.ctrl = ctrl;
     462           0 :   arg.protected_key = *keybuf;
     463           0 :   arg.unprotected_key = NULL;
     464           0 :   arg.change_required = 0;
     465           0 :   pi->check_cb_arg = &arg;
     466             : 
     467           0 :   rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, hexgrip, cache_mode);
     468           0 :   if (!rc)
     469             :     {
     470           0 :       assert (arg.unprotected_key);
     471           0 :       if (arg.change_required)
     472             :         {
     473             :           /* The callback told as that the user should change their
     474             :              passphrase.  Present the dialog to do.  */
     475             :           size_t canlen, erroff;
     476             :           gcry_sexp_t s_skey;
     477             : 
     478           0 :           assert (arg.unprotected_key);
     479           0 :           canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
     480           0 :           rc = gcry_sexp_sscan (&s_skey, &erroff,
     481           0 :                                 (char*)arg.unprotected_key, canlen);
     482           0 :           if (rc)
     483             :             {
     484           0 :               log_error ("failed to build S-Exp (off=%u): %s\n",
     485             :                          (unsigned int)erroff, gpg_strerror (rc));
     486           0 :               wipememory (arg.unprotected_key, canlen);
     487           0 :               xfree (arg.unprotected_key);
     488           0 :               xfree (pi);
     489           0 :               return rc;
     490             :             }
     491           0 :           rc = agent_protect_and_store (ctrl, s_skey, NULL);
     492           0 :           gcry_sexp_release (s_skey);
     493           0 :           if (rc)
     494             :             {
     495           0 :               log_error ("changing the passphrase failed: %s\n",
     496             :                          gpg_strerror (rc));
     497           0 :               wipememory (arg.unprotected_key, canlen);
     498           0 :               xfree (arg.unprotected_key);
     499           0 :               xfree (pi);
     500           0 :               return rc;
     501             :             }
     502             :         }
     503             :       else
     504             :         {
     505             :           /* Passphrase is fine.  */
     506           0 :           agent_put_cache (hexgrip, cache_mode, pi->pin,
     507             :                            lookup_ttl? lookup_ttl (hexgrip) : 0);
     508           0 :           agent_store_cache_hit (hexgrip);
     509           0 :           if (r_passphrase && *pi->pin)
     510           0 :             *r_passphrase = xtrystrdup (pi->pin);
     511             :         }
     512           0 :       xfree (*keybuf);
     513           0 :       *keybuf = arg.unprotected_key;
     514             :     }
     515           0 :   xfree (pi);
     516           0 :   return rc;
     517             : }
     518             : 
     519             : 
     520             : /* Read the key identified by GRIP from the private key directory and
     521             :    return it as an gcrypt S-expression object in RESULT.  On failure
     522             :    returns an error code and stores NULL at RESULT. */
     523             : static gpg_error_t
     524         372 : read_key_file (const unsigned char *grip, gcry_sexp_t *result)
     525             : {
     526             :   int rc;
     527             :   char *fname;
     528             :   estream_t fp;
     529             :   struct stat st;
     530             :   unsigned char *buf;
     531             :   size_t buflen, erroff;
     532             :   gcry_sexp_t s_skey;
     533             :   char hexgrip[40+4+1];
     534             : 
     535         372 :   *result = NULL;
     536             : 
     537         372 :   bin2hex (grip, 20, hexgrip);
     538         372 :   strcpy (hexgrip+40, ".key");
     539             : 
     540         372 :   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
     541         372 :   fp = es_fopen (fname, "rb");
     542         372 :   if (!fp)
     543             :     {
     544           0 :       rc = gpg_error_from_syserror ();
     545           0 :       if (gpg_err_code (rc) != GPG_ERR_ENOENT)
     546           0 :         log_error ("can't open '%s': %s\n", fname, strerror (errno));
     547           0 :       xfree (fname);
     548           0 :       return rc;
     549             :     }
     550             : 
     551         372 :   if (fstat (es_fileno (fp), &st))
     552             :     {
     553           0 :       rc = gpg_error_from_syserror ();
     554           0 :       log_error ("can't stat '%s': %s\n", fname, strerror (errno));
     555           0 :       xfree (fname);
     556           0 :       es_fclose (fp);
     557           0 :       return rc;
     558             :     }
     559             : 
     560         372 :   buflen = st.st_size;
     561         372 :   buf = xtrymalloc (buflen+1);
     562         372 :   if (!buf)
     563             :     {
     564           0 :       rc = gpg_error_from_syserror ();
     565           0 :       log_error ("error allocating %zu bytes for '%s': %s\n",
     566           0 :                  buflen, fname, strerror (errno));
     567           0 :       xfree (fname);
     568           0 :       es_fclose (fp);
     569           0 :       xfree (buf);
     570           0 :       return rc;
     571             : 
     572             :     }
     573             : 
     574         372 :   if (es_fread (buf, buflen, 1, fp) != 1)
     575             :     {
     576           0 :       rc = gpg_error_from_syserror ();
     577           0 :       log_error ("error reading %zu bytes from '%s': %s\n",
     578           0 :                  buflen, fname, strerror (errno));
     579           0 :       xfree (fname);
     580           0 :       es_fclose (fp);
     581           0 :       xfree (buf);
     582           0 :       return rc;
     583             :     }
     584             : 
     585             :   /* Convert the file into a gcrypt S-expression object.  */
     586         372 :   rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
     587         372 :   xfree (fname);
     588         372 :   es_fclose (fp);
     589         372 :   xfree (buf);
     590         372 :   if (rc)
     591             :     {
     592           0 :       log_error ("failed to build S-Exp (off=%u): %s\n",
     593             :                  (unsigned int)erroff, gpg_strerror (rc));
     594           0 :       return rc;
     595             :     }
     596         372 :   *result = s_skey;
     597         372 :   return 0;
     598             : }
     599             : 
     600             : 
     601             : /* Remove the key identified by GRIP from the private key directory.  */
     602             : static gpg_error_t
     603           0 : remove_key_file (const unsigned char *grip)
     604             : {
     605           0 :   gpg_error_t err = 0;
     606             :   char *fname;
     607             :   char hexgrip[40+4+1];
     608             : 
     609           0 :   bin2hex (grip, 20, hexgrip);
     610           0 :   strcpy (hexgrip+40, ".key");
     611           0 :   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
     612           0 :   if (gnupg_remove (fname))
     613           0 :     err = gpg_error_from_syserror ();
     614           0 :   xfree (fname);
     615           0 :   return err;
     616             : }
     617             : 
     618             : 
     619             : /* Return the secret key as an S-Exp in RESULT after locating it using
     620             :    the GRIP.  If the operation shall be diverted to a token, an
     621             :    allocated S-expression with the shadow_info part from the file is
     622             :    stored at SHADOW_INFO; if not NULL will be stored at SHADOW_INFO.
     623             :    CACHE_MODE defines now the cache shall be used.  DESC_TEXT may be
     624             :    set to present a custom description for the pinentry.  LOOKUP_TTL
     625             :    is an optional function to convey a TTL to the cache manager; we do
     626             :    not simply pass the TTL value because the value is only needed if
     627             :    an unprotect action was needed and looking up the TTL may have some
     628             :    overhead (e.g. scanning the sshcontrol file).  If a CACHE_NONCE is
     629             :    given that cache item is first tried to get a passphrase.  If
     630             :    R_PASSPHRASE is not NULL, the function succeeded and the key was
     631             :    protected the used passphrase (entered or from the cache) is stored
     632             :    there; if not NULL will be stored.  The caller needs to free the
     633             :    returned passphrase.   */
     634             : gpg_error_t
     635         372 : agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
     636             :                      const char *desc_text,
     637             :                      const unsigned char *grip, unsigned char **shadow_info,
     638             :                      cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
     639             :                      gcry_sexp_t *result, char **r_passphrase)
     640             : {
     641             :   int rc;
     642             :   unsigned char *buf;
     643             :   size_t len, buflen, erroff;
     644             :   gcry_sexp_t s_skey;
     645             : 
     646         372 :   *result = NULL;
     647         372 :   if (shadow_info)
     648         372 :     *shadow_info = NULL;
     649         372 :   if (r_passphrase)
     650           0 :     *r_passphrase = NULL;
     651             : 
     652         372 :   rc = read_key_file (grip, &s_skey);
     653         372 :   if (rc)
     654             :     {
     655           0 :       if (gpg_err_code (rc) == GPG_ERR_ENOENT)
     656           0 :         rc = gpg_error (GPG_ERR_NO_SECKEY);
     657           0 :       return rc;
     658             :     }
     659             : 
     660             :   /* For use with the protection functions we also need the key as an
     661             :      canonical encoded S-expression in a buffer.  Create this buffer
     662             :      now.  */
     663         372 :   rc = make_canon_sexp (s_skey, &buf, &len);
     664         372 :   if (rc)
     665           0 :     return rc;
     666             : 
     667         372 :   switch (agent_private_key_type (buf))
     668             :     {
     669             :     case PRIVATE_KEY_CLEAR:
     670         252 :       break; /* no unprotection needed */
     671             :     case PRIVATE_KEY_OPENPGP_NONE:
     672             :       {
     673             :         unsigned char *buf_new;
     674             :         size_t buf_newlen;
     675             : 
     676           0 :         rc = agent_unprotect (ctrl, buf, "", NULL, &buf_new, &buf_newlen);
     677           0 :         if (rc)
     678           0 :           log_error ("failed to convert unprotected openpgp key: %s\n",
     679             :                      gpg_strerror (rc));
     680             :         else
     681             :           {
     682           0 :             xfree (buf);
     683           0 :             buf = buf_new;
     684             :           }
     685             :       }
     686           0 :       break;
     687             :     case PRIVATE_KEY_PROTECTED:
     688             :       {
     689             :         char *desc_text_final;
     690         120 :         char *comment = NULL;
     691             : 
     692             :         /* Note, that we will take the comment as a C string for
     693             :            display purposes; i.e. all stuff beyond a Nul character is
     694             :            ignored.  */
     695             :         {
     696             :           gcry_sexp_t comment_sexp;
     697             : 
     698         120 :           comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
     699         120 :           if (comment_sexp)
     700           0 :             comment = gcry_sexp_nth_string (comment_sexp, 1);
     701         120 :           gcry_sexp_release (comment_sexp);
     702             :         }
     703             : 
     704         120 :         desc_text_final = NULL;
     705         120 :         if (desc_text)
     706         120 :           rc = modify_description (desc_text, comment? comment:"", s_skey,
     707             :                                    &desc_text_final);
     708         120 :         gcry_free (comment);
     709             : 
     710         120 :         if (!rc)
     711             :           {
     712         120 :             rc = unprotect (ctrl, cache_nonce, desc_text_final, &buf, grip,
     713             :                             cache_mode, lookup_ttl, r_passphrase);
     714         120 :             if (rc)
     715           0 :               log_error ("failed to unprotect the secret key: %s\n",
     716             :                          gpg_strerror (rc));
     717             :           }
     718             : 
     719         120 :         xfree (desc_text_final);
     720             :       }
     721         120 :       break;
     722             :     case PRIVATE_KEY_SHADOWED:
     723           0 :       if (shadow_info)
     724             :         {
     725             :           const unsigned char *s;
     726             :           size_t n;
     727             : 
     728           0 :           rc = agent_get_shadow_info (buf, &s);
     729           0 :           if (!rc)
     730             :             {
     731           0 :               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
     732           0 :               assert (n);
     733           0 :               *shadow_info = xtrymalloc (n);
     734           0 :               if (!*shadow_info)
     735           0 :                 rc = out_of_core ();
     736             :               else
     737             :                 {
     738           0 :                   memcpy (*shadow_info, s, n);
     739           0 :                   rc = 0;
     740             :                 }
     741             :             }
     742           0 :           if (rc)
     743           0 :             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
     744             :         }
     745             :       else
     746           0 :         rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
     747           0 :       break;
     748             :     default:
     749           0 :       log_error ("invalid private key format\n");
     750           0 :       rc = gpg_error (GPG_ERR_BAD_SECKEY);
     751           0 :       break;
     752             :     }
     753         372 :   gcry_sexp_release (s_skey);
     754         372 :   s_skey = NULL;
     755         372 :   if (rc)
     756             :     {
     757           0 :       xfree (buf);
     758           0 :       if (r_passphrase)
     759             :         {
     760           0 :           xfree (*r_passphrase);
     761           0 :           *r_passphrase = NULL;
     762             :         }
     763           0 :       return rc;
     764             :     }
     765             : 
     766         372 :   buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
     767         372 :   rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
     768         372 :   wipememory (buf, buflen);
     769         372 :   xfree (buf);
     770         372 :   if (rc)
     771             :     {
     772           0 :       log_error ("failed to build S-Exp (off=%u): %s\n",
     773             :                  (unsigned int)erroff, gpg_strerror (rc));
     774           0 :       if (r_passphrase)
     775             :         {
     776           0 :           xfree (*r_passphrase);
     777           0 :           *r_passphrase = NULL;
     778             :         }
     779           0 :       return rc;
     780             :     }
     781             : 
     782         372 :   *result = s_skey;
     783         372 :   return 0;
     784             : }
     785             : 
     786             : 
     787             : /* Return the string name from the S-expression S_KEY as well as a
     788             :    string describing the names of the parameters.  ALGONAMESIZE and
     789             :    ELEMSSIZE give the allocated size of the provided buffers.  The
     790             :    buffers may be NULL if not required.  If R_LIST is not NULL the top
     791             :    level list will be stored there; the caller needs to release it in
     792             :    this case.  */
     793             : static gpg_error_t
     794         240 : key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
     795             :                      char *r_algoname, size_t algonamesize,
     796             :                      char *r_elems, size_t elemssize)
     797             : {
     798             :   gcry_sexp_t list, l2;
     799             :   const char *name, *algoname, *elems;
     800             :   size_t n;
     801             : 
     802         240 :   if (r_list)
     803         240 :     *r_list = NULL;
     804             : 
     805         240 :   list = gcry_sexp_find_token (s_key, "shadowed-private-key", 0 );
     806         240 :   if (!list)
     807         240 :     list = gcry_sexp_find_token (s_key, "protected-private-key", 0 );
     808         240 :   if (!list)
     809         240 :     list = gcry_sexp_find_token (s_key, "private-key", 0 );
     810         240 :   if (!list)
     811             :     {
     812           0 :       log_error ("invalid private key format\n");
     813           0 :       return gpg_error (GPG_ERR_BAD_SECKEY);
     814             :     }
     815             : 
     816         240 :   l2 = gcry_sexp_cadr (list);
     817         240 :   gcry_sexp_release (list);
     818         240 :   list = l2;
     819         240 :   name = gcry_sexp_nth_data (list, 0, &n);
     820         240 :   if (n==3 && !memcmp (name, "rsa", 3))
     821             :     {
     822          16 :       algoname = "rsa";
     823          16 :       elems = "ne";
     824             :     }
     825         224 :   else if (n==3 && !memcmp (name, "dsa", 3))
     826             :     {
     827         182 :       algoname = "dsa";
     828         182 :       elems = "pqgy";
     829             :     }
     830          42 :   else if (n==3 && !memcmp (name, "ecc", 3))
     831             :     {
     832          42 :       algoname = "ecc";
     833          42 :       elems = "pabgnq";
     834             :     }
     835           0 :   else if (n==5 && !memcmp (name, "ecdsa", 5))
     836             :     {
     837           0 :       algoname = "ecdsa";
     838           0 :       elems = "pabgnq";
     839             :     }
     840           0 :   else if (n==4 && !memcmp (name, "ecdh", 4))
     841             :     {
     842           0 :       algoname = "ecdh";
     843           0 :       elems = "pabgnq";
     844             :     }
     845           0 :   else if (n==3 && !memcmp (name, "elg", 3))
     846             :     {
     847           0 :       algoname = "elg";
     848           0 :       elems = "pgy";
     849             :     }
     850             :   else
     851             :     {
     852           0 :       log_error ("unknown private key algorithm\n");
     853           0 :       gcry_sexp_release (list);
     854           0 :       return gpg_error (GPG_ERR_BAD_SECKEY);
     855             :     }
     856             : 
     857         240 :   if (r_algoname)
     858             :     {
     859         240 :       if (strlen (algoname) >= algonamesize)
     860           0 :         return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
     861         240 :       strcpy (r_algoname, algoname);
     862             :     }
     863         240 :   if (r_elems)
     864             :     {
     865           0 :       if (strlen (elems) >= elemssize)
     866           0 :         return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
     867           0 :       strcpy (r_elems, elems);
     868             :     }
     869             : 
     870         240 :   if (r_list)
     871         240 :     *r_list = list;
     872             :   else
     873           0 :     gcry_sexp_release (list);
     874             : 
     875         240 :   return 0;
     876             : }
     877             : 
     878             : 
     879             : /* Return true if KEYPARMS holds an EdDSA key.  */
     880             : static int
     881          42 : is_eddsa (gcry_sexp_t keyparms)
     882             : {
     883          42 :   int result = 0;
     884             :   gcry_sexp_t list;
     885             :   const char *s;
     886             :   size_t n;
     887             :   int i;
     888             : 
     889          42 :   list = gcry_sexp_find_token (keyparms, "flags", 0);
     890          42 :   for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
     891             :     {
     892           0 :       s = gcry_sexp_nth_data (list, i, &n);
     893           0 :       if (!s)
     894           0 :         continue; /* Not a data element. */
     895             : 
     896           0 :       if (n == 5 && !memcmp (s, "eddsa", 5))
     897             :         {
     898           0 :           result = 1;
     899           0 :           break;
     900             :         }
     901             :     }
     902          42 :   gcry_sexp_release (list);
     903          42 :   return result;
     904             : }
     905             : 
     906             : 
     907             : /* Return the public key algorithm number if S_KEY is a DSA style key.
     908             :    If it is not a DSA style key, return 0.  */
     909             : int
     910         120 : agent_is_dsa_key (gcry_sexp_t s_key)
     911             : {
     912             :   int result;
     913             :   gcry_sexp_t list;
     914             :   char algoname[6];
     915             : 
     916         120 :   if (!s_key)
     917           0 :     return 0;
     918             : 
     919         120 :   if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
     920           0 :     return 0; /* Error - assume it is not an DSA key.  */
     921             : 
     922         120 :   if (!strcmp (algoname, "dsa"))
     923          91 :     result = GCRY_PK_DSA;
     924          29 :   else if (!strcmp (algoname, "ecc"))
     925             :     {
     926          21 :       if (is_eddsa (list))
     927           0 :         result = 0;
     928             :       else
     929          21 :         result = GCRY_PK_ECDSA;
     930             :     }
     931           8 :   else if (!strcmp (algoname, "ecdsa"))
     932           0 :     result = GCRY_PK_ECDSA;
     933             :   else
     934           8 :     result = 0;
     935             : 
     936         120 :   gcry_sexp_release (list);
     937         120 :   return result;
     938             : }
     939             : 
     940             : 
     941             : /* Return true if S_KEY is an EdDSA key as used with curve Ed25519.  */
     942             : int
     943         120 : agent_is_eddsa_key (gcry_sexp_t s_key)
     944             : {
     945             :   int result;
     946             :   gcry_sexp_t list;
     947             :   char algoname[6];
     948             : 
     949         120 :   if (!s_key)
     950           0 :     return 0;
     951             : 
     952         120 :   if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
     953           0 :     return 0; /* Error - assume it is not an EdDSA key.  */
     954             : 
     955         120 :   if (!strcmp (algoname, "ecc") && is_eddsa (list))
     956           0 :     result = 1;
     957         120 :   else if (!strcmp (algoname, "eddsa")) /* backward compatibility.  */
     958           0 :     result = 1;
     959             :   else
     960         120 :     result = 0;
     961             : 
     962         120 :   gcry_sexp_release (list);
     963         120 :   return result;
     964             : }
     965             : 
     966             : 
     967             : /* Return the key for the keygrip GRIP.  The result is stored at
     968             :    RESULT.  This function extracts the key from the private key
     969             :    database and returns it as an S-expression object as it is.  On
     970             :    failure an error code is returned and NULL stored at RESULT. */
     971             : gpg_error_t
     972           0 : agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
     973             :                          gcry_sexp_t *result)
     974             : {
     975             :   gpg_error_t err;
     976             :   gcry_sexp_t s_skey;
     977             : 
     978             :   (void)ctrl;
     979             : 
     980           0 :   *result = NULL;
     981             : 
     982           0 :   err = read_key_file (grip, &s_skey);
     983           0 :   if (!err)
     984           0 :     *result = s_skey;
     985           0 :   return err;
     986             : }
     987             : 
     988             : 
     989             : /* Return the public key for the keygrip GRIP.  The result is stored
     990             :    at RESULT.  This function extracts the public key from the private
     991             :    key database.  On failure an error code is returned and NULL stored
     992             :    at RESULT. */
     993             : gpg_error_t
     994           0 : agent_public_key_from_file (ctrl_t ctrl,
     995             :                             const unsigned char *grip,
     996             :                             gcry_sexp_t *result)
     997             : {
     998             :   gpg_error_t err;
     999             :   int i, idx;
    1000             :   gcry_sexp_t s_skey;
    1001             :   const char *algoname, *elems;
    1002             :   int npkey;
    1003             :   gcry_mpi_t array[10];
    1004           0 :   gcry_sexp_t curve = NULL;
    1005           0 :   gcry_sexp_t flags = NULL;
    1006             :   gcry_sexp_t uri_sexp, comment_sexp;
    1007             :   const char *uri, *comment;
    1008             :   size_t uri_length, comment_length;
    1009             :   char *format, *p;
    1010             :   void *args[2+7+2+2+1]; /* Size is 2 + max. # of elements + 2 for uri + 2
    1011             :                             for comment + end-of-list.  */
    1012             :   int argidx;
    1013           0 :   gcry_sexp_t list = NULL;
    1014             :   const char *s;
    1015             : 
    1016             :   (void)ctrl;
    1017             : 
    1018           0 :   *result = NULL;
    1019             : 
    1020           0 :   err = read_key_file (grip, &s_skey);
    1021           0 :   if (err)
    1022           0 :     return err;
    1023             : 
    1024           0 :   for (i=0; i < DIM (array); i++)
    1025           0 :     array[i] = NULL;
    1026             : 
    1027           0 :   err = extract_private_key (s_skey, 0, &algoname, &npkey, NULL, &elems,
    1028             :                              array, DIM (array), &curve, &flags);
    1029           0 :   if (err)
    1030             :     {
    1031           0 :       gcry_sexp_release (s_skey);
    1032           0 :       return err;
    1033             :     }
    1034             : 
    1035           0 :   uri = NULL;
    1036           0 :   uri_length = 0;
    1037           0 :   uri_sexp = gcry_sexp_find_token (s_skey, "uri", 0);
    1038           0 :   if (uri_sexp)
    1039           0 :     uri = gcry_sexp_nth_data (uri_sexp, 1, &uri_length);
    1040             : 
    1041           0 :   comment = NULL;
    1042           0 :   comment_length = 0;
    1043           0 :   comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
    1044           0 :   if (comment_sexp)
    1045           0 :     comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
    1046             : 
    1047           0 :   gcry_sexp_release (s_skey);
    1048           0 :   s_skey = NULL;
    1049             : 
    1050             : 
    1051             :   /* FIXME: The following thing is pretty ugly code; we should
    1052             :      investigate how to make it cleaner.  Probably code to handle
    1053             :      canonical S-expressions in a memory buffer is better suited for
    1054             :      such a task.  After all that is what we do in protect.c.  Neeed
    1055             :      to find common patterns and write a straightformward API to use
    1056             :      them.  */
    1057             :   assert (sizeof (size_t) <= sizeof (void*));
    1058             : 
    1059           0 :   format = xtrymalloc (15+4+7*npkey+10+15+1+1);
    1060           0 :   if (!format)
    1061             :     {
    1062           0 :       err = gpg_error_from_syserror ();
    1063           0 :       for (i=0; array[i]; i++)
    1064           0 :         gcry_mpi_release (array[i]);
    1065           0 :       gcry_sexp_release (curve);
    1066           0 :       gcry_sexp_release (flags);
    1067           0 :       gcry_sexp_release (uri_sexp);
    1068           0 :       gcry_sexp_release (comment_sexp);
    1069           0 :       return err;
    1070             :     }
    1071             : 
    1072           0 :   argidx = 0;
    1073           0 :   p = stpcpy (stpcpy (format, "(public-key("), algoname);
    1074           0 :   p = stpcpy (p, "%S%S");       /* curve name and flags.  */
    1075           0 :   args[argidx++] = &curve;
    1076           0 :   args[argidx++] = &flags;
    1077           0 :   for (idx=0, s=elems; idx < npkey; idx++)
    1078             :     {
    1079           0 :       *p++ = '(';
    1080           0 :       *p++ = *s++;
    1081           0 :       p = stpcpy (p, " %m)");
    1082           0 :       assert (argidx < DIM (args));
    1083           0 :       args[argidx++] = &array[idx];
    1084             :     }
    1085           0 :   *p++ = ')';
    1086           0 :   if (uri)
    1087             :     {
    1088           0 :       p = stpcpy (p, "(uri %b)");
    1089           0 :       assert (argidx+1 < DIM (args));
    1090           0 :       args[argidx++] = (void *)&uri_length;
    1091           0 :       args[argidx++] = (void *)&uri;
    1092             :     }
    1093           0 :   if (comment)
    1094             :     {
    1095           0 :       p = stpcpy (p, "(comment %b)");
    1096           0 :       assert (argidx+1 < DIM (args));
    1097           0 :       args[argidx++] = (void *)&comment_length;
    1098           0 :       args[argidx++] = (void*)&comment;
    1099             :     }
    1100           0 :   *p++ = ')';
    1101           0 :   *p = 0;
    1102           0 :   assert (argidx < DIM (args));
    1103           0 :   args[argidx] = NULL;
    1104             : 
    1105           0 :   err = gcry_sexp_build_array (&list, NULL, format, args);
    1106           0 :   xfree (format);
    1107           0 :   for (i=0; array[i]; i++)
    1108           0 :     gcry_mpi_release (array[i]);
    1109           0 :   gcry_sexp_release (curve);
    1110           0 :   gcry_sexp_release (flags);
    1111           0 :   gcry_sexp_release (uri_sexp);
    1112           0 :   gcry_sexp_release (comment_sexp);
    1113             : 
    1114           0 :   if (!err)
    1115           0 :     *result = list;
    1116           0 :   return err;
    1117             : }
    1118             : 
    1119             : 
    1120             : 
    1121             : /* Check whether the the secret key identified by GRIP is available.
    1122             :    Returns 0 is the key is available.  */
    1123             : int
    1124         944 : agent_key_available (const unsigned char *grip)
    1125             : {
    1126             :   int result;
    1127             :   char *fname;
    1128             :   char hexgrip[40+4+1];
    1129             : 
    1130         944 :   bin2hex (grip, 20, hexgrip);
    1131         944 :   strcpy (hexgrip+40, ".key");
    1132             : 
    1133         944 :   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
    1134         944 :   result = !access (fname, R_OK)? 0 : -1;
    1135         944 :   xfree (fname);
    1136         944 :   return result;
    1137             : }
    1138             : 
    1139             : 
    1140             : 
    1141             : /* Return the information about the secret key specified by the binary
    1142             :    keygrip GRIP.  If the key is a shadowed one the shadow information
    1143             :    will be stored at the address R_SHADOW_INFO as an allocated
    1144             :    S-expression.  */
    1145             : gpg_error_t
    1146           0 : agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
    1147             :                           int *r_keytype, unsigned char **r_shadow_info)
    1148             : {
    1149             :   gpg_error_t err;
    1150             :   unsigned char *buf;
    1151             :   size_t len;
    1152             :   int keytype;
    1153             : 
    1154             :   (void)ctrl;
    1155             : 
    1156           0 :   if (r_keytype)
    1157           0 :     *r_keytype = PRIVATE_KEY_UNKNOWN;
    1158           0 :   if (r_shadow_info)
    1159           0 :     *r_shadow_info = NULL;
    1160             : 
    1161             :   {
    1162             :     gcry_sexp_t sexp;
    1163             : 
    1164           0 :     err = read_key_file (grip, &sexp);
    1165           0 :     if (err)
    1166             :       {
    1167           0 :         if (gpg_err_code (err) == GPG_ERR_ENOENT)
    1168           0 :           return gpg_error (GPG_ERR_NOT_FOUND);
    1169             :         else
    1170           0 :           return err;
    1171             :       }
    1172           0 :     err = make_canon_sexp (sexp, &buf, &len);
    1173           0 :     gcry_sexp_release (sexp);
    1174           0 :     if (err)
    1175           0 :       return err;
    1176             :   }
    1177             : 
    1178           0 :   keytype = agent_private_key_type (buf);
    1179           0 :   switch (keytype)
    1180             :     {
    1181             :     case PRIVATE_KEY_CLEAR:
    1182             :     case PRIVATE_KEY_OPENPGP_NONE:
    1183           0 :       break;
    1184             :     case PRIVATE_KEY_PROTECTED:
    1185             :       /* If we ever require it we could retrieve the comment fields
    1186             :          from such a key. */
    1187           0 :       break;
    1188             :     case PRIVATE_KEY_SHADOWED:
    1189           0 :       if (r_shadow_info)
    1190             :         {
    1191             :           const unsigned char *s;
    1192             :           size_t n;
    1193             : 
    1194           0 :           err = agent_get_shadow_info (buf, &s);
    1195           0 :           if (!err)
    1196             :             {
    1197           0 :               n = gcry_sexp_canon_len (s, 0, NULL, NULL);
    1198           0 :               assert (n);
    1199           0 :               *r_shadow_info = xtrymalloc (n);
    1200           0 :               if (!*r_shadow_info)
    1201           0 :                 err = gpg_error_from_syserror ();
    1202             :               else
    1203           0 :                 memcpy (*r_shadow_info, s, n);
    1204             :             }
    1205             :         }
    1206           0 :       break;
    1207             :     default:
    1208           0 :       err = gpg_error (GPG_ERR_BAD_SECKEY);
    1209           0 :       break;
    1210             :     }
    1211             : 
    1212           0 :   if (!err && r_keytype)
    1213           0 :     *r_keytype = keytype;
    1214             : 
    1215           0 :   xfree (buf);
    1216           0 :   return err;
    1217             : }
    1218             : 
    1219             : 
    1220             : 
    1221             : /* Delete the key with GRIP from the disk after having asked for
    1222             :    confirmation using DESC_TEXT.  If FORCE is set the fucntion won't
    1223             :    require a confirmation via Pinentry or warns if the key is also
    1224             :    used by ssh.
    1225             : 
    1226             :    Common error codes are:
    1227             :      GPG_ERR_NO_SECKEY
    1228             :      GPG_ERR_KEY_ON_CARD
    1229             :      GPG_ERR_NOT_CONFIRMED
    1230             : */
    1231             : gpg_error_t
    1232           0 : agent_delete_key (ctrl_t ctrl, const char *desc_text,
    1233             :                   const unsigned char *grip, int force)
    1234             : {
    1235             :   gpg_error_t err;
    1236           0 :   gcry_sexp_t s_skey = NULL;
    1237           0 :   unsigned char *buf = NULL;
    1238             :   size_t len;
    1239           0 :   char *desc_text_final = NULL;
    1240           0 :   char *comment = NULL;
    1241           0 :   ssh_control_file_t cf = NULL;
    1242             :   char hexgrip[40+4+1];
    1243           0 :   char *default_desc = NULL;
    1244             : 
    1245           0 :   err = read_key_file (grip, &s_skey);
    1246           0 :   if (gpg_err_code (err) == GPG_ERR_ENOENT)
    1247           0 :     err = gpg_error (GPG_ERR_NO_SECKEY);
    1248           0 :   if (err)
    1249           0 :     goto leave;
    1250             : 
    1251           0 :   err = make_canon_sexp (s_skey, &buf, &len);
    1252           0 :   if (err)
    1253           0 :     goto leave;
    1254             : 
    1255           0 :   switch (agent_private_key_type (buf))
    1256             :     {
    1257             :     case PRIVATE_KEY_CLEAR:
    1258             :     case PRIVATE_KEY_OPENPGP_NONE:
    1259             :     case PRIVATE_KEY_PROTECTED:
    1260           0 :       bin2hex (grip, 20, hexgrip);
    1261           0 :       if (!force)
    1262             :         {
    1263           0 :           if (!desc_text)
    1264             :             {
    1265           0 :               default_desc = xtryasprintf
    1266             :           (L_("Do you really want to delete the key identified by keygrip%%0A"
    1267             :               "  %s%%0A  %%C%%0A?"), hexgrip);
    1268           0 :               desc_text = default_desc;
    1269             :             }
    1270             : 
    1271             :           /* Note, that we will take the comment as a C string for
    1272             :              display purposes; i.e. all stuff beyond a Nul character is
    1273             :              ignored.  */
    1274             :           {
    1275             :             gcry_sexp_t comment_sexp;
    1276             : 
    1277           0 :             comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
    1278           0 :             if (comment_sexp)
    1279           0 :               comment = gcry_sexp_nth_string (comment_sexp, 1);
    1280           0 :             gcry_sexp_release (comment_sexp);
    1281             :           }
    1282             : 
    1283           0 :           if (desc_text)
    1284           0 :             err = modify_description (desc_text, comment? comment:"", s_skey,
    1285             :                                       &desc_text_final);
    1286           0 :           if (err)
    1287           0 :             goto leave;
    1288             : 
    1289           0 :           err = agent_get_confirmation (ctrl, desc_text_final,
    1290             :                                         L_("Delete key"), L_("No"), 0);
    1291           0 :           if (err)
    1292           0 :             goto leave;
    1293             : 
    1294           0 :           cf = ssh_open_control_file ();
    1295           0 :           if (cf)
    1296             :             {
    1297           0 :               if (!ssh_search_control_file (cf, hexgrip, NULL, NULL, NULL))
    1298             :                 {
    1299           0 :                   err = agent_get_confirmation
    1300             :                     (ctrl,
    1301             :                      L_("Warning: This key is also listed for use with SSH!\n"
    1302             :                         "Deleting the key might remove your ability to "
    1303             :                         "access remote machines."),
    1304             :                      L_("Delete key"), L_("No"), 0);
    1305           0 :                   if (err)
    1306           0 :                     goto leave;
    1307             :                 }
    1308             :             }
    1309             :         }
    1310           0 :       err = remove_key_file (grip);
    1311           0 :       break;
    1312             : 
    1313             :     case PRIVATE_KEY_SHADOWED:
    1314           0 :       err = gpg_error (GPG_ERR_KEY_ON_CARD);
    1315           0 :       break;
    1316             : 
    1317             :     default:
    1318           0 :       log_error ("invalid private key format\n");
    1319           0 :       err = gpg_error (GPG_ERR_BAD_SECKEY);
    1320           0 :       break;
    1321             :     }
    1322             : 
    1323             :  leave:
    1324           0 :   ssh_close_control_file (cf);
    1325           0 :   gcry_free (comment);
    1326           0 :   xfree (desc_text_final);
    1327           0 :   xfree (default_desc);
    1328           0 :   xfree (buf);
    1329           0 :   gcry_sexp_release (s_skey);
    1330           0 :   return err;
    1331             : }

Generated by: LCOV version 1.11