mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-29 16:07:02 +01: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:
parent
9ae48b173c
commit
402aa0f948
@ -324,6 +324,7 @@ gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
|
||||
const unsigned char *grip,
|
||||
gcry_sexp_t *result);
|
||||
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);
|
||||
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
||||
int *r_keytype,
|
||||
|
@ -729,6 +729,11 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
|
||||
algoname = "dsa";
|
||||
elems = "pqgy";
|
||||
}
|
||||
else if (n==3 && !memcmp (name, "ecc", 3))
|
||||
{
|
||||
algoname = "ecc";
|
||||
elems = "pabgnq";
|
||||
}
|
||||
else if (n==5 && !memcmp (name, "ecdsa", 5))
|
||||
{
|
||||
algoname = "ecdsa";
|
||||
@ -788,6 +793,8 @@ agent_is_dsa_key (gcry_sexp_t s_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
|
||||
@ -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
|
||||
RESULT. This function extracts the key from the private key
|
||||
|
@ -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. */
|
||||
static gpg_error_t
|
||||
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;
|
||||
|
||||
/* 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,
|
||||
ctrl->digest.valuelen,
|
||||
gcry_pk_get_nbits (s_skey),
|
||||
@ -421,10 +443,8 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
{
|
||||
log_debug ("skey:\n");
|
||||
gcry_sexp_dump (s_skey);
|
||||
log_debug ("hash:\n");
|
||||
gcry_sexp_dump (s_hash);
|
||||
gcry_log_debugsxp ("skey", s_skey);
|
||||
gcry_log_debugsxp ("hash", s_hash);
|
||||
}
|
||||
|
||||
/* sign */
|
||||
@ -437,10 +457,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
}
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
{
|
||||
log_debug ("result:\n");
|
||||
gcry_sexp_dump (s_sig);
|
||||
}
|
||||
gcry_log_debugsxp ("rslt", s_sig);
|
||||
}
|
||||
|
||||
leave:
|
||||
|
@ -467,6 +467,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
int depth = 0;
|
||||
unsigned char *p;
|
||||
gcry_md_hd_t md;
|
||||
int have_curve = 0;
|
||||
|
||||
/* Create an S-expression with the protected-at timestamp. */
|
||||
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)
|
||||
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;
|
||||
prot_from_idx = protect_info[infidx].prot_from;
|
||||
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
|
||||
the name of the curve. We change the parameter list
|
||||
here to the one we expect in this case. */
|
||||
have_curve = 1;
|
||||
parmlist = "?qd";
|
||||
prot_from_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
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* openpgp-oids.c - OID helper for OpenPGP
|
||||
* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2013 Werner Koch
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -36,6 +37,11 @@
|
||||
#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. */
|
||||
static size_t
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
static void
|
||||
test_openpgp_oid_from_str (void)
|
||||
{
|
||||
static char *sample_oids[] =
|
||||
static char *sample_oids[] =
|
||||
{
|
||||
"0.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
|
||||
main (int argc, char **argv)
|
||||
@ -143,6 +178,7 @@ main (int argc, char **argv)
|
||||
|
||||
test_openpgp_oid_from_str ();
|
||||
test_openpgp_oid_to_str ();
|
||||
test_openpgp_oid_is_ed25519 ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -215,6 +215,9 @@ size_t percent_unescape_inplace (char *string, int nulrepl);
|
||||
/*-- openpgp-oid.c --*/
|
||||
gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
@ -32,8 +32,8 @@ fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
|
||||
#+end_example
|
||||
|
||||
The double =--with-fingerprint= prints the fingerprint for the subkeys
|
||||
too. Old versions of gpg used a lighly different format and required
|
||||
the use of the option =--fixed-list-mode= to conform to format
|
||||
too. Old versions of gpg used a slighrly different format and required
|
||||
the use of the option =--fixed-list-mode= to conform to the format
|
||||
described here.
|
||||
|
||||
** Description of the fields
|
||||
@ -201,6 +201,11 @@ described here.
|
||||
For sig records, this is the used hash algorithm. For example:
|
||||
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
|
||||
|
||||
*** PKD - Public key data
|
||||
|
@ -166,9 +166,14 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
{
|
||||
unsigned int nbits;
|
||||
const void *p;
|
||||
unsigned int lenhdr[2];
|
||||
|
||||
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
|
||||
{
|
||||
@ -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. */
|
||||
u32
|
||||
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++ )
|
||||
{
|
||||
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)
|
||||
goto leave;
|
||||
}
|
||||
@ -473,7 +505,12 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
|
||||
write_fake_data( a, enc->data[0] );
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -197,11 +197,11 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
|
||||
obuf = iobuf_temp();
|
||||
/* 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 */
|
||||
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
|
||||
/* 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 */
|
||||
iobuf_write (obuf, "Anonymous Sender ", 20);
|
||||
/* fixed-length field 5, recipient fp */
|
||||
|
@ -583,7 +583,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
goto leave;
|
||||
curvename = gcry_pk_get_curve (s_pubkey, 0, NULL);
|
||||
gcry_sexp_release (s_pubkey);
|
||||
curveoidstr = gpg_curve_to_oid (curvename, NULL);
|
||||
curveoidstr = openpgp_curve_to_oid (curvename, NULL);
|
||||
if (!curveoidstr)
|
||||
{
|
||||
log_error ("no OID known for curve '%s'\n", curvename);
|
||||
|
232
g10/keygen.c
232
g10/keygen.c
@ -60,9 +60,11 @@
|
||||
enum para_name {
|
||||
pKEYTYPE,
|
||||
pKEYLENGTH,
|
||||
pKEYCURVE,
|
||||
pKEYUSAGE,
|
||||
pSUBKEYTYPE,
|
||||
pSUBKEYLENGTH,
|
||||
pSUBKEYCURVE,
|
||||
pSUBKEYUSAGE,
|
||||
pAUTHKEYTYPE,
|
||||
pNAMEREAL,
|
||||
@ -1071,40 +1073,6 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
|
||||
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
|
||||
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;
|
||||
}
|
||||
gcry_sexp_release (l2);
|
||||
oidstr = gpg_curve_to_oid (curve, &nbits);
|
||||
oidstr = openpgp_curve_to_oid (curve, &nbits);
|
||||
if (!oidstr)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@ -1534,31 +1502,24 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
|
||||
* Generate an ECC key
|
||||
*/
|
||||
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,
|
||||
int keygen_flags, char **cache_nonce_addr)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const char *curve;
|
||||
char *keyparms;
|
||||
|
||||
assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
|
||||
|
||||
/* For now we may only use one of the 3 NIST curves. See also
|
||||
gpg_curve_to_oid. */
|
||||
if (nbits <= 256)
|
||||
curve = "NIST P-256";
|
||||
else if (nbits <= 384)
|
||||
curve = "NIST P-384";
|
||||
else
|
||||
curve = "NIST P-521";
|
||||
if (!curve || !*curve)
|
||||
return gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
|
||||
keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))",
|
||||
algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
|
||||
keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s%s)))",
|
||||
strlen (curve), curve,
|
||||
((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
|
||||
"(transient-key)" : "" );
|
||||
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
|
||||
" transient-key" : ""),
|
||||
(!strcmp (curve, "Ed25519")? " eddsa":""));
|
||||
if (!keyparms)
|
||||
err = gpg_error_from_syserror ();
|
||||
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.
|
||||
* 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
|
||||
routines based on the requested algorithm. */
|
||||
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,
|
||||
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,
|
||||
keygen_flags, cache_nonce_addr);
|
||||
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);
|
||||
else if (algo == PUBKEY_ALGO_RSA)
|
||||
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. */
|
||||
STRING2KEY *s2k;
|
||||
DEK *dek;
|
||||
static int count;
|
||||
|
||||
s2k = xmalloc ( sizeof *s2k );
|
||||
s2k->mode = opt.s2k_mode;
|
||||
@ -3058,9 +3110,11 @@ read_parameter_file( const char *fname )
|
||||
} keywords[] = {
|
||||
{ "Key-Type", pKEYTYPE},
|
||||
{ "Key-Length", pKEYLENGTH },
|
||||
{ "Key-Curve", pKEYCURVE },
|
||||
{ "Key-Usage", pKEYUSAGE },
|
||||
{ "Subkey-Type", pSUBKEYTYPE },
|
||||
{ "Subkey-Length", pSUBKEYLENGTH },
|
||||
{ "Subkey-Curve", pSUBKEYCURVE },
|
||||
{ "Subkey-Usage", pSUBKEYUSAGE },
|
||||
{ "Name-Real", pNAMEREAL },
|
||||
{ "Name-Email", pNAMEEMAIL },
|
||||
@ -3340,6 +3394,7 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
|
||||
else
|
||||
{
|
||||
int subkey_algo;
|
||||
char *curve = NULL;
|
||||
|
||||
/* Fixme: To support creating a primary key by keygrip we better
|
||||
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 );
|
||||
r->next = para;
|
||||
para = r;
|
||||
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;
|
||||
if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
curve = ask_curve ();
|
||||
r = xmalloc_clear (sizeof *r + strlen (curve));
|
||||
r->key = pKEYCURVE;
|
||||
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->key = pKEYUSAGE;
|
||||
strcpy( r->u.value, "sign" );
|
||||
@ -3400,12 +3467,27 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
|
||||
nbits = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
if (algo == PUBKEY_ALGO_ECDSA || 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;
|
||||
}
|
||||
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);
|
||||
@ -3630,6 +3712,7 @@ do_generate_keypair (struct para_data_s *para,
|
||||
if (!card)
|
||||
err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
|
||||
get_parameter_uint( para, pKEYLENGTH ),
|
||||
get_parameter_value (para, pKEYCURVE),
|
||||
pub_root,
|
||||
timestamp,
|
||||
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),
|
||||
get_parameter_uint (para, pSUBKEYLENGTH),
|
||||
get_parameter_value (para, pSUBKEYCURVE),
|
||||
pub_root,
|
||||
timestamp,
|
||||
get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
|
||||
@ -3827,7 +3911,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
|
||||
int algo;
|
||||
unsigned int use;
|
||||
u32 expire;
|
||||
unsigned int nbits;
|
||||
unsigned int nbits = 0;
|
||||
char *curve = NULL;
|
||||
u32 cur_time;
|
||||
char *hexgrip = NULL;
|
||||
char *serialno = NULL;
|
||||
@ -3881,7 +3966,14 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
|
||||
hexgrip = NULL;
|
||||
algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
|
||||
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);
|
||||
if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
|
||||
_("Really create? (y/N) ")))
|
||||
@ -3894,7 +3986,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
|
||||
err = do_create_from_keygrip (ctrl, algo, hexgrip,
|
||||
keyblock, cur_time, expire, 1);
|
||||
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)
|
||||
goto leave;
|
||||
|
||||
@ -3911,6 +4004,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
|
||||
write_status_text (STATUS_KEY_CREATED, "S");
|
||||
|
||||
leave:
|
||||
xfree (curve);
|
||||
xfree (hexgrip);
|
||||
xfree (serialno);
|
||||
if (err)
|
||||
|
@ -817,6 +817,17 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo),
|
||||
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)
|
||||
{
|
||||
es_fprintf (es_stdout, " [");
|
||||
@ -940,6 +951,18 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
s2k_char,
|
||||
nbits_from_pk (pk2), pubkey_letter (pk2->pubkey_algo),
|
||||
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)
|
||||
{
|
||||
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);
|
||||
print_capabilities (pk, keyblock);
|
||||
es_putc (':', es_stdout); /* End of field 13. */
|
||||
es_putc (':', es_stdout); /* End of field 14. */
|
||||
if (secret)
|
||||
{
|
||||
es_putc (':', es_stdout); /* End of field 13. */
|
||||
es_putc (':', es_stdout); /* End of field 14. */
|
||||
if (stubkey)
|
||||
es_putc ('#', es_stdout);
|
||||
else if (serialno)
|
||||
es_fputs(serialno, es_stdout);
|
||||
es_putc (':', es_stdout); /* End of field 15. */
|
||||
es_fputs (serialno, es_stdout);
|
||||
}
|
||||
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);
|
||||
|
||||
print_revokers (pk);
|
||||
@ -1285,16 +1320,28 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
|
||||
/* fixme: add LID and ownertrust here */
|
||||
);
|
||||
print_capabilities (pk2, NULL);
|
||||
es_putc (':', es_stdout); /* End of field 13. */
|
||||
es_putc (':', es_stdout); /* End of field 14. */
|
||||
if (secret)
|
||||
{
|
||||
es_putc (':', es_stdout); /* End of field 13. */
|
||||
es_putc (':', es_stdout); /* End of field 14. */
|
||||
if (stubkey)
|
||||
es_putc ('#', es_stdout);
|
||||
else if (serialno)
|
||||
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);
|
||||
if (fpr > 1)
|
||||
print_fingerprint (pk2, 0);
|
||||
|
@ -230,7 +230,6 @@ void keyedit_passwd (ctrl_t ctrl, const char *username);
|
||||
void show_basic_key_info (KBNODE keyblock);
|
||||
|
||||
/*-- keygen.c --*/
|
||||
const char *gpg_curve_to_oid (const char *name, unsigned int *r_nbits);
|
||||
u32 parse_expire_string(const char *string);
|
||||
u32 ask_expire_interval(int object,const char *def_expire);
|
||||
u32 ask_expiredate(void);
|
||||
|
@ -445,6 +445,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
|
||||
/*-- build-packet.c --*/
|
||||
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_nohdr (iobuf_t out, gcry_mpi_t a);
|
||||
u32 calc_packet_length( PACKET *pkt );
|
||||
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
||||
const byte *buffer, size_t buflen );
|
||||
|
@ -140,22 +140,13 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
|
||||
nread++;
|
||||
}
|
||||
|
||||
if (nread >= 2 && !(buf[0] << 8 | buf[1]))
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
|
||||
a = NULL;
|
||||
|
||||
leave:
|
||||
gcry_free (buf);
|
||||
if (nread > *ret_nread)
|
||||
log_bug ("mpi larger than packet");
|
||||
log_bug ("mpi larger than packet (%zu/%u)", nread, *ret_nread);
|
||||
else
|
||||
*ret_nread = nread;
|
||||
return a;
|
||||
@ -1999,8 +1990,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
{
|
||||
for (i = 0; i < npkey; i++)
|
||||
{
|
||||
if ((algorithm == PUBKEY_ALGO_ECDSA
|
||||
|| algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2))
|
||||
if ((algorithm == PUBKEY_ALGO_ECDSA && (i == 0))
|
||||
|| (algorithm == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2))
|
||||
{
|
||||
size_t n;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
77
g10/pkglue.c
77
g10/pkglue.c
@ -33,14 +33,14 @@
|
||||
/* FIXME: Better chnage the fucntion name because mpi_ is used by
|
||||
gcrypt macros. */
|
||||
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_mpi_t data;
|
||||
|
||||
list = gcry_sexp_find_token (sexp, item, 0);
|
||||
assert (list);
|
||||
data = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
|
||||
data = gcry_sexp_nth_mpi (list, 1, mpifmt);
|
||||
assert (data);
|
||||
gcry_sexp_release (list);
|
||||
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;
|
||||
int rc;
|
||||
const int pkalgo = map_pk_openpgp_to_gcry (algo);
|
||||
int is_ed25519 = 0;
|
||||
|
||||
/* Make a sexp from pkey. */
|
||||
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 */
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (pkey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
is_ed25519 = openpgp_oid_is_ed25519 (pkey[0]);
|
||||
if (is_ed25519)
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecc(curve Ed25519)"
|
||||
"(flags eddsa)(q%m)))",
|
||||
pkey[1]);
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdsa(curve %s)(q%m)))",
|
||||
curve, pkey[1]);
|
||||
xfree (curve);
|
||||
char *curve = openpgp_oid_to_str (pkey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdsa(curve %s)(q%m)))",
|
||||
curve, pkey[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
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. */
|
||||
|
||||
/* Put hash into a S-Exp s_hash. */
|
||||
if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
|
||||
BUG (); /* gcry_sexp_build should never fail. */
|
||||
if (is_ed25519)
|
||||
{
|
||||
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. */
|
||||
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])
|
||||
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
|
||||
rc = gcry_sexp_build (&s_sig, NULL,
|
||||
"(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;
|
||||
|
||||
/* Get the shared point and the ephemeral public key. */
|
||||
shared = mpi_from_sexp (s_ciph, "s");
|
||||
public = mpi_from_sexp (s_ciph, "e");
|
||||
shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
|
||||
public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (s_ciph);
|
||||
s_ciph = NULL;
|
||||
if (DBG_CIPHER)
|
||||
@ -256,9 +279,9 @@ pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
|
||||
else /* Elgamal or RSA case. */
|
||||
{ /* Fixme: Add better error handling or make gnupg use
|
||||
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)
|
||||
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);
|
||||
@ -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)
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (skey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
if (openpgp_oid_is_ed25519 (skey[0]))
|
||||
{
|
||||
rc = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(ecdsa(curve%s)(q%m)(d%m)))",
|
||||
curve, skey[1], skey[2]);
|
||||
xfree (curve);
|
||||
"(private-key(ecc(curve Ed25519)"
|
||||
"(flags eddsa)(q%m)(d%m)))",
|
||||
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
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "packet.h" /* For PKT_public_key. */
|
||||
|
||||
/*-- 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,
|
||||
gcry_mpi_t *pkey);
|
||||
|
@ -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);
|
||||
|
||||
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. */
|
||||
|
||||
|
35
g10/sign.c
35
g10/sign.c
@ -281,11 +281,16 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig,
|
||||
;
|
||||
else if (pksk->pubkey_algo == GCRY_PK_RSA
|
||||
|| 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
|
||||
{
|
||||
sig->data[0] = mpi_from_sexp (s_sigval, "r");
|
||||
sig->data[1] = mpi_from_sexp (s_sigval, "s");
|
||||
sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_USG);
|
||||
sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG);
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
the signing key prefs either before or after using the personal
|
||||
list?
|
||||
@ -437,6 +446,14 @@ hash_for (PKT_public_key *pk)
|
||||
{
|
||||
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
|
||||
|| 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 )
|
||||
{
|
||||
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
|
||||
(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)
|
||||
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
|
||||
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
|
||||
digest_algo = DIGEST_ALGO_SHA1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user