agent/
[gnupg.git] / agent / protect-tool.c
blob78234d22d21c2b8dc388e867f54e34888cc7caec
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 <http://www.gnu.org/licenses/>.
20 #include <config.h>
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
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 #include "estream.h"
50 enum cmd_and_opt_values
52 aNull = 0,
53 oVerbose = 'v',
54 oArmor = 'a',
55 oPassphrase = 'P',
57 oProtect = 'p',
58 oUnprotect = 'u',
60 oNoVerbose = 500,
61 oShadow,
62 oShowShadowInfo,
63 oShowKeygrip,
64 oCanonical,
66 oP12Import,
67 oP12Export,
68 oP12Charset,
69 oStore,
70 oForce,
71 oHaveCert,
72 oNoFailOnExist,
73 oHomedir,
74 oPrompt,
75 oStatusMsg,
77 oAgentProgram
81 struct rsa_secret_key_s
83 gcry_mpi_t n; /* public modulus */
84 gcry_mpi_t e; /* public exponent */
85 gcry_mpi_t d; /* exponent */
86 gcry_mpi_t p; /* prime p. */
87 gcry_mpi_t q; /* prime q. */
88 gcry_mpi_t u; /* inverse of p mod q. */
92 static const char *opt_homedir;
93 static int opt_armor;
94 static int opt_canonical;
95 static int opt_store;
96 static int opt_force;
97 static int opt_no_fail_on_exist;
98 static int opt_have_cert;
99 static const char *opt_passphrase;
100 static char *opt_prompt;
101 static int opt_status_msg;
102 static const char *opt_p12_charset;
103 static const char *opt_agent_program;
105 static char *get_passphrase (int promptno);
106 static void release_passphrase (char *pw);
107 static int store_private_key (const unsigned char *grip,
108 const void *buffer, size_t length, int force);
111 static ARGPARSE_OPTS opts[] = {
112 ARGPARSE_group (300, N_("@Commands:\n ")),
114 ARGPARSE_c (oProtect, "protect", "protect a private key"),
115 ARGPARSE_c (oUnprotect, "unprotect", "unprotect a private key"),
116 ARGPARSE_c (oShadow, "shadow", "create a shadow entry for a public key"),
117 ARGPARSE_c (oShowShadowInfo, "show-shadow-info", "return the shadow info"),
118 ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""),
119 ARGPARSE_c (oP12Import, "p12-import",
120 "import a pkcs#12 encoded private key"),
121 ARGPARSE_c (oP12Export, "p12-export",
122 "export a private key pkcs#12 encoded"),
124 ARGPARSE_group (301, N_("@\nOptions:\n ")),
126 ARGPARSE_s_n (oVerbose, "verbose", "verbose"),
127 ARGPARSE_s_n (oArmor, "armor", "write output in advanced format"),
128 ARGPARSE_s_n (oCanonical, "canonical", "write output in canonical format"),
130 ARGPARSE_s_s (oPassphrase, "passphrase", "|STRING|use passphrase STRING"),
131 ARGPARSE_s_s (oP12Charset,"p12-charset",
132 "|NAME|set charset for a new PKCS#12 passphrase to NAME"),
133 ARGPARSE_s_n (oHaveCert, "have-cert",
134 "certificate to export provided on STDIN"),
135 ARGPARSE_s_n (oStore, "store",
136 "store the created key in the appropriate place"),
137 ARGPARSE_s_n (oForce, "force",
138 "force overwriting"),
139 ARGPARSE_s_n (oNoFailOnExist, "no-fail-on-exist", "@"),
140 ARGPARSE_s_s (oHomedir, "homedir", "@"),
141 ARGPARSE_s_s (oPrompt, "prompt",
142 "|ESCSTRING|use ESCSTRING as prompt in pinentry"),
143 ARGPARSE_s_n (oStatusMsg, "enable-status-msg", "@"),
145 ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
147 ARGPARSE_end ()
150 static const char *
151 my_strusage (int level)
153 const char *p;
154 switch (level)
156 case 11: p = "gpg-protect-tool (GnuPG)";
157 break;
158 case 13: p = VERSION; break;
159 case 17: p = PRINTABLE_OS_NAME; break;
160 case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
162 case 1:
163 case 40: p = _("Usage: gpg-protect-tool [options] (-h for help)\n");
164 break;
165 case 41: p = _("Syntax: gpg-protect-tool [options] [args]\n"
166 "Secret key maintenance tool\n");
167 break;
169 default: p = NULL;
171 return p;
175 /* static void */
176 /* print_mpi (const char *text, gcry_mpi_t a) */
177 /* { */
178 /* char *buf; */
179 /* void *bufaddr = &buf; */
180 /* int rc; */
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 /* } */
194 static unsigned char *
195 make_canonical (const char *fname, const char *buf, size_t buflen)
197 int rc;
198 size_t erroff, len;
199 gcry_sexp_t sexp;
200 unsigned char *result;
202 rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
203 if (rc)
205 log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
206 fname, (unsigned int)erroff, gpg_strerror (rc));
207 return NULL;
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;
218 static char *
219 make_advanced (const unsigned char *buf, size_t buflen)
221 int rc;
222 size_t erroff, len;
223 gcry_sexp_t sexp;
224 char *result;
226 rc = gcry_sexp_sscan (&sexp, &erroff, (const char*)buf, buflen);
227 if (rc)
229 log_error ("invalid canonical S-Expression (off=%u): %s\n",
230 (unsigned int)erroff, gpg_strerror (rc));
231 return NULL;
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;
243 static char *
244 read_file (const char *fname, size_t *r_length)
246 FILE *fp;
247 char *buf;
248 size_t buflen;
250 if (!strcmp (fname, "-"))
252 size_t nread, bufsize = 0;
254 fp = stdin;
255 #ifdef HAVE_DOSISH_SYSTEM
256 setmode ( fileno(fp) , O_BINARY );
257 #endif
258 buf = NULL;
259 buflen = 0;
260 #define NCHUNK 8192
263 bufsize += NCHUNK;
264 if (!buf)
265 buf = xmalloc (bufsize);
266 else
267 buf = xrealloc (buf, bufsize);
269 nread = fread (buf+buflen, 1, NCHUNK, fp);
270 if (nread < NCHUNK && ferror (fp))
272 log_error ("error reading `[stdin]': %s\n", strerror (errno));
273 xfree (buf);
274 return NULL;
276 buflen += nread;
278 while (nread == NCHUNK);
279 #undef NCHUNK
282 else
284 struct stat st;
286 fp = fopen (fname, "rb");
287 if (!fp)
289 log_error ("can't open `%s': %s\n", fname, strerror (errno));
290 return NULL;
293 if (fstat (fileno(fp), &st))
295 log_error ("can't stat `%s': %s\n", fname, strerror (errno));
296 fclose (fp);
297 return NULL;
300 buflen = st.st_size;
301 buf = xmalloc (buflen+1);
302 if (fread (buf, buflen, 1, fp) != 1)
304 log_error ("error reading `%s': %s\n", fname, strerror (errno));
305 fclose (fp);
306 xfree (buf);
307 return NULL;
309 fclose (fp);
312 *r_length = buflen;
313 return buf;
317 static unsigned char *
318 read_key (const char *fname)
320 char *buf;
321 size_t buflen;
322 unsigned char *key;
324 buf = read_file (fname, &buflen);
325 if (!buf)
326 return NULL;
327 key = make_canonical (fname, buf, buflen);
328 xfree (buf);
329 return key;
334 static void
335 read_and_protect (const char *fname)
337 int rc;
338 unsigned char *key;
339 unsigned char *result;
340 size_t resultlen;
341 char *pw;
343 key = read_key (fname);
344 if (!key)
345 return;
347 pw = get_passphrase (1);
348 rc = agent_protect (key, pw, &result, &resultlen);
349 release_passphrase (pw);
350 xfree (key);
351 if (rc)
353 log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
354 return;
357 if (opt_armor)
359 char *p = make_advanced (result, resultlen);
360 xfree (result);
361 if (!p)
362 return;
363 result = (unsigned char*)p;
364 resultlen = strlen (p);
367 fwrite (result, resultlen, 1, stdout);
368 xfree (result);
372 static void
373 read_and_unprotect (const char *fname)
375 int rc;
376 unsigned char *key;
377 unsigned char *result;
378 size_t resultlen;
379 char *pw;
380 gnupg_isotime_t protected_at;
382 key = read_key (fname);
383 if (!key)
384 return;
386 rc = agent_unprotect (key, (pw=get_passphrase (1)),
387 protected_at, &result, &resultlen);
388 release_passphrase (pw);
389 xfree (key);
390 if (rc)
392 if (opt_status_msg)
393 log_info ("[PROTECT-TOOL:] bad-passphrase\n");
394 log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
395 return;
397 if (opt.verbose)
398 log_info ("key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s\n",
399 protected_at, protected_at+4, protected_at+6,
400 protected_at+9, protected_at+11, protected_at+13);
403 if (opt_armor)
405 char *p = make_advanced (result, resultlen);
406 xfree (result);
407 if (!p)
408 return;
409 result = (unsigned char*)p;
410 resultlen = strlen (p);
413 fwrite (result, resultlen, 1, stdout);
414 xfree (result);
419 static void
420 read_and_shadow (const char *fname)
422 int rc;
423 unsigned char *key;
424 unsigned char *result;
425 size_t resultlen;
426 unsigned char dummy_info[] = "(8:313233342:43)";
428 key = read_key (fname);
429 if (!key)
430 return;
432 rc = agent_shadow_key (key, dummy_info, &result);
433 xfree (key);
434 if (rc)
436 log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
437 return;
439 resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
440 assert (resultlen);
442 if (opt_armor)
444 char *p = make_advanced (result, resultlen);
445 xfree (result);
446 if (!p)
447 return;
448 result = (unsigned char*)p;
449 resultlen = strlen (p);
452 fwrite (result, resultlen, 1, stdout);
453 xfree (result);
456 static void
457 show_shadow_info (const char *fname)
459 int rc;
460 unsigned char *key;
461 const unsigned char *info;
462 size_t infolen;
464 key = read_key (fname);
465 if (!key)
466 return;
468 rc = agent_get_shadow_info (key, &info);
469 xfree (key);
470 if (rc)
472 log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
473 return;
475 infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
476 assert (infolen);
478 if (opt_armor)
480 char *p = make_advanced (info, infolen);
481 if (!p)
482 return;
483 fwrite (p, strlen (p), 1, stdout);
484 xfree (p);
486 else
487 fwrite (info, infolen, 1, stdout);
491 static void
492 show_file (const char *fname)
494 unsigned char *key;
495 size_t keylen;
496 char *p;
498 key = read_key (fname);
499 if (!key)
500 return;
502 keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
503 assert (keylen);
505 if (opt_canonical)
507 fwrite (key, keylen, 1, stdout);
509 else
511 p = make_advanced (key, keylen);
512 if (p)
514 fwrite (p, strlen (p), 1, stdout);
515 xfree (p);
518 xfree (key);
521 static void
522 show_keygrip (const char *fname)
524 unsigned char *key;
525 gcry_sexp_t private;
526 unsigned char grip[20];
527 int i;
529 key = read_key (fname);
530 if (!key)
531 return;
533 if (gcry_sexp_new (&private, key, 0, 0))
535 log_error ("gcry_sexp_new failed\n");
536 return;
538 xfree (key);
540 if (!gcry_pk_get_keygrip (private, grip))
542 log_error ("can't calculate keygrip\n");
543 return;
545 gcry_sexp_release (private);
547 for (i=0; i < 20; i++)
548 printf ("%02X", grip[i]);
549 putchar ('\n');
553 static int
554 rsa_key_check (struct rsa_secret_key_s *skey)
556 int err = 0;
557 gcry_mpi_t t = gcry_mpi_snew (0);
558 gcry_mpi_t t1 = gcry_mpi_snew (0);
559 gcry_mpi_t t2 = gcry_mpi_snew (0);
560 gcry_mpi_t phi = gcry_mpi_snew (0);
562 /* check that n == p * q */
563 gcry_mpi_mul (t, skey->p, skey->q);
564 if (gcry_mpi_cmp( t, skey->n) )
566 log_error ("RSA oops: n != p * q\n");
567 err++;
570 /* check that p is less than q */
571 if (gcry_mpi_cmp (skey->p, skey->q) > 0)
573 gcry_mpi_t tmp;
575 log_info ("swapping secret primes\n");
576 tmp = gcry_mpi_copy (skey->p);
577 gcry_mpi_set (skey->p, skey->q);
578 gcry_mpi_set (skey->q, tmp);
579 gcry_mpi_release (tmp);
580 /* and must recompute u of course */
581 gcry_mpi_invm (skey->u, skey->p, skey->q);
584 /* check that e divides neither p-1 nor q-1 */
585 gcry_mpi_sub_ui (t, skey->p, 1 );
586 gcry_mpi_div (NULL, t, t, skey->e, 0);
587 if (!gcry_mpi_cmp_ui( t, 0) )
589 log_error ("RSA oops: e divides p-1\n");
590 err++;
592 gcry_mpi_sub_ui (t, skey->q, 1);
593 gcry_mpi_div (NULL, t, t, skey->e, 0);
594 if (!gcry_mpi_cmp_ui( t, 0))
596 log_info ( "RSA oops: e divides q-1\n" );
597 err++;
600 /* check that d is correct. */
601 gcry_mpi_sub_ui (t1, skey->p, 1);
602 gcry_mpi_sub_ui (t2, skey->q, 1);
603 gcry_mpi_mul (phi, t1, t2);
604 gcry_mpi_invm (t, skey->e, phi);
605 if (gcry_mpi_cmp (t, skey->d))
606 { /* no: try universal exponent. */
607 gcry_mpi_gcd (t, t1, t2);
608 gcry_mpi_div (t, NULL, phi, t, 0);
609 gcry_mpi_invm (t, skey->e, t);
610 if (gcry_mpi_cmp (t, skey->d))
612 log_error ("RSA oops: bad secret exponent\n");
613 err++;
617 /* check for correctness of u */
618 gcry_mpi_invm (t, skey->p, skey->q);
619 if (gcry_mpi_cmp (t, skey->u))
621 log_info ( "RSA oops: bad u parameter\n");
622 err++;
625 if (err)
626 log_info ("RSA secret key check failed\n");
628 gcry_mpi_release (t);
629 gcry_mpi_release (t1);
630 gcry_mpi_release (t2);
631 gcry_mpi_release (phi);
633 return err? -1:0;
637 /* A callback used by p12_parse to return a certificate. */
638 static void
639 import_p12_cert_cb (void *opaque, const unsigned char *cert, size_t certlen)
641 struct b64state state;
642 gpg_error_t err, err2;
644 (void)opaque;
646 err = b64enc_start (&state, stdout, "CERTIFICATE");
647 if (!err)
648 err = b64enc_write (&state, cert, certlen);
649 err2 = b64enc_finish (&state);
650 if (!err)
651 err = err2;
652 if (err)
653 log_error ("error writing armored certificate: %s\n", gpg_strerror (err));
656 static void
657 import_p12_file (const char *fname)
659 char *buf;
660 unsigned char *result;
661 size_t buflen, resultlen, buf_off;
662 int i;
663 int rc;
664 gcry_mpi_t *kparms;
665 struct rsa_secret_key_s sk;
666 gcry_sexp_t s_key;
667 unsigned char *key;
668 unsigned char grip[20];
669 char *pw;
671 /* fixme: we should release some stuff on error */
673 buf = read_file (fname, &buflen);
674 if (!buf)
675 return;
677 /* GnuPG 2.0.4 accidently created binary P12 files with the string
678 "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data.
679 We fix that here. */
680 if (buflen > 29 && !memcmp (buf, "The passphrase is ", 18))
682 for (buf_off=18; buf_off < buflen && buf[buf_off] != '\n'; buf_off++)
684 buf_off++;
685 if (buf_off < buflen && buf[buf_off] == '\n')
686 buf_off++;
688 else
689 buf_off = 0;
691 kparms = p12_parse ((unsigned char*)buf+buf_off, buflen-buf_off,
692 (pw=get_passphrase (2)),
693 import_p12_cert_cb, NULL);
694 release_passphrase (pw);
695 xfree (buf);
696 if (!kparms)
698 log_error ("error parsing or decrypting the PKCS-12 file\n");
699 return;
701 for (i=0; kparms[i]; i++)
703 if (i != 8)
705 log_error ("invalid structure of private key\n");
706 return;
710 /* print_mpi (" n", kparms[0]); */
711 /* print_mpi (" e", kparms[1]); */
712 /* print_mpi (" d", kparms[2]); */
713 /* print_mpi (" p", kparms[3]); */
714 /* print_mpi (" q", kparms[4]); */
715 /* print_mpi ("dmp1", kparms[5]); */
716 /* print_mpi ("dmq1", kparms[6]); */
717 /* print_mpi (" u", kparms[7]); */
719 sk.n = kparms[0];
720 sk.e = kparms[1];
721 sk.d = kparms[2];
722 sk.q = kparms[3];
723 sk.p = kparms[4];
724 sk.u = kparms[7];
725 if (rsa_key_check (&sk))
726 return;
727 /* print_mpi (" n", sk.n); */
728 /* print_mpi (" e", sk.e); */
729 /* print_mpi (" d", sk.d); */
730 /* print_mpi (" p", sk.p); */
731 /* print_mpi (" q", sk.q); */
732 /* print_mpi (" u", sk.u); */
734 /* Create an S-expresion from the parameters. */
735 rc = gcry_sexp_build (&s_key, NULL,
736 "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
737 sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
738 for (i=0; i < 8; i++)
739 gcry_mpi_release (kparms[i]);
740 gcry_free (kparms);
741 if (rc)
743 log_error ("failed to created S-expression from key: %s\n",
744 gpg_strerror (rc));
745 return;
748 /* Compute the keygrip. */
749 if (!gcry_pk_get_keygrip (s_key, grip))
751 log_error ("can't calculate keygrip\n");
752 return;
754 log_info ("keygrip: ");
755 for (i=0; i < 20; i++)
756 log_printf ("%02X", grip[i]);
757 log_printf ("\n");
759 /* Convert to canonical encoding. */
760 buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0);
761 assert (buflen);
762 key = gcry_xmalloc_secure (buflen);
763 buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, key, buflen);
764 assert (buflen);
765 gcry_sexp_release (s_key);
767 pw = get_passphrase (4);
768 rc = agent_protect (key, pw, &result, &resultlen);
769 release_passphrase (pw);
770 xfree (key);
771 if (rc)
773 log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
774 return;
777 if (opt_armor)
779 char *p = make_advanced (result, resultlen);
780 xfree (result);
781 if (!p)
782 return;
783 result = (unsigned char*)p;
784 resultlen = strlen (p);
787 if (opt_store)
788 store_private_key (grip, result, resultlen, opt_force);
789 else
790 fwrite (result, resultlen, 1, stdout);
792 xfree (result);
797 static gcry_mpi_t *
798 sexp_to_kparms (gcry_sexp_t sexp)
800 gcry_sexp_t list, l2;
801 const char *name;
802 const char *s;
803 size_t n;
804 int i, idx;
805 const char *elems;
806 gcry_mpi_t *array;
808 list = gcry_sexp_find_token (sexp, "private-key", 0 );
809 if(!list)
810 return NULL;
811 l2 = gcry_sexp_cadr (list);
812 gcry_sexp_release (list);
813 list = l2;
814 name = gcry_sexp_nth_data (list, 0, &n);
815 if(!name || n != 3 || memcmp (name, "rsa", 3))
817 gcry_sexp_release (list);
818 return NULL;
821 /* Parameter names used with RSA. */
822 elems = "nedpqu";
823 array = xcalloc (strlen(elems) + 1, sizeof *array);
824 for (idx=0, s=elems; *s; s++, idx++ )
826 l2 = gcry_sexp_find_token (list, s, 1);
827 if (!l2)
829 for (i=0; i<idx; i++)
830 gcry_mpi_release (array[i]);
831 xfree (array);
832 gcry_sexp_release (list);
833 return NULL; /* required parameter not found */
835 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
836 gcry_sexp_release (l2);
837 if (!array[idx])
839 for (i=0; i<idx; i++)
840 gcry_mpi_release (array[i]);
841 xfree (array);
842 gcry_sexp_release (list);
843 return NULL; /* required parameter is invalid */
847 gcry_sexp_release (list);
848 return array;
852 /* Check whether STRING is a KEYGRIP, i.e has the correct length and
853 does only consist of uppercase hex characters. */
854 static int
855 is_keygrip (const char *string)
857 int i;
859 for(i=0; string[i] && i < 41; i++)
860 if (!strchr("01234567890ABCDEF", string[i]))
861 return 0;
862 return i == 40;
866 static void
867 export_p12_file (const char *fname)
869 int rc;
870 gcry_mpi_t kparms[9], *kp;
871 unsigned char *key;
872 size_t keylen;
873 gcry_sexp_t private;
874 struct rsa_secret_key_s sk;
875 int i;
876 unsigned char *cert = NULL;
877 size_t certlen = 0;
878 int keytype;
879 size_t keylen_for_wipe = 0;
880 char *pw;
882 if ( is_keygrip (fname) )
884 char hexgrip[40+4+1];
885 char *p;
887 assert (strlen(fname) == 40);
888 strcpy (stpcpy (hexgrip, fname), ".key");
890 p = make_filename (opt_homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
891 key = read_key (p);
892 xfree (p);
894 else
895 key = read_key (fname);
897 if (!key)
898 return;
900 keytype = agent_private_key_type (key);
901 if (keytype == PRIVATE_KEY_PROTECTED)
903 unsigned char *tmpkey;
904 size_t tmplen;
906 rc = agent_unprotect (key, (pw=get_passphrase (1)),
907 NULL, &tmpkey, &tmplen);
908 release_passphrase (pw);
909 if (rc)
911 if (opt_status_msg && gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE )
912 log_info ("[PROTECT-TOOL:] bad-passphrase\n");
913 log_error ("unprotecting key `%s' failed: %s\n",
914 fname, gpg_strerror (rc));
915 xfree (key);
916 return;
918 xfree (key);
919 key = tmpkey;
920 keylen_for_wipe = tmplen;
922 keytype = agent_private_key_type (key);
925 if (keytype == PRIVATE_KEY_SHADOWED)
927 log_error ("`%s' is a shadowed private key - can't export it\n", fname);
928 wipememory (key, keylen_for_wipe);
929 xfree (key);
930 return;
932 else if (keytype != PRIVATE_KEY_CLEAR)
934 log_error ("\%s' is not a private key\n", fname);
935 wipememory (key, keylen_for_wipe);
936 xfree (key);
937 return;
941 if (opt_have_cert)
943 cert = (unsigned char*)read_file ("-", &certlen);
944 if (!cert)
946 wipememory (key, keylen_for_wipe);
947 xfree (key);
948 return;
953 if (gcry_sexp_new (&private, key, 0, 0))
955 log_error ("gcry_sexp_new failed\n");
956 wipememory (key, keylen_for_wipe);
957 xfree (key);
958 xfree (cert);
959 return;
961 wipememory (key, keylen_for_wipe);
962 xfree (key);
964 kp = sexp_to_kparms (private);
965 gcry_sexp_release (private);
966 if (!kp)
968 log_error ("error converting key parameters\n");
969 xfree (cert);
970 return;
972 sk.n = kp[0];
973 sk.e = kp[1];
974 sk.d = kp[2];
975 sk.p = kp[3];
976 sk.q = kp[4];
977 sk.u = kp[5];
978 xfree (kp);
981 kparms[0] = sk.n;
982 kparms[1] = sk.e;
983 kparms[2] = sk.d;
984 kparms[3] = sk.q;
985 kparms[4] = sk.p;
986 kparms[5] = gcry_mpi_snew (0); /* compute d mod (p-1) */
987 gcry_mpi_sub_ui (kparms[5], kparms[3], 1);
988 gcry_mpi_mod (kparms[5], sk.d, kparms[5]);
989 kparms[6] = gcry_mpi_snew (0); /* compute d mod (q-1) */
990 gcry_mpi_sub_ui (kparms[6], kparms[4], 1);
991 gcry_mpi_mod (kparms[6], sk.d, kparms[6]);
992 kparms[7] = sk.u;
993 kparms[8] = NULL;
995 pw = get_passphrase (3);
996 key = p12_build (kparms, cert, certlen, pw, opt_p12_charset, &keylen);
997 release_passphrase (pw);
998 xfree (cert);
999 for (i=0; i < 8; i++)
1000 gcry_mpi_release (kparms[i]);
1001 if (!key)
1002 return;
1004 #ifdef HAVE_DOSISH_SYSTEM
1005 setmode ( fileno (stdout) , O_BINARY );
1006 #endif
1007 fwrite (key, keylen, 1, stdout);
1008 xfree (key);
1014 main (int argc, char **argv )
1016 ARGPARSE_ARGS pargs;
1017 int cmd = 0;
1018 const char *fname;
1020 set_strusage (my_strusage);
1021 gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
1022 log_set_prefix ("gpg-protect-tool", 1);
1024 /* Make sure that our subsystems are ready. */
1025 i18n_init ();
1026 init_common_subsystems ();
1028 if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
1030 log_fatal( _("%s is too old (need %s, have %s)\n"), "libgcrypt",
1031 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
1034 setup_libgcrypt_logging ();
1035 gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1038 opt_homedir = default_homedir ();
1041 pargs.argc = &argc;
1042 pargs.argv = &argv;
1043 pargs.flags= 1; /* (do not remove the args) */
1044 while (arg_parse (&pargs, opts) )
1046 switch (pargs.r_opt)
1048 case oVerbose: opt.verbose++; break;
1049 case oArmor: opt_armor=1; break;
1050 case oCanonical: opt_canonical=1; break;
1051 case oHomedir: opt_homedir = pargs.r.ret_str; break;
1053 case oAgentProgram: opt_agent_program = pargs.r.ret_str; break;
1055 case oProtect: cmd = oProtect; break;
1056 case oUnprotect: cmd = oUnprotect; break;
1057 case oShadow: cmd = oShadow; break;
1058 case oShowShadowInfo: cmd = oShowShadowInfo; break;
1059 case oShowKeygrip: cmd = oShowKeygrip; break;
1060 case oP12Import: cmd = oP12Import; break;
1061 case oP12Export: cmd = oP12Export; break;
1062 case oP12Charset: opt_p12_charset = pargs.r.ret_str; break;
1064 case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
1065 case oStore: opt_store = 1; break;
1066 case oForce: opt_force = 1; break;
1067 case oNoFailOnExist: opt_no_fail_on_exist = 1; break;
1068 case oHaveCert: opt_have_cert = 1; break;
1069 case oPrompt: opt_prompt = pargs.r.ret_str; break;
1070 case oStatusMsg: opt_status_msg = 1; break;
1072 default: pargs.err = ARGPARSE_PRINT_ERROR; break;
1075 if (log_get_errorcount (0))
1076 exit (2);
1078 fname = "-";
1079 if (argc == 1)
1080 fname = *argv;
1081 else if (argc > 1)
1082 usage (1);
1084 /* Set the information which can't be taken from envvars. */
1085 gnupg_prepare_get_passphrase (GPG_ERR_SOURCE_DEFAULT,
1086 opt.verbose,
1087 opt_homedir,
1088 opt_agent_program,
1089 NULL, NULL, NULL);
1091 if (opt_prompt)
1092 opt_prompt = percent_plus_unescape (opt_prompt, 0);
1094 if (cmd == oProtect)
1095 read_and_protect (fname);
1096 else if (cmd == oUnprotect)
1097 read_and_unprotect (fname);
1098 else if (cmd == oShadow)
1099 read_and_shadow (fname);
1100 else if (cmd == oShowShadowInfo)
1101 show_shadow_info (fname);
1102 else if (cmd == oShowKeygrip)
1103 show_keygrip (fname);
1104 else if (cmd == oP12Import)
1105 import_p12_file (fname);
1106 else if (cmd == oP12Export)
1107 export_p12_file (fname);
1108 else
1109 show_file (fname);
1111 agent_exit (0);
1112 return 8; /*NOTREACHED*/
1115 void
1116 agent_exit (int rc)
1118 rc = rc? rc : log_get_errorcount(0)? 2 : 0;
1119 exit (rc);
1123 /* Return the passphrase string and ask the agent if it has not been
1124 set from the command line PROMPTNO select the prompt to display:
1125 0 = default
1126 1 = taken from the option --prompt
1127 2 = for unprotecting a pkcs#12 object
1128 3 = for protecting a new pkcs#12 object
1129 4 = for protecting an imported pkcs#12 in our system
1131 static char *
1132 get_passphrase (int promptno)
1134 char *pw;
1135 int err;
1136 const char *desc;
1137 char *orig_codeset;
1138 int repeat = 0;
1140 if (opt_passphrase)
1141 return xstrdup (opt_passphrase);
1143 orig_codeset = i18n_switchto_utf8 ();
1145 if (promptno == 1 && opt_prompt)
1147 desc = opt_prompt;
1149 else if (promptno == 2)
1151 desc = _("Please enter the passphrase to unprotect the "
1152 "PKCS#12 object.");
1154 else if (promptno == 3)
1156 desc = _("Please enter the passphrase to protect the "
1157 "new PKCS#12 object.");
1158 repeat = 1;
1160 else if (promptno == 4)
1162 desc = _("Please enter the passphrase to protect the "
1163 "imported object within the GnuPG system.");
1164 repeat = 1;
1166 else
1167 desc = _("Please enter the passphrase or the PIN\n"
1168 "needed to complete this operation.");
1170 i18n_switchback (orig_codeset);
1172 err = gnupg_get_passphrase (NULL, NULL, _("Passphrase:"), desc,
1173 repeat, repeat, 1, &pw);
1174 if (err)
1176 if (gpg_err_code (err) == GPG_ERR_CANCELED)
1177 log_info (_("cancelled\n"));
1178 else
1179 log_error (_("error while asking for the passphrase: %s\n"),
1180 gpg_strerror (err));
1181 agent_exit (0);
1183 assert (pw);
1185 return pw;
1189 static void
1190 release_passphrase (char *pw)
1192 if (pw)
1194 wipememory (pw, strlen (pw));
1195 xfree (pw);
1199 static int
1200 store_private_key (const unsigned char *grip,
1201 const void *buffer, size_t length, int force)
1203 char *fname;
1204 estream_t fp;
1205 char hexgrip[40+4+1];
1207 bin2hex (grip, 20, hexgrip);
1208 strcpy (hexgrip+40, ".key");
1210 fname = make_filename (opt_homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
1211 if (force)
1212 fp = es_fopen (fname, "wb");
1213 else
1215 if (!access (fname, F_OK))
1217 if (opt_status_msg)
1218 log_info ("[PROTECT-TOOL:] secretkey-exists\n");
1219 if (opt_no_fail_on_exist)
1220 log_info ("secret key file `%s' already exists\n", fname);
1221 else
1222 log_error ("secret key file `%s' already exists\n", fname);
1223 xfree (fname);
1224 return opt_no_fail_on_exist? 0 : -1;
1226 /* FWIW: Under Windows Vista the standard fopen in the msvcrt
1227 fails if the "x" GNU extension is used. */
1228 fp = es_fopen (fname, "wbx");
1231 if (!fp)
1233 log_error ("can't create `%s': %s\n", fname, strerror (errno));
1234 xfree (fname);
1235 return -1;
1238 if (es_fwrite (buffer, length, 1, fp) != 1)
1240 log_error ("error writing `%s': %s\n", fname, strerror (errno));
1241 es_fclose (fp);
1242 remove (fname);
1243 xfree (fname);
1244 return -1;
1246 if (es_fclose (fp))
1248 log_error ("error closing `%s': %s\n", fname, strerror (errno));
1249 remove (fname);
1250 xfree (fname);
1251 return -1;
1253 log_info ("secret key stored as `%s'\n", fname);
1255 if (opt_status_msg)
1256 log_info ("[PROTECT-TOOL:] secretkey-stored\n");
1258 xfree (fname);
1259 return 0;