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