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