mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
gpgsm: Allow parsing of PKCS#12 files with two private keys.
* sm/minip12.c (struct p12_parse_ctx_s): Add privatekey2. (parse_shrouded_key_bag): Handle a second private key. (p12_parse_free_kparms): New. * sm/import.c (parse_p12): Factor some code out to ... (p12_to_skey): this. (parse_p12): Use p12_parse_free_kparms. -- Take care: We allow parsing of a second private key but we are not yet able to import the second private key. The whole things is required to at least import the certificates of current pkcs#12 files as created by the German Elster tax system. No test data, sorry.
This commit is contained in:
parent
092154e17e
commit
0cb622d632
157
sm/import.c
157
sm/import.c
@ -692,6 +692,85 @@ store_cert_cb (void *opaque,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for parse_p12. */
|
||||||
|
static gpg_error_t
|
||||||
|
p12_to_skey (gcry_mpi_t *kparms, const char *curve, gcry_sexp_t *r_skey)
|
||||||
|
{
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
struct rsa_secret_key_s sk;
|
||||||
|
gcry_ctx_t ecctx = NULL;
|
||||||
|
|
||||||
|
if (curve)
|
||||||
|
{
|
||||||
|
/* log_debug ("curve: %s\n", curve); */
|
||||||
|
/* gcry_log_debugmpi ("MPI[0]", kparms[0]); */
|
||||||
|
|
||||||
|
/* We need to get the public key. */
|
||||||
|
err = gcry_mpi_ec_new (&ecctx, NULL, curve);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error creating context for curve '%s': %s\n",
|
||||||
|
curve, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
err = gcry_mpi_ec_set_mpi ("d", kparms[0], ecctx);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error setting 'd' into context of curve '%s': %s\n",
|
||||||
|
curve, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
kparms[1] = gcry_mpi_ec_get_mpi ("q", ecctx, 1);
|
||||||
|
if (!kparms[1])
|
||||||
|
{
|
||||||
|
log_error ("error computing 'q' from 'd' for curve '%s'\n", curve);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_sexp_build (r_skey, NULL,
|
||||||
|
"(private-key(ecc(curve %s)(q%m)(d%m)))",
|
||||||
|
curve, kparms[1], kparms[0], NULL);
|
||||||
|
}
|
||||||
|
else /* RSA */
|
||||||
|
{
|
||||||
|
/* 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];
|
||||||
|
err = rsa_key_check (&sk);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
/* 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-expression from the parameters. */
|
||||||
|
err = gcry_sexp_build (r_skey, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
gcry_ctx_release (ecctx);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Assume that the reader is at a pkcs#12 message and try to import
|
/* Assume that the reader is at a pkcs#12 message and try to import
|
||||||
certificates from that stupid format. We will transfer secret
|
certificates from that stupid format. We will transfer secret
|
||||||
keys to the agent. */
|
keys to the agent. */
|
||||||
@ -706,7 +785,6 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
|
|||||||
size_t p12buflen;
|
size_t p12buflen;
|
||||||
size_t p12bufoff;
|
size_t p12bufoff;
|
||||||
gcry_mpi_t *kparms = NULL;
|
gcry_mpi_t *kparms = NULL;
|
||||||
struct rsa_secret_key_s sk;
|
|
||||||
char *passphrase = NULL;
|
char *passphrase = NULL;
|
||||||
unsigned char *key = NULL;
|
unsigned char *key = NULL;
|
||||||
size_t keylen;
|
size_t keylen;
|
||||||
@ -792,82 +870,9 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curve)
|
|
||||||
{
|
|
||||||
gcry_ctx_t ecctx = NULL;
|
|
||||||
|
|
||||||
/* log_debug ("curve: %s\n", curve); */
|
err = p12_to_skey (kparms, curve, &s_key);
|
||||||
/* gcry_log_debugmpi ("MPI[0]", kparms[0]); */
|
p12_parse_free_kparms (kparms);
|
||||||
|
|
||||||
/* We need to get the public key. */
|
|
||||||
err = gcry_mpi_ec_new (&ecctx, NULL, curve);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error ("error creating context for curve '%s': %s\n",
|
|
||||||
curve, gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
err = gcry_mpi_ec_set_mpi ("d", kparms[0], ecctx);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error ("error setting 'd' into context of curve '%s': %s\n",
|
|
||||||
curve, gpg_strerror (err));
|
|
||||||
gcry_ctx_release (ecctx);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
kparms[1] = gcry_mpi_ec_get_mpi ("q", ecctx, 1);
|
|
||||||
if (!kparms[1])
|
|
||||||
{
|
|
||||||
log_error ("error computing 'q' from 'd' for curve '%s'\n", curve);
|
|
||||||
gcry_ctx_release (ecctx);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
gcry_ctx_release (ecctx);
|
|
||||||
|
|
||||||
err = gcry_sexp_build (&s_key, NULL,
|
|
||||||
"(private-key(ecc(curve %s)(q%m)(d%m)))",
|
|
||||||
curve, kparms[1], kparms[0], NULL);
|
|
||||||
}
|
|
||||||
else /* RSA */
|
|
||||||
{
|
|
||||||
/* 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];
|
|
||||||
err = rsa_key_check (&sk);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
/* 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-expression from the parameters. */
|
|
||||||
err = 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The next is very ugly - we really should not rely on our
|
|
||||||
* knowledge of p12_parse internals. */
|
|
||||||
for (i=0; i < 8; i++)
|
|
||||||
gcry_mpi_release (kparms[i]);
|
|
||||||
gcry_free (kparms);
|
|
||||||
kparms = NULL;
|
kparms = NULL;
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
58
sm/minip12.c
58
sm/minip12.c
@ -168,6 +168,9 @@ struct p12_parse_ctx_s
|
|||||||
|
|
||||||
/* The private key as an MPI array. */
|
/* The private key as an MPI array. */
|
||||||
gcry_mpi_t *privatekey;
|
gcry_mpi_t *privatekey;
|
||||||
|
|
||||||
|
/* A second private key as an MPI array. */
|
||||||
|
gcry_mpi_t *privatekey2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1248,6 +1251,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
|
|||||||
int is_pbes2 = 0;
|
int is_pbes2 = 0;
|
||||||
int is_aes256 = 0;
|
int is_aes256 = 0;
|
||||||
int digest_algo = GCRY_MD_SHA1;
|
int digest_algo = GCRY_MD_SHA1;
|
||||||
|
gcry_mpi_t *privatekey;
|
||||||
|
|
||||||
where = "shrouded_key_bag";
|
where = "shrouded_key_bag";
|
||||||
if (opt_verbose)
|
if (opt_verbose)
|
||||||
@ -1565,19 +1569,26 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
|
|||||||
if (tlv_expect_sequence (tlv))
|
if (tlv_expect_sequence (tlv))
|
||||||
goto bailout;
|
goto bailout;
|
||||||
|
|
||||||
if (ctx->privatekey)
|
if (ctx->privatekey2)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_DUP_VALUE);
|
err = gpg_error (GPG_ERR_DUP_VALUE);
|
||||||
log_error ("a private key has already been received\n");
|
log_error ("two private kesy have already been received\n");
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
ctx->privatekey = gcry_calloc (10, sizeof *ctx->privatekey);
|
privatekey = gcry_calloc (10, sizeof *privatekey);
|
||||||
if (!ctx->privatekey)
|
if (!privatekey)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
log_error ("error allocating privatekey element array\n");
|
log_error ("error allocating privatekey element array\n");
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
if (ctx->privatekey)
|
||||||
|
{
|
||||||
|
log_info ("a private key has already been received - reading second\n");
|
||||||
|
ctx->privatekey2 = privatekey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx->privatekey = privatekey;
|
||||||
|
|
||||||
where = "shrouded_key_bag.reading.key-parameters";
|
where = "shrouded_key_bag.reading.key-parameters";
|
||||||
if (ctx->curve) /* ECC case. */
|
if (ctx->curve) /* ECC case. */
|
||||||
@ -1600,7 +1611,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
|
|||||||
goto bailout;
|
goto bailout;
|
||||||
if (opt_verbose > 1)
|
if (opt_verbose > 1)
|
||||||
log_printhex (data, datalen, "ecc q=");
|
log_printhex (data, datalen, "ecc q=");
|
||||||
err = gcry_mpi_scan (ctx->privatekey, GCRYMPI_FMT_USG,
|
err = gcry_mpi_scan (privatekey, GCRYMPI_FMT_USG,
|
||||||
data, datalen, NULL);
|
data, datalen, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@ -1623,7 +1634,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = tlv_expect_mpinteger (tlv, firstparam,
|
err = tlv_expect_mpinteger (tlv, firstparam,
|
||||||
ctx->privatekey+keyelem_count);
|
privatekey+keyelem_count);
|
||||||
if (firstparam && gpg_err_code (err) == GPG_ERR_FALSE)
|
if (firstparam && gpg_err_code (err) == GPG_ERR_FALSE)
|
||||||
; /* Ignore the first value iff it is zero. */
|
; /* Ignore the first value iff it is zero. */
|
||||||
else if (err)
|
else if (err)
|
||||||
@ -1918,6 +1929,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
|||||||
size_t oidlen;
|
size_t oidlen;
|
||||||
int intval;
|
int intval;
|
||||||
unsigned int startlevel;
|
unsigned int startlevel;
|
||||||
|
int i;
|
||||||
|
|
||||||
*r_badpass = 0;
|
*r_badpass = 0;
|
||||||
|
|
||||||
@ -2037,6 +2049,15 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
|||||||
else
|
else
|
||||||
gcry_free (ctx.curve);
|
gcry_free (ctx.curve);
|
||||||
|
|
||||||
|
/* We have no way yet to return the second private key. */
|
||||||
|
if (ctx.privatekey2)
|
||||||
|
{
|
||||||
|
for (i=0; ctx.privatekey2[i]; i++)
|
||||||
|
gcry_mpi_release (ctx.privatekey2[i]);
|
||||||
|
gcry_free (ctx.privatekey2);
|
||||||
|
ctx.privatekey2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return ctx.privatekey;
|
return ctx.privatekey;
|
||||||
|
|
||||||
bailout:
|
bailout:
|
||||||
@ -2050,13 +2071,18 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
|||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
if (ctx.privatekey)
|
if (ctx.privatekey)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; ctx.privatekey[i]; i++)
|
for (i=0; ctx.privatekey[i]; i++)
|
||||||
gcry_mpi_release (ctx.privatekey[i]);
|
gcry_mpi_release (ctx.privatekey[i]);
|
||||||
gcry_free (ctx.privatekey);
|
gcry_free (ctx.privatekey);
|
||||||
ctx.privatekey = NULL;
|
ctx.privatekey = NULL;
|
||||||
}
|
}
|
||||||
|
if (ctx.privatekey2)
|
||||||
|
{
|
||||||
|
for (i=0; ctx.privatekey2[i]; i++)
|
||||||
|
gcry_mpi_release (ctx.privatekey2[i]);
|
||||||
|
gcry_free (ctx.privatekey2);
|
||||||
|
ctx.privatekey2 = NULL;
|
||||||
|
}
|
||||||
tlv_parser_release (tlv);
|
tlv_parser_release (tlv);
|
||||||
gcry_free (ctx.curve);
|
gcry_free (ctx.curve);
|
||||||
if (r_curve)
|
if (r_curve)
|
||||||
@ -2065,6 +2091,22 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Free the parameters as returned by p12_parse. */
|
||||||
|
void
|
||||||
|
p12_parse_free_kparms (gcry_mpi_t *kparms)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (kparms)
|
||||||
|
{
|
||||||
|
for (i=0; i < 8; i++)
|
||||||
|
gcry_mpi_release (kparms[i]);
|
||||||
|
gcry_free (kparms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
compute_tag_length (size_t n)
|
compute_tag_length (size_t n)
|
||||||
|
@ -29,6 +29,7 @@ gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length,
|
|||||||
const char *pw,
|
const char *pw,
|
||||||
void (*certcb)(void*, const unsigned char*, size_t),
|
void (*certcb)(void*, const unsigned char*, size_t),
|
||||||
void *certcbarg, int *r_badpass, char **r_curve);
|
void *certcbarg, int *r_badpass, char **r_curve);
|
||||||
|
void p12_parse_free_kparms (gcry_mpi_t *kparms);
|
||||||
|
|
||||||
unsigned char *p12_build (gcry_mpi_t *kparms,
|
unsigned char *p12_build (gcry_mpi_t *kparms,
|
||||||
const void *cert, size_t certlen,
|
const void *cert, size_t certlen,
|
||||||
|
@ -580,13 +580,7 @@ run_one_test (const char *name, const char *desc, const char *pass,
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
p12_parse_free_kparms (result);
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i=0; result[i]; i++)
|
|
||||||
gcry_mpi_release (result[i]);
|
|
||||||
gcry_free (result);
|
|
||||||
}
|
|
||||||
xfree (certstr);
|
xfree (certstr);
|
||||||
xfree (resulthash);
|
xfree (resulthash);
|
||||||
xfree (curve);
|
xfree (curve);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user