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