mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-18 14:17:03 +01:00
gpg: Make export of ECC keys work again.
* agent/cvt-openpgp.c (convert_to_openpgp): Use the curve name instead of the curve parameters. * g10/export.c (canon_pubkey_algo): Rename to ... (canon_pk_algo): this. Support ECC. (transfer_format_to_openpgp): Expect curve name.
This commit is contained in:
parent
d6ca407a27
commit
f4fcaa2936
@ -1142,6 +1142,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
|||||||
const char *algoname;
|
const char *algoname;
|
||||||
int npkey, nskey;
|
int npkey, nskey;
|
||||||
gcry_mpi_t array[10];
|
gcry_mpi_t array[10];
|
||||||
|
gcry_sexp_t curve = NULL;
|
||||||
char protect_iv[16];
|
char protect_iv[16];
|
||||||
char salt[8];
|
char salt[8];
|
||||||
unsigned long s2k_count;
|
unsigned long s2k_count;
|
||||||
@ -1200,13 +1201,26 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
|||||||
}
|
}
|
||||||
else if (!strcmp (name, "ecc"))
|
else if (!strcmp (name, "ecc"))
|
||||||
{
|
{
|
||||||
/* FIXME: We need to use the curve parameter. */
|
gcry_buffer_t iob;
|
||||||
|
char iobbuf[32];
|
||||||
|
|
||||||
algoname = "ecc"; /* Decide later by checking the usage. */
|
algoname = "ecc"; /* Decide later by checking the usage. */
|
||||||
npkey = 6;
|
npkey = 1;
|
||||||
nskey = 7;
|
nskey = 2;
|
||||||
err = gcry_sexp_extract_param (list, NULL, "pabgnqd",
|
iob.data = iobbuf;
|
||||||
array+0, array+1, array+2, array+3,
|
iob.size = sizeof iobbuf - 1;
|
||||||
array+4, array+5, array+6, NULL);
|
iob.off = 0;
|
||||||
|
iob.len = 0;
|
||||||
|
err = gcry_sexp_extract_param (list, NULL, "&'curve'/qd",
|
||||||
|
&iob, array+0, array+1, NULL);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
assert (iob.len < sizeof iobbuf -1);
|
||||||
|
iobbuf[iob.len] = 0;
|
||||||
|
err = gcry_sexp_build (&curve, NULL, "(curve %s)", iobbuf);
|
||||||
|
|
||||||
|
gcry_log_debugsxp ("at 1", curve);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp (name, "ecdsa"))
|
else if (!strcmp (name, "ecdsa"))
|
||||||
{
|
{
|
||||||
@ -1231,9 +1245,12 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
|||||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||||
}
|
}
|
||||||
xfree (name);
|
xfree (name);
|
||||||
gcry_sexp_release (list);
|
gcry_sexp_release (list); list = NULL;
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
{
|
||||||
|
gcry_sexp_release (curve);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
gcry_create_nonce (protect_iv, sizeof protect_iv);
|
gcry_create_nonce (protect_iv, sizeof protect_iv);
|
||||||
gcry_create_nonce (salt, sizeof salt);
|
gcry_create_nonce (salt, sizeof salt);
|
||||||
@ -1282,9 +1299,10 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
|||||||
"(openpgp-private-key\n"
|
"(openpgp-private-key\n"
|
||||||
" (version 1:4)\n"
|
" (version 1:4)\n"
|
||||||
" (algo %s)\n"
|
" (algo %s)\n"
|
||||||
" %S\n"
|
" %S%S\n"
|
||||||
" (protection sha1 aes %b 1:3 sha1 %b %s))\n",
|
" (protection sha1 aes %b 1:3 sha1 %b %s))\n",
|
||||||
algoname,
|
algoname,
|
||||||
|
curve,
|
||||||
tmpkey,
|
tmpkey,
|
||||||
(int)sizeof protect_iv, protect_iv,
|
(int)sizeof protect_iv, protect_iv,
|
||||||
(int)sizeof salt, salt,
|
(int)sizeof salt, salt,
|
||||||
@ -1297,6 +1315,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
|||||||
|
|
||||||
for (i=0; i < DIM (array); i++)
|
for (i=0; i < DIM (array); i++)
|
||||||
gcry_mpi_release (array[i]);
|
gcry_mpi_release (array[i]);
|
||||||
|
gcry_sexp_release (curve);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
149
g10/export.c
149
g10/export.c
@ -1,6 +1,7 @@
|
|||||||
/* export.c - Export keys in the OpenPGP defined format.
|
/* export.c - Export keys in the OpenPGP defined format.
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||||
* 2005, 2010 Free Software Foundation, Inc.
|
* 2005, 2010 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2014 Werner Koch
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -338,8 +339,8 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
|
|||||||
/* Return a canonicalized public key algoithms. This is used to
|
/* Return a canonicalized public key algoithms. This is used to
|
||||||
compare different flavors of algorithms (e.g. ELG and ELG_E are
|
compare different flavors of algorithms (e.g. ELG and ELG_E are
|
||||||
considered the same). */
|
considered the same). */
|
||||||
static int
|
static enum gcry_pk_algos
|
||||||
canon_pubkey_algo (int algo)
|
canon_pk_algo (enum gcry_pk_algos algo)
|
||||||
{
|
{
|
||||||
switch (algo)
|
switch (algo)
|
||||||
{
|
{
|
||||||
@ -348,6 +349,9 @@ canon_pubkey_algo (int algo)
|
|||||||
case GCRY_PK_RSA_S: return GCRY_PK_RSA;
|
case GCRY_PK_RSA_S: return GCRY_PK_RSA;
|
||||||
case GCRY_PK_ELG:
|
case GCRY_PK_ELG:
|
||||||
case GCRY_PK_ELG_E: return GCRY_PK_ELG;
|
case GCRY_PK_ELG_E: return GCRY_PK_ELG;
|
||||||
|
case GCRY_PK_ECC:
|
||||||
|
case GCRY_PK_ECDSA:
|
||||||
|
case GCRY_PK_ECDH: return GCRY_PK_ECC;
|
||||||
default: return algo;
|
default: return algo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,12 +366,13 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
gcry_sexp_t top_list;
|
gcry_sexp_t top_list;
|
||||||
gcry_sexp_t list = NULL;
|
gcry_sexp_t list = NULL;
|
||||||
|
char *curve = NULL;
|
||||||
const char *value;
|
const char *value;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
char *string;
|
char *string;
|
||||||
int idx;
|
int idx;
|
||||||
int is_v4, is_protected;
|
int is_v4, is_protected;
|
||||||
int pubkey_algo;
|
enum gcry_pk_algos pk_algo;
|
||||||
int protect_algo = 0;
|
int protect_algo = 0;
|
||||||
char iv[16];
|
char iv[16];
|
||||||
int ivlen = 0;
|
int ivlen = 0;
|
||||||
@ -375,11 +380,13 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
int s2k_algo = 0;
|
int s2k_algo = 0;
|
||||||
byte s2k_salt[8];
|
byte s2k_salt[8];
|
||||||
u32 s2k_count = 0;
|
u32 s2k_count = 0;
|
||||||
|
int is_ecdh = 0;
|
||||||
size_t npkey, nskey;
|
size_t npkey, nskey;
|
||||||
gcry_mpi_t skey[10]; /* We support up to 9 parameters. */
|
gcry_mpi_t skey[10]; /* We support up to 9 parameters. */
|
||||||
int skeyidx = 0;
|
int skeyidx = 0;
|
||||||
struct seckey_info *ski;
|
struct seckey_info *ski;
|
||||||
|
|
||||||
|
/* gcry_log_debugsxp ("transferkey", s_pgp); */
|
||||||
top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
|
top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
|
||||||
if (!top_list)
|
if (!top_list)
|
||||||
goto bad_seckey;
|
goto bad_seckey;
|
||||||
@ -445,6 +452,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
xfree (string);
|
xfree (string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse the gcrypt PK algo and check that it is okay. */
|
||||||
gcry_sexp_release (list);
|
gcry_sexp_release (list);
|
||||||
list = gcry_sexp_find_token (top_list, "algo", 0);
|
list = gcry_sexp_find_token (top_list, "algo", 0);
|
||||||
if (!list)
|
if (!list)
|
||||||
@ -452,15 +460,52 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
string = gcry_sexp_nth_string (list, 1);
|
string = gcry_sexp_nth_string (list, 1);
|
||||||
if (!string)
|
if (!string)
|
||||||
goto bad_seckey;
|
goto bad_seckey;
|
||||||
pubkey_algo = gcry_pk_map_name (string);
|
pk_algo = gcry_pk_map_name (string);
|
||||||
xfree (string);
|
xfree (string); string = NULL;
|
||||||
|
if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|
||||||
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|
|| gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|
||||||
|| gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|
|
||||||
|| !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY)
|
|| !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY)
|
||||||
goto bad_seckey;
|
goto bad_seckey;
|
||||||
pubkey_algo = map_pk_gcry_to_openpgp (pubkey_algo);
|
|
||||||
|
|
||||||
|
/* Check that the pubkey algo matches the one from the public key. */
|
||||||
|
switch (canon_pk_algo (pk_algo))
|
||||||
|
{
|
||||||
|
case GCRY_PK_RSA:
|
||||||
|
if (!is_RSA (pk->pubkey_algo))
|
||||||
|
pk_algo = 0; /* Does not match. */
|
||||||
|
break;
|
||||||
|
case GCRY_PK_DSA:
|
||||||
|
if (!is_DSA (pk->pubkey_algo))
|
||||||
|
pk_algo = 0; /* Does not match. */
|
||||||
|
break;
|
||||||
|
case GCRY_PK_ELG:
|
||||||
|
if (!is_ELGAMAL (pk->pubkey_algo))
|
||||||
|
pk_algo = 0; /* Does not match. */
|
||||||
|
break;
|
||||||
|
case GCRY_PK_ECC:
|
||||||
|
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
|
||||||
|
;
|
||||||
|
else if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||||
|
is_ecdh = 1;
|
||||||
|
else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
pk_algo = 0; /* Does not match. */
|
||||||
|
/* For ECC we do not have the domain parameters thus fix our info. */
|
||||||
|
npkey = 1;
|
||||||
|
nskey = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pk_algo = 0; /* Oops. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!pk_algo)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the key parameters. */
|
||||||
gcry_sexp_release (list);
|
gcry_sexp_release (list);
|
||||||
list = gcry_sexp_find_token (top_list, "skey", 0);
|
list = gcry_sexp_find_token (top_list, "skey", 0);
|
||||||
if (!list)
|
if (!list)
|
||||||
@ -509,7 +554,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
|
|
||||||
gcry_sexp_release (list); list = NULL;
|
gcry_sexp_release (list); list = NULL;
|
||||||
|
|
||||||
/* We have no need for the CSUM valuel thus we don't parse it. */
|
/* We have no need for the CSUM value thus we don't parse it. */
|
||||||
/* list = gcry_sexp_find_token (top_list, "csum", 0); */
|
/* list = gcry_sexp_find_token (top_list, "csum", 0); */
|
||||||
/* if (list) */
|
/* if (list) */
|
||||||
/* { */
|
/* { */
|
||||||
@ -523,6 +568,14 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
/* desired_csum = 0; */
|
/* desired_csum = 0; */
|
||||||
/* gcry_sexp_release (list); list = NULL; */
|
/* gcry_sexp_release (list); list = NULL; */
|
||||||
|
|
||||||
|
/* Get the curve name if any, */
|
||||||
|
list = gcry_sexp_find_token (top_list, "curve", 0);
|
||||||
|
if (list)
|
||||||
|
{
|
||||||
|
curve = gcry_sexp_nth_string (list, 1);
|
||||||
|
gcry_sexp_release (list); list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
gcry_sexp_release (top_list); top_list = NULL;
|
gcry_sexp_release (top_list); top_list = NULL;
|
||||||
|
|
||||||
/* log_debug ("XXX is_v4=%d\n", is_v4); */
|
/* log_debug ("XXX is_v4=%d\n", is_v4); */
|
||||||
@ -559,57 +612,49 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We need to change the received parameters for ECC algorithms.
|
/* We need to change the received parameters for ECC algorithms.
|
||||||
The transfer format has all parameters but OpenPGP defines that
|
The transfer format has the curve name and the parameters
|
||||||
only the OID of the curve is to be used. */
|
separate. We put them all into the SKEY array. */
|
||||||
if (pubkey_algo == PUBKEY_ALGO_ECDSA
|
if (canon_pk_algo (pk_algo) == GCRY_PK_ECC)
|
||||||
|| pubkey_algo == PUBKEY_ALGO_EDDSA
|
|
||||||
|| pubkey_algo == PUBKEY_ALGO_ECDH)
|
|
||||||
{
|
{
|
||||||
gcry_sexp_t s_pubkey;
|
const char *oidstr;
|
||||||
const char *curvename, *curveoidstr;
|
|
||||||
gcry_mpi_t mpi;
|
|
||||||
|
|
||||||
/* We build an S-expression with the public key parameters and
|
/* Assert that all required parameters are available. We also
|
||||||
ask Libgcrypt to return the matching curve name. */
|
check that the array does not contain more parameters than
|
||||||
if (npkey != 6 || !skey[0] || !skey[1] || !skey[2]
|
needed (this was used by some beta versions of 2.1. */
|
||||||
|| !skey[3] || !skey[4] || !skey[5]
|
if (!curve || !skey[0] || !skey[1] || skey[2])
|
||||||
|| !skey[6] || skey[7])
|
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_INTERNAL);
|
err = gpg_error (GPG_ERR_INTERNAL);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
err = gcry_sexp_build (&s_pubkey, NULL,
|
|
||||||
"(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))",
|
oidstr = openpgp_curve_to_oid (curve, NULL);
|
||||||
skey[0], skey[1], skey[2], skey[3], skey[4]);
|
if (!oidstr)
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
curvename = gcry_pk_get_curve (s_pubkey, 0, NULL);
|
|
||||||
gcry_sexp_release (s_pubkey);
|
|
||||||
curveoidstr = openpgp_curve_to_oid (curvename, NULL);
|
|
||||||
if (!curveoidstr)
|
|
||||||
{
|
{
|
||||||
log_error ("no OID known for curve '%s'\n", curvename);
|
log_error ("no OID known for curve '%s'\n", curve);
|
||||||
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
|
err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
err = openpgp_oid_from_str (curveoidstr, &mpi);
|
/* Put the curve's OID into into the MPI array. This requires
|
||||||
|
that we shift Q and D. For ECDH also insert the KDF parms. */
|
||||||
|
if (is_ecdh)
|
||||||
|
{
|
||||||
|
skey[4] = NULL;
|
||||||
|
skey[3] = skey[1];
|
||||||
|
skey[2] = gcry_mpi_copy (pk->pkey[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skey[3] = NULL;
|
||||||
|
skey[2] = skey[1];
|
||||||
|
}
|
||||||
|
skey[1] = skey[0];
|
||||||
|
skey[0] = NULL;
|
||||||
|
err = openpgp_oid_from_str (oidstr, skey + 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
/* Now replace the curve parameters by the OID and shift the
|
|
||||||
rest of the parameters. */
|
|
||||||
gcry_mpi_release (skey[0]);
|
|
||||||
skey[0] = mpi;
|
|
||||||
for (idx=1; idx <= 4; idx++)
|
|
||||||
gcry_mpi_release (skey[idx]);
|
|
||||||
skey[1] = skey[5];
|
|
||||||
skey[2] = skey[6];
|
|
||||||
for (idx=3; idx <= 6; idx++)
|
|
||||||
skey[idx] = NULL;
|
|
||||||
|
|
||||||
/* Fixup the NPKEY and NSKEY to match OpenPGP reality. */
|
/* Fixup the NPKEY and NSKEY to match OpenPGP reality. */
|
||||||
npkey = 2;
|
npkey = 2 + is_ecdh;
|
||||||
nskey = 3;
|
nskey = 3 + is_ecdh;
|
||||||
|
|
||||||
/* for (idx=0; skey[idx]; idx++) */
|
/* for (idx=0; skey[idx]; idx++) */
|
||||||
/* { */
|
/* { */
|
||||||
@ -634,11 +679,6 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
err = gpg_error (GPG_ERR_INV_DATA);
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (canon_pubkey_algo (pubkey_algo) != canon_pubkey_algo (pk->pubkey_algo))
|
|
||||||
{
|
|
||||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
err = openpgp_cipher_test_algo (protect_algo);
|
err = openpgp_cipher_test_algo (protect_algo);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -695,6 +735,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
|||||||
/* That's it. */
|
/* That's it. */
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
gcry_free (curve);
|
||||||
gcry_sexp_release (list);
|
gcry_sexp_release (list);
|
||||||
gcry_sexp_release (top_list);
|
gcry_sexp_release (top_list);
|
||||||
for (idx=0; idx < skeyidx; idx++)
|
for (idx=0; idx < skeyidx; idx++)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user