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