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