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