Fix buglet.
[gnupg.git] / agent / findkey.c
blob9866b54b91d732beb5fa122f44b742ce5a301f97
1 /* findkey.c - locate the secret key
2 * Copyright (C) 2001, 2002, 2003, 2004 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 <fcntl.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <assert.h>
33 #include "agent.h"
35 /* Helper to pass data to the check callback of the unprotect function. */
36 struct try_unprotect_arg_s {
37 const unsigned char *protected_key;
38 unsigned char *unprotected_key;
43 int
44 agent_write_private_key (const unsigned char *grip,
45 const void *buffer, size_t length, int force)
47 int i;
48 char *fname;
49 FILE *fp;
50 char hexgrip[40+4+1];
52 for (i=0; i < 20; i++)
53 sprintf (hexgrip+2*i, "%02X", grip[i]);
54 strcpy (hexgrip+40, ".key");
56 fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
57 if (force)
58 fp = fopen (fname, "wb");
59 else
61 int fd;
63 if (!access (fname, F_OK))
65 log_error ("secret key file `%s' already exists\n", fname);
66 xfree (fname);
67 return gpg_error (GPG_ERR_GENERAL);
70 /* We would like to create FNAME but only if it does not already
71 exist. We cannot make this guarantee just using POSIX (GNU
72 provides the "x" opentype for fopen, however, this is not
73 portable). Thus, we use the more flexible open function and
74 then use fdopen to obtain a stream.
76 The mode parameter to open is what fopen uses. It will be
77 combined with the process' umask automatically. */
78 fd = open (fname, O_CREAT | O_EXCL | O_RDWR,
79 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
80 if (fd < 0)
81 fp = 0;
82 else
84 fp = fdopen (fd, "wb");
85 if (!fp)
87 int save_e = errno;
88 close (fd);
89 errno = save_e;
94 if (!fp)
96 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
97 log_error ("can't create `%s': %s\n", fname, strerror (errno));
98 xfree (fname);
99 return tmperr;
102 if (fwrite (buffer, length, 1, fp) != 1)
104 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
105 log_error ("error writing `%s': %s\n", fname, strerror (errno));
106 fclose (fp);
107 remove (fname);
108 xfree (fname);
109 return tmperr;
111 if ( fclose (fp) )
113 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
114 log_error ("error closing `%s': %s\n", fname, strerror (errno));
115 remove (fname);
116 xfree (fname);
117 return tmperr;
120 xfree (fname);
121 return 0;
125 /* Callback function to try the unprotection from the passpharse query
126 code. */
127 static int
128 try_unprotect_cb (struct pin_entry_info_s *pi)
130 struct try_unprotect_arg_s *arg = pi->check_cb_arg;
131 size_t dummy;
133 assert (!arg->unprotected_key);
134 return agent_unprotect (arg->protected_key, pi->pin,
135 &arg->unprotected_key, &dummy);
139 /* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP
140 should be the hex encoded keygrip of that key to be used with the
141 caching mechanism. DESC_TEXT may be set to override the default
142 description used for the pinentry. */
143 static int
144 unprotect (CTRL ctrl, const char *desc_text,
145 unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
147 struct pin_entry_info_s *pi;
148 struct try_unprotect_arg_s arg;
149 int rc, i;
150 unsigned char *result;
151 size_t resultlen;
152 char hexgrip[40+1];
154 for (i=0; i < 20; i++)
155 sprintf (hexgrip+2*i, "%02X", grip[i]);
156 hexgrip[40] = 0;
158 /* First try to get it from the cache - if there is none or we can't
159 unprotect it, we fall back to ask the user */
160 if (!ignore_cache)
162 void *cache_marker;
163 const char *pw = agent_get_cache (hexgrip, &cache_marker);
164 if (pw)
166 rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
167 agent_unlock_cache_entry (&cache_marker);
168 if (!rc)
170 xfree (*keybuf);
171 *keybuf = result;
172 return 0;
174 rc = 0;
178 pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
179 pi->max_length = 100;
180 pi->min_digits = 0; /* we want a real passphrase */
181 pi->max_digits = 8;
182 pi->max_tries = 3;
183 pi->check_cb = try_unprotect_cb;
184 arg.protected_key = *keybuf;
185 arg.unprotected_key = NULL;
186 pi->check_cb_arg = &arg;
188 rc = agent_askpin (ctrl, desc_text, NULL, pi);
189 if (!rc)
191 assert (arg.unprotected_key);
192 agent_put_cache (hexgrip, pi->pin, 0);
193 xfree (*keybuf);
194 *keybuf = arg.unprotected_key;
196 xfree (pi);
197 return rc;
202 /* Return the secret key as an S-Exp in RESULT after locating it using
203 the grip. Returns NULL in RESULT if the operation should be
204 diverted to a token; SHADOW_INFO will point then to an allocated
205 S-Expression with the shadow_info part from the file. With
206 IGNORE_CACHE passed as true the passphrase is not taken from the
207 cache. DESC_TEXT may be set to present a custom description for the
208 pinentry. */
209 gpg_error_t
210 agent_key_from_file (CTRL ctrl, const char *desc_text,
211 const unsigned char *grip, unsigned char **shadow_info,
212 int ignore_cache, gcry_sexp_t *result)
214 int i, rc;
215 char *fname;
216 FILE *fp;
217 struct stat st;
218 unsigned char *buf;
219 size_t len, buflen, erroff;
220 gcry_sexp_t s_skey;
221 char hexgrip[40+4+1];
222 int got_shadow_info = 0;
224 *result = NULL;
225 if (shadow_info)
226 *shadow_info = NULL;
228 for (i=0; i < 20; i++)
229 sprintf (hexgrip+2*i, "%02X", grip[i]);
230 strcpy (hexgrip+40, ".key");
232 fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
233 fp = fopen (fname, "rb");
234 if (!fp)
236 rc = gpg_error_from_errno (errno);
237 log_error ("can't open `%s': %s\n", fname, strerror (errno));
238 xfree (fname);
239 return rc;
242 if (fstat (fileno(fp), &st))
244 rc = gpg_error_from_errno (errno);
245 log_error ("can't stat `%s': %s\n", fname, strerror (errno));
246 xfree (fname);
247 fclose (fp);
248 return rc;
251 buflen = st.st_size;
252 buf = xmalloc (buflen+1);
253 if (fread (buf, buflen, 1, fp) != 1)
255 rc = gpg_error_from_errno (errno);
256 log_error ("error reading `%s': %s\n", fname, strerror (errno));
257 xfree (fname);
258 fclose (fp);
259 xfree (buf);
260 return rc;
263 rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
264 xfree (fname);
265 fclose (fp);
266 xfree (buf);
267 if (rc)
269 log_error ("failed to build S-Exp (off=%u): %s\n",
270 (unsigned int)erroff, gpg_strerror (rc));
271 return rc;
273 len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
274 assert (len);
275 buf = xtrymalloc (len);
276 if (!buf)
278 rc = out_of_core ();
279 gcry_sexp_release (s_skey);
280 return rc;
282 len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
283 assert (len);
284 gcry_sexp_release (s_skey);
286 switch (agent_private_key_type (buf))
288 case PRIVATE_KEY_CLEAR:
289 break; /* no unprotection needed */
290 case PRIVATE_KEY_PROTECTED:
291 rc = unprotect (ctrl, desc_text, &buf, grip, ignore_cache);
292 if (rc)
293 log_error ("failed to unprotect the secret key: %s\n",
294 gpg_strerror (rc));
295 break;
296 case PRIVATE_KEY_SHADOWED:
297 if (shadow_info)
299 const unsigned char *s;
300 size_t n;
302 rc = agent_get_shadow_info (buf, &s);
303 if (!rc)
305 n = gcry_sexp_canon_len (s, 0, NULL,NULL);
306 assert (n);
307 *shadow_info = xtrymalloc (n);
308 if (!*shadow_info)
309 rc = out_of_core ();
310 else
312 memcpy (*shadow_info, s, n);
313 rc = 0;
314 got_shadow_info = 1;
317 if (rc)
318 log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
320 else
321 rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
322 break;
323 default:
324 log_error ("invalid private key format\n");
325 rc = gpg_error (GPG_ERR_BAD_SECKEY);
326 break;
328 if (rc || got_shadow_info)
330 xfree (buf);
331 return rc;
334 buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
335 rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
336 wipememory (buf, buflen);
337 xfree (buf);
338 if (rc)
340 log_error ("failed to build S-Exp (off=%u): %s\n",
341 (unsigned int)erroff, gpg_strerror (rc));
342 return rc;
345 *result = s_skey;
346 return 0;
349 /* Return the secret key as an S-Exp after locating it using the grip.
350 Returns NULL if key is not available. 0 = key is available */
352 agent_key_available (const unsigned char *grip)
354 int i;
355 char *fname;
356 char hexgrip[40+4+1];
358 for (i=0; i < 20; i++)
359 sprintf (hexgrip+2*i, "%02X", grip[i]);
360 strcpy (hexgrip+40, ".key");
362 fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
363 i = !access (fname, R_OK)? 0 : -1;
364 xfree (fname);
365 return i;