speedo,w32: Fix uninstallation
[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 #include "agent.h"
42 #include "i18n.h"
43 #include "get-passphrase.h"
44 #include "sysutils.h"
45 #include "../common/init.h"
46
47
48 enum cmd_and_opt_values
49 {
50   aNull = 0,
51   oVerbose        = 'v',
52   oArmor          = 'a',
53   oPassphrase     = 'P',
54
55   oProtect        = 'p',
56   oUnprotect      = 'u',
57
58   oNoVerbose = 500,
59   oShadow,
60   oShowShadowInfo,
61   oShowKeygrip,
62   oS2Kcalibration,
63   oCanonical,
64
65   oStore,
66   oForce,
67   oHaveCert,
68   oNoFailOnExist,
69   oHomedir,
70   oPrompt,
71   oStatusMsg,
72   oDebugUseOCB,
73
74   oAgentProgram
75 };
76
77
78 struct rsa_secret_key_s
79 {
80   gcry_mpi_t n;     /* public modulus */
81   gcry_mpi_t e;     /* public exponent */
82   gcry_mpi_t d;     /* exponent */
83   gcry_mpi_t p;     /* prime  p. */
84   gcry_mpi_t q;     /* prime  q. */
85   gcry_mpi_t u;     /* inverse of p mod q. */
86 };
87
88
89 static const char *opt_homedir;
90 static int opt_armor;
91 static int opt_canonical;
92 static int opt_store;
93 static int opt_force;
94 static int opt_no_fail_on_exist;
95 static int opt_have_cert;
96 static const char *opt_passphrase;
97 static char *opt_prompt;
98 static int opt_status_msg;
99 static const char *opt_agent_program;
100 static int opt_debug_use_ocb;
101
102 static char *get_passphrase (int promptno);
103 static void release_passphrase (char *pw);
104
105
106 static ARGPARSE_OPTS opts[] = {
107   ARGPARSE_group (300, N_("@Commands:\n ")),
108
109   ARGPARSE_c (oProtect,   "protect",   "protect a private key"),
110   ARGPARSE_c (oUnprotect, "unprotect", "unprotect a private key"),
111   ARGPARSE_c (oShadow,    "shadow", "create a shadow entry for a public key"),
112   ARGPARSE_c (oShowShadowInfo,  "show-shadow-info", "return the shadow info"),
113   ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""),
114   ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"),
115
116   ARGPARSE_group (301, N_("@\nOptions:\n ")),
117
118   ARGPARSE_s_n (oVerbose, "verbose", "verbose"),
119   ARGPARSE_s_n (oArmor, "armor", "write output in advanced format"),
120   ARGPARSE_s_n (oCanonical, "canonical", "write output in canonical format"),
121
122   ARGPARSE_s_s (oPassphrase, "passphrase", "|STRING|use passphrase STRING"),
123   ARGPARSE_s_n (oHaveCert, "have-cert",
124                 "certificate to export provided on STDIN"),
125   ARGPARSE_s_n (oStore,    "store",
126                 "store the created key in the appropriate place"),
127   ARGPARSE_s_n (oForce,    "force",
128                 "force overwriting"),
129   ARGPARSE_s_n (oNoFailOnExist, "no-fail-on-exist", "@"),
130   ARGPARSE_s_s (oHomedir, "homedir", "@"),
131   ARGPARSE_s_s (oPrompt,  "prompt",
132                 "|ESCSTRING|use ESCSTRING as prompt in pinentry"),
133   ARGPARSE_s_n (oStatusMsg, "enable-status-msg", "@"),
134
135   ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
136
137   ARGPARSE_s_n (oDebugUseOCB,  "debug-use-ocb", "@"), /* For hacking only.  */
138
139   ARGPARSE_end ()
140 };
141
142 static const char *
143 my_strusage (int level)
144 {
145   const char *p;
146   switch (level)
147     {
148     case 11: p = "gpg-protect-tool (" GNUPG_NAME ")";
149       break;
150     case 13: p = VERSION; break;
151     case 17: p = PRINTABLE_OS_NAME; break;
152     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
153
154     case 1:
155     case 40: p =  _("Usage: gpg-protect-tool [options] (-h for help)\n");
156       break;
157     case 41: p =  _("Syntax: gpg-protect-tool [options] [args]\n"
158                     "Secret key maintenance tool\n");
159     break;
160
161     default: p = NULL;
162     }
163   return p;
164 }
165
166
167 /*  static void */
168 /*  print_mpi (const char *text, gcry_mpi_t a) */
169 /*  { */
170 /*    char *buf; */
171 /*    void *bufaddr = &buf; */
172 /*    int rc; */
173
174 /*    rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
175 /*    if (rc) */
176 /*      log_info ("%s: [error printing number: %s]\n", text, gpg_strerror (rc)); */
177 /*    else */
178 /*      { */
179 /*        log_info ("%s: %s\n", text, buf); */
180 /*        gcry_free (buf); */
181 /*      } */
182 /*  } */
183
184
185 \f
186 static unsigned char *
187 make_canonical (const char *fname, const char *buf, size_t buflen)
188 {
189   int rc;
190   size_t erroff, len;
191   gcry_sexp_t sexp;
192   unsigned char *result;
193
194   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
195   if (rc)
196     {
197       log_error ("invalid S-Expression in '%s' (off=%u): %s\n",
198                  fname, (unsigned int)erroff, gpg_strerror (rc));
199       return NULL;
200     }
201   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
202   assert (len);
203   result = xmalloc (len);
204   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
205   assert (len);
206   gcry_sexp_release (sexp);
207   return result;
208 }
209
210 static char *
211 make_advanced (const unsigned char *buf, size_t buflen)
212 {
213   int rc;
214   size_t erroff, len;
215   gcry_sexp_t sexp;
216   char *result;
217
218   rc = gcry_sexp_sscan (&sexp, &erroff, (const char*)buf, buflen);
219   if (rc)
220     {
221       log_error ("invalid canonical S-Expression (off=%u): %s\n",
222                  (unsigned int)erroff, gpg_strerror (rc));
223       return NULL;
224     }
225   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
226   assert (len);
227   result = xmalloc (len);
228   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
229   assert (len);
230   gcry_sexp_release (sexp);
231   return result;
232 }
233
234
235 static char *
236 read_file (const char *fname, size_t *r_length)
237 {
238   FILE *fp;
239   char *buf;
240   size_t buflen;
241
242   if (!strcmp (fname, "-"))
243     {
244       size_t nread, bufsize = 0;
245
246       fp = stdin;
247 #ifdef HAVE_DOSISH_SYSTEM
248       setmode ( fileno(fp) , O_BINARY );
249 #endif
250       buf = NULL;
251       buflen = 0;
252 #define NCHUNK 8192
253       do
254         {
255           bufsize += NCHUNK;
256           if (!buf)
257             buf = xmalloc (bufsize);
258           else
259             buf = xrealloc (buf, bufsize);
260
261           nread = fread (buf+buflen, 1, NCHUNK, fp);
262           if (nread < NCHUNK && ferror (fp))
263             {
264               log_error ("error reading '[stdin]': %s\n", strerror (errno));
265               xfree (buf);
266               return NULL;
267             }
268           buflen += nread;
269         }
270       while (nread == NCHUNK);
271 #undef NCHUNK
272
273     }
274   else
275     {
276       struct stat st;
277
278       fp = fopen (fname, "rb");
279       if (!fp)
280         {
281           log_error ("can't open '%s': %s\n", fname, strerror (errno));
282           return NULL;
283         }
284
285       if (fstat (fileno(fp), &st))
286         {
287           log_error ("can't stat '%s': %s\n", fname, strerror (errno));
288           fclose (fp);
289           return NULL;
290         }
291
292       buflen = st.st_size;
293       buf = xmalloc (buflen+1);
294       if (fread (buf, buflen, 1, fp) != 1)
295         {
296           log_error ("error reading '%s': %s\n", fname, strerror (errno));
297           fclose (fp);
298           xfree (buf);
299           return NULL;
300         }
301       fclose (fp);
302     }
303
304   *r_length = buflen;
305   return buf;
306 }
307
308
309 static unsigned char *
310 read_key (const char *fname)
311 {
312   char *buf;
313   size_t buflen;
314   unsigned char *key;
315
316   buf = read_file (fname, &buflen);
317   if (!buf)
318     return NULL;
319   key = make_canonical (fname, buf, buflen);
320   xfree (buf);
321   return key;
322 }
323
324
325 \f
326 static void
327 read_and_protect (const char *fname)
328 {
329   int  rc;
330   unsigned char *key;
331   unsigned char *result;
332   size_t resultlen;
333   char *pw;
334
335   key = read_key (fname);
336   if (!key)
337     return;
338
339   pw = get_passphrase (1);
340   rc = agent_protect (key, pw, &result, &resultlen, 0,
341                       opt_debug_use_ocb? 1 : -1);
342   release_passphrase (pw);
343   xfree (key);
344   if (rc)
345     {
346       log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
347       return;
348     }
349
350   if (opt_armor)
351     {
352       char *p = make_advanced (result, resultlen);
353       xfree (result);
354       if (!p)
355         return;
356       result = (unsigned char*)p;
357       resultlen = strlen (p);
358     }
359
360   fwrite (result, resultlen, 1, stdout);
361   xfree (result);
362 }
363
364
365 static void
366 read_and_unprotect (ctrl_t ctrl, const char *fname)
367 {
368   int  rc;
369   unsigned char *key;
370   unsigned char *result;
371   size_t resultlen;
372   char *pw;
373   gnupg_isotime_t protected_at;
374
375   key = read_key (fname);
376   if (!key)
377     return;
378
379   rc = agent_unprotect (ctrl, key, (pw=get_passphrase (1)),
380                         protected_at, &result, &resultlen);
381   release_passphrase (pw);
382   xfree (key);
383   if (rc)
384     {
385       if (opt_status_msg)
386         log_info ("[PROTECT-TOOL:] bad-passphrase\n");
387       log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
388       return;
389     }
390   if (opt.verbose)
391     {
392       if (*protected_at)
393         log_info ("key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s\n",
394                   protected_at, protected_at+4, protected_at+6,
395                   protected_at+9, protected_at+11, protected_at+13);
396       else
397         log_info ("key protection done at [unknown]\n");
398     }
399
400   if (opt_armor)
401     {
402       char *p = make_advanced (result, resultlen);
403       xfree (result);
404       if (!p)
405         return;
406       result = (unsigned char*)p;
407       resultlen = strlen (p);
408     }
409
410   fwrite (result, resultlen, 1, stdout);
411   xfree (result);
412 }
413
414
415 \f
416 static void
417 read_and_shadow (const char *fname)
418 {
419   int  rc;
420   unsigned char *key;
421   unsigned char *result;
422   size_t resultlen;
423   unsigned char dummy_info[] = "(8:313233342:43)";
424
425   key = read_key (fname);
426   if (!key)
427     return;
428
429   rc = agent_shadow_key (key, dummy_info, &result);
430   xfree (key);
431   if (rc)
432     {
433       log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
434       return;
435     }
436   resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
437   assert (resultlen);
438
439   if (opt_armor)
440     {
441       char *p = make_advanced (result, resultlen);
442       xfree (result);
443       if (!p)
444         return;
445       result = (unsigned char*)p;
446       resultlen = strlen (p);
447     }
448
449   fwrite (result, resultlen, 1, stdout);
450   xfree (result);
451 }
452
453 static void
454 show_shadow_info (const char *fname)
455 {
456   int  rc;
457   unsigned char *key;
458   const unsigned char *info;
459   size_t infolen;
460
461   key = read_key (fname);
462   if (!key)
463     return;
464
465   rc = agent_get_shadow_info (key, &info);
466   xfree (key);
467   if (rc)
468     {
469       log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
470       return;
471     }
472   infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
473   assert (infolen);
474
475   if (opt_armor)
476     {
477       char *p = make_advanced (info, infolen);
478       if (!p)
479         return;
480       fwrite (p, strlen (p), 1, stdout);
481       xfree (p);
482     }
483   else
484     fwrite (info, infolen, 1, stdout);
485 }
486
487
488 static void
489 show_file (const char *fname)
490 {
491   unsigned char *key;
492   size_t keylen;
493   char *p;
494
495   key = read_key (fname);
496   if (!key)
497     return;
498
499   keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
500   assert (keylen);
501
502   if (opt_canonical)
503     {
504       fwrite (key, keylen, 1, stdout);
505     }
506   else
507     {
508       p = make_advanced (key, keylen);
509       if (p)
510         {
511           fwrite (p, strlen (p), 1, stdout);
512           xfree (p);
513         }
514     }
515   xfree (key);
516 }
517
518 static void
519 show_keygrip (const char *fname)
520 {
521   unsigned char *key;
522   gcry_sexp_t private;
523   unsigned char grip[20];
524   int i;
525
526   key = read_key (fname);
527   if (!key)
528     return;
529
530   if (gcry_sexp_new (&private, key, 0, 0))
531     {
532       log_error ("gcry_sexp_new failed\n");
533       return;
534     }
535   xfree (key);
536
537   if (!gcry_pk_get_keygrip (private, grip))
538     {
539       log_error ("can't calculate keygrip\n");
540       return;
541     }
542   gcry_sexp_release (private);
543
544   for (i=0; i < 20; i++)
545     printf ("%02X", grip[i]);
546   putchar ('\n');
547 }
548
549 \f
550
551
552 \f
553 int
554 main (int argc, char **argv )
555 {
556   ARGPARSE_ARGS pargs;
557   int cmd = 0;
558   const char *fname;
559   ctrl_t ctrl;
560
561   early_system_init ();
562   set_strusage (my_strusage);
563   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
564   log_set_prefix ("gpg-protect-tool", 1);
565
566   /* Make sure that our subsystems are ready.  */
567   i18n_init ();
568   init_common_subsystems (&argc, &argv);
569
570   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
571     {
572       log_fatal( _("%s is too old (need %s, have %s)\n"), "libgcrypt",
573                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
574     }
575
576   setup_libgcrypt_logging ();
577   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
578
579
580   opt_homedir = default_homedir ();
581
582
583   pargs.argc = &argc;
584   pargs.argv = &argv;
585   pargs.flags=  1;  /* (do not remove the args) */
586   while (arg_parse (&pargs, opts) )
587     {
588       switch (pargs.r_opt)
589         {
590         case oVerbose: opt.verbose++; break;
591         case oArmor:   opt_armor=1; break;
592         case oCanonical: opt_canonical=1; break;
593         case oHomedir: opt_homedir = pargs.r.ret_str; break;
594
595         case oAgentProgram: opt_agent_program = pargs.r.ret_str; break;
596
597         case oProtect: cmd = oProtect; break;
598         case oUnprotect: cmd = oUnprotect; break;
599         case oShadow: cmd = oShadow; break;
600         case oShowShadowInfo: cmd = oShowShadowInfo; break;
601         case oShowKeygrip: cmd = oShowKeygrip; break;
602         case oS2Kcalibration: cmd = oS2Kcalibration; break;
603
604         case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
605         case oStore: opt_store = 1; break;
606         case oForce: opt_force = 1; break;
607         case oNoFailOnExist: opt_no_fail_on_exist = 1; break;
608         case oHaveCert: opt_have_cert = 1; break;
609         case oPrompt: opt_prompt = pargs.r.ret_str; break;
610         case oStatusMsg: opt_status_msg = 1; break;
611         case oDebugUseOCB: opt_debug_use_ocb = 1; break;
612
613         default: pargs.err = ARGPARSE_PRINT_ERROR; break;
614         }
615     }
616   if (log_get_errorcount (0))
617     exit (2);
618
619   fname = "-";
620   if (argc == 1)
621     fname = *argv;
622   else if (argc > 1)
623     usage (1);
624
625   /* Allocate an CTRL object.  An empty object should sufficent.  */
626   ctrl = xtrycalloc (1, sizeof *ctrl);
627   if (!ctrl)
628     {
629       log_error ("error allocating connection control data: %s\n",
630                  strerror (errno));
631       agent_exit (1);
632     }
633
634   /* Set the information which can't be taken from envvars.  */
635   gnupg_prepare_get_passphrase (GPG_ERR_SOURCE_DEFAULT,
636                                 opt.verbose,
637                                 opt_homedir,
638                                 opt_agent_program,
639                                 NULL, NULL, NULL);
640
641   if (opt_prompt)
642     opt_prompt = percent_plus_unescape (opt_prompt, 0);
643
644   if (cmd == oProtect)
645     read_and_protect (fname);
646   else if (cmd == oUnprotect)
647     read_and_unprotect (ctrl, fname);
648   else if (cmd == oShadow)
649     read_and_shadow (fname);
650   else if (cmd == oShowShadowInfo)
651     show_shadow_info (fname);
652   else if (cmd == oShowKeygrip)
653     show_keygrip (fname);
654   else if (cmd == oS2Kcalibration)
655     {
656       if (!opt.verbose)
657         opt.verbose++; /* We need to see something.  */
658       get_standard_s2k_count ();
659     }
660   else
661     show_file (fname);
662
663   xfree (ctrl);
664
665   agent_exit (0);
666   return 8; /*NOTREACHED*/
667 }
668
669 void
670 agent_exit (int rc)
671 {
672   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
673   exit (rc);
674 }
675
676
677 /* Return the passphrase string and ask the agent if it has not been
678    set from the command line  PROMPTNO select the prompt to display:
679      0 = default
680      1 = taken from the option --prompt
681      2 = for unprotecting a pkcs#12 object
682      3 = for protecting a new pkcs#12 object
683      4 = for protecting an imported pkcs#12 in our system
684 */
685 static char *
686 get_passphrase (int promptno)
687 {
688   char *pw;
689   int err;
690   const char *desc;
691   char *orig_codeset;
692   int repeat = 0;
693
694   if (opt_passphrase)
695     return xstrdup (opt_passphrase);
696
697   orig_codeset = i18n_switchto_utf8 ();
698
699   if (promptno == 1 && opt_prompt)
700     {
701       desc = opt_prompt;
702     }
703   else if (promptno == 2)
704     {
705       desc = _("Please enter the passphrase to unprotect the "
706                "PKCS#12 object.");
707     }
708   else if (promptno == 3)
709     {
710       desc = _("Please enter the passphrase to protect the "
711                "new PKCS#12 object.");
712       repeat = 1;
713     }
714   else if (promptno == 4)
715     {
716       desc = _("Please enter the passphrase to protect the "
717                "imported object within the GnuPG system.");
718       repeat = 1;
719     }
720   else
721     desc = _("Please enter the passphrase or the PIN\n"
722              "needed to complete this operation.");
723
724   i18n_switchback (orig_codeset);
725
726   err = gnupg_get_passphrase (NULL, NULL, _("Passphrase:"), desc,
727                               repeat, repeat, 1, &pw);
728   if (err)
729     {
730       if (gpg_err_code (err) == GPG_ERR_CANCELED
731           || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
732         log_info (_("cancelled\n"));
733       else
734         log_error (_("error while asking for the passphrase: %s\n"),
735                    gpg_strerror (err));
736       agent_exit (0);
737     }
738   assert (pw);
739
740   return pw;
741 }
742
743
744 static void
745 release_passphrase (char *pw)
746 {
747   if (pw)
748     {
749       wipememory (pw, strlen (pw));
750       xfree (pw);
751     }
752 }
753
754
755 /* Stub function.  */
756 int
757 agent_key_available (const unsigned char *grip)
758 {
759   (void)grip;
760   return -1;  /* Not available.  */
761 }
762
763 char *
764 agent_get_cache (const char *key, cache_mode_t cache_mode)
765 {
766   (void)key;
767   (void)cache_mode;
768   return NULL;
769 }
770
771 gpg_error_t
772 agent_askpin (ctrl_t ctrl,
773               const char *desc_text, const char *prompt_text,
774               const char *initial_errtext,
775               struct pin_entry_info_s *pininfo,
776               const char *keyinfo, cache_mode_t cache_mode)
777 {
778   gpg_error_t err;
779   unsigned char *passphrase;
780   size_t size;
781
782   (void)ctrl;
783   (void)desc_text;
784   (void)prompt_text;
785   (void)initial_errtext;
786   (void)keyinfo;
787   (void)cache_mode;
788
789   *pininfo->pin = 0; /* Reset the PIN. */
790   passphrase = get_passphrase (0);
791   size = strlen (passphrase);
792   if (size >= pininfo->max_length)
793     return gpg_error (GPG_ERR_TOO_LARGE);
794
795   memcpy (&pininfo->pin, passphrase, size);
796   xfree (passphrase);
797   pininfo->pin[size] = 0;
798   if (pininfo->check_cb)
799     {
800       /* More checks by utilizing the optional callback. */
801       pininfo->cb_errtext = NULL;
802       err = pininfo->check_cb (pininfo);
803     }
804   else
805     err = 0;
806   return err;
807 }
808
809 /* Replacement for the function in findkey.c.  Here we write the key
810  * to stdout. */
811 int
812 agent_write_private_key (const unsigned char *grip,
813                          const void *buffer, size_t length, int force)
814 {
815   char hexgrip[40+4+1];
816   char *p;
817
818   (void)force;
819
820   bin2hex (grip, 20, hexgrip);
821   strcpy (hexgrip+40, ".key");
822   p = make_advanced (buffer, length);
823   if (p)
824     {
825       printf ("# Begin dump of %s\n%s%s# End dump of %s\n",
826               hexgrip, p, (*p && p[strlen(p)-1] == '\n')? "":"\n", hexgrip);
827       xfree (p);
828     }
829
830   return 0;
831 }