2009-05-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / protect-tool.c
blobd0b68a1fac8a8bdbb619295c968814520f9220b0
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"
49 enum cmd_and_opt_values
51 aNull = 0,
52 oVerbose = 'v',
53 oArmor = 'a',
54 oPassphrase = 'P',
56 oProtect = 'p',
57 oUnprotect = 'u',
59 oNoVerbose = 500,
60 oShadow,
61 oShowShadowInfo,
62 oShowKeygrip,
63 oCanonical,
65 oP12Import,
66 oP12Export,
67 oP12Charset,
68 oStore,
69 oForce,
70 oHaveCert,
71 oNoFailOnExist,
72 oHomedir,
73 oPrompt,
74 oStatusMsg,
76 oAgentProgram
80 struct rsa_secret_key_s
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. */
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;
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);
110 static ARGPARSE_OPTS opts[] = {
111 ARGPARSE_group (300, N_("@Commands:\n ")),
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"),
123 ARGPARSE_group (301, N_("@\nOptions:\n ")),
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"),
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", "@"),
144 ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
146 ARGPARSE_end ()
149 static const char *
150 my_strusage (int level)
152 const char *p;
153 switch (level)
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;
168 default: p = NULL;
170 return p;
174 /* static void */
175 /* print_mpi (const char *text, gcry_mpi_t a) */
176 /* { */
177 /* char *buf; */
178 /* void *bufaddr = &buf; */
179 /* int rc; */
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 /* } */
193 static unsigned char *
194 make_canonical (const char *fname, const char *buf, size_t buflen)
196 int rc;
197 size_t erroff, len;
198 gcry_sexp_t sexp;
199 unsigned char *result;
201 rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
202 if (rc)
204 log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
205 fname, (unsigned int)erroff, gpg_strerror (rc));
206 return NULL;
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;
217 static char *
218 make_advanced (const unsigned char *buf, size_t buflen)
220 int rc;
221 size_t erroff, len;
222 gcry_sexp_t sexp;
223 char *result;
225 rc = gcry_sexp_sscan (&sexp, &erroff, (const char*)buf, buflen);
226 if (rc)
228 log_error ("invalid canonical S-Expression (off=%u): %s\n",
229 (unsigned int)erroff, gpg_strerror (rc));
230 return NULL;
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;
242 static char *
243 read_file (const char *fname, size_t *r_length)
245 FILE *fp;
246 char *buf;
247 size_t buflen;
249 if (!strcmp (fname, "-"))
251 size_t nread, bufsize = 0;
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
262 bufsize += NCHUNK;
263 if (!buf)
264 buf = xmalloc (bufsize);
265 else
266 buf = xrealloc (buf, bufsize);
268 nread = fread (buf+buflen, 1, NCHUNK, fp);
269 if (nread < NCHUNK && ferror (fp))
271 log_error ("error reading `[stdin]': %s\n", strerror (errno));
272 xfree (buf);
273 return NULL;
275 buflen += nread;
277 while (nread == NCHUNK);
278 #undef NCHUNK
281 else
283 struct stat st;
285 fp = fopen (fname, "rb");
286 if (!fp)
288 log_error ("can't open `%s': %s\n", fname, strerror (errno));
289 return NULL;
292 if (fstat (fileno(fp), &st))
294 log_error ("can't stat `%s': %s\n", fname, strerror (errno));
295 fclose (fp);
296 return NULL;
299 buflen = st.st_size;
300 buf = xmalloc (buflen+1);
301 if (fread (buf, buflen, 1, fp) != 1)
303 log_error ("error reading `%s': %s\n", fname, strerror (errno));
304 fclose (fp);
305 xfree (buf);
306 return NULL;
308 fclose (fp);
311 *r_length = buflen;
312 return buf;
316 static unsigned char *
317 read_key (const char *fname)
319 char *buf;
320 size_t buflen;
321 unsigned char *key;
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;
333 static void
334 read_and_protect (const char *fname)
336 int rc;
337 unsigned char *key;
338 unsigned char *result;
339 size_t resultlen;
340 char *pw;
342 key = read_key (fname);
343 if (!key)
344 return;
346 pw = get_passphrase (1);
347 rc = agent_protect (key, pw, &result, &resultlen);
348 release_passphrase (pw);
349 xfree (key);
350 if (rc)
352 log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
353 return;
356 if (opt_armor)
358 char *p = make_advanced (result, resultlen);
359 xfree (result);
360 if (!p)
361 return;
362 result = (unsigned char*)p;
363 resultlen = strlen (p);
366 fwrite (result, resultlen, 1, stdout);
367 xfree (result);
371 static void
372 read_and_unprotect (const char *fname)
374 int rc;
375 unsigned char *key;
376 unsigned char *result;
377 size_t resultlen;
378 char *pw;
379 gnupg_isotime_t protected_at;
381 key = read_key (fname);
382 if (!key)
383 return;
385 rc = agent_unprotect (key, (pw=get_passphrase (1)),
386 protected_at, &result, &resultlen);
387 release_passphrase (pw);
388 xfree (key);
389 if (rc)
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;
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);
402 if (opt_armor)
404 char *p = make_advanced (result, resultlen);
405 xfree (result);
406 if (!p)
407 return;
408 result = (unsigned char*)p;
409 resultlen = strlen (p);
412 fwrite (result, resultlen, 1, stdout);
413 xfree (result);
418 static void
419 read_and_shadow (const char *fname)
421 int rc;
422 unsigned char *key;
423 unsigned char *result;
424 size_t resultlen;
425 unsigned char dummy_info[] = "(8:313233342:43)";
427 key = read_key (fname);
428 if (!key)
429 return;
431 rc = agent_shadow_key (key, dummy_info, &result);
432 xfree (key);
433 if (rc)
435 log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
436 return;
438 resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
439 assert (resultlen);
441 if (opt_armor)
443 char *p = make_advanced (result, resultlen);
444 xfree (result);
445 if (!p)
446 return;
447 result = (unsigned char*)p;
448 resultlen = strlen (p);
451 fwrite (result, resultlen, 1, stdout);
452 xfree (result);
455 static void
456 show_shadow_info (const char *fname)
458 int rc;
459 unsigned char *key;
460 const unsigned char *info;
461 size_t infolen;
463 key = read_key (fname);
464 if (!key)
465 return;
467 rc = agent_get_shadow_info (key, &info);
468 xfree (key);
469 if (rc)
471 log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
472 return;
474 infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
475 assert (infolen);
477 if (opt_armor)
479 char *p = make_advanced (info, infolen);
480 if (!p)
481 return;
482 fwrite (p, strlen (p), 1, stdout);
483 xfree (p);
485 else
486 fwrite (info, infolen, 1, stdout);
490 static void
491 show_file (const char *fname)
493 unsigned char *key;
494 size_t keylen;
495 char *p;
497 key = read_key (fname);
498 if (!key)
499 return;
501 keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
502 assert (keylen);
504 if (opt_canonical)
506 fwrite (key, keylen, 1, stdout);
508 else
510 p = make_advanced (key, keylen);
511 if (p)
513 fwrite (p, strlen (p), 1, stdout);
514 xfree (p);
517 xfree (key);
520 static void
521 show_keygrip (const char *fname)
523 unsigned char *key;
524 gcry_sexp_t private;
525 unsigned char grip[20];
526 int i;
528 key = read_key (fname);
529 if (!key)
530 return;
532 if (gcry_sexp_new (&private, key, 0, 0))
534 log_error ("gcry_sexp_new failed\n");
535 return;
537 xfree (key);
539 if (!gcry_pk_get_keygrip (private, grip))
541 log_error ("can't calculate keygrip\n");
542 return;
544 gcry_sexp_release (private);
546 for (i=0; i < 20; i++)
547 printf ("%02X", grip[i]);
548 putchar ('\n');
552 static int
553 rsa_key_check (struct rsa_secret_key_s *skey)
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);
561 /* check that n == p * q */
562 gcry_mpi_mul (t, skey->p, skey->q);
563 if (gcry_mpi_cmp( t, skey->n) )
565 log_error ("RSA oops: n != p * q\n");
566 err++;
569 /* check that p is less than q */
570 if (gcry_mpi_cmp (skey->p, skey->q) > 0)
572 gcry_mpi_t tmp;
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);
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) )
588 log_error ("RSA oops: e divides p-1\n");
589 err++;
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))
595 log_info ( "RSA oops: e divides q-1\n" );
596 err++;
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))
611 log_error ("RSA oops: bad secret exponent\n");
612 err++;
616 /* check for correctness of u */
617 gcry_mpi_invm (t, skey->p, skey->q);
618 if (gcry_mpi_cmp (t, skey->u))
620 log_info ( "RSA oops: bad u parameter\n");
621 err++;
624 if (err)
625 log_info ("RSA secret key check failed\n");
627 gcry_mpi_release (t);
628 gcry_mpi_release (t1);
629 gcry_mpi_release (t2);
630 gcry_mpi_release (phi);
632 return err? -1:0;
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)
640 struct b64state state;
641 gpg_error_t err, err2;
643 (void)opaque;
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));
655 static void
656 import_p12_file (const char *fname)
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;
670 /* fixme: we should release some stuff on error */
672 buf = read_file (fname, &buflen);
673 if (!buf)
674 return;
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))
681 for (buf_off=18; buf_off < buflen && buf[buf_off] != '\n'; buf_off++)
683 buf_off++;
684 if (buf_off < buflen && buf[buf_off] == '\n')
685 buf_off++;
687 else
688 buf_off = 0;
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)
697 log_error ("error parsing or decrypting the PKCS-12 file\n");
698 return;
700 for (i=0; kparms[i]; i++)
702 if (i != 8)
704 log_error ("invalid structure of private key\n");
705 return;
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]); */
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); */
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)
742 log_error ("failed to created S-expression from key: %s\n",
743 gpg_strerror (rc));
744 return;
747 /* Compute the keygrip. */
748 if (!gcry_pk_get_keygrip (s_key, grip))
750 log_error ("can't calculate keygrip\n");
751 return;
753 log_info ("keygrip: ");
754 for (i=0; i < 20; i++)
755 log_printf ("%02X", grip[i]);
756 log_printf ("\n");
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);
766 pw = get_passphrase (4);
767 rc = agent_protect (key, pw, &result, &resultlen);
768 release_passphrase (pw);
769 xfree (key);
770 if (rc)
772 log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
773 return;
776 if (opt_armor)
778 char *p = make_advanced (result, resultlen);
779 xfree (result);
780 if (!p)
781 return;
782 result = (unsigned char*)p;
783 resultlen = strlen (p);
786 if (opt_store)
787 store_private_key (grip, result, resultlen, opt_force);
788 else
789 fwrite (result, resultlen, 1, stdout);
791 xfree (result);
796 static gcry_mpi_t *
797 sexp_to_kparms (gcry_sexp_t sexp)
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;
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))
816 gcry_sexp_release (list);
817 return NULL;
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++ )
825 l2 = gcry_sexp_find_token (list, s, 1);
826 if (!l2)
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 */
834 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
835 gcry_sexp_release (l2);
836 if (!array[idx])
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 */
846 gcry_sexp_release (list);
847 return array;
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)
856 int i;
858 for(i=0; string[i] && i < 41; i++)
859 if (!strchr("01234567890ABCDEF", string[i]))
860 return 0;
861 return i == 40;
865 static void
866 export_p12_file (const char *fname)
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;
881 if ( is_keygrip (fname) )
883 char hexgrip[40+4+1];
884 char *p;
886 assert (strlen(fname) == 40);
887 strcpy (stpcpy (hexgrip, fname), ".key");
889 p = make_filename (opt_homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
890 key = read_key (p);
891 xfree (p);
893 else
894 key = read_key (fname);
896 if (!key)
897 return;
899 keytype = agent_private_key_type (key);
900 if (keytype == PRIVATE_KEY_PROTECTED)
902 unsigned char *tmpkey;
903 size_t tmplen;
905 rc = agent_unprotect (key, (pw=get_passphrase (1)),
906 NULL, &tmpkey, &tmplen);
907 release_passphrase (pw);
908 if (rc)
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;
917 xfree (key);
918 key = tmpkey;
919 keylen_for_wipe = tmplen;
921 keytype = agent_private_key_type (key);
924 if (keytype == PRIVATE_KEY_SHADOWED)
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;
931 else if (keytype != PRIVATE_KEY_CLEAR)
933 log_error ("\%s' is not a private key\n", fname);
934 wipememory (key, keylen_for_wipe);
935 xfree (key);
936 return;
940 if (opt_have_cert)
942 cert = (unsigned char*)read_file ("-", &certlen);
943 if (!cert)
945 wipememory (key, keylen_for_wipe);
946 xfree (key);
947 return;
952 if (gcry_sexp_new (&private, key, 0, 0))
954 log_error ("gcry_sexp_new failed\n");
955 wipememory (key, keylen_for_wipe);
956 xfree (key);
957 xfree (cert);
958 return;
960 wipememory (key, keylen_for_wipe);
961 xfree (key);
963 kp = sexp_to_kparms (private);
964 gcry_sexp_release (private);
965 if (!kp)
967 log_error ("error converting key parameters\n");
968 xfree (cert);
969 return;
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);
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;
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;
1003 #ifdef HAVE_DOSISH_SYSTEM
1004 setmode ( fileno (stdout) , O_BINARY );
1005 #endif
1006 fwrite (key, keylen, 1, stdout);
1007 xfree (key);
1013 main (int argc, char **argv )
1015 ARGPARSE_ARGS pargs;
1016 int cmd = 0;
1017 const char *fname;
1019 set_strusage (my_strusage);
1020 gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
1021 log_set_prefix ("gpg-protect-tool", 1);
1023 /* Make sure that our subsystems are ready. */
1024 i18n_init ();
1025 init_common_subsystems ();
1027 if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
1029 log_fatal( _("%s is too old (need %s, have %s)\n"), "libgcrypt",
1030 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
1033 setup_libgcrypt_logging ();
1034 gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1037 opt_homedir = default_homedir ();
1040 pargs.argc = &argc;
1041 pargs.argv = &argv;
1042 pargs.flags= 1; /* (do not remove the args) */
1043 while (arg_parse (&pargs, opts) )
1045 switch (pargs.r_opt)
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;
1052 case oAgentProgram: opt_agent_program = pargs.r.ret_str; break;
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;
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;
1071 default: pargs.err = ARGPARSE_PRINT_ERROR; break;
1074 if (log_get_errorcount (0))
1075 exit (2);
1077 fname = "-";
1078 if (argc == 1)
1079 fname = *argv;
1080 else if (argc > 1)
1081 usage (1);
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);
1090 if (opt_prompt)
1091 opt_prompt = percent_plus_unescape (opt_prompt, 0);
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);
1110 agent_exit (0);
1111 return 8; /*NOTREACHED*/
1114 void
1115 agent_exit (int rc)
1117 rc = rc? rc : log_get_errorcount(0)? 2 : 0;
1118 exit (rc);
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
1130 static char *
1131 get_passphrase (int promptno)
1133 char *pw;
1134 int err;
1135 const char *desc;
1136 char *orig_codeset;
1137 int repeat = 0;
1139 if (opt_passphrase)
1140 return xstrdup (opt_passphrase);
1142 orig_codeset = i18n_switchto_utf8 ();
1144 if (promptno == 1 && opt_prompt)
1146 desc = opt_prompt;
1148 else if (promptno == 2)
1150 desc = _("Please enter the passphrase to unprotect the "
1151 "PKCS#12 object.");
1153 else if (promptno == 3)
1155 desc = _("Please enter the passphrase to protect the "
1156 "new PKCS#12 object.");
1157 repeat = 1;
1159 else if (promptno == 4)
1161 desc = _("Please enter the passphrase to protect the "
1162 "imported object within the GnuPG system.");
1163 repeat = 1;
1165 else
1166 desc = _("Please enter the passphrase or the PIN\n"
1167 "needed to complete this operation.");
1169 i18n_switchback (orig_codeset);
1171 err = gnupg_get_passphrase (NULL, NULL, _("Passphrase:"), desc,
1172 repeat, repeat, 1, &pw);
1173 if (err)
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);
1182 assert (pw);
1184 return pw;
1188 static void
1189 release_passphrase (char *pw)
1191 if (pw)
1193 wipememory (pw, strlen (pw));
1194 xfree (pw);
1198 static int
1199 store_private_key (const unsigned char *grip,
1200 const void *buffer, size_t length, int force)
1202 int i;
1203 char *fname;
1204 FILE *fp;
1205 char hexgrip[40+4+1];
1207 for (i=0; i < 20; i++)
1208 sprintf (hexgrip+2*i, "%02X", grip[i]);
1209 strcpy (hexgrip+40, ".key");
1211 fname = make_filename (opt_homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
1212 if (force)
1213 fp = fopen (fname, "wb");
1214 else
1216 if (!access (fname, F_OK))
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;
1227 fp = fopen (fname, "wbx"); /* FIXME: the x is a GNU extension - let
1228 configure check whether this actually
1229 works */
1232 if (!fp)
1234 log_error ("can't create `%s': %s\n", fname, strerror (errno));
1235 xfree (fname);
1236 return -1;
1239 if (fwrite (buffer, length, 1, fp) != 1)
1241 log_error ("error writing `%s': %s\n", fname, strerror (errno));
1242 fclose (fp);
1243 remove (fname);
1244 xfree (fname);
1245 return -1;
1247 if ( fclose (fp) )
1249 log_error ("error closing `%s': %s\n", fname, strerror (errno));
1250 remove (fname);
1251 xfree (fname);
1252 return -1;
1254 log_info ("secret key stored as `%s'\n", fname);
1256 if (opt_status_msg)
1257 log_info ("[PROTECT-TOOL:] secretkey-stored\n");
1259 xfree (fname);
1260 return 0;