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