* findkey.c (unprotect): Show an error message for a bad passphrase.
[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. */
99 GCRY_SEXP
100 agent_key_from_file (const unsigned char *grip)
101 {
102   int i, rc;
103   char *fname;
104   FILE *fp;
105   struct stat st;
106   unsigned char *buf;
107   size_t len, buflen, erroff;
108   GCRY_SEXP s_skey;
109   char hexgrip[40+4+1];
110   
111   for (i=0; i < 20; i++)
112     sprintf (hexgrip+2*i, "%02X", grip[i]);
113   strcpy (hexgrip+40, ".key");
114
115   fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
116   fp = fopen (fname, "rb");
117   if (!fp)
118     {
119       log_error ("can't open `%s': %s\n", fname, strerror (errno));
120       xfree (fname);
121       return NULL;
122     }
123   
124   if (fstat (fileno(fp), &st))
125     {
126       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
127       xfree (fname);
128       fclose (fp);
129       return NULL;
130     }
131
132   buflen = st.st_size;
133   buf = xmalloc (buflen+1);
134   if (fread (buf, buflen, 1, fp) != 1)
135     {
136       log_error ("error reading `%s': %s\n", fname, strerror (errno));
137       xfree (fname);
138       fclose (fp);
139       xfree (buf);
140       return NULL;
141     }
142
143   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
144   xfree (fname);
145   fclose (fp);
146   xfree (buf);
147   if (rc)
148     {
149       log_error ("failed to build S-Exp (off=%u): %s\n",
150                  (unsigned int)erroff, gcry_strerror (rc));
151       return NULL;
152     }
153   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
154   assert (len);
155   buf = xtrymalloc (len);
156   if (!buf)
157     {
158       gcry_sexp_release (s_skey);
159       return NULL;
160     }
161   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
162   assert (len);
163   gcry_sexp_release (s_skey);
164
165   switch (agent_private_key_type (buf))
166     {
167     case PRIVATE_KEY_CLEAR:
168       break; /* no unprotection needed */
169     case PRIVATE_KEY_PROTECTED:
170       rc = unprotect (&buf, grip);
171       if (rc)
172         log_error ("failed to unprotect the secret key: %s\n",
173                    gnupg_strerror (rc));
174       break;
175     case PRIVATE_KEY_SHADOWED:
176       log_error ("shadowed private keys are not yet supported\n");
177       rc = GNUPG_Not_Implemented;
178       break;
179     default:
180       log_error ("invalid private key format\n");
181       rc = GNUPG_Bad_Secret_Key;
182       break;
183     }
184   if (rc)
185     {
186       xfree (buf);
187       return NULL;
188     }
189
190   /* arggg FIXME: does scan support secure memory? */
191   rc = gcry_sexp_sscan (&s_skey, &erroff,
192                         buf, gcry_sexp_canon_len (buf, 0, NULL, NULL));
193   xfree (buf);
194   if (rc)
195     {
196       log_error ("failed to build S-Exp (off=%u): %s\n",
197                  (unsigned int)erroff, gcry_strerror (rc));
198       return NULL;
199     }
200
201   return s_skey;
202 }
203
204 /* Return the secret key as an S-Exp after locating it using the grip.
205    Returns NULL if key is not available. 0 = key is available */
206 int
207 agent_key_available (const unsigned char *grip)
208 {
209   int i;
210   char *fname;
211   char hexgrip[40+4+1];
212   
213   for (i=0; i < 20; i++)
214     sprintf (hexgrip+2*i, "%02X", grip[i]);
215   strcpy (hexgrip+40, ".key");
216
217   fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
218   i = !access (fname, R_OK)? 0 : -1;
219   xfree (fname);
220   return i;
221 }
222
223
224