1 /* protect-tool.c - A tool to test the secret key protection
2 * Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
34 #ifdef HAVE_LANGINFO_CODESET
37 #ifdef HAVE_DOSISH_SYSTEM
38 #include <fcntl.h> /* for setmode() */
43 #include "get-passphrase.h"
45 #include "../common/init.h"
48 enum cmd_and_opt_values
78 struct rsa_secret_key_s
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. */
90 static int opt_canonical;
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 static int opt_debug_use_ocb;
101 static char *get_passphrase (int promptno);
102 static void release_passphrase (char *pw);
105 static ARGPARSE_OPTS opts[] = {
106 ARGPARSE_group (300, N_("@Commands:\n ")),
108 ARGPARSE_c (oProtect, "protect", "protect a private key"),
109 ARGPARSE_c (oUnprotect, "unprotect", "unprotect a private key"),
110 ARGPARSE_c (oShadow, "shadow", "create a shadow entry for a public key"),
111 ARGPARSE_c (oShowShadowInfo, "show-shadow-info", "return the shadow info"),
112 ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""),
113 ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"),
115 ARGPARSE_group (301, N_("@\nOptions:\n ")),
117 ARGPARSE_s_n (oVerbose, "verbose", "verbose"),
118 ARGPARSE_s_n (oArmor, "armor", "write output in advanced format"),
119 ARGPARSE_s_n (oCanonical, "canonical", "write output in canonical format"),
121 ARGPARSE_s_s (oPassphrase, "passphrase", "|STRING|use passphrase STRING"),
122 ARGPARSE_s_n (oHaveCert, "have-cert",
123 "certificate to export provided on STDIN"),
124 ARGPARSE_s_n (oStore, "store",
125 "store the created key in the appropriate place"),
126 ARGPARSE_s_n (oForce, "force",
127 "force overwriting"),
128 ARGPARSE_s_n (oNoFailOnExist, "no-fail-on-exist", "@"),
129 ARGPARSE_s_s (oHomedir, "homedir", "@"),
130 ARGPARSE_s_s (oPrompt, "prompt",
131 "|ESCSTRING|use ESCSTRING as prompt in pinentry"),
132 ARGPARSE_s_n (oStatusMsg, "enable-status-msg", "@"),
134 ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
136 ARGPARSE_s_n (oDebugUseOCB, "debug-use-ocb", "@"), /* For hacking only. */
142 my_strusage (int level)
147 case 11: p = "gpg-protect-tool (" GNUPG_NAME ")";
149 case 13: p = VERSION; break;
150 case 17: p = PRINTABLE_OS_NAME; break;
151 case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
154 case 40: p = _("Usage: gpg-protect-tool [options] (-h for help)\n");
156 case 41: p = _("Syntax: gpg-protect-tool [options] [args]\n"
157 "Secret key maintenance tool\n");
167 /* print_mpi (const char *text, gcry_mpi_t a) */
170 /* void *bufaddr = &buf; */
173 /* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
175 /* log_info ("%s: [error printing number: %s]\n", text, gpg_strerror (rc)); */
178 /* log_info ("%s: %s\n", text, buf); */
179 /* gcry_free (buf); */
185 static unsigned char *
186 make_canonical (const char *fname, const char *buf, size_t buflen)
191 unsigned char *result;
193 rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
196 log_error ("invalid S-Expression in '%s' (off=%u): %s\n",
197 fname, (unsigned int)erroff, gpg_strerror (rc));
200 len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
202 result = xmalloc (len);
203 len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
205 gcry_sexp_release (sexp);
210 make_advanced (const unsigned char *buf, size_t buflen)
217 rc = gcry_sexp_sscan (&sexp, &erroff, (const char*)buf, buflen);
220 log_error ("invalid canonical S-Expression (off=%u): %s\n",
221 (unsigned int)erroff, gpg_strerror (rc));
224 len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
226 result = xmalloc (len);
227 len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
229 gcry_sexp_release (sexp);
235 read_file (const char *fname, size_t *r_length)
241 if (!strcmp (fname, "-"))
243 size_t nread, bufsize = 0;
246 #ifdef HAVE_DOSISH_SYSTEM
247 setmode ( fileno(fp) , O_BINARY );
256 buf = xmalloc (bufsize);
258 buf = xrealloc (buf, bufsize);
260 nread = fread (buf+buflen, 1, NCHUNK, fp);
261 if (nread < NCHUNK && ferror (fp))
263 log_error ("error reading '[stdin]': %s\n", strerror (errno));
269 while (nread == NCHUNK);
277 fp = fopen (fname, "rb");
280 log_error ("can't open '%s': %s\n", fname, strerror (errno));
284 if (fstat (fileno(fp), &st))
286 log_error ("can't stat '%s': %s\n", fname, strerror (errno));
292 buf = xmalloc (buflen+1);
293 if (fread (buf, buflen, 1, fp) != 1)
295 log_error ("error reading '%s': %s\n", fname, strerror (errno));
308 static unsigned char *
309 read_key (const char *fname)
315 buf = read_file (fname, &buflen);
318 key = make_canonical (fname, buf, buflen);
326 read_and_protect (const char *fname)
330 unsigned char *result;
334 key = read_key (fname);
338 pw = get_passphrase (1);
339 rc = agent_protect (key, pw, &result, &resultlen, 0,
340 opt_debug_use_ocb? 1 : -1);
341 release_passphrase (pw);
345 log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
351 char *p = make_advanced (result, resultlen);
355 result = (unsigned char*)p;
356 resultlen = strlen (p);
359 fwrite (result, resultlen, 1, stdout);
365 read_and_unprotect (ctrl_t ctrl, const char *fname)
369 unsigned char *result;
372 gnupg_isotime_t protected_at;
374 key = read_key (fname);
378 rc = agent_unprotect (ctrl, key, (pw=get_passphrase (1)),
379 protected_at, &result, &resultlen);
380 release_passphrase (pw);
385 log_info ("[PROTECT-TOOL:] bad-passphrase\n");
386 log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
392 log_info ("key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s\n",
393 protected_at, protected_at+4, protected_at+6,
394 protected_at+9, protected_at+11, protected_at+13);
396 log_info ("key protection done at [unknown]\n");
401 char *p = make_advanced (result, resultlen);
405 result = (unsigned char*)p;
406 resultlen = strlen (p);
409 fwrite (result, resultlen, 1, stdout);
416 read_and_shadow (const char *fname)
420 unsigned char *result;
422 unsigned char dummy_info[] = "(8:313233342:43)";
424 key = read_key (fname);
428 rc = agent_shadow_key (key, dummy_info, &result);
432 log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
435 resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
440 char *p = make_advanced (result, resultlen);
444 result = (unsigned char*)p;
445 resultlen = strlen (p);
448 fwrite (result, resultlen, 1, stdout);
453 show_shadow_info (const char *fname)
457 const unsigned char *info;
460 key = read_key (fname);
464 rc = agent_get_shadow_info (key, &info);
468 log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
471 infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
476 char *p = make_advanced (info, infolen);
479 fwrite (p, strlen (p), 1, stdout);
483 fwrite (info, infolen, 1, stdout);
488 show_file (const char *fname)
494 key = read_key (fname);
498 keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
503 fwrite (key, keylen, 1, stdout);
507 p = make_advanced (key, keylen);
510 fwrite (p, strlen (p), 1, stdout);
518 show_keygrip (const char *fname)
522 unsigned char grip[20];
525 key = read_key (fname);
529 if (gcry_sexp_new (&private, key, 0, 0))
531 log_error ("gcry_sexp_new failed\n");
536 if (!gcry_pk_get_keygrip (private, grip))
538 log_error ("can't calculate keygrip\n");
541 gcry_sexp_release (private);
543 for (i=0; i < 20; i++)
544 printf ("%02X", grip[i]);
553 main (int argc, char **argv )
560 early_system_init ();
561 set_strusage (my_strusage);
562 gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
563 log_set_prefix ("gpg-protect-tool", GPGRT_LOG_WITH_PREFIX);
565 /* Make sure that our subsystems are ready. */
567 init_common_subsystems (&argc, &argv);
569 setup_libgcrypt_logging ();
570 gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
574 pargs.flags= 1; /* (do not remove the args) */
575 while (arg_parse (&pargs, opts) )
579 case oVerbose: opt.verbose++; break;
580 case oArmor: opt_armor=1; break;
581 case oCanonical: opt_canonical=1; break;
582 case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
584 case oAgentProgram: opt_agent_program = pargs.r.ret_str; break;
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;
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 case oDebugUseOCB: opt_debug_use_ocb = 1; break;
602 default: pargs.err = ARGPARSE_PRINT_ERROR; break;
605 if (log_get_errorcount (0))
614 /* Allocate an CTRL object. An empty object should be sufficient. */
615 ctrl = xtrycalloc (1, sizeof *ctrl);
618 log_error ("error allocating connection control data: %s\n",
623 /* Set the information which can't be taken from envvars. */
624 gnupg_prepare_get_passphrase (GPG_ERR_SOURCE_DEFAULT,
630 opt_prompt = percent_plus_unescape (opt_prompt, 0);
633 read_and_protect (fname);
634 else if (cmd == oUnprotect)
635 read_and_unprotect (ctrl, fname);
636 else if (cmd == oShadow)
637 read_and_shadow (fname);
638 else if (cmd == oShowShadowInfo)
639 show_shadow_info (fname);
640 else if (cmd == oShowKeygrip)
641 show_keygrip (fname);
642 else if (cmd == oS2Kcalibration)
645 opt.verbose++; /* We need to see something. */
646 get_standard_s2k_count ();
654 return 8; /*NOTREACHED*/
660 rc = rc? rc : log_get_errorcount(0)? 2 : 0;
665 /* Return the passphrase string and ask the agent if it has not been
666 set from the command line PROMPTNO select the prompt to display:
668 1 = taken from the option --prompt
669 2 = for unprotecting a pkcs#12 object
670 3 = for protecting a new pkcs#12 object
671 4 = for protecting an imported pkcs#12 in our system
674 get_passphrase (int promptno)
683 return xstrdup (opt_passphrase);
685 orig_codeset = i18n_switchto_utf8 ();
687 if (promptno == 1 && opt_prompt)
691 else if (promptno == 2)
693 desc = _("Please enter the passphrase to unprotect the "
696 else if (promptno == 3)
698 desc = _("Please enter the passphrase to protect the "
699 "new PKCS#12 object.");
702 else if (promptno == 4)
704 desc = _("Please enter the passphrase to protect the "
705 "imported object within the GnuPG system.");
709 desc = _("Please enter the passphrase or the PIN\n"
710 "needed to complete this operation.");
712 i18n_switchback (orig_codeset);
714 err = gnupg_get_passphrase (NULL, NULL, _("Passphrase:"), desc,
715 repeat, repeat, 1, &pw);
718 if (gpg_err_code (err) == GPG_ERR_CANCELED
719 || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
720 log_info (_("cancelled\n"));
722 log_error (_("error while asking for the passphrase: %s\n"),
733 release_passphrase (char *pw)
737 wipememory (pw, strlen (pw));
745 agent_key_available (const unsigned char *grip)
748 return -1; /* Not available. */
752 agent_get_cache (const char *key, cache_mode_t cache_mode)
760 agent_askpin (ctrl_t ctrl,
761 const char *desc_text, const char *prompt_text,
762 const char *initial_errtext,
763 struct pin_entry_info_s *pininfo,
764 const char *keyinfo, cache_mode_t cache_mode)
767 unsigned char *passphrase;
773 (void)initial_errtext;
777 *pininfo->pin = 0; /* Reset the PIN. */
778 passphrase = get_passphrase (0);
779 size = strlen (passphrase);
780 if (size >= pininfo->max_length)
781 return gpg_error (GPG_ERR_TOO_LARGE);
783 memcpy (&pininfo->pin, passphrase, size);
785 pininfo->pin[size] = 0;
786 if (pininfo->check_cb)
788 /* More checks by utilizing the optional callback. */
789 pininfo->cb_errtext = NULL;
790 err = pininfo->check_cb (pininfo);
797 /* Replacement for the function in findkey.c. Here we write the key
800 agent_write_private_key (const unsigned char *grip,
801 const void *buffer, size_t length, int force)
803 char hexgrip[40+4+1];
808 bin2hex (grip, 20, hexgrip);
809 strcpy (hexgrip+40, ".key");
810 p = make_advanced (buffer, length);
813 printf ("# Begin dump of %s\n%s%s# End dump of %s\n",
814 hexgrip, p, (*p && p[strlen(p)-1] == '\n')? "":"\n", hexgrip);