diff options
Diffstat (limited to 'agent/protect-tool.c')
-rw-r--r-- | agent/protect-tool.c | 262 |
1 files changed, 256 insertions, 6 deletions
diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 16277bb75..f53342595 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -1,4 +1,4 @@ -/* protect-tool.c - A tool to text the secret key protection +/* protect-tool.c - A tool to test the secret key protection * Copyright (C) 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -34,6 +34,7 @@ #define JNLIB_NEED_LOG_LOGV #include "agent.h" +#include "minip12.h" #define N_(a) a #define _(a) a @@ -53,8 +54,20 @@ enum cmd_and_opt_values oShowShadowInfo, oShowKeygrip, + oP12Import, + aTest }; +struct rsa_secret_key_s + { + MPI n; /* public modulus */ + MPI e; /* public exponent */ + MPI d; /* exponent */ + MPI p; /* prime p. */ + MPI q; /* prime q. */ + MPI u; /* inverse of p mod q. */ + }; + static int opt_armor; static const char *passphrase = "abc"; @@ -65,13 +78,14 @@ static ARGPARSE_OPTS opts[] = { { oVerbose, "verbose", 0, "verbose" }, { oArmor, "armor", 0, "write output in advanced format" }, - { oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" }, + { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" }, { oProtect, "protect", 256, "protect a private key"}, { oUnprotect, "unprotect", 256, "unprotect a private key"}, { oShadow, "shadow", 256, "create a shadow entry for a priblic key"}, { oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"}, - { oShowKeygrip, "show-keygrip", 256, " show the \"keygrip\""}, + { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""}, + { oP12Import, "p12-import", 256, "import a PKCS-12 encoded private key"}, {0} }; @@ -135,6 +149,25 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr) log_logv (level, fmt, arg_ptr); } + +/* static void */ +/* print_mpi (const char *text, GcryMPI a) */ +/* { */ +/* char *buf; */ +/* void *bufaddr = &buf; */ +/* int rc; */ + +/* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */ +/* if (rc) */ +/* log_info ("%s: [error printing number: %s]\n", text, gcry_strerror (rc)); */ +/* else */ +/* { */ +/* log_info ("%s: %s\n", text, buf); */ +/* gcry_free (buf); */ +/* } */ +/* } */ + + static unsigned char * make_canonical (const char *fname, const char *buf, size_t buflen) @@ -185,14 +218,13 @@ make_advanced (const unsigned char *buf, size_t buflen) } -static unsigned char * -read_key (const char *fname) +static char * +read_file (const char *fname, size_t *r_length) { FILE *fp; struct stat st; char *buf; size_t buflen; - unsigned char *key; fp = fopen (fname, "rb"); if (!fp) @@ -219,6 +251,19 @@ read_key (const char *fname) } fclose (fp); + *r_length = buflen; + return buf; +} + + +static unsigned char * +read_key (const char *fname) +{ + char *buf; + size_t buflen; + unsigned char *key; + + buf = read_file (fname, &buflen); key = make_canonical (fname, buf, buflen); xfree (buf); return key; @@ -422,9 +467,211 @@ show_keygrip (const char *fname) putchar ('\n'); } + +static int +rsa_key_check (struct rsa_secret_key_s *skey) +{ + int err = 0; + MPI t = gcry_mpi_snew (0); + MPI t1 = gcry_mpi_snew (0); + MPI t2 = gcry_mpi_snew (0); + MPI phi = gcry_mpi_snew (0); + + /* check that n == p * q */ + gcry_mpi_mul (t, skey->p, skey->q); + if (gcry_mpi_cmp( t, skey->n) ) + { + log_error ("RSA oops: n != p * q\n"); + err++; + } + + /* check that p is less than q */ + if (gcry_mpi_cmp (skey->p, skey->q) > 0) + { + GcryMPI tmp; + + log_info ("swapping secret primes\n"); + tmp = gcry_mpi_copy (skey->p); + gcry_mpi_set (skey->p, skey->q); + gcry_mpi_set (skey->q, tmp); + gcry_mpi_release (tmp); + /* and must recompute u of course */ + gcry_mpi_invm (skey->u, skey->p, skey->q); + } + + /* check that e divides neither p-1 nor q-1 */ + gcry_mpi_sub_ui (t, skey->p, 1 ); + gcry_mpi_div (NULL, t, t, skey->e, 0); + if (!gcry_mpi_cmp_ui( t, 0) ) + { + log_error ("RSA oops: e divides p-1\n"); + err++; + } + gcry_mpi_sub_ui (t, skey->q, 1); + gcry_mpi_div (NULL, t, t, skey->e, 0); + if (!gcry_mpi_cmp_ui( t, 0)) + { + log_info ( "RSA oops: e divides q-1\n" ); + err++; + } + + /* check that d is correct. */ + gcry_mpi_sub_ui (t1, skey->p, 1); + gcry_mpi_sub_ui (t2, skey->q, 1); + gcry_mpi_mul (phi, t1, t2); + gcry_mpi_invm (t, skey->e, phi); + if (gcry_mpi_cmp (t, skey->d)) + { /* no: try universal exponent. */ + gcry_mpi_gcd (t, t1, t2); + gcry_mpi_div (t, NULL, phi, t, 0); + gcry_mpi_invm (t, skey->e, t); + if (gcry_mpi_cmp (t, skey->d)) + { + log_error ("RSA oops: bad secret exponent\n"); + err++; + } + } + + /* check for correctness of u */ + gcry_mpi_invm (t, skey->p, skey->q); + if (gcry_mpi_cmp (t, skey->u)) + { + log_info ( "RSA oops: bad u parameter\n"); + err++; + } + + if (err) + log_info ("RSA secret key check failed\n"); + + gcry_mpi_release (t); + gcry_mpi_release (t1); + gcry_mpi_release (t2); + gcry_mpi_release (phi); + + return err? -1:0; +} + + +static void +import_p12_file (const char *fname) +{ + char *buf; + unsigned char *result; + size_t buflen, resultlen; + int i; + int rc; + GcryMPI *kparms; + struct rsa_secret_key_s sk; + GcrySexp s_key; + unsigned char *key; + + /* fixme: we should release some stuff on error */ + + buf = read_file (fname, &buflen); + if (!buf) + return; + + kparms = p12_parse (buf, buflen, passphrase); + xfree (buf); + if (!kparms) + { + log_error ("error parsing or decrypting the PKCS-1 file\n"); + return; + } + for (i=0; kparms[i]; i++) + ; + if (i != 8) + { + log_error ("invalid structure of private key\n"); + return; + } + + +/* print_mpi (" n", kparms[0]); */ +/* print_mpi (" e", kparms[1]); */ +/* print_mpi (" d", kparms[2]); */ +/* print_mpi (" p", kparms[3]); */ +/* print_mpi (" q", kparms[4]); */ +/* print_mpi ("dmp1", kparms[5]); */ +/* print_mpi ("dmq1", kparms[6]); */ +/* print_mpi (" u", kparms[7]); */ + + sk.n = kparms[0]; + sk.e = kparms[1]; + sk.d = kparms[2]; + sk.q = kparms[3]; + sk.p = kparms[4]; + sk.u = kparms[7]; + if (rsa_key_check (&sk)) + return; +/* print_mpi (" n", sk.n); */ +/* print_mpi (" e", sk.e); */ +/* print_mpi (" d", sk.d); */ +/* print_mpi (" p", sk.p); */ +/* print_mpi (" q", sk.q); */ +/* print_mpi (" u", sk.u); */ + + /* Create an S-expresion from the parameters. */ + rc = gcry_sexp_build (&s_key, NULL, + "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", + sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL); + for (i=0; i < 8; i++) + gcry_mpi_release (kparms[i]); + gcry_free (kparms); + if (rc) + { + log_error ("failed to created S-expression from key: %s\n", + gcry_strerror (rc)); + return; + } + /* Compute the keygrip. */ + { + unsigned char grip[20]; + if (!gcry_pk_get_keygrip (s_key, grip)) + { + log_error ("can't calculate keygrip\n"); + return; + } + log_info ("keygrip: "); + for (i=0; i < 20; i++) + log_printf ("%02X", grip[i]); + log_printf ("\n"); + } + + /* convert to canonical encoding */ + buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0); + assert (buflen); + key = gcry_xmalloc_secure (buflen); + buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, key, buflen); + assert (buflen); + gcry_sexp_release (s_key); + rc = agent_protect (key, passphrase, &result, &resultlen); + xfree (key); + if (rc) + { + log_error ("protecting the key failed: %s\n", gnupg_strerror (rc)); + return; + } + + if (opt_armor) + { + char *p = make_advanced (result, resultlen); + xfree (result); + if (!p) + return; + result = p; + resultlen = strlen (p); + } + + fwrite (result, resultlen, 1, stdout); + xfree (result); +} + + + int main (int argc, char **argv ) { @@ -461,6 +708,7 @@ main (int argc, char **argv ) case oShadow: cmd = oShadow; break; case oShowShadowInfo: cmd = oShowShadowInfo; break; case oShowKeygrip: cmd = oShowKeygrip; break; + case oP12Import: cmd = oP12Import; break; case oPassphrase: passphrase = pargs.r.ret_str; break; @@ -483,6 +731,8 @@ main (int argc, char **argv ) show_shadow_info (*argv); else if (cmd == oShowKeygrip) show_keygrip (*argv); + else if (cmd == oP12Import) + import_p12_file (*argv); else show_file (*argv); |