2002-04-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / findkey.c
blob662a56f8913dbc2542190bd6a9c886321b09460f
1 /* findkey.c - locate the secret key
2 * Copyright (C) 2001 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
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>
31 #include "agent.h"
34 int
35 agent_write_private_key (const unsigned char *grip,
36 const void *buffer, size_t length, int force)
38 int i;
39 char *fname;
40 FILE *fp;
41 char hexgrip[40+4+1];
43 for (i=0; i < 20; i++)
44 sprintf (hexgrip+2*i, "%02X", grip[i]);
45 strcpy (hexgrip+40, ".key");
47 fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
48 if (force)
49 fp = fopen (fname, "wb");
50 else
52 if (!access (fname, F_OK))
54 log_error ("secret key file `%s' already exists\n", fname);
55 xfree (fname);
56 return seterr (General_Error);
58 fp = fopen (fname, "wbx"); /* FIXME: the x is a GNU extension - let
59 configure check whether this actually
60 works */
63 if (!fp)
65 log_error ("can't create `%s': %s\n", fname, strerror (errno));
66 xfree (fname);
67 return seterr (File_Create_Error);
70 if (fwrite (buffer, length, 1, fp) != 1)
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);
78 if ( fclose (fp) )
80 log_error ("error closing `%s': %s\n", fname, strerror (errno));
81 remove (fname);
82 xfree (fname);
83 return seterr (File_Create_Error);
86 xfree (fname);
87 return 0;
91 static int
92 unprotect (unsigned char **keybuf, const unsigned char *grip)
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;
102 for (i=0; i < 20; i++)
103 sprintf (hexgrip+2*i, "%02X", grip[i]);
104 hexgrip[40] = 0;
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 */
109 const char *pw = agent_get_cache (hexgrip);
110 if (pw)
112 rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
113 if (!rc)
115 xfree (*keybuf);
116 *keybuf = result;
117 return 0;
119 rc = 0;
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;
129 errtext = NULL;
132 rc = agent_askpin (NULL, errtext, pi);
133 if (!rc)
135 rc = agent_unprotect (*keybuf, pi->pin, &result, &resultlen);
136 if (!rc)
138 agent_put_cache (hexgrip, pi->pin, 0);
139 xfree (*keybuf);
140 *keybuf = result;
141 xfree (pi);
142 return 0;
145 errtext = pi->min_digits? trans ("Bad PIN") : trans ("Bad Passphrase");
147 while ((rc == GNUPG_Bad_Passphrase || rc == GNUPG_Bad_PIN)
148 && tries++ < 3);
149 xfree (pi);
150 return rc;
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)
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];
172 if (shadow_info)
173 *shadow_info = NULL;
175 for (i=0; i < 20; i++)
176 sprintf (hexgrip+2*i, "%02X", grip[i]);
177 strcpy (hexgrip+40, ".key");
179 fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
180 fp = fopen (fname, "rb");
181 if (!fp)
183 log_error ("can't open `%s': %s\n", fname, strerror (errno));
184 xfree (fname);
185 return NULL;
188 if (fstat (fileno(fp), &st))
190 log_error ("can't stat `%s': %s\n", fname, strerror (errno));
191 xfree (fname);
192 fclose (fp);
193 return NULL;
196 buflen = st.st_size;
197 buf = xmalloc (buflen+1);
198 if (fread (buf, buflen, 1, fp) != 1)
200 log_error ("error reading `%s': %s\n", fname, strerror (errno));
201 xfree (fname);
202 fclose (fp);
203 xfree (buf);
204 return NULL;
207 rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
208 xfree (fname);
209 fclose (fp);
210 xfree (buf);
211 if (rc)
213 log_error ("failed to build S-Exp (off=%u): %s\n",
214 (unsigned int)erroff, gcry_strerror (rc));
215 return NULL;
217 len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
218 assert (len);
219 buf = xtrymalloc (len);
220 if (!buf)
222 gcry_sexp_release (s_skey);
223 return NULL;
225 len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
226 assert (len);
227 gcry_sexp_release (s_skey);
229 switch (agent_private_key_type (buf))
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)
242 const unsigned char *s;
243 size_t n;
245 rc = agent_get_shadow_info (buf, &s);
246 if (!rc)
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
255 memcpy (*shadow_info, s, n);
256 rc = 0;
259 if (rc)
260 log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
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;
270 if (rc)
272 xfree (buf);
273 return NULL;
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)
282 log_error ("failed to build S-Exp (off=%u): %s\n",
283 (unsigned int)erroff, gcry_strerror (rc));
284 return NULL;
287 return s_skey;
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 */
293 agent_key_available (const unsigned char *grip)
295 int i;
296 char *fname;
297 char hexgrip[40+4+1];
299 for (i=0; i < 20; i++)
300 sprintf (hexgrip+2*i, "%02X", grip[i]);
301 strcpy (hexgrip+40, ".key");
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;