Imported Upstream version 2.0.19
[platform/upstream/gpg2.git] / agent / findkey.c
1 /* findkey.c - Locate the secret key
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
3  *               2010, 2011 Free Software Foundation, Inc.
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 <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <fcntl.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <assert.h>
32 #include <pth.h> /* (we use pth_sleep) */
33
34 #include "agent.h"
35 #include "i18n.h"
36 #include "../common/ssh-utils.h"
37
38 #ifndef O_BINARY
39 #define O_BINARY 0
40 #endif
41
42 /* Helper to pass data to the check callback of the unprotect function. */
43 struct try_unprotect_arg_s
44 {
45   ctrl_t ctrl;
46   const unsigned char *protected_key;
47   unsigned char *unprotected_key;
48   int change_required; /* Set by the callback to indicate that the
49                           user should chnage the passphrase.  */
50 };
51
52
53 /* Write an S-expression formatted key to our key storage.  With FORCE
54    passed as true an existing key with the given GRIP will get
55    overwritten.  */
56 int
57 agent_write_private_key (const unsigned char *grip,
58                          const void *buffer, size_t length, int force)
59 {
60   char *fname;
61   FILE *fp;
62   char hexgrip[40+4+1];
63   int fd;
64
65   bin2hex (grip, 20, hexgrip);
66   strcpy (hexgrip+40, ".key");
67
68   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
69
70   if (!force && !access (fname, F_OK))
71     {
72       log_error ("secret key file `%s' already exists\n", fname);
73       xfree (fname);
74       return gpg_error (GPG_ERR_GENERAL);
75     }
76
77   /* In FORCE mode we would like to create FNAME but only if it does
78      not already exist.  We cannot make this guarantee just using
79      POSIX (GNU provides the "x" opentype for fopen, however, this is
80      not portable).  Thus, we use the more flexible open function and
81      then use fdopen to obtain a stream. */
82   fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY | O_BINARY)
83                          : (O_CREAT | O_EXCL | O_WRONLY | O_BINARY),
84              S_IRUSR | S_IWUSR
85 #ifndef HAVE_W32_SYSTEM
86                  | S_IRGRP
87 #endif
88                  );
89   if (fd < 0)
90     fp = NULL;
91   else
92     {
93       fp = fdopen (fd, "wb");
94       if (!fp)
95         {
96           int save_e = errno;
97           close (fd);
98           errno = save_e;
99         }
100     }
101
102   if (!fp)
103     {
104       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
105       log_error ("can't create `%s': %s\n", fname, strerror (errno));
106       xfree (fname);
107       return tmperr;
108     }
109
110   if (fwrite (buffer, length, 1, fp) != 1)
111     {
112       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
113       log_error ("error writing `%s': %s\n", fname, strerror (errno));
114       fclose (fp);
115       remove (fname);
116       xfree (fname);
117       return tmperr;
118     }
119   if ( fclose (fp) )
120     {
121       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
122       log_error ("error closing `%s': %s\n", fname, strerror (errno));
123       remove (fname);
124       xfree (fname);
125       return tmperr;
126     }
127   bump_key_eventcounter ();
128   xfree (fname);
129   return 0;
130 }
131
132
133 /* Callback function to try the unprotection from the passpharse query
134    code. */
135 static int
136 try_unprotect_cb (struct pin_entry_info_s *pi)
137 {
138   struct try_unprotect_arg_s *arg = pi->check_cb_arg;
139   size_t dummy;
140   gpg_error_t err;
141   gnupg_isotime_t now, protected_at, tmptime;
142   char *desc = NULL;
143
144   assert (!arg->unprotected_key);
145
146   arg->change_required = 0;
147   err = agent_unprotect (arg->protected_key, pi->pin, protected_at,
148                          &arg->unprotected_key, &dummy);
149   if (err)
150     return err;
151   if (!opt.max_passphrase_days || arg->ctrl->in_passwd)
152     return 0;  /* No regular passphrase change required.  */
153
154   if (!*protected_at)
155     {
156       /* No protection date known - must force passphrase change.  */
157       desc = xtrystrdup (_("Note: This passphrase has never been changed.%0A"
158                            "Please change it now."));
159       if (!desc)
160         return gpg_error_from_syserror ();
161     }
162   else
163     {
164       gnupg_get_isotime (now);
165       gnupg_copy_time (tmptime, protected_at);
166       err = add_days_to_isotime (tmptime, opt.max_passphrase_days);
167       if (err)
168         return err;
169       if (strcmp (now, tmptime) > 0 )
170         {
171           /* Passphrase "expired".  */
172           desc = xtryasprintf
173             (_("This passphrase has not been changed%%0A"
174                "since %.4s-%.2s-%.2s.  Please change it now."),
175              protected_at, protected_at+4, protected_at+6);
176           if (!desc)
177             return gpg_error_from_syserror ();
178         }
179     }
180
181   if (desc)
182     {
183       /* Change required.  */
184       if (opt.enforce_passphrase_constraints)
185         {
186           err = agent_get_confirmation (arg->ctrl, desc,
187                                         _("Change passphrase"), NULL, 0);
188           if (!err)
189             arg->change_required = 1;
190         }
191       else
192         {
193           err = agent_get_confirmation (arg->ctrl, desc,
194                                         _("Change passphrase"),
195                                         _("I'll change it later"), 0);
196           if (!err)
197             arg->change_required = 1;
198           else if (gpg_err_code (err) == GPG_ERR_CANCELED)
199             err = 0;
200         }
201       xfree (desc);
202     }
203
204   return 0;
205 }
206
207
208 /* Modify a Key description, replacing certain special format
209    characters.  List of currently supported replacements:
210
211    %% - Replaced by a single %
212    %c - Replaced by the content of COMMENT.
213    %F - Replaced by an ssh style fingerprint computed from KEY.
214
215    The functions returns 0 on success or an error code.  On success a
216    newly allocated string is stored at the address of RESULT.
217  */
218 static gpg_error_t
219 modify_description (const char *in, const char *comment, const gcry_sexp_t key,
220                     char **result)
221 {
222   size_t comment_length;
223   size_t in_len;
224   size_t out_len;
225   char *out;
226   size_t i;
227   int special, pass;
228   char *ssh_fpr = NULL;
229
230   comment_length = strlen (comment);
231   in_len  = strlen (in);
232
233   /* First pass calculates the length, second pass does the actual
234      copying.  */
235   out = NULL;
236   out_len = 0;
237   for (pass=0; pass < 2; pass++)
238     {
239       special = 0;
240       for (i = 0; i < in_len; i++)
241         {
242           if (special)
243             {
244               special = 0;
245               switch (in[i])
246                 {
247                 case '%':
248                   if (out)
249                     *out++ = '%';
250                   else
251                     out_len++;
252                   break;
253
254                 case 'c': /* Comment.  */
255                   if (out)
256                     {
257                       memcpy (out, comment, comment_length);
258                       out += comment_length;
259                     }
260                   else
261                     out_len += comment_length;
262                   break;
263
264                 case 'F': /* SSH style fingerprint.  */
265                   if (!ssh_fpr && key)
266                     ssh_get_fingerprint_string (key, &ssh_fpr);
267                   if (ssh_fpr)
268                     {
269                       if (out)
270                         out = stpcpy (out, ssh_fpr);
271                       else
272                         out_len += strlen (ssh_fpr);
273                     }
274                   break;
275
276                 default: /* Invalid special sequences are kept as they are. */
277                   if (out)
278                     {
279                       *out++ = '%';
280                       *out++ = in[i];
281                     }
282                   else
283                     out_len+=2;
284                   break;
285                 }
286             }
287           else if (in[i] == '%')
288             special = 1;
289           else
290             {
291               if (out)
292                 *out++ = in[i];
293               else
294                 out_len++;
295             }
296         }
297
298       if (!pass)
299         {
300           *result = out = xtrymalloc (out_len + 1);
301           if (!out)
302             {
303               xfree (ssh_fpr);
304               return gpg_error_from_syserror ();
305             }
306         }
307     }
308
309   *out = 0;
310   assert (*result + out_len == out);
311   xfree (ssh_fpr);
312   return 0;
313 }
314
315
316
317 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
318    should be the hex encoded keygrip of that key to be used with the
319    caching mechanism. DESC_TEXT may be set to override the default
320    description used for the pinentry.  If LOOKUP_TTL is given this
321    function is used to lookup the default ttl. */
322 static int
323 unprotect (ctrl_t ctrl, const char *desc_text,
324            unsigned char **keybuf, const unsigned char *grip,
325            cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
326 {
327   struct pin_entry_info_s *pi;
328   struct try_unprotect_arg_s arg;
329   int rc;
330   unsigned char *result;
331   size_t resultlen;
332   char hexgrip[40+1];
333
334   bin2hex (grip, 20, hexgrip);
335
336   /* First try to get it from the cache - if there is none or we can't
337      unprotect it, we fall back to ask the user */
338   if (cache_mode != CACHE_MODE_IGNORE)
339     {
340       void *cache_marker;
341       const char *pw;
342
343     retry:
344       pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
345       if (pw)
346         {
347           rc = agent_unprotect (*keybuf, pw, NULL, &result, &resultlen);
348           agent_unlock_cache_entry (&cache_marker);
349           if (!rc)
350             {
351               xfree (*keybuf);
352               *keybuf = result;
353               return 0;
354             }
355           rc  = 0;
356         }
357
358       /* If the pinentry is currently in use, we wait up to 60 seconds
359          for it to close and check the cache again.  This solves a common
360          situation where several requests for unprotecting a key have
361          been made but the user is still entering the passphrase for
362          the first request.  Because all requests to agent_askpin are
363          serialized they would then pop up one after the other to
364          request the passphrase - despite that the user has already
365          entered it and is then available in the cache.  This
366          implementation is not race free but in the worst case the
367          user has to enter the passphrase only once more. */
368       if (pinentry_active_p (ctrl, 0))
369         {
370           /* Active - wait */
371           if (!pinentry_active_p (ctrl, 60))
372             {
373               /* We need to give the other thread a chance to actually put
374                  it into the cache. */
375               pth_sleep (1);
376               goto retry;
377             }
378           /* Timeout - better call pinentry now the plain way. */
379         }
380     }
381
382   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
383   if (!pi)
384     return gpg_error_from_syserror ();
385   pi->max_length = 100;
386   pi->min_digits = 0;  /* we want a real passphrase */
387   pi->max_digits = 16;
388   pi->max_tries = 3;
389   pi->check_cb = try_unprotect_cb;
390   arg.ctrl = ctrl;
391   arg.protected_key = *keybuf;
392   arg.unprotected_key = NULL;
393   arg.change_required = 0;
394   pi->check_cb_arg = &arg;
395
396   rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
397   if (!rc)
398     {
399       assert (arg.unprotected_key);
400       if (arg.change_required)
401         {
402           size_t canlen, erroff;
403           gcry_sexp_t s_skey;
404
405           assert (arg.unprotected_key);
406           canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
407           rc = gcry_sexp_sscan (&s_skey, &erroff,
408                                 (char*)arg.unprotected_key, canlen);
409           if (rc)
410             {
411               log_error ("failed to build S-Exp (off=%u): %s\n",
412                          (unsigned int)erroff, gpg_strerror (rc));
413               wipememory (arg.unprotected_key, canlen);
414               xfree (arg.unprotected_key);
415               xfree (pi);
416               return rc;
417             }
418           rc = agent_protect_and_store (ctrl, s_skey);
419           gcry_sexp_release (s_skey);
420           if (rc)
421             {
422               log_error ("changing the passphrase failed: %s\n",
423                          gpg_strerror (rc));
424               wipememory (arg.unprotected_key, canlen);
425               xfree (arg.unprotected_key);
426               xfree (pi);
427               return rc;
428             }
429         }
430       else
431         agent_put_cache (hexgrip, cache_mode, pi->pin,
432                          lookup_ttl? lookup_ttl (hexgrip) : 0);
433       xfree (*keybuf);
434       *keybuf = arg.unprotected_key;
435     }
436   xfree (pi);
437   return rc;
438 }
439
440
441 /* Read the key identified by GRIP from the private key directory and
442    return it as an gcrypt S-expression object in RESULT.  On failure
443    returns an error code and stores NULL at RESULT. */
444 static gpg_error_t
445 read_key_file (const unsigned char *grip, gcry_sexp_t *result)
446 {
447   int rc;
448   char *fname;
449   FILE *fp;
450   struct stat st;
451   unsigned char *buf;
452   size_t buflen, erroff;
453   gcry_sexp_t s_skey;
454   char hexgrip[40+4+1];
455
456   *result = NULL;
457
458   bin2hex (grip, 20, hexgrip);
459   strcpy (hexgrip+40, ".key");
460
461   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
462   fp = fopen (fname, "rb");
463   if (!fp)
464     {
465       rc = gpg_error_from_syserror ();
466       if (gpg_err_code (rc) != GPG_ERR_ENOENT)
467         log_error ("can't open `%s': %s\n", fname, strerror (errno));
468       xfree (fname);
469       return rc;
470     }
471
472   if (fstat (fileno(fp), &st))
473     {
474       rc = gpg_error_from_syserror ();
475       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
476       xfree (fname);
477       fclose (fp);
478       return rc;
479     }
480
481   buflen = st.st_size;
482   buf = xtrymalloc (buflen+1);
483   if (!buf || fread (buf, buflen, 1, fp) != 1)
484     {
485       rc = gpg_error_from_syserror ();
486       log_error ("error reading `%s': %s\n", fname, strerror (errno));
487       xfree (fname);
488       fclose (fp);
489       xfree (buf);
490       return rc;
491     }
492
493   /* Convert the file into a gcrypt S-expression object.  */
494   rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
495   xfree (fname);
496   fclose (fp);
497   xfree (buf);
498   if (rc)
499     {
500       log_error ("failed to build S-Exp (off=%u): %s\n",
501                  (unsigned int)erroff, gpg_strerror (rc));
502       return rc;
503     }
504   *result = s_skey;
505   return 0;
506 }
507
508
509 /* Return the secret key as an S-Exp in RESULT after locating it using
510    the GRIP.  Stores NULL at RESULT if the operation shall be diverted
511    to a token; in this case an allocated S-expression with the
512    shadow_info part from the file is stored at SHADOW_INFO.
513    CACHE_MODE defines now the cache shall be used.  DESC_TEXT may be
514    set to present a custom description for the pinentry.  LOOKUP_TTL
515    is an optional function to convey a TTL to the cache manager; we do
516    not simply pass the TTL value because the value is only needed if an
517    unprotect action was needed and looking up the TTL may have some
518    overhead (e.g. scanning the sshcontrol file). */
519 gpg_error_t
520 agent_key_from_file (ctrl_t ctrl, const char *desc_text,
521                      const unsigned char *grip, unsigned char **shadow_info,
522                      cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
523                      gcry_sexp_t *result)
524 {
525   int rc;
526   unsigned char *buf;
527   size_t len, buflen, erroff;
528   gcry_sexp_t s_skey;
529   int got_shadow_info = 0;
530
531   *result = NULL;
532   if (shadow_info)
533     *shadow_info = NULL;
534
535   rc = read_key_file (grip, &s_skey);
536   if (rc)
537     return rc;
538
539   /* For use with the protection functions we also need the key as an
540      canonical encoded S-expression in a buffer.  Create this buffer
541      now.  */
542   rc = make_canon_sexp (s_skey, &buf, &len);
543   if (rc)
544     return rc;
545
546   switch (agent_private_key_type (buf))
547     {
548     case PRIVATE_KEY_CLEAR:
549       break; /* no unprotection needed */
550     case PRIVATE_KEY_PROTECTED:
551       {
552         char *desc_text_final;
553         char *comment = NULL;
554
555         /* Note, that we will take the comment as a C string for
556            display purposes; i.e. all stuff beyond a Nul character is
557            ignored.  */
558         {
559           gcry_sexp_t comment_sexp;
560
561           comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
562           if (comment_sexp)
563             comment = gcry_sexp_nth_string (comment_sexp, 1);
564           gcry_sexp_release (comment_sexp);
565         }
566
567         desc_text_final = NULL;
568         if (desc_text)
569           rc = modify_description (desc_text, comment? comment:"", s_skey,
570                                    &desc_text_final);
571         gcry_free (comment);
572
573         if (!rc)
574           {
575             rc = unprotect (ctrl, desc_text_final, &buf, grip,
576                             cache_mode, lookup_ttl);
577             if (rc)
578               log_error ("failed to unprotect the secret key: %s\n",
579                          gpg_strerror (rc));
580           }
581
582         xfree (desc_text_final);
583       }
584       break;
585     case PRIVATE_KEY_SHADOWED:
586       if (shadow_info)
587         {
588           const unsigned char *s;
589           size_t n;
590
591           rc = agent_get_shadow_info (buf, &s);
592           if (!rc)
593             {
594               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
595               assert (n);
596               *shadow_info = xtrymalloc (n);
597               if (!*shadow_info)
598                 rc = out_of_core ();
599               else
600                 {
601                   memcpy (*shadow_info, s, n);
602                   rc = 0;
603                   got_shadow_info = 1;
604                 }
605             }
606           if (rc)
607             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
608         }
609       else
610         rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
611       break;
612     default:
613       log_error ("invalid private key format\n");
614       rc = gpg_error (GPG_ERR_BAD_SECKEY);
615       break;
616     }
617   gcry_sexp_release (s_skey);
618   s_skey = NULL;
619   if (rc || got_shadow_info)
620     {
621       xfree (buf);
622       return rc;
623     }
624
625   buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
626   rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
627   wipememory (buf, buflen);
628   xfree (buf);
629   if (rc)
630     {
631       log_error ("failed to build S-Exp (off=%u): %s\n",
632                  (unsigned int)erroff, gpg_strerror (rc));
633       return rc;
634     }
635
636   *result = s_skey;
637   return 0;
638 }
639
640
641 /* Return the key for the keygrip GRIP.  The result is stored at
642    RESULT.  This function extracts the key from the private key
643    database and returns it as an S-expression object as it is.  On
644    failure an error code is returned and NULL stored at RESULT. */
645 gpg_error_t
646 agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
647                          gcry_sexp_t *result)
648 {
649   gpg_error_t err;
650   gcry_sexp_t s_skey;
651
652   (void)ctrl;
653
654   *result = NULL;
655
656   err = read_key_file (grip, &s_skey);
657   if (!err)
658     *result = s_skey;
659   return err;
660 }
661
662
663 /* Return the public key for the keygrip GRIP.  The result is stored
664    at RESULT.  This function extracts the public key from the private
665    key database.  On failure an error code is returned and NULL stored
666    at RESULT. */
667 gpg_error_t
668 agent_public_key_from_file (ctrl_t ctrl,
669                             const unsigned char *grip,
670                             gcry_sexp_t *result)
671 {
672   int i, idx, rc;
673   gcry_sexp_t s_skey;
674   const char *algoname;
675   gcry_sexp_t uri_sexp, comment_sexp;
676   const char *uri, *comment;
677   size_t uri_length, comment_length;
678   char *format, *p;
679   void *args[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2
680                            for comment + end-of-list.  */
681   int argidx;
682   gcry_sexp_t list, l2;
683   const char *name;
684   const char *s;
685   size_t n;
686   const char *elems;
687   gcry_mpi_t *array;
688
689   (void)ctrl;
690
691   *result = NULL;
692
693   rc = read_key_file (grip, &s_skey);
694   if (rc)
695     return rc;
696
697   list = gcry_sexp_find_token (s_skey, "shadowed-private-key", 0 );
698   if (!list)
699     list = gcry_sexp_find_token (s_skey, "protected-private-key", 0 );
700   if (!list)
701     list = gcry_sexp_find_token (s_skey, "private-key", 0 );
702   if (!list)
703     {
704       log_error ("invalid private key format\n");
705       gcry_sexp_release (s_skey);
706       return gpg_error (GPG_ERR_BAD_SECKEY);
707     }
708
709   l2 = gcry_sexp_cadr (list);
710   gcry_sexp_release (list);
711   list = l2;
712   name = gcry_sexp_nth_data (list, 0, &n);
713   if (n==3 && !memcmp (name, "rsa", 3))
714     {
715       algoname = "rsa";
716       elems = "ne";
717     }
718   else if (n==3 && !memcmp (name, "dsa", 3))
719     {
720       algoname = "dsa";
721       elems = "pqgy";
722     }
723   else if (n==3 && !memcmp (name, "elg", 3))
724     {
725       algoname = "elg";
726       elems = "pgy";
727     }
728   else
729     {
730       log_error ("unknown private key algorithm\n");
731       gcry_sexp_release (list);
732       gcry_sexp_release (s_skey);
733       return gpg_error (GPG_ERR_BAD_SECKEY);
734     }
735
736   /* Allocate an array for the parameters and copy them out of the
737      secret key.   FIXME: We should have a generic copy function. */
738   array = xtrycalloc (strlen(elems) + 1, sizeof *array);
739   if (!array)
740     {
741       rc = gpg_error_from_syserror ();
742       gcry_sexp_release (list);
743       gcry_sexp_release (s_skey);
744       return rc;
745     }
746
747   for (idx=0, s=elems; *s; s++, idx++ )
748     {
749       l2 = gcry_sexp_find_token (list, s, 1);
750       if (!l2)
751         {
752           /* Required parameter not found.  */
753           for (i=0; i<idx; i++)
754             gcry_mpi_release (array[i]);
755           xfree (array);
756           gcry_sexp_release (list);
757           gcry_sexp_release (s_skey);
758           return gpg_error (GPG_ERR_BAD_SECKEY);
759         }
760       array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
761       gcry_sexp_release (l2);
762       if (!array[idx])
763         {
764           /* Required parameter is invalid. */
765           for (i=0; i<idx; i++)
766             gcry_mpi_release (array[i]);
767           xfree (array);
768           gcry_sexp_release (list);
769           gcry_sexp_release (s_skey);
770           return gpg_error (GPG_ERR_BAD_SECKEY);
771         }
772     }
773   gcry_sexp_release (list);
774   list = NULL;
775
776   uri = NULL;
777   uri_length = 0;
778   uri_sexp = gcry_sexp_find_token (s_skey, "uri", 0);
779   if (uri_sexp)
780     uri = gcry_sexp_nth_data (uri_sexp, 1, &uri_length);
781
782   comment = NULL;
783   comment_length = 0;
784   comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
785   if (comment_sexp)
786     comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
787
788   gcry_sexp_release (s_skey);
789   s_skey = NULL;
790
791
792   /* FIXME: The following thing is pretty ugly code; we should
793      investigate how to make it cleaner. Probably code to handle
794      canonical S-expressions in a memory buffer is better suioted for
795      such a task.  After all that is what we do in protect.c.  Neeed
796      to find common patterns and write a straightformward API to use
797      them.  */
798   assert (sizeof (size_t) <= sizeof (void*));
799
800   format = xtrymalloc (15+7*strlen (elems)+10+15+1+1);
801   if (!format)
802     {
803       rc = gpg_error_from_syserror ();
804       for (i=0; array[i]; i++)
805         gcry_mpi_release (array[i]);
806       xfree (array);
807       gcry_sexp_release (uri_sexp);
808       gcry_sexp_release (comment_sexp);
809       return rc;
810     }
811
812   argidx = 0;
813   p = stpcpy (stpcpy (format, "(public-key("), algoname);
814   for (idx=0, s=elems; *s; s++, idx++ )
815     {
816       *p++ = '(';
817       *p++ = *s;
818       p = stpcpy (p, " %m)");
819       assert (argidx < DIM (args));
820       args[argidx++] = &array[idx];
821     }
822   *p++ = ')';
823   if (uri)
824     {
825       p = stpcpy (p, "(uri %b)");
826       assert (argidx+1 < DIM (args));
827       args[argidx++] = (void *)uri_length;
828       args[argidx++] = (void *)uri;
829     }
830   if (comment)
831     {
832       p = stpcpy (p, "(comment %b)");
833       assert (argidx+1 < DIM (args));
834       args[argidx++] = (void *)comment_length;
835       args[argidx++] = (void*)comment;
836     }
837   *p++ = ')';
838   *p = 0;
839   assert (argidx < DIM (args));
840   args[argidx] = NULL;
841
842   rc = gcry_sexp_build_array (&list, NULL, format, args);
843   xfree (format);
844   for (i=0; array[i]; i++)
845     gcry_mpi_release (array[i]);
846   xfree (array);
847   gcry_sexp_release (uri_sexp);
848   gcry_sexp_release (comment_sexp);
849
850   if (!rc)
851     *result = list;
852   return rc;
853 }
854
855
856
857 /* Return the secret key as an S-Exp after locating it using the grip.
858    Returns NULL if key is not available. 0 = key is available */
859 int
860 agent_key_available (const unsigned char *grip)
861 {
862   int result;
863   char *fname;
864   char hexgrip[40+4+1];
865
866   bin2hex (grip, 20, hexgrip);
867   strcpy (hexgrip+40, ".key");
868
869   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
870   result = !access (fname, R_OK)? 0 : -1;
871   xfree (fname);
872   return result;
873 }
874
875
876
877 /* Return the information about the secret key specified by the binary
878    keygrip GRIP.  If the key is a shadowed one the shadow information
879    will be stored at the address R_SHADOW_INFO as an allocated
880    S-expression.  */
881 gpg_error_t
882 agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
883                           int *r_keytype, unsigned char **r_shadow_info)
884 {
885   gpg_error_t err;
886   unsigned char *buf;
887   size_t len;
888   int keytype;
889
890   (void)ctrl;
891
892   if (r_keytype)
893     *r_keytype = PRIVATE_KEY_UNKNOWN;
894   if (r_shadow_info)
895     *r_shadow_info = NULL;
896
897   {
898     gcry_sexp_t sexp;
899
900     err = read_key_file (grip, &sexp);
901     if (err)
902       {
903         if (gpg_err_code (err) == GPG_ERR_ENOENT)
904           return gpg_error (GPG_ERR_NOT_FOUND);
905         else
906           return err;
907       }
908     err = make_canon_sexp (sexp, &buf, &len);
909     gcry_sexp_release (sexp);
910     if (err)
911       return err;
912   }
913
914   keytype = agent_private_key_type (buf);
915   switch (keytype)
916     {
917     case PRIVATE_KEY_CLEAR:
918       break;
919     case PRIVATE_KEY_PROTECTED:
920       /* If we ever require it we could retrieve the comment fields
921          from such a key. */
922       break;
923     case PRIVATE_KEY_SHADOWED:
924       if (r_shadow_info)
925         {
926           const unsigned char *s;
927           size_t n;
928
929           err = agent_get_shadow_info (buf, &s);
930           if (!err)
931             {
932               n = gcry_sexp_canon_len (s, 0, NULL, NULL);
933               assert (n);
934               *r_shadow_info = xtrymalloc (n);
935               if (!*r_shadow_info)
936                 err = gpg_error_from_syserror ();
937               else
938                 memcpy (*r_shadow_info, s, n);
939             }
940         }
941       break;
942     default:
943       err = gpg_error (GPG_ERR_BAD_SECKEY);
944       break;
945     }
946
947   if (!err && r_keytype)
948     *r_keytype = keytype;
949
950   xfree (buf);
951   return err;
952 }