Minor fixes
[gnupg.git] / agent / findkey.c
1 /* findkey.c - locate the secret key
2  *      Copyright (C) 2001 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 <assert.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <assert.h>
31
32 #include "agent.h"
33
34 /* Helper to pass data to the check callback of the unprotect function. */
35 struct try_unprotect_arg_s {
36   const unsigned char *protected_key;
37   unsigned char *unprotected_key;
38 };
39
40
41
42 int
43 agent_write_private_key (const unsigned char *grip,
44                          const void *buffer, size_t length, int force)
45 {
46   int i;
47   char *fname;
48   FILE *fp;
49   char hexgrip[40+4+1];
50   
51   for (i=0; i < 20; i++)
52     sprintf (hexgrip+2*i, "%02X", grip[i]);
53   strcpy (hexgrip+40, ".key");
54
55   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
56   if (force)
57     fp = fopen (fname, "wb");
58   else
59     {
60       if (!access (fname, F_OK))
61       {
62         log_error ("secret key file `%s' already exists\n", fname);
63         xfree (fname);
64         return seterr (General_Error);
65       }
66       fp = fopen (fname, "wbx");  /* FIXME: the x is a GNU extension - let
67                                      configure check whether this actually
68                                      works */
69     }
70
71   if (!fp) 
72     { 
73       log_error ("can't create `%s': %s\n", fname, strerror (errno));
74       xfree (fname);
75       return seterr (File_Create_Error);
76     }
77
78   if (fwrite (buffer, length, 1, fp) != 1)
79     {
80       log_error ("error writing `%s': %s\n", fname, strerror (errno));
81       fclose (fp);
82       remove (fname);
83       xfree (fname);
84       return seterr (File_Create_Error);
85     }
86   if ( fclose (fp) )
87     {
88       log_error ("error closing `%s': %s\n", fname, strerror (errno));
89       remove (fname);
90       xfree (fname);
91       return seterr (File_Create_Error);
92     }
93
94   xfree (fname);
95   return 0;
96 }
97
98
99 /* Callback function to try the unprotection from the passpharse query
100    code. */
101 static int
102 try_unprotect_cb (struct pin_entry_info_s *pi)
103 {
104   struct try_unprotect_arg_s *arg = pi->check_cb_arg;
105   size_t dummy;
106
107   assert (!arg->unprotected_key);
108   return agent_unprotect (arg->protected_key, pi->pin,
109                           &arg->unprotected_key, &dummy);
110 }
111
112
113 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
114    should be the hex encoded keygrip of that key to be used with the
115    cahing mechanism. */
116 static int
117 unprotect (unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
118 {
119   struct pin_entry_info_s *pi;
120   struct try_unprotect_arg_s arg;
121   int rc, i;
122   unsigned char *result;
123   size_t resultlen;
124   char hexgrip[40+1];
125   
126   for (i=0; i < 20; i++)
127     sprintf (hexgrip+2*i, "%02X", grip[i]);
128   hexgrip[40] = 0;
129
130   /* first try to get it from the cache - if there is none or we can't
131      unprotect it, we fall back to ask the user */
132   if (!ignore_cache)
133     {
134       void *cache_marker;
135       const char *pw = agent_get_cache (hexgrip, &cache_marker);
136       if (pw)
137         {
138           rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
139           agent_unlock_cache_entry (&cache_marker);
140           if (!rc)
141             {
142               xfree (*keybuf);
143               *keybuf = result;
144               return 0;
145             }
146           rc  = 0;
147         }
148     }
149   
150   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
151   pi->max_length = 100;
152   pi->min_digits = 0;  /* we want a real passphrase */
153   pi->max_digits = 8;
154   pi->max_tries = 3;
155   pi->check_cb = try_unprotect_cb;
156   arg.protected_key = *keybuf;
157   arg.unprotected_key = NULL;
158   pi->check_cb_arg = &arg;
159
160   rc = agent_askpin (NULL, pi);
161   if (!rc)
162     {
163       assert (arg.unprotected_key);
164       agent_put_cache (hexgrip, pi->pin, 0);
165       xfree (*keybuf);
166       *keybuf = arg.unprotected_key;
167     }
168   xfree (pi);
169   return rc;
170 }
171
172
173
174 /* Return the secret key as an S-Exp after locating it using the grip.
175    Returns NULL if key is not available or the operation should be
176    diverted to a token.  In the latter case shadow_info will point to
177    an allocated S-Expression with the shadow_info part from the file.
178    With IGNORE_CACHE passed as true the passphrase is not taken from
179    the cache.*/
180 GCRY_SEXP
181 agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info,
182                      int ignore_cache)
183 {
184   int i, rc;
185   char *fname;
186   FILE *fp;
187   struct stat st;
188   unsigned char *buf;
189   size_t len, buflen, erroff;
190   GCRY_SEXP s_skey;
191   char hexgrip[40+4+1];
192   
193   if (shadow_info)
194       *shadow_info = NULL;
195
196   for (i=0; i < 20; i++)
197     sprintf (hexgrip+2*i, "%02X", grip[i]);
198   strcpy (hexgrip+40, ".key");
199
200   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
201   fp = fopen (fname, "rb");
202   if (!fp)
203     {
204       log_error ("can't open `%s': %s\n", fname, strerror (errno));
205       xfree (fname);
206       return NULL;
207     }
208   
209   if (fstat (fileno(fp), &st))
210     {
211       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
212       xfree (fname);
213       fclose (fp);
214       return NULL;
215     }
216
217   buflen = st.st_size;
218   buf = xmalloc (buflen+1);
219   if (fread (buf, buflen, 1, fp) != 1)
220     {
221       log_error ("error reading `%s': %s\n", fname, strerror (errno));
222       xfree (fname);
223       fclose (fp);
224       xfree (buf);
225       return NULL;
226     }
227
228   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
229   xfree (fname);
230   fclose (fp);
231   xfree (buf);
232   if (rc)
233     {
234       log_error ("failed to build S-Exp (off=%u): %s\n",
235                  (unsigned int)erroff, gcry_strerror (rc));
236       return NULL;
237     }
238   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
239   assert (len);
240   buf = xtrymalloc (len);
241   if (!buf)
242     {
243       gcry_sexp_release (s_skey);
244       return NULL;
245     }
246   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
247   assert (len);
248   gcry_sexp_release (s_skey);
249
250   switch (agent_private_key_type (buf))
251     {
252     case PRIVATE_KEY_CLEAR:
253       break; /* no unprotection needed */
254     case PRIVATE_KEY_PROTECTED:
255       rc = unprotect (&buf, grip, ignore_cache);
256       if (rc)
257         log_error ("failed to unprotect the secret key: %s\n",
258                    gnupg_strerror (rc));
259       break;
260     case PRIVATE_KEY_SHADOWED:
261       if (shadow_info)
262         {
263           const unsigned char *s;
264           size_t n;
265
266           rc = agent_get_shadow_info (buf, &s);
267           if (!rc)
268             {
269               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
270               assert (n);
271               *shadow_info = xtrymalloc (n);
272               if (!*shadow_info)
273                 rc = GNUPG_Out_Of_Core;
274               else
275                 {
276                   memcpy (*shadow_info, s, n);
277                   rc = 0;
278                 }
279             }
280           if (rc)
281             log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
282         }
283       rc = -1; /* ugly interface: we return an error but keep a value
284                   in shadow_info.  */
285       break;
286     default:
287       log_error ("invalid private key format\n");
288       rc = GNUPG_Bad_Secret_Key;
289       break;
290     }
291   if (rc)
292     {
293       xfree (buf);
294       return NULL;
295     }
296
297   /* arggg FIXME: does scan support secure memory? */
298   rc = gcry_sexp_sscan (&s_skey, &erroff,
299                         buf, gcry_sexp_canon_len (buf, 0, NULL, NULL));
300   xfree (buf);
301   if (rc)
302     {
303       log_error ("failed to build S-Exp (off=%u): %s\n",
304                  (unsigned int)erroff, gcry_strerror (rc));
305       return NULL;
306     }
307
308   return s_skey;
309 }
310
311 /* Return the secret key as an S-Exp after locating it using the grip.
312    Returns NULL if key is not available. 0 = key is available */
313 int
314 agent_key_available (const unsigned char *grip)
315 {
316   int i;
317   char *fname;
318   char hexgrip[40+4+1];
319   
320   for (i=0; i < 20; i++)
321     sprintf (hexgrip+2*i, "%02X", grip[i]);
322   strcpy (hexgrip+40, ".key");
323
324   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
325   i = !access (fname, R_OK)? 0 : -1;
326   xfree (fname);
327   return i;
328 }
329
330
331