diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/build-packet.c | 43 | ||||
-rw-r--r-- | g10/ecdh.c | 4 | ||||
-rw-r--r-- | g10/export.c | 2 | ||||
-rw-r--r-- | g10/keygen.c | 232 | ||||
-rw-r--r-- | g10/keylist.c | 61 | ||||
-rw-r--r-- | g10/main.h | 1 | ||||
-rw-r--r-- | g10/packet.h | 1 | ||||
-rw-r--r-- | g10/parse-packet.c | 27 | ||||
-rw-r--r-- | g10/pkglue.c | 77 | ||||
-rw-r--r-- | g10/pkglue.h | 2 | ||||
-rw-r--r-- | g10/seskey.c | 7 | ||||
-rw-r--r-- | g10/sign.c | 35 |
12 files changed, 365 insertions, 127 deletions
diff --git a/g10/build-packet.c b/g10/build-packet.c index 159b783ed..6681b3429 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -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) { diff --git a/g10/ecdh.c b/g10/ecdh.c index 8b1949c48..752181ee5 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -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 */ diff --git a/g10/export.c b/g10/export.c index 7fbcb346b..01bdd5e82 100644 --- a/g10/export.c +++ b/g10/export.c @@ -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); diff --git a/g10/keygen.c b/g10/keygen.c index 3b02f043d..9c371bd1a 100644 --- a/g10/keygen.c +++ b/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) diff --git a/g10/keylist.c b/g10/keylist.c index d45aed672..356fac320 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -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); diff --git a/g10/main.h b/g10/main.h index 15d3b7627..fd4e5e9ec 100644 --- a/g10/main.h +++ b/g10/main.h @@ -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); diff --git a/g10/packet.h b/g10/packet.h index fa32ab194..b3956efb2 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -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 ); diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 9c0436231..3b2698fcb 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -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); } } diff --git a/g10/pkglue.c b/g10/pkglue.c index 3a078bd3f..7e50a1c3d 100644 --- a/g10/pkglue.c +++ b/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 diff --git a/g10/pkglue.h b/g10/pkglue.h index e5165f73b..48bfbb5e0 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -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); diff --git a/g10/seskey.c b/g10/seskey.c index ac6e6d6e9..e7f499731 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -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. */ diff --git a/g10/sign.c b/g10/sign.c index 8944067d7..cfac5de76 100644 --- a/g10/sign.c +++ b/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; } |