1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

gpg: Finish experimental support for Ed25519.

* agent/cvt-openpgp.c (try_do_unprotect_arg_s): Add field "curve".
(get_keygrip): Add and use arg CURVE.
(convert_secret_key): Ditto.
(convert_transfer_key): Ditto.
(get_npkey_nskey): New.
(prepare_unprotect): Replace gcrypt functions by
get_npkey_nskey.  Allow opaque MPIs.
(do_unprotect): Use CURVE instead of parameters.
(convert_from_openpgp_main): Ditto.
(convert_to_openpgp):  Simplify.
* g10/import.c (one_mpi_from_pkey): Remove.
(transfer_secret_keys): Rewrite to use the curve instead of the
parameters.
* g10/parse-packet.c (parse_key): Mark protected MPIs with USER1 flag.

* common/openpgp-oid.c (openpgp_curve_to_oid): Allow the use of
 "NIST P-256" et al.
* g10/keygen.c (ask_curve): Add arg ALGO.
(generate_keypair): Rewrite the ECC key logic.

* tests/openpgp/ecc.test: Provide the "ecc" passphrase.
This commit is contained in:
Werner Koch 2014-05-07 13:16:32 +02:00
parent bdb9c2b314
commit 8fee6c1ce6
7 changed files with 231 additions and 229 deletions

View File

@ -36,6 +36,7 @@ struct try_do_unprotect_arg_s
int is_v4;
int is_protected;
int pubkey_algo;
const char *curve;
int protect_algo;
char *iv;
int ivlen;
@ -54,7 +55,8 @@ struct try_do_unprotect_arg_s
/* Compute the keygrip from the public key and store it at GRIP. */
static gpg_error_t
get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey,
unsigned char *grip)
{
gpg_error_t err;
gcry_sexp_t s_pkey = NULL;
@ -80,9 +82,8 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
case GCRY_PK_ECC:
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))",
pkey[0], pkey[1], pkey[2], pkey[3], pkey[4],
pkey[5]);
"(public-key(ecc(curve %s)(q%m)))",
curve, pkey[0]);
break;
default:
@ -102,7 +103,8 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
parameters into our s-expression based format. Note that
PUBKEY_ALGO has an gcrypt algorithm number. */
static gpg_error_t
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
const char *curve)
{
gpg_error_t err;
gcry_sexp_t s_skey = NULL;
@ -135,11 +137,12 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
break;
case GCRY_PK_ECC:
err = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)"
"(d%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4],
skey[5], skey[6]);
if (!curve)
err = gpg_error (GPG_ERR_BAD_SECKEY);
else
err = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecc(curve%s)(q%m)(d%m)))",
curve, skey[0], skey[1]);
break;
default:
@ -160,7 +163,7 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
mode. Note that PUBKEY_ALGO has an gcrypt algorithm number. */
static gpg_error_t
convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
gcry_sexp_t transfer_key)
const char *curve, gcry_sexp_t transfer_key)
{
gpg_error_t err;
gcry_sexp_t s_skey = NULL;
@ -197,9 +200,9 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
case GCRY_PK_ECC:
err = gcry_sexp_build
(&s_skey, NULL,
"(protected-private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)"
"(protected-private-key(ecc(curve%s)(q%m)"
"(protected openpgp-native%S)))",
skey[0], skey[1], skey[2], skey[3], skey[4], skey[5], transfer_key);
curve, skey[0], transfer_key);
break;
default:
@ -254,6 +257,22 @@ checksum (const unsigned char *p, unsigned int n)
}
/* Return the number of expected key parameters. */
static void
get_npkey_nskey (int pubkey_algo, size_t *npkey, size_t *nskey)
{
switch (pubkey_algo)
{
case GCRY_PK_RSA: *npkey = 2; *nskey = 6; break;
case GCRY_PK_ELG: *npkey = 3; *nskey = 4; break;
case GCRY_PK_ELG_E: *npkey = 3; *nskey = 4; break;
case GCRY_PK_DSA: *npkey = 4; *nskey = 5; break;
case GCRY_PK_ECC: *npkey = 1; *nskey = 2; break;
default: *npkey = 0; *nskey = 0; break;
}
}
/* Helper for do_unprotect. PUBKEY_ALOGO is the gcrypt algo number.
On success R_NPKEY and R_NSKEY receive the number or parameters for
the algorithm PUBKEY_ALGO and R_SKEYLEN the used length of
@ -264,7 +283,6 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
unsigned int *r_npkey, unsigned int *r_nskey,
unsigned int *r_skeylen)
{
gpg_error_t err;
size_t npkey, nskey, skeylen;
int i;
@ -293,12 +311,8 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
/* Get properties of the public key algorithm and do some
consistency checks. Note that we need at least NPKEY+1 elements
in the SKEY array. */
if ( (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY,
NULL, &npkey))
|| (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY,
NULL, &nskey)))
return err;
if (!npkey || npkey >= nskey)
get_npkey_nskey (pubkey_algo, &npkey, &nskey);
if (!npkey || !nskey || npkey >= nskey)
return gpg_error (GPG_ERR_INTERNAL);
if (skeylen <= npkey)
return gpg_error (GPG_ERR_MISSING_VALUE);
@ -309,7 +323,7 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
encrypted. */
for (i=0; i < npkey; i++)
{
if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
return gpg_error (GPG_ERR_BAD_SECKEY);
}
@ -329,7 +343,7 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
static int
do_unprotect (const char *passphrase,
int pkt_version, int pubkey_algo, int is_protected,
gcry_mpi_t *skey, size_t skeysize,
const char *curve, gcry_mpi_t *skey, size_t skeysize,
int protect_algo, void *protect_iv, size_t protect_ivlen,
int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count,
u16 desired_csum, gcry_sexp_t *r_key)
@ -353,23 +367,26 @@ do_unprotect (const char *passphrase,
merely verify the checksum. */
if (!is_protected)
{
unsigned char *buffer;
actual_csum = 0;
for (i=npkey; i < nskey; i++)
{
if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
return gpg_error (GPG_ERR_BAD_SECKEY);
err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]);
if (!err)
if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
{
buffer = (gcry_is_secure (skey[i])?
xtrymalloc_secure (nbytes) : xtrymalloc (nbytes));
if (!buffer)
return gpg_error_from_syserror ();
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes,
NULL, skey[i]);
unsigned int nbits;
const unsigned char *buffer;
buffer = gcry_mpi_get_opaque (skey[i], &nbits);
nbytes = (nbits+7)/8;
actual_csum += checksum (buffer, nbytes);
}
else
{
unsigned char *buffer;
err = gcry_mpi_aprint (GCRYMPI_FMT_PGP, &buffer, &nbytes,
skey[i]);
if (!err)
actual_csum += checksum (buffer, nbytes);
xfree (buffer);
@ -428,7 +445,8 @@ do_unprotect (const char *passphrase,
{
int ndata;
unsigned int ndatabits;
unsigned char *p, *data;
const unsigned char *p;
unsigned char *data;
u16 csum_pgp7 = 0;
if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE ))
@ -527,7 +545,7 @@ do_unprotect (const char *passphrase,
for (i = npkey; i < nskey; i++)
{
unsigned char *p;
const unsigned char *p;
size_t ndata;
unsigned int ndatabits;
@ -580,7 +598,7 @@ do_unprotect (const char *passphrase,
if (nskey != skeylen)
err = gpg_error (GPG_ERR_BAD_SECKEY);
else
err = convert_secret_key (r_key, pubkey_algo, skey);
err = convert_secret_key (r_key, pubkey_algo, skey, curve);
if (err)
return err;
@ -608,6 +626,7 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi)
err = do_unprotect (pi->pin,
arg->is_v4? 4:3,
arg->pubkey_algo, arg->is_protected,
arg->curve,
arg->skey, arg->skeysize,
arg->protect_algo, arg->iv, arg->ivlen,
arg->s2k_mode, arg->s2k_algo,
@ -651,6 +670,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
u32 s2k_count = 0;
size_t npkey, nskey;
gcry_mpi_t skey[10]; /* We support up to 9 parameters. */
char *curve = NULL;
u16 desired_csum;
int skeyidx = 0;
gcry_sexp_t s_skey = NULL;
@ -695,8 +715,6 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
if (!string)
goto bad_seckey;
protect_algo = gcry_cipher_map_name (string);
if (!protect_algo && !!strcmp (string, "IDEA"))
protect_algo = GCRY_CIPHER_IDEA;
xfree (string);
value = gcry_sexp_nth_data (list, 3, &valuelen);
@ -739,11 +757,21 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
pubkey_algo = gcry_pk_map_name (string);
xfree (string);
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|| gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|| !npkey || npkey >= nskey)
get_npkey_nskey (pubkey_algo, &npkey, &nskey);
if (!npkey || !nskey || npkey >= nskey)
goto bad_seckey;
if (npkey == 1) /* This is ECC */
{
gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "curve", 0);
if (!list)
goto bad_seckey;
curve = gcry_sexp_nth_string (list, 1);
if (!curve)
goto bad_seckey;
}
gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "skey", 0);
if (!list)
@ -770,15 +798,15 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
value = gcry_sexp_nth_data (list, ++idx, &valuelen);
if (!value || !valuelen)
goto bad_seckey;
if (is_enc)
if (is_enc || curve)
{
void *p = xtrymalloc (valuelen);
if (!p)
goto outofmem;
memcpy (p, value, valuelen);
skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8);
/* Encrypted parameters and ECC parameters need or can be
stored as opaque. */
skey[skeyidx] = gcry_mpi_set_opaque_copy (NULL, value, valuelen*8);
if (!skey[skeyidx])
goto outofmem;
if (is_enc)
gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1);
}
else
{
@ -807,33 +835,24 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
gcry_sexp_release (list); list = NULL;
gcry_sexp_release (top_list); top_list = NULL;
/* log_debug ("XXX is_v4=%d\n", is_v4); */
/* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */
/* log_debug ("XXX is_protected=%d\n", is_protected); */
/* log_debug ("XXX protect_algo=%d\n", protect_algo); */
/* log_printhex ("XXX iv", iv, ivlen); */
/* log_debug ("XXX ivlen=%d\n", ivlen); */
/* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */
/* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */
/* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */
/* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */
/* for (idx=0; skey[idx]; idx++) */
/* { */
/* int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */
/* log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */
/* if (is_enc) */
/* { */
/* void *p; */
/* unsigned int nbits; */
/* p = gcry_mpi_get_opaque (skey[idx], &nbits); */
/* log_printhex (NULL, p, (nbits+7)/8); */
/* } */
/* else */
/* gcry_mpi_dump (skey[idx]); */
/* log_printf ("\n"); */
/* } */
#if 0
log_debug ("XXX is_v4=%d\n", is_v4);
log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
log_debug ("XXX is_protected=%d\n", is_protected);
log_debug ("XXX protect_algo=%d\n", protect_algo);
log_printhex ("XXX iv", iv, ivlen);
log_debug ("XXX ivlen=%d\n", ivlen);
log_debug ("XXX s2k_mode=%d\n", s2k_mode);
log_debug ("XXX s2k_algo=%d\n", s2k_algo);
log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt);
log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count);
log_debug ("XXX curve='%s'\n", curve);
for (idx=0; skey[idx]; idx++)
gcry_log_debugmpi (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_USER1)
? "skey(e)" : "skey(_)", skey[idx]);
#endif /*0*/
err = get_keygrip (pubkey_algo, skey, grip);
err = get_keygrip (pubkey_algo, curve, skey, grip);
if (err)
goto leave;
@ -850,7 +869,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
if (err)
goto leave;
err = convert_transfer_key (&s_skey, pubkey_algo, skey, s_pgp);
err = convert_transfer_key (&s_skey, pubkey_algo, skey, curve, s_pgp);
if (err)
goto leave;
}
@ -871,6 +890,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
pi_arg.is_v4 = is_v4;
pi_arg.is_protected = is_protected;
pi_arg.pubkey_algo = pubkey_algo;
pi_arg.curve = curve;
pi_arg.protect_algo = protect_algo;
pi_arg.iv = iv;
pi_arg.ivlen = ivlen;
@ -929,6 +949,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
err = make_canon_sexp_pad (s_skey, 1, r_key, NULL);
leave:
xfree (curve);
gcry_sexp_release (s_skey);
gcry_sexp_release (list);
gcry_sexp_release (top_list);
@ -1223,11 +1244,9 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
{
char countbuf[35];
membuf_t mbuf;
void *format_args_buf_ptr[1];
int format_args_buf_int[1];
void *format_args[10+2];
unsigned int n;
gcry_sexp_t tmpkey, tmpsexp = NULL;
gcry_sexp_t tmpkey;
gcry_sexp_t tmpsexp = NULL;
snprintf (countbuf, sizeof countbuf, "%lu", s2k_count);
@ -1238,11 +1257,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = array + i;
}
put_membuf_str (&mbuf, " e %b");
format_args_buf_ptr[0] = gcry_mpi_get_opaque (array[npkey], &n);
format_args_buf_int[0] = (n+7)/8;
format_args[j++] = format_args_buf_int;
format_args[j++] = format_args_buf_ptr;
put_membuf_str (&mbuf, " e %m");
format_args[j++] = array + npkey;
put_membuf_str (&mbuf, ")\n");
put_membuf (&mbuf, "", 1);

View File

@ -211,6 +211,7 @@ This format is used to transfer keys between gpg and gpg-agent.
(openpgp-private-key
(version V)
(algo PUBKEYALGO)
(curve CURVENAME)
(skey _ P1 _ P2 _ P3 ... e PN)
(csum n)
(protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT))
@ -218,6 +219,7 @@ This format is used to transfer keys between gpg and gpg-agent.
* V is the packet version number (3 or 4).
* PUBKEYALGO is a Libgcrypt algo name
* CURVENAME is the name of the curve - only used with ECC.
* P1 .. PN are the parameters; the public parameters are never encrypted
the secrect key parameters are encrypted if the "protection" list is
given. To make this more explicit each parameter is preceded by a

View File

@ -280,17 +280,20 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits)
oidstr = "1.3.6.1.4.1.11591.15.1";
nbits = 255;
}
else if (!strcmp (name, "nistp256"))
else if (!strcmp (name, "nistp256") || !strcmp (name, "NIST P-256"))
{
/* Libgcrypt uses "NIST P-256" as standard name for this curve
and thus the key generation returns this value. Thus we
allow both strings. */
oidstr = "1.2.840.10045.3.1.7";
nbits = 256;
}
else if (!strcmp (name, "nistp384"))
else if (!strcmp (name, "nistp384") || !strcmp (name, "NIST P-384"))
{
oidstr = "1.3.132.0.34";
nbits = 384;
}
else if (!strcmp (name, "nistp521"))
else if (!strcmp (name, "nistp521") || !strcmp (name, "NIST P-521"))
{
oidstr = "1.3.132.0.35";
nbits = 521;

View File

@ -1128,37 +1128,6 @@ import_one (ctrl_t ctrl,
}
/* Extract one MPI value from the S-expression PKEY which is expected
to hold a "public-key". Returns NULL on error. */
static gcry_mpi_t
one_mpi_from_pkey (gcry_sexp_t pkey, const char *name, size_t namelen)
{
gcry_sexp_t list, l2;
gcry_mpi_t a;
list = gcry_sexp_find_token (pkey, "public-key", 0);
if (!list)
return NULL;
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
if (!list)
return NULL;
l2 = gcry_sexp_find_token (list, name, namelen);
if (!l2)
{
gcry_sexp_release (list);
return NULL;
}
a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
gcry_sexp_release (list);
return a;
}
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
function prints diagnostics and returns an error code. */
static gpg_error_t
@ -1174,18 +1143,15 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
int nskey;
membuf_t mbuf;
int i, j;
unsigned int n;
void *format_args_buf_ptr[PUBKEY_MAX_NSKEY];
int format_args_buf_int[PUBKEY_MAX_NSKEY];
void *format_args[2*PUBKEY_MAX_NSKEY];
gcry_sexp_t skey, prot, tmpsexp;
gcry_sexp_t curve = NULL;
unsigned char *transferkey = NULL;
size_t transferkeylen;
gcry_cipher_hd_t cipherhd = NULL;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
char *cache_nonce = NULL;
gcry_mpi_t ecc_params[5] = {NULL, NULL, NULL, NULL, NULL};
/* Get the current KEK. */
err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
@ -1263,65 +1229,30 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
/* We need special treatment for ECC algorithms. OpenPGP
stores only the curve name but the agent expects a full
key. This is so that we can keep all curve name
validation code out of gpg-agent. */
#if PUBKEY_MAX_NSKEY < 7
#error PUBKEY_MAX_NSKEY too low for ECC
#endif
char *curve = openpgp_oid_to_str (pk->pkey[0]);
if (!curve)
/* The ECC case. */
char *curvestr = openpgp_oid_to_str (pk->pkey[0]);
if (!curvestr)
err = gpg_error_from_syserror ();
else
{
gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECC, curve);
xfree (curve);
if (!cparam)
err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
else
err = gcry_sexp_build (&curve, NULL, "(curve %s)", curvestr);
xfree (curvestr);
if (!err)
{
const char *s;
j = 0;
/* Append the public key element Q. */
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = pk->pkey + 1;
/* Append the curve parameters P, A, B, G and N. */
for (i=j=0; !err && *(s = "pabgn"+i); i++)
{
ecc_params[i] = one_mpi_from_pkey (cparam, s, 1);
if (!ecc_params[i])
err = gpg_error (GPG_ERR_INV_CURVE);
else
{
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = ecc_params+i;
}
}
gcry_sexp_release (cparam);
if (!err)
{
/* Append the public key element Q. */
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = pk->pkey + 1;
/* Append the secret key element D. Note that
for ECDH we need to skip PKEY[2] because this
holds the KEK which is not needed. */
i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
{
put_membuf_str (&mbuf, " e %b");
format_args_buf_ptr[i]
= gcry_mpi_get_opaque (pk->pkey[i],&n);
format_args_buf_int[i] = (n+7)/8;
format_args[j++] = format_args_buf_int + i;
format_args[j++] = format_args_buf_ptr + i;
}
else
{
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = pk->pkey + i;
}
}
/* Append the secret key element D. For ECDH we
skip PKEY[2] because this holds the KEK which is
not needed by gpg-agent. */
i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
put_membuf_str (&mbuf, " e %m");
else
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = pk->pkey + i;
}
}
}
@ -1331,23 +1262,16 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
for (i=j=0; i < nskey; i++)
{
if (!pk->pkey[i])
; /* Protected keys only have NPKEY+1 elements. */
else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
{
put_membuf_str (&mbuf, " e %b");
format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i],&n);
format_args_buf_int[i] = (n+7)/8;
format_args[j++] = format_args_buf_int + i;
format_args[j++] = format_args_buf_ptr + i;
}
continue; /* Protected keys only have NPKEY+1 elements. */
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
put_membuf_str (&mbuf, " e %m");
else
{
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = pk->pkey + i;
}
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = pk->pkey + i;
}
}
put_membuf_str (&mbuf, ")\n");
put_membuf_str (&mbuf, ")");
put_membuf (&mbuf, "", 1);
if (err)
xfree (get_membuf (&mbuf, NULL));
@ -1398,12 +1322,13 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
"(openpgp-private-key\n"
" (version %d)\n"
" (algo %s)\n"
" %S\n"
" %S%S\n"
" (csum %d)\n"
" %S)\n",
pk->version,
openpgp_pk_algo_name (pk->pubkey_algo),
skey, (int)(unsigned long)ski->csum, prot);
curve, skey,
(int)(unsigned long)ski->csum, prot);
gcry_sexp_release (skey);
gcry_sexp_release (prot);
if (!err)
@ -1463,8 +1388,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
}
leave:
for (i=0; i < DIM (ecc_params); i++)
gcry_mpi_release (ecc_params[i]);
gcry_sexp_release (curve);
xfree (cache_nonce);
xfree (wrappedkey);
xfree (transferkey);

View File

@ -2086,29 +2086,30 @@ ask_keysize (int algo, unsigned int primary_keysize)
}
/* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE
is not 0, the function asks for the size of the encryption
subkey. */
/* Ask for the curve. ALGO is the selected algorithm which this
function may adjust. Returns a malloced string with the name of
the curve. */
static char *
ask_curve (void)
ask_curve (int *algo)
{
struct {
const char *name;
int available;
int expert_only;
int fix_curve;
const char *pretty_name;
} curves[] = {
#if GPG_USE_EDDSA
{ "Ed25519", 0, 0, "Curve 25519" },
{ "Curve25519", 0, 0, 1, "Curve 25519" },
#endif
#if GPG_USE_ECDSA || GPG_USE_ECDH
{ "NIST P-256", 0, 1, },
{ "NIST P-384", 0, 0, },
{ "NIST P-521", 0, 1, },
{ "brainpoolP256r1", 0, 1, "Brainpool P-256" },
{ "brainpoolP384r1", 0, 1, "Brainpool P-384" },
{ "brainpoolP512r1", 0, 1, "Brainpool P-512" },
{ "secp256k1", 0, 1 },
{ "NIST P-256", 0, 1, 0, },
{ "NIST P-384", 0, 0, 0, },
{ "NIST P-521", 0, 1, 0, },
{ "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" },
{ "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" },
{ "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" },
{ "secp256k1", 0, 1, 0 },
#endif
};
int idx;
@ -2127,9 +2128,14 @@ ask_curve (void)
if (!opt.expert && curves[idx].expert_only)
continue;
/* FIXME: The strcmp below is a temporary hack during
development. It shall be removed as soon as we have proper
Curve25519 support in Libgcrypt. */
gcry_sexp_release (keyparms);
rc = gcry_sexp_build (&keyparms, NULL,
"(public-key(ecc(curve %s)))", curves[idx].name);
"(public-key(ecc(curve %s)))",
(!strcmp (curves[idx].name, "Curve25519")
? "Ed25519" : curves[idx].name));
if (rc)
continue;
if (!gcry_pk_get_curve (keyparms, 0, NULL))
@ -2171,7 +2177,22 @@ ask_curve (void)
tty_printf (_("Invalid selection.\n"));
else
{
result = xstrdup (curves[idx].name);
if (curves[idx].fix_curve)
log_info ("WARNING: Curve25519 is an experimental algorithm and"
" not yet specified by OpenPGP. The current"
" implementation may change with the next GnuPG release"
" and thus rendering the key unusable!\n");
/* If the user selected a signing algorithm and Curve25519
we need to update the algo and and the curve name. */
if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
&& curves[idx].fix_curve)
{
*algo = PUBKEY_ALGO_EDDSA;
result = xstrdup ("Ed25519");
}
else
result = xstrdup (curves[idx].name);
break;
}
}
@ -3459,16 +3480,16 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
{
/* Create primary and subkey at once. */
both = 1;
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo );
r->next = para;
para = r;
if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
curve = ask_curve ();
curve = ask_curve (&algo);
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo);
r->next = para;
para = r;
nbits = 0;
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = pKEYCURVE;
@ -3478,6 +3499,11 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
}
else
{
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo);
r->next = para;
para = r;
nbits = ask_keysize (algo, 0);
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYLENGTH;
@ -3501,9 +3527,43 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
strcpy( r->u.value, "encrypt" );
r->next = para;
para = r;
if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
if (algo == PUBKEY_ALGO_EDDSA
&& subkey_algo == PUBKEY_ALGO_ECDH)
{
/* Need to switch to a different curve for the
encryption key. */
xfree (curve);
curve = xstrdup ("Curve25519");
}
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = pSUBKEYCURVE;
strcpy (r->u.value, curve);
r->next = para;
para = r;
}
}
else
else /* Create only a single key. */
{
/* For ECC we need to ask for the curve before storing the
algo becuase ask_curve may change the algo. */
if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
curve = ask_curve (&algo);
nbits = 0;
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = pKEYCURVE;
strcpy (r->u.value, curve);
r->next = para;
para = r;
}
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo );
@ -3528,13 +3588,7 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
if (!both)
curve = ask_curve ();
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = both? pSUBKEYCURVE : pKEYCURVE;
strcpy (r->u.value, curve);
r->next = para;
para = r;
/* The curve has already been set. */
}
else
{
@ -4031,11 +4085,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
curve = ask_curve ();
if (curve && !strcmp (curve, "Ed25519"))
algo = PUBKEY_ALGO_EDDSA;
}
curve = ask_curve (&algo);
else
nbits = ask_keysize (algo, 0);

View File

@ -2240,6 +2240,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
read_rest (inp, pktlen),
pktlen * 8);
/* Mark that MPI as protected - we need this information for
importing a key. The OPAQUE flag can't be used because
we also store public EdDSA values in opaque MPIs. */
if (pk->pkey[npkey])
gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1);
pktlen = 0;
if (list_mode)
es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey);
@ -2252,6 +2257,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
if (ski->is_protected)
{
pk->pkey[i] = read_protected_v3_mpi (inp, &pktlen);
if (pk->pkey[i])
gcry_mpi_set_flag (pk->pkey[i], GCRYMPI_FLAG_USER1);
if (list_mode)
es_fprintf (listfp, "\tskey[%d]: [v3 protected]\n", i);
}

View File

@ -188,7 +188,7 @@ echo 'This is one line' >z
for msg in $tests; do
info "checking: $msg"
eval "(IFS=; echo \"\$$msg\")" >x
$GPG -o y --yes x || error "decryption of $msg failed"
PINENTRY_USER_DATA=ecc $GPG -o y --yes x || error "decryption of $msg failed"
cmp y z || error "$msg: mismatch"
done
@ -204,7 +204,7 @@ for i in $plain_files $data_files ; do
for k in $mainkeyids ; do
info "file: $i key: $k"
$GPG ${opt_always} -e -o x --yes -r $k $i
$GPG -o y --yes x
PINENTRY_USER_DATA=ecc $GPG -o y --yes x
cmp $i y || error "$i,$k: mismatch"
done
done
@ -217,7 +217,7 @@ info "Checking ECC signing and verifiction."
for i in $plain_files $data_files ; do
for k in $mainkeyids ; do
info "file: $i key: $k"
$GPG -s -o x --yes -u $k $i
PINENTRY_USER_DATA=ecc $GPG -s -o x --yes -u $k $i
$GPG -o y --yes x || error "verify of $i,$k failed"
cmp $i y || error "$i,$k: mismatch"
done