* AUTHORS: Copied from 1.4 and edited to refelct the changes in
[gnupg.git] / agent / findkey.c
1 /* findkey.c - locate the secret key
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
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
33 #include "agent.h"
34
35 /* Helper to pass data to the check callback of the unprotect function. */
36 struct try_unprotect_arg_s {
37   const unsigned char *protected_key;
38   unsigned char *unprotected_key;
39 };
40
41
42
43 int
44 agent_write_private_key (const unsigned char *grip,
45                          const void *buffer, size_t length, int force)
46 {
47   int i;
48   char *fname;
49   FILE *fp;
50   char hexgrip[40+4+1];
51   
52   for (i=0; i < 20; i++)
53     sprintf (hexgrip+2*i, "%02X", grip[i]);
54   strcpy (hexgrip+40, ".key");
55
56   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
57   if (force)
58     fp = fopen (fname, "wb");
59   else
60     {
61       int fd;
62
63       if (!access (fname, F_OK))
64       {
65         log_error ("secret key file `%s' already exists\n", fname);
66         xfree (fname);
67         return gpg_error (GPG_ERR_GENERAL);
68       }
69
70       /* We would like to create FNAME but only if it does not already
71          exist.  We cannot make this guarantee just using POSIX (GNU
72          provides the "x" opentype for fopen, however, this is not
73          portable).  Thus, we use the more flexible open function and
74          then use fdopen to obtain a stream.
75
76          The mode parameter to open is what fopen uses.  It will be
77          combined with the process' umask automatically.  */
78       fd = open (fname, O_CREAT | O_EXCL | O_RDWR,
79                  S_IRUSR | S_IWUSR 
80 #ifndef HAVE_W32_SYSTEM
81                  | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
82 #endif
83                  );
84       if (fd < 0)
85         fp = 0;
86       else
87         {
88           fp = fdopen (fd, "wb");
89           if (!fp)
90             { 
91               int save_e = errno;
92               close (fd);
93               errno = save_e;
94             }
95         }
96     }
97
98   if (!fp) 
99     { 
100       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
101       log_error ("can't create `%s': %s\n", fname, strerror (errno));
102       xfree (fname);
103       return tmperr;
104     }
105
106   if (fwrite (buffer, length, 1, fp) != 1)
107     {
108       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
109       log_error ("error writing `%s': %s\n", fname, strerror (errno));
110       fclose (fp);
111       remove (fname);
112       xfree (fname);
113       return tmperr;
114     }
115   if ( fclose (fp) )
116     {
117       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
118       log_error ("error closing `%s': %s\n", fname, strerror (errno));
119       remove (fname);
120       xfree (fname);
121       return tmperr;
122     }
123
124   xfree (fname);
125   return 0;
126 }
127
128
129 /* Callback function to try the unprotection from the passpharse query
130    code. */
131 static int
132 try_unprotect_cb (struct pin_entry_info_s *pi)
133 {
134   struct try_unprotect_arg_s *arg = pi->check_cb_arg;
135   size_t dummy;
136
137   assert (!arg->unprotected_key);
138   return agent_unprotect (arg->protected_key, pi->pin,
139                           &arg->unprotected_key, &dummy);
140 }
141
142
143 /* Modify a Key description, replacing certain special format
144    characters.  List of currently supported replacements:
145
146    %% - Replaced by a single %
147    %c - Replaced by the content of COMMENT.
148
149    The functions returns 0 on success or an error code.  On success a
150    newly allocated string is stored at the address of RESULT.
151  */
152 static gpg_error_t
153 modify_description (const char *in, const char *comment, char **result)
154 {
155   size_t comment_length;
156   size_t in_len;
157   size_t out_len;
158   char *out;
159   size_t i;
160   int special, pass;
161
162   comment_length = strlen (comment);
163   in_len  = strlen (in);
164
165   /* First pass calculates the length, second pass does the actual
166      copying.  */
167   out = NULL;
168   out_len = 0;
169   for (pass=0; pass < 2; pass++)
170     {
171       special = 0;
172       for (i = 0; i < in_len; i++)
173         {
174           if (in[i] == '%')
175             special = 1;
176           else if (special)
177             {
178               special = 0;
179               switch (in[i])
180                 {
181                 case '%':
182                   out_len++;
183                   if (out)
184                     *out++ = '%';
185                   break;
186
187                 case 'c': /* Comment.  */
188                   out_len += comment_length;
189                   if (out && comment_length)
190                     {
191                       memcpy (out, comment, comment_length);
192                       out += comment_length;
193                     }
194                   break;
195
196                 default: /* Invalid special sequences are ignored.  */
197                   break;
198                 }
199             }
200           else
201             {
202               out_len++;
203               if (out)
204                 *out++ = in[i];
205             }
206         }
207       
208       if (!pass)
209         {
210           *result = out = xtrymalloc (out_len + 1);
211           if (!out)
212             return gpg_error_from_errno (errno);
213         }
214     }
215
216   *out = 0;
217   assert (*result + out_len == out);
218   return 0;
219 }
220
221   
222
223 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
224    should be the hex encoded keygrip of that key to be used with the
225    caching mechanism. DESC_TEXT may be set to override the default
226    description used for the pinentry. */
227 static int
228 unprotect (CTRL ctrl, const char *desc_text,
229            unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
230 {
231   struct pin_entry_info_s *pi;
232   struct try_unprotect_arg_s arg;
233   int rc, i;
234   unsigned char *result;
235   size_t resultlen;
236   char hexgrip[40+1];
237   
238   for (i=0; i < 20; i++)
239     sprintf (hexgrip+2*i, "%02X", grip[i]);
240   hexgrip[40] = 0;
241
242   /* First try to get it from the cache - if there is none or we can't
243      unprotect it, we fall back to ask the user */
244   if (!ignore_cache)
245     {
246       void *cache_marker;
247       const char *pw = agent_get_cache (hexgrip, &cache_marker);
248       if (pw)
249         {
250           rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
251           agent_unlock_cache_entry (&cache_marker);
252           if (!rc)
253             {
254               xfree (*keybuf);
255               *keybuf = result;
256               return 0;
257             }
258           rc  = 0;
259         }
260     }
261   
262   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
263   pi->max_length = 100;
264   pi->min_digits = 0;  /* we want a real passphrase */
265   pi->max_digits = 8;
266   pi->max_tries = 3;
267   pi->check_cb = try_unprotect_cb;
268   arg.protected_key = *keybuf;
269   arg.unprotected_key = NULL;
270   pi->check_cb_arg = &arg;
271
272   rc = agent_askpin (ctrl, desc_text, NULL, pi);
273   if (!rc)
274     {
275       assert (arg.unprotected_key);
276       agent_put_cache (hexgrip, pi->pin, 0);
277       xfree (*keybuf);
278       *keybuf = arg.unprotected_key;
279     }
280   xfree (pi);
281   return rc;
282 }
283
284
285
286 /* Return the secret key as an S-Exp in RESULT after locating it using
287    the grip.  Returns NULL in RESULT if the operation should be
288    diverted to a token; SHADOW_INFO will point then to an allocated
289    S-Expression with the shadow_info part from the file.  With
290    IGNORE_CACHE passed as true the passphrase is not taken from the
291    cache.  DESC_TEXT may be set to present a custom description for the
292    pinentry. */
293 gpg_error_t
294 agent_key_from_file (CTRL ctrl, const char *desc_text,
295                      const unsigned char *grip, unsigned char **shadow_info,
296                      int ignore_cache, gcry_sexp_t *result)
297 {
298   int i, rc;
299   char *fname;
300   FILE *fp;
301   struct stat st;
302   unsigned char *buf;
303   size_t len, buflen, erroff;
304   gcry_sexp_t s_skey;
305   char hexgrip[40+4+1];
306   int got_shadow_info = 0;
307   
308   *result = NULL;
309   if (shadow_info)
310       *shadow_info = NULL;
311
312   for (i=0; i < 20; i++)
313     sprintf (hexgrip+2*i, "%02X", grip[i]);
314   strcpy (hexgrip+40, ".key");
315
316   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
317   fp = fopen (fname, "rb");
318   if (!fp)
319     {
320       rc = gpg_error_from_errno (errno);
321       log_error ("can't open `%s': %s\n", fname, strerror (errno));
322       xfree (fname);
323       return rc;
324     }
325   
326   if (fstat (fileno(fp), &st))
327     {
328       rc = gpg_error_from_errno (errno);
329       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
330       xfree (fname);
331       fclose (fp);
332       return rc;
333     }
334
335   buflen = st.st_size;
336   buf = xmalloc (buflen+1);
337   if (fread (buf, buflen, 1, fp) != 1)
338     {
339       rc = gpg_error_from_errno (errno);
340       log_error ("error reading `%s': %s\n", fname, strerror (errno));
341       xfree (fname);
342       fclose (fp);
343       xfree (buf);
344       return rc;
345     }
346
347   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
348   xfree (fname);
349   fclose (fp);
350   xfree (buf);
351   if (rc)
352     {
353       log_error ("failed to build S-Exp (off=%u): %s\n",
354                  (unsigned int)erroff, gpg_strerror (rc));
355       return rc;
356     }
357   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
358   assert (len);
359   buf = xtrymalloc (len);
360   if (!buf)
361     {
362       rc = out_of_core ();
363       gcry_sexp_release (s_skey);
364       return rc;
365     }
366   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
367   assert (len);
368   gcry_sexp_release (s_skey);
369
370   switch (agent_private_key_type (buf))
371     {
372     case PRIVATE_KEY_CLEAR:
373       break; /* no unprotection needed */
374     case PRIVATE_KEY_PROTECTED:
375       {
376         gcry_sexp_t comment_sexp;
377         size_t comment_length;
378         char *desc_text_final;
379         const char *comment = NULL;
380
381         /* Note, that we will take the comment as a C styring for
382            display purposes; i.e. all stuff beyond a Nul character is
383            ignored.  */
384         comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
385         if (comment_sexp)
386           comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
387         if (!comment)
388           {
389             comment = "";
390             comment_length = 0;
391           }
392
393         desc_text_final = NULL;
394         if (desc_text)
395           {
396             if (comment[comment_length])
397               {
398                 /* Not a C-string; create one.  We might here allocate
399                    more than actually displayed but well, that
400                    shouldn't be a problem.  */
401                 char *tmp = xtrymalloc (comment_length+1);
402                 if (!tmp)
403                   rc = gpg_error_from_errno (errno);
404                 else
405                   {
406                     memcpy (tmp, comment, comment_length);
407                     tmp[comment_length] = 0;
408                     rc = modify_description (desc_text, tmp, &desc_text_final);
409                     xfree (tmp);
410                   }
411               }
412             else
413               rc = modify_description (desc_text, comment, &desc_text_final);
414           }
415
416         if (!rc)
417           {
418             rc = unprotect (ctrl, desc_text_final, &buf, grip, ignore_cache);
419             if (rc)
420               log_error ("failed to unprotect the secret key: %s\n",
421                          gpg_strerror (rc));
422           }
423         
424         gcry_sexp_release (comment_sexp);
425         xfree (desc_text_final);
426       }
427       break;
428     case PRIVATE_KEY_SHADOWED:
429       if (shadow_info)
430         {
431           const unsigned char *s;
432           size_t n;
433
434           rc = agent_get_shadow_info (buf, &s);
435           if (!rc)
436             {
437               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
438               assert (n);
439               *shadow_info = xtrymalloc (n);
440               if (!*shadow_info)
441                 rc = out_of_core ();
442               else
443                 {
444                   memcpy (*shadow_info, s, n);
445                   rc = 0;
446                   got_shadow_info = 1;
447                 }
448             }
449           if (rc)
450             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
451         }
452       else
453         rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
454       break;
455     default:
456       log_error ("invalid private key format\n");
457       rc = gpg_error (GPG_ERR_BAD_SECKEY);
458       break;
459     }
460   if (rc || got_shadow_info)
461     {
462       xfree (buf);
463       return rc;
464     }
465
466   buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
467   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
468   wipememory (buf, buflen);
469   xfree (buf);
470   if (rc)
471     {
472       log_error ("failed to build S-Exp (off=%u): %s\n",
473                  (unsigned int)erroff, gpg_strerror (rc));
474       return rc;
475     }
476
477   *result = s_skey;
478   return 0;
479 }
480
481 /* Return the secret key as an S-Exp after locating it using the grip.
482    Returns NULL if key is not available. 0 = key is available */
483 int
484 agent_key_available (const unsigned char *grip)
485 {
486   int i;
487   char *fname;
488   char hexgrip[40+4+1];
489   
490   for (i=0; i < 20; i++)
491     sprintf (hexgrip+2*i, "%02X", grip[i]);
492   strcpy (hexgrip+40, ".key");
493
494   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
495   i = !access (fname, R_OK)? 0 : -1;
496   xfree (fname);
497   return i;
498 }
499
500
501