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