* command.c (cmd_passwd): Take acount of a key description.
[gnupg.git] / agent / findkey.c
1 /* findkey.c - locate the secret key
2  * Copyright (C) 2001, 2002, 2003, 2004 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 | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
80       if (fd < 0)
81         fp = 0;
82       else
83         {
84           fp = fdopen (fd, "wb");
85           if (!fp)
86             { 
87               int save_e = errno;
88               close (fd);
89               errno = save_e;
90             }
91         }
92     }
93
94   if (!fp) 
95     { 
96       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
97       log_error ("can't create `%s': %s\n", fname, strerror (errno));
98       xfree (fname);
99       return tmperr;
100     }
101
102   if (fwrite (buffer, length, 1, fp) != 1)
103     {
104       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
105       log_error ("error writing `%s': %s\n", fname, strerror (errno));
106       fclose (fp);
107       remove (fname);
108       xfree (fname);
109       return tmperr;
110     }
111   if ( fclose (fp) )
112     {
113       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
114       log_error ("error closing `%s': %s\n", fname, strerror (errno));
115       remove (fname);
116       xfree (fname);
117       return tmperr;
118     }
119
120   xfree (fname);
121   return 0;
122 }
123
124
125 /* Callback function to try the unprotection from the passpharse query
126    code. */
127 static int
128 try_unprotect_cb (struct pin_entry_info_s *pi)
129 {
130   struct try_unprotect_arg_s *arg = pi->check_cb_arg;
131   size_t dummy;
132
133   assert (!arg->unprotected_key);
134   return agent_unprotect (arg->protected_key, pi->pin,
135                           &arg->unprotected_key, &dummy);
136 }
137
138
139 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
140    should be the hex encoded keygrip of that key to be used with the
141    caching mechanism. DESC_TEXT may be set to override the default
142    description used for the pinentry. */
143 static int
144 unprotect (CTRL ctrl, const char *desc_text,
145            unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
146 {
147   struct pin_entry_info_s *pi;
148   struct try_unprotect_arg_s arg;
149   int rc, i;
150   unsigned char *result;
151   size_t resultlen;
152   char hexgrip[40+1];
153   
154   for (i=0; i < 20; i++)
155     sprintf (hexgrip+2*i, "%02X", grip[i]);
156   hexgrip[40] = 0;
157
158   /* First try to get it from the cache - if there is none or we can't
159      unprotect it, we fall back to ask the user */
160   if (!ignore_cache)
161     {
162       void *cache_marker;
163       const char *pw = agent_get_cache (hexgrip, &cache_marker);
164       if (pw)
165         {
166           rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
167           agent_unlock_cache_entry (&cache_marker);
168           if (!rc)
169             {
170               xfree (*keybuf);
171               *keybuf = result;
172               return 0;
173             }
174           rc  = 0;
175         }
176     }
177   
178   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
179   pi->max_length = 100;
180   pi->min_digits = 0;  /* we want a real passphrase */
181   pi->max_digits = 8;
182   pi->max_tries = 3;
183   pi->check_cb = try_unprotect_cb;
184   arg.protected_key = *keybuf;
185   arg.unprotected_key = NULL;
186   pi->check_cb_arg = &arg;
187
188   rc = agent_askpin (ctrl, desc_text, NULL, pi);
189   if (!rc)
190     {
191       assert (arg.unprotected_key);
192       agent_put_cache (hexgrip, pi->pin, 0);
193       xfree (*keybuf);
194       *keybuf = arg.unprotected_key;
195     }
196   xfree (pi);
197   return rc;
198 }
199
200
201
202 /* Return the secret key as an S-Exp in RESULT after locating it using
203    the grip.  Returns NULL in RESULT if the operation should be
204    diverted to a token; SHADOW_INFO will point then to an allocated
205    S-Expression with the shadow_info part from the file.  With
206    IGNORE_CACHE passed as true the passphrase is not taken from the
207    cache.  DESC_TEXT may be set to present a custom description for the
208    pinentry. */
209 gpg_error_t
210 agent_key_from_file (CTRL ctrl, const char *desc_text,
211                      const unsigned char *grip, unsigned char **shadow_info,
212                      int ignore_cache, gcry_sexp_t *result)
213 {
214   int i, rc;
215   char *fname;
216   FILE *fp;
217   struct stat st;
218   unsigned char *buf;
219   size_t len, buflen, erroff;
220   gcry_sexp_t s_skey;
221   char hexgrip[40+4+1];
222   int got_shadow_info = 0;
223   
224   *result = NULL;
225   if (shadow_info)
226       *shadow_info = NULL;
227
228   for (i=0; i < 20; i++)
229     sprintf (hexgrip+2*i, "%02X", grip[i]);
230   strcpy (hexgrip+40, ".key");
231
232   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
233   fp = fopen (fname, "rb");
234   if (!fp)
235     {
236       rc = gpg_error_from_errno (errno);
237       log_error ("can't open `%s': %s\n", fname, strerror (errno));
238       xfree (fname);
239       return rc;
240     }
241   
242   if (fstat (fileno(fp), &st))
243     {
244       rc = gpg_error_from_errno (errno);
245       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
246       xfree (fname);
247       fclose (fp);
248       return rc;
249     }
250
251   buflen = st.st_size;
252   buf = xmalloc (buflen+1);
253   if (fread (buf, buflen, 1, fp) != 1)
254     {
255       rc = gpg_error_from_errno (errno);
256       log_error ("error reading `%s': %s\n", fname, strerror (errno));
257       xfree (fname);
258       fclose (fp);
259       xfree (buf);
260       return rc;
261     }
262
263   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
264   xfree (fname);
265   fclose (fp);
266   xfree (buf);
267   if (rc)
268     {
269       log_error ("failed to build S-Exp (off=%u): %s\n",
270                  (unsigned int)erroff, gpg_strerror (rc));
271       return rc;
272     }
273   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
274   assert (len);
275   buf = xtrymalloc (len);
276   if (!buf)
277     {
278       rc = out_of_core ();
279       gcry_sexp_release (s_skey);
280       return rc;
281     }
282   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
283   assert (len);
284   gcry_sexp_release (s_skey);
285
286   switch (agent_private_key_type (buf))
287     {
288     case PRIVATE_KEY_CLEAR:
289       break; /* no unprotection needed */
290     case PRIVATE_KEY_PROTECTED:
291       rc = unprotect (ctrl, desc_text, &buf, grip, ignore_cache);
292       if (rc)
293         log_error ("failed to unprotect the secret key: %s\n",
294                    gpg_strerror (rc));
295       break;
296     case PRIVATE_KEY_SHADOWED:
297       if (shadow_info)
298         {
299           const unsigned char *s;
300           size_t n;
301
302           rc = agent_get_shadow_info (buf, &s);
303           if (!rc)
304             {
305               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
306               assert (n);
307               *shadow_info = xtrymalloc (n);
308               if (!*shadow_info)
309                 rc = out_of_core ();
310               else
311                 {
312                   memcpy (*shadow_info, s, n);
313                   rc = 0;
314                   got_shadow_info = 1;
315                 }
316             }
317           if (rc)
318             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
319         }
320       else
321         rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
322       break;
323     default:
324       log_error ("invalid private key format\n");
325       rc = gpg_error (GPG_ERR_BAD_SECKEY);
326       break;
327     }
328   if (rc || got_shadow_info)
329     {
330       xfree (buf);
331       return rc;
332     }
333
334   buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
335   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
336   wipememory (buf, buflen);
337   xfree (buf);
338   if (rc)
339     {
340       log_error ("failed to build S-Exp (off=%u): %s\n",
341                  (unsigned int)erroff, gpg_strerror (rc));
342       return rc;
343     }
344
345   *result = s_skey;
346   return 0;
347 }
348
349 /* Return the secret key as an S-Exp after locating it using the grip.
350    Returns NULL if key is not available. 0 = key is available */
351 int
352 agent_key_available (const unsigned char *grip)
353 {
354   int i;
355   char *fname;
356   char hexgrip[40+4+1];
357   
358   for (i=0; i < 20; i++)
359     sprintf (hexgrip+2*i, "%02X", grip[i]);
360   strcpy (hexgrip+40, ".key");
361
362   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
363   i = !access (fname, R_OK)? 0 : -1;
364   xfree (fname);
365   return i;
366 }
367
368
369