* cache.c: Add a few debug outputs.
[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 static int
34 unprotect (unsigned char **keybuf, const unsigned char *grip)
35 {
36   struct pin_entry_info_s *pi;
37   int rc, i;
38   unsigned char *result;
39   size_t resultlen;
40   int tries = 0;
41   char hexgrip[40+1];
42   
43   for (i=0; i < 20; i++)
44     sprintf (hexgrip+2*i, "%02X", grip[i]);
45   hexgrip[40] = 0;
46
47   /* first try to get it from the cache - if there is none or we can't
48      unprotect it, we fall back to ask the user */
49   {
50     const char *pw = agent_get_cache (hexgrip);
51     if (pw)
52       {
53         rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
54         if (!rc)
55           {
56             xfree (*keybuf);
57             *keybuf = result;
58             return 0;
59           }
60         rc  = 0;
61       }
62   }
63   
64   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
65   pi->max_length = 100;
66   pi->min_digits = 0;  /* we want a real passphrase */
67   pi->max_digits = 8;
68   pi->max_tries = 3;
69
70   do
71     {
72       rc = agent_askpin (NULL, NULL, pi);
73       if (!rc)
74         {
75           rc = agent_unprotect (*keybuf, pi->pin, &result, &resultlen);
76           if (!rc)
77             {
78               agent_put_cache (hexgrip, pi->pin, 0);
79               xfree (*keybuf);
80               *keybuf = result;
81               xfree (pi);
82               return 0;
83             }
84         }
85     }
86   while ((rc == GNUPG_Bad_Passphrase || rc == GNUPG_Bad_PIN)
87          && tries++ < 3);
88   xfree (pi);
89   return rc;
90 }
91
92
93
94 /* Return the secret key as an S-Exp after locating it using the grip.
95    Returns NULL if key is not available. */
96 GCRY_SEXP
97 agent_key_from_file (const unsigned char *grip)
98 {
99   int i, rc;
100   char *fname;
101   FILE *fp;
102   struct stat st;
103   unsigned char *buf;
104   size_t len, buflen, erroff;
105   GCRY_SEXP s_skey;
106   char hexgrip[40+4+1];
107   
108   for (i=0; i < 20; i++)
109     sprintf (hexgrip+2*i, "%02X", grip[i]);
110   strcpy (hexgrip+40, ".key");
111
112   fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
113   fp = fopen (fname, "rb");
114   if (!fp)
115     {
116       log_error ("can't open `%s': %s\n", fname, strerror (errno));
117       xfree (fname);
118       return NULL;
119     }
120   
121   if (fstat (fileno(fp), &st))
122     {
123       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
124       xfree (fname);
125       fclose (fp);
126       return NULL;
127     }
128
129   buflen = st.st_size;
130   buf = xmalloc (buflen+1);
131   if (fread (buf, buflen, 1, fp) != 1)
132     {
133       log_error ("error reading `%s': %s\n", fname, strerror (errno));
134       xfree (fname);
135       fclose (fp);
136       xfree (buf);
137       return NULL;
138     }
139
140   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
141   xfree (fname);
142   fclose (fp);
143   xfree (buf);
144   if (rc)
145     {
146       log_error ("failed to build S-Exp (off=%u): %s\n",
147                  (unsigned int)erroff, gcry_strerror (rc));
148       return NULL;
149     }
150   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
151   assert (len);
152   buf = xtrymalloc (len);
153   if (!buf)
154     {
155       gcry_sexp_release (s_skey);
156       return NULL;
157     }
158   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
159   assert (len);
160   gcry_sexp_release (s_skey);
161
162   switch (agent_private_key_type (buf))
163     {
164     case PRIVATE_KEY_CLEAR:
165       break; /* no unprotection needed */
166     case PRIVATE_KEY_PROTECTED:
167       rc = unprotect (&buf, grip);
168       if (rc)
169         log_error ("failed to unprotect the secret key: %s\n",
170                    gnupg_strerror (rc));
171       break;
172     case PRIVATE_KEY_SHADOWED:
173       log_error ("shadowed private keys are not yet supported\n");
174       rc = GNUPG_Not_Implemented;
175       break;
176     default:
177       log_error ("invalid private key format\n");
178       rc = GNUPG_Bad_Secret_Key;
179       break;
180     }
181   if (rc)
182     {
183       xfree (buf);
184       return NULL;
185     }
186
187   /* arggg FIXME: does scan support secure memory? */
188   rc = gcry_sexp_sscan (&s_skey, &erroff,
189                         buf, gcry_sexp_canon_len (buf, 0, NULL, NULL));
190   xfree (buf);
191   if (rc)
192     {
193       log_error ("failed to build S-Exp (off=%u): %s\n",
194                  (unsigned int)erroff, gcry_strerror (rc));
195       return NULL;
196     }
197
198   return s_skey;
199 }
200
201 /* Return the secret key as an S-Exp after locating it using the grip.
202    Returns NULL if key is not available. 0 = key is available */
203 int
204 agent_key_available (const unsigned char *grip)
205 {
206   int i;
207   char *fname;
208   char hexgrip[40+4+1];
209   
210   for (i=0; i < 20; i++)
211     sprintf (hexgrip+2*i, "%02X", grip[i]);
212   strcpy (hexgrip+40, ".key");
213
214   fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
215   i = !access (fname, R_OK)? 0 : -1;
216   xfree (fname);
217   return i;
218 }
219
220
221