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