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