[git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-265-g5499942

by Werner Koch cvs at cvs.gnupg.org
Fri Nov 15 15:56:11 CET 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  5499942571a88a1223a7318992605c6d29858866 (commit)
       via  a0102a548d0e2ed2fce74ba4a21adf26bc352641 (commit)
       via  402aa0f94854bb00475c934be5ca6043a4632126 (commit)
       via  9ae48b173c93f4747a9826beb1fbd023c4362c22 (commit)
       via  b27161cd0c76ae6e2381f60c3a502cde3a2aaa21 (commit)
      from  abd922e79b2ff63a5a763a30d4a06a91f93d0b12 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 5499942571a88a1223a7318992605c6d29858866
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Nov 15 15:54:31 2013 +0100

    kbx: Implement update operation for OpenPGP keyblocks.
    
    * kbx/keybox-update.c (keybox_update_keyblock): Implement.
    * kbx/keybox-search.c (get_blob_flags): Move to ...
    * kbx/keybox-defs.h (blob_get_type): here.
    * kbx/keybox-file.c (_keybox_read_blob2): Fix calling without R_BLOB.
    * g10/keydb.c (build_keyblock_image): Allow calling without
    R_SIGSTATUS.
    (keydb_update_keyblock): Implement for keybox.
    
    * kbx/keybox-dump.c (_keybox_dump_blob): Fix printing of the unhashed
    size.  Print "does not expire" also on 64 bit platforms.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/keydb.c b/g10/keydb.c
index 79ab5af..9085012 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -1,6 +1,7 @@
 /* keydb.c - key database dispatcher
  * Copyright (C) 2001, 2002, 2003, 2004, 2005,
  *               2008, 2009, 2011, 2013 Free Software Foundation, Inc.
+ * Coyrright (C) 2013 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -896,18 +897,24 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
   u32 *sigstatus;
 
   *r_iobuf = NULL;
-  *r_sigstatus = NULL;
+  if (r_sigstatus)
+    *r_sigstatus = NULL;
 
   /* Allocate a vector for the signature cache.  This is an array of
      u32 values with the first value giving the number of elements to
      follow and each element descriping the cache status of the
      signature.  */
-  for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
-    if (node->pkt->pkttype == PKT_SIGNATURE)
-      n_sigs++;
-  sigstatus = xtrycalloc (1+n_sigs, sizeof *sigstatus);
-  if (!sigstatus)
-    return gpg_error_from_syserror ();
+  if (r_sigstatus)
+    {
+      for (kbctx=NULL, n_sigs=0; (node = walk_kbnode (keyblock, &kbctx, 0));)
+        if (node->pkt->pkttype == PKT_SIGNATURE)
+          n_sigs++;
+      sigstatus = xtrycalloc (1+n_sigs, sizeof *sigstatus);
+      if (!sigstatus)
+        return gpg_error_from_syserror ();
+    }
+  else
+    sigstatus = NULL;
 
   iobuf = iobuf_temp ();
   for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
@@ -940,8 +947,8 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
           PKT_signature *sig = node->pkt->pkt.signature;
 
           n_sigs++;
-          /* Fixme: Detect tye "missing key" status.  */
-          if (sig->flags.checked)
+          /* Fixme: Detect the "missing key" status.  */
+          if (sig->flags.checked && sigstatus)
             {
               if (sig->flags.valid)
                 {
@@ -957,10 +964,12 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
             }
         }
     }
-  sigstatus[0] = n_sigs;
+  if (sigstatus)
+    sigstatus[0] = n_sigs;
 
   *r_iobuf = iobuf;
-  *r_sigstatus = sigstatus;
+  if (r_sigstatus)
+    *r_sigstatus = sigstatus;
   return 0;
 }
 
@@ -971,7 +980,7 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
 gpg_error_t
 keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
 {
-  gpg_error_t rc;
+  gpg_error_t err;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
@@ -984,28 +993,36 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
   if (opt.dry_run)
     return 0;
 
-  rc = lock_all (hd);
-  if (rc)
-    return rc;
+  err = lock_all (hd);
+  if (err)
+    return err;
 
   switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      rc = gpg_error (GPG_ERR_GENERAL); /* oops */
+      err = gpg_error (GPG_ERR_GENERAL); /* oops */
       break;
     case KEYDB_RESOURCE_TYPE_KEYRING:
-      rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
+      err = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
+      break;
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      {
+        iobuf_t iobuf;
+
+        err = build_keyblock_image (kb, &iobuf, NULL);
+        if (!err)
+          {
+            err = keybox_update_keyblock (hd->active[hd->found].u.kb,
+                                          iobuf_get_temp_buffer (iobuf),
+                                          iobuf_get_temp_length (iobuf));
+            iobuf_close (iobuf);
+          }
+      }
       break;
-    /* case KEYDB_RESOURCE_TYPE_KEYRING: */
-    /*   rc = build_keyblock (kb, &image, &imagelen); */
-    /*   if (!rc) */
-    /*     rc = keybox_update_keyblock (hd->active[hd->found].u.kb, */
-    /*                                  image, imagelen); */
-    /*   break; */
     }
 
   unlock_all (hd);
-  return rc;
+  return err;
 }
 
 
@@ -1197,6 +1214,9 @@ keydb_rebuild_caches (int noisy)
             log_error (_("failed to rebuild keyring cache: %s\n"),
                        g10_errstr (rc));
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          /* N/A.  */
+          break;
         }
     }
 }
diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c
index 6493527..a38f991 100644
--- a/kbx/keybox-blob.c
+++ b/kbx/keybox-blob.c
@@ -120,8 +120,9 @@
    - bN   Arbitrary space for example used to store data which is not
           part of the keyblock or certificate.  For example the v3 key
           IDs go here.
-   - bN   Space for the keyblock or certifciate.
-   - bN   RFU
+   - bN   Space for the keyblock or certificate.
+   - bN   RFU.  This is the remaining space after keyblock and before
+          the checksum.  Is is not covered by the checksum.
    - b20  SHA-1 checksum (useful for KS syncronisation?)
           Note, that KBX versions before GnuPG 2.1 used an MD5
           checksum.  However it was only created but never checked.
diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h
index ad8e49d..f79c093 100644
--- a/kbx/keybox-defs.h
+++ b/kbx/keybox-defs.h
@@ -1,4 +1,4 @@
-/* keybox-defs.h - interal Keybox defintions
+/* keybox-defs.h - internal Keybox definitions
  *	Copyright (C) 2001, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
@@ -193,6 +193,20 @@ gpg_err_code_t _keybox_get_flag_location (const unsigned char *buffer,
                                           int what,
                                           size_t *flag_off, size_t *flag_size);
 
+static inline int
+blob_get_type (KEYBOXBLOB blob)
+{
+  const unsigned char *buffer;
+  size_t length;
+
+  buffer = _keybox_get_blob_image (blob, &length);
+  if (length < 32)
+    return -1; /* blob too short */
+
+  return buffer[4];
+}
+
+
 /*-- keybox-dump.c --*/
 int _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp);
 int _keybox_dump_file (const char *filename, int stats_only, FILE *outfp);
diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c
index 1af6a9c..af9052d 100644
--- a/kbx/keybox-dump.c
+++ b/kbx/keybox-dump.c
@@ -245,7 +245,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
       || rawdata_len + 4 > length
       || rawdata_off+rawdata_len + 4 > length)
     fprintf (fp, "[Error: raw data larger than blob]\n");
-  unhashed = get32 (buffer + rawdata_off + rawdata_len);
+  unhashed = length - rawdata_off - rawdata_len;
   fprintf (fp, "Unhashed: %lu\n", unhashed);
 
   nkeys = get16 (buffer + 16);
@@ -378,7 +378,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
           fputs ("[bad signature]", fp);
         else if (sflags < 0x10000000)
           fprintf (fp, "[bad flag %0lx]", sflags);
-        else if (sflags == 0xffffffff)
+        else if (sflags == (ulong)(-1))
           fputs ("[good - does not expire]", fp );
         else
           fprintf (fp, "[good - expires at %lu]", sflags);
diff --git a/kbx/keybox-file.c b/kbx/keybox-file.c
index 027bcf8..f720993 100644
--- a/kbx/keybox-file.c
+++ b/kbx/keybox-file.c
@@ -43,7 +43,7 @@ ftello (FILE *stream)
 
 
 /* Read a block at the current postion and return it in r_blob.
-   r_blob may be NULL to simply skip the current block */
+   r_blob may be NULL to simply skip the current block.  */
 int
 _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
 {
@@ -55,7 +55,8 @@ _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
 
   *skipped_deleted = 0;
  again:
-  *r_blob = NULL;
+  if (r_blob)
+    *r_blob = NULL;
   off = ftello (fp);
   if (off == (off_t)-1)
     return gpg_error_from_syserror ();
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index 5e6432f..7980794 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -65,19 +65,6 @@ get16 (const byte *buffer)
 
 
 
-static inline int
-blob_get_type (KEYBOXBLOB blob)
-{
-  const unsigned char *buffer;
-  size_t length;
-
-  buffer = _keybox_get_blob_image (blob, &length);
-  if (length < 32)
-    return -1; /* blob too short */
-
-  return buffer[4];
-}
-
 static inline unsigned int
 blob_get_blob_flags (KEYBOXBLOB blob)
 {
diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c
index 1fdf435..6ade9e7 100644
--- a/kbx/keybox-update.c
+++ b/kbx/keybox-update.c
@@ -425,10 +425,47 @@ keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen,
 gpg_error_t
 keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
 {
-  (void)hd;
-  (void)image;
-  (void)imagelen;
-  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  gpg_error_t err;
+  const char *fname;
+  off_t off;
+  KEYBOXBLOB blob;
+  size_t nparsed;
+  struct _keybox_openpgp_info info;
+
+  if (!hd || !image || !imagelen)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (!hd->found.blob)
+    return gpg_error (GPG_ERR_NOTHING_FOUND);
+  if (blob_get_type (hd->found.blob) != BLOBTYPE_PGP)
+    return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
+  fname = hd->kb->fname;
+  if (!fname)
+    return gpg_error (GPG_ERR_INV_HANDLE);
+
+  off = _keybox_get_blob_fileoffset (hd->found.blob);
+  if (off == (off_t)-1)
+    return gpg_error (GPG_ERR_GENERAL);
+
+  /* Close this the file so that we do no mess up the position for a
+     next search.  */
+  _keybox_close_file (hd);
+
+  /* Build a new blob.  */
+  err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
+  if (err)
+    return err;
+  assert (nparsed <= imagelen);
+  err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
+                                     NULL, hd->ephemeral);
+  _keybox_destroy_openpgp_info (&info);
+
+  /* Update the keyblock.  */
+  if (!err)
+    {
+      err = blob_filecopy (FILECOPY_UPDATE, fname, blob, hd->secret, off);
+      _keybox_release_blob (blob);
+    }
+  return err;
 }
 
 

commit a0102a548d0e2ed2fce74ba4a21adf26bc352641
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Nov 15 09:23:40 2013 +0100

    Fix minor compiler warnings.
    
    --

diff --git a/g10/build-packet.c b/g10/build-packet.c
index 6681b34..b4514ae 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -331,7 +331,7 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
   for (i=0; i < npkey; i++ )
     {
       if ((pk->pubkey_algo == PUBKEY_ALGO_ECDSA && (i == 0))
-          || (pk->pubkey_algo == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2))
+          || ((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]);
diff --git a/g10/kbnode.c b/g10/kbnode.c
index d490740..ad66f8a 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -26,6 +26,7 @@
 
 #include "gpg.h"
 #include "util.h"
+#include "../common/init.h"
 #include "packet.h"
 #include "keydb.h"
 
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 3b2698f..f4390c3 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -1991,7 +1991,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       for (i = 0; i < npkey; i++)
         {
           if ((algorithm == PUBKEY_ALGO_ECDSA && (i == 0))
-              || (algorithm == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2))
+              || ((algorithm == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2)))
             {
               size_t n;
 	      err = read_size_body (inp, pktlen, &n, pk->pkey+i);
diff --git a/tests/openpgp/ecc.test b/tests/openpgp/ecc.test
index 6e3ae81..01e1e06 100755
--- a/tests/openpgp/ecc.test
+++ b/tests/openpgp/ecc.test
@@ -20,7 +20,7 @@ mainkeyids='BAA59D9C
             45AF2FFE'
 
 
-if have_pubkey_algo "ECDH"; then
+if have_pubkey_algo "ECC"; then
   :
 else
   info "No ECC support due to an old Libgcrypt"
diff --git a/tests/openpgp/import.test b/tests/openpgp/import.test
index f9fe990..eb6860e 100755
--- a/tests/openpgp/import.test
+++ b/tests/openpgp/import.test
@@ -31,11 +31,3 @@ if $GPG --list-keys --with-colons $keyid \
 else
   error "$goodkey: import failed (bug 1223)"
 fi
-
-
-
-
-
-
-
-

commit 402aa0f94854bb00475c934be5ca6043a4632126
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Nov 15 08:59:45 2013 +0100

    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 at gnupg.org>

diff --git a/agent/agent.h b/agent/agent.h
index ae4e468..d409300 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -324,6 +324,7 @@ gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
                                         const unsigned char *grip,
                                         gcry_sexp_t *result);
 int agent_is_dsa_key (gcry_sexp_t s_key);
+int agent_is_eddsa_key (gcry_sexp_t s_key);
 int agent_key_available (const unsigned char *grip);
 gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
                                       int *r_keytype,
diff --git a/agent/findkey.c b/agent/findkey.c
index d11f088..aa2c6a2 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -729,6 +729,11 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
       algoname = "dsa";
       elems = "pqgy";
     }
+  else if (n==3 && !memcmp (name, "ecc", 3))
+    {
+      algoname = "ecc";
+      elems = "pabgnq";
+    }
   else if (n==5 && !memcmp (name, "ecdsa", 5))
     {
       algoname = "ecdsa";
@@ -788,6 +793,8 @@ agent_is_dsa_key (gcry_sexp_t s_key)
 
   if (!strcmp (algoname, "dsa"))
     return GCRY_PK_DSA;
+  else if (!strcmp (algoname, "ecc"))
+    return GCRY_PK_ECDSA; /* FIXME: Check for the EdDSA flag.  */
   else if (!strcmp (algoname, "ecdsa"))
     return GCRY_PK_ECDSA;
   else
@@ -795,6 +802,28 @@ agent_is_dsa_key (gcry_sexp_t s_key)
 }
 
 
+/* Return true if S_KEY is an EdDSA key as used with curve Ed25519.  */
+int
+agent_is_eddsa_key (gcry_sexp_t s_key)
+{
+  char algoname[6];
+
+  if (!s_key)
+    return 0;
+
+  if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
+    return 0; /* Error - assume it is not an DSA key.  */
+
+  if (!strcmp (algoname, "dsa"))
+    return GCRY_PK_DSA;
+  else if (!strcmp (algoname, "ecc"))
+    return GCRY_PK_ECDSA; /* FIXME: Check for the EdDSA flag.  */
+  else if (!strcmp (algoname, "ecdsa"))
+    return GCRY_PK_ECDSA;
+  else
+    return 0;
+}
+
 
 /* Return the key for the keygrip GRIP.  The result is stored at
    RESULT.  This function extracts the key from the private key
diff --git a/agent/pksign.c b/agent/pksign.c
index 9c7341a..b2ee28f 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -131,6 +131,24 @@ rfc6979_hash_algo_string (size_t mdlen)
 }
 
 
+/* Encode a message digest for use with the EdDSA algorithm
+   (i.e. curve Ed25519). */
+static gpg_error_t
+do_encode_eddsa (const byte *md, size_t mdlen, gcry_sexp_t *r_hash)
+{
+  gpg_error_t err;
+  gcry_sexp_t hash;
+
+  *r_hash = NULL;
+  err = gcry_sexp_build (&hash, NULL,
+                         "(data(flags eddsa)(hash-algo sha512)(value %b))",
+                         (int)mdlen, md);
+  if (!err)
+    *r_hash = hash;
+  return err;
+}
+
+
 /* Encode a message digest for use with an DSA algorithm. */
 static gpg_error_t
 do_encode_dsa (const byte *md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
@@ -400,7 +418,11 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
       int dsaalgo;
 
       /* Put the hash into a sexp */
-      if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
+      if (agent_is_eddsa_key (s_skey))
+        rc = do_encode_eddsa (ctrl->digest.value,
+                              ctrl->digest.valuelen,
+                              &s_hash);
+      else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
         rc = do_encode_raw_pkcs1 (ctrl->digest.value,
                                   ctrl->digest.valuelen,
                                   gcry_pk_get_nbits (s_skey),
@@ -421,10 +443,8 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
 
       if (DBG_CRYPTO)
         {
-          log_debug ("skey:\n");
-          gcry_sexp_dump (s_skey);
-          log_debug ("hash:\n");
-          gcry_sexp_dump (s_hash);
+          gcry_log_debugsxp ("skey", s_skey);
+          gcry_log_debugsxp ("hash", s_hash);
         }
 
       /* sign */
@@ -437,10 +457,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
         }
 
       if (DBG_CRYPTO)
-        {
-          log_debug ("result:\n");
-          gcry_sexp_dump (s_sig);
-        }
+        gcry_log_debugsxp ("rslt", s_sig);
     }
 
  leave:
diff --git a/agent/protect.c b/agent/protect.c
index b29f494..749867c 100644
--- a/agent/protect.c
+++ b/agent/protect.c
@@ -467,6 +467,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
   int depth = 0;
   unsigned char *p;
   gcry_md_hd_t md;
+  int have_curve = 0;
 
   /* Create an S-expression with the protected-at timestamp.  */
   memcpy (timestamp_exp, "(12:protected-at15:", 19);
@@ -499,6 +500,11 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
   if (!protect_info[infidx].algo)
     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
 
+  /* The parser below is a complete mess: To make it robust for ECC
+     use we should reorder the s-expression to include only what we
+     really need and thus guarantee the right order for saving stuff.
+     This should be done before calling this function and maybe with
+     the help of the new gcry_sexp_extract_param.  */
   parmlist      = protect_info[infidx].parmlist;
   prot_from_idx = protect_info[infidx].prot_from;
   prot_to_idx   = protect_info[infidx].prot_to;
@@ -522,10 +528,19 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
               /* This is a private ECC key but the first parameter is
                  the name of the curve.  We change the parameter list
                  here to the one we expect in this case.  */
+              have_curve = 1;
               parmlist = "?qd";
               prot_from_idx = 2;
               prot_to_idx = 2;
             }
+          else if (n == 5 && !memcmp (s, "flags", 5)
+                   && i == 1 && have_curve)
+            {
+              /* "curve" followed by "flags": Change again.  */
+              parmlist = "??qd";
+              prot_from_idx = 3;
+              prot_to_idx = 3;
+            }
           else
             return gpg_error (GPG_ERR_INV_SEXP);
         }
diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
index 19fadd3..a1ceba4 100644
--- a/common/openpgp-oid.c
+++ b/common/openpgp-oid.c
@@ -1,5 +1,6 @@
 /* openpgp-oids.c - OID helper for OpenPGP
  * Copyright (C) 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -36,6 +37,11 @@
 #include "util.h"
 
 
+/* The OID for Curve Ed25519 in OpenPGP format.  */
+static const char oid_ed25519[] =
+  { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
+
+
 /* Helper for openpgp_oid_from_str.  */
 static size_t
 make_flagged_int (unsigned long value, char *buf, size_t buflen)
@@ -236,3 +242,88 @@ openpgp_oid_to_str (gcry_mpi_t a)
   xfree (string);
   return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
 }
+
+
+
+/* Return true if A represents the OID for Ed25519.  */
+int
+openpgp_oid_is_ed25519 (gcry_mpi_t a)
+{
+  const unsigned char *buf;
+  unsigned int nbits;
+  size_t n;
+
+  if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    return 0;
+
+  buf = gcry_mpi_get_opaque (a, &nbits);
+  n = (nbits+7)/8;
+  return (n == DIM (oid_ed25519)
+          && !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
+}
+
+
+
+/* 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 *
+openpgp_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, "Ed25519"))
+    {
+      oidstr = "1.3.6.1.4.1.3029.1.5.1";
+      nbits = 255;
+    }
+  else if (!strcmp (name, "nistp256"))
+    {
+      oidstr = "1.2.840.10045.3.1.7";
+      nbits = 256;
+    }
+  else if (!strcmp (name, "nistp384"))
+    {
+      oidstr = "1.3.132.0.34";
+      nbits = 384;
+    }
+  else if (!strcmp (name, "nistp521"))
+    {
+      oidstr = "1.3.132.0.35";
+      nbits = 521;
+    }
+  else
+    oidstr = NULL;
+
+  if (r_nbits)
+    *r_nbits = nbits;
+  return oidstr;
+}
+
+
+/* Map an OpenPGP OID to the Libgcrypt curve NAME.  If R_NBITS is not
+   NULL store the bit size of the curve there.  Returns "?" for
+   unknown curve names.  */
+const char *
+openpgp_oid_to_curve (const char *oid)
+{
+  const char *name;
+
+  if (!oid)
+    name = "";
+  else if (!strcmp (oid, "1.3.6.1.4.1.3029.1.5.1"))
+    name = "Ed25519";
+  else if (!strcmp (oid, "1.2.840.10045.3.1.7"))
+    name = "NIST P-256";
+  else if (!strcmp (oid, "1.3.132.0.34"))
+    name = "NIST P-384";
+  else if (!strcmp (oid, "1.3.132.0.35"))
+    name = "NIST P-521";
+  else /* FIXME: Lookup via Libgcrypt.  */
+    name = "?";
+
+  return name;
+}
diff --git a/common/t-openpgp-oid.c b/common/t-openpgp-oid.c
index 80e5763..d101b75 100644
--- a/common/t-openpgp-oid.c
+++ b/common/t-openpgp-oid.c
@@ -35,7 +35,7 @@
 static void
 test_openpgp_oid_from_str (void)
 {
-  static char *sample_oids[] =
+   static char *sample_oids[] =
     {
       "0.0",
       "1.0",
@@ -134,6 +134,41 @@ test_openpgp_oid_to_str (void)
 }
 
 
+static void
+test_openpgp_oid_is_ed25519 (void)
+{
+  static struct
+  {
+    int yes;
+    const char *oidstr;
+  } samples[] = {
+    { 0, "0.0" },
+    { 0, "1.3.132.0.35" },
+    { 0, "1.3.6.1.4.1.3029.1.5.0" },
+    { 1, "1.3.6.1.4.1.3029.1.5.1" },
+    { 0, "1.3.6.1.4.1.3029.1.5.2" },
+    { 0, "1.3.6.1.4.1.3029.1.5.1.0" },
+    { 0, "1.3.6.1.4.1.3029.1.5" },
+    { 0, NULL },
+  };
+  gpg_error_t err;
+  gcry_mpi_t a;
+  int idx;
+
+  for (idx=0; samples[idx].oidstr; idx++)
+    {
+      err = openpgp_oid_from_str (samples[idx].oidstr, &a);
+      if (err)
+        fail (idx, err);
+
+      if (openpgp_oid_is_ed25519 (a) != samples[idx].yes)
+        fail (idx, 0);
+
+      gcry_mpi_release (a);
+    }
+
+}
+
 
 int
 main (int argc, char **argv)
@@ -143,6 +178,7 @@ main (int argc, char **argv)
 
   test_openpgp_oid_from_str ();
   test_openpgp_oid_to_str ();
+  test_openpgp_oid_is_ed25519 ();
 
   return 0;
 }
diff --git a/common/util.h b/common/util.h
index 13b702c..f938888 100644
--- a/common/util.h
+++ b/common/util.h
@@ -215,6 +215,9 @@ size_t percent_unescape_inplace (char *string, int nulrepl);
 /*-- openpgp-oid.c --*/
 gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
 char *openpgp_oid_to_str (gcry_mpi_t a);
+int openpgp_oid_is_ed25519 (gcry_mpi_t a);
+const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits);
+const char *openpgp_oid_to_curve (const char *oid);
 
 
 
diff --git a/doc/DETAILS b/doc/DETAILS
index 100755a..a52f51c 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -32,8 +32,8 @@ fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
 #+end_example
 
 The double =--with-fingerprint= prints the fingerprint for the subkeys
-too.  Old versions of gpg used a lighly different format and required
-the use of the option =--fixed-list-mode= to conform to format
+too.  Old versions of gpg used a slighrly different format and required
+the use of the option =--fixed-list-mode= to conform to the format
 described here.
 
 ** Description of the fields
@@ -201,6 +201,11 @@ described here.
     For sig records, this is the used hash algorithm.  For example:
     2 = SHA-1, 8 = SHA-256.
 
+*** Field 17 - Curve name
+
+    For pub, sub, sec, and sbb records this field is used for the ECC
+    curve name.
+
 ** Special fields
 
 *** PKD - Public key data
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 159b783..6681b34 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 8b1949c..752181e 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 7fbcb34..01bdd5e 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 3b02f04..9c371bd 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 d45aed6..356fac3 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 15d3b76..fd4e5e9 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 fa32ab1..b3956ef 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 9c04362..3b2698f 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 3a078bd..7e50a1c 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 e5165f7..48bfbb5 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 ac6e6d6..e7f4997 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 8944067..cfac5de 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;
       }

commit 9ae48b173c93f4747a9826beb1fbd023c4362c22
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Nov 15 08:36:39 2013 +0100

    kbx: Fix possible segv in kbxdump.
    
    * kbx/keybox-dump.c (_keybox_dump_blob): Check length before get32.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c
index c397f9c..1af6a9c 100644
--- a/kbx/keybox-dump.c
+++ b/kbx/keybox-dump.c
@@ -402,7 +402,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
   n = get32 (p ); p += 4;
   fprintf (fp, "Reserved-Space: %lu\n", n );
 
-  if (unhashed >= 24)
+  if (n >= 4 && unhashed >= 24)
     {
       n = get32 ( buffer + length - unhashed);
       fprintf (fp, "Storage-Flags: %08lx\n", n );

commit b27161cd0c76ae6e2381f60c3a502cde3a2aaa21
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Nov 11 11:33:14 2013 +0100

    Require Libgcrypt 1.6
    
    * agent/pksign.c (do_encode_dsa): Remove Libgcrypt version check
    --
    
    Now that we have decided on a release plan for Libgcrypt 1.6 and given
    all the improvements it makes more sense to make use of these
    improvements than to clutter the GnuPG code with workarounds for older
    Libgcrypt versions.

diff --git a/agent/pksign.c b/agent/pksign.c
index ad783ce..9c7341a 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -197,32 +197,11 @@ do_encode_dsa (const byte *md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
   if (mdlen > qbits/8)
     mdlen = qbits/8;
 
-  /* Create the S-expression.  If we are using Libgcrypt 1.6 we make
-     use of Deterministic DSA.  Libgcrypt < 1.6 does not implement
-     RFC-6979 and also requires us to convert to an MPI because it
-     expects an unsigned integer.  Using %b directly is not possible
-     because Libgcrypt assumes an MPI and uses GCRYMPI_FMT_STD for
-     parsing and thus possible yielding a negative value.  */
-#if GCRYPT_VERSION_NUMBER >= 0x010600 /* Libgcrypt >= 1.6 */
-  {
-    err = gcry_sexp_build (&hash, NULL,
-                           "(data (flags rfc6979) (hash %s %b))",
-                           rfc6979_hash_algo_string (mdlen),
-                           (int)mdlen, md);
-  }
-#else /* Libgcrypt < 1.6 */
-  {
-    gcry_mpi_t mpi;
-
-    err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
-    if (!err)
-      {
-        err = gcry_sexp_build (&hash, NULL,
-                               "(data (flags raw) (value %m))", mpi);
-        gcry_mpi_release (mpi);
-      }
-  }
-#endif /* Libgcrypt < 1.6 */
+  /* Create the S-expression.  */
+  err = gcry_sexp_build (&hash, NULL,
+                         "(data (flags rfc6979) (hash %s %b))",
+                         rfc6979_hash_algo_string (mdlen),
+                         (int)mdlen, md);
   if (!err)
     *r_hash = hash;
   return err;
diff --git a/configure.ac b/configure.ac
index 5a5e9f4..e20a70c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,7 +46,7 @@ AC_INIT([gnupg],[mym4_full_version], [http://bugs.gnupg.org])
 NEED_GPG_ERROR_VERSION=1.11
 
 NEED_LIBGCRYPT_API=1
-NEED_LIBGCRYPT_VERSION=1.5.0
+NEED_LIBGCRYPT_VERSION=1.6.0
 
 NEED_LIBASSUAN_API=2
 NEED_LIBASSUAN_VERSION=2.1.0

-----------------------------------------------------------------------

Summary of changes:
 agent/agent.h             |    1 +
 agent/findkey.c           |   29 ++++++
 agent/pksign.c            |   66 ++++++-------
 agent/protect.c           |   15 +++
 common/openpgp-oid.c      |   91 ++++++++++++++++++
 common/t-openpgp-oid.c    |   38 +++++++-
 common/util.h             |    3 +
 configure.ac              |    2 +-
 doc/DETAILS               |    9 +-
 g10/build-packet.c        |   43 ++++++++-
 g10/ecdh.c                |    4 +-
 g10/export.c              |    2 +-
 g10/kbnode.c              |    1 +
 g10/keydb.c               |   68 ++++++++-----
 g10/keygen.c              |  232 +++++++++++++++++++++++++++++++--------------
 g10/keylist.c             |   61 ++++++++++--
 g10/main.h                |    1 -
 g10/packet.h              |    1 +
 g10/parse-packet.c        |   27 +++---
 g10/pkglue.c              |   77 ++++++++++-----
 g10/pkglue.h              |    2 +-
 g10/seskey.c              |    7 +-
 g10/sign.c                |   35 +++++--
 kbx/keybox-blob.c         |    5 +-
 kbx/keybox-defs.h         |   16 +++-
 kbx/keybox-dump.c         |    6 +-
 kbx/keybox-file.c         |    5 +-
 kbx/keybox-search.c       |   13 ---
 kbx/keybox-update.c       |   45 ++++++++-
 tests/openpgp/ecc.test    |    2 +-
 tests/openpgp/import.test |    8 --
 31 files changed, 691 insertions(+), 224 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list