gcc-4 defaults forced me to edit many many files to get rid of the
[gnupg.git] / agent / findkey.c
1 /* findkey.c - locate the secret key
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005 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 /* Write an S-expression formatted key to our key storage.  With FORCE
43    pased as true an existsing key with the given GRIP will get
44    overwritten.  */
45 int
46 agent_write_private_key (const unsigned char *grip,
47                          const void *buffer, size_t length, int force)
48 {
49   int i;
50   char *fname;
51   FILE *fp;
52   char hexgrip[40+4+1];
53   int fd;
54   
55   for (i=0; i < 20; i++)
56     sprintf (hexgrip+2*i, "%02X", grip[i]);
57   strcpy (hexgrip+40, ".key");
58
59   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
60
61   if (!force && !access (fname, F_OK))
62     {
63       log_error ("secret key file `%s' already exists\n", fname);
64       xfree (fname);
65       return gpg_error (GPG_ERR_GENERAL);
66     }
67
68   /* In FORCE mode we would like to create FNAME but only if it does
69      not already exist.  We cannot make this guarantee just using
70      POSIX (GNU provides the "x" opentype for fopen, however, this is
71      not portable).  Thus, we use the more flexible open function and
72      then use fdopen to obtain a stream. */
73   fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY)
74                          : (O_CREAT | O_EXCL | O_WRONLY),
75              S_IRUSR | S_IWUSR 
76 #ifndef HAVE_W32_SYSTEM
77                  | S_IRGRP 
78 #endif
79                  );
80   if (fd < 0)
81     fp = NULL;
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   if (!fp) 
94     { 
95       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
96       log_error ("can't create `%s': %s\n", fname, strerror (errno));
97       xfree (fname);
98       return tmperr;
99     }
100
101   if (fwrite (buffer, length, 1, fp) != 1)
102     {
103       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
104       log_error ("error writing `%s': %s\n", fname, strerror (errno));
105       fclose (fp);
106       remove (fname);
107       xfree (fname);
108       return tmperr;
109     }
110   if ( fclose (fp) )
111     {
112       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
113       log_error ("error closing `%s': %s\n", fname, strerror (errno));
114       remove (fname);
115       xfree (fname);
116       return tmperr;
117     }
118
119   xfree (fname);
120   return 0;
121 }
122
123
124 /* Callback function to try the unprotection from the passpharse query
125    code. */
126 static int
127 try_unprotect_cb (struct pin_entry_info_s *pi)
128 {
129   struct try_unprotect_arg_s *arg = pi->check_cb_arg;
130   size_t dummy;
131
132   assert (!arg->unprotected_key);
133   return agent_unprotect (arg->protected_key, pi->pin,
134                           &arg->unprotected_key, &dummy);
135 }
136
137
138 /* Modify a Key description, replacing certain special format
139    characters.  List of currently supported replacements:
140
141    %% - Replaced by a single %
142    %c - Replaced by the content of COMMENT.
143
144    The functions returns 0 on success or an error code.  On success a
145    newly allocated string is stored at the address of RESULT.
146  */
147 static gpg_error_t
148 modify_description (const char *in, const char *comment, char **result)
149 {
150   size_t comment_length;
151   size_t in_len;
152   size_t out_len;
153   char *out;
154   size_t i;
155   int special, pass;
156
157   comment_length = strlen (comment);
158   in_len  = strlen (in);
159
160   /* First pass calculates the length, second pass does the actual
161      copying.  */
162   out = NULL;
163   out_len = 0;
164   for (pass=0; pass < 2; pass++)
165     {
166       special = 0;
167       for (i = 0; i < in_len; i++)
168         {
169           if (special)
170             {
171               special = 0;
172               switch (in[i])
173                 {
174                 case '%':
175                   if (out)
176                     *out++ = '%';
177                   else
178                     out_len++;
179                   break;
180
181                 case 'c': /* Comment.  */
182                   if (out)
183                     {
184                       memcpy (out, comment, comment_length);
185                       out += comment_length;
186                     }
187                   else
188                     out_len += comment_length;
189                   break;
190
191                 default: /* Invalid special sequences are kept as they are. */
192                   if (out)
193                     {
194                       *out++ = '%';
195                       *out++ = in[i];
196                     }
197                   else
198                     out_len+=2;
199                   break;
200                 }
201             }
202           else if (in[i] == '%')
203             special = 1;
204           else
205             {
206               if (out)
207                 *out++ = in[i];
208               else
209                 out_len++;
210             }
211         }
212       
213       if (!pass)
214         {
215           *result = out = xtrymalloc (out_len + 1);
216           if (!out)
217             return gpg_error_from_errno (errno);
218         }
219     }
220
221   *out = 0;
222   assert (*result + out_len == out);
223   return 0;
224 }
225
226   
227
228 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
229    should be the hex encoded keygrip of that key to be used with the
230    caching mechanism. DESC_TEXT may be set to override the default
231    description used for the pinentry. */
232 static int
233 unprotect (ctrl_t ctrl, const char *desc_text,
234            unsigned char **keybuf, const unsigned char *grip, 
235            cache_mode_t cache_mode)
236 {
237   struct pin_entry_info_s *pi;
238   struct try_unprotect_arg_s arg;
239   int rc, i;
240   unsigned char *result;
241   size_t resultlen;
242   char hexgrip[40+1];
243   
244   for (i=0; i < 20; i++)
245     sprintf (hexgrip+2*i, "%02X", grip[i]);
246   hexgrip[40] = 0;
247
248   /* First try to get it from the cache - if there is none or we can't
249      unprotect it, we fall back to ask the user */
250   if (cache_mode != CACHE_MODE_IGNORE)
251     {
252       void *cache_marker;
253       const char *pw;
254       
255       pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
256       if (pw)
257         {
258           rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
259           agent_unlock_cache_entry (&cache_marker);
260           if (!rc)
261             {
262               xfree (*keybuf);
263               *keybuf = result;
264               return 0;
265             }
266           rc  = 0;
267         }
268     }
269   
270   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
271   if (!pi)
272     return gpg_error_from_errno (errno);
273   pi->max_length = 100;
274   pi->min_digits = 0;  /* we want a real passphrase */
275   pi->max_digits = 8;
276   pi->max_tries = 3;
277   pi->check_cb = try_unprotect_cb;
278   arg.protected_key = *keybuf;
279   arg.unprotected_key = NULL;
280   pi->check_cb_arg = &arg;
281
282   rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
283   if (!rc)
284     {
285       assert (arg.unprotected_key);
286       agent_put_cache (hexgrip, cache_mode, pi->pin, 0);
287       xfree (*keybuf);
288       *keybuf = arg.unprotected_key;
289     }
290   xfree (pi);
291   return rc;
292 }
293
294
295 /* Read the key identified by GRIP from the private key directory and
296    return it as an gcrypt S-expression object in RESULT.  On failure
297    returns an error code and stores NULL at RESULT. */
298 static gpg_error_t
299 read_key_file (const unsigned char *grip, gcry_sexp_t *result)
300 {
301   int i, rc;
302   char *fname;
303   FILE *fp;
304   struct stat st;
305   unsigned char *buf;
306   size_t buflen, erroff;
307   gcry_sexp_t s_skey;
308   char hexgrip[40+4+1];
309   
310   *result = NULL;
311
312   for (i=0; i < 20; i++)
313     sprintf (hexgrip+2*i, "%02X", grip[i]);
314   strcpy (hexgrip+40, ".key");
315
316   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
317   fp = fopen (fname, "rb");
318   if (!fp)
319     {
320       rc = gpg_error_from_errno (errno);
321       log_error ("can't open `%s': %s\n", fname, strerror (errno));
322       xfree (fname);
323       return rc;
324     }
325   
326   if (fstat (fileno(fp), &st))
327     {
328       rc = gpg_error_from_errno (errno);
329       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
330       xfree (fname);
331       fclose (fp);
332       return rc;
333     }
334
335   buflen = st.st_size;
336   buf = xtrymalloc (buflen+1);
337   if (!buf || fread (buf, buflen, 1, fp) != 1)
338     {
339       rc = gpg_error_from_errno (errno);
340       log_error ("error reading `%s': %s\n", fname, strerror (errno));
341       xfree (fname);
342       fclose (fp);
343       xfree (buf);
344       return rc;
345     }
346
347   /* Convert the file into a gcrypt S-expression object.  */
348   rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
349   xfree (fname);
350   fclose (fp);
351   xfree (buf);
352   if (rc)
353     {
354       log_error ("failed to build S-Exp (off=%u): %s\n",
355                  (unsigned int)erroff, gpg_strerror (rc));
356       return rc;
357     }
358   *result = s_skey;
359   return 0;
360 }
361
362
363 /* Return the secret key as an S-Exp in RESULT after locating it using
364    the grip.  Returns NULL in RESULT if the operation should be
365    diverted to a token; SHADOW_INFO will point then to an allocated
366    S-Expression with the shadow_info part from the file.  CACHE_MODE
367    defines now the cache shall be used.  DESC_TEXT may be set to
368    present a custom description for the pinentry. */
369 gpg_error_t
370 agent_key_from_file (ctrl_t ctrl, const char *desc_text,
371                      const unsigned char *grip, unsigned char **shadow_info,
372                      cache_mode_t cache_mode, gcry_sexp_t *result)
373 {
374   int rc;
375   unsigned char *buf;
376   size_t len, buflen, erroff;
377   gcry_sexp_t s_skey;
378   int got_shadow_info = 0;
379   
380   *result = NULL;
381   if (shadow_info)
382       *shadow_info = NULL;
383
384   rc = read_key_file (grip, &s_skey);
385   if (rc)
386     return rc;
387
388   /* For use with the protection functions we also need the key as an
389      canonical encoded S-expression in abuffer.  Create this buffer
390      now.  */
391   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
392   assert (len);
393   buf = xtrymalloc (len);
394   if (!buf)
395     {
396       rc = gpg_error_from_errno (errno);
397       gcry_sexp_release (s_skey);
398       return rc;
399     }
400   len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
401   assert (len);
402
403
404   switch (agent_private_key_type (buf))
405     {
406     case PRIVATE_KEY_CLEAR:
407       break; /* no unprotection needed */
408     case PRIVATE_KEY_PROTECTED:
409       {
410         gcry_sexp_t comment_sexp;
411         size_t comment_length;
412         char *desc_text_final;
413         const char *comment = NULL;
414
415         /* Note, that we will take the comment as a C string for
416            display purposes; i.e. all stuff beyond a Nul character is
417            ignored.  */
418         comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
419         if (comment_sexp)
420           comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
421         if (!comment)
422           {
423             comment = "";
424             comment_length = 0;
425           }
426
427         desc_text_final = NULL;
428         if (desc_text)
429           {
430             if (comment[comment_length])
431               {
432                 /* Not a C-string; create one.  We might here allocate
433                    more than actually displayed but well, that
434                    shouldn't be a problem.  */
435                 char *tmp = xtrymalloc (comment_length+1);
436                 if (!tmp)
437                   rc = gpg_error_from_errno (errno);
438                 else
439                   {
440                     memcpy (tmp, comment, comment_length);
441                     tmp[comment_length] = 0;
442                     rc = modify_description (desc_text, tmp, &desc_text_final);
443                     xfree (tmp);
444                   }
445               }
446             else
447               rc = modify_description (desc_text, comment, &desc_text_final);
448           }
449
450         if (!rc)
451           {
452             rc = unprotect (ctrl, desc_text_final, &buf, grip, cache_mode);
453             if (rc)
454               log_error ("failed to unprotect the secret key: %s\n",
455                          gpg_strerror (rc));
456           }
457         
458         gcry_sexp_release (comment_sexp);
459         xfree (desc_text_final);
460       }
461       break;
462     case PRIVATE_KEY_SHADOWED:
463       if (shadow_info)
464         {
465           const unsigned char *s;
466           size_t n;
467
468           rc = agent_get_shadow_info (buf, &s);
469           if (!rc)
470             {
471               n = gcry_sexp_canon_len (s, 0, NULL,NULL);
472               assert (n);
473               *shadow_info = xtrymalloc (n);
474               if (!*shadow_info)
475                 rc = out_of_core ();
476               else
477                 {
478                   memcpy (*shadow_info, s, n);
479                   rc = 0;
480                   got_shadow_info = 1;
481                 }
482             }
483           if (rc)
484             log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
485         }
486       else
487         rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
488       break;
489     default:
490       log_error ("invalid private key format\n");
491       rc = gpg_error (GPG_ERR_BAD_SECKEY);
492       break;
493     }
494   gcry_sexp_release (s_skey);
495   s_skey = NULL;
496   if (rc || got_shadow_info)
497     {
498       xfree (buf);
499       return rc;
500     }
501
502   buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
503   rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
504   wipememory (buf, buflen);
505   xfree (buf);
506   if (rc)
507     {
508       log_error ("failed to build S-Exp (off=%u): %s\n",
509                  (unsigned int)erroff, gpg_strerror (rc));
510       return rc;
511     }
512
513   *result = s_skey;
514   return 0;
515 }
516
517
518
519 /* Return the public key for the keygrip GRIP.  The result is stored
520    at RESULT.  This function extracts the public key from the private
521    key database.  On failure an error code is returned and NULL stored
522    at RESULT. */
523 gpg_error_t
524 agent_public_key_from_file (ctrl_t ctrl, 
525                             const unsigned char *grip,
526                             gcry_sexp_t *result)
527 {
528   int i, idx, rc;
529   gcry_sexp_t s_skey;
530   const char *algoname;
531   gcry_sexp_t uri_sexp, comment_sexp;
532   const char *uri, *comment;
533   size_t uri_length, comment_length;
534   char *format, *p;
535   void *args[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2
536                            for comment + end-of-list.  */
537   int argidx;
538   gcry_sexp_t list, l2;
539   const char *name;
540   const char *s;
541   size_t n;
542   const char *elems;
543   gcry_mpi_t *array;
544
545   *result = NULL;
546
547   rc = read_key_file (grip, &s_skey);
548   if (rc)
549     return rc;
550
551   list = gcry_sexp_find_token (s_skey, "shadowed-private-key", 0 );
552   if (!list)
553     list = gcry_sexp_find_token (s_skey, "protected-private-key", 0 );
554   if (!list)
555     list = gcry_sexp_find_token (s_skey, "private-key", 0 );
556   if (!list)
557     {
558       log_error ("invalid private key format\n");
559       gcry_sexp_release (s_skey);
560       return gpg_error (GPG_ERR_BAD_SECKEY);
561     }
562
563   l2 = gcry_sexp_cadr (list);
564   gcry_sexp_release (list);
565   list = l2;
566   name = gcry_sexp_nth_data (list, 0, &n);
567   if (n==3 && !memcmp (name, "rsa", 3))
568     {
569       algoname = "rsa";
570       elems = "ne";
571     }
572   else if (n==3 && !memcmp (name, "dsa", 3))
573     {
574       algoname = "dsa";
575       elems = "pqgy";
576     }
577   else if (n==3 && !memcmp (name, "elg", 3))
578     {
579       algoname = "elg";
580       elems = "pgy";
581     }
582   else
583     {
584       log_error ("unknown private key algorithm\n");
585       gcry_sexp_release (list);
586       gcry_sexp_release (s_skey);
587       return gpg_error (GPG_ERR_BAD_SECKEY);
588     }
589
590   /* Allocate an array for the parameters and copy them out of the
591      secret key.   FIXME: We should have a generic copy function. */
592   array = xtrycalloc (strlen(elems) + 1, sizeof *array);
593   if (!array)
594     {
595       rc = gpg_error_from_errno (errno);
596       gcry_sexp_release (list);
597       gcry_sexp_release (s_skey);
598       return rc;
599     }
600
601   for (idx=0, s=elems; *s; s++, idx++ ) 
602     {
603       l2 = gcry_sexp_find_token (list, s, 1);
604       if (!l2)
605         {
606           /* Required parameter not found.  */
607           for (i=0; i<idx; i++)
608             gcry_mpi_release (array[i]);
609           xfree (array);
610           gcry_sexp_release (list);
611           gcry_sexp_release (s_skey);
612           return gpg_error (GPG_ERR_BAD_SECKEY);
613         }
614       array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
615       gcry_sexp_release (l2);
616       if (!array[idx])
617         {
618           /* Required parameter is invalid. */
619           for (i=0; i<idx; i++)
620             gcry_mpi_release (array[i]);
621           xfree (array);
622           gcry_sexp_release (list);
623           gcry_sexp_release (s_skey);
624           return gpg_error (GPG_ERR_BAD_SECKEY);
625         }
626     }
627   gcry_sexp_release (list);
628   list = NULL;
629
630   uri = NULL;
631   uri_length = 0;
632   uri_sexp = gcry_sexp_find_token (s_skey, "uri", 0);
633   if (uri_sexp)
634     uri = gcry_sexp_nth_data (uri_sexp, 1, &uri_length);
635
636   comment = NULL;
637   comment_length = 0;
638   comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
639   if (comment_sexp)
640     comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
641
642   gcry_sexp_release (s_skey);
643   s_skey = NULL;
644
645
646   /* FIXME: The following thing is pretty ugly code; we should
647      investigate how to make it cleaner. Probably code to handle
648      canonical S-expressions in a memory buffer is better suioted for
649      such a task.  After all that is what we do in protect.c.  Neeed
650      to find common patterns and write a straightformward API to use
651      them.  */
652   assert (sizeof (size_t) <= sizeof (void*));
653
654   format = xtrymalloc (15+7*strlen (elems)+10+15+1+1);
655   if (!format)
656     {
657       rc = gpg_error_from_errno (errno);
658       for (i=0; array[i]; i++)
659         gcry_mpi_release (array[i]);
660       xfree (array);
661       gcry_sexp_release (uri_sexp);
662       gcry_sexp_release (comment_sexp);
663       return rc;
664     }
665
666   argidx = 0;
667   p = stpcpy (stpcpy (format, "(public-key("), algoname);
668   for (idx=0, s=elems; *s; s++, idx++ ) 
669     {
670       *p++ = '(';
671       *p++ = *s;
672       p = stpcpy (p, " %m)");
673       assert (argidx < DIM (args));
674       args[argidx++] = array[idx];
675     }
676   *p++ = ')';
677   if (uri)
678     {
679       p = stpcpy (p, "(uri %b)");
680       assert (argidx+1 < DIM (args));
681       args[argidx++] = (void *)uri_length;
682       args[argidx++] = (void *)uri;
683     }
684   if (comment)
685     {
686       p = stpcpy (p, "(comment %b)");
687       assert (argidx+1 < DIM (args));
688       args[argidx++] = (void *)comment_length;
689       args[argidx++] = (void*)comment;
690     }
691   *p++ = ')';
692   *p = 0;
693   assert (argidx < DIM (args));
694   args[argidx] = NULL;
695     
696   rc = gcry_sexp_build_array (&list, NULL, format, args);
697   xfree (format);
698   for (i=0; array[i]; i++)
699     gcry_mpi_release (array[i]);
700   xfree (array);
701   gcry_sexp_release (uri_sexp);
702   gcry_sexp_release (comment_sexp);
703
704   if (!rc)
705     *result = list;
706   return rc;
707 }
708
709
710
711 /* Return the secret key as an S-Exp after locating it using the grip.
712    Returns NULL if key is not available. 0 = key is available */
713 int
714 agent_key_available (const unsigned char *grip)
715 {
716   int i;
717   char *fname;
718   char hexgrip[40+4+1];
719   
720   for (i=0; i < 20; i++)
721     sprintf (hexgrip+2*i, "%02X", grip[i]);
722   strcpy (hexgrip+40, ".key");
723
724   fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
725   i = !access (fname, R_OK)? 0 : -1;
726   xfree (fname);
727   return i;
728 }
729
730
731