diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 76932a7a8..7defc200a 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -27,7 +27,7 @@ #include "../common/i18n.h" #include "cvt-openpgp.h" #include "../common/host2net.h" - +#include "../common/openpgpdefs.h" /* Helper to pass data via the callback to do_unprotect. */ struct try_do_unprotect_arg_s @@ -153,6 +153,9 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, else { const char *format; + gcry_mpi_t pubkey = NULL; + gcry_mpi_t seckey = NULL; + pubkey_algo_t pkalgo = 0; /* Specify NONE */ if (!strcmp (curve, "Ed25519")) /* Do not store the OID as name but the real name and the @@ -161,9 +164,24 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, else if (!strcmp (curve, "Curve25519")) format = "(private-key(ecc(curve %s)(flags djb-tweak)(q%m)(d%m)))"; else - format = "(private-key(ecc(curve %s)(q%m)(d%m)))"; + { + if (!strcmp (curve, "Ed448")) + pkalgo = PUBKEY_ALGO_EDDSA; + else if (!strcmp (curve, "X448")) + pkalgo = PUBKEY_ALGO_ECDH; + format = "(private-key(ecc(curve %s)(q%m)(d%m)))"; + } - err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], skey[1]); + if (pkalgo) + { + pubkey = openpgp_ecc_parse_pubkey (pkalgo, curve, skey[0]); + seckey = openpgp_ecc_parse_seckey (pkalgo, curve, skey[1]); + err = gcry_sexp_build (&s_skey, NULL, format, curve, pubkey, seckey); + gcry_mpi_release (pubkey); + gcry_mpi_release (seckey); + } + else + err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], skey[1]); } break; diff --git a/common/Makefile.am b/common/Makefile.am index d8368fc22..8dbf05af7 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -85,7 +85,7 @@ common_sources = \ localename.c \ session-env.c session-env.h \ userids.c userids.h \ - openpgp-oid.c openpgp-s2k.c \ + openpgp-oid.c openpgp-s2k.c openpgp-misc.c \ ssh-utils.c ssh-utils.h \ agent-opt.c \ helpfile.c \ diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h index 625747983..4e5500d0b 100644 --- a/common/openpgpdefs.h +++ b/common/openpgpdefs.h @@ -239,5 +239,10 @@ pubkey_algo_t map_gcry_pk_to_openpgp (enum gcry_pk_algos algo); enum gcry_pk_algos map_openpgp_pk_to_gcry (pubkey_algo_t algo); +/*-- openpgp-misc.c --*/ +gcry_mpi_t openpgp_ecc_parse_pubkey (pubkey_algo_t pkalgo, const char *curve, + gcry_mpi_t pubkey); +gcry_mpi_t openpgp_ecc_parse_seckey (pubkey_algo_t pkalgo, const char *curve_oid, + gcry_mpi_t seckey); #endif /*GNUPG_COMMON_OPENPGPDEFS_H*/ diff --git a/g10/keyid.c b/g10/keyid.c index 522cc9cda..d0a3e4057 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -1068,6 +1068,9 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) err = gpg_error_from_syserror (); else { + gcry_mpi_t pubkey = openpgp_ecc_parse_pubkey (pk->pubkey_algo, + curve, pk->pkey[1]); + err = gcry_sexp_build (&s_pkey, NULL, pk->pubkey_algo == PUBKEY_ALGO_EDDSA? "(public-key(ecc(curve%s)(flags eddsa)(q%m)))": @@ -1075,8 +1078,9 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) && openpgp_oid_is_cv25519 (pk->pkey[0]))? "(public-key(ecc(curve%s)(flags djb-tweak)(q%m)))": "(public-key(ecc(curve%s)(q%m)))", - curve, pk->pkey[1]); + curve, pubkey); xfree (curve); + gcry_mpi_release (pubkey); } } break; diff --git a/g10/misc.c b/g10/misc.c index 2a431b137..c329bef55 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1805,10 +1805,13 @@ pubkey_nbits( int algo, gcry_mpi_t *key ) rc = gpg_error_from_syserror (); else { + gcry_mpi_t pubkey = openpgp_ecc_parse_pubkey (algo, curve, key[1]); + rc = gcry_sexp_build (&sexp, NULL, "(public-key(ecc(curve%s)(q%m)))", curve, key[1]); xfree (curve); + gcry_mpi_release (pubkey); } } else diff --git a/g10/pkglue.c b/g10/pkglue.c index 1e0191e12..137e520e4 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -121,6 +121,26 @@ get_data_from_sexp (gcry_sexp_t sexp, const char *item, size_t *r_size) } +static void +openpgp_ecc_parse_signature (pubkey_algo_t pkalgo, gcry_mpi_t sig_data, + gcry_mpi_t *r, gcry_mpi_t *s) +{ + unsigned int nbits = 0; + unsigned char *buf; + + if (pkalgo != PUBKEY_ALGO_EDDSA) + return; + + buf = gcry_mpi_get_opaque (sig_data, &nbits); + if ((nbits+7)/8 != (8 /*prefix*/ + 448 + 8 /*r*/ + 448 + 8 /*s*/)/8) + return; + + /* Ed448 signature with the prefix. */ + *r = gcry_mpi_set_opaque_copy (NULL, buf+1, 8 + 448); + *s = gcry_mpi_set_opaque_copy (NULL, buf+1+57, 8 + 448); +} + + /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. @@ -171,14 +191,17 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, else { const char *fmt; + gcry_mpi_t pubkey; + pubkey = openpgp_ecc_parse_pubkey (pkalgo, curve, pkey[1]); if (openpgp_oid_is_ed25519 (pkey[0])) fmt = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))"; else fmt = "(public-key(ecc(curve %s)(q%m)))"; - rc = gcry_sexp_build (&s_pkey, NULL, fmt, curve, pkey[1]); + rc = gcry_sexp_build (&s_pkey, NULL, fmt, curve, pubkey); xfree (curve); + gcry_mpi_release (pubkey); } } else @@ -298,6 +321,9 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, } } } + else if (!gcry_mpi_cmp_ui (s, 0)) + /* When data[1] == MPI(0), parse the signature into R and S parts. */ + openpgp_ecc_parse_signature (pkalgo, r, &r, &s); else rc = 0; @@ -388,14 +414,17 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, else { int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]); + gcry_mpi_t pubkey; + pubkey = openpgp_ecc_parse_pubkey (algo, curve, pkey[1]); /* Now use the ephemeral secret to compute the shared point. */ rc = gcry_sexp_build (&s_pkey, NULL, with_djb_tweak_flag ? - "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))" - : "(public-key(ecdh(curve%s)(q%m)))", - curve, pkey[1]); + "(public-key(ecc(curve%s)(flags djb-tweak)(q%m)))" + : "(public-key(ecc(curve%s)(q%m)))", + curve, pubkey); xfree (curve); + gcry_mpi_release (pubkey); /* Put K into a simplified S-expression. */ if (!rc) rc = gcry_sexp_build (&s_data, NULL, "%m", k); @@ -508,10 +537,17 @@ pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) rc = gpg_error_from_syserror (); else { + gcry_mpi_t pubkey; + gcry_mpi_t seckey; + + pubkey = openpgp_ecc_parse_pubkey (pkalgo, curve, skey[1]); + seckey = openpgp_ecc_parse_seckey (pkalgo, curve, skey[2]); rc = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve%s)(q%m)(d%m)))", - curve, skey[1], skey[2]); + curve, pubkey, seckey); xfree (curve); + gcry_mpi_release (pubkey); + gcry_mpi_release (seckey); } } else if (pkalgo == PUBKEY_ALGO_EDDSA) @@ -522,14 +558,20 @@ pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) else { const char *fmt; + gcry_mpi_t pubkey; + gcry_mpi_t seckey; + pubkey = openpgp_ecc_parse_pubkey (pkalgo, curve, skey[1]); + seckey = openpgp_ecc_parse_seckey (pkalgo, curve, skey[2]); if (openpgp_oid_is_ed25519 (skey[0])) fmt = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))"; else fmt = "(private-key(ecc(curve %s)(q%m)(d%m)))"; - rc = gcry_sexp_build (&s_skey, NULL, fmt, curve, skey[1], skey[2]); + rc = gcry_sexp_build (&s_skey, NULL, fmt, curve, pubkey, seckey); xfree (curve); + gcry_mpi_release (pubkey); + gcry_mpi_release (seckey); } } else