* gpg-agent.c (handle_signal): Reload the trustlist on SIGHUP.
[gnupg.git] / agent / protect-tool.c
1 /* protect-tool.c - A tool to test the secret key protection
2  *      Copyright (C) 2002, 2003, 2004 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
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #define JNLIB_NEED_LOG_LOGV
34 #include "agent.h"
35 #include "minip12.h"
36 #include "simple-pwquery.h"
37 #include "i18n.h"
38
39 enum cmd_and_opt_values 
40 { aNull = 0,
41   oVerbose        = 'v',
42   oArmor          = 'a',
43   oPassphrase     = 'P',
44
45   oProtect        = 'p',
46   oUnprotect      = 'u',
47   
48   oNoVerbose = 500,
49   oShadow,
50   oShowShadowInfo,
51   oShowKeygrip,
52
53   oP12Import,
54   oP12Export,
55   oStore,
56   oForce,
57   oHaveCert,
58   oNoFailOnExist,
59   oHomedir,
60   oPrompt,
61   oStatusMsg, 
62
63 aTest };
64
65 struct rsa_secret_key_s 
66   {
67     gcry_mpi_t n;           /* public modulus */
68     gcry_mpi_t e;           /* public exponent */
69     gcry_mpi_t d;           /* exponent */
70     gcry_mpi_t p;           /* prime  p. */
71     gcry_mpi_t q;           /* prime  q. */
72     gcry_mpi_t u;           /* inverse of p mod q. */
73   };
74
75
76 static char *opt_homedir;
77 static int opt_armor;
78 static int opt_store;
79 static int opt_force;
80 static int opt_no_fail_on_exist;
81 static int opt_have_cert;
82 static const char *opt_passphrase;
83 static char *opt_prompt;
84 static int opt_status_msg;
85
86 static char *get_passphrase (int promptno);
87 static void release_passphrase (char *pw);
88 static int store_private_key (const unsigned char *grip,
89                               const void *buffer, size_t length, int force);
90
91
92 static ARGPARSE_OPTS opts[] = {
93   
94   { 301, NULL, 0, N_("@Options:\n ") },
95
96   { oVerbose, "verbose",   0, "verbose" },
97   { oArmor,   "armor",     0, "write output in advanced format" },
98   { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" },
99   { oProtect, "protect",     256, "protect a private key"},
100   { oUnprotect, "unprotect", 256, "unprotect a private key"},
101   { oShadow,  "shadow", 256, "create a shadow entry for a priblic key"},
102   { oShowShadowInfo,  "show-shadow-info", 256, "return the shadow info"},
103   { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},
104
105   { oP12Import, "p12-import", 256, "import a PKCS-12 encoded private key"},
106   { oP12Export, "p12-export", 256, "export a private key PKCS-12 encoded"},
107   { oHaveCert, "have-cert", 0,  "certificate to export provided on STDIN"},
108   { oStore,     "store", 0, "store the created key in the appropriate place"},
109   { oForce,     "force", 0, "force overwriting"},
110   { oNoFailOnExist, "no-fail-on-exist", 0, "@" },
111   { oHomedir, "homedir", 2, "@" }, 
112   { oPrompt,  "prompt", 2, "|ESCSTRING|use ESCSTRING as prompt in pinentry"}, 
113   { oStatusMsg, "enable-status-msg", 0, "@"},
114   {0}
115 };
116
117 static const char *
118 my_strusage (int level)
119 {
120   const char *p;
121   switch (level)
122     {
123     case 11: p = "gpg-protect-tool (GnuPG)";
124       break;
125     case 13: p = VERSION; break;
126     case 17: p = PRINTABLE_OS_NAME; break;
127     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
128       break;
129     case 1:
130     case 40: p =  _("Usage: gpg-protect-tool [options] (-h for help)\n");
131       break;
132     case 41: p =  _("Syntax: gpg-protect-tool [options] [args]]\n"
133                     "Secret key maintenance tool\n");
134     break;
135     
136     default: p = NULL;
137     }
138   return p;
139 }
140
141
142
143 static void
144 i18n_init (void)
145 {
146 #ifdef USE_SIMPLE_GETTEXT
147     set_gettext_file( PACKAGE_GT );
148 #else
149 #ifdef ENABLE_NLS
150     setlocale (LC_ALL, "");
151     bindtextdomain (PACKAGE_GT, LOCALEDIR);
152     textdomain (PACKAGE_GT);
153 #endif
154 #endif
155 }
156
157
158
159 /* Used by gcry for logging */
160 static void
161 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
162 {
163   /* translate the log levels */
164   switch (level)
165     {
166     case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
167     case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
168     case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
169     case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
170     case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
171     case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
172     case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
173     default:            level = JNLIB_LOG_ERROR; break;      }
174   log_logv (level, fmt, arg_ptr);
175 }
176
177
178 /*  static void */
179 /*  print_mpi (const char *text, gcry_mpi_t a) */
180 /*  { */
181 /*    char *buf; */
182 /*    void *bufaddr = &buf; */
183 /*    int rc; */
184
185 /*    rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
186 /*    if (rc) */
187 /*      log_info ("%s: [error printing number: %s]\n", text, gpg_strerror (rc)); */
188 /*    else */
189 /*      { */
190 /*        log_info ("%s: %s\n", text, buf); */
191 /*        gcry_free (buf); */
192 /*      } */
193 /*  } */
194
195
196 \f
197 static unsigned char *
198 make_canonical (const char *fname, const char *buf, size_t buflen)
199 {
200   int rc;
201   size_t erroff, len;
202   gcry_sexp_t sexp;
203   unsigned char *result;
204
205   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
206   if (rc)
207     {
208       log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
209                  fname, (unsigned int)erroff, gpg_strerror (rc));
210       return NULL;
211     }
212   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
213   assert (len);
214   result = xmalloc (len);
215   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
216   assert (len);
217   gcry_sexp_release (sexp);
218   return result;
219 }
220
221 static char *
222 make_advanced (const unsigned char *buf, size_t buflen)
223 {
224   int rc;
225   size_t erroff, len;
226   gcry_sexp_t sexp;
227   unsigned char *result;
228
229   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
230   if (rc)
231     {
232       log_error ("invalid canonical S-Expression (off=%u): %s\n",
233                  (unsigned int)erroff, gpg_strerror (rc));
234       return NULL;
235     }
236   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
237   assert (len);
238   result = xmalloc (len);
239   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
240   assert (len);
241   gcry_sexp_release (sexp);
242   return result;
243 }
244
245
246 static char *
247 read_file (const char *fname, size_t *r_length)
248 {
249   FILE *fp;
250   char *buf;
251   size_t buflen;
252   
253   if (!strcmp (fname, "-"))
254     {
255       size_t nread, bufsize = 0;
256
257       fp = stdin;
258       buf = NULL;
259       buflen = 0;
260 #define NCHUNK 8192
261       do 
262         {
263           bufsize += NCHUNK;
264           if (!buf)
265             buf = xmalloc (bufsize);
266           else
267             buf = xrealloc (buf, bufsize);
268
269           nread = fread (buf+buflen, 1, NCHUNK, fp);
270           if (nread < NCHUNK && ferror (fp))
271             {
272               log_error ("error reading `[stdin]': %s\n", strerror (errno));
273               xfree (buf);
274               return NULL;
275             }
276           buflen += nread;
277         }
278       while (nread == NCHUNK);
279 #undef NCHUNK
280
281     }
282   else
283     {
284       struct stat st;
285
286       fp = fopen (fname, "rb");
287       if (!fp)
288         {
289           log_error ("can't open `%s': %s\n", fname, strerror (errno));
290           return NULL;
291         }
292   
293       if (fstat (fileno(fp), &st))
294         {
295           log_error ("can't stat `%s': %s\n", fname, strerror (errno));
296           fclose (fp);
297           return NULL;
298         }
299       
300       buflen = st.st_size;
301       buf = xmalloc (buflen+1);
302       if (fread (buf, buflen, 1, fp) != 1)
303         {
304           log_error ("error reading `%s': %s\n", fname, strerror (errno));
305           fclose (fp);
306           xfree (buf);
307           return NULL;
308         }
309       fclose (fp);
310     }
311
312   *r_length = buflen;
313   return buf;
314 }
315
316
317 static unsigned char *
318 read_key (const char *fname)
319 {
320   char *buf;
321   size_t buflen;
322   unsigned char *key;
323   
324   buf = read_file (fname, &buflen);
325   if (!buf)
326     return NULL;
327   key = make_canonical (fname, buf, buflen);
328   xfree (buf);
329   return key;
330 }
331
332
333 \f
334 static void
335 read_and_protect (const char *fname)
336 {
337   int  rc;
338   unsigned char *key;
339   unsigned char *result;
340   size_t resultlen;
341   char *pw;
342   
343   key = read_key (fname);
344   if (!key)
345     return;
346
347   pw = get_passphrase (1);
348   rc = agent_protect (key, pw, &result, &resultlen);
349   release_passphrase (pw);
350   xfree (key);
351   if (rc)
352     {
353       log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
354       return;
355     }
356   
357   if (opt_armor)
358     {
359       char *p = make_advanced (result, resultlen);
360       xfree (result);
361       if (!p)
362         return;
363       result = p;
364       resultlen = strlen (p);
365     }
366
367   fwrite (result, resultlen, 1, stdout);
368   xfree (result);
369 }
370
371
372 static void
373 read_and_unprotect (const char *fname)
374 {
375   int  rc;
376   unsigned char *key;
377   unsigned char *result;
378   size_t resultlen;
379   char *pw;
380   
381   key = read_key (fname);
382   if (!key)
383     return;
384
385   rc = agent_unprotect (key, (pw=get_passphrase (1)), &result, &resultlen);
386   release_passphrase (pw);
387   xfree (key);
388   if (rc)
389     {
390       if (opt_status_msg)
391         log_info ("[PROTECT-TOOL:] bad-passphrase\n");
392       log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
393       return;
394     }
395   
396   if (opt_armor)
397     {
398       char *p = make_advanced (result, resultlen);
399       xfree (result);
400       if (!p)
401         return;
402       result = p;
403       resultlen = strlen (p);
404     }
405
406   fwrite (result, resultlen, 1, stdout);
407   xfree (result);
408 }
409
410
411 \f
412 static void
413 read_and_shadow (const char *fname)
414 {
415   int  rc;
416   unsigned char *key;
417   unsigned char *result;
418   size_t resultlen;
419   
420   key = read_key (fname);
421   if (!key)
422     return;
423
424   rc = agent_shadow_key (key, "(8:313233342:43)", &result);
425   xfree (key);
426   if (rc)
427     {
428       log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
429       return;
430     }
431   resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
432   assert (resultlen);
433   
434   if (opt_armor)
435     {
436       char *p = make_advanced (result, resultlen);
437       xfree (result);
438       if (!p)
439         return;
440       result = p;
441       resultlen = strlen (p);
442     }
443
444   fwrite (result, resultlen, 1, stdout);
445   xfree (result);
446 }
447
448 static void
449 show_shadow_info (const char *fname)
450 {
451   int  rc;
452   unsigned char *key;
453   const unsigned char *info;
454   size_t infolen;
455   
456   key = read_key (fname);
457   if (!key)
458     return;
459
460   rc = agent_get_shadow_info (key, &info);
461   xfree (key);
462   if (rc)
463     {
464       log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
465       return;
466     }
467   infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
468   assert (infolen);
469   
470   if (opt_armor)
471     {
472       char *p = make_advanced (info, infolen);
473       if (!p)
474         return;
475       fwrite (p, strlen (p), 1, stdout);
476       xfree (p);
477     }
478   else
479     fwrite (info, infolen, 1, stdout);
480 }
481
482
483 static void
484 show_file (const char *fname)
485 {
486   unsigned char *key;
487   size_t keylen;
488   char *p;
489   
490   key = read_key (fname);
491   if (!key)
492     return;
493
494   keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
495   assert (keylen);
496
497   p = make_advanced (key, keylen);
498   xfree (key);
499   if (p)
500     {
501       fwrite (p, strlen (p), 1, stdout);
502       xfree (p);
503     }
504 }
505
506 static void
507 show_keygrip (const char *fname)
508 {
509   unsigned char *key;
510   gcry_sexp_t private;
511   unsigned char grip[20];
512   int i;
513   
514   key = read_key (fname);
515   if (!key)
516     return;
517
518   if (gcry_sexp_new (&private, key, 0, 0))
519     {
520       log_error ("gcry_sexp_new failed\n");
521       return;
522     } 
523   xfree (key);
524
525   if (!gcry_pk_get_keygrip (private, grip))
526     {
527       log_error ("can't calculate keygrip\n");
528       return;
529     }
530   gcry_sexp_release (private);
531
532   for (i=0; i < 20; i++)
533     printf ("%02X", grip[i]);
534   putchar ('\n');
535 }
536
537 \f
538 static int
539 rsa_key_check (struct rsa_secret_key_s *skey)
540 {
541   int err = 0;
542   gcry_mpi_t t = gcry_mpi_snew (0);
543   gcry_mpi_t t1 = gcry_mpi_snew (0);
544   gcry_mpi_t t2 = gcry_mpi_snew (0);
545   gcry_mpi_t phi = gcry_mpi_snew (0);
546
547   /* check that n == p * q */
548   gcry_mpi_mul (t, skey->p, skey->q);
549   if (gcry_mpi_cmp( t, skey->n) )
550     {
551       log_error ("RSA oops: n != p * q\n");
552       err++;
553     }
554
555   /* check that p is less than q */
556   if (gcry_mpi_cmp (skey->p, skey->q) > 0)
557     {
558       gcry_mpi_t tmp;
559
560       log_info ("swapping secret primes\n");
561       tmp = gcry_mpi_copy (skey->p);
562       gcry_mpi_set (skey->p, skey->q);
563       gcry_mpi_set (skey->q, tmp);
564       gcry_mpi_release (tmp);
565       /* and must recompute u of course */
566       gcry_mpi_invm (skey->u, skey->p, skey->q);
567     }
568
569   /* check that e divides neither p-1 nor q-1 */
570   gcry_mpi_sub_ui (t, skey->p, 1 );
571   gcry_mpi_div (NULL, t, t, skey->e, 0);
572   if (!gcry_mpi_cmp_ui( t, 0) )
573     {
574       log_error ("RSA oops: e divides p-1\n");
575       err++;
576     }
577   gcry_mpi_sub_ui (t, skey->q, 1);
578   gcry_mpi_div (NULL, t, t, skey->e, 0);
579   if (!gcry_mpi_cmp_ui( t, 0))
580     {
581       log_info ( "RSA oops: e divides q-1\n" );
582       err++;
583     }
584
585   /* check that d is correct. */
586   gcry_mpi_sub_ui (t1, skey->p, 1);
587   gcry_mpi_sub_ui (t2, skey->q, 1);
588   gcry_mpi_mul (phi, t1, t2);
589   gcry_mpi_invm (t, skey->e, phi);
590   if (gcry_mpi_cmp (t, skey->d))
591     { /* no: try universal exponent. */
592       gcry_mpi_gcd (t, t1, t2);
593       gcry_mpi_div (t, NULL, phi, t, 0);
594       gcry_mpi_invm (t, skey->e, t);
595       if (gcry_mpi_cmp (t, skey->d))
596         {
597           log_error ("RSA oops: bad secret exponent\n");
598           err++;
599         }
600     }
601
602   /* check for correctness of u */
603   gcry_mpi_invm (t, skey->p, skey->q);
604   if (gcry_mpi_cmp (t, skey->u))
605     {
606       log_info ( "RSA oops: bad u parameter\n");
607       err++;
608     }
609
610   if (err)
611     log_info ("RSA secret key check failed\n");
612
613   gcry_mpi_release (t);
614   gcry_mpi_release (t1);
615   gcry_mpi_release (t2);
616   gcry_mpi_release (phi);
617
618   return err? -1:0;
619 }
620
621
622 /* A callback used by p12_parse to return a certificate.  */
623 static void
624 import_p12_cert_cb (void *opaque, const unsigned char *cert, size_t certlen)
625 {
626   struct b64state state;
627   gpg_error_t err, err2;
628
629   err = b64enc_start (&state, stdout, "CERTIFICATE");
630   if (!err)
631     err = b64enc_write (&state, cert, certlen);
632   err2 = b64enc_finish (&state);
633   if (!err)
634     err = err2;
635   if (err)
636     log_error ("error writing armored certificate: %s\n", gpg_strerror (err));
637 }
638
639 static void
640 import_p12_file (const char *fname)
641 {
642   char *buf;
643   unsigned char *result;
644   size_t buflen, resultlen;
645   int i;
646   int rc;
647   gcry_mpi_t *kparms;
648   struct rsa_secret_key_s sk;
649   gcry_sexp_t s_key;
650   unsigned char *key;
651   unsigned char grip[20];
652   char *pw;
653
654   /* fixme: we should release some stuff on error */
655   
656   buf = read_file (fname, &buflen);
657   if (!buf)
658     return;
659
660   kparms = p12_parse (buf, buflen, (pw=get_passphrase (0)),
661                       import_p12_cert_cb, NULL);
662   release_passphrase (pw);
663   xfree (buf);
664   if (!kparms)
665     {
666       log_error ("error parsing or decrypting the PKCS-12 file\n");
667       return;
668     }
669   for (i=0; kparms[i]; i++)
670     ;
671   if (i != 8)
672     {
673       log_error ("invalid structure of private key\n");
674       return;
675     }
676
677
678 /*    print_mpi ("   n", kparms[0]); */
679 /*    print_mpi ("   e", kparms[1]); */
680 /*    print_mpi ("   d", kparms[2]); */
681 /*    print_mpi ("   p", kparms[3]); */
682 /*    print_mpi ("   q", kparms[4]); */
683 /*    print_mpi ("dmp1", kparms[5]); */
684 /*    print_mpi ("dmq1", kparms[6]); */
685 /*    print_mpi ("   u", kparms[7]); */
686
687   sk.n = kparms[0];
688   sk.e = kparms[1];
689   sk.d = kparms[2];
690   sk.q = kparms[3];
691   sk.p = kparms[4];
692   sk.u = kparms[7];
693   if (rsa_key_check (&sk))
694     return;
695 /*    print_mpi ("   n", sk.n); */
696 /*    print_mpi ("   e", sk.e); */
697 /*    print_mpi ("   d", sk.d); */
698 /*    print_mpi ("   p", sk.p); */
699 /*    print_mpi ("   q", sk.q); */
700 /*    print_mpi ("   u", sk.u); */
701
702   /* Create an S-expresion from the parameters. */
703   rc = gcry_sexp_build (&s_key, NULL,
704                         "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
705                         sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
706   for (i=0; i < 8; i++)
707     gcry_mpi_release (kparms[i]);
708   gcry_free (kparms);
709   if (rc)
710     {
711       log_error ("failed to created S-expression from key: %s\n",
712                  gpg_strerror (rc));
713       return;
714     }
715
716   /* Compute the keygrip. */
717   if (!gcry_pk_get_keygrip (s_key, grip))
718     {
719       log_error ("can't calculate keygrip\n");
720       return;
721     }
722   log_info ("keygrip: ");
723   for (i=0; i < 20; i++)
724     log_printf ("%02X", grip[i]);
725   log_printf ("\n");
726
727   /* Convert to canonical encoding. */
728   buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0);
729   assert (buflen);
730   key = gcry_xmalloc_secure (buflen);
731   buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, key, buflen);
732   assert (buflen);
733   gcry_sexp_release (s_key);
734
735
736   rc = agent_protect (key, (pw=get_passphrase (0)), &result, &resultlen);
737   release_passphrase (pw);
738   xfree (key);
739   if (rc)
740     {
741       log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
742       return;
743     }
744   
745   if (opt_armor)
746     {
747       char *p = make_advanced (result, resultlen);
748       xfree (result);
749       if (!p)
750         return;
751       result = p;
752       resultlen = strlen (p);
753     }
754
755   if (opt_store)
756     store_private_key (grip, result, resultlen, opt_force);
757   else
758     fwrite (result, resultlen, 1, stdout);
759
760   xfree (result);
761 }
762
763 \f
764
765 static gcry_mpi_t *
766 sexp_to_kparms (gcry_sexp_t sexp)
767 {
768   gcry_sexp_t list, l2;
769   const char *name;
770   const char *s;
771   size_t n;
772   int i, idx;
773   const char *elems;
774   gcry_mpi_t *array;
775
776   list = gcry_sexp_find_token (sexp, "private-key", 0 );
777   if(!list)
778     return NULL; 
779   l2 = gcry_sexp_cadr (list);
780   gcry_sexp_release (list);
781   list = l2;
782   name = gcry_sexp_nth_data (list, 0, &n);
783   if(!name || n != 3 || memcmp (name, "rsa", 3))
784     {
785       gcry_sexp_release (list);
786       return NULL;
787     }
788
789   /* Parameter names used with RSA. */
790   elems = "nedpqu";
791   array = xcalloc (strlen(elems) + 1, sizeof *array);
792   for (idx=0, s=elems; *s; s++, idx++ ) 
793     {
794       l2 = gcry_sexp_find_token (list, s, 1);
795       if (!l2)
796         {
797           for (i=0; i<idx; i++)
798             gcry_mpi_release (array[i]);
799           xfree (array);
800           gcry_sexp_release (list);
801           return NULL; /* required parameter not found */
802         }
803       array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
804       gcry_sexp_release (l2);
805       if (!array[idx])
806         {
807           for (i=0; i<idx; i++)
808             gcry_mpi_release (array[i]);
809           xfree (array);
810           gcry_sexp_release (list);
811           return NULL; /* required parameter is invalid */
812         }
813     }
814   
815   gcry_sexp_release (list);
816   return array;
817 }
818
819
820 /* Check whether STRING is a KEYGRIP, i.e has the correct length and
821    does only consist of uppercase hex characters. */
822 static int
823 is_keygrip (const char *string)
824 {
825   int i;
826
827   for(i=0; string[i] && i < 41; i++) 
828     if (!strchr("01234567890ABCDEF", string[i]))
829       return 0; 
830   return i == 40;
831 }
832
833
834 static void
835 export_p12_file (const char *fname)
836 {
837   int rc;
838   gcry_mpi_t kparms[9], *kp;
839   unsigned char *key;
840   size_t keylen;
841   gcry_sexp_t private;
842   struct rsa_secret_key_s sk;
843   int i;
844   unsigned char *cert = NULL;
845   size_t certlen = 0;
846   int keytype;
847   size_t keylen_for_wipe = 0;
848   char *pw;
849
850   if ( is_keygrip (fname) )
851     {
852       char hexgrip[40+4+1];
853       char *p;
854   
855       assert (strlen(fname) == 40);
856       strcpy (stpcpy (hexgrip, fname), ".key");
857
858       p = make_filename (opt_homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
859       key = read_key (p);
860       xfree (p);
861     }
862   else
863     key = read_key (fname);
864
865   if (!key)
866     return;
867
868   keytype = agent_private_key_type (key);
869   if (keytype == PRIVATE_KEY_PROTECTED)
870     {
871       unsigned char *tmpkey;
872       size_t tmplen;
873
874       rc = agent_unprotect (key, (pw=get_passphrase (1)), &tmpkey, &tmplen);
875       release_passphrase (pw);
876       if (rc)
877         {
878           log_error ("unprotecting key `%s' failed: %s\n",
879                      fname, gpg_strerror (rc));
880           xfree (key);
881           return;
882         }
883       xfree (key);
884       key = tmpkey;
885       keylen_for_wipe = tmplen;
886
887       keytype = agent_private_key_type (key);
888     }
889
890   if (keytype == PRIVATE_KEY_SHADOWED)
891     {
892       log_error ("`%s' is a shadowed private key - can't export it\n", fname);
893       wipememory (key, keylen_for_wipe);
894       xfree (key);
895       return;
896     }
897   else if (keytype != PRIVATE_KEY_CLEAR)
898     {
899       log_error ("\%s' is not a private key\n", fname);
900       wipememory (key, keylen_for_wipe);
901       xfree (key);
902       return;
903     }
904
905
906   if (opt_have_cert)
907     {
908       cert = read_file ("-", &certlen);
909       if (!cert)
910         {
911           wipememory (key, keylen_for_wipe);
912           xfree (key);
913           return;
914         }
915     }
916
917
918   if (gcry_sexp_new (&private, key, 0, 0))
919     {
920       log_error ("gcry_sexp_new failed\n");
921       wipememory (key, keylen_for_wipe);
922       xfree (key);
923       xfree (cert);
924       return;
925     } 
926   wipememory (key, keylen_for_wipe);
927   xfree (key);
928
929   kp = sexp_to_kparms (private);
930   gcry_sexp_release (private);
931   if (!kp)
932     {
933       log_error ("error converting key parameters\n");
934       xfree (cert);
935       return;
936     } 
937   sk.n = kp[0];
938   sk.e = kp[1];
939   sk.d = kp[2];
940   sk.p = kp[3];
941   sk.q = kp[4];
942   sk.u = kp[5];
943   xfree (kp);
944
945  
946   kparms[0] = sk.n;
947   kparms[1] = sk.e;
948   kparms[2] = sk.d;
949   kparms[3] = sk.q;
950   kparms[4] = sk.p;
951   kparms[5] = gcry_mpi_snew (0);  /* compute d mod (p-1) */
952   gcry_mpi_sub_ui (kparms[5], kparms[3], 1);
953   gcry_mpi_mod (kparms[5], sk.d, kparms[5]);   
954   kparms[6] = gcry_mpi_snew (0);  /* compute d mod (q-1) */
955   gcry_mpi_sub_ui (kparms[6], kparms[4], 1);
956   gcry_mpi_mod (kparms[6], sk.d, kparms[6]);   
957   kparms[7] = sk.u;
958   kparms[8] = NULL;
959
960   key = p12_build (kparms, cert, certlen, (pw=get_passphrase (0)), &keylen);
961   release_passphrase (pw);
962   xfree (cert);
963   for (i=0; i < 8; i++)
964     gcry_mpi_release (kparms[i]);
965   if (!key)
966     return;
967   
968   fwrite (key, keylen, 1, stdout);
969   xfree (key);
970 }
971
972
973
974 /* Do the percent and plus/space unescaping in place and return the
975    length of the valid buffer. */
976 static size_t
977 percent_plus_unescape (unsigned char *string)
978 {
979   unsigned char *p = string;
980   size_t n = 0;
981
982   while (*string)
983     {
984       if (*string == '%' && string[1] && string[2])
985         { 
986           string++;
987           *p++ = xtoi_2 (string);
988           n++;
989           string+= 2;
990         }
991       else if (*string == '+')
992         {
993           *p++ = ' ';
994           n++;
995           string++;
996         }
997       else
998         {
999           *p++ = *string++;
1000           n++;
1001         }
1002     }
1003
1004   return n;
1005 }
1006
1007 /* Remove percent and plus escaping and make sure that the reuslt is a
1008    string.  This is done in place. Returns STRING. */
1009 static char *
1010 percent_plus_unescape_string (char *string) 
1011 {
1012   unsigned char *p = string;
1013   size_t n;
1014
1015   n = percent_plus_unescape (p);
1016   p[n] = 0;
1017
1018   return string;
1019 }
1020
1021 \f
1022 int
1023 main (int argc, char **argv )
1024 {
1025   ARGPARSE_ARGS pargs;
1026   int cmd = 0;
1027   const char *fname;
1028
1029   set_strusage (my_strusage);
1030   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
1031   log_set_prefix ("gpg-protect-tool", 1); 
1032
1033   /* Try to auto set the character set.  */
1034   set_native_charset (NULL); 
1035
1036   i18n_init ();
1037
1038   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
1039     {
1040       log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
1041                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
1042     }
1043
1044   gcry_set_log_handler (my_gcry_logger, NULL);
1045   
1046   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1047
1048
1049 #ifdef __MINGW32__
1050   opt_homedir = read_w32_registry_string ( NULL,
1051                                            "Software\\GNU\\GnuPG", "HomeDir" );
1052 #else
1053   opt_homedir = getenv ("GNUPGHOME");
1054 #endif
1055   if (!opt_homedir || !*opt_homedir)
1056     opt_homedir = GNUPG_DEFAULT_HOMEDIR;
1057
1058
1059   pargs.argc = &argc;
1060   pargs.argv = &argv;
1061   pargs.flags=  1;  /* (do not remove the args) */
1062   while (arg_parse (&pargs, opts) )
1063     {
1064       switch (pargs.r_opt)
1065         {
1066         case oVerbose: opt.verbose++; break;
1067         case oArmor:   opt_armor=1; break;
1068         case oHomedir: opt_homedir = pargs.r.ret_str; break;
1069
1070         case oProtect: cmd = oProtect; break;
1071         case oUnprotect: cmd = oUnprotect; break;
1072         case oShadow: cmd = oShadow; break;
1073         case oShowShadowInfo: cmd = oShowShadowInfo; break;
1074         case oShowKeygrip: cmd = oShowKeygrip; break;
1075         case oP12Import: cmd = oP12Import; break;
1076         case oP12Export: cmd = oP12Export; break;
1077
1078         case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
1079         case oStore: opt_store = 1; break;
1080         case oForce: opt_force = 1; break;
1081         case oNoFailOnExist: opt_no_fail_on_exist = 1; break;
1082         case oHaveCert: opt_have_cert = 1; break;
1083         case oPrompt: opt_prompt = pargs.r.ret_str; break;
1084         case oStatusMsg: opt_status_msg = 1; break;
1085           
1086         default : pargs.err = 2; break;
1087         }
1088     }
1089   if (log_get_errorcount(0))
1090     exit(2);
1091
1092   fname = "-";
1093   if (argc == 1)
1094     fname = *argv;
1095   else if (argc > 1)
1096     usage (1);
1097
1098   if (opt_prompt)
1099     opt_prompt = percent_plus_unescape_string (xstrdup (opt_prompt));
1100
1101   if (cmd == oProtect)
1102     read_and_protect (fname);
1103   else if (cmd == oUnprotect)
1104     read_and_unprotect (fname);
1105   else if (cmd == oShadow)
1106     read_and_shadow (fname);
1107   else if (cmd == oShowShadowInfo)
1108     show_shadow_info (fname);
1109   else if (cmd == oShowKeygrip)
1110     show_keygrip (fname);
1111   else if (cmd == oP12Import)
1112     import_p12_file (fname);
1113   else if (cmd == oP12Export)
1114     export_p12_file (fname);
1115   else
1116     show_file (fname);
1117
1118   agent_exit (0);
1119   return 8; /*NOTREACHED*/
1120 }
1121
1122 void
1123 agent_exit (int rc)
1124 {
1125   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
1126   exit (rc);
1127 }
1128
1129
1130 /* Return the passphrase string and ask the agent if it has not been
1131    set from the command line  PROMPTNO select the prompt to display:
1132      0 = default
1133      1 = taken from the option --prompt
1134 */
1135 static char *
1136 get_passphrase (int promptno)
1137 {
1138   char *pw;
1139   int err;
1140   const char *desc;
1141
1142   if (opt_passphrase)
1143     return xstrdup (opt_passphrase);
1144
1145   if (promptno == 1 && opt_prompt)
1146     desc = opt_prompt;
1147   else
1148     desc = _("Please enter the passphrase or the PIN\n"
1149              "needed to complete this operation.");
1150
1151   pw = simple_pwquery (NULL,NULL, _("Passphrase:"), desc, &err);
1152   if (!pw)
1153     {
1154       if (err)
1155         log_error ("error while asking for the passphrase\n");
1156       else
1157         log_info ("cancelled\n");
1158       agent_exit (0);
1159     }
1160
1161   return pw;
1162 }
1163
1164 static void
1165 release_passphrase (char *pw)
1166 {
1167   if (pw)
1168     {
1169       wipememory (pw, strlen (pw));
1170       xfree (pw);
1171     }
1172 }
1173
1174 static int
1175 store_private_key (const unsigned char *grip,
1176                    const void *buffer, size_t length, int force)
1177 {
1178   int i;
1179   char *fname;
1180   FILE *fp;
1181   char hexgrip[40+4+1];
1182   
1183   for (i=0; i < 20; i++)
1184     sprintf (hexgrip+2*i, "%02X", grip[i]);
1185   strcpy (hexgrip+40, ".key");
1186
1187   fname = make_filename (opt_homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
1188   if (force)
1189     fp = fopen (fname, "wb");
1190   else
1191     {
1192       if (!access (fname, F_OK))
1193       {
1194         if (opt_status_msg)
1195           log_info ("[PROTECT-TOOL:] secretkey-exists\n");
1196         if (opt_no_fail_on_exist)
1197           log_info ("secret key file `%s' already exists\n", fname);
1198         else
1199           log_error ("secret key file `%s' already exists\n", fname);
1200         xfree (fname);
1201         return opt_no_fail_on_exist? 0 : -1;
1202       }
1203       fp = fopen (fname, "wbx");  /* FIXME: the x is a GNU extension - let
1204                                      configure check whether this actually
1205                                      works */
1206     }
1207
1208   if (!fp) 
1209     { 
1210       log_error ("can't create `%s': %s\n", fname, strerror (errno));
1211       xfree (fname);
1212       return -1;
1213     }
1214
1215   if (fwrite (buffer, length, 1, fp) != 1)
1216     {
1217       log_error ("error writing `%s': %s\n", fname, strerror (errno));
1218       fclose (fp);
1219       remove (fname);
1220       xfree (fname);
1221       return -1;
1222     }
1223   if ( fclose (fp) )
1224     {
1225       log_error ("error closing `%s': %s\n", fname, strerror (errno));
1226       remove (fname);
1227       xfree (fname);
1228       return -1;
1229     }
1230   log_info ("secret key stored as `%s'\n", fname);
1231
1232   if (opt_status_msg)
1233     log_info ("[PROTECT-TOOL:] secretkey-stored\n");
1234
1235   xfree (fname);
1236   return 0;
1237 }