gpg,agent: Support Ed448 signing.

* agent/pksign.c (do_encode_eddsa): First argument is NBITs,
so that it can support Ed448, as well as Ed25519.
(agent_pksign_do): Follow the change.
* agent/sexp-secret.c (fixup_when_ecc_private_key): No fix-up needed
for Ed448, it's only for classic curves.
* common/openpgp-oid.c (oidtable): Add Ed448.
* common/sexputil.c (get_pk_algo_from_key): Ed448 is only for EdDSA.
* g10/export.c (match_curve_skey_pk): Ed448 is for EdDSA.
* g10/keygen.c (gen_ecc): Support Ed448 with the name of "ed448".
(ask_algo, parse_key_parameter_part): Handle "ed448".
* g10/pkglue.c (pk_verify): Support Ed448.
(pk_check_secret_key): Support Ed448.
* g10/sign.c (hash_for): Defaults to SHA512 for Ed448.
(make_keysig_packet): Likewise.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2020-06-24 10:05:03 +09:00
parent c94eea15d6
commit a763bb2580
8 changed files with 147 additions and 98 deletions

View File

@ -129,15 +129,20 @@ rfc6979_hash_algo_string (size_t mdlen)
/* Encode a message digest for use with the EdDSA algorithm /* Encode a message digest for use with the EdDSA algorithm
(i.e. curve Ed25519). */ (i.e. curve Ed25519). */
static gpg_error_t static gpg_error_t
do_encode_eddsa (const byte *md, size_t mdlen, gcry_sexp_t *r_hash) do_encode_eddsa (size_t nbits, const byte *md, size_t mdlen,
gcry_sexp_t *r_hash)
{ {
gpg_error_t err; gpg_error_t err;
gcry_sexp_t hash; gcry_sexp_t hash;
const char *fmt;
if (nbits == 448)
fmt = "(data(value %b))";
else
fmt = "(data(flags eddsa)(hash-algo sha512)(value %b))";
*r_hash = NULL; *r_hash = NULL;
err = gcry_sexp_build (&hash, NULL, err = gcry_sexp_build (&hash, NULL, fmt, (int)mdlen, md);
"(data(flags eddsa)(hash-algo sha512)(value %b))",
(int)mdlen, md);
if (!err) if (!err)
*r_hash = hash; *r_hash = hash;
return err; return err;
@ -482,7 +487,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
/* Put the hash into a sexp */ /* Put the hash into a sexp */
if (algo == GCRY_PK_EDDSA) if (algo == GCRY_PK_EDDSA)
err = do_encode_eddsa (data, datalen, err = do_encode_eddsa (gcry_pk_get_nbits (s_skey), data, datalen,
&s_hash); &s_hash);
else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1) else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
err = do_encode_raw_pkcs1 (data, datalen, err = do_encode_raw_pkcs1 (data, datalen,

View File

@ -83,6 +83,7 @@ fixup_when_ecc_private_key (unsigned char *buf, size_t *buflen_p)
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
else if (!*s /* Leading 0x00 added at the front for classic curve */ else if (!*s /* Leading 0x00 added at the front for classic curve */
&& strcmp (curve_name, "Ed25519") && strcmp (curve_name, "Ed25519")
&& strcmp (curve_name, "Ed448")
&& strcmp (curve_name, "X448")) && strcmp (curve_name, "X448"))
{ {
size_t numsize; size_t numsize;

View File

@ -49,6 +49,7 @@ static struct {
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH }, { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA }, { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH }, { "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
{ "Ed448", "1.3.101.113", 448, "ed448", PUBKEY_ALGO_EDDSA },
{ "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" }, { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
{ "NIST P-384", "1.3.132.0.34", 384, "nistp384" }, { "NIST P-384", "1.3.132.0.34", 384, "nistp384" },

View File

@ -624,9 +624,10 @@ get_pk_algo_from_key (gcry_sexp_t key)
algo = gcry_pk_map_name (algoname); algo = gcry_pk_map_name (algoname);
if (algo == GCRY_PK_ECC) if (algo == GCRY_PK_ECC)
{ {
gcry_sexp_t l1 = gcry_sexp_find_token (list, "flags", 0); gcry_sexp_t l1;
int i; int i;
l1 = gcry_sexp_find_token (list, "flags", 0);
for (i = l1 ? gcry_sexp_length (l1)-1 : 0; i > 0; i--) for (i = l1 ? gcry_sexp_length (l1)-1 : 0; i > 0; i--)
{ {
s = gcry_sexp_nth_data (l1, i, &n); s = gcry_sexp_nth_data (l1, i, &n);
@ -640,6 +641,12 @@ get_pk_algo_from_key (gcry_sexp_t key)
} }
} }
gcry_sexp_release (l1); gcry_sexp_release (l1);
l1 = gcry_sexp_find_token (list, "curve", 0);
s = gcry_sexp_nth_data (l1, 1, &n);
if (n == 5 && !memcmp (s, "Ed448", 5))
algo = GCRY_PK_EDDSA;
gcry_sexp_release (l1);
} }
out: out:

View File

@ -568,6 +568,8 @@ match_curve_skey_pk (gcry_sexp_t s_key, PKT_public_key *pk)
log_error ("no curve name\n"); log_error ("no curve name\n");
return gpg_error (GPG_ERR_UNKNOWN_CURVE); return gpg_error (GPG_ERR_UNKNOWN_CURVE);
} }
if (!strcmp (curve_str, "Ed448"))
is_eddsa = 1;
oidstr = openpgp_curve_to_oid (curve_str, NULL, NULL); oidstr = openpgp_curve_to_oid (curve_str, NULL, NULL);
if (!oidstr) if (!oidstr)
{ {

View File

@ -1750,16 +1750,25 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
curve = "Ed25519"; curve = "Ed25519";
else if (!ascii_strcasecmp (curve, "cv448")) else if (!ascii_strcasecmp (curve, "cv448"))
curve = "X448"; curve = "X448";
else if (!ascii_strcasecmp (curve, "ed448"))
curve = "Ed448";
/* Note that we use the "comp" flag with EdDSA to request the use of /* Note that we use the "comp" flag with EdDSA to request the use of
a 0x40 compression prefix octet. */ a 0x40 compression prefix octet. */
if (algo == PUBKEY_ALGO_EDDSA) if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed25519"))
keyparms = xtryasprintf keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))", ("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))",
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" : ""));
else if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed448"))
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519")) else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519"))
keyparms = xtryasprintf keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))", ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
@ -2326,6 +2335,8 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
{ {
if (!strcmp (algostr, "ed25519")) if (!strcmp (algostr, "ed25519"))
kpi->algo = PUBKEY_ALGO_EDDSA; kpi->algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "ed448"))
kpi->algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "cv25519")) else if (!strcmp (algostr, "cv25519"))
kpi->algo = PUBKEY_ALGO_ECDH; kpi->algo = PUBKEY_ALGO_ECDH;
else if (!strcmp (algostr, "cv448")) else if (!strcmp (algostr, "cv448"))
@ -3481,6 +3492,8 @@ parse_key_parameter_part (ctrl_t ctrl,
{ {
if (!strcmp (algostr, "ed25519")) if (!strcmp (algostr, "ed25519"))
algo = PUBKEY_ALGO_EDDSA; algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "ed448"))
kpi->algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "cv25519")) else if (!strcmp (algostr, "cv25519"))
algo = PUBKEY_ALGO_ECDH; algo = PUBKEY_ALGO_ECDH;
else if (!strcmp (algostr, "cv448")) else if (!strcmp (algostr, "cv448"))
@ -3611,6 +3624,7 @@ parse_key_parameter_part (ctrl_t ctrl,
* dsa2048 := DSA with 2048 bit. * dsa2048 := DSA with 2048 bit.
* elg2048 := Elgamal with 2048 bit. * elg2048 := Elgamal with 2048 bit.
* ed25519 := EDDSA using curve Ed25519. * ed25519 := EDDSA using curve Ed25519.
* ed448 := EDDSA using curve Ed448.
* cv25519 := ECDH using curve Curve25519. * cv25519 := ECDH using curve Curve25519.
* cv448 := ECDH using curve X448. * cv448 := ECDH using curve X448.
* nistp256:= ECDSA or ECDH using curve NIST P-256 * nistp256:= ECDSA or ECDH using curve NIST P-256

View File

@ -131,7 +131,6 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
{ {
gcry_sexp_t s_sig, s_hash, s_pkey; gcry_sexp_t s_sig, s_hash, s_pkey;
int rc; int rc;
unsigned int neededfixedlen = 0;
/* Make a sexp from pkey. */ /* Make a sexp from pkey. */
if (pkalgo == PUBKEY_ALGO_DSA) if (pkalgo == PUBKEY_ALGO_DSA)
@ -171,15 +170,16 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
else else
{ {
rc = gcry_sexp_build (&s_pkey, NULL, const char *fmt;
"(public-key(ecc(curve %s)"
"(flags eddsa)(q%m)))",
curve, pkey[1]);
xfree (curve);
}
if (openpgp_oid_is_ed25519 (pkey[0])) if (openpgp_oid_is_ed25519 (pkey[0]))
neededfixedlen = 256 / 8; 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]);
xfree (curve);
}
} }
else else
return GPG_ERR_PUBKEY_ALGO; return GPG_ERR_PUBKEY_ALGO;
@ -190,9 +190,14 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
/* Put hash into a S-Exp s_hash. */ /* Put hash into a S-Exp s_hash. */
if (pkalgo == PUBKEY_ALGO_EDDSA) if (pkalgo == PUBKEY_ALGO_EDDSA)
{ {
if (gcry_sexp_build (&s_hash, NULL, const char *fmt;
"(data(flags eddsa)(hash-algo sha512)(value %m))",
hash)) if (openpgp_oid_is_ed25519 (pkey[0]))
fmt = "(data(flags eddsa)(hash-algo sha512)(value %m))";
else
fmt = "(data(value %m))";
if (gcry_sexp_build (&s_hash, NULL, fmt, hash))
BUG (); /* gcry_sexp_build should never fail. */ BUG (); /* gcry_sexp_build should never fail. */
} }
else else
@ -223,9 +228,13 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
{ {
gcry_mpi_t r = data[0]; gcry_mpi_t r = data[0];
gcry_mpi_t s = data[1]; gcry_mpi_t s = data[1];
if (openpgp_oid_is_ed25519 (pkey[0]))
{
size_t rlen, slen, n; /* (bytes) */ size_t rlen, slen, n; /* (bytes) */
char buf[64]; char buf[64];
unsigned int nbits; unsigned int nbits;
unsigned int neededfixedlen = 256 / 8;
log_assert (neededfixedlen <= sizeof buf); log_assert (neededfixedlen <= sizeof buf);
@ -287,6 +296,10 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
memset (buf, 0, neededfixedlen - n); memset (buf, 0, neededfixedlen - n);
gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8); gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8);
} }
}
}
else
rc = 0;
if (!rc) if (!rc)
rc = gcry_sexp_build (&s_sig, NULL, rc = gcry_sexp_build (&s_sig, NULL,
@ -297,7 +310,6 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
if (s != data[1]) if (s != data[1])
gcry_mpi_release (s); gcry_mpi_release (s);
} }
}
else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
{ {
if (!data[0] || !data[1]) if (!data[0] || !data[1])
@ -506,10 +518,14 @@ pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
else else
{ {
rc = gcry_sexp_build (&s_skey, NULL, const char *fmt;
"(private-key(ecc(curve %s)"
"(flags eddsa)(q%m)(d%m)))", if (openpgp_oid_is_ed25519 (skey[0]))
curve, skey[1], skey[2]); 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]);
xfree (curve); xfree (curve);
} }
} }

View File

@ -630,7 +630,7 @@ match_dsa_hash (unsigned int qbytes)
usable for the pubkey algorithm. If --personal-digest-prefs isn't usable for the pubkey algorithm. If --personal-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 Note that EdDSA takes an input of arbitrary length and thus
we don't enforce any particular algorithm like we do for standard we don't enforce any particular algorithm like we do for standard
ECDSA. However, we use SHA256 as the default algorithm. ECDSA. However, we use SHA256 as the default algorithm.
@ -649,11 +649,13 @@ hash_for (PKT_public_key *pk)
{ {
return recipient_digest_algo; return recipient_digest_algo;
} }
else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA)
&& openpgp_oid_is_ed25519 (pk->pkey[0]))
{ {
if (opt.personal_digest_prefs) if (opt.personal_digest_prefs)
return opt.personal_digest_prefs[0].value; return opt.personal_digest_prefs[0].value;
else
if (gcry_mpi_get_nbits (pk->pkey[1]) > 256)
return DIGEST_ALGO_SHA512;
else else
return DIGEST_ALGO_SHA256; return DIGEST_ALGO_SHA256;
} }
@ -1742,14 +1744,15 @@ make_keysig_packet (ctrl_t ctrl,
digest_algo = opt.cert_digest_algo; digest_algo = opt.cert_digest_algo;
else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */ else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */
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 /* Meet ECDSA requirements. */ else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA) /* Meet ECDSA requirements. */
|| pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
{
if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
digest_algo = DIGEST_ALGO_SHA256;
else
digest_algo = match_dsa_hash digest_algo = match_dsa_hash
(ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
else if (pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
{
if (gcry_mpi_get_nbits (pksk->pkey[1]) > 256)
digest_algo = DIGEST_ALGO_SHA512;
else
digest_algo = DIGEST_ALGO_SHA256;
} }
else /* Use the default. */ else /* Use the default. */
digest_algo = DEFAULT_DIGEST_ALGO; digest_algo = DEFAULT_DIGEST_ALGO;