1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-02 22:38:02 +02:00

gpg: Rework ECC support and add experimental support for Ed25519.

* agent/findkey.c (key_parms_from_sexp): Add algo name "ecc".
(agent_is_dsa_key): Ditto.
(agent_is_eddsa_key): New.  Not finished, though.
* agent/pksign.c (do_encode_eddsa): New.
(agent_pksign_do): Use gcry_log_debug functions.
* agent/protect.c (agent_protect): Parse a flags parameter.
* g10/keygen.c (gpg_curve_to_oid): Move to ...
* common/openpgp-oid.c (openpgp_curve_to_oid): here and rename.
(oid_ed25519): New.
(openpgp_oid_is_ed25519): New.
(openpgp_oid_to_curve): New.
* common/t-openpgp-oid.c (test_openpgp_oid_is_ed25519): New.
* g10/build-packet.c (gpg_mpi_write): Write the length header also for
opaque MPIs.
(gpg_mpi_write_nohdr): New.
(do_key): Use gpg_mpi_write_nohdr depending on algorithm.
(do_pubkey_enc): Ditto.
* g10/ecdh.c (pk_ecdh_encrypt_with_shared_point): Use
gpg_mpi_write_nohdr.
* g10/export.c (transfer_format_to_openpgp):
* g10/keygen.c (ecckey_from_sexp): Return the error.
(gen_ecc): Repalce arg NBITS by CURVE.
(read_parameter_file): Add keywords "Key-Curve" and "Subkey-Curve".
(ask_curve): New.
(generate_keypair, generate_subkeypair): Use ask_curve.
(do_generate_keypair): Also pass curve name.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Print
curve name.
* g10/parse-packet.c (mpi_read): Remove workaround for
Libcgrypt < 1.5.
(parse_key): Fix ECC case.  Print the curve name.
* g10/pkglue.c (mpi_from_sexp): Rename to get_mpi_from_sexp.
(pk_verify, pk_check_secret_key): Add special case for Ed25519.
* g10/seskey.c (encode_md_value): Ditto.
* g10/sign.c (do_sign, hash_for, sign_file): Ditto.
--

Be warned that this code is subject to further changes and that the
format will very likely change before a release.  There are also known
bugs and missing code.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2013-11-15 08:59:45 +01:00
parent 9ae48b173c
commit 402aa0f948
20 changed files with 574 additions and 139 deletions

View File

@ -324,6 +324,7 @@ gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip, const unsigned char *grip,
gcry_sexp_t *result); gcry_sexp_t *result);
int agent_is_dsa_key (gcry_sexp_t s_key); int agent_is_dsa_key (gcry_sexp_t s_key);
int agent_is_eddsa_key (gcry_sexp_t s_key);
int agent_key_available (const unsigned char *grip); int agent_key_available (const unsigned char *grip);
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip, gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype, int *r_keytype,

View File

@ -729,6 +729,11 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
algoname = "dsa"; algoname = "dsa";
elems = "pqgy"; elems = "pqgy";
} }
else if (n==3 && !memcmp (name, "ecc", 3))
{
algoname = "ecc";
elems = "pabgnq";
}
else if (n==5 && !memcmp (name, "ecdsa", 5)) else if (n==5 && !memcmp (name, "ecdsa", 5))
{ {
algoname = "ecdsa"; algoname = "ecdsa";
@ -788,6 +793,8 @@ agent_is_dsa_key (gcry_sexp_t s_key)
if (!strcmp (algoname, "dsa")) if (!strcmp (algoname, "dsa"))
return GCRY_PK_DSA; return GCRY_PK_DSA;
else if (!strcmp (algoname, "ecc"))
return GCRY_PK_ECDSA; /* FIXME: Check for the EdDSA flag. */
else if (!strcmp (algoname, "ecdsa")) else if (!strcmp (algoname, "ecdsa"))
return GCRY_PK_ECDSA; return GCRY_PK_ECDSA;
else else
@ -795,6 +802,28 @@ agent_is_dsa_key (gcry_sexp_t s_key)
} }
/* Return true if S_KEY is an EdDSA key as used with curve Ed25519. */
int
agent_is_eddsa_key (gcry_sexp_t s_key)
{
char algoname[6];
if (!s_key)
return 0;
if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
return 0; /* Error - assume it is not an DSA key. */
if (!strcmp (algoname, "dsa"))
return GCRY_PK_DSA;
else if (!strcmp (algoname, "ecc"))
return GCRY_PK_ECDSA; /* FIXME: Check for the EdDSA flag. */
else if (!strcmp (algoname, "ecdsa"))
return GCRY_PK_ECDSA;
else
return 0;
}
/* Return the key for the keygrip GRIP. The result is stored at /* Return the key for the keygrip GRIP. The result is stored at
RESULT. This function extracts the key from the private key RESULT. This function extracts the key from the private key

View File

@ -131,6 +131,24 @@ rfc6979_hash_algo_string (size_t mdlen)
} }
/* Encode a message digest for use with the EdDSA algorithm
(i.e. curve Ed25519). */
static gpg_error_t
do_encode_eddsa (const byte *md, size_t mdlen, gcry_sexp_t *r_hash)
{
gpg_error_t err;
gcry_sexp_t hash;
*r_hash = NULL;
err = gcry_sexp_build (&hash, NULL,
"(data(flags eddsa)(hash-algo sha512)(value %b))",
(int)mdlen, md);
if (!err)
*r_hash = hash;
return err;
}
/* Encode a message digest for use with an DSA algorithm. */ /* Encode a message digest for use with an DSA algorithm. */
static gpg_error_t static gpg_error_t
do_encode_dsa (const byte *md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey, do_encode_dsa (const byte *md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
@ -400,7 +418,11 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
int dsaalgo; int dsaalgo;
/* Put the hash into a sexp */ /* Put the hash into a sexp */
if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1) if (agent_is_eddsa_key (s_skey))
rc = do_encode_eddsa (ctrl->digest.value,
ctrl->digest.valuelen,
&s_hash);
else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
rc = do_encode_raw_pkcs1 (ctrl->digest.value, rc = do_encode_raw_pkcs1 (ctrl->digest.value,
ctrl->digest.valuelen, ctrl->digest.valuelen,
gcry_pk_get_nbits (s_skey), gcry_pk_get_nbits (s_skey),
@ -421,10 +443,8 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
if (DBG_CRYPTO) if (DBG_CRYPTO)
{ {
log_debug ("skey:\n"); gcry_log_debugsxp ("skey", s_skey);
gcry_sexp_dump (s_skey); gcry_log_debugsxp ("hash", s_hash);
log_debug ("hash:\n");
gcry_sexp_dump (s_hash);
} }
/* sign */ /* sign */
@ -437,10 +457,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
} }
if (DBG_CRYPTO) if (DBG_CRYPTO)
{ gcry_log_debugsxp ("rslt", s_sig);
log_debug ("result:\n");
gcry_sexp_dump (s_sig);
}
} }
leave: leave:

View File

@ -467,6 +467,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
int depth = 0; int depth = 0;
unsigned char *p; unsigned char *p;
gcry_md_hd_t md; gcry_md_hd_t md;
int have_curve = 0;
/* Create an S-expression with the protected-at timestamp. */ /* Create an S-expression with the protected-at timestamp. */
memcpy (timestamp_exp, "(12:protected-at15:", 19); memcpy (timestamp_exp, "(12:protected-at15:", 19);
@ -499,6 +500,11 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
if (!protect_info[infidx].algo) if (!protect_info[infidx].algo)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
/* The parser below is a complete mess: To make it robust for ECC
use we should reorder the s-expression to include only what we
really need and thus guarantee the right order for saving stuff.
This should be done before calling this function and maybe with
the help of the new gcry_sexp_extract_param. */
parmlist = protect_info[infidx].parmlist; parmlist = protect_info[infidx].parmlist;
prot_from_idx = protect_info[infidx].prot_from; prot_from_idx = protect_info[infidx].prot_from;
prot_to_idx = protect_info[infidx].prot_to; prot_to_idx = protect_info[infidx].prot_to;
@ -522,10 +528,19 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
/* This is a private ECC key but the first parameter is /* This is a private ECC key but the first parameter is
the name of the curve. We change the parameter list the name of the curve. We change the parameter list
here to the one we expect in this case. */ here to the one we expect in this case. */
have_curve = 1;
parmlist = "?qd"; parmlist = "?qd";
prot_from_idx = 2; prot_from_idx = 2;
prot_to_idx = 2; prot_to_idx = 2;
} }
else if (n == 5 && !memcmp (s, "flags", 5)
&& i == 1 && have_curve)
{
/* "curve" followed by "flags": Change again. */
parmlist = "??qd";
prot_from_idx = 3;
prot_to_idx = 3;
}
else else
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
} }

View File

@ -1,5 +1,6 @@
/* openpgp-oids.c - OID helper for OpenPGP /* openpgp-oids.c - OID helper for OpenPGP
* Copyright (C) 2011 Free Software Foundation, Inc. * Copyright (C) 2011 Free Software Foundation, Inc.
* Copyright (C) 2013 Werner Koch
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -36,6 +37,11 @@
#include "util.h" #include "util.h"
/* The OID for Curve Ed25519 in OpenPGP format. */
static const char oid_ed25519[] =
{ 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
/* Helper for openpgp_oid_from_str. */ /* Helper for openpgp_oid_from_str. */
static size_t static size_t
make_flagged_int (unsigned long value, char *buf, size_t buflen) make_flagged_int (unsigned long value, char *buf, size_t buflen)
@ -236,3 +242,88 @@ openpgp_oid_to_str (gcry_mpi_t a)
xfree (string); xfree (string);
return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973"); return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
} }
/* Return true if A represents the OID for Ed25519. */
int
openpgp_oid_is_ed25519 (gcry_mpi_t a)
{
const unsigned char *buf;
unsigned int nbits;
size_t n;
if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
return 0;
buf = gcry_mpi_get_opaque (a, &nbits);
n = (nbits+7)/8;
return (n == DIM (oid_ed25519)
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
}
/* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL
store the bit size of the curve there. Returns NULL for unknown
curve names. */
const char *
openpgp_curve_to_oid (const char *name, unsigned int *r_nbits)
{
unsigned int nbits = 0;
const char *oidstr;
if (!name)
oidstr = NULL;
else if (!strcmp (name, "Ed25519"))
{
oidstr = "1.3.6.1.4.1.3029.1.5.1";
nbits = 255;
}
else if (!strcmp (name, "nistp256"))
{
oidstr = "1.2.840.10045.3.1.7";
nbits = 256;
}
else if (!strcmp (name, "nistp384"))
{
oidstr = "1.3.132.0.34";
nbits = 384;
}
else if (!strcmp (name, "nistp521"))
{
oidstr = "1.3.132.0.35";
nbits = 521;
}
else
oidstr = NULL;
if (r_nbits)
*r_nbits = nbits;
return oidstr;
}
/* Map an OpenPGP OID to the Libgcrypt curve NAME. If R_NBITS is not
NULL store the bit size of the curve there. Returns "?" for
unknown curve names. */
const char *
openpgp_oid_to_curve (const char *oid)
{
const char *name;
if (!oid)
name = "";
else if (!strcmp (oid, "1.3.6.1.4.1.3029.1.5.1"))
name = "Ed25519";
else if (!strcmp (oid, "1.2.840.10045.3.1.7"))
name = "NIST P-256";
else if (!strcmp (oid, "1.3.132.0.34"))
name = "NIST P-384";
else if (!strcmp (oid, "1.3.132.0.35"))
name = "NIST P-521";
else /* FIXME: Lookup via Libgcrypt. */
name = "?";
return name;
}

View File

@ -35,7 +35,7 @@
static void static void
test_openpgp_oid_from_str (void) test_openpgp_oid_from_str (void)
{ {
static char *sample_oids[] = static char *sample_oids[] =
{ {
"0.0", "0.0",
"1.0", "1.0",
@ -134,6 +134,41 @@ test_openpgp_oid_to_str (void)
} }
static void
test_openpgp_oid_is_ed25519 (void)
{
static struct
{
int yes;
const char *oidstr;
} samples[] = {
{ 0, "0.0" },
{ 0, "1.3.132.0.35" },
{ 0, "1.3.6.1.4.1.3029.1.5.0" },
{ 1, "1.3.6.1.4.1.3029.1.5.1" },
{ 0, "1.3.6.1.4.1.3029.1.5.2" },
{ 0, "1.3.6.1.4.1.3029.1.5.1.0" },
{ 0, "1.3.6.1.4.1.3029.1.5" },
{ 0, NULL },
};
gpg_error_t err;
gcry_mpi_t a;
int idx;
for (idx=0; samples[idx].oidstr; idx++)
{
err = openpgp_oid_from_str (samples[idx].oidstr, &a);
if (err)
fail (idx, err);
if (openpgp_oid_is_ed25519 (a) != samples[idx].yes)
fail (idx, 0);
gcry_mpi_release (a);
}
}
int int
main (int argc, char **argv) main (int argc, char **argv)
@ -143,6 +178,7 @@ main (int argc, char **argv)
test_openpgp_oid_from_str (); test_openpgp_oid_from_str ();
test_openpgp_oid_to_str (); test_openpgp_oid_to_str ();
test_openpgp_oid_is_ed25519 ();
return 0; return 0;
} }

View File

@ -215,6 +215,9 @@ size_t percent_unescape_inplace (char *string, int nulrepl);
/*-- openpgp-oid.c --*/ /*-- openpgp-oid.c --*/
gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi); gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
char *openpgp_oid_to_str (gcry_mpi_t a); char *openpgp_oid_to_str (gcry_mpi_t a);
int openpgp_oid_is_ed25519 (gcry_mpi_t a);
const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits);
const char *openpgp_oid_to_curve (const char *oid);

View File

@ -32,8 +32,8 @@ fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
#+end_example #+end_example
The double =--with-fingerprint= prints the fingerprint for the subkeys The double =--with-fingerprint= prints the fingerprint for the subkeys
too. Old versions of gpg used a lighly different format and required too. Old versions of gpg used a slighrly different format and required
the use of the option =--fixed-list-mode= to conform to format the use of the option =--fixed-list-mode= to conform to the format
described here. described here.
** Description of the fields ** Description of the fields
@ -201,6 +201,11 @@ described here.
For sig records, this is the used hash algorithm. For example: For sig records, this is the used hash algorithm. For example:
2 = SHA-1, 8 = SHA-256. 2 = SHA-1, 8 = SHA-256.
*** Field 17 - Curve name
For pub, sub, sec, and sbb records this field is used for the ECC
curve name.
** Special fields ** Special fields
*** PKD - Public key data *** PKD - Public key data

View File

@ -166,9 +166,14 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
{ {
unsigned int nbits; unsigned int nbits;
const void *p; const void *p;
unsigned int lenhdr[2];
p = gcry_mpi_get_opaque (a, &nbits); p = gcry_mpi_get_opaque (a, &nbits);
rc = iobuf_write (out, p, (nbits+7)/8); lenhdr[0] = nbits >> 8;
lenhdr[1] = nbits;
rc = iobuf_write (out, lenhdr, 2);
if (!rc)
rc = iobuf_write (out, p, (nbits+7)/8);
} }
else else
{ {
@ -191,6 +196,29 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
} }
/*
* Write an opaque MPI to the output stream without length info.
*/
gpg_error_t
gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a)
{
int rc;
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
{
unsigned int nbits;
const void *p;
p = gcry_mpi_get_opaque (a, &nbits);
rc = iobuf_write (out, p, (nbits+7)/8);
}
else
rc = gpg_error (GPG_ERR_BAD_MPI);
return rc;
}
/* Calculate the length of a packet described by PKT. */ /* Calculate the length of a packet described by PKT. */
u32 u32
calc_packet_length( PACKET *pkt ) calc_packet_length( PACKET *pkt )
@ -302,7 +330,11 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
for (i=0; i < npkey; i++ ) for (i=0; i < npkey; i++ )
{ {
err = gpg_mpi_write (a, pk->pkey[i]); if ((pk->pubkey_algo == PUBKEY_ALGO_ECDSA && (i == 0))
|| (pk->pubkey_algo == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2))
err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
else
err = gpg_mpi_write (a, pk->pkey[i]);
if (err) if (err)
goto leave; goto leave;
} }
@ -473,7 +505,12 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
write_fake_data( a, enc->data[0] ); write_fake_data( a, enc->data[0] );
for (i=0; i < n && !rc ; i++ ) for (i=0; i < n && !rc ; i++ )
rc = gpg_mpi_write (a, enc->data[i]); {
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
rc = gpg_mpi_write_nohdr (a, enc->data[i]);
else
rc = gpg_mpi_write (a, enc->data[i]);
}
if (!rc) if (!rc)
{ {

View File

@ -197,11 +197,11 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
obuf = iobuf_temp(); obuf = iobuf_temp();
/* variable-length field 1, curve name OID */ /* variable-length field 1, curve name OID */
err = gpg_mpi_write (obuf, pkey[0]); err = gpg_mpi_write_nohdr (obuf, pkey[0]);
/* fixed-length field 2 */ /* fixed-length field 2 */
iobuf_put (obuf, PUBKEY_ALGO_ECDH); iobuf_put (obuf, PUBKEY_ALGO_ECDH);
/* variable-length field 3, KDF params */ /* variable-length field 3, KDF params */
err = (err ? err : gpg_mpi_write (obuf, pkey[2])); err = (err ? err : gpg_mpi_write_nohdr (obuf, pkey[2]));
/* fixed-length field 4 */ /* fixed-length field 4 */
iobuf_write (obuf, "Anonymous Sender ", 20); iobuf_write (obuf, "Anonymous Sender ", 20);
/* fixed-length field 5, recipient fp */ /* fixed-length field 5, recipient fp */

View File

@ -583,7 +583,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
goto leave; goto leave;
curvename = gcry_pk_get_curve (s_pubkey, 0, NULL); curvename = gcry_pk_get_curve (s_pubkey, 0, NULL);
gcry_sexp_release (s_pubkey); gcry_sexp_release (s_pubkey);
curveoidstr = gpg_curve_to_oid (curvename, NULL); curveoidstr = openpgp_curve_to_oid (curvename, NULL);
if (!curveoidstr) if (!curveoidstr)
{ {
log_error ("no OID known for curve '%s'\n", curvename); log_error ("no OID known for curve '%s'\n", curvename);

View File

@ -60,9 +60,11 @@
enum para_name { enum para_name {
pKEYTYPE, pKEYTYPE,
pKEYLENGTH, pKEYLENGTH,
pKEYCURVE,
pKEYUSAGE, pKEYUSAGE,
pSUBKEYTYPE, pSUBKEYTYPE,
pSUBKEYLENGTH, pSUBKEYLENGTH,
pSUBKEYCURVE,
pSUBKEYUSAGE, pSUBKEYUSAGE,
pAUTHKEYTYPE, pAUTHKEYTYPE,
pNAMEREAL, pNAMEREAL,
@ -1071,40 +1073,6 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
return err; return err;
} }
/* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL
store the bit size of the curve there. Returns NULL for unknown
curve names. */
const char *
gpg_curve_to_oid (const char *name, unsigned int *r_nbits)
{
unsigned int nbits = 0;
const char *oidstr;
if (!name)
oidstr = NULL;
else if (!strcmp (name, "NIST P-256"))
{
oidstr = "1.2.840.10045.3.1.7";
nbits = 256;
}
else if (!strcmp (name, "NIST P-384"))
{
oidstr = "1.3.132.0.34";
nbits = 384;
}
else if (!strcmp (name, "NIST P-521"))
{
oidstr = "1.3.132.0.35";
nbits = 521;
}
else
oidstr = NULL;
if (r_nbits)
*r_nbits = nbits;
return oidstr;
}
static gpg_error_t static gpg_error_t
ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
@ -1142,7 +1110,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
goto leave; goto leave;
} }
gcry_sexp_release (l2); gcry_sexp_release (l2);
oidstr = gpg_curve_to_oid (curve, &nbits); oidstr = openpgp_curve_to_oid (curve, &nbits);
if (!oidstr) if (!oidstr)
{ {
/* That can't happen because we used one of the curves /* That can't happen because we used one of the curves
@ -1188,7 +1156,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
array[i] = NULL; array[i] = NULL;
} }
} }
return 0; return err;
} }
@ -1534,31 +1502,24 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
* Generate an ECC key * Generate an ECC key
*/ */
static gpg_error_t static gpg_error_t
gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root, gen_ecc (int algo, const char *curve, kbnode_t pub_root,
u32 timestamp, u32 expireval, int is_subkey, u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, char **cache_nonce_addr) int keygen_flags, char **cache_nonce_addr)
{ {
gpg_error_t err; gpg_error_t err;
const char *curve;
char *keyparms; char *keyparms;
assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH); assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
/* For now we may only use one of the 3 NIST curves. See also if (!curve || !*curve)
gpg_curve_to_oid. */ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
if (nbits <= 256)
curve = "NIST P-256";
else if (nbits <= 384)
curve = "NIST P-384";
else
curve = "NIST P-521";
keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))", keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s%s)))",
algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
strlen (curve), curve, strlen (curve), curve,
((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
"(transient-key)" : "" ); " transient-key" : ""),
(!strcmp (curve, "Ed25519")? " eddsa":""));
if (!keyparms) if (!keyparms)
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
else else
@ -2082,6 +2043,98 @@ 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. */
static char *
ask_curve (void)
{
struct {
const char *name;
int available;
int expert_only;
const char *pretty_name;
} curves[] = {
{ "Ed25519", 0, 0, "Curve 25519" },
{ "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" },
};
int idx;
char *answer;
char *result = NULL;
gcry_sexp_t keyparms;
tty_printf (_("Please select which elliptic curve you want:\n"));
keyparms = NULL;
for (idx=0; idx < DIM(curves); idx++)
{
int rc;
curves[idx].available = 0;
if (!opt.expert && curves[idx].expert_only)
continue;
gcry_sexp_release (keyparms);
rc = gcry_sexp_build (&keyparms, NULL,
"(public-key(ecc(curve %s)))", curves[idx].name);
if (rc)
continue;
if (!gcry_pk_get_curve (keyparms, 0, NULL))
continue;
curves[idx].available = 1;
tty_printf (_(" (%d) %s\n"), idx + 1,
curves[idx].pretty_name?
curves[idx].pretty_name:curves[idx].name);
}
gcry_sexp_release (keyparms);
for (;;)
{
answer = cpr_get ("keygen.curve", _("Your selection? "));
cpr_kill_prompt ();
idx = *answer? atoi (answer) : 1;
if (*answer && !idx)
{
/* See whether the user entered the name of the curve. */
for (idx=0; idx < DIM(curves); idx++)
{
if (!opt.expert && curves[idx].expert_only)
continue;
if (!stricmp (curves[idx].name, answer)
|| (curves[idx].pretty_name
&& !stricmp (curves[idx].pretty_name, answer)))
break;
}
if (idx == DIM(curves))
idx = -1;
}
else
idx--;
xfree(answer);
answer = NULL;
if (idx < 0 || idx >= DIM (curves) || !curves[idx].available)
tty_printf (_("Invalid selection.\n"));
else
{
result = xstrdup (curves[idx].name);
break;
}
}
if (!result)
result = xstrdup (curves[0].name);
return result;
}
/**************** /****************
* Parse an expire string and return its value in seconds. * Parse an expire string and return its value in seconds.
* Returns (u32)-1 on error. * Returns (u32)-1 on error.
@ -2539,7 +2592,7 @@ do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
/* Basic key generation. Here we divert to the actual generation /* Basic key generation. Here we divert to the actual generation
routines based on the requested algorithm. */ routines based on the requested algorithm. */
static int static int
do_create (int algo, unsigned int nbits, KBNODE pub_root, do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
u32 timestamp, u32 expiredate, int is_subkey, u32 timestamp, u32 expiredate, int is_subkey,
int keygen_flags, char **cache_nonce_addr) int keygen_flags, char **cache_nonce_addr)
{ {
@ -2561,7 +2614,7 @@ do_create (int algo, unsigned int nbits, KBNODE pub_root,
err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, cache_nonce_addr); keygen_flags, cache_nonce_addr);
else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH) else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
err = gen_ecc (algo, nbits, pub_root, timestamp, expiredate, is_subkey, err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, cache_nonce_addr); keygen_flags, cache_nonce_addr);
else if (algo == PUBKEY_ALGO_RSA) else if (algo == PUBKEY_ALGO_RSA)
err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey, err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
@ -2974,7 +3027,6 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
* but because we do this always, why not here. */ * but because we do this always, why not here. */
STRING2KEY *s2k; STRING2KEY *s2k;
DEK *dek; DEK *dek;
static int count;
s2k = xmalloc ( sizeof *s2k ); s2k = xmalloc ( sizeof *s2k );
s2k->mode = opt.s2k_mode; s2k->mode = opt.s2k_mode;
@ -3058,9 +3110,11 @@ read_parameter_file( const char *fname )
} keywords[] = { } keywords[] = {
{ "Key-Type", pKEYTYPE}, { "Key-Type", pKEYTYPE},
{ "Key-Length", pKEYLENGTH }, { "Key-Length", pKEYLENGTH },
{ "Key-Curve", pKEYCURVE },
{ "Key-Usage", pKEYUSAGE }, { "Key-Usage", pKEYUSAGE },
{ "Subkey-Type", pSUBKEYTYPE }, { "Subkey-Type", pSUBKEYTYPE },
{ "Subkey-Length", pSUBKEYLENGTH }, { "Subkey-Length", pSUBKEYLENGTH },
{ "Subkey-Curve", pSUBKEYCURVE },
{ "Subkey-Usage", pSUBKEYUSAGE }, { "Subkey-Usage", pSUBKEYUSAGE },
{ "Name-Real", pNAMEREAL }, { "Name-Real", pNAMEREAL },
{ "Name-Email", pNAMEEMAIL }, { "Name-Email", pNAMEEMAIL },
@ -3340,6 +3394,7 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
else else
{ {
int subkey_algo; int subkey_algo;
char *curve = NULL;
/* Fixme: To support creating a primary key by keygrip we better /* Fixme: To support creating a primary key by keygrip we better
also define the keyword for the parameter file. Note that also define the keyword for the parameter file. Note that
@ -3355,12 +3410,24 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
sprintf( r->u.value, "%d", algo ); sprintf( r->u.value, "%d", algo );
r->next = para; r->next = para;
para = r; para = r;
nbits = ask_keysize (algo, 0); if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
r = xmalloc_clear( sizeof *r + 20 ); {
r->key = pKEYLENGTH; curve = ask_curve ();
sprintf( r->u.value, "%u", nbits); r = xmalloc_clear (sizeof *r + strlen (curve));
r->next = para; r->key = pKEYCURVE;
para = r; strcpy (r->u.value, curve);
r->next = para;
para = r;
}
else
{
nbits = ask_keysize (algo, 0);
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYLENGTH;
sprintf( r->u.value, "%u", nbits);
r->next = para;
para = r;
}
r = xmalloc_clear( sizeof *r + 20 ); r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYUSAGE; r->key = pKEYUSAGE;
strcpy( r->u.value, "sign" ); strcpy( r->u.value, "sign" );
@ -3400,12 +3467,27 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
nbits = 0; nbits = 0;
} }
nbits = ask_keysize (both? subkey_algo : algo, nbits); if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
r = xmalloc_clear( sizeof *r + 20 ); {
r->key = both? pSUBKEYLENGTH : pKEYLENGTH; if (!both)
sprintf( r->u.value, "%u", nbits); curve = ask_curve ();
r->next = para; r = xmalloc_clear (sizeof *r + strlen (curve));
para = r; r->key = both? pSUBKEYCURVE : pKEYCURVE;
strcpy (r->u.value, curve);
r->next = para;
para = r;
}
else
{
nbits = ask_keysize (both? subkey_algo : algo, nbits);
r = xmalloc_clear( sizeof *r + 20 );
r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
sprintf( r->u.value, "%u", nbits);
r->next = para;
para = r;
}
xfree (curve);
} }
expire = ask_expire_interval(0,NULL); expire = ask_expire_interval(0,NULL);
@ -3630,6 +3712,7 @@ do_generate_keypair (struct para_data_s *para,
if (!card) if (!card)
err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ), err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
get_parameter_uint( para, pKEYLENGTH ), get_parameter_uint( para, pKEYLENGTH ),
get_parameter_value (para, pKEYCURVE),
pub_root, pub_root,
timestamp, timestamp,
get_parameter_u32( para, pKEYEXPIRE ), 0, get_parameter_u32( para, pKEYEXPIRE ), 0,
@ -3681,6 +3764,7 @@ do_generate_keypair (struct para_data_s *para,
{ {
err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL), err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_uint (para, pSUBKEYLENGTH),
get_parameter_value (para, pSUBKEYCURVE),
pub_root, pub_root,
timestamp, timestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE), 1, get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
@ -3827,7 +3911,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
int algo; int algo;
unsigned int use; unsigned int use;
u32 expire; u32 expire;
unsigned int nbits; unsigned int nbits = 0;
char *curve = NULL;
u32 cur_time; u32 cur_time;
char *hexgrip = NULL; char *hexgrip = NULL;
char *serialno = NULL; char *serialno = NULL;
@ -3881,7 +3966,14 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
hexgrip = NULL; hexgrip = NULL;
algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip); algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
assert (algo); assert (algo);
nbits = hexgrip? 0 : ask_keysize (algo, 0);
if (hexgrip)
nbits = 0;
else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
curve = ask_curve ();
else
nbits = ask_keysize (algo, 0);
expire = ask_expire_interval (0, NULL); expire = ask_expire_interval (0, NULL);
if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay", if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
_("Really create? (y/N) "))) _("Really create? (y/N) ")))
@ -3894,7 +3986,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
err = do_create_from_keygrip (ctrl, algo, hexgrip, err = do_create_from_keygrip (ctrl, algo, hexgrip,
keyblock, cur_time, expire, 1); keyblock, cur_time, expire, 1);
else else
err = do_create (algo, nbits, keyblock, cur_time, expire, 1, 0, NULL); err = do_create (algo, nbits, curve,
keyblock, cur_time, expire, 1, 0, NULL);
if (err) if (err)
goto leave; goto leave;
@ -3911,6 +4004,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
write_status_text (STATUS_KEY_CREATED, "S"); write_status_text (STATUS_KEY_CREATED, "S");
leave: leave:
xfree (curve);
xfree (hexgrip); xfree (hexgrip);
xfree (serialno); xfree (serialno);
if (err) if (err)

View File

@ -817,6 +817,17 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo), nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo),
keystr_from_pk (pk), datestr_from_pk (pk)); keystr_from_pk (pk), datestr_from_pk (pk));
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
const char *name = openpgp_oid_to_curve (curve);
if (!*name || *name == '?')
name = curve;
es_fprintf (es_stdout, " %s", name);
xfree (curve);
}
if (pk->flags.revoked) if (pk->flags.revoked)
{ {
es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, " [");
@ -940,6 +951,18 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
s2k_char, s2k_char,
nbits_from_pk (pk2), pubkey_letter (pk2->pubkey_algo), nbits_from_pk (pk2), pubkey_letter (pk2->pubkey_algo),
keystr_from_pk (pk2), datestr_from_pk (pk2)); keystr_from_pk (pk2), datestr_from_pk (pk2));
if (pk2->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk2->pubkey_algo == PUBKEY_ALGO_ECDH)
{
char *curve = openpgp_oid_to_str (pk2->pkey[0]);
const char *name = openpgp_oid_to_curve (curve);
if (!*name || *name == '?')
name = curve;
es_fprintf (es_stdout, " %s", name);
xfree (curve);
}
if (pk2->flags.revoked) if (pk2->flags.revoked)
{ {
es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, " [");
@ -1172,16 +1195,28 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
es_putc (':', es_stdout); es_putc (':', es_stdout);
es_putc (':', es_stdout); es_putc (':', es_stdout);
print_capabilities (pk, keyblock); print_capabilities (pk, keyblock);
es_putc (':', es_stdout); /* End of field 13. */
es_putc (':', es_stdout); /* End of field 14. */
if (secret) if (secret)
{ {
es_putc (':', es_stdout); /* End of field 13. */
es_putc (':', es_stdout); /* End of field 14. */
if (stubkey) if (stubkey)
es_putc ('#', es_stdout); es_putc ('#', es_stdout);
else if (serialno) else if (serialno)
es_fputs(serialno, es_stdout); es_fputs (serialno, es_stdout);
es_putc (':', es_stdout); /* End of field 15. */
} }
es_putc (':', es_stdout); /* End of field 15. */
es_putc (':', es_stdout); /* End of field 16. */
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
const char *name = openpgp_oid_to_curve (curve);
if (!*name || *name == '?')
name = curve;
es_fputs (name, es_stdout);
xfree (curve);
}
es_putc (':', es_stdout); /* End of field 17. */
es_putc ('\n', es_stdout); es_putc ('\n', es_stdout);
print_revokers (pk); print_revokers (pk);
@ -1285,16 +1320,28 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
/* fixme: add LID and ownertrust here */ /* fixme: add LID and ownertrust here */
); );
print_capabilities (pk2, NULL); print_capabilities (pk2, NULL);
es_putc (':', es_stdout); /* End of field 13. */
es_putc (':', es_stdout); /* End of field 14. */
if (secret) if (secret)
{ {
es_putc (':', es_stdout); /* End of field 13. */
es_putc (':', es_stdout); /* End of field 14. */
if (stubkey) if (stubkey)
es_putc ('#', es_stdout); es_putc ('#', es_stdout);
else if (serialno) else if (serialno)
es_fputs (serialno, es_stdout); es_fputs (serialno, es_stdout);
es_putc (':', es_stdout); /* End of field 15. */
} }
es_putc (':', es_stdout); /* End of field 15. */
es_putc (':', es_stdout); /* End of field 16. */
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
const char *name = openpgp_oid_to_curve (curve);
if (!*name || *name == '?')
name = curve;
es_fputs (name, es_stdout);
xfree (curve);
}
es_putc (':', es_stdout); /* End of field 17. */
es_putc ('\n', es_stdout); es_putc ('\n', es_stdout);
if (fpr > 1) if (fpr > 1)
print_fingerprint (pk2, 0); print_fingerprint (pk2, 0);

View File

@ -230,7 +230,6 @@ void keyedit_passwd (ctrl_t ctrl, const char *username);
void show_basic_key_info (KBNODE keyblock); void show_basic_key_info (KBNODE keyblock);
/*-- keygen.c --*/ /*-- keygen.c --*/
const char *gpg_curve_to_oid (const char *name, unsigned int *r_nbits);
u32 parse_expire_string(const char *string); u32 parse_expire_string(const char *string);
u32 ask_expire_interval(int object,const char *def_expire); u32 ask_expire_interval(int object,const char *def_expire);
u32 ask_expiredate(void); u32 ask_expiredate(void);

View File

@ -445,6 +445,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
/*-- build-packet.c --*/ /*-- build-packet.c --*/
int build_packet( iobuf_t inp, PACKET *pkt ); int build_packet( iobuf_t inp, PACKET *pkt );
gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a); gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a);
gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
u32 calc_packet_length( PACKET *pkt ); u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen ); const byte *buffer, size_t buflen );

View File

@ -140,22 +140,13 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
nread++; nread++;
} }
if (nread >= 2 && !(buf[0] << 8 | buf[1])) if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
{ a = NULL;
/* Libgcrypt < 1.5.0 accidently rejects zero-length (i.e. zero)
MPIs. We fix this here. */
a = gcry_mpi_new (0);
}
else
{
if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
a = NULL;
}
leave: leave:
gcry_free (buf); gcry_free (buf);
if (nread > *ret_nread) if (nread > *ret_nread)
log_bug ("mpi larger than packet"); log_bug ("mpi larger than packet (%zu/%u)", nread, *ret_nread);
else else
*ret_nread = nread; *ret_nread = nread;
return a; return a;
@ -1999,8 +1990,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
{ {
for (i = 0; i < npkey; i++) for (i = 0; i < npkey; i++)
{ {
if ((algorithm == PUBKEY_ALGO_ECDSA if ((algorithm == PUBKEY_ALGO_ECDSA && (i == 0))
|| algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2)) || (algorithm == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2))
{ {
size_t n; size_t n;
err = read_size_body (inp, pktlen, &n, pk->pkey+i); err = read_size_body (inp, pktlen, &n, pk->pkey+i);
@ -2020,6 +2011,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
{ {
es_fprintf (listfp, "\tpkey[%d]: ", i); es_fprintf (listfp, "\tpkey[%d]: ", i);
mpi_print (listfp, pk->pkey[i], mpi_print_mode); mpi_print (listfp, pk->pkey[i], mpi_print_mode);
if ((algorithm == PUBKEY_ALGO_ECDSA
|| algorithm == PUBKEY_ALGO_ECDH) && i==0)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
es_fprintf (listfp, " %s (%s)",
openpgp_oid_to_curve (curve), curve);
xfree (curve);
}
es_putc ('\n', listfp); es_putc ('\n', listfp);
} }
} }

View File

@ -33,14 +33,14 @@
/* FIXME: Better chnage the fucntion name because mpi_ is used by /* FIXME: Better chnage the fucntion name because mpi_ is used by
gcrypt macros. */ gcrypt macros. */
gcry_mpi_t gcry_mpi_t
mpi_from_sexp (gcry_sexp_t sexp, const char * item) get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
{ {
gcry_sexp_t list; gcry_sexp_t list;
gcry_mpi_t data; gcry_mpi_t data;
list = gcry_sexp_find_token (sexp, item, 0); list = gcry_sexp_find_token (sexp, item, 0);
assert (list); assert (list);
data = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); data = gcry_sexp_nth_mpi (list, 1, mpifmt);
assert (data); assert (data);
gcry_sexp_release (list); gcry_sexp_release (list);
return data; return data;
@ -58,6 +58,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
gcry_sexp_t s_sig, s_hash, s_pkey; gcry_sexp_t s_sig, s_hash, s_pkey;
int rc; int rc;
const int pkalgo = map_pk_openpgp_to_gcry (algo); const int pkalgo = map_pk_openpgp_to_gcry (algo);
int is_ed25519 = 0;
/* Make a sexp from pkey. */ /* Make a sexp from pkey. */
if (pkalgo == GCRY_PK_DSA) if (pkalgo == GCRY_PK_DSA)
@ -79,15 +80,24 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
} }
else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */ else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
{ {
char *curve = openpgp_oid_to_str (pkey[0]); is_ed25519 = openpgp_oid_is_ed25519 (pkey[0]);
if (!curve) if (is_ed25519)
rc = gpg_error_from_syserror (); rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecc(curve Ed25519)"
"(flags eddsa)(q%m)))",
pkey[1]);
else else
{ {
rc = gcry_sexp_build (&s_pkey, NULL, char *curve = openpgp_oid_to_str (pkey[0]);
"(public-key(ecdsa(curve %s)(q%m)))", if (!curve)
curve, pkey[1]); rc = gpg_error_from_syserror ();
xfree (curve); else
{
rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecdsa(curve %s)(q%m)))",
curve, pkey[1]);
xfree (curve);
}
} }
} }
else else
@ -97,8 +107,18 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
BUG (); /* gcry_sexp_build should never fail. */ BUG (); /* gcry_sexp_build should never fail. */
/* Put hash into a S-Exp s_hash. */ /* Put hash into a S-Exp s_hash. */
if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) if (is_ed25519)
BUG (); /* gcry_sexp_build should never fail. */ {
if (gcry_sexp_build (&s_hash, NULL,
"(data(flags eddsa)(hash-algo sha512)(value %m))",
hash))
BUG (); /* gcry_sexp_build should never fail. */
}
else
{
if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
BUG (); /* gcry_sexp_build should never fail. */
}
/* Put data into a S-Exp s_sig. */ /* Put data into a S-Exp s_sig. */
s_sig = NULL; s_sig = NULL;
@ -114,6 +134,9 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
{ {
if (!data[0] || !data[1]) if (!data[0] || !data[1])
rc = gpg_error (GPG_ERR_BAD_MPI); rc = gpg_error (GPG_ERR_BAD_MPI);
else if (is_ed25519)
rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]);
else else
rc = gcry_sexp_build (&s_sig, NULL, rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
@ -223,8 +246,8 @@ pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
size_t fpn; size_t fpn;
/* Get the shared point and the ephemeral public key. */ /* Get the shared point and the ephemeral public key. */
shared = mpi_from_sexp (s_ciph, "s"); shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
public = mpi_from_sexp (s_ciph, "e"); public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
gcry_sexp_release (s_ciph); gcry_sexp_release (s_ciph);
s_ciph = NULL; s_ciph = NULL;
if (DBG_CIPHER) if (DBG_CIPHER)
@ -256,9 +279,9 @@ pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
else /* Elgamal or RSA case. */ else /* Elgamal or RSA case. */
{ /* Fixme: Add better error handling or make gnupg use { /* Fixme: Add better error handling or make gnupg use
S-expressions directly. */ S-expressions directly. */
resarr[0] = mpi_from_sexp (s_ciph, "a"); resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E) if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
resarr[1] = mpi_from_sexp (s_ciph, "b"); resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
} }
gcry_sexp_release (s_ciph); gcry_sexp_release (s_ciph);
@ -296,15 +319,25 @@ pk_check_secret_key (int algo, gcry_mpi_t *skey)
} }
else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH) else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
{ {
char *curve = openpgp_oid_to_str (skey[0]); if (openpgp_oid_is_ed25519 (skey[0]))
if (!curve)
rc = gpg_error_from_syserror ();
else
{ {
rc = gcry_sexp_build (&s_skey, NULL, rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecdsa(curve%s)(q%m)(d%m)))", "(private-key(ecc(curve Ed25519)"
curve, skey[1], skey[2]); "(flags eddsa)(q%m)(d%m)))",
xfree (curve); skey[1], skey[2]);
}
else
{
char *curve = openpgp_oid_to_str (skey[0]);
if (!curve)
rc = gpg_error_from_syserror ();
else
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecdsa(curve%s)(q%m)(d%m)))",
curve, skey[1], skey[2]);
xfree (curve);
}
} }
} }
else else

View File

@ -23,7 +23,7 @@
#include "packet.h" /* For PKT_public_key. */ #include "packet.h" /* For PKT_public_key. */
/*-- pkglue.c --*/ /*-- pkglue.c --*/
gcry_mpi_t mpi_from_sexp (gcry_sexp_t sexp, const char * item); gcry_mpi_t get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt);
int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_mpi_t *pkey); gcry_mpi_t *pkey);

View File

@ -264,7 +264,12 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
pkalgo = map_pk_openpgp_to_gcry (pk->pubkey_algo); pkalgo = map_pk_openpgp_to_gcry (pk->pubkey_algo);
if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA) if (pkalgo == GCRY_PK_ECDSA && openpgp_oid_is_ed25519 (pk->pkey[0]))
{
frame = gcry_mpi_set_opaque_copy (NULL, gcry_md_read (md, hash_algo),
8*gcry_md_get_algo_dlen (hash_algo));
}
else if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA)
{ {
/* It's a DSA signature, so find out the size of q. */ /* It's a DSA signature, so find out the size of q. */

View File

@ -281,11 +281,16 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig,
; ;
else if (pksk->pubkey_algo == GCRY_PK_RSA else if (pksk->pubkey_algo == GCRY_PK_RSA
|| pksk->pubkey_algo == GCRY_PK_RSA_S) || pksk->pubkey_algo == GCRY_PK_RSA_S)
sig->data[0] = mpi_from_sexp (s_sigval, "s"); sig->data[0] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG);
else if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
{
sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_OPAQUE);
sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_OPAQUE);
}
else else
{ {
sig->data[0] = mpi_from_sexp (s_sigval, "r"); sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_USG);
sig->data[1] = mpi_from_sexp (s_sigval, "s"); sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG);
} }
gcry_sexp_release (s_sigval); gcry_sexp_release (s_sigval);
@ -422,6 +427,10 @@ match_dsa_hash (unsigned int qbytes)
usable for the pubkey algorithm. If --preferred-digest-prefs isn't usable for the pubkey algorithm. If --preferred-digest-prefs isn't
set, then take the OpenPGP default (i.e. SHA-1). set, then take the OpenPGP default (i.e. SHA-1).
Note that Ed25519+EdDSA takes an input of arbitrary length and thus
we don't enforce any particular algorithm like we do for standard
ECDSA. However, we use SHA256 as the default algorithm.
Possible improvement: Use the highest-ranked usable algorithm from Possible improvement: Use the highest-ranked usable algorithm from
the signing key prefs either before or after using the personal the signing key prefs either before or after using the personal
list? list?
@ -437,6 +446,14 @@ hash_for (PKT_public_key *pk)
{ {
return recipient_digest_algo; return recipient_digest_algo;
} }
else if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
&& openpgp_oid_is_ed25519 (pk->pkey[0]))
{
if (opt.personal_digest_prefs)
return opt.personal_digest_prefs[0].value;
else
return DIGEST_ALGO_SHA256;
}
else if (pk->pubkey_algo == PUBKEY_ALGO_DSA else if (pk->pubkey_algo == PUBKEY_ALGO_DSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA) || pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
{ {
@ -927,7 +944,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
{ {
if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA
|| sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) || (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA
&& !openpgp_oid_is_ed25519 (sk_rover->pk->pkey[1])))
{ {
int temp_hashlen = (gcry_mpi_get_nbits int temp_hashlen = (gcry_mpi_get_nbits
(sk_rover->pk->pkey[1])); (sk_rover->pk->pkey[1]));
@ -1492,8 +1510,13 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA) else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA)
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
else if(pksk->pubkey_algo == PUBKEY_ALGO_ECDSA ) else if(pksk->pubkey_algo == PUBKEY_ALGO_ECDSA )
digest_algo = match_dsa_hash (ecdsa_qbits_from_Q {
(gcry_mpi_get_nbits (pksk->pkey[1]))/8); if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
digest_algo = DIGEST_ALGO_SHA256;
else
digest_algo = match_dsa_hash
(ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
}
else else
digest_algo = DIGEST_ALGO_SHA1; digest_algo = DIGEST_ALGO_SHA1;
} }