* findkey.c (agent_key_from_file): Now return an error code so
[gnupg.git] / agent / findkey.c
1 /* findkey.c - locate the secret key
2  *      Copyright (C) 2001, 2002, 2003 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. */
142 static int
143 unprotect (CTRL ctrl,
144            unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
145 {
146   struct pin_entry_info_s *pi;
147   struct try_unprotect_arg_s arg;
148   int rc, i;
149   unsigned char *result;
150   size_t resultlen;
151   char hexgrip[40+1];
152   
153   for (i=0; i < 20; i++)
154     sprintf (hexgrip+2*i, "%02X", grip[i]);
155   hexgrip[40] = 0;
156
157   /* first try to get it from the cache - if there is none or we can't
158      unprotect it, we fall back to ask the user */
159   if (!ignore_cache)
160     {
161       void *cache_marker;
162       const char *pw = agent_get_cache (hexgrip, &cache_marker);
163       if (pw)
164         {
165           rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
166           agent_unlock_cache_entry (&cache_marker);
167           if (!rc)
168             {
169               xfree (*keybuf);
170               *keybuf = result;
171               return 0;
172             }
173           rc  = 0;
174         }
175     }
176   
177   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
178   pi->max_length = 100;
179   pi->min_digits = 0;  /* we want a real passphrase */
180   pi->max_digits = 8;
181   pi->max_tries = 3;
182   pi->check_cb = try_unprotect_cb;
183   arg.protected_key = *keybuf;
184   arg.unprotected_key = NULL;
185   pi->check_cb_arg = &arg;
186
187   rc = agent_askpin (ctrl, NULL, pi);
188   if (!rc)
189     {
190       assert (arg.unprotected_key);
191       agent_put_cache (hexgrip, pi->pin, 0);
192       xfree (*keybuf);
193       *keybuf = arg.unprotected_key;
194     }
195   xfree (pi);
196   return rc;
197 }
198
199
200
201 /* Return the secret key as an S-Exp in RESULT after locating it using
202    the grip.  Returns NULL in RESULT if the operation should be
203    diverted to a token; SHADOW_INFO will point then to an allocated
204    S-Expression with the shadow_info part from the file.  With
205    IGNORE_CACHE passed as true the passphrase is not taken from the
206    cache.*/
207 gpg_error_t
208 agent_key_from_file (CTRL ctrl,
209                      const unsigned char *grip, unsigned char **shadow_info,
210                      int ignore_cache, gcry_sexp_t *result)
211 {
212   int i, rc;
213   char *fname;
214   FILE *fp;
215   struct stat st;
216   unsigned char *buf;
217   size_t len, buflen, erroff;
218   gcry_sexp_t s_skey;
219   char hexgrip[40+4+1];
220   int got_shadow_info = 0;
221   
222   *result = NULL;
223   if (shadow_info)
224       *shadow_info = NULL;
225
226   for (i=0; i < 20; i++)
227     sprintf (hexgrip+2*i, "%02X", grip[i]);
228   strcpy (hexgrip+40, ".key");
229
230   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
231   fp = fopen (fname, "rb");
232   if (!fp)
233     {
234       rc = gpg_error_from_errno (errno);
235       log_error ("can't open `%s': %s\n", fname, strerror (errno));
236       xfree (fname);
237       return rc;
238     }
239   
240   if (fstat (fileno(fp), &st))
241     {
242       rc = gpg_error_from_errno (errno);
243       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
244       xfree (fname);
245       fclose (fp);
246       return rc;
247     }
248
249   buflen = st.st_size;
250   buf = xmalloc (buflen+1);
251   if (fread (buf, buflen, 1, fp) != 1)
252     {
253       rc = gpg_error_from_errno (errno);
254       log_error ("error reading `%s': %s\n", fname, strerror (errno));
255       xfree (fname);
256       fclose (fp);
257       xfree (buf);
258       return rc;
259     }
260
261   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
262   xfree (fname);
263   fclose (fp);
264   xfree (buf);
265   if (rc)
266     {
267       log_error ("failed to build S-Exp (off=%u): %s\n",
268                  (unsigned int)erroff, gpg_strerror (rc));
269       return rc;
270     }
271   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
272   assert (len);
273   buf = xtrymalloc (len);
274   if (!buf)
275     {
276       rc = out_of_core ();
277       gcry_sexp_release (s_skey);
278       return rc;
279     }
280   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
281   assert (len);
282   gcry_sexp_release (s_skey);
283
284   switch (agent_private_key_type (buf))
285     {
286     case PRIVATE_KEY_CLEAR:
287       break; /* no unprotection needed */
288     case PRIVATE_KEY_PROTECTED:
289       rc = unprotect (ctrl, &buf, grip, ignore_cache);
290       if (rc)
291         log_error ("failed to unprotect the secret key: %s\n",
292                    gpg_strerror (rc));
293       break;
294     case PRIVATE_KEY_SHADOWED:
295       if (shadow_info)
296         {
297           const unsigned char *s;
298           size_t n;
299
300           rc = agent_get_shadow_info (buf, &s);
301           if (!rc)
302             {
303               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
304               assert (n);
305               *shadow_info = xtrymalloc (n);
306               if (!*shadow_info)
307                 rc = out_of_core ();
308               else
309                 {
310                   memcpy (*shadow_info, s, n);
311                   rc = 0;
312                   got_shadow_info = 1;
313                 }
314             }
315           if (rc)
316             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
317         }
318       else
319         rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
320       break;
321     default:
322       log_error ("invalid private key format\n");
323       rc = gpg_error (GPG_ERR_BAD_SECKEY);
324       break;
325     }
326   if (rc || got_shadow_info)
327     {
328       xfree (buf);
329       return rc;
330     }
331
332   /* Arggg FIXME: does scan support secure memory? */
333   rc = gcry_sexp_sscan (&s_skey, &erroff,
334                         buf, gcry_sexp_canon_len (buf, 0, NULL, NULL));
335   xfree (buf);
336   if (rc)
337     {
338       log_error ("failed to build S-Exp (off=%u): %s\n",
339                  (unsigned int)erroff, gpg_strerror (rc));
340       return rc;
341     }
342
343   *result = s_skey;
344   return 0;
345 }
346
347 /* Return the secret key as an S-Exp after locating it using the grip.
348    Returns NULL if key is not available. 0 = key is available */
349 int
350 agent_key_available (const unsigned char *grip)
351 {
352   int i;
353   char *fname;
354   char hexgrip[40+4+1];
355   
356   for (i=0; i < 20; i++)
357     sprintf (hexgrip+2*i, "%02X", grip[i]);
358   strcpy (hexgrip+40, ".key");
359
360   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
361   i = !access (fname, R_OK)? 0 : -1;
362   xfree (fname);
363   return i;
364 }
365
366
367