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