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