mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Sample ECC keys and message do now work.
Import and export of secret keys does now work. Encryption has been fixed to be compatible with the sample messages. This version tests for new Libgcrypt function and thus needs to be build with a new Libgcrypt installed.
This commit is contained in:
parent
e0d4139e19
commit
4659c923a0
@ -1,3 +1,7 @@
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (HAVE_GCRY_PK_GET_CURVE): Define if availabale.
|
||||
|
||||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (AC_CONFIG_FILES): Remove keyserver/.
|
||||
|
@ -1,5 +1,12 @@
|
||||
2011-02-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cvt-openpgp.c (convert_secret_key): Remove algo mapping.
|
||||
|
||||
2011-01-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cvt-openpgp.c (convert_to_openpgp): Adjust to reverted Libgcrypt
|
||||
ABI.
|
||||
|
||||
* protect.c (protect_info): Adjust ECDSA and ECDH parameter names.
|
||||
Add "ecc".
|
||||
* findkey.c (key_parms_from_sexp): Ditto.
|
||||
|
@ -90,7 +90,9 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
|
||||
case GCRY_PK_ECDSA:
|
||||
case GCRY_PK_ECDH:
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecc(c%m)(q%m)))", pkey[0], pkey[1]);
|
||||
"(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]);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -108,8 +110,7 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
|
||||
|
||||
/* Convert a secret key given as algorithm id and an array of key
|
||||
parameters into our s-expression based format. Note that
|
||||
PUBKEY_ALGO is a standard id and not an OpenPGP id.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
@ -118,9 +119,6 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
|
||||
*r_key = NULL;
|
||||
|
||||
/* FIXME: This is not consistent with the above comment. */
|
||||
pubkey_algo = map_pk_openpgp_to_gcry (pubkey_algo);
|
||||
|
||||
switch (pubkey_algo)
|
||||
{
|
||||
case GCRY_PK_DSA:
|
||||
@ -147,15 +145,15 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
break;
|
||||
|
||||
case GCRY_PK_ECDSA:
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(ecdsa(c%m)(q%m)(d%m)))",
|
||||
skey[0], skey[1], skey[2]);
|
||||
break;
|
||||
|
||||
case GCRY_PK_ECDH:
|
||||
/* Although our code would work with "ecc" we explicitly use
|
||||
"ecdh" or "ecdsa" to implicitly set the key capabilities. */
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(ecdh(c%m)(q%m)(p%m)(d%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3]);
|
||||
"(private-key(%s(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)"
|
||||
"(d%m)))",
|
||||
pubkey_algo == GCRY_PK_ECDSA?"ecdsa":"ecdh",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4],
|
||||
skey[5], skey[6]);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1038,8 +1036,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
|
||||
case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
|
||||
case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break;
|
||||
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 2; elems = "cqd"; break;
|
||||
case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 3; elems = "cqpd"; break;
|
||||
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break;
|
||||
case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 6; elems = "pabgnqd"; break;
|
||||
default: algoname = ""; npkey = 0; elems = NULL; break;
|
||||
}
|
||||
assert (!elems || strlen (elems) < DIM (array) );
|
||||
|
@ -42,6 +42,12 @@
|
||||
#ifndef GPG_ERR_FULLY_CANCELED
|
||||
#define GPG_ERR_FULLY_CANCELED 198
|
||||
#endif
|
||||
#ifndef GPG_ERR_INV_CURVE
|
||||
#define GPG_ERR_INV_CURVE 187
|
||||
#endif
|
||||
#ifndef GPG_ERR_UNKNOWN_CURVE
|
||||
#define GPG_ERR_UNKNOWN_CURVE 188
|
||||
#endif
|
||||
|
||||
|
||||
/* Hash function used with libksba. */
|
||||
|
16
configure.ac
16
configure.ac
@ -742,6 +742,7 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
|
||||
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION",
|
||||
have_libgcrypt=yes,have_libgcrypt=no)
|
||||
|
||||
# fixme: We can remove the next two checks if we require libgcrypt 1.5.
|
||||
AC_CACHE_CHECK([whether Libgcrypt support ECDH], gnupg_cv_gcry_pk_ecdh,
|
||||
[ _gnupg_gcry_save_cflags=$CFLAGS
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
@ -756,6 +757,21 @@ if test "$gnupg_cv_gcry_pk_ecdh" = yes; then
|
||||
[Define if gcrypt.h has the enum value for ECDH.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether Libgcrypt has gcry_pk_get_curve],
|
||||
gnupg_cv_gcry_pk_get_curve,
|
||||
[ _gnupg_gcry_save_cflags=$CFLAGS
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <gcrypt.h>],
|
||||
[ return gcry_pk_get_curve (NULL, 0, NULL); ],
|
||||
gnupg_cv_gcry_pk_get_curve=yes,
|
||||
gnupg_cv_gcry_pk_get_curve=no)
|
||||
CFLAGS=$_gnupg_gcry_save_cflags])
|
||||
if test "$gnupg_cv_gcry_pk_get_curve" = yes; then
|
||||
AC_DEFINE([HAVE_GCRY_PK_GET_CURVE], 1,
|
||||
[Define if gcrypt.h has gcry_pk_get_curve.])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# libassuan is used for IPC
|
||||
|
@ -1,3 +1,18 @@
|
||||
2011-02-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* import.c (transfer_secret_keys): Make sure keyids are available.
|
||||
|
||||
* keyid.c (hash_public_key): Adjust for the ECC case.
|
||||
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* import.c (transfer_secret_keys): Implement ECC case.
|
||||
|
||||
* gpg.c (main): Call setup_libgcrypt_logging.
|
||||
|
||||
* keygen.c (gpg_curve_to_oid): New.
|
||||
(ecckey_from_sexp): Factor curve name mapping out to new function.
|
||||
|
||||
2011-01-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* misc.c (make_flagged_int, openpgp_oid_from_str)
|
||||
|
25
g10/ecdh.c
25
g10/ecdh.c
@ -106,8 +106,8 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
byte *secret_x;
|
||||
int secret_x_size;
|
||||
unsigned int nbits;
|
||||
const unsigned char *kdf_params;
|
||||
size_t kdf_params_size;
|
||||
const unsigned char *kek_params;
|
||||
size_t kek_params_size;
|
||||
int kdf_hash_algo;
|
||||
int kdf_encr_algo;
|
||||
unsigned char message[256];
|
||||
@ -158,18 +158,18 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
*/
|
||||
if (!gcry_mpi_get_flag (pkey[2], GCRYMPI_FLAG_OPAQUE))
|
||||
return GPG_ERR_BUG;
|
||||
kdf_params = gcry_mpi_get_opaque (pkey[2], &nbits);
|
||||
kdf_params_size = (nbits+7)/8;
|
||||
kek_params = gcry_mpi_get_opaque (pkey[2], &nbits);
|
||||
kek_params_size = (nbits+7)/8;
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh KDF params:", kdf_params, kdf_params_size);
|
||||
log_printhex ("ecdh KDF params:", kek_params, kek_params_size);
|
||||
|
||||
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
|
||||
if (kdf_params_size != 4 || kdf_params[0] != 3 || kdf_params[1] != 1)
|
||||
if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1)
|
||||
return GPG_ERR_BAD_PUBKEY;
|
||||
|
||||
kdf_hash_algo = kdf_params[2];
|
||||
kdf_encr_algo = kdf_params[3];
|
||||
kdf_hash_algo = kek_params[2];
|
||||
kdf_encr_algo = kek_params[3];
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n",
|
||||
@ -207,11 +207,10 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
return err;
|
||||
|
||||
if(DBG_CIPHER)
|
||||
log_printhex ("ecdh KDF message params are:",
|
||||
kdf_params, kdf_params_size );
|
||||
log_printhex ("ecdh KDF message params are:", message, message_size);
|
||||
}
|
||||
|
||||
/* Derive a KEK (key wrapping key) using kdf_params and secret_x. */
|
||||
/* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. */
|
||||
{
|
||||
gcry_md_hd_t h;
|
||||
int old_size;
|
||||
@ -222,7 +221,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
kdf_hash_algo, gpg_strerror (err));
|
||||
gcry_md_write(h, "\x00\x00\x00\x01", 4); /* counter = 1 */
|
||||
gcry_md_write(h, secret_x, secret_x_size); /* x of the point X */
|
||||
gcry_md_write(h, kdf_params, kdf_params_size);/* KDF parameters */
|
||||
gcry_md_write(h, message, message_size);/* KDF parameters */
|
||||
|
||||
gcry_md_final (h);
|
||||
|
||||
@ -453,5 +452,3 @@ pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
sk_fp, data/*encr data as an MPI*/,
|
||||
skey, result);
|
||||
}
|
||||
|
||||
|
||||
|
84
g10/export.c
84
g10/export.c
@ -354,7 +354,7 @@ canon_pubkey_algo (int algo)
|
||||
|
||||
|
||||
/* Use the key transfer format given in S_PGP to create the secinfo
|
||||
structure in PK and chnage the parameter array in PK to include the
|
||||
structure in PK and change the parameter array in PK to include the
|
||||
secret parameters. */
|
||||
static gpg_error_t
|
||||
transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
@ -460,6 +460,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
|| gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|
||||
|| !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY)
|
||||
goto bad_seckey;
|
||||
pubkey_algo = map_pk_gcry_to_openpgp (pubkey_algo);
|
||||
|
||||
gcry_sexp_release (list);
|
||||
list = gcry_sexp_find_token (top_list, "skey", 0);
|
||||
@ -557,6 +558,77 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* We need to change the received parameters for ECC algorithms.
|
||||
The transfer format has all parameters but OpenPGP defines that
|
||||
only the OID of the curve is to be used. */
|
||||
if (pubkey_algo == PUBKEY_ALGO_ECDSA || pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
gcry_sexp_t s_pubkey;
|
||||
const char *curvename, *curveoidstr;
|
||||
gcry_mpi_t mpi;
|
||||
|
||||
/* We build an S-expression with the public key parameters and
|
||||
ask Libgcrypt to return the matching curve name. */
|
||||
if (npkey != 6 || !skey[0] || !skey[1] || !skey[2]
|
||||
|| !skey[3] || !skey[4] || !skey[5]
|
||||
|| !skey[6] || skey[7])
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INTERNAL);
|
||||
goto leave;
|
||||
}
|
||||
err = gcry_sexp_build (&s_pubkey, NULL,
|
||||
"(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4]);
|
||||
if (err)
|
||||
goto leave;
|
||||
#ifdef HAVE_GCRY_PK_GET_CURVE
|
||||
curvename = gcry_pk_get_curve (s_pubkey, 0, NULL);
|
||||
#else
|
||||
curvename = "?";
|
||||
#endif
|
||||
gcry_sexp_release (s_pubkey);
|
||||
curveoidstr = gpg_curve_to_oid (curvename, NULL);
|
||||
if (!curveoidstr)
|
||||
{
|
||||
log_error ("no OID known for curve `%s'\n", curvename);
|
||||
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
|
||||
goto leave;
|
||||
}
|
||||
err = openpgp_oid_from_str (curveoidstr, &mpi);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Now replace the curve parameters by the OID and shift the
|
||||
rest of the parameters. */
|
||||
gcry_mpi_release (skey[0]);
|
||||
skey[0] = mpi;
|
||||
for (idx=1; idx <= 4; idx++)
|
||||
gcry_mpi_release (skey[idx]);
|
||||
skey[1] = skey[5];
|
||||
skey[2] = skey[6];
|
||||
for (idx=3; idx <= 6; idx++)
|
||||
skey[idx] = NULL;
|
||||
|
||||
/* Fixup the NPKEY and NSKEY to match OpenPGP reality. */
|
||||
npkey = 2;
|
||||
nskey = 3;
|
||||
|
||||
/* for (idx=0; skey[idx]; idx++) */
|
||||
/* { */
|
||||
/* log_info ("YYY skey[%d]:", idx); */
|
||||
/* if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */
|
||||
/* { */
|
||||
/* 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"); */
|
||||
/* } */
|
||||
}
|
||||
|
||||
/* Do some sanity checks. */
|
||||
if (s2k_count <= 1024)
|
||||
{
|
||||
@ -577,10 +649,16 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Check that the public key parameters match. */
|
||||
/* Check that the public key parameters match. Since Libgcrypt 1.5
|
||||
and the gcry_pk_get_curve function, gcry_mpi_cmp handles opaque
|
||||
MPI correctly and thus we don't need to to do the extra
|
||||
opaqueness checks. */
|
||||
for (idx=0; idx < npkey; idx++)
|
||||
if (gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE)
|
||||
if (0
|
||||
#ifndef HAVE_GCRY_PK_GET_CURVE
|
||||
gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE)
|
||||
|| gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)
|
||||
#endif
|
||||
|| gcry_mpi_cmp (pk->pkey[idx], skey[idx]))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
|
@ -1959,6 +1959,9 @@ main (int argc, char **argv)
|
||||
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
|
||||
}
|
||||
|
||||
/* Use our own logging handler for Libcgrypt. */
|
||||
setup_libgcrypt_logging ();
|
||||
|
||||
/* Put random number into secure memory */
|
||||
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
|
||||
|
||||
|
138
g10/import.c
138
g10/import.c
@ -1,6 +1,6 @@
|
||||
/* import.c - import a key into our key storage.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||
* 2007, 2010 Free Software Foundation, Inc.
|
||||
* 2007, 2010, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -1107,6 +1107,37 @@ 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
|
||||
@ -1133,6 +1164,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
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);
|
||||
@ -1148,7 +1180,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
if (!err)
|
||||
err = gcry_cipher_setkey (cipherhd, kek, keklen);
|
||||
if (err)
|
||||
goto leave; xfree (kek);
|
||||
goto leave;
|
||||
xfree (kek);
|
||||
kek = NULL;
|
||||
|
||||
main_pk = NULL;
|
||||
@ -1161,6 +1194,20 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
if (!main_pk)
|
||||
main_pk = pk;
|
||||
|
||||
/* Make sure the keyids are available. */
|
||||
keyid_from_pk (pk, NULL);
|
||||
if (node->pkt->pkttype == PKT_SECRET_KEY)
|
||||
{
|
||||
pk->main_keyid[0] = pk->keyid[0];
|
||||
pk->main_keyid[1] = pk->keyid[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
pk->main_keyid[0] = main_pk->keyid[0];
|
||||
pk->main_keyid[1] = main_pk->keyid[1];
|
||||
}
|
||||
|
||||
|
||||
ski = pk->seckey_info;
|
||||
if (!ski)
|
||||
BUG ();
|
||||
@ -1191,14 +1238,61 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
|
||||
init_membuf (&mbuf, 50);
|
||||
put_membuf_str (&mbuf, "(skey");
|
||||
for (i=j=0; i < nskey; i++)
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
if (!pk->pkey[i])
|
||||
; /* Protected keys only have NPKEY+1 elements. */
|
||||
else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
/* 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)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_GCRY_PK_GET_CURVE /* Also ensures availability of get_param. */
|
||||
gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECDSA, curve);
|
||||
#else
|
||||
gcry_sexp_t cparam = NULL;
|
||||
#endif
|
||||
xfree (curve);
|
||||
if (!cparam)
|
||||
err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
else
|
||||
{
|
||||
const char *s;
|
||||
|
||||
/* 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_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;
|
||||
@ -1209,8 +1303,36 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
format_args[j++] = pk->pkey + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Standard case for the old (non-ECC) algorithms. */
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
put_membuf_str (&mbuf, " _ %m");
|
||||
format_args[j++] = pk->pkey + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
put_membuf_str (&mbuf, ")\n");
|
||||
put_membuf (&mbuf, "", 1);
|
||||
if (err)
|
||||
xfree (get_membuf (&mbuf, NULL));
|
||||
else
|
||||
{
|
||||
char *format = get_membuf (&mbuf, NULL);
|
||||
if (!format)
|
||||
@ -1328,6 +1450,8 @@ 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]);
|
||||
xfree (cache_nonce);
|
||||
xfree (wrappedkey);
|
||||
xfree (transferkey);
|
||||
|
57
g10/keygen.c
57
g10/keygen.c
@ -1080,6 +1080,40 @@ 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)
|
||||
@ -1117,23 +1151,11 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
|
||||
goto leave;
|
||||
}
|
||||
gcry_sexp_release (l2);
|
||||
if (!strcmp (curve, "NIST P-256"))
|
||||
{
|
||||
oidstr = "1.2.840.10045.3.1.7";
|
||||
nbits = 256;
|
||||
}
|
||||
else if (!strcmp (curve, "NIST P-384"))
|
||||
{
|
||||
oidstr = "1.3.132.0.34";
|
||||
nbits = 384;
|
||||
}
|
||||
else if (!strcmp (curve, "NIST P-521"))
|
||||
{
|
||||
oidstr = "1.3.132.0.35";
|
||||
nbits = 521;
|
||||
}
|
||||
else
|
||||
oidstr = gpg_curve_to_oid (curve, &nbits);
|
||||
if (!oidstr)
|
||||
{
|
||||
/* That can't happen because we used one of the curves
|
||||
gpg_curve_to_oid knows about. */
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
@ -1445,7 +1467,8 @@ gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root,
|
||||
|
||||
assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
|
||||
|
||||
/* For now we may only use one of the 3 NISY curves. */
|
||||
/* 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)
|
||||
|
31
g10/keyid.c
31
g10/keyid.c
@ -81,6 +81,11 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
||||
if(pk->version<4)
|
||||
n+=2;
|
||||
|
||||
/* FIXME: We can avoid the extra malloc by calling only the first
|
||||
mpi_print here which computes the required length and calling the
|
||||
real mpi_print only at the end. The speed advantage would only be
|
||||
for ECC (opaque MPIs) or if we could implement an mpi_print
|
||||
variant with a callback handler to do the hashing. */
|
||||
if (npkey==0 && pk->pkey[0]
|
||||
&& gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
@ -92,24 +97,31 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
||||
{
|
||||
for (i=0; i < npkey; i++ )
|
||||
{
|
||||
enum gcry_mpi_format fmt;
|
||||
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
size_t nbits;
|
||||
const void *p;
|
||||
|
||||
if ((pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
&& (i == 0 || i == 2))
|
||||
fmt = GCRYMPI_FMT_USG; /* Name of OID or KEK parms. */
|
||||
p = gcry_mpi_get_opaque (pk->pkey[i], &nbits);
|
||||
pp[i] = xmalloc ((nbits+7)/8);
|
||||
memcpy (pp[i], p, (nbits+7)/8);
|
||||
nn[i] = (nbits+7)/8;
|
||||
n += nn[i];
|
||||
}
|
||||
else
|
||||
fmt = GCRYMPI_FMT_PGP;
|
||||
|
||||
if (gcry_mpi_print (fmt, NULL, 0, &nbytes, pk->pkey[i]))
|
||||
{
|
||||
if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0,
|
||||
&nbytes, pk->pkey[i]))
|
||||
BUG ();
|
||||
pp[i] = xmalloc (nbytes);
|
||||
if (gcry_mpi_print (fmt, pp[i], nbytes, &nbytes, pk->pkey[i]))
|
||||
if (gcry_mpi_print (GCRYMPI_FMT_PGP, pp[i], nbytes,
|
||||
&nbytes, pk->pkey[i]))
|
||||
BUG ();
|
||||
nn[i] = nbytes;
|
||||
n += nn[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gcry_md_putc ( md, 0x99 ); /* ctb */
|
||||
/* What does it mean if n is greater than than 0xFFFF ? */
|
||||
@ -786,4 +798,3 @@ hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip)
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -236,6 +236,7 @@ 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);
|
||||
|
@ -1,3 +1,8 @@
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cipher.h (PUBKEY_MAX_NPKEY, PUBKEY_MAX_NSKEY): Bump up to
|
||||
accommodate gcrypt ECC keys.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros
|
||||
|
@ -100,8 +100,8 @@ typedef struct
|
||||
|
||||
|
||||
/* Constants to allocate static MPI arrays. */
|
||||
#define PUBKEY_MAX_NPKEY 4
|
||||
#define PUBKEY_MAX_NSKEY 6
|
||||
#define PUBKEY_MAX_NPKEY 5
|
||||
#define PUBKEY_MAX_NSKEY 7
|
||||
#define PUBKEY_MAX_NSIG 2
|
||||
#define PUBKEY_MAX_NENC 2
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
|
||||
no-creation-time.gpg A key with a zero creation time.
|
||||
|
||||
ecc-sample-1-pub.asc The first ECC sample key.
|
||||
ecc-sample-1-sec.asc The first ECC sample key (secret).
|
||||
|
||||
|
22
tests/openpgp/samplekeys/ecc-sample-1-pub.asc
Normal file
22
tests/openpgp/samplekeys/ecc-sample-1-pub.asc
Normal file
@ -0,0 +1,22 @@
|
||||
The key has been generated by the first GnuPG ECC version at
|
||||
http://code.google.com/p/gnupg-ecc.
|
||||
|
||||
The sample key has ECDSA top key 0xBAA59D9C and a single ECDH
|
||||
encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128
|
||||
with KDF.
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2.1.0-ecc (GNU/Linux)
|
||||
|
||||
mFIETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs
|
||||
xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLmtCRlY19kc2FfZGhf
|
||||
MjU2IDxvcGVucGdwQGJyYWluaHViLm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgH
|
||||
AwIGFQgCCQoLBBYCAwECHgECF4AACgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9d
|
||||
JtLJ5As98Alit2oFwzhxG7mSVmQA/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehx
|
||||
XDfpHj+/uFYETJPQrRIIKoZIzj0DAQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1X
|
||||
XsRJEwrzftreZYrn7jXSDoiXkRyfVkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB4hh
|
||||
BBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYBAOSUmaQ8rkgihnepbnpK7tNz
|
||||
3QEocsLEtsTCDUBGNYGyAQDclifYqsUChXlWKaw3md+yHJPcWZXzHt37c4q/MhIm
|
||||
oQ==
|
||||
=hMzp
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
25
tests/openpgp/samplekeys/ecc-sample-1-sec.asc
Normal file
25
tests/openpgp/samplekeys/ecc-sample-1-sec.asc
Normal file
@ -0,0 +1,25 @@
|
||||
The key has been generated by the first GnuPG ECC version at
|
||||
http://code.google.com/p/gnupg-ecc.
|
||||
|
||||
The sample key has ECDSA top key 0xBAA59D9C and a single ECDH
|
||||
encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128
|
||||
with KDF. The password for the key is "ecc".
|
||||
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Version: GnuPG v2.1.0-ecc (GNU/Linux)
|
||||
|
||||
lJ0ETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs
|
||||
xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLm/gMDAmHomSLb9NbE
|
||||
oyWUoqgKTbZzbFR/SWmiCcuiQEhREcTyvyU1hAglj7FsBJoQ6/pbeAEQZ3bVzlNM
|
||||
8F0nF8KPLPuEADF1+4CntCRlY19kc2FfZGhfMjU2IDxvcGVucGdwQGJyYWluaHVi
|
||||
Lm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
|
||||
CgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9dJtLJ5As98Alit2oFwzhxG7mSVmQA
|
||||
/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehxXDfpHj+/nKEETJPQrRIIKoZIzj0D
|
||||
AQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1XXsRJEwrzftreZYrn7jXSDoiXkRyf
|
||||
VkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB/4DAwJh6Jki2/TWxKO7gHKWIcOcxYZp
|
||||
CRWjlUghbKb6Q83p8GLPjKRN0USl/U1tObWdksqMXhUO0ePLWUnrbwoWYfYXg9Er
|
||||
ADTgCYhhBBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYA/3eJRirPQZmBno+Z
|
||||
P/HOBSFWmFt4cUBGUx3oqiUd5loOAP480pb+vXx9ipljJWCJDSl/boRSuqB4hePP
|
||||
qt9Rd5gNdQ==
|
||||
=O8Dg
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
Loading…
x
Reference in New Issue
Block a user