* ldap.m4: New. Moved from configure.ac.
[gnupg.git] / agent / findkey.c
1 /* findkey.c - locate the secret key
2  *      Copyright (C) 2001, 2002, 2003 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 <fcntl.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <assert.h>
32
33 #include "agent.h"
34
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;
39 };
40
41
42
43 int
44 agent_write_private_key (const unsigned char *grip,
45                          const void *buffer, size_t length, int force)
46 {
47   int i;
48   char *fname;
49   FILE *fp;
50   char hexgrip[40+4+1];
51   
52   for (i=0; i < 20; i++)
53     sprintf (hexgrip+2*i, "%02X", grip[i]);
54   strcpy (hexgrip+40, ".key");
55
56   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
57   if (force)
58     fp = fopen (fname, "wb");
59   else
60     {
61       int fd;
62
63       if (!access (fname, F_OK))
64       {
65         log_error ("secret key file `%s' already exists\n", fname);
66         xfree (fname);
67         return gpg_error (GPG_ERR_GENERAL);
68       }
69
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.
75
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
83         {
84           fp = fdopen (fd, "wb");
85           if (!fp)
86             { 
87               int save_e = errno;
88               close (fd);
89               errno = save_e;
90             }
91         }
92     }
93
94   if (!fp) 
95     { 
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;
100     }
101
102   if (fwrite (buffer, length, 1, fp) != 1)
103     {
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;
110     }
111   if ( fclose (fp) )
112     {
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;
118     }
119
120   xfree (fname);
121   return 0;
122 }
123
124
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)
129 {
130   struct try_unprotect_arg_s *arg = pi->check_cb_arg;
131   size_t dummy;
132
133   assert (!arg->unprotected_key);
134   return agent_unprotect (arg->protected_key, pi->pin,
135                           &arg->unprotected_key, &dummy);
136 }
137
138
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. */
142 static int
143 unprotect (CTRL ctrl,
144            unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
145 {
146   struct pin_entry_info_s *pi;
147   struct try_unprotect_arg_s arg;
148   int rc, i;
149   unsigned char *result;
150   size_t resultlen;
151   char hexgrip[40+1];
152   
153   for (i=0; i < 20; i++)
154     sprintf (hexgrip+2*i, "%02X", grip[i]);
155   hexgrip[40] = 0;
156
157   /* first try to get it from the cache - if there is none or we can't
158      unprotect it, we fall back to ask the user */
159   if (!ignore_cache)
160     {
161       void *cache_marker;
162       const char *pw = agent_get_cache (hexgrip, &cache_marker);
163       if (pw)
164         {
165           rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
166           agent_unlock_cache_entry (&cache_marker);
167           if (!rc)
168             {
169               xfree (*keybuf);
170               *keybuf = result;
171               return 0;
172             }
173           rc  = 0;
174         }
175     }
176   
177   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
178   pi->max_length = 100;
179   pi->min_digits = 0;  /* we want a real passphrase */
180   pi->max_digits = 8;
181   pi->max_tries = 3;
182   pi->check_cb = try_unprotect_cb;
183   arg.protected_key = *keybuf;
184   arg.unprotected_key = NULL;
185   pi->check_cb_arg = &arg;
186
187   rc = agent_askpin (ctrl, NULL, pi);
188   if (!rc)
189     {
190       assert (arg.unprotected_key);
191       agent_put_cache (hexgrip, pi->pin, 0);
192       xfree (*keybuf);
193       *keybuf = arg.unprotected_key;
194     }
195   xfree (pi);
196   return rc;
197 }
198
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 or the operation should be
203    diverted to a token.  In the latter case shadow_info will point to
204    an allocated S-Expression with the shadow_info part from the file.
205    With IGNORE_CACHE passed as true the passphrase is not taken from
206    the cache.*/
207 gcry_sexp_t
208 agent_key_from_file (CTRL ctrl,
209                      const unsigned char *grip, unsigned char **shadow_info,
210                      int ignore_cache)
211 {
212   int i, rc;
213   char *fname;
214   FILE *fp;
215   struct stat st;
216   unsigned char *buf;
217   size_t len, buflen, erroff;
218   gcry_sexp_t s_skey;
219   char hexgrip[40+4+1];
220   
221   if (shadow_info)
222       *shadow_info = NULL;
223
224   for (i=0; i < 20; i++)
225     sprintf (hexgrip+2*i, "%02X", grip[i]);
226   strcpy (hexgrip+40, ".key");
227
228   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
229   fp = fopen (fname, "rb");
230   if (!fp)
231     {
232       log_error ("can't open `%s': %s\n", fname, strerror (errno));
233       xfree (fname);
234       return NULL;
235     }
236   
237   if (fstat (fileno(fp), &st))
238     {
239       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
240       xfree (fname);
241       fclose (fp);
242       return NULL;
243     }
244
245   buflen = st.st_size;
246   buf = xmalloc (buflen+1);
247   if (fread (buf, buflen, 1, fp) != 1)
248     {
249       log_error ("error reading `%s': %s\n", fname, strerror (errno));
250       xfree (fname);
251       fclose (fp);
252       xfree (buf);
253       return NULL;
254     }
255
256   rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
257   xfree (fname);
258   fclose (fp);
259   xfree (buf);
260   if (rc)
261     {
262       log_error ("failed to build S-Exp (off=%u): %s\n",
263                  (unsigned int)erroff, gpg_strerror (rc));
264       return NULL;
265     }
266   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
267   assert (len);
268   buf = xtrymalloc (len);
269   if (!buf)
270     {
271       gcry_sexp_release (s_skey);
272       return NULL;
273     }
274   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
275   assert (len);
276   gcry_sexp_release (s_skey);
277
278   switch (agent_private_key_type (buf))
279     {
280     case PRIVATE_KEY_CLEAR:
281       break; /* no unprotection needed */
282     case PRIVATE_KEY_PROTECTED:
283       rc = unprotect (ctrl, &buf, grip, ignore_cache);
284       if (rc)
285         log_error ("failed to unprotect the secret key: %s\n",
286                    gpg_strerror (rc));
287       break;
288     case PRIVATE_KEY_SHADOWED:
289       if (shadow_info)
290         {
291           const unsigned char *s;
292           size_t n;
293
294           rc = agent_get_shadow_info (buf, &s);
295           if (!rc)
296             {
297               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
298               assert (n);
299               *shadow_info = xtrymalloc (n);
300               if (!*shadow_info)
301                 rc = out_of_core ();
302               else
303                 {
304                   memcpy (*shadow_info, s, n);
305                   rc = 0;
306                 }
307             }
308           if (rc)
309             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
310         }
311       rc = -1; /* ugly interface: we return an error but keep a value
312                   in shadow_info.  */
313       break;
314     default:
315       log_error ("invalid private key format\n");
316       rc = gpg_error (GPG_ERR_BAD_SECKEY);
317       break;
318     }
319   if (rc)
320     {
321       xfree (buf);
322       return NULL;
323     }
324
325   /* arggg FIXME: does scan support secure memory? */
326   rc = gcry_sexp_sscan (&s_skey, &erroff,
327                         buf, gcry_sexp_canon_len (buf, 0, NULL, NULL));
328   xfree (buf);
329   if (rc)
330     {
331       log_error ("failed to build S-Exp (off=%u): %s\n",
332                  (unsigned int)erroff, gpg_strerror (rc));
333       return NULL;
334     }
335
336   return s_skey;
337 }
338
339 /* Return the secret key as an S-Exp after locating it using the grip.
340    Returns NULL if key is not available. 0 = key is available */
341 int
342 agent_key_available (const unsigned char *grip)
343 {
344   int i;
345   char *fname;
346   char hexgrip[40+4+1];
347   
348   for (i=0; i < 20; i++)
349     sprintf (hexgrip+2*i, "%02X", grip[i]);
350   strcpy (hexgrip+40, ".key");
351
352   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
353   i = !access (fname, R_OK)? 0 : -1;
354   xfree (fname);
355   return i;
356 }
357
358
359