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