mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
gpg: Rework ECC support and add experimental support for Ed25519.
* agent/findkey.c (key_parms_from_sexp): Add algo name "ecc". (agent_is_dsa_key): Ditto. (agent_is_eddsa_key): New. Not finished, though. * agent/pksign.c (do_encode_eddsa): New. (agent_pksign_do): Use gcry_log_debug functions. * agent/protect.c (agent_protect): Parse a flags parameter. * g10/keygen.c (gpg_curve_to_oid): Move to ... * common/openpgp-oid.c (openpgp_curve_to_oid): here and rename. (oid_ed25519): New. (openpgp_oid_is_ed25519): New. (openpgp_oid_to_curve): New. * common/t-openpgp-oid.c (test_openpgp_oid_is_ed25519): New. * g10/build-packet.c (gpg_mpi_write): Write the length header also for opaque MPIs. (gpg_mpi_write_nohdr): New. (do_key): Use gpg_mpi_write_nohdr depending on algorithm. (do_pubkey_enc): Ditto. * g10/ecdh.c (pk_ecdh_encrypt_with_shared_point): Use gpg_mpi_write_nohdr. * g10/export.c (transfer_format_to_openpgp): * g10/keygen.c (ecckey_from_sexp): Return the error. (gen_ecc): Repalce arg NBITS by CURVE. (read_parameter_file): Add keywords "Key-Curve" and "Subkey-Curve". (ask_curve): New. (generate_keypair, generate_subkeypair): Use ask_curve. (do_generate_keypair): Also pass curve name. * g10/keylist.c (list_keyblock_print, list_keyblock_colon): Print curve name. * g10/parse-packet.c (mpi_read): Remove workaround for Libcgrypt < 1.5. (parse_key): Fix ECC case. Print the curve name. * g10/pkglue.c (mpi_from_sexp): Rename to get_mpi_from_sexp. (pk_verify, pk_check_secret_key): Add special case for Ed25519. * g10/seskey.c (encode_md_value): Ditto. * g10/sign.c (do_sign, hash_for, sign_file): Ditto. -- Be warned that this code is subject to further changes and that the format will very likely change before a release. There are also known bugs and missing code. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
9ae48b173c
commit
402aa0f948
20 changed files with 574 additions and 139 deletions
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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue