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