2005-01-26 Moritz Schulte <moritz@g10code.com>
[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    %% -> %
147    %c -> <COMMENT>. */
148 static int
149 modify_description (const char *description,
150                     const char *comment, size_t comment_length,
151                     char **description_modified)
152 {
153   size_t description_length;
154   size_t description_new_length;
155   gpg_error_t err;
156   char *description_new;
157   unsigned int i, j;
158   unsigned int special;
159
160   description_length  = strlen (description);
161   description_new_length = description_length;
162   description_new = NULL;
163
164   /* Calculate length.  */
165   special = 0;
166   for (i = 0; i < description_length; i++)
167     {
168       if (description[i] == '%')
169         special = 1;
170       else
171         {
172           if (special)
173             {
174               description_new_length -= 2;
175               switch (description[i])
176                 {
177                 case 'c':
178                   /* Comment.  */
179                   description_new_length += comment_length;
180                   break;
181                   
182                 case '%':
183                   description_new_length += 1;
184                   break;
185                 }
186               special = 0;
187             }
188         }
189     }
190
191   /* Allocate.  */
192   description_new = xtrymalloc (description_new_length + 1);
193   if (! description_new)
194     {
195       err = gpg_error_from_errno (errno);
196       goto out;
197     }
198
199   /* Fill.  */
200   for (i = j = 0; i < description_length; i++)
201     {
202       if (description[i] == '%')
203         special = 1;
204       else
205         {
206           if (special)
207             {
208               switch (description[i])
209                 {
210                 case 'c':
211                   /* Comment.  */
212                   if (comment)
213                     {
214                       strncpy (description_new + j, comment, comment_length);
215                       j += comment_length;
216                     }
217                   break;
218                   
219                 case '%':
220                   description_new[j] = '%';
221                   j++;
222                   break;
223                 }
224               special = 0;
225             }
226           else
227             {
228               description_new[j] = description[i];
229               j++;
230             }
231         }
232     }
233
234   description_new[j] = 0;
235   *description_modified = description_new;
236   err = 0;
237
238  out:
239
240   return err;
241 }
242
243   
244
245 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
246    should be the hex encoded keygrip of that key to be used with the
247    caching mechanism. DESC_TEXT may be set to override the default
248    description used for the pinentry. */
249 static int
250 unprotect (CTRL ctrl, const char *desc_text,
251            unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
252 {
253   struct pin_entry_info_s *pi;
254   struct try_unprotect_arg_s arg;
255   int rc, i;
256   unsigned char *result;
257   size_t resultlen;
258   char hexgrip[40+1];
259   
260   for (i=0; i < 20; i++)
261     sprintf (hexgrip+2*i, "%02X", grip[i]);
262   hexgrip[40] = 0;
263
264   /* First try to get it from the cache - if there is none or we can't
265      unprotect it, we fall back to ask the user */
266   if (!ignore_cache)
267     {
268       void *cache_marker;
269       const char *pw = agent_get_cache (hexgrip, &cache_marker);
270       if (pw)
271         {
272           rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
273           agent_unlock_cache_entry (&cache_marker);
274           if (!rc)
275             {
276               xfree (*keybuf);
277               *keybuf = result;
278               return 0;
279             }
280           rc  = 0;
281         }
282     }
283   
284   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
285   pi->max_length = 100;
286   pi->min_digits = 0;  /* we want a real passphrase */
287   pi->max_digits = 8;
288   pi->max_tries = 3;
289   pi->check_cb = try_unprotect_cb;
290   arg.protected_key = *keybuf;
291   arg.unprotected_key = NULL;
292   pi->check_cb_arg = &arg;
293
294   rc = agent_askpin (ctrl, desc_text, NULL, pi);
295   if (!rc)
296     {
297       assert (arg.unprotected_key);
298       agent_put_cache (hexgrip, pi->pin, 0);
299       xfree (*keybuf);
300       *keybuf = arg.unprotected_key;
301     }
302   xfree (pi);
303   return rc;
304 }
305
306
307
308 /* Return the secret key as an S-Exp in RESULT after locating it using
309    the grip.  Returns NULL in RESULT if the operation should be
310    diverted to a token; SHADOW_INFO will point then to an allocated
311    S-Expression with the shadow_info part from the file.  With
312    IGNORE_CACHE passed as true the passphrase is not taken from the
313    cache.  DESC_TEXT may be set to present a custom description for the
314    pinentry. */
315 gpg_error_t
316 agent_key_from_file (CTRL ctrl, const char *desc_text,
317                      const unsigned char *grip, unsigned char **shadow_info,
318                      int ignore_cache, gcry_sexp_t *result)
319 {
320   int i, rc;
321   char *fname;
322   FILE *fp;
323   struct stat st;
324   unsigned char *buf;
325   size_t len, buflen, erroff;
326   gcry_sexp_t s_skey;
327   char hexgrip[40+4+1];
328   int got_shadow_info = 0;
329   
330   *result = NULL;
331   if (shadow_info)
332       *shadow_info = NULL;
333
334   for (i=0; i < 20; i++)
335     sprintf (hexgrip+2*i, "%02X", grip[i]);
336   strcpy (hexgrip+40, ".key");
337
338   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
339   fp = fopen (fname, "rb");
340   if (!fp)
341     {
342       rc = gpg_error_from_errno (errno);
343       log_error ("can't open `%s': %s\n", fname, strerror (errno));
344       xfree (fname);
345       return rc;
346     }
347   
348   if (fstat (fileno(fp), &st))
349     {
350       rc = gpg_error_from_errno (errno);
351       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
352       xfree (fname);
353       fclose (fp);
354       return rc;
355     }
356
357   buflen = st.st_size;
358   buf = xmalloc (buflen+1);
359   if (fread (buf, buflen, 1, fp) != 1)
360     {
361       rc = gpg_error_from_errno (errno);
362       log_error ("error reading `%s': %s\n", fname, strerror (errno));
363       xfree (fname);
364       fclose (fp);
365       xfree (buf);
366       return rc;
367     }
368
369   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
370   xfree (fname);
371   fclose (fp);
372   xfree (buf);
373   if (rc)
374     {
375       log_error ("failed to build S-Exp (off=%u): %s\n",
376                  (unsigned int)erroff, gpg_strerror (rc));
377       return rc;
378     }
379   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
380   assert (len);
381   buf = xtrymalloc (len);
382   if (!buf)
383     {
384       rc = out_of_core ();
385       gcry_sexp_release (s_skey);
386       return rc;
387     }
388   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
389   assert (len);
390   gcry_sexp_release (s_skey);
391
392   switch (agent_private_key_type (buf))
393     {
394     case PRIVATE_KEY_CLEAR:
395       break; /* no unprotection needed */
396     case PRIVATE_KEY_PROTECTED:
397       {
398         gcry_sexp_t comment_sexp;
399         size_t comment_length;
400         char *desc_text_final;
401         const char *comment;
402         
403         comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
404         if (comment_sexp)
405           comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
406         else
407           {
408             comment = NULL;
409             comment_length = 0;
410           }
411
412         if (desc_text)
413           {
414             rc = modify_description (desc_text,
415                                      comment, comment_length, &desc_text_final);
416             if (rc)
417               log_error ("failed to modify description: %s\n", gpg_strerror (rc));
418           }
419         else
420           desc_text_final = NULL;
421
422         if (! rc)
423           {
424             rc = unprotect (ctrl, desc_text_final, &buf, grip, ignore_cache);
425             if (rc)
426               log_error ("failed to unprotect the secret key: %s\n",
427                          gpg_strerror (rc));
428           }
429
430         gcry_sexp_release (comment_sexp);
431         xfree (desc_text_final);
432       }
433       break;
434     case PRIVATE_KEY_SHADOWED:
435       if (shadow_info)
436         {
437           const unsigned char *s;
438           size_t n;
439
440           rc = agent_get_shadow_info (buf, &s);
441           if (!rc)
442             {
443               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
444               assert (n);
445               *shadow_info = xtrymalloc (n);
446               if (!*shadow_info)
447                 rc = out_of_core ();
448               else
449                 {
450                   memcpy (*shadow_info, s, n);
451                   rc = 0;
452                   got_shadow_info = 1;
453                 }
454             }
455           if (rc)
456             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
457         }
458       else
459         rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
460       break;
461     default:
462       log_error ("invalid private key format\n");
463       rc = gpg_error (GPG_ERR_BAD_SECKEY);
464       break;
465     }
466   if (rc || got_shadow_info)
467     {
468       xfree (buf);
469       return rc;
470     }
471
472   buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
473   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
474   wipememory (buf, buflen);
475   xfree (buf);
476   if (rc)
477     {
478       log_error ("failed to build S-Exp (off=%u): %s\n",
479                  (unsigned int)erroff, gpg_strerror (rc));
480       return rc;
481     }
482
483   *result = s_skey;
484   return 0;
485 }
486
487 /* Return the secret key as an S-Exp after locating it using the grip.
488    Returns NULL if key is not available. 0 = key is available */
489 int
490 agent_key_available (const unsigned char *grip)
491 {
492   int i;
493   char *fname;
494   char hexgrip[40+4+1];
495   
496   for (i=0; i < 20; i++)
497     sprintf (hexgrip+2*i, "%02X", grip[i]);
498   strcpy (hexgrip+40, ".key");
499
500   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
501   i = !access (fname, R_OK)? 0 : -1;
502   xfree (fname);
503   return i;
504 }
505
506
507