[Pkg-gnupg-commit] [gnupg2] 02/04: more patches from upstream

Daniel Kahn Gillmor dkg at fifthhorseman.net
Wed Oct 26 01:41:52 UTC 2016


This is an automated email from the git hooks/post-receive script.

dkg pushed a commit to branch master
in repository gnupg2.

commit 1c5cb4e684fa9194d6d378604d6023797f9aff59
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Mon Oct 17 16:38:01 2016 -0400

    more patches from upstream
---
 debian/patches/0064-tools-Fix-error-handling.patch |  34 +
 .../0065-g10-Fix-a-column-s-type-in-TOFU-DB.patch  |  29 +
 ...ove-inotify-code-to-common-and-improve-it.patch | 335 +++++++
 ...traightforward-names-for-the-default-sock.patch |  35 +
 debian/patches/0068-gpgconf-Fix-for-homedir.patch  | 158 ++++
 .../patches/0069-scd-Fix-keytocard-for-ECC.patch   |  28 +
 ...pg-agent-1-at-the-right-gpg-manpage-in-SE.patch |  25 +
 ...ument-how-to-manually-shut-down-gpg-agent.patch |  41 +
 ...72-scd-minor-cleanup-to-merge-other-works.patch | 218 +++++
 .../0073-scd-Support-ECC-key-generation.patch      | 309 +++++++
 ...Make-use-of-default_errsource-in-exechelp.patch | 101 +++
 ...32-Extend-gnupg_create_inbound_pipe-et-al.patch |  93 ++
 ...Communicate-with-child-in-non-blocking-mo.patch |  52 ++
 .../0077-common-Fix-copying-data-to-estreams.patch |  43 +
 .../0078-agent-Add-card-option-for-READKEY.patch   | 274 ++++++
 .../patches/0079-g10-smartcard-keygen-change.patch | 341 +++++++
 ...-scd-GENKEY-updates-the-public-key-in-APP.patch | 568 ++++++++++++
 debian/patches/0081-agent-g10-Fix-keygen.patch     |  44 +
 .../0082-agent-Fix-saving-with-FORCE-1.patch       |  54 ++
 .../patches/0083-Fix-use-cases-of-snprintf.patch   | 999 +++++++++++++++++++++
 .../0084-g10-Support-ECC-for-gen_card_key.patch    | 126 +++
 ...10-Don-t-ask-keysize-for-for-non-RSA-card.patch | 108 +++
 .../0086-scd-Fix-segfault-changing-key-attr.patch  |  33 +
 debian/patches/0087-g10-scd-Fix-ECC-keygen.patch   | 236 +++++
 ...-Write-first-keybox-record-in-binary-mode.patch |  27 +
 .../0089-g10-More-card-key-generation-change.patch | 161 ++++
 .../0090-g10-Fix-card-keygen-for-decryption.patch  |  29 +
 ...091-common-Fix-openpgp_is_curve_supported.patch |  30 +
 ...scd-Use-canonical-curve-name-of-libgcrypt.patch | 318 +++++++
 ...-Slightly-change-structure-of-cmd_readkey.patch | 117 +++
 ...or-cleanup-for-recent-change-in-findkey.c.patch |  32 +
 .../0095-gpg-Replace-two-sprintf-calls.patch       |  54 ++
 ...-w32-Fix-relaying-pinentry-user-data-fix-.patch | 190 ++++
 debian/patches/series                              |  33 +
 34 files changed, 5275 insertions(+)

diff --git a/debian/patches/0064-tools-Fix-error-handling.patch b/debian/patches/0064-tools-Fix-error-handling.patch
new file mode 100644
index 0000000..02f33c5
--- /dev/null
+++ b/debian/patches/0064-tools-Fix-error-handling.patch
@@ -0,0 +1,34 @@
+From: Justus Winter <justus at g10code.com>
+Date: Fri, 7 Oct 2016 12:52:09 +0200
+Subject: tools: Fix error handling.
+
+* tools/gpgtar-create.c (gpgtar_create): Do not crash if opening the
+tarball failed.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ tools/gpgtar-create.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c
+index 6adc1f5..6780eff 100644
+--- a/tools/gpgtar-create.c
++++ b/tools/gpgtar-create.c
+@@ -853,8 +853,6 @@ gpgtar_create (char **inpattern, int encrypt, int sign)
+       if (!outstream)
+         {
+           err = gpg_error_from_syserror ();
+-          log_error (_("can't create '%s': %s\n"),
+-                     opt.outfile, gpg_strerror (err));
+           goto leave;
+         }
+     }
+@@ -958,7 +956,7 @@ gpgtar_create (char **inpattern, int encrypt, int sign)
+   if (err)
+     {
+       log_error ("creating tarball '%s' failed: %s\n",
+-                 es_fname_get (outstream), gpg_strerror (err));
++                 opt.outfile ? opt.outfile : "-", gpg_strerror (err));
+       if (outstream && outstream != es_stdout)
+         es_fclose (outstream);
+       if (cipher_stream && cipher_stream != es_stdout)
diff --git a/debian/patches/0065-g10-Fix-a-column-s-type-in-TOFU-DB.patch b/debian/patches/0065-g10-Fix-a-column-s-type-in-TOFU-DB.patch
new file mode 100644
index 0000000..8e3d625
--- /dev/null
+++ b/debian/patches/0065-g10-Fix-a-column-s-type-in-TOFU-DB.patch
@@ -0,0 +1,29 @@
+From: "Neal H. Walfield" <neal at g10code.com>
+Date: Wed, 12 Oct 2016 21:37:34 +0200
+Subject: g10: Fix a column's type in TOFU DB.
+
+* g10/tofu.c (initdb): Change policy from a boolean to an integer.
+
+--
+Signed-off-by: Neal H. Walfield <neal at g10code.com>
+Reported-by: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+
+Note: sqlite ignores type information so this change has no real
+impact.
+---
+ g10/tofu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/g10/tofu.c b/g10/tofu.c
+index ef14e85..87c7e87 100644
+--- a/g10/tofu.c
++++ b/g10/tofu.c
+@@ -567,7 +567,7 @@ initdb (sqlite3 *db)
+        "create table bindings\n"
+        " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+        "  fingerprint TEXT, email TEXT, user_id TEXT, time INTEGER,\n"
+-       "  policy BOOLEAN CHECK (policy in (%d, %d, %d, %d, %d)),\n"
++       "  policy INTEGER CHECK (policy in (%d, %d, %d, %d, %d)),\n"
+        "  conflict STRING,\n"
+        "  unique (fingerprint, email));\n"
+        "create index bindings_fingerprint_email\n"
diff --git a/debian/patches/0066-agent-Move-inotify-code-to-common-and-improve-it.patch b/debian/patches/0066-agent-Move-inotify-code-to-common-and-improve-it.patch
new file mode 100644
index 0000000..b7270cd
--- /dev/null
+++ b/debian/patches/0066-agent-Move-inotify-code-to-common-and-improve-it.patch
@@ -0,0 +1,335 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Sat, 15 Oct 2016 21:35:05 +0200
+Subject: agent: Move inotify code to common and improve it.
+
+* common/sysutils.c: Include sys/inotify.h.
+(my_error_from_syserror, my_error): New.
+(gnupg_inotify_watch_socket): New.
+(gnupg_inotify_has_name): New.
+* agent/gpg-agent.c: Do not include sys/inotify.h.
+(my_inotify_is_name): Remove.
+(handle_connections): Remove HAVE_INOTIFY_INIT protected code and use
+the new functions.
+--
+
+When removing not a simple socket file but the entire directory the
+old code missed most events and thus did not worked properly.
+
+IN_DELETE_SELF has also been added to the watch list to detect a
+removal of the directory.  However, in all tests that event was not
+triggered.  The only way it could be triggered was by not watching
+the socket dir but an arbitary directory and rmdir that.
+
+GnuPG-bug-id: 2756
+Signed-off-by: Werner Koch <wk at gnupg.org>
+---
+ agent/gpg-agent.c |  65 ++++------------------------
+ common/sysutils.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ common/sysutils.h |   4 ++
+ 3 files changed, 140 insertions(+), 56 deletions(-)
+
+diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
+index 44a6bbb..0146d85 100644
+--- a/agent/gpg-agent.c
++++ b/agent/gpg-agent.c
+@@ -47,9 +47,6 @@
+ #ifdef HAVE_SIGNAL_H
+ # include <signal.h>
+ #endif
+-#ifdef HAVE_INOTIFY_INIT
+-# include <sys/inotify.h>
+-#endif /*HAVE_INOTIFY_INIT*/
+ #include <npth.h>
+ #ifdef HAVE_PRCTL
+ # include <sys/prctl.h>
+@@ -2724,31 +2721,6 @@ start_connection_thread_ssh (void *arg)
+ }
+ 
+ 
+-#ifdef HAVE_INOTIFY_INIT
+-/* Read an inotify event and return true if it matches NAME.  */
+-static int
+-my_inotify_is_name (int fd, const char *name)
+-{
+-  union {
+-    struct inotify_event ev;
+-    char _buf[sizeof (struct inotify_event) + 100 + 1];
+-  } buf;
+-  int n;
+-
+-  n = npth_read (fd, &buf, sizeof buf);
+-  if (n < sizeof (struct inotify_event))
+-    return 0;
+-  if (buf.ev.len < strlen (name)+1)
+-    return 0;
+-  if (strcmp (buf.ev.name, name))
+-    return 0; /* Not the desired file.  */
+-
+-  return 1; /* Found.  */
+-}
+-#endif /*HAVE_INOTIFY_INIT*/
+-
+-
+-
+ /* Connection handler loop.  Wait for connection requests and spawn a
+    thread after accepting a connection.  */
+ static void
+@@ -2757,6 +2729,7 @@ handle_connections (gnupg_fd_t listen_fd,
+                     gnupg_fd_t listen_fd_browser,
+                     gnupg_fd_t listen_fd_ssh)
+ {
++  gpg_error_t err;
+   npth_attr_t tattr;
+   struct sockaddr_un paddr;
+   socklen_t plen;
+@@ -2772,9 +2745,7 @@ handle_connections (gnupg_fd_t listen_fd,
+   HANDLE events[2];
+   unsigned int events_set;
+ #endif
+-#ifdef HAVE_INOTIFY_INIT
+-  int my_inotify_fd;
+-#endif /*HAVE_INOTIFY_INIT*/
++  int my_inotify_fd = -1;
+   struct {
+     const char *name;
+     void *(*func) (void *arg);
+@@ -2812,27 +2783,14 @@ handle_connections (gnupg_fd_t listen_fd,
+ # endif
+ #endif
+ 
+-#ifdef HAVE_INOTIFY_INIT
+   if (disable_check_own_socket)
+     my_inotify_fd = -1;
+-  else if ((my_inotify_fd = inotify_init ()) == -1)
+-    log_info ("error enabling fast daemon termination: %s\n",
+-              strerror (errno));
+-  else
++  else if ((err = gnupg_inotify_watch_socket (&my_inotify_fd, socket_name)))
+     {
+-      /* We need to watch the directory for the file becuase there
+-       * won't be an IN_DELETE_SELF for a socket file.  */
+-      char *slash = strrchr (socket_name, '/');
+-      log_assert (slash && slash[1]);
+-      *slash = 0;
+-      if (inotify_add_watch (my_inotify_fd, socket_name, IN_DELETE) == -1)
+-        {
+-          close (my_inotify_fd);
+-          my_inotify_fd = -1;
+-        }
+-      *slash = '/';
++      if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
++        log_info ("error enabling fast daemon termination: %s\n",
++                  gpg_strerror (err));
+     }
+-#endif /*HAVE_INOTIFY_INIT*/
+ 
+   /* On Windows we need to fire up a separate thread to listen for
+      requests from Putty (an SSH client), so we can replace Putty's
+@@ -2875,14 +2833,12 @@ handle_connections (gnupg_fd_t listen_fd,
+       if (FD2INT (listen_fd_ssh) > nfd)
+         nfd = FD2INT (listen_fd_ssh);
+     }
+-#ifdef HAVE_INOTIFY_INIT
+   if (my_inotify_fd != -1)
+     {
+       FD_SET (my_inotify_fd, &fdset);
+       if (my_inotify_fd > nfd)
+         nfd = my_inotify_fd;
+     }
+-#endif /*HAVE_INOTIFY_INIT*/
+ 
+   listentbl[0].l_fd = listen_fd;
+   listentbl[1].l_fd = listen_fd_extra;
+@@ -2957,14 +2913,13 @@ handle_connections (gnupg_fd_t listen_fd,
+           ctrl_t ctrl;
+           npth_t thread;
+ 
+-#ifdef HAVE_INOTIFY_INIT
+-          if (my_inotify_fd != -1 && FD_ISSET (my_inotify_fd, &read_fdset)
+-              && my_inotify_is_name (my_inotify_fd, GPG_AGENT_SOCK_NAME))
++          if (my_inotify_fd != -1
++              && FD_ISSET (my_inotify_fd, &read_fdset)
++              && gnupg_inotify_has_name (my_inotify_fd, GPG_AGENT_SOCK_NAME))
+             {
+               shutdown_pending = 1;
+               log_info ("socket file has been removed - shutting down\n");
+             }
+-#endif /*HAVE_INOTIFY_INIT*/
+ 
+           for (idx=0; idx < DIM(listentbl); idx++)
+             {
+@@ -3012,10 +2967,8 @@ handle_connections (gnupg_fd_t listen_fd,
+         }
+     }
+ 
+-#ifdef HAVE_INOTIFY_INIT
+   if (my_inotify_fd != -1)
+     close (my_inotify_fd);
+-#endif /*HAVE_INOTIFY_INIT*/
+   cleanup ();
+   log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
+   npth_attr_destroy (&tattr);
+diff --git a/common/sysutils.c b/common/sysutils.c
+index 0f7b7f5..2e663bc 100644
+--- a/common/sysutils.c
++++ b/common/sysutils.c
+@@ -63,6 +63,9 @@
+ # endif
+ # include <windows.h>
+ #endif
++#ifdef HAVE_INOTIFY_INIT
++# include <sys/inotify.h>
++#endif /*HAVE_INOTIFY_INIT*/
+ #ifdef HAVE_NPTH
+ # include <npth.h>
+ #endif
+@@ -78,6 +81,20 @@
+ #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+ 
+ 
++static GPGRT_INLINE gpg_error_t
++my_error_from_syserror (void)
++{
++  return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
++}
++
++static GPGRT_INLINE gpg_error_t
++my_error (int e)
++{
++  return gpg_err_make (default_errsource, (e));
++}
++
++
++
+ #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
+ #warning using trap_unaligned
+ static int
+@@ -929,3 +946,113 @@ w32_get_user_sid (void)
+   return sid;
+ }
+ #endif /*HAVE_W32_SYSTEM*/
++
++
++

++/* Support for inotify under Linux.  */
++
++/* Store a new inotify file handle for SOCKET_NAME at R_FD or return
++ * an error code. */
++gpg_error_t
++gnupg_inotify_watch_socket (int *r_fd, const char *socket_name)
++{
++#if HAVE_INOTIFY_INIT
++  gpg_error_t err;
++  char *fname;
++  int fd;
++  char *p;
++
++  *r_fd = -1;
++
++  fname = xtrystrdup (socket_name);
++  if (!fname)
++    return my_error_from_syserror ();
++
++  fd = inotify_init ();
++  if (fd == -1)
++    {
++      err = my_error_from_syserror ();
++      xfree (fname);
++      return err;
++    }
++
++  /* We need to watch the directory for the file because there won't
++   * be an IN_DELETE_SELF for a socket file.  To handle a removal of
++   * the directory we also watch the directory itself. */
++  p = strrchr (fname, '/');
++  if (p)
++    *p = 0;
++  if (inotify_add_watch (fd, fname,
++                         (IN_DELETE|IN_DELETE_SELF|IN_EXCL_UNLINK)) == -1)
++    {
++      err = my_error_from_syserror ();
++      close (fd);
++      xfree (fname);
++      return err;
++    }
++
++  xfree (fname);
++
++  *r_fd = fd;
++  return 0;
++#else /*!HAVE_INOTIFY_INIT*/
++
++  (void)socket_name;
++  *r_fd = -1;
++  return my_error (GPG_ERR_NOT_SUPPORTED);
++
++#endif /*!HAVE_INOTIFY_INIT*/
++}
++
++
++/* Read an inotify event and return true if it matches NAME or if it
++ * sees an IN_DELETE_SELF event for the directory of NAME.  */
++int
++gnupg_inotify_has_name (int fd, const char *name)
++{
++#if USE_NPTH && HAVE_INOTIFY_INIT
++  union {
++    struct inotify_event ev;
++    char _buf[sizeof (struct inotify_event) + 255 + 1];
++  } buf;
++  struct inotify_event *evp;
++  int n;
++
++  n = npth_read (fd, &buf, sizeof buf);
++  /* log_debug ("notify read: n=%d\n", n); */
++  evp = &buf.ev;
++  while (n >= sizeof (struct inotify_event))
++    {
++      /* log_debug ("             mask=%x len=%u name=(%s)\n", */
++      /*        evp->mask, (unsigned int)evp->len, evp->len? evp->name:""); */
++      if ((evp->mask & IN_UNMOUNT))
++        {
++          /* log_debug ("             found (dir unmounted)\n"); */
++          return 3; /* Directory was unmounted.  */
++        }
++      if ((evp->mask & IN_DELETE_SELF))
++        {
++          /* log_debug ("             found (dir removed)\n"); */
++          return 2; /* Directory was removed.  */
++        }
++      if ((evp->mask & IN_DELETE))
++        {
++          if (evp->len >= strlen (name) && !strcmp (evp->name, name))
++            {
++              /* log_debug ("             found (file removed)\n"); */
++              return 1; /* File was removed.  */
++            }
++        }
++      n -= sizeof (*evp) + evp->len;
++      evp = (struct inotify_event *)((char*)evp + sizeof (*evp) + evp->len);
++    }
++
++#else /*!(USE_NPTH && HAVE_INOTIFY_INIT)*/
++
++  (void)fd;
++  (void)name;
++
++#endif  /*!(USE_NPTH && HAVE_INOTIFY_INIT)*/
++
++  return 0; /* Not found.  */
++}
+diff --git a/common/sysutils.h b/common/sysutils.h
+index ba66ce6..ea92e4c 100644
+--- a/common/sysutils.h
++++ b/common/sysutils.h
+@@ -67,6 +67,10 @@ int  gnupg_setenv (const char *name, const char *value, int overwrite);
+ int  gnupg_unsetenv (const char *name);
+ char *gnupg_getcwd (void);
+ 
++gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);
++int gnupg_inotify_has_name (int fd, const char *name);
++
++
+ #ifdef HAVE_W32_SYSTEM
+ void *w32_get_user_sid (void);
+ 
diff --git a/debian/patches/0067-agent-Use-straightforward-names-for-the-default-sock.patch b/debian/patches/0067-agent-Use-straightforward-names-for-the-default-sock.patch
new file mode 100644
index 0000000..d9c9cab
--- /dev/null
+++ b/debian/patches/0067-agent-Use-straightforward-names-for-the-default-sock.patch
@@ -0,0 +1,35 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Sun, 16 Oct 2016 22:30:26 +0200
+Subject: agent: Use straightforward names for the default socket names.
+
+* configure.ac (GPG_AGENT_SOCK_NAME): Change name to *.extra.
+(GPG_AGENT_EXTRA_SOCK_NAME): Change name to *browser.
+--
+
+There has been quite some fuzz about the naming of the (new) default
+socket files.  The used names do not match the names of the option.
+Because these are just names we now change the names to match the
+names of the options instead of changing the option names to something
+we can't agree upon.
+
+Signed-off-by: Werner Koch <wk at gnupg.org>
+---
+ configure.ac | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index acfd8c2..634a570 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1747,9 +1747,9 @@ AC_DEFINE_UNQUOTED(GPGTAR_NAME, "gpgtar", [The name of the gpgtar tool])
+ 
+ AC_DEFINE_UNQUOTED(GPG_AGENT_SOCK_NAME, "S.gpg-agent",
+                    [The name of the agent socket])
+-AC_DEFINE_UNQUOTED(GPG_AGENT_EXTRA_SOCK_NAME, "S.gpg-agent.rstrd",
++AC_DEFINE_UNQUOTED(GPG_AGENT_EXTRA_SOCK_NAME, "S.gpg-agent.extra",
+                    [The name of the agent socket for remote access])
+-AC_DEFINE_UNQUOTED(GPG_AGENT_BROWSER_SOCK_NAME, "S.gpg-agent.brwsr",
++AC_DEFINE_UNQUOTED(GPG_AGENT_BROWSER_SOCK_NAME, "S.gpg-agent.browser",
+                    [The name of the agent socket for browsers])
+ AC_DEFINE_UNQUOTED(GPG_AGENT_SSH_SOCK_NAME, "S.gpg-agent.ssh",
+                    [The name of the agent socket for ssh])
diff --git a/debian/patches/0068-gpgconf-Fix-for-homedir.patch b/debian/patches/0068-gpgconf-Fix-for-homedir.patch
new file mode 100644
index 0000000..23fb7b4
--- /dev/null
+++ b/debian/patches/0068-gpgconf-Fix-for-homedir.patch
@@ -0,0 +1,158 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Mon, 17 Oct 2016 11:36:45 +0900
+Subject: gpgconf: Fix for --homedir.
+
+* tools/gpgconf-comp.c (gpg_agent_runtime_change,
+scdaemon_runtime_change, dirmngr_runtime_change): Provide the homedir
+arguments by --homedir when it's not default.
+
+--
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ tools/gpgconf-comp.c | 80 +++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 60 insertions(+), 20 deletions(-)
+
+diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c
+index 82b5325..8bf3086 100644
+--- a/tools/gpgconf-comp.c
++++ b/tools/gpgconf-comp.c
+@@ -1088,33 +1088,48 @@ struct error_line_s
+ static void
+ gpg_agent_runtime_change (int killflag)
+ {
+-  gpg_error_t err;
++  gpg_error_t err = 0;
+   const char *pgmname;
+-  const char *argv[3];
++  const char *argv[5];
+   pid_t pid;
++  char *abs_homedir = NULL;
++  int i = 0;
+ 
+   pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT);
+-  argv[0] = "--no-autostart";
+-  argv[1] = killflag? "KILLAGENT" : "RELOADAGENT";
+-  argv[2] = NULL;
++  if (!gnupg_default_homedir_p ())
++    {
++      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
++      if (!abs_homedir)
++        err = gpg_error_from_syserror ();
+ 
+-  err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
++      argv[i++] = "--homedir";
++      argv[i++] = abs_homedir;
++    }
++  argv[i++] = "--no-autostart";
++  argv[i++] = killflag? "KILLAGENT" : "RELOADAGENT";
++  argv[i++] = NULL;
++
++  if (!err)
++    err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+   if (!err)
+     err = gnupg_wait_process (pgmname, pid, 1, NULL);
+   if (err)
+     gc_error (0, 0, "error running '%s %s': %s",
+               pgmname, argv[1], gpg_strerror (err));
+   gnupg_release_process (pid);
++  xfree (abs_homedir);
+ }
+ 
+ 
+ static void
+ scdaemon_runtime_change (int killflag)
+ {
+-  gpg_error_t err;
++  gpg_error_t err = 0;
+   const char *pgmname;
+-  const char *argv[7];
++  const char *argv[9];
+   pid_t pid;
++  char *abs_homedir = NULL;
++  int i = 0;
+ 
+   (void)killflag;  /* For scdaemon kill and reload are synonyms.  */
+ 
+@@ -1124,45 +1139,70 @@ scdaemon_runtime_change (int killflag)
+      obviously a race condition but that should not harm too much.  */
+ 
+   pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT);
+-  argv[0] = "-s";
+-  argv[1] = "--no-autostart";
+-  argv[2] = "GETINFO scd_running";
+-  argv[3] = "/if ${! $?}";
+-  argv[4] = "scd killscd";
+-  argv[5] = "/end";
+-  argv[6] = NULL;
++  if (!gnupg_default_homedir_p ())
++    {
++      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
++      if (!abs_homedir)
++        err = gpg_error_from_syserror ();
++
++      argv[i++] = "--homedir";
++      argv[i++] = abs_homedir;
++    }
++  argv[i++] = "-s";
++  argv[i++] = "--no-autostart";
++  argv[i++] = "GETINFO scd_running";
++  argv[i++] = "/if ${! $?}";
++  argv[i++] = "scd killscd";
++  argv[i++] = "/end";
++  argv[i++] = NULL;
+ 
+-  err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
++  if (!err)
++    err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+   if (!err)
+     err = gnupg_wait_process (pgmname, pid, 1, NULL);
+   if (err)
+     gc_error (0, 0, "error running '%s %s': %s",
+               pgmname, argv[4], gpg_strerror (err));
+   gnupg_release_process (pid);
++  xfree (abs_homedir);
+ }
+ 
+ 
+ static void
+ dirmngr_runtime_change (int killflag)
+ {
+-  gpg_error_t err;
++  gpg_error_t err = 0;
+   const char *pgmname;
+-  const char *argv[4];
++  const char *argv[6];
+   pid_t pid;
++  char *abs_homedir = NULL;
+ 
+   pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT);
+   argv[0] = "--no-autostart";
+   argv[1] = "--dirmngr";
+   argv[2] = killflag? "KILLDIRMNGR" : "RELOADDIRMNGR";
+-  argv[3] = NULL;
++  if (gnupg_default_homedir_p ())
++    argv[3] = NULL;
++  else
++    {
++      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
++      if (!abs_homedir)
++        err = gpg_error_from_syserror ();
+ 
+-  err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
++      argv[3] = "--homedir";
++      argv[4] = abs_homedir;
++      argv[5] = NULL;
++    }
++
++  if (!err)
++    err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+   if (!err)
+     err = gnupg_wait_process (pgmname, pid, 1, NULL);
+   if (err)
+     gc_error (0, 0, "error running '%s %s': %s",
+               pgmname, argv[2], gpg_strerror (err));
+   gnupg_release_process (pid);
++  xfree (abs_homedir);
+ }
+ 
+ 
diff --git a/debian/patches/0069-scd-Fix-keytocard-for-ECC.patch b/debian/patches/0069-scd-Fix-keytocard-for-ECC.patch
new file mode 100644
index 0000000..ef6ce96
--- /dev/null
+++ b/debian/patches/0069-scd-Fix-keytocard-for-ECC.patch
@@ -0,0 +1,28 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Mon, 17 Oct 2016 12:02:28 +0900
+Subject: scd: Fix keytocard for ECC.
+
+* scd/app-openpgp.c (build_ecc_privkey_template): Size can be greater
+than 128 when it comes with public key for curve of larger field.
+
+--
+
+Reported-by: Arnaud Fontaine <arnaud.fontaine at ssi.gouv.fr>
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ scd/app-openpgp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index 563a045..ef335fe 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -2689,6 +2689,8 @@ build_ecc_privkey_template (app_t app, int keyno,
+                    + privkey_len
+                    + suffix_len
+                    + datalen);
++  if (exthdr_len + privkey_len + suffix_len + datalen >= 128)
++    template_size++;
+   tp = template = xtrymalloc_secure (template_size);
+   if (!template)
+     return gpg_error_from_syserror ();
diff --git a/debian/patches/0070-doc-Point-gpg-agent-1-at-the-right-gpg-manpage-in-SE.patch b/debian/patches/0070-doc-Point-gpg-agent-1-at-the-right-gpg-manpage-in-SE.patch
new file mode 100644
index 0000000..f6edf8d
--- /dev/null
+++ b/debian/patches/0070-doc-Point-gpg-agent-1-at-the-right-gpg-manpage-in-SE.patch
@@ -0,0 +1,25 @@
+From: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+Date: Fri, 14 Oct 2016 02:23:37 -0400
+Subject: doc: Point gpg-agent(1) at the right gpg manpage in SEE ALSO.
+
+* doc/gpg-agent.texi (SEE ALSO): refer to @gpgname, instead of
+  hard-coding "gpg2".
+
+Signed-off-by: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+---
+ doc/gpg-agent.texi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi
+index 232e060..0645741 100644
+--- a/doc/gpg-agent.texi
++++ b/doc/gpg-agent.texi
+@@ -1516,7 +1516,7 @@ much slower or faster than the actual box.
+ 
+ @mansect see also
+ @ifset isman
+- at command{gpg2}(1),
++ at command{@gpgname}(1),
+ @command{gpgsm}(1),
+ @command{gpg-connect-agent}(1),
+ @command{scdaemon}(1)
diff --git a/debian/patches/0071-doc-Document-how-to-manually-shut-down-gpg-agent.patch b/debian/patches/0071-doc-Document-how-to-manually-shut-down-gpg-agent.patch
new file mode 100644
index 0000000..6362a8c
--- /dev/null
+++ b/debian/patches/0071-doc-Document-how-to-manually-shut-down-gpg-agent.patch
@@ -0,0 +1,41 @@
+From: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+Date: Fri, 14 Oct 2016 12:42:24 -0400
+Subject: doc: Document how to manually shut down gpg-agent.
+
+* doc/gpg-agent.texi: document "gpgconf --kill gpg-agent" for manual
+  agent termination.
+
+This was requested in a side-comment in https://bugs.debian.org/840669
+
+Signed-off-by: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+---
+ doc/gpg-agent.texi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi
+index 0645741..cc016f8 100644
+--- a/doc/gpg-agent.texi
++++ b/doc/gpg-agent.texi
+@@ -85,6 +85,14 @@ gpg-connect-agent /bye
+ @end example
+ 
+ @noindent
++If you want to manually terminate the currently-running agent, you can
++safely do so with:
++
++ at example
++gpgconf --kill gpg-agent
++ at end example
++
++ at noindent
+ @efindex GPG_TTY
+ You should always add the following lines to your @code{.bashrc} or
+ whatever initialization file is used for all shell invocations:
+@@ -1518,6 +1526,7 @@ much slower or faster than the actual box.
+ @ifset isman
+ @command{@gpgname}(1),
+ @command{gpgsm}(1),
++ at command{gpgconf}(1),
+ @command{gpg-connect-agent}(1),
+ @command{scdaemon}(1)
+ @end ifset
diff --git a/debian/patches/0072-scd-minor-cleanup-to-merge-other-works.patch b/debian/patches/0072-scd-minor-cleanup-to-merge-other-works.patch
new file mode 100644
index 0000000..c9eb33b
--- /dev/null
+++ b/debian/patches/0072-scd-minor-cleanup-to-merge-other-works.patch
@@ -0,0 +1,218 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Tue, 18 Oct 2016 20:40:09 +0900
+Subject: scd: minor cleanup to merge other works.
+
+* scd/iso7816.c (do_generate_keypair): Use const char * for DATA.
+(iso7816_generate_keypair, iso7816_read_public_key): Likewise.
+* scd/app-openpgp.c (get_public_key): Follow the change.
+(do_genkey): Ditto.  Use ERR instead of RC.  Use u32 for CREATED_AT.
+--
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ scd/app-openpgp.c | 58 +++++++++++++++++++++++++------------------------------
+ scd/iso7816.c     |  9 ++++-----
+ scd/iso7816.h     |  4 ++--
+ 3 files changed, 32 insertions(+), 39 deletions(-)
+
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index ef335fe..ba16255 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -1276,12 +1276,10 @@ get_public_key (app_t app, int keyno)
+           le_value = 256; /* Use legacy value. */
+         }
+ 
+-      err = iso7816_read_public_key
+-        (app->slot, exmode,
+-         (const unsigned char*)(keyno == 0? "\xB6" :
+-                                keyno == 1? "\xB8" : "\xA4"), 2,
+-         le_value,
+-         &buffer, &buflen);
++      err = iso7816_read_public_key (app->slot, exmode,
++                                     (keyno == 0? "\xB6" :
++                                      keyno == 1? "\xB8" : "\xA4"),
++                                     2, le_value, &buffer, &buflen);
+       if (err)
+         {
+           log_error (_("reading public key failed: %s\n"), gpg_strerror (err));
+@@ -3534,13 +3532,13 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+            gpg_error_t (*pincb)(void*, const char *, char **),
+            void *pincb_arg)
+ {
+-  int rc;
++  gpg_error_t err;
+   char numbuf[30];
+   unsigned char fprbuf[20];
+   const unsigned char *keydata, *m, *e;
+   unsigned char *buffer = NULL;
+   size_t buflen, keydatalen, mlen, elen;
+-  time_t created_at;
++  u32 created_at;
+   int keyno = atoi (keynostr) - 1;
+   int force = (flags & 1);
+   time_t start_at;
+@@ -3562,9 +3560,9 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   app->app_local->pk[keyno].read_done = 0;
+ 
+   /* Check whether a key already exists.  */
+-  rc = does_key_exist (app, keyno, 1, force);
+-  if (rc)
+-    return rc;
++  err = does_key_exist (app, keyno, 1, force);
++  if (err)
++    return err;
+ 
+   /* Because we send the key parameter back via status lines we need
+      to put a limit on the max. allowed keysize.  2048 bit will
+@@ -3575,8 +3573,8 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+     return gpg_error (GPG_ERR_TOO_LARGE);
+ 
+   /* Prepare for key generation by verifying the Admin PIN.  */
+-  rc = verify_chv3 (app, pincb, pincb_arg);
+-  if (rc)
++  err = verify_chv3 (app, pincb, pincb_arg);
++  if (err)
+     goto leave;
+ 
+   /* Test whether we will need extended length mode.  (1900 is an
+@@ -3597,17 +3595,13 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+ 
+   log_info (_("please wait while key is being generated ...\n"));
+   start_at = time (NULL);
+-  rc = iso7816_generate_keypair
+-/* # warning key generation temporary replaced by reading an existing key. */
+-/*   rc = iso7816_read_public_key */
+-    (app->slot, exmode,
+-     (const unsigned char*)(keyno == 0? "\xB6" :
+-                            keyno == 1? "\xB8" : "\xA4"), 2,
+-     le_value,
+-     &buffer, &buflen);
+-  if (rc)
++  err = iso7816_generate_keypair (app->slot, exmode,
++                                  (keyno == 0? "\xB6" :
++                                   keyno == 1? "\xB8" : "\xA4"),
++                                  2, le_value, &buffer, &buflen);
++  if (err)
+     {
+-      rc = gpg_error (GPG_ERR_CARD);
++      err = gpg_error (GPG_ERR_CARD);
+       log_error (_("generating key failed\n"));
+       goto leave;
+     }
+@@ -3622,7 +3616,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
+   if (!keydata)
+     {
+-      rc = gpg_error (GPG_ERR_CARD);
++      err = gpg_error (GPG_ERR_CARD);
+       log_error (_("response does not contain the public key data\n"));
+       goto leave;
+     }
+@@ -3630,7 +3624,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
+   if (!m)
+     {
+-      rc = gpg_error (GPG_ERR_CARD);
++      err = gpg_error (GPG_ERR_CARD);
+       log_error (_("response does not contain the RSA modulus\n"));
+       goto leave;
+     }
+@@ -3640,15 +3634,15 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   e = find_tlv (keydata, keydatalen, 0x0082, &elen);
+   if (!e)
+     {
+-      rc = gpg_error (GPG_ERR_CARD);
++      err = gpg_error (GPG_ERR_CARD);
+       log_error (_("response does not contain the RSA public exponent\n"));
+       goto leave;
+     }
+   /* log_printhex ("RSA e:", e, elen); */
+   send_key_data (ctrl, "e", e, elen);
+ 
+-  created_at = createtime? createtime : gnupg_get_time ();
+-  sprintf (numbuf, "%lu", (unsigned long)created_at);
++  created_at = (u32)(createtime? createtime : gnupg_get_time ());
++  sprintf (numbuf, "%u", created_at);
+   send_status_info (ctrl, "KEY-CREATED-AT",
+                     numbuf, (size_t)strlen(numbuf), NULL, 0);
+ 
+@@ -3657,16 +3651,16 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   for (; elen && !*e; elen--, e++) /* strip leading zeroes */
+     ;
+ 
+-  rc = store_fpr (app, keyno, (u32)created_at, fprbuf, PUBKEY_ALGO_RSA,
+-                  m, mlen, e, elen);
+-  if (rc)
++  err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
++                   m, mlen, e, elen);
++  if (err)
+     goto leave;
+   send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
+ 
+ 
+  leave:
+   xfree (buffer);
+-  return rc;
++  return err;
+ }
+ 
+ 
+diff --git a/scd/iso7816.c b/scd/iso7816.c
+index 515e21f..28cd2eb 100644
+--- a/scd/iso7816.c
++++ b/scd/iso7816.c
+@@ -604,8 +604,7 @@ iso7816_internal_authenticate (int slot, int extended_mode,
+    (e.g. 4096 bytes), a value larger 256 used that value.  */
+ static gpg_error_t
+ do_generate_keypair (int slot, int extended_mode, int read_only,
+-                     const unsigned char *data, size_t datalen,
+-                     int le,
++                     const char *data, size_t datalen, int le,
+                      unsigned char **result, size_t *resultlen)
+ {
+   int sw;
+@@ -617,7 +616,7 @@ do_generate_keypair (int slot, int extended_mode, int read_only,
+ 
+   sw = apdu_send_le (slot, extended_mode,
+                      0x00, CMD_GENERATE_KEYPAIR, read_only? 0x81:0x80, 0,
+-                     datalen, (const char*)data,
++                     datalen, data,
+                      le >= 0 && le < 256? 256:le,
+                      result, resultlen);
+   if (sw != SW_SUCCESS)
+@@ -635,7 +634,7 @@ do_generate_keypair (int slot, int extended_mode, int read_only,
+ 
+ gpg_error_t
+ iso7816_generate_keypair (int slot, int extended_mode,
+-                          const unsigned char *data, size_t datalen,
++                          const char *data, size_t datalen,
+                           int le,
+                           unsigned char **result, size_t *resultlen)
+ {
+@@ -646,7 +645,7 @@ iso7816_generate_keypair (int slot, int extended_mode,
+ 
+ gpg_error_t
+ iso7816_read_public_key (int slot, int extended_mode,
+-                         const unsigned char *data, size_t datalen,
++                         const char *data, size_t datalen,
+                          int le,
+                          unsigned char **result, size_t *resultlen)
+ {
+diff --git a/scd/iso7816.h b/scd/iso7816.h
+index 6dd1052..45cd416 100644
+--- a/scd/iso7816.h
++++ b/scd/iso7816.h
+@@ -100,11 +100,11 @@ gpg_error_t iso7816_internal_authenticate (int slot, int extended_mode,
+                                    int le,
+                                    unsigned char **result, size_t *resultlen);
+ gpg_error_t iso7816_generate_keypair (int slot, int extended_mode,
+-                                    const unsigned char *data, size_t datalen,
++                                    const char *data, size_t datalen,
+                                     int le,
+                                     unsigned char **result, size_t *resultlen);
+ gpg_error_t iso7816_read_public_key (int slot, int extended_mode,
+-                                    const unsigned char *data, size_t datalen,
++                                    const char *data, size_t datalen,
+                                     int le,
+                                     unsigned char **result, size_t *resultlen);
+ gpg_error_t iso7816_get_challenge (int slot,
diff --git a/debian/patches/0073-scd-Support-ECC-key-generation.patch b/debian/patches/0073-scd-Support-ECC-key-generation.patch
new file mode 100644
index 0000000..d65f47f
--- /dev/null
+++ b/debian/patches/0073-scd-Support-ECC-key-generation.patch
@@ -0,0 +1,309 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Tue, 18 Oct 2016 22:46:37 +0900
+Subject: scd: Support ECC key generation.
+
+* scd/app-openpgp.c (get_public_key): Fix a message.
+(change_keyattr_from_string, ecc_writekey): Call mpi_release sooner.
+(do_genkey): Add ECC support.
+
+--
+
+In OpenPGP card specification 3.0, ECC is introduced.  So far, do_genkey
+only supported RSA.  Since KDF spec. is needed to calculate the
+fingerprint, it is hard coded in app-openpgp.c.  But it's defined by
+OpenPGP ECC (RFC-6637), and card does nothing with KDF in fact.
+
+Co-authored-by: Arnaud Fontaine <arnaud.fontaine at ssi.gouv.fr>
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ scd/app-openpgp.c | 198 +++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 137 insertions(+), 61 deletions(-)
+
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index ba16255..09e4800 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -1318,7 +1318,7 @@ get_public_key (app_t app, int keyno)
+           if (!m)
+             {
+               err = gpg_error (GPG_ERR_CARD);
+-              log_error (_("response does not contain the EC public point\n"));
++              log_error (_("response does not contain the EC public key\n"));
+               goto leave;
+             }
+         }
+@@ -2847,6 +2847,7 @@ change_keyattr_from_string (app_t app,
+       size_t oid_len;
+ 
+       oidstr = openpgp_curve_to_oid (string+n, NULL);
++      gcry_mpi_release (oid);
+       if (!oidstr)
+         {
+           err = gpg_error (GPG_ERR_INV_DATA);
+@@ -2864,7 +2865,6 @@ change_keyattr_from_string (app_t app,
+       string[0] = algo;
+       memcpy (string+1, oidbuf+1, oid_len-1);
+       err = change_keyattr (app, keyno, string, oid_len, pincb, pincb_arg);
+-      gcry_mpi_release (oid);
+     }
+   else
+     err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+@@ -3355,13 +3355,14 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+   if (err)
+     goto leave;
+   oidbuf = gcry_mpi_get_opaque (oid, &n);
+-  oid_len = (n+7)/8;
+   if (!oidbuf)
+     {
+       err = gpg_error_from_syserror ();
+       gcry_mpi_release (oid);
+       goto leave;
+     }
++  gcry_mpi_release (oid);
++  oid_len = (n+7)/8;
+ 
+   if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
+       || app->app_local->keyattr[keyno].ecc.oid != oidstr
+@@ -3442,8 +3443,6 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+                    ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
+ 
+  leave:
+-  if (oidbuf)
+-    gcry_mpi_release (oid);
+   return err;
+ }
+ 
+@@ -3535,16 +3534,15 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   gpg_error_t err;
+   char numbuf[30];
+   unsigned char fprbuf[20];
+-  const unsigned char *keydata, *m, *e;
+   unsigned char *buffer = NULL;
+-  size_t buflen, keydatalen, mlen, elen;
++  const unsigned char *keydata;
++  size_t buflen, keydatalen;
+   u32 created_at;
+   int keyno = atoi (keynostr) - 1;
+   int force = (flags & 1);
+   time_t start_at;
+-  int exmode;
+-  int le_value;
+-  unsigned int keybits;
++  int exmode = 0;
++  int le_value = 256; /* Use legacy value. */
+ 
+   if (keyno < 0 || keyno > 2)
+     return gpg_error (GPG_ERR_INV_ID);
+@@ -3564,34 +3562,34 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   if (err)
+     return err;
+ 
+-  /* Because we send the key parameter back via status lines we need
+-     to put a limit on the max. allowed keysize.  2048 bit will
+-     already lead to a 527 byte long status line and thus a 4096 bit
+-     key would exceed the Assuan line length limit.  */
+-  keybits = app->app_local->keyattr[keyno].rsa.n_bits;
+-  if (keybits > 4096)
+-    return gpg_error (GPG_ERR_TOO_LARGE);
++  if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
++    {
++      unsigned int keybits = app->app_local->keyattr[keyno].rsa.n_bits;
++
++      /* Because we send the key parameter back via status lines we need
++         to put a limit on the max. allowed keysize.  2048 bit will
++         already lead to a 527 byte long status line and thus a 4096 bit
++         key would exceed the Assuan line length limit.  */
++      if (keybits > 4096)
++        return gpg_error (GPG_ERR_TOO_LARGE);
++
++      /* Test whether we will need extended length mode.  (1900 is an
++         arbitrary length which for sure fits into a short apdu.)  */
++      if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
++        {
++          exmode = 1;    /* Use extended length w/o a limit.  */
++          le_value = app->app_local->extcap.max_rsp_data;
++          /* No need to check le_value because it comes from a 16 bit
++             value and thus can't create an overflow on a 32 bit
++             system.  */
++        }
++    }
+ 
+   /* Prepare for key generation by verifying the Admin PIN.  */
+   err = verify_chv3 (app, pincb, pincb_arg);
+   if (err)
+-    goto leave;
++    return err;
+ 
+-  /* Test whether we will need extended length mode.  (1900 is an
+-     arbitrary length which for sure fits into a short apdu.)  */
+-  if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
+-    {
+-      exmode = 1;    /* Use extended length w/o a limit.  */
+-      le_value = app->app_local->extcap.max_rsp_data;
+-      /* No need to check le_value because it comes from a 16 bit
+-         value and thus can't create an overflow on a 32 bit
+-         system.  */
+-    }
+-  else
+-    {
+-      exmode = 0;
+-      le_value = 256; /* Use legacy value. */
+-    }
+ 
+   log_info (_("please wait while key is being generated ...\n"));
+   start_at = time (NULL);
+@@ -3601,9 +3599,8 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+                                   2, le_value, &buffer, &buflen);
+   if (err)
+     {
+-      err = gpg_error (GPG_ERR_CARD);
+       log_error (_("generating key failed\n"));
+-      goto leave;
++      return gpg_error (GPG_ERR_CARD);
+     }
+ 
+   {
+@@ -3621,38 +3618,117 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+       goto leave;
+     }
+ 
+-  m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
+-  if (!m)
+-    {
+-      err = gpg_error (GPG_ERR_CARD);
+-      log_error (_("response does not contain the RSA modulus\n"));
+-      goto leave;
+-    }
+-  /* log_printhex ("RSA n:", m, mlen); */
+-  send_key_data (ctrl, "n", m, mlen);
+-
+-  e = find_tlv (keydata, keydatalen, 0x0082, &elen);
+-  if (!e)
+-    {
+-      err = gpg_error (GPG_ERR_CARD);
+-      log_error (_("response does not contain the RSA public exponent\n"));
+-      goto leave;
+-    }
+-  /* log_printhex ("RSA e:", e, elen); */
+-  send_key_data (ctrl, "e", e, elen);
+-
+   created_at = (u32)(createtime? createtime : gnupg_get_time ());
+   sprintf (numbuf, "%u", created_at);
+   send_status_info (ctrl, "KEY-CREATED-AT",
+                     numbuf, (size_t)strlen(numbuf), NULL, 0);
+ 
+-  for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
+-    ;
+-  for (; elen && !*e; elen--, e++) /* strip leading zeroes */
+-    ;
++  if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
++    {
++      const unsigned char *m, *e;
++      size_t mlen, elen;
++
++      m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
++      if (!m)
++        {
++          err = gpg_error (GPG_ERR_CARD);
++          log_error (_("response does not contain the RSA modulus\n"));
++          goto leave;
++        }
++      /* log_printhex ("RSA n:", m, mlen); */
++      send_key_data (ctrl, "n", m, mlen);
++
++      e = find_tlv (keydata, keydatalen, 0x0082, &elen);
++      if (!e)
++        {
++          err = gpg_error (GPG_ERR_CARD);
++          log_error (_("response does not contain the RSA public exponent\n"));
++          goto leave;
++        }
++      /* log_printhex ("RSA e:", e, elen); */
++      send_key_data (ctrl, "e", e, elen);
++
++      for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
++        ;
++      for (; elen && !*e; elen--, e++) /* strip leading zeroes */
++        ;
++
++      err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
++                       m, mlen, e, elen);
++    }
++  else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
++    {
++      const unsigned char *ecc_q;
++      size_t ecc_q_len;
++      gcry_mpi_t oid;
++      int n;
++      const unsigned char *oidbuf;
++      size_t oid_len;
++      int algo;
++
++      ecc_q = find_tlv (keydata, keydatalen, 0x0086, &ecc_q_len);
++      if (!ecc_q)
++        {
++          err = gpg_error (GPG_ERR_CARD);
++          log_error (_("response does not contain the EC public key\n"));
++          goto leave;
++        }
++
++      err = openpgp_oid_from_str (app->app_local->keyattr[keyno].ecc.oid, &oid);
++      if (err)
++        goto leave;
++
++      oidbuf = gcry_mpi_get_opaque (oid, &n);
++      if (!oidbuf)
++        {
++          err = gpg_error_from_syserror ();
++          gcry_mpi_release (oid);
++          goto leave;
++        }
++      gcry_mpi_release (oid);
++      oid_len = (n+7)/8;
++
++      if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
++        {               /* Prepend 0x40 prefix.  */
++          unsigned char *q = xtrymalloc (ecc_q_len + 1);
++
++          if (!q)
++            {
++              err = gpg_error_from_syserror ();
++              goto leave;
++            }
++          *q = 0x40;
++          memcpy (q+1, ecc_q, ecc_q_len);
++          send_key_data (ctrl, "q", q, ecc_q_len + 1);
++          xfree (q);
++        }
++      else
++        {
++          /* strip leading zeroes */
++          for (; ecc_q_len && !*ecc_q; ecc_q_len--, ecc_q++)
++            ;
++          send_key_data (ctrl, "q", ecc_q, ecc_q_len);
++        }
++
++      send_key_data (ctrl, "curve", oidbuf, oid_len);
++
++      if (keyno == 1)
++        {
++          send_key_data (ctrl, "kdf", "\x03\x01\x08\x07", (size_t)4);
++          algo = PUBKEY_ALGO_ECDH;
++        }
++      else
++        {
++          if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
++            algo = PUBKEY_ALGO_EDDSA;
++          else
++            algo = PUBKEY_ALGO_ECDSA;
++        }
++
++      err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
++                       ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
++    }
+ 
+-  err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
+-                   m, mlen, e, elen);
+   if (err)
+     goto leave;
+   send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
diff --git a/debian/patches/0074-common-w32-Make-use-of-default_errsource-in-exechelp.patch b/debian/patches/0074-common-w32-Make-use-of-default_errsource-in-exechelp.patch
new file mode 100644
index 0000000..09225a4
--- /dev/null
+++ b/debian/patches/0074-common-w32-Make-use-of-default_errsource-in-exechelp.patch
@@ -0,0 +1,101 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 18 Oct 2016 14:01:53 +0200
+Subject: common,w32: Make use of default_errsource in exechelp.
+
+* common/exechelp-posix.c (my_error_from_syserror, my_error): New.
+Use them instead of gpg_error and gpg_error_from_syserror.
+
+Fixes-commit: 96c7901ec1c79be732570811223d3ea54875abfe
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/exechelp-w32.c | 28 +++++++++++++++++++++-------
+ 1 file changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c
+index b2d2457..418eb9b 100644
+--- a/common/exechelp-w32.c
++++ b/common/exechelp-w32.c
+@@ -84,6 +84,20 @@
+ # define handle_to_pid(a) ((int)(a))
+ 
+ 
++/* Helper */
++static inline gpg_error_t
++my_error_from_syserror (void)
++{
++  return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
++}
++
++static inline gpg_error_t
++my_error (int errcode)
++{
++  return gpg_err_make (default_errsource, errcode);
++}
++
++
+ /* Return the maximum number of currently allowed open file
+    descriptors.  Only useful on POSIX systems but returns a value on
+    other systems too.  */
+@@ -219,7 +233,7 @@ build_w32_commandline (const char *pgmname, const char * const *argv,
+ 
+   buf = p = xtrymalloc (n);
+   if (!buf)
+-    return gpg_error_from_syserror ();
++    return my_error_from_syserror ();
+ 
+   p = build_w32_commandline_copy (p, pgmname);
+   for (i=0; argv[i]; i++)
+@@ -293,7 +307,7 @@ do_create_pipe (int filedes[2], int flags)
+   HANDLE fds[2];
+ 
+   filedes[0] = filedes[1] = -1;
+-  err = gpg_error (GPG_ERR_GENERAL);
++  err = my_error (GPG_ERR_GENERAL);
+   if (!create_inheritable_pipe (fds, flags))
+     {
+       filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY);
+@@ -662,7 +676,7 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
+                       ))
+     {
+       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
+-      err = gpg_error (GPG_ERR_GENERAL);
++      err = my_error (GPG_ERR_GENERAL);
+     }
+   else
+     err = 0;
+@@ -707,7 +721,7 @@ gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+ 
+   procs = xtrycalloc (count, sizeof *procs);
+   if (procs == NULL)
+-    return gpg_error_from_syserror ();
++    return my_error_from_syserror ();
+ 
+   for (i = 0; i < count; i++)
+     {
+@@ -715,7 +729,7 @@ gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+         r_exitcodes[i] = -1;
+ 
+       if (pids[i] == (pid_t)(-1))
+-        return gpg_error (GPG_ERR_INV_VALUE);
++        return my_error (GPG_ERR_INV_VALUE);
+ 
+       procs[i] = fd_to_handle (pids[i]);
+     }
+@@ -818,7 +832,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
+   (void)envp;
+ 
+   if (access (pgmname, X_OK))
+-    return gpg_error_from_syserror ();
++    return my_error_from_syserror ();
+ 
+   /* Prepare security attributes.  */
+   memset (&sec_attr, 0, sizeof sec_attr );
+@@ -856,7 +870,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
+     {
+       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
+       xfree (cmdline);
+-      return gpg_error (GPG_ERR_GENERAL);
++      return my_error (GPG_ERR_GENERAL);
+     }
+   xfree (cmdline);
+   cmdline = NULL;
diff --git a/debian/patches/0075-common-w32-Extend-gnupg_create_inbound_pipe-et-al.patch b/debian/patches/0075-common-w32-Extend-gnupg_create_inbound_pipe-et-al.patch
new file mode 100644
index 0000000..55df5d7
--- /dev/null
+++ b/debian/patches/0075-common-w32-Extend-gnupg_create_inbound_pipe-et-al.patch
@@ -0,0 +1,93 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 18 Oct 2016 13:55:12 +0200
+Subject: common,w32: Extend gnupg_create_inbound_pipe et al.
+
+* common/exechelp-w32.c (do_create_pipe): Rename, add arguments, and
+create a stream if reqested.
+(gnupg_create_inbound_pipe): Use the extended function to open the
+stream if requested.
+(gnupg_create_outbound_pipe): Likewise.
+(gnupg_create_pipe): Update call site.
+
+Fixes-commit: 5d991e333a1885adc40abd9d00c01fec4bd5d9d7
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/exechelp-w32.c | 37 +++++++++++++++++++++++++++----------
+ 1 file changed, 27 insertions(+), 10 deletions(-)
+
+diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c
+index 418eb9b..c5d6b08 100644
+--- a/common/exechelp-w32.c
++++ b/common/exechelp-w32.c
+@@ -301,7 +301,8 @@ w32_open_null (int for_write)
+ 
+ 
+ static gpg_error_t
+-do_create_pipe (int filedes[2], int flags)
++create_pipe_and_estream (int filedes[2], int flags,
++                         estream_t *r_fp, int outbound, int nonblock)
+ {
+   gpg_error_t err = 0;
+   HANDLE fds[2];
+@@ -330,6 +331,25 @@ do_create_pipe (int filedes[2], int flags)
+             err = 0;
+         }
+     }
++
++  if (! err && r_fp)
++    {
++      if (!outbound)
++        *r_fp = es_fdopen (filedes[0], nonblock? "r,nonblock" : "r");
++      else
++        *r_fp = es_fdopen (filedes[1], nonblock? "w,nonblock" : "w");
++      if (!*r_fp)
++        {
++          err = my_error_from_syserror ();
++          log_error (_("error creating a stream for a pipe: %s\n"),
++                     gpg_strerror (err));
++          close (filedes[0]);
++          close (filedes[1]);
++          filedes[0] = filedes[1] = -1;
++          return err;
++        }
++    }
++
+   return err;
+ }
+ 
+@@ -339,10 +359,8 @@ do_create_pipe (int filedes[2], int flags)
+ gpg_error_t
+ gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+ {
+-  if (r_fp)
+-    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+-  else
+-    return do_create_pipe (filedes, INHERIT_WRITE);
++  return create_pipe_and_estream (filedes, INHERIT_WRITE,
++                                  r_fp, 0, nonblock);
+ }
+ 
+ 
+@@ -352,10 +370,8 @@ gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+ gpg_error_t
+ gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+ {
+-  if (r_fp)
+-    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+-  else
+-    return do_create_pipe (filedes, INHERIT_READ);
++  return create_pipe_and_estream (filedes, INHERIT_READ,
++                                  r_fp, 1, nonblock);
+ }
+ 
+ 
+@@ -364,7 +380,8 @@ gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+ gpg_error_t
+ gnupg_create_pipe (int filedes[2])
+ {
+-  return do_create_pipe (filedes, INHERIT_BOTH);
++  return create_pipe_and_estream (filedes, INHERIT_BOTH,
++                                  NULL, 0, 0);
+ }
+ 
+ 
diff --git a/debian/patches/0076-common-w32-Communicate-with-child-in-non-blocking-mo.patch b/debian/patches/0076-common-w32-Communicate-with-child-in-non-blocking-mo.patch
new file mode 100644
index 0000000..31dea61
--- /dev/null
+++ b/debian/patches/0076-common-w32-Communicate-with-child-in-non-blocking-mo.patch
@@ -0,0 +1,52 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 18 Oct 2016 14:04:54 +0200
+Subject: common,w32: Communicate with child in non-blocking mode.
+
+* common/exechelp-w32.c (gnupg_spawn_process): Open streams in
+non-blocking mode if requested.
+
+Fixes-commit: 83811e3f1f0c615b2b63bafdb49a35a0fc198088
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/exechelp-w32.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c
+index c5d6b08..19e4d9e 100644
+--- a/common/exechelp-w32.c
++++ b/common/exechelp-w32.c
+@@ -418,6 +418,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
+   int i;
+   es_syshd_t syshd;
+   gpg_err_source_t errsource = default_errsource;
++  int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
+ 
+   (void)except; /* Not yet used.  */
+ 
+@@ -440,7 +441,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
+ 
+       syshd.type = ES_SYSHD_HANDLE;
+       syshd.u.handle = inpipe[1];
+-      infp = es_sysopen (&syshd, "w");
++      infp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
+       if (!infp)
+         {
+           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+@@ -464,7 +465,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
+ 
+       syshd.type = ES_SYSHD_HANDLE;
+       syshd.u.handle = outpipe[0];
+-      outfp = es_sysopen (&syshd, "r");
++      outfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+       if (!outfp)
+         {
+           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+@@ -494,7 +495,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
+ 
+       syshd.type = ES_SYSHD_HANDLE;
+       syshd.u.handle = errpipe[0];
+-      errfp = es_sysopen (&syshd, "r");
++      errfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+       if (!errfp)
+         {
+           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
diff --git a/debian/patches/0077-common-Fix-copying-data-to-estreams.patch b/debian/patches/0077-common-Fix-copying-data-to-estreams.patch
new file mode 100644
index 0000000..9992ab1
--- /dev/null
+++ b/debian/patches/0077-common-Fix-copying-data-to-estreams.patch
@@ -0,0 +1,43 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 18 Oct 2016 17:57:19 +0200
+Subject: common: Fix copying data to estreams.
+
+* common/exectool.c (copy_buffer_do_copy): Correctly account for
+partially written data in the event of errors.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/exectool.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/common/exectool.c b/common/exectool.c
+index e46071c..cf54efe 100644
+--- a/common/exectool.c
++++ b/common/exectool.c
+@@ -248,7 +248,14 @@ copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
+     return 0;	/* Done copying.  */
+ 
+ 
++  nwritten = 0;
+   err = sink? es_write (sink, c->writep, c->nread, &nwritten) : 0;
++
++  assert (nwritten <= c->nread);
++  c->writep += nwritten;
++  c->nread -= nwritten;
++  assert (c->writep - c->buffer <= sizeof c->buffer);
++
+   if (err)
+     {
+       if (errno == EAGAIN)
+@@ -257,11 +264,6 @@ copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
+       return my_error_from_syserror ();
+     }
+ 
+-  assert (nwritten <= c->nread);
+-  c->writep += nwritten;
+-  c->nread -= nwritten;
+-  assert (c->writep - c->buffer <= sizeof c->buffer);
+-
+   if (sink && es_fflush (sink) && errno != EAGAIN)
+     err = my_error_from_syserror ();
+ 
diff --git a/debian/patches/0078-agent-Add-card-option-for-READKEY.patch b/debian/patches/0078-agent-Add-card-option-for-READKEY.patch
new file mode 100644
index 0000000..c860bb0
--- /dev/null
+++ b/debian/patches/0078-agent-Add-card-option-for-READKEY.patch
@@ -0,0 +1,274 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Thu, 20 Oct 2016 12:05:15 +0900
+Subject: agent: Add --card option for READKEY.
+
+* agent/findkey.c (agent_write_shadow_key): New.
+* agent/command-ssh.c (card_key_available): Use agent_write_shadow_key.
+* agent/learncard.c (agent_handle_learn): Likewise.
+* agent/command.c (cmd_readkey): Add --card option.
+--
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ agent/agent.h       |  3 +++
+ agent/command-ssh.c | 32 +------------------------
+ agent/command.c     | 69 +++++++++++++++++++++++++++++++++++++++++++----------
+ agent/findkey.c     | 36 ++++++++++++++++++++++++++++
+ agent/learncard.c   | 30 +++--------------------
+ 5 files changed, 100 insertions(+), 70 deletions(-)
+
+diff --git a/agent/agent.h b/agent/agent.h
+index fe5ffba..a3ec457 100644
+--- a/agent/agent.h
++++ b/agent/agent.h
+@@ -490,6 +490,9 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
+                                  const unsigned char *s2ksalt,
+                                  unsigned int s2kcount,
+                                  unsigned char *key, size_t keylen);
++gpg_error_t agent_write_shadow_key (const unsigned char *grip,
++                                    const char *serialno, const char *keyid,
++                                    const unsigned char *pkbuf, int force);
+ 
+ 
+ /*-- trustlist.c --*/
+diff --git a/agent/command-ssh.c b/agent/command-ssh.c
+index 83a27ed..dd74d2d 100644
+--- a/agent/command-ssh.c
++++ b/agent/command-ssh.c
+@@ -2474,39 +2474,9 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
+   if ( agent_key_available (grip) )
+     {
+       /* (Shadow)-key is not available in our key storage.  */
+-      unsigned char *shadow_info;
+-      unsigned char *tmp;
+-
+-      shadow_info = make_shadow_info (serialno, authkeyid);
+-      if (!shadow_info)
+-        {
+-          err = gpg_error_from_syserror ();
+-          xfree (pkbuf);
+-          gcry_sexp_release (s_pk);
+-          xfree (serialno);
+-          xfree (authkeyid);
+-          return err;
+-        }
+-      err = agent_shadow_key (pkbuf, shadow_info, &tmp);
+-      xfree (shadow_info);
+-      if (err)
+-        {
+-          log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err));
+-          xfree (pkbuf);
+-          gcry_sexp_release (s_pk);
+-          xfree (serialno);
+-          xfree (authkeyid);
+-          return err;
+-        }
+-      xfree (pkbuf);
+-      pkbuf = tmp;
+-      pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
+-      assert (pkbuflen);
+-
+-      err = agent_write_private_key (grip, pkbuf, pkbuflen, 0);
++      err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0);
+       if (err)
+         {
+-          log_error (_("error writing key: %s\n"), gpg_strerror (err));
+           xfree (pkbuf);
+           gcry_sexp_release (s_pk);
+           xfree (serialno);
+diff --git a/agent/command.c b/agent/command.c
+index 9522f89..12d90ed 100644
+--- a/agent/command.c
++++ b/agent/command.c
+@@ -981,8 +981,10 @@ cmd_genkey (assuan_context_t ctx, char *line)
+ 

+ static const char hlp_readkey[] =
+   "READKEY <hexstring_with_keygrip>\n"
++  "        --card <keyid>\n"
+   "\n"
+-  "Return the public key for the given keygrip.";
++  "Return the public key for the given keygrip or keyid.\n"
++  "With --card, private key file with card information will be created.";
+ static gpg_error_t
+ cmd_readkey (assuan_context_t ctx, char *line)
+ {
+@@ -990,10 +992,57 @@ cmd_readkey (assuan_context_t ctx, char *line)
+   int rc;
+   unsigned char grip[20];
+   gcry_sexp_t s_pkey = NULL;
++  unsigned char *pkbuf = NULL;
++  size_t pkbuflen;
+ 
+   if (ctrl->restricted)
+     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ 
++  if (has_option_name (line, "--card"))
++    {
++      const char *keyid;
++      char *serialno = NULL;
++
++      keyid = skip_options (line);
++
++      rc = agent_card_getattr (ctrl, "SERIALNO", &serialno);
++      if (rc)
++        {
++          log_error (_("error getting serial number of card: %s\n"),
++                     gpg_strerror (rc));
++          goto leave;
++        }
++
++      pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
++      rc = agent_card_readkey (ctrl, keyid, &pkbuf);
++      if (rc)
++        goto leave;
++      rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)pkbuf, pkbuflen);
++      if (rc)
++        goto leave;
++
++      if (!gcry_pk_get_keygrip (s_pkey, grip))
++        {
++          rc = gcry_pk_testkey (s_pkey);
++          if (rc == 0)
++            rc = gpg_error (GPG_ERR_INTERNAL);
++
++          goto leave;
++        }
++
++      rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0);
++      if (rc)
++        goto leave;
++
++      rc = assuan_send_data (ctx, pkbuf, pkbuflen);
++
++ leave:
++      xfree (serialno);
++      xfree (pkbuf);
++      gcry_sexp_release (s_pkey);
++      return leave_cmd (ctx, rc);
++    }
++
+   rc = parse_keygrip (ctx, line, grip);
+   if (rc)
+     return rc; /* Return immediately as this is already an Assuan error code.*/
+@@ -1001,20 +1050,16 @@ cmd_readkey (assuan_context_t ctx, char *line)
+   rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
+   if (!rc)
+     {
+-      size_t len;
+-      unsigned char *buf;
+-
+-      len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
+-      assert (len);
+-      buf = xtrymalloc (len);
+-      if (!buf)
++      pkbuflen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
++      assert (pkbuflen);
++      pkbuf = xtrymalloc (pkbuflen);
++      if (!pkbuf)
+         rc = gpg_error_from_syserror ();
+       else
+         {
+-          len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, buf, len);
+-          assert (len);
+-          rc = assuan_send_data (ctx, buf, len);
+-          xfree (buf);
++          gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, pkbuf, pkbuflen);
++          rc = assuan_send_data (ctx, pkbuf, pkbuflen);
++          xfree (pkbuf);
+         }
+       gcry_sexp_release (s_pkey);
+     }
+diff --git a/agent/findkey.c b/agent/findkey.c
+index c5ab0e9..23e94f0 100644
+--- a/agent/findkey.c
++++ b/agent/findkey.c
+@@ -1492,3 +1492,39 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
+   gcry_sexp_release (s_skey);
+   return err;
+ }
++
++
++/* Write an S-expression formatted shadow key to our key storage.
++   Shadow key is created by an S-expression public key in PKBUF and
++   card's SERIALNO and the IDSTRING.  With FORCE passed as true an
++   existing key with the given GRIP will get overwritten.  */
++gpg_error_t
++agent_write_shadow_key (const unsigned char *grip,
++                        const char *serialno, const char *keyid,
++                        const unsigned char *pkbuf, int force)
++{
++  gpg_error_t err;
++  unsigned char *shadow_info;
++  unsigned char *shdkey;
++  size_t len;
++
++  shadow_info = make_shadow_info (serialno, keyid);
++  if (!shadow_info)
++    return gpg_error_from_syserror ();
++
++  err = agent_shadow_key (pkbuf, shadow_info, &shdkey);
++  xfree (shadow_info);
++  if (err)
++    {
++      log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
++      return err;
++    }
++
++  len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
++  err = agent_write_private_key (grip, shdkey, len, force);
++  xfree (shdkey);
++  if (err)
++    log_error ("error writing key: %s\n", gpg_strerror (err));
++
++  return err;
++}
+diff --git a/agent/learncard.c b/agent/learncard.c
+index e9304fb..103a821 100644
+--- a/agent/learncard.c
++++ b/agent/learncard.c
+@@ -381,8 +381,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
+ 
+   for (item = parm.info; item; item = item->next)
+     {
+-      unsigned char *pubkey, *shdkey;
+-      size_t n;
++      unsigned char *pubkey;
+ 
+       if (opt.verbose)
+         log_info ("          id: %s    (grip=%s)\n", item->id, item->hexgrip);
+@@ -410,33 +409,10 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
+           goto leave;
+         }
+ 
+-      {
+-        unsigned char *shadow_info = make_shadow_info (serialno, item->id);
+-        if (!shadow_info)
+-          {
+-            rc = gpg_error (GPG_ERR_ENOMEM);
+-            xfree (pubkey);
+-            goto leave;
+-          }
+-        rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
+-        xfree (shadow_info);
+-      }
++      rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force);
+       xfree (pubkey);
+       if (rc)
+-        {
+-          log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
+-          goto leave;
+-        }
+-      n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
+-      assert (n);
+-
+-      rc = agent_write_private_key (grip, shdkey, n, force);
+-      xfree (shdkey);
+-      if (rc)
+-        {
+-          log_error ("error writing key: %s\n", gpg_strerror (rc));
+-          goto leave;
+-        }
++        goto leave;
+ 
+       if (opt.verbose)
+         log_info ("          id: %s - shadow key created\n", item->id);
diff --git a/debian/patches/0079-g10-smartcard-keygen-change.patch b/debian/patches/0079-g10-smartcard-keygen-change.patch
new file mode 100644
index 0000000..bd028b3
--- /dev/null
+++ b/debian/patches/0079-g10-smartcard-keygen-change.patch
@@ -0,0 +1,341 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Thu, 20 Oct 2016 13:30:47 +0900
+Subject: g10: smartcard keygen change.
+
+* g10/call-agent.c (scd_genkey_cb_append_savedbytes): Remove.
+(scd_genkey_cb): Only handle KEY-CREATED-AT and PROGRESS.
+(agent_scd_genkey): Remove INFO argument.  CREATETIME is now in/out
+argument.
+(agent_readkey): Use READKEY --card instead of SCD READKEY.
+* g10/keygen.c (gen_card_key): Use READKEY --card command of the agent
+to retrieve public key information from card and let the agent make
+a file for private key with shadow info.
+--
+
+This change removes gpg's KEY-DATA handling for SCD GENKEY.  Information
+with KEY-DATA is simply not used.  Instead, it is read by READKEY --card
+command of gpg-agent.  This can consolidate public key handling in a
+single method by READKEY.
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ g10/call-agent.c | 118 ++++++-------------------------------------------------
+ g10/call-agent.h |  10 +----
+ g10/keygen.c     |  54 ++++++++++++++-----------
+ 3 files changed, 45 insertions(+), 137 deletions(-)
+
+diff --git a/g10/call-agent.c b/g10/call-agent.c
+index 0fb392c..632cabe 100644
+--- a/g10/call-agent.c
++++ b/g10/call-agent.c
+@@ -103,13 +103,6 @@ struct cache_nonce_parm_s
+ };
+ 
+ 
+-struct scd_genkey_parm_s
+-{
+-  struct agent_card_genkey_s *cgk;
+-  char *savedbytes;     /* Malloced space to save key parameter chunks.  */
+-};
+-
+-
+ static gpg_error_t learn_status_cb (void *opaque, const char *line);
+ 
+ 
+@@ -979,133 +972,50 @@ agent_scd_writekey (int keyno, const char *serialno,
+ 
+ 
+ 

+-static gpg_error_t
+-scd_genkey_cb_append_savedbytes (struct scd_genkey_parm_s *parm,
+-                                 const char *line)
+-{
+-  gpg_error_t err = 0;
+-  char *p;
+-
+-  if (!parm->savedbytes)
+-    {
+-      parm->savedbytes = xtrystrdup (line);
+-      if (!parm->savedbytes)
+-        err = gpg_error_from_syserror ();
+-    }
+-  else
+-    {
+-      p = xtrymalloc (strlen (parm->savedbytes) + strlen (line) + 1);
+-      if (!p)
+-        err = gpg_error_from_syserror ();
+-      else
+-        {
+-          strcpy (stpcpy (p, parm->savedbytes), line);
+-          xfree (parm->savedbytes);
+-          parm->savedbytes = p;
+-        }
+-    }
+-
+-  return err;
+-}
+-
+ /* Status callback for the SCD GENKEY command. */
+ static gpg_error_t
+ scd_genkey_cb (void *opaque, const char *line)
+ {
+-  struct scd_genkey_parm_s *parm = opaque;
++  u32 *createtime = opaque;
+   const char *keyword = line;
+   int keywordlen;
+-  gpg_error_t rc = 0;
+ 
+   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+     ;
+   while (spacep (line))
+     line++;
+ 
+-  if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
+-    {
+-      parm->cgk->fprvalid = unhexify_fpr (line, parm->cgk->fpr);
+-    }
+-  else if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
+-    {
+-      gcry_mpi_t a;
+-      const char *name = line;
+-
+-      while (*line && !spacep (line))
+-        line++;
+-      while (spacep (line))
+-        line++;
+-
+-      if (*name == '-' && spacep (name+1))
+-        rc = scd_genkey_cb_append_savedbytes (parm, line);
+-      else
+-        {
+-          if (parm->savedbytes)
+-            {
+-              rc = scd_genkey_cb_append_savedbytes (parm, line);
+-              if (!rc)
+-                rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX,
+-                                    parm->savedbytes, 0, NULL);
+-            }
+-          else
+-            rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
+-          if (rc)
+-            log_error ("error parsing received key data: %s\n",
+-                       gpg_strerror (rc));
+-          else if (*name == 'n' && spacep (name+1))
+-            parm->cgk->n = a;
+-          else if (*name == 'e' && spacep (name+1))
+-            parm->cgk->e = a;
+-          else
+-            {
+-              log_info ("unknown parameter name in received key data\n");
+-              gcry_mpi_release (a);
+-              rc = gpg_error (GPG_ERR_INV_PARAMETER);
+-            }
+-
+-          xfree (parm->savedbytes);
+-          parm->savedbytes = NULL;
+-        }
+-    }
+-  else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
++ if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
+     {
+-      parm->cgk->created_at = (u32)strtoul (line, NULL, 10);
++      *createtime = (u32)strtoul (line, NULL, 10);
+     }
+   else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen))
+     {
+       write_status_text (STATUS_PROGRESS, line);
+     }
+ 
+-  return rc;
++  return 0;
+ }
+ 
+-/* Send a GENKEY command to the SCdaemon.  SERIALNO is not used in
+-   this implementation.  If CREATEDATE is not 0, it will be passed to
+-   SCDAEMON so that the key is created with this timestamp.  INFO will
+-   receive information about the generated key.  */
++/* Send a GENKEY command to the SCdaemon.  If CREATETIME is not 0, it
++  will be passed to SCDAEMON so that the key is created with this
++  timestamp.  On success, creation time  is stored back to CREATETIME.  */
+ int
+-agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
+-                  const char *serialno, u32 createtime)
++agent_scd_genkey (int keyno, int force, u32 *createtime)
+ {
+   int rc;
+   char line[ASSUAN_LINELENGTH];
+   gnupg_isotime_t tbuf;
+-  struct scd_genkey_parm_s parms;
+   struct default_inq_parm_s dfltparm;
+ 
+   memset (&dfltparm, 0, sizeof dfltparm);
+ 
+-  (void)serialno;
+-
+-  memset (&parms, 0, sizeof parms);
+-  parms.cgk = info;
+-
+   rc = start_agent (NULL, 1);
+   if (rc)
+     return rc;
+ 
+-  if (createtime)
+-    epoch2isotime (tbuf, createtime);
++  if (*createtime)
++    epoch2isotime (tbuf, *createtime);
+   else
+     *tbuf = 0;
+ 
+@@ -1116,12 +1026,9 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
+   line[DIM(line)-1] = 0;
+ 
+   dfltparm.ctx = agent_ctx;
+-  memset (info, 0, sizeof *info);
+   rc = assuan_transact (agent_ctx, line,
+                         NULL, NULL, default_inq_cb, &dfltparm,
+-                        scd_genkey_cb, &parms);
+-
+-  xfree (parms.savedbytes);
++                        scd_genkey_cb, createtime);
+ 
+   status_sc_op_failure (rc);
+   return rc;
+@@ -1854,7 +1761,8 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
+   if (err)
+     return err;
+ 
+-  snprintf (line, DIM(line)-1, "%sREADKEY %s", fromcard? "SCD ":"", hexkeygrip);
++  snprintf (line, DIM(line)-1, "READKEY %s%s", fromcard? "--card ":"",
++            hexkeygrip);
+ 
+   init_membuf (&data, 1024);
+   err = assuan_transact (agent_ctx, line,
+diff --git a/g10/call-agent.h b/g10/call-agent.h
+index d85a6fd..032c345 100644
+--- a/g10/call-agent.h
++++ b/g10/call-agent.h
+@@ -68,13 +68,6 @@ struct agent_card_info_s
+   unsigned int status_indicator;
+ };
+ 
+-struct agent_card_genkey_s {
+-  char fprvalid;
+-  char fpr[20];
+-  u32  created_at;
+-  gcry_mpi_t n;
+-  gcry_mpi_t e;
+-};
+ 
+ 
+ /* Release the card info structure. */
+@@ -107,8 +100,7 @@ int agent_scd_writekey (int keyno, const char *serialno,
+                         const unsigned char *keydata, size_t keydatalen);
+ 
+ /* Send a GENKEY command to the SCdaemon. */
+-int agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
+-                      const char *serialno, u32 createtime);
++int agent_scd_genkey (int keyno, int force, u32 *createtime);
+ 
+ /* Send a READKEY command to the SCdaemon. */
+ int agent_scd_readcert (const char *certidstr,
+diff --git a/g10/keygen.c b/g10/keygen.c
+index 9cf314d..90f8544 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -4870,9 +4870,14 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+ {
+ #ifdef ENABLE_CARD_SUPPORT
+   gpg_error_t err;
+-  struct agent_card_genkey_s info;
+   PACKET *pkt;
+   PKT_public_key *pk;
++  char keyid[10];
++  unsigned char *public;
++  gcry_sexp_t s_key;
++
++  snprintf (keyid, DIM(keyid)-1, "OPENPGP.%d", keyno);
++  keyid[DIM(keyid)-1] = 0;
+ 
+   if (algo != PUBKEY_ALGO_RSA)
+     return gpg_error (GPG_ERR_PUBKEY_ALGO);
+@@ -4888,7 +4893,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+     }
+ 
+   /* Note: SCD knows the serialnumber, thus there is no point in passing it.  */
+-  err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
++  err = agent_scd_genkey (keyno, 1, timestamp);
+   /*  The code below is not used because we force creation of
+    *  the a card key (3rd arg).
+    * if (gpg_err_code (rc) == GPG_ERR_EEXIST)
+@@ -4898,16 +4903,9 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+    *     tty_printf ("\n");
+    *     if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
+    *                                 _("Replace existing key? ")))
+-   *       rc = agent_scd_genkey (&info, keyno, 1);
++   *       rc = agent_scd_genkey (keyno, 1, timestamp);
+    *   }
+   */
+-  if (!err && (!info.n || !info.e))
+-    {
+-      log_error ("communication error with SCD\n");
+-      gcry_mpi_release (info.n);
+-      gcry_mpi_release (info.e);
+-      err =  gpg_error (GPG_ERR_GENERAL);
+-    }
+   if (err)
+     {
+       log_error ("key generation failed: %s\n", gpg_strerror (err));
+@@ -4916,30 +4914,40 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+       return err;
+     }
+ 
+-  /* Send the learn command so that the agent creates a shadow key for
++  /* Send the READKEY command so that the agent creates a shadow key for
+      card key.  We need to do that now so that we are able to create
+      the self-signatures. */
+-  err = agent_scd_learn (NULL, 0);
++  err = agent_readkey (NULL, 1, keyid, &public);
++  if (err)
++    return err;
++  err = gcry_sexp_sscan (&s_key, NULL, public,
++                         gcry_sexp_canon_len (public, 0, NULL, NULL));
++  xfree (public);
++  if (err)
++    return err;
++
++  if (algo == PUBKEY_ALGO_RSA)
++    err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
++  else if (algo == PUBKEY_ALGO_ECDSA
++	   || algo == PUBKEY_ALGO_EDDSA
++	   || algo == PUBKEY_ALGO_ECDH )
++    err = ecckey_from_sexp (pk->pkey, s_key, algo);
++  else
++    err = gpg_error (GPG_ERR_PUBKEY_ALGO);
++  gcry_sexp_release (s_key);
++
+   if (err)
+     {
+-      /* Oops: Card removed during generation.  */
+-      log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
+-      xfree (pkt);
+-      xfree (pk);
++      log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
++      free_public_key (pk);
+       return err;
+     }
+ 
+-  if (*timestamp != info.created_at)
+-    log_info ("NOTE: the key does not use the suggested creation date\n");
+-  *timestamp = info.created_at;
+-
+-  pk->timestamp = info.created_at;
++  pk->timestamp = *timestamp;
+   pk->version = 4;
+   if (expireval)
+     pk->expiredate = pk->timestamp + expireval;
+   pk->pubkey_algo = algo;
+-  pk->pkey[0] = info.n;
+-  pk->pkey[1] = info.e;
+ 
+   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+   pkt->pkt.public_key = pk;
diff --git a/debian/patches/0080-scd-GENKEY-updates-the-public-key-in-APP.patch b/debian/patches/0080-scd-GENKEY-updates-the-public-key-in-APP.patch
new file mode 100644
index 0000000..099c03a
--- /dev/null
+++ b/debian/patches/0080-scd-GENKEY-updates-the-public-key-in-APP.patch
@@ -0,0 +1,568 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Thu, 20 Oct 2016 16:25:47 +0900
+Subject: scd: GENKEY updates the public key in APP.
+
+* scd/app-openpgp.c (rsa_read_pubkey, ecc_read_pubkey): New.
+(read_public_key): New.
+(get_public_key, do_genkey): Use read_public_key.
+
+--
+
+With this change, since GENKEY updates the public key (pk[keyno].key) in
+APP, READKEY will be possible after the command even for the old
+card (version <= 0x0100).
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ scd/app-openpgp.c | 485 +++++++++++++++++++++++++++++-------------------------
+ 1 file changed, 257 insertions(+), 228 deletions(-)
+
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index 09e4800..843fdf0 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -1221,6 +1221,246 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
+ #endif /*GNUPG_MAJOR_VERSION > 1*/
+ 
+ 
++static gpg_error_t
++rsa_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at,  int keyno,
++                 const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp)
++{
++  gpg_error_t err;
++  const unsigned char *m, *e;
++  size_t mlen, elen;
++  unsigned char *mbuf = NULL, *ebuf = NULL;
++
++  m = find_tlv (data, datalen, 0x0081, &mlen);
++  if (!m)
++    {
++      log_error (_("response does not contain the RSA modulus\n"));
++      return gpg_error (GPG_ERR_CARD);
++    }
++
++  e = find_tlv (data, datalen, 0x0082, &elen);
++  if (!e)
++    {
++      log_error (_("response does not contain the RSA public exponent\n"));
++      return gpg_error (GPG_ERR_CARD);
++    }
++
++  if (ctrl)
++    {
++      send_key_data (ctrl, "n", m, mlen);
++      send_key_data (ctrl, "e", e, elen);
++    }
++
++  for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
++    ;
++  for (; elen && !*e; elen--, e++) /* strip leading zeroes */
++    ;
++
++  if (ctrl)
++    {
++      unsigned char fprbuf[20];
++
++      err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
++                       m, mlen, e, elen);
++      if (err)
++        return err;
++
++      send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
++    }
++
++  mbuf = xtrymalloc (mlen + 1);
++  if (!mbuf)
++    {
++      err = gpg_error_from_syserror ();
++      goto leave;
++    }
++  /* Prepend numbers with a 0 if needed.  */
++  if (mlen && (*m & 0x80))
++    {
++      *mbuf = 0;
++      memcpy (mbuf+1, m, mlen);
++      mlen++;
++    }
++  else
++    memcpy (mbuf, m, mlen);
++
++  ebuf = xtrymalloc (elen + 1);
++  if (!ebuf)
++    {
++      err = gpg_error_from_syserror ();
++      goto leave;
++    }
++  /* Prepend numbers with a 0 if needed.  */
++  if (elen && (*e & 0x80))
++    {
++      *ebuf = 0;
++      memcpy (ebuf+1, e, elen);
++      elen++;
++    }
++  else
++    memcpy (ebuf, e, elen);
++
++  err = gcry_sexp_build (r_sexp, NULL, "(public-key(rsa(n%b)(e%b)))",
++                         (int)mlen, mbuf, (int)elen, ebuf);
++ leave:
++  xfree (mbuf);
++  xfree (ebuf);
++  return err;
++}
++
++static gpg_error_t
++ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
++                 const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp)
++{
++  gpg_error_t err;
++  unsigned char *qbuf;
++  const unsigned char *ecc_q;
++  size_t ecc_q_len;
++  gcry_mpi_t oid;
++  int n;
++  const unsigned char *oidbuf;
++  size_t oid_len;
++  int algo;
++  const char *format;
++  const char *curve;
++
++  ecc_q = find_tlv (data, datalen, 0x0086, &ecc_q_len);
++  if (!ecc_q)
++    {
++      log_error (_("response does not contain the EC public key\n"));
++      return gpg_error (GPG_ERR_CARD);
++    }
++
++  err = openpgp_oid_from_str (app->app_local->keyattr[keyno].ecc.oid, &oid);
++  if (err)
++    return err;
++
++  oidbuf = gcry_mpi_get_opaque (oid, &n);
++  if (!oidbuf)
++    {
++      err = gpg_error_from_syserror ();
++      gcry_mpi_release (oid);
++      return err;
++    }
++  gcry_mpi_release (oid);
++  oid_len = (n+7)/8;
++
++  qbuf = xtrymalloc (ecc_q_len + 1);
++  if (!qbuf)
++    return gpg_error_from_syserror ();
++
++  if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
++    {               /* Prepend 0x40 prefix.  */
++      *qbuf = 0x40;
++      memcpy (qbuf+1, ecc_q, ecc_q_len);
++      ecc_q_len++;
++    }
++  else
++    memcpy (qbuf, ecc_q, ecc_q_len);
++
++  if (ctrl)
++    {
++      send_key_data (ctrl, "q", ecc_q, ecc_q_len);
++      send_key_data (ctrl, "curve", oidbuf, oid_len);
++    }
++
++  if (keyno == 1)
++    {
++      if (ctrl)
++        send_key_data (ctrl, "kdf", "\x03\x01\x08\x07", (size_t)4);
++      algo = PUBKEY_ALGO_ECDH;
++    }
++  else
++    {
++      if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
++        algo = PUBKEY_ALGO_EDDSA;
++      else
++        algo = PUBKEY_ALGO_ECDSA;
++    }
++
++  if (ctrl)
++    {
++      unsigned char fprbuf[20];
++
++      err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
++                       qbuf, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
++      if (err)
++        goto leave;
++
++      send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
++    }
++
++  if (!(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
++    format = "(public-key(ecc(curve%s)(q%b)))";
++  else if (keyno == 1)
++    format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))";
++  else
++    format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))";
++
++  curve = openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 1);
++  err = gcry_sexp_build (r_sexp, NULL, format, curve, (int)ecc_q_len, qbuf);
++ leave:
++  xfree (qbuf);
++  return err;
++}
++
++
++/* Parse tag-length-value data for public key in BUFFER of BUFLEN
++   length.  Key of KEYNO in APP is updated with an S-expression of
++   public key.  When CTRL is not NULL, fingerprint is computed with
++   CREATED_AT, and fingerprint is written to the card, and key data
++   and fingerprint are send back to the client side.
++ */
++static gpg_error_t
++read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
++                 const unsigned char *buffer, size_t buflen)
++{
++  gpg_error_t err;
++  const unsigned char *data;
++  size_t datalen;
++  gcry_sexp_t s_pkey = NULL;
++
++  data = find_tlv (buffer, buflen, 0x7F49, &datalen);
++  if (!data)
++    {
++      log_error (_("response does not contain the public key data\n"));
++      return gpg_error (GPG_ERR_CARD);
++    }
++
++  if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
++    err = rsa_read_pubkey (app, ctrl, created_at, keyno,
++                           data, datalen, &s_pkey);
++  else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
++    err = ecc_read_pubkey (app, ctrl, created_at, keyno,
++                           data, datalen, &s_pkey);
++  else
++    err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
++
++  if (!err)
++    {
++      unsigned char *keybuf;
++      size_t len;
++
++      len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
++      keybuf = xtrymalloc (len);
++      if (!data)
++        {
++          err = gpg_error_from_syserror ();
++          gcry_sexp_release (s_pkey);
++          return err;
++        }
++
++      gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len);
++      gcry_sexp_release (s_pkey);
++
++      app->app_local->pk[keyno].key = keybuf;
++      /* Decrement for trailing '\0' */
++      app->app_local->pk[keyno].keylen = len - 1;
++    }
++
++  return err;
++}
++
++
+ /* Get the public key for KEYNO and store it as an S-expresion with
+    the APP handle.  On error that field gets cleared.  If we already
+    know about the public key we will just return.  Note that this does
+@@ -1237,12 +1477,10 @@ get_public_key (app_t app, int keyno)
+ {
+   gpg_error_t err = 0;
+   unsigned char *buffer;
+-  const unsigned char *keydata, *m, *e;
+-  size_t buflen, keydatalen;
++  const unsigned char *m, *e;
++  size_t buflen;
+   size_t mlen = 0;
+   size_t elen = 0;
+-  unsigned char *mbuf = NULL;
+-  unsigned char *ebuf = NULL;
+   char *keybuf = NULL;
+   gcry_sexp_t s_pkey;
+   size_t len;
+@@ -1286,42 +1524,7 @@ get_public_key (app_t app, int keyno)
+           goto leave;
+         }
+ 
+-      keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
+-      if (!keydata)
+-        {
+-          err = gpg_error (GPG_ERR_CARD);
+-          log_error (_("response does not contain the public key data\n"));
+-          goto leave;
+-        }
+-
+-      if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
+-        {
+-          m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
+-          if (!m)
+-            {
+-              err = gpg_error (GPG_ERR_CARD);
+-              log_error (_("response does not contain the RSA modulus\n"));
+-              goto leave;
+-            }
+-
+-          e = find_tlv (keydata, keydatalen, 0x0082, &elen);
+-          if (!e)
+-            {
+-              err = gpg_error (GPG_ERR_CARD);
+-              log_error (_("response does not contain the RSA public exponent\n"));
+-              goto leave;
+-            }
+-        }
+-      else
+-        {
+-          m = find_tlv (keydata, keydatalen, 0x0086, &mlen);
+-          if (!m)
+-            {
+-              err = gpg_error (GPG_ERR_CARD);
+-              log_error (_("response does not contain the EC public key\n"));
+-              goto leave;
+-            }
+-        }
++      err = read_public_key (app, NULL, 0U, keyno, buffer, buflen);
+     }
+   else
+     {
+@@ -1375,98 +1578,35 @@ get_public_key (app_t app, int keyno)
+                      gpg_strerror (err));
+ 	  goto leave;
+ 	}
+-    }
+ 
+-  mbuf = xtrymalloc (mlen + 1);
+-  if (!mbuf)
+-    {
+-      err = gpg_error_from_syserror ();
+-      goto leave;
+-    }
++      err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))",
++                             (int)mlen, m, (int)elen, e);
++      if (err)
++        goto leave;
+ 
+-  if ((app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA
+-       || (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC
+-           && !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
+-      && mlen && (*m & 0x80))
+-    {               /* Prepend numbers with a 0 if needed for MPI.  */
+-      *mbuf = 0;
+-      memcpy (mbuf+1, m, mlen);
+-      mlen++;
+-    }
+-  else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC
+-           && (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
+-    {               /* Prepend 0x40 prefix.  */
+-      *mbuf = 0x40;
+-      memcpy (mbuf+1, m, mlen);
+-      mlen++;
+-    }
+-  else
+-    memcpy (mbuf, m, mlen);
++      len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
+ 
+-  if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
+-    {
+-      ebuf = xtrymalloc (elen + 1);
+-      if (!ebuf)
++      keybuf = xtrymalloc (len);
++      if (!keybuf)
+         {
+           err = gpg_error_from_syserror ();
++          gcry_sexp_release (s_pkey);
+           goto leave;
+         }
+-      /* Prepend numbers with a 0 if needed.  */
+-      if (elen && (*e & 0x80))
+-        {
+-          *ebuf = 0;
+-          memcpy (ebuf+1, e, elen);
+-          elen++;
+-        }
+-      else
+-        memcpy (ebuf, e, elen);
+ 
+-      err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))",
+-                             (int)mlen, mbuf, (int)elen, ebuf);
+-    }
+-  else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
+-    {
+-      char *format;
+-
+-      if (!(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
+-        format = "(public-key(ecc(curve%s)(q%b)))";
+-      else if (keyno == 1)
+-        format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))";
+-      else
+-        format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))";
+-
+-      err = gcry_sexp_build (&s_pkey, NULL, format,
+-                openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 1),
+-                             (int)mlen, mbuf);
+-    }
+-  else
+-    err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+-
+-  if (err)
+-    goto leave;
+-
+-  len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
+-
+-  keybuf = xtrymalloc (len);
+-  if (!keybuf)
+-    {
++      gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len);
+       gcry_sexp_release (s_pkey);
+-      err = gpg_error_from_syserror ();
+-      goto leave;
+-    }
+-  gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len);
+-  gcry_sexp_release (s_pkey);
+ 
+-  app->app_local->pk[keyno].key = (unsigned char*)keybuf;
+-  app->app_local->pk[keyno].keylen = len - 1; /* Decrement for trailing '\0' */
++      app->app_local->pk[keyno].key = (unsigned char*)keybuf;
++      /* Decrement for trailing '\0' */
++      app->app_local->pk[keyno].keylen = len - 1;
++    }
+ 
+  leave:
+   /* Set a flag to indicate that we tried to read the key.  */
+   app->app_local->pk[keyno].read_done = 1;
+ 
+   xfree (buffer);
+-  xfree (mbuf);
+-  xfree (ebuf);
+   return err;
+ }
+ #endif /* GNUPG_MAJOR_VERSION > 1 */
+@@ -3533,7 +3673,6 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+ {
+   gpg_error_t err;
+   char numbuf[30];
+-  unsigned char fprbuf[20];
+   unsigned char *buffer = NULL;
+   const unsigned char *keydata;
+   size_t buflen, keydatalen;
+@@ -3623,117 +3762,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
+   send_status_info (ctrl, "KEY-CREATED-AT",
+                     numbuf, (size_t)strlen(numbuf), NULL, 0);
+ 
+-  if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
+-    {
+-      const unsigned char *m, *e;
+-      size_t mlen, elen;
+-
+-      m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
+-      if (!m)
+-        {
+-          err = gpg_error (GPG_ERR_CARD);
+-          log_error (_("response does not contain the RSA modulus\n"));
+-          goto leave;
+-        }
+-      /* log_printhex ("RSA n:", m, mlen); */
+-      send_key_data (ctrl, "n", m, mlen);
+-
+-      e = find_tlv (keydata, keydatalen, 0x0082, &elen);
+-      if (!e)
+-        {
+-          err = gpg_error (GPG_ERR_CARD);
+-          log_error (_("response does not contain the RSA public exponent\n"));
+-          goto leave;
+-        }
+-      /* log_printhex ("RSA e:", e, elen); */
+-      send_key_data (ctrl, "e", e, elen);
+-
+-      for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
+-        ;
+-      for (; elen && !*e; elen--, e++) /* strip leading zeroes */
+-        ;
+-
+-      err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
+-                       m, mlen, e, elen);
+-    }
+-  else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
+-    {
+-      const unsigned char *ecc_q;
+-      size_t ecc_q_len;
+-      gcry_mpi_t oid;
+-      int n;
+-      const unsigned char *oidbuf;
+-      size_t oid_len;
+-      int algo;
+-
+-      ecc_q = find_tlv (keydata, keydatalen, 0x0086, &ecc_q_len);
+-      if (!ecc_q)
+-        {
+-          err = gpg_error (GPG_ERR_CARD);
+-          log_error (_("response does not contain the EC public key\n"));
+-          goto leave;
+-        }
+-
+-      err = openpgp_oid_from_str (app->app_local->keyattr[keyno].ecc.oid, &oid);
+-      if (err)
+-        goto leave;
+-
+-      oidbuf = gcry_mpi_get_opaque (oid, &n);
+-      if (!oidbuf)
+-        {
+-          err = gpg_error_from_syserror ();
+-          gcry_mpi_release (oid);
+-          goto leave;
+-        }
+-      gcry_mpi_release (oid);
+-      oid_len = (n+7)/8;
+-
+-      if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
+-        {               /* Prepend 0x40 prefix.  */
+-          unsigned char *q = xtrymalloc (ecc_q_len + 1);
+-
+-          if (!q)
+-            {
+-              err = gpg_error_from_syserror ();
+-              goto leave;
+-            }
+-          *q = 0x40;
+-          memcpy (q+1, ecc_q, ecc_q_len);
+-          send_key_data (ctrl, "q", q, ecc_q_len + 1);
+-          xfree (q);
+-        }
+-      else
+-        {
+-          /* strip leading zeroes */
+-          for (; ecc_q_len && !*ecc_q; ecc_q_len--, ecc_q++)
+-            ;
+-          send_key_data (ctrl, "q", ecc_q, ecc_q_len);
+-        }
+-
+-      send_key_data (ctrl, "curve", oidbuf, oid_len);
+-
+-      if (keyno == 1)
+-        {
+-          send_key_data (ctrl, "kdf", "\x03\x01\x08\x07", (size_t)4);
+-          algo = PUBKEY_ALGO_ECDH;
+-        }
+-      else
+-        {
+-          if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
+-            algo = PUBKEY_ALGO_EDDSA;
+-          else
+-            algo = PUBKEY_ALGO_ECDSA;
+-        }
+-
+-      err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
+-                       ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
+-    }
+-
+-  if (err)
+-    goto leave;
+-  send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
+-
+-
++  err = read_public_key (app, ctrl, created_at, keyno, buffer, buflen);
+  leave:
+   xfree (buffer);
+   return err;
diff --git a/debian/patches/0081-agent-g10-Fix-keygen.patch b/debian/patches/0081-agent-g10-Fix-keygen.patch
new file mode 100644
index 0000000..d72da6c
--- /dev/null
+++ b/debian/patches/0081-agent-g10-Fix-keygen.patch
@@ -0,0 +1,44 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Thu, 20 Oct 2016 20:01:46 +0900
+Subject: agent, g10: Fix keygen.
+
+* agent/command.c (cmd_readkey): Get length after card_readkey.
+* g10/keygen.c (gen_card_key): Fix off-by-one error.
+
+--
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ agent/command.c | 2 +-
+ g10/keygen.c    | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/agent/command.c b/agent/command.c
+index 12d90ed..1cab1d4 100644
+--- a/agent/command.c
++++ b/agent/command.c
+@@ -1013,10 +1013,10 @@ cmd_readkey (assuan_context_t ctx, char *line)
+           goto leave;
+         }
+ 
+-      pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
+       rc = agent_card_readkey (ctrl, keyid, &pkbuf);
+       if (rc)
+         goto leave;
++      pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
+       rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)pkbuf, pkbuflen);
+       if (rc)
+         goto leave;
+diff --git a/g10/keygen.c b/g10/keygen.c
+index 90f8544..2115b5a 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -4876,7 +4876,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+   unsigned char *public;
+   gcry_sexp_t s_key;
+ 
+-  snprintf (keyid, DIM(keyid)-1, "OPENPGP.%d", keyno);
++  snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno);
+   keyid[DIM(keyid)-1] = 0;
+ 
+   if (algo != PUBKEY_ALGO_RSA)
diff --git a/debian/patches/0082-agent-Fix-saving-with-FORCE-1.patch b/debian/patches/0082-agent-Fix-saving-with-FORCE-1.patch
new file mode 100644
index 0000000..5f39692
--- /dev/null
+++ b/debian/patches/0082-agent-Fix-saving-with-FORCE-1.patch
@@ -0,0 +1,54 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Fri, 21 Oct 2016 10:57:29 +0900
+Subject: agent: Fix saving with FORCE=1.
+
+* agent/findkey.c (agent_write_private_key): Recover from an error of
+GPG_ERR_ENOENT when FORCE=1 and it is opened with "rb+".
+
+--
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ agent/findkey.c | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/agent/findkey.c b/agent/findkey.c
+index 23e94f0..162e8c2 100644
+--- a/agent/findkey.c
++++ b/agent/findkey.c
+@@ -152,17 +152,30 @@ agent_write_private_key (const unsigned char *grip,
+   if (!fp)
+     {
+       gpg_error_t tmperr = gpg_error_from_syserror ();
+-      log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
+-      xfree (fname);
+-      return tmperr;
+-    }
+ 
+-  /* See if an existing key is in extended format.  */
+-  if (force)
++      if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
++        {
++          fp = es_fopen (fname, "wbx,mode=-rw");
++          if (!fp)
++            {
++              tmperr = gpg_error_from_syserror ();
++              goto error;
++            }
++        }
++      else
++        {
++        error:
++          log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
++          xfree (fname);
++          return tmperr;
++        }
++    }
++  else if (force)
+     {
+       gpg_error_t rc;
+       char first;
+ 
++      /* See if an existing key is in extended format.  */
+       if (es_fread (&first, 1, 1, fp) != 1)
+         {
+           rc = gpg_error_from_syserror ();
diff --git a/debian/patches/0083-Fix-use-cases-of-snprintf.patch b/debian/patches/0083-Fix-use-cases-of-snprintf.patch
new file mode 100644
index 0000000..3960058
--- /dev/null
+++ b/debian/patches/0083-Fix-use-cases-of-snprintf.patch
@@ -0,0 +1,999 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Fri, 21 Oct 2016 12:04:46 +0900
+Subject: Fix use cases of snprintf.
+
+* agent/call-pinentry.c, agent/call-scd.c, agent/command.c,
+build-aux/speedo/w32/g4wihelp.c, common/get-passphrase.c,
+dirmngr/dirmngr.c, g10/call-agent.c, g10/cpr.c, g10/keygen.c,
+g10/openfile.c, g10/passphrase.c, scd/app-openpgp.c, scd/scdaemon.c,
+sm/call-agent.c, sm/call-dirmngr.c, sm/certreqgen.c: Fix assuming C99.
+
+--
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ agent/call-pinentry.c           | 75 +++++++++++++++--------------------------
+ agent/call-scd.c                | 12 +++----
+ agent/command.c                 |  2 +-
+ build-aux/speedo/w32/g4wihelp.c |  8 ++---
+ common/get-passphrase.c         |  6 ++--
+ dirmngr/dirmngr.c               |  3 +-
+ g10/call-agent.c                | 65 ++++++++++++++---------------------
+ g10/cpr.c                       |  6 ++--
+ g10/keygen.c                    |  1 -
+ g10/openfile.c                  |  4 +--
+ g10/passphrase.c                |  4 +--
+ scd/app-openpgp.c               |  2 +-
+ scd/scdaemon.c                  |  3 +-
+ sm/call-agent.c                 | 50 ++++++++++-----------------
+ sm/call-dirmngr.c               | 11 +++---
+ sm/certreqgen.c                 |  2 +-
+ 16 files changed, 97 insertions(+), 157 deletions(-)
+
+diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
+index 0f24086..46db9e8 100644
+--- a/agent/call-pinentry.c
++++ b/agent/call-pinentry.c
+@@ -734,8 +734,7 @@ setup_qualitybar (ctrl_t ctrl)
+   /* TRANSLATORS: This string is displayed by Pinentry as the label
+      for the quality bar.  */
+   tmpstr = try_percent_escape (L_("Quality:"), "\t\r\n\f\v");
+-  snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SETQUALITYBAR %s", tmpstr? tmpstr:"");
+   xfree (tmpstr);
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc == 103 /*(Old assuan error code)*/
+@@ -763,8 +762,7 @@ setup_qualitybar (ctrl_t ctrl)
+     }
+   tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
+   xfree (tmpstr2);
+-  snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
+   xfree (tmpstr);
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc == 103 /*(Old assuan error code)*/
+@@ -887,27 +885,25 @@ agent_askpin (ctrl_t ctrl,
+   if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
+                   || cache_mode == CACHE_MODE_USER
+                   || cache_mode == CACHE_MODE_SSH))
+-    snprintf (line, DIM(line)-1, "SETKEYINFO %c/%s",
++    snprintf (line, DIM(line), "SETKEYINFO %c/%s",
+ 	      cache_mode == CACHE_MODE_USER? 'u' :
+ 	      cache_mode == CACHE_MODE_SSH? 's' : 'n',
+ 	      keyinfo);
+   else
+-    snprintf (line, DIM(line)-1, "SETKEYINFO --clear");
++    snprintf (line, DIM(line), "SETKEYINFO --clear");
+ 
+   rc = assuan_transact (entry_ctx, line,
+ 			NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
+     return unlock_pinentry (rc);
+ 
+-  snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SETDESC %s", desc_text);
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc)
+     return unlock_pinentry (rc);
+ 
+-  snprintf (line, DIM(line)-1, "SETPROMPT %s",
++  snprintf (line, DIM(line), "SETPROMPT %s",
+             prompt_text? prompt_text : is_pin? L_("PIN:") : L_("Passphrase:"));
+-  line[DIM(line)-1] = 0;
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc)
+     return unlock_pinentry (rc);
+@@ -924,8 +920,7 @@ agent_askpin (ctrl_t ctrl,
+ 
+   if (initial_errtext)
+     {
+-      snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETERROR %s", initial_errtext);
+       rc = assuan_transact (entry_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (rc)
+@@ -934,9 +929,8 @@ agent_askpin (ctrl_t ctrl,
+ 
+   if (pininfo->with_repeat)
+     {
+-      snprintf (line, DIM(line)-1, "SETREPEATERROR %s",
++      snprintf (line, DIM(line), "SETREPEATERROR %s",
+                 L_("does not match - try again"));
+-      line[DIM(line)-1] = 0;
+       rc = assuan_transact (entry_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (rc)
+@@ -956,9 +950,8 @@ agent_askpin (ctrl_t ctrl,
+           /* TRANSLATORS: The string is appended to an error message in
+              the pinentry.  The %s is the actual error message, the
+              two %d give the current and maximum number of tries. */
+-          snprintf (line, DIM(line)-1, L_("SETERROR %s (try %d of %d)"),
++          snprintf (line, DIM(line), L_("SETERROR %s (try %d of %d)"),
+                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
+-          line[DIM(line)-1] = 0;
+           rc = assuan_transact (entry_ctx, line,
+                                 NULL, NULL, NULL, NULL, NULL, NULL);
+           if (rc)
+@@ -968,8 +961,7 @@ agent_askpin (ctrl_t ctrl,
+ 
+       if (pininfo->with_repeat)
+         {
+-          snprintf (line, DIM(line)-1, "SETREPEAT %s", L_("Repeat:"));
+-          line[DIM(line)-1] = 0;
++          snprintf (line, DIM(line), "SETREPEAT %s", L_("Repeat:"));
+           rc = assuan_transact (entry_ctx, line,
+                                 NULL, NULL, NULL, NULL, NULL, NULL);
+           if (rc)
+@@ -1100,12 +1092,12 @@ agent_get_passphrase (ctrl_t ctrl,
+   if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
+                   || cache_mode == CACHE_MODE_USER
+                   || cache_mode == CACHE_MODE_SSH))
+-    snprintf (line, DIM(line)-1, "SETKEYINFO %c/%s",
++    snprintf (line, DIM(line), "SETKEYINFO %c/%s",
+ 	      cache_mode == CACHE_MODE_USER? 'u' :
+ 	      cache_mode == CACHE_MODE_SSH? 's' : 'n',
+ 	      keyinfo);
+   else
+-    snprintf (line, DIM(line)-1, "SETKEYINFO --clear");
++    snprintf (line, DIM(line), "SETKEYINFO --clear");
+ 
+   rc = assuan_transact (entry_ctx, line,
+ 			NULL, NULL, NULL, NULL, NULL, NULL);
+@@ -1114,16 +1106,14 @@ agent_get_passphrase (ctrl_t ctrl,
+ 
+ 
+   if (desc)
+-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
++    snprintf (line, DIM(line), "SETDESC %s", desc);
+   else
+-    snprintf (line, DIM(line)-1, "RESET");
+-  line[DIM(line)-1] = 0;
++    snprintf (line, DIM(line), "RESET");
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc)
+     return unlock_pinentry (rc);
+ 
+-  snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SETPROMPT %s", prompt);
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc)
+     return unlock_pinentry (rc);
+@@ -1137,8 +1127,7 @@ agent_get_passphrase (ctrl_t ctrl,
+ 
+   if (errtext)
+     {
+-      snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETERROR %s", errtext);
+       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+       if (rc)
+         return unlock_pinentry (rc);
+@@ -1205,10 +1194,9 @@ agent_get_confirmation (ctrl_t ctrl,
+     return rc;
+ 
+   if (desc)
+-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
++    snprintf (line, DIM(line), "SETDESC %s", desc);
+   else
+-    snprintf (line, DIM(line)-1, "RESET");
+-  line[DIM(line)-1] = 0;
++    snprintf (line, DIM(line), "RESET");
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   /* Most pinentries out in the wild return the old Assuan error code
+      for canceled which gets translated to an assuan Cancel error and
+@@ -1221,8 +1209,7 @@ agent_get_confirmation (ctrl_t ctrl,
+ 
+   if (ok)
+     {
+-      snprintf (line, DIM(line)-1, "SETOK %s", ok);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETOK %s", ok);
+       rc = assuan_transact (entry_ctx,
+                             line, NULL, NULL, NULL, NULL, NULL, NULL);
+       if (rc)
+@@ -1235,8 +1222,7 @@ agent_get_confirmation (ctrl_t ctrl,
+          the standard cancel.  */
+       if (with_cancel)
+         {
+-          snprintf (line, DIM(line)-1, "SETNOTOK %s", notok);
+-          line[DIM(line)-1] = 0;
++          snprintf (line, DIM(line), "SETNOTOK %s", notok);
+           rc = assuan_transact (entry_ctx,
+                                 line, NULL, NULL, NULL, NULL, NULL, NULL);
+         }
+@@ -1245,8 +1231,7 @@ agent_get_confirmation (ctrl_t ctrl,
+ 
+       if (gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
+ 	{
+-	  snprintf (line, DIM(line)-1, "SETCANCEL %s", notok);
+-	  line[DIM(line)-1] = 0;
++	  snprintf (line, DIM(line), "SETCANCEL %s", notok);
+ 	  rc = assuan_transact (entry_ctx, line,
+                                 NULL, NULL, NULL, NULL, NULL, NULL);
+ 	}
+@@ -1282,10 +1267,9 @@ agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
+     return rc;
+ 
+   if (desc)
+-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
++    snprintf (line, DIM(line), "SETDESC %s", desc);
+   else
+-    snprintf (line, DIM(line)-1, "RESET");
+-  line[DIM(line)-1] = 0;
++    snprintf (line, DIM(line), "RESET");
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   /* Most pinentries out in the wild return the old Assuan error code
+      for canceled which gets translated to an assuan Cancel error and
+@@ -1298,8 +1282,7 @@ agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
+ 
+   if (ok_btn)
+     {
+-      snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETOK %s", ok_btn);
+       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
+                             NULL, NULL, NULL);
+       if (rc)
+@@ -1354,18 +1337,16 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
+     return rc;
+ 
+   if (desc)
+-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
++    snprintf (line, DIM(line), "SETDESC %s", desc);
+   else
+-    snprintf (line, DIM(line)-1, "RESET");
+-  line[DIM(line)-1] = 0;
++    snprintf (line, DIM(line), "RESET");
+   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc)
+     return unlock_pinentry (rc);
+ 
+   if (ok_btn)
+     {
+-      snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETOK %s", ok_btn);
+       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
+       if (rc)
+         return unlock_pinentry (rc);
+@@ -1465,7 +1446,7 @@ agent_clear_passphrase (ctrl_t ctrl,
+   if (rc)
+     return rc;
+ 
+-  snprintf (line, DIM(line)-1, "CLEARPASSPHRASE %c/%s",
++  snprintf (line, DIM(line), "CLEARPASSPHRASE %c/%s",
+ 	    cache_mode == CACHE_MODE_USER? 'u' :
+ 	    cache_mode == CACHE_MODE_SSH? 's' : 'n',
+ 	    keyinfo);
+diff --git a/agent/call-scd.c b/agent/call-scd.c
+index 934ab4c..0f7d570 100644
+--- a/agent/call-scd.c
++++ b/agent/call-scd.c
+@@ -946,8 +946,7 @@ agent_card_pkdecrypt (ctrl_t ctrl,
+   inqparm.getpin_cb_arg = getpin_cb_arg;
+   inqparm.passthru = 0;
+   inqparm.any_inq_seen = 0;
+-  snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "PKDECRYPT %s", keyid);
+   rc = assuan_transact (ctrl->scd_local->ctx, line,
+                         put_membuf_cb, &data,
+                         inq_needpin, &inqparm,
+@@ -986,8 +985,7 @@ agent_card_readcert (ctrl_t ctrl,
+     return rc;
+ 
+   init_membuf (&data, 1024);
+-  snprintf (line, DIM(line)-1, "READCERT %s", id);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "READCERT %s", id);
+   rc = assuan_transact (ctrl->scd_local->ctx, line,
+                         put_membuf_cb, &data,
+                         NULL, NULL,
+@@ -1022,8 +1020,7 @@ agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf)
+     return rc;
+ 
+   init_membuf (&data, 1024);
+-  snprintf (line, DIM(line)-1, "READKEY %s", id);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "READKEY %s", id);
+   rc = assuan_transact (ctrl->scd_local->ctx, line,
+                         put_membuf_cb, &data,
+                         NULL, NULL,
+@@ -1088,8 +1085,7 @@ agent_card_writekey (ctrl_t ctrl,  int force, const char *serialno,
+   if (rc)
+     return rc;
+ 
+-  snprintf (line, DIM(line)-1, "WRITEKEY %s%s", force ? "--force " : "", id);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "WRITEKEY %s%s", force ? "--force " : "", id);
+   parms.ctx = ctrl->scd_local->ctx;
+   parms.getpin_cb = getpin_cb;
+   parms.getpin_cb_arg = getpin_cb_arg;
+diff --git a/agent/command.c b/agent/command.c
+index 1cab1d4..b17c62d 100644
+--- a/agent/command.c
++++ b/agent/command.c
+@@ -362,7 +362,7 @@ agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid)
+   if (!ctrl || !ctrl->server_local
+       || !ctrl->server_local->allow_pinentry_notify)
+     return 0;
+-  snprintf (line, DIM(line)-1, "PINENTRY_LAUNCHED %lu", pid);
++  snprintf (line, DIM(line), "PINENTRY_LAUNCHED %lu", pid);
+   return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
+ }
+ 
+diff --git a/build-aux/speedo/w32/g4wihelp.c b/build-aux/speedo/w32/g4wihelp.c
+index d2c93e7..fe903aa 100644
+--- a/build-aux/speedo/w32/g4wihelp.c
++++ b/build-aux/speedo/w32/g4wihelp.c
+@@ -70,12 +70,12 @@ dummy (HWND hwndParent, int string_size, char *variables,
+   // do your stuff here
+   {
+     char buf[1024];
+-    snprintf (buf, sizeof buf - 1, "$R0=%s\r\n$R1=%s\r\n",
++    snprintf (buf, sizeof buf, "$R0=%s\r\n$R1=%s\r\n",
+               getuservariable(INST_R0),
+               getuservariable(INST_R1));
+     MessageBox (g_hwndParent,buf,0,MB_OK);
+ 
+-    snprintf (buf, sizeof buf - 1,
++    snprintf (buf, sizeof buf,
+              "autoclose    =%d\r\n"
+              "all_user_var =%d\r\n"
+              "exec_error   =%d\r\n"
+@@ -278,7 +278,7 @@ void
+ service_error (const char *str)
+ {
+   char buf[1024];
+-  snprintf (buf, sizeof (buf) - 1, "error: %s: ec=%d\r\n", str,
++  snprintf (buf, sizeof (buf), "error: %s: ec=%d\r\n", str,
+ 	    GetLastError ());
+   MessageBox(g_hwndParent, buf, 0, MB_OK);
+ 
+@@ -575,7 +575,7 @@ service_stop (HWND hwndParent, int string_size, char *variables,
+       if (GetTickCount () - start_time > timeout)
+ 	{
+ 	  char buf[1024];
+-	  snprintf (buf, sizeof (buf) - 1,
++	  snprintf (buf, sizeof (buf),
+ 		    "time out waiting for service %s to stop\r\n",
+ 		    service_name);
+ 	  MessageBox (g_hwndParent, buf, 0, MB_OK);
+diff --git a/common/get-passphrase.c b/common/get-passphrase.c
+index 8f3137b..46a7835 100644
+--- a/common/get-passphrase.c
++++ b/common/get-passphrase.c
+@@ -181,7 +181,7 @@ gnupg_get_passphrase (const char *cache_id,
+     if (!(arg4 = percent_plus_escape (desc_msg)))
+       goto no_mem;
+ 
+-  snprintf (line, DIM(line)-1,
++  snprintf (line, DIM(line),
+             "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s",
+             check_quality? "--check ":"",
+             repeat,
+@@ -189,7 +189,6 @@ gnupg_get_passphrase (const char *cache_id,
+             arg2? arg2:"X",
+             arg3? arg3:"X",
+             arg4? arg4:"X");
+-  line[DIM(line)-1] = 0;
+   xfree (arg2);
+   xfree (arg3);
+   xfree (arg4);
+@@ -250,8 +249,7 @@ gnupg_clear_passphrase (const char *cache_id)
+   if (err)
+     return err;
+ 
+-  snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "CLEAR_PASSPHRASE %s", cache_id);
+   return assuan_transact (agent_ctx, line, NULL, NULL,
+                           default_inq_cb, NULL, NULL, NULL);
+ }
+diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
+index 2bbc0ed..ba9f96d 100644
+--- a/dirmngr/dirmngr.c
++++ b/dirmngr/dirmngr.c
+@@ -2050,9 +2050,8 @@ handle_connections (assuan_fd_t listen_fd)
+ 
+               memset (&argval, 0, sizeof argval);
+               argval.afd = fd;
+-              snprintf (threadname, sizeof threadname-1,
++              snprintf (threadname, sizeof threadname,
+                         "conn fd=%d", FD2INT(fd));
+-              threadname[sizeof threadname -1] = 0;
+ 
+               ret = npth_create (&thread, &tattr,
+                                  start_connection_thread, argval.aptr);
+diff --git a/g10/call-agent.c b/g10/call-agent.c
+index 632cabe..c1ad8dd 100644
+--- a/g10/call-agent.c
++++ b/g10/call-agent.c
+@@ -726,7 +726,7 @@ agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
+ 
+       init_membuf (&mb, 256);
+ 
+-      snprintf (line, DIM(line)-1, "SCD APDU %s", hexapdu);
++      snprintf (line, DIM(line), "SCD APDU %s", hexapdu);
+       err = assuan_transact (agent_ctx, line,
+                              put_membuf_cb, &mb, NULL, NULL, NULL, NULL);
+       if (!err)
+@@ -758,9 +758,8 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
+ 
+   memset (&parm, 0, sizeof parm);
+ 
+-  snprintf (line, DIM(line)-1, "KEYTOCARD %s%s %s OPENPGP.%d %s",
++  snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s",
+             force?"--force ": "", hexgrip, serialno, keyno, timestamp);
+-  line[DIM(line)-1] = 0;
+ 
+   rc = start_agent (NULL, 1);
+   if (rc)
+@@ -902,8 +901,7 @@ agent_scd_writecert (const char *certidstr,
+ 
+   memset (&parms, 0, sizeof parms);
+ 
+-  snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SCD WRITECERT %s", certidstr);
+   dfltparm.ctx = agent_ctx;
+   parms.dflt = &dfltparm;
+   parms.certdata = certdata;
+@@ -956,8 +954,7 @@ agent_scd_writekey (int keyno, const char *serialno,
+ 
+   memset (&parms, 0, sizeof parms);
+ 
+-  snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SCD WRITEKEY --force OPENPGP.%d", keyno);
+   dfltparm.ctx = agent_ctx;
+   parms.dflt = &dfltparm;
+   parms.keydata = keydata;
+@@ -1019,11 +1016,10 @@ agent_scd_genkey (int keyno, int force, u32 *createtime)
+   else
+     *tbuf = 0;
+ 
+-  snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d",
++  snprintf (line, DIM(line), "SCD GENKEY %s%s %s %d",
+             *tbuf? "--timestamp=":"", tbuf,
+             force? "--force":"",
+             keyno);
+-  line[DIM(line)-1] = 0;
+ 
+   dfltparm.ctx = agent_ctx;
+   rc = assuan_transact (agent_ctx, line,
+@@ -1151,8 +1147,7 @@ agent_scd_readcert (const char *certidstr,
+ 
+   init_membuf (&data, 2048);
+ 
+-  snprintf (line, DIM(line)-1, "SCD READCERT %s", certidstr);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SCD READCERT %s", certidstr);
+   rc = assuan_transact (agent_ctx, line,
+                         put_membuf_cb, &data,
+                         default_inq_cb, &dfltparm,
+@@ -1202,8 +1197,7 @@ agent_scd_change_pin (int chvno, const char *serialno)
+     return rc;
+   dfltparm.ctx = agent_ctx;
+ 
+-  snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SCD PASSWD %s %d", reset, chvno);
+   rc = assuan_transact (agent_ctx, line,
+                         NULL, NULL,
+                         default_inq_cb, &dfltparm,
+@@ -1230,8 +1224,7 @@ agent_scd_checkpin  (const char *serialno)
+     return rc;
+   dfltparm.ctx = agent_ctx;
+ 
+-  snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SCD CHECKPIN %s", serialno);
+   rc = assuan_transact (agent_ctx, line,
+                         NULL, NULL,
+                         default_inq_cb, &dfltparm,
+@@ -1301,7 +1294,7 @@ agent_get_passphrase (const char *cache_id,
+     if (!(arg4 = percent_plus_escape (desc_msg)))
+       goto no_mem;
+ 
+-  snprintf (line, DIM(line)-1,
++  snprintf (line, DIM(line),
+             "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s",
+             repeat,
+             check? " --check --qualitybar":"",
+@@ -1309,7 +1302,6 @@ agent_get_passphrase (const char *cache_id,
+             arg2? arg2:"X",
+             arg3? arg3:"X",
+             arg4? arg4:"X");
+-  line[DIM(line)-1] = 0;
+   xfree (arg1);
+   xfree (arg2);
+   xfree (arg3);
+@@ -1358,8 +1350,7 @@ agent_clear_passphrase (const char *cache_id)
+     return rc;
+   dfltparm.ctx = agent_ctx;
+ 
+-  snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "CLEAR_PASSPHRASE %s", cache_id);
+   return assuan_transact (agent_ctx, line,
+                           NULL, NULL,
+                           default_inq_cb, &dfltparm,
+@@ -1387,8 +1378,7 @@ gpg_agent_get_confirmation (const char *desc)
+   tmp = percent_plus_escape (desc);
+   if (!tmp)
+     return gpg_error_from_syserror ();
+-  snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", tmp);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "GET_CONFIRMATION %s", tmp);
+   xfree (tmp);
+ 
+   rc = assuan_transact (agent_ctx, line,
+@@ -1574,8 +1564,7 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
+   if (!hexkeygrip || strlen (hexkeygrip) != 40)
+     return gpg_error (GPG_ERR_INV_VALUE);
+ 
+-  snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
+ 
+   err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
+                          keyinfo_status_cb, &keyinfo);
+@@ -1761,7 +1750,7 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
+   if (err)
+     return err;
+ 
+-  snprintf (line, DIM(line)-1, "READKEY %s%s", fromcard? "--card ":"",
++  snprintf (line, DIM(line), "READKEY %s%s", fromcard? "--card ":"",
+             hexkeygrip);
+ 
+   init_membuf (&data, 1024);
+@@ -1826,16 +1815,14 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce,
+   if (err)
+     return err;
+ 
+-  snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SIGKEY %s", keygrip);
+   err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (err)
+     return err;
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       err = assuan_transact (agent_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (err)
+@@ -1966,8 +1953,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       err = assuan_transact (agent_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (err)
+@@ -2059,7 +2045,7 @@ agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen)
+     return err;
+   dfltparm.ctx = agent_ctx;
+ 
+-  snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
++  snprintf (line, DIM(line), "KEYWRAP_KEY %s",
+             forexport? "--export":"--import");
+ 
+   init_membuf_secure (&data, 64);
+@@ -2121,8 +2107,7 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       err = assuan_transact (agent_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (err)
+@@ -2182,14 +2167,14 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       err = assuan_transact (agent_ctx, line,
+                              NULL, NULL, NULL, NULL, NULL, NULL);
+       if (err)
+         return err;
+     }
+ 
+-  snprintf (line, DIM(line)-1, "EXPORT_KEY %s%s%s %s",
++  snprintf (line, DIM(line), "EXPORT_KEY %s%s%s %s",
+             openpgp_protected ? "--openpgp ":"",
+             cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+             cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+@@ -2241,14 +2226,14 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       err = assuan_transact (agent_ctx, line,
+                              NULL, NULL, NULL, NULL, NULL, NULL);
+       if (err)
+         return err;
+     }
+ 
+-  snprintf (line, DIM(line)-1, "DELETE_KEY%s %s",
++  snprintf (line, DIM(line), "DELETE_KEY%s %s",
+             force? " --force":"", hexkeygrip);
+   err = assuan_transact (agent_ctx, line, NULL, NULL,
+                          default_inq_cb, &dfltparm,
+@@ -2287,7 +2272,7 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify,
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       err = assuan_transact (agent_ctx, line,
+                              NULL, NULL, NULL, NULL, NULL, NULL);
+       if (err)
+@@ -2295,12 +2280,12 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify,
+     }
+ 
+   if (verify)
+-    snprintf (line, DIM(line)-1, "PASSWD %s%s --verify %s",
++    snprintf (line, DIM(line), "PASSWD %s%s --verify %s",
+               cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+               cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+               hexkeygrip);
+   else
+-    snprintf (line, DIM(line)-1, "PASSWD %s%s %s%s %s",
++    snprintf (line, DIM(line), "PASSWD %s%s %s%s %s",
+               cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+               cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+               passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
+diff --git a/g10/cpr.c b/g10/cpr.c
+index 9d8fec9..7760847 100644
+--- a/g10/cpr.c
++++ b/g10/cpr.c
+@@ -53,9 +53,9 @@ progress_cb (void *ctx, const char *what, int printchar,
+   (void)ctx;
+ 
+   if ( printchar == '\n' && !strcmp (what, "primegen") )
+-    snprintf (buf, sizeof buf -1, "%.20s X 100 100", what );
++    snprintf (buf, sizeof buf, "%.20s X 100 100", what );
+   else
+-    snprintf (buf, sizeof buf -1, "%.20s %c %d %d",
++    snprintf (buf, sizeof buf, "%.20s %c %d %d",
+               what, printchar=='\n'?'X':printchar, current, total );
+   write_status_text (STATUS_PROGRESS, buf);
+ }
+@@ -329,7 +329,7 @@ write_status_begin_signing (gcry_md_hd_t md)
+           ga = map_md_openpgp_to_gcry (i);
+           if (ga && gcry_md_is_enabled (md, ga) && buflen+10 < DIM(buf))
+             {
+-              snprintf (buf+buflen, DIM(buf) - buflen - 1,
++              snprintf (buf+buflen, DIM(buf) - buflen,
+                         "%sH%d", buflen? " ":"",i);
+               buflen += strlen (buf+buflen);
+             }
+diff --git a/g10/keygen.c b/g10/keygen.c
+index 2115b5a..5ff89f6 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -4877,7 +4877,6 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+   gcry_sexp_t s_key;
+ 
+   snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno);
+-  keyid[DIM(keyid)-1] = 0;
+ 
+   if (algo != PUBKEY_ALGO_RSA)
+     return gpg_error (GPG_ERR_PUBKEY_ALGO);
+diff --git a/g10/openfile.c b/g10/openfile.c
+index 006ff35..ad25604 100644
+--- a/g10/openfile.c
++++ b/g10/openfile.c
+@@ -148,9 +148,9 @@ ask_outfile_name( const char *name, size_t namelen )
+   n = strlen(s) + (defname?strlen (defname):0) + 10;
+   prompt = xmalloc (n);
+   if (defname)
+-    snprintf (prompt, n-1, "%s [%s]: ", s, defname );
++    snprintf (prompt, n, "%s [%s]: ", s, defname );
+   else
+-    snprintf (prompt, n-1, "%s: ", s );
++    snprintf (prompt, n, "%s: ", s );
+   tty_enable_completion(NULL);
+   fname = cpr_get ("openfile.askoutname", prompt );
+   cpr_kill_prompt ();
+diff --git a/g10/passphrase.c b/g10/passphrase.c
+index be71b68..d75d980 100644
+--- a/g10/passphrase.c
++++ b/g10/passphrase.c
+@@ -347,7 +347,7 @@ passphrase_to_dek (int cipher_algo, STRING2KEY *s2k,
+     {
+       char buf[50];
+ 
+-      snprintf (buf, sizeof buf -1, "%d %d %d",
++      snprintf (buf, sizeof buf, "%d %d %d",
+                 cipher_algo, s2k->mode, s2k->hash_algo );
+       write_status_text ( STATUS_NEED_PASSPHRASE_SYM, buf );
+     }
+@@ -447,7 +447,7 @@ emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo)
+   write_status_text (STATUS_USERID_HINT, us);
+   xfree (us);
+ 
+-  snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0",
++  snprintf (buf, sizeof buf, "%08lX%08lX %08lX%08lX %d 0",
+             (ulong)keyid[0],
+             (ulong)keyid[1],
+             (ulong)(mainkeyid? mainkeyid[0]:keyid[0]),
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index 843fdf0..0931095 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -1872,7 +1872,7 @@ verify_a_chv (app_t app,
+       prompt_buffer = xtrymalloc (promptsize);
+       if (!prompt_buffer)
+         return gpg_error_from_syserror ();
+-      snprintf (prompt_buffer, promptsize-1, PROMPTSTRING, sigcount);
++      snprintf (prompt_buffer, promptsize, PROMPTSTRING, sigcount);
+       prompt = prompt_buffer;
+ #undef PROMPTSTRING
+     }
+diff --git a/scd/scdaemon.c b/scd/scdaemon.c
+index 33a822e..0d26410 100644
+--- a/scd/scdaemon.c
++++ b/scd/scdaemon.c
+@@ -1292,8 +1292,7 @@ handle_connections (int listen_fd)
+               char threadname[50];
+ 	      npth_t thread;
+ 
+-              snprintf (threadname, sizeof threadname-1, "conn fd=%d", fd);
+-              threadname[sizeof threadname -1] = 0;
++              snprintf (threadname, sizeof threadname, "conn fd=%d", fd);
+               ctrl->thread_startup.fd = INT2FD (fd);
+               ret = npth_create (&thread, &tattr, start_connection_thread, ctrl);
+ 	      if (ret)
+diff --git a/sm/call-agent.c b/sm/call-agent.c
+index 3262650..c0a2081 100644
+--- a/sm/call-agent.c
++++ b/sm/call-agent.c
+@@ -243,16 +243,14 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
+   if (rc)
+     return rc;
+ 
+-  snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SIGKEY %s", keygrip);
+   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc)
+     return rc;
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       rc = assuan_transact (agent_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (rc)
+@@ -335,8 +333,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
+ 
+   init_membuf (&data, 1024);
+ 
+-  snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SCD PKSIGN %s %s", hashopt, keyid);
+   rc = assuan_transact (agent_ctx, line,
+                         put_membuf_cb, &data, default_inq_cb, &inq_parm,
+                         NULL, NULL);
+@@ -429,16 +426,14 @@ gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
+     return rc;
+ 
+   assert ( DIM(line) >= 50 );
+-  snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "SETKEY %s", keygrip);
+   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   if (rc)
+     return rc;
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       rc = assuan_transact (agent_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (rc)
+@@ -594,9 +589,8 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
+   if (rc)
+     return rc;
+ 
+-  snprintf (line, DIM(line)-1, "%sREADKEY %s",
++  snprintf (line, DIM(line), "%sREADKEY %s",
+             fromcard? "SCD ":"", hexkeygrip);
+-  line[DIM(line)-1] = 0;
+ 
+   init_membuf (&data, 1024);
+   rc = assuan_transact (agent_ctx, line,
+@@ -810,8 +804,7 @@ gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr,
+ 
+   if (hexfpr)
+     {
+-      snprintf (line, DIM(line)-1, "ISTRUSTED %s", hexfpr);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "ISTRUSTED %s", hexfpr);
+     }
+   else
+     {
+@@ -824,8 +817,7 @@ gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr,
+           return gpg_error (GPG_ERR_GENERAL);
+         }
+ 
+-      snprintf (line, DIM(line)-1, "ISTRUSTED %s", fpr);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "ISTRUSTED %s", fpr);
+       xfree (fpr);
+     }
+ 
+@@ -868,8 +860,7 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
+   xfree (dn);
+   if (!dnfmt)
+     return gpg_error_from_syserror ();
+-  snprintf (line, DIM(line)-1, "MARKTRUSTED %s S %s", fpr, dnfmt);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "MARKTRUSTED %s S %s", fpr, dnfmt);
+   ksba_free (dnfmt);
+   xfree (fpr);
+ 
+@@ -895,8 +886,7 @@ gpgsm_agent_havekey (ctrl_t ctrl, const char *hexkeygrip)
+   if (!hexkeygrip || strlen (hexkeygrip) != 40)
+     return gpg_error (GPG_ERR_INV_VALUE);
+ 
+-  snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "HAVEKEY %s", hexkeygrip);
+ 
+   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+   return rc;
+@@ -1045,16 +1035,14 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+-      line[DIM(line)-1] = 0;
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       rc = assuan_transact (agent_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+       if (rc)
+         return rc;
+     }
+ 
+-  snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "PASSWD %s", hexkeygrip);
+ 
+   rc = assuan_transact (agent_ctx, line, NULL, NULL,
+                         default_inq_cb, &inq_parm, NULL, NULL);
+@@ -1078,8 +1066,7 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc)
+   inq_parm.ctrl = ctrl;
+   inq_parm.ctx = agent_ctx;
+ 
+-  snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", desc);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "GET_CONFIRMATION %s", desc);
+ 
+   rc = assuan_transact (agent_ctx, line, NULL, NULL,
+                         default_inq_cb, &inq_parm, NULL, NULL);
+@@ -1150,8 +1137,7 @@ gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+   if (!hexkeygrip || strlen (hexkeygrip) != 40)
+     return gpg_error (GPG_ERR_INV_VALUE);
+ 
+-  snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip);
+-  line[DIM(line)-1] = 0;
++  snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
+ 
+   err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
+                          keyinfo_status_cb, &serialno);
+@@ -1196,7 +1182,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
+   if (desc_msg && *desc_msg && !(arg4 = percent_plus_escape (desc_msg)))
+     return gpg_error_from_syserror ();
+ 
+-  snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data%s -- X X X %s",
++  snprintf (line, DIM(line), "GET_PASSPHRASE --data%s -- X X X %s",
+             repeat? " --repeat=1 --check --qualitybar":"",
+             arg4);
+   xfree (arg4);
+@@ -1241,7 +1227,7 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
+   inq_parm.ctrl = ctrl;
+   inq_parm.ctx = agent_ctx;
+ 
+-  snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
++  snprintf (line, DIM(line), "KEYWRAP_KEY %s",
+             forexport? "--export":"--import");
+ 
+   init_membuf_secure (&data, 64);
+@@ -1335,14 +1321,14 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
+ 
+   if (desc)
+     {
+-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
++      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
+       err = assuan_transact (agent_ctx, line,
+                              NULL, NULL, NULL, NULL, NULL, NULL);
+       if (err)
+         return err;
+     }
+ 
+-  snprintf (line, DIM(line)-1, "EXPORT_KEY %s", keygrip);
++  snprintf (line, DIM(line), "EXPORT_KEY %s", keygrip);
+ 
+   init_membuf_secure (&data, 1024);
+   err = assuan_transact (agent_ctx, line,
+diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c
+index 6987121..4afc697 100644
+--- a/sm/call-dirmngr.c
++++ b/sm/call-dirmngr.c
+@@ -215,9 +215,8 @@ prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
+       char *pass = server->pass ? server->pass : "";
+       char *base = server->base ? server->base : "";
+ 
+-      snprintf (line, DIM (line) - 1, "LDAPSERVER %s:%i:%s:%s:%s",
++      snprintf (line, DIM (line), "LDAPSERVER %s:%i:%s:%s:%s",
+ 		server->host, server->port, user, pass, base);
+-      line[DIM (line) - 1] = 0;
+ 
+       assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+       /* The code below is not required becuase we don't return an error.  */
+@@ -548,10 +547,9 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl,
+                          NULL, NULL, NULL, NULL, NULL, NULL);
+       did_options = 1;
+     }
+-  snprintf (line, DIM(line)-1, "ISVALID%s %s",
++  snprintf (line, DIM(line), "ISVALID%s %s",
+             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
+             certid);
+-  line[DIM(line)-1] = 0;
+   xfree (certid);
+ 
+   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
+@@ -803,9 +801,8 @@ gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
+ 
+       return out_of_core ();
+     }
+-  snprintf (line, DIM(line)-1, "LOOKUP%s %s",
++  snprintf (line, DIM(line), "LOOKUP%s %s",
+             cache_only? " --cache-only":"", pattern);
+-  line[DIM(line)-1] = 0;
+   xfree (pattern);
+ 
+   parm.ctrl = ctrl;
+@@ -861,7 +858,7 @@ get_cached_cert (assuan_context_t ctx,
+   *r_cert = NULL;
+ 
+   bin2hex (fpr, 20, hexfpr);
+-  snprintf (line, DIM(line)-1, "LOOKUP --single --cache-only 0x%s", hexfpr);
++  snprintf (line, DIM(line), "LOOKUP --single --cache-only 0x%s", hexfpr);
+ 
+   init_membuf (&mb, 4096);
+   err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
+diff --git a/sm/certreqgen.c b/sm/certreqgen.c
+index 2c6550c..4d50270 100644
+--- a/sm/certreqgen.c
++++ b/sm/certreqgen.c
+@@ -719,7 +719,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
+   else if (!outctrl->dryrun) /* Generate new key.  */
+     {
+       sprintf (numbuf, "%u", nbits);
+-      snprintf ((char*)keyparms, DIM (keyparms)-1,
++      snprintf ((char*)keyparms, DIM (keyparms),
+                 "(6:genkey(3:rsa(5:nbits%d:%s)))",
+                 (int)strlen (numbuf), numbuf);
+       rc = gpgsm_agent_genkey (ctrl, keyparms, &public);
diff --git a/debian/patches/0084-g10-Support-ECC-for-gen_card_key.patch b/debian/patches/0084-g10-Support-ECC-for-gen_card_key.patch
new file mode 100644
index 0000000..c245c13
--- /dev/null
+++ b/debian/patches/0084-g10-Support-ECC-for-gen_card_key.patch
@@ -0,0 +1,126 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Fri, 21 Oct 2016 13:59:09 +0900
+Subject: g10: Support ECC for gen_card_key.
+
+* g10/keygen.c (gen_card_key): Remove the first argument of ALGO.
+(do_generate_keypair, generate_card_subkeypair): Follow the change.
+
+--
+ALGO is determined by the key attribute of the card.
+
+Co-authored-by: Arnaud Fontaine <arnaud.fontaine at ssi.gouv.fr>
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ g10/keygen.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/g10/keygen.c b/g10/keygen.c
+index 5ff89f6..64e0d43 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -154,8 +154,7 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+ static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+ 				 struct output_control_s *outctrl, int card );
+ static int write_keyblock (iobuf_t out, kbnode_t node);
+-static gpg_error_t gen_card_key (int algo, int keyno, int is_primary,
+-                                 kbnode_t pub_root,
++static gpg_error_t gen_card_key (int keyno, int is_primary, kbnode_t pub_root,
+                                  u32 *timestamp, u32 expireval);
+ 
+ 
+@@ -4238,8 +4237,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+                      get_parameter_passphrase (para),
+                      &cache_nonce, NULL);
+   else
+-    err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
+-                        &timestamp,
++    err = gen_card_key (1, 1, pub_root, &timestamp,
+                         get_parameter_u32 (para, pKEYEXPIRE));
+ 
+   /* Get the pointer to the generated public key packet.  */
+@@ -4277,8 +4275,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+ 
+   if (!err && card && get_parameter (para, pAUTHKEYTYPE))
+     {
+-      err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root,
+-                          &timestamp,
++      err = gen_card_key (3, 0, pub_root, &timestamp,
+                           get_parameter_u32 (para, pKEYEXPIRE));
+       if (!err)
+         err = write_keybinding (pub_root, pri_psk, NULL,
+@@ -4317,7 +4314,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+         }
+       else
+         {
+-          err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, &timestamp,
++          err = gen_card_key (2, 0, pub_root, &timestamp,
+                               get_parameter_u32 (para, pKEYEXPIRE));
+         }
+ 
+@@ -4749,7 +4746,6 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
+   gpg_error_t err = 0;
+   kbnode_t node;
+   PKT_public_key *pri_pk = NULL;
+-  int algo;
+   unsigned int use;
+   u32 expire;
+   u32 cur_time;
+@@ -4800,7 +4796,6 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
+       goto leave;
+     }
+ 
+-  algo = PUBKEY_ALGO_RSA;
+   expire = ask_expire_interval (0, NULL);
+   if (keyno == 1)
+     use = PUBKEY_USAGE_SIG;
+@@ -4817,7 +4812,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
+ 
+   /* Note, that depending on the backend, the card key generation may
+      update CUR_TIME.  */
+-  err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire);
++  err = gen_card_key (keyno, 0, pub_keyblock, &cur_time, expire);
+   /* Get the pointer to the generated public subkey packet.  */
+   if (!err)
+     {
+@@ -4865,21 +4860,29 @@ write_keyblock( IOBUF out, KBNODE node )
+ 
+ /* Note that timestamp is an in/out arg. */
+ static gpg_error_t
+-gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
++gen_card_key (int keyno, int is_primary, kbnode_t pub_root,
+               u32 *timestamp, u32 expireval)
+ {
+ #ifdef ENABLE_CARD_SUPPORT
+   gpg_error_t err;
++  struct agent_card_info_s info;
++  int algo;
+   PACKET *pkt;
+   PKT_public_key *pk;
+   char keyid[10];
+   unsigned char *public;
+   gcry_sexp_t s_key;
+ 
+-  snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno);
++  err = agent_scd_getattr ("KEY-ATTR", &info);
++  if (err)
++    {
++      log_error (_("error getting current key info: %s\n"), gpg_strerror (err));
++      return err;
++    }
+ 
+-  if (algo != PUBKEY_ALGO_RSA)
+-    return gpg_error (GPG_ERR_PUBKEY_ALGO);
++  algo = info.key_attr[keyno-1].algo;
++
++  snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno);
+ 
+   pk = xtrycalloc (1, sizeof *pk );
+   if (!pk)
+@@ -4954,7 +4957,6 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+ 
+   return 0;
+ #else
+-  (void)algo;
+   (void)keyno;
+   (void)is_primary;
+   (void)pub_root;
diff --git a/debian/patches/0085-g10-Don-t-ask-keysize-for-for-non-RSA-card.patch b/debian/patches/0085-g10-Don-t-ask-keysize-for-for-non-RSA-card.patch
new file mode 100644
index 0000000..e31b0fa
--- /dev/null
+++ b/debian/patches/0085-g10-Don-t-ask-keysize-for-for-non-RSA-card.patch
@@ -0,0 +1,108 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Fri, 21 Oct 2016 14:15:05 +0900
+Subject: g10: Don't ask keysize for for non-RSA card.
+
+* g10/card-util.c (card_status): Bug fix for keyno.
+(ask_card_rsa_keysize, do_change_rsa_keysize): Rename.
+(generate_card_keys): Only ask keysize when RSA.
+(card_generate_subkey): Likewise.
+
+--
+
+Co-authored-by: Arnaud Fontaine <arnaud.fontaine at ssi.gouv.fr>
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ g10/card-util.c | 50 ++++++++++++++++++++++++++++----------------------
+ 1 file changed, 28 insertions(+), 22 deletions(-)
+
+diff --git a/g10/card-util.c b/g10/card-util.c
+index 2cb44f9..2f3f714 100644
+--- a/g10/card-util.c
++++ b/g10/card-util.c
+@@ -476,7 +476,7 @@ card_status (estream_t fp, char *serialno, size_t serialnobuflen)
+ 
+       es_fprintf (fp, "forcepin:%d:::\n", !info.chv1_cached);
+       for (i=0; i < DIM (info.key_attr); i++)
+-        if (info.key_attr[0].algo == PUBKEY_ALGO_RSA)
++        if (info.key_attr[i].algo == PUBKEY_ALGO_RSA)
+           es_fprintf (fp, "keyattr:%d:%d:%u:\n", i+1,
+                       info.key_attr[i].algo, info.key_attr[i].nbits);
+         else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH
+@@ -1277,7 +1277,7 @@ show_keysize_warning (void)
+    select the prompt.  Returns 0 to use the default size (i.e. NBITS)
+    or the selected size.  */
+ static unsigned int
+-ask_card_keysize (int keyno, unsigned int nbits)
++ask_card_rsa_keysize (int keyno, unsigned int nbits)
+ {
+   unsigned int min_nbits = 1024;
+   unsigned int max_nbits = 4096;
+@@ -1327,7 +1327,7 @@ ask_card_keysize (int keyno, unsigned int nbits)
+ /* Change the size of key KEYNO (0..2) to NBITS and show an error
+    message if that fails.  */
+ static gpg_error_t
+-do_change_keysize (int keyno, unsigned int nbits)
++do_change_rsa_keysize (int keyno, unsigned int nbits)
+ {
+   gpg_error_t err;
+   char args[100];
+@@ -1406,15 +1406,18 @@ generate_card_keys (ctrl_t ctrl)
+ 
+       for (keyno = 0; keyno < DIM (info.key_attr); keyno++)
+         {
+-          nbits = ask_card_keysize (keyno, info.key_attr[keyno].nbits);
+-          if (nbits && do_change_keysize (keyno, nbits))
++          if (info.key_attr[keyno].algo == PUBKEY_ALGO_RSA)
+             {
+-              /* Error: Better read the default key size again.  */
+-              agent_release_card_info (&info);
+-              if (get_info_for_key_operation (&info))
+-                goto leave;
+-              /* Ask again for this key size. */
+-              keyno--;
++              nbits = ask_card_rsa_keysize (keyno, info.key_attr[keyno].nbits);
++              if (nbits && do_change_rsa_keysize (keyno, nbits))
++                {
++                  /* Error: Better read the default key size again.  */
++                  agent_release_card_info (&info);
++                  if (get_info_for_key_operation (&info))
++                    goto leave;
++                  /* Ask again for this key size. */
++                  keyno--;
++                }
+             }
+         }
+       /* Note that INFO has not be synced.  However we will only use
+@@ -1483,18 +1486,21 @@ card_generate_subkey (KBNODE pub_keyblock)
+      key size.  */
+   if (info.is_v2 && info.extcap.aac)
+     {
+-      unsigned int nbits;
+-
+-    ask_again:
+-      nbits = ask_card_keysize (keyno-1, info.key_attr[keyno-1].nbits);
+-      if (nbits && do_change_keysize (keyno-1, nbits))
++      if (info.key_attr[keyno-1].algo == PUBKEY_ALGO_RSA)
+         {
+-          /* Error: Better read the default key size again.  */
+-          agent_release_card_info (&info);
+-          err = get_info_for_key_operation (&info);
+-          if (err)
+-            goto leave;
+-          goto ask_again;
++          unsigned int nbits;
++
++        ask_again:
++          nbits = ask_card_rsa_keysize (keyno-1, info.key_attr[keyno-1].nbits);
++          if (nbits && do_change_rsa_keysize (keyno-1, nbits))
++            {
++              /* Error: Better read the default key size again.  */
++              agent_release_card_info (&info);
++              err = get_info_for_key_operation (&info);
++              if (err)
++                goto leave;
++              goto ask_again;
++            }
+         }
+       /* Note that INFO has not be synced.  However we will only use
+          the serialnumber and thus it won't harm.  */
diff --git a/debian/patches/0086-scd-Fix-segfault-changing-key-attr.patch b/debian/patches/0086-scd-Fix-segfault-changing-key-attr.patch
new file mode 100644
index 0000000..b9fb2b5
--- /dev/null
+++ b/debian/patches/0086-scd-Fix-segfault-changing-key-attr.patch
@@ -0,0 +1,33 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Fri, 21 Oct 2016 16:27:46 +0900
+Subject: scd: Fix segfault changing key attr.
+
+* asc/app-openpgp.c (change_keyattr_from_string): Release after
+allocated.
+--
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ scd/app-openpgp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index 0931095..f909c6f 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -2987,7 +2987,6 @@ change_keyattr_from_string (app_t app,
+       size_t oid_len;
+ 
+       oidstr = openpgp_curve_to_oid (string+n, NULL);
+-      gcry_mpi_release (oid);
+       if (!oidstr)
+         {
+           err = gpg_error (GPG_ERR_INV_DATA);
+@@ -3005,6 +3004,7 @@ change_keyattr_from_string (app_t app,
+       string[0] = algo;
+       memcpy (string+1, oidbuf+1, oid_len-1);
+       err = change_keyattr (app, keyno, string, oid_len, pincb, pincb_arg);
++      gcry_mpi_release (oid);
+     }
+   else
+     err = gpg_error (GPG_ERR_PUBKEY_ALGO);
diff --git a/debian/patches/0087-g10-scd-Fix-ECC-keygen.patch b/debian/patches/0087-g10-scd-Fix-ECC-keygen.patch
new file mode 100644
index 0000000..0f2ba5d
--- /dev/null
+++ b/debian/patches/0087-g10-scd-Fix-ECC-keygen.patch
@@ -0,0 +1,236 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Fri, 21 Oct 2016 21:37:04 +0900
+Subject: g10,scd: Fix ECC keygen.
+
+* g10/keygen.c (generate_keypair): For card key generation, fill
+parameters by KEY-ATTR.
+
+* scd/app-openpgp.c (ecc_read_pubkey): OID should be freed at last,
+after its reference by OIDBUF is finished.
+(ecc_writekey): Likewise.
+--
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ g10/call-agent.c  |  8 +++++---
+ g10/keygen.c      | 60 ++++++++++++++++++++++++++++++++++++++++++++++++-------
+ scd/app-openpgp.c | 23 +++++++++++----------
+ 3 files changed, 70 insertions(+), 21 deletions(-)
+
+diff --git a/g10/call-agent.c b/g10/call-agent.c
+index c1ad8dd..e7af001 100644
+--- a/g10/call-agent.c
++++ b/g10/call-agent.c
+@@ -994,9 +994,11 @@ scd_genkey_cb (void *opaque, const char *line)
+   return 0;
+ }
+ 
+-/* Send a GENKEY command to the SCdaemon.  If CREATETIME is not 0, it
+-  will be passed to SCDAEMON so that the key is created with this
+-  timestamp.  On success, creation time  is stored back to CREATETIME.  */
++/* Send a GENKEY command to the SCdaemon.  If *CREATETIME is not 0,
++  the value will be passed to SCDAEMON with --timestamp option so that
++  the key is created with this.  Otherwise, timestamp was generated by
++  SCDEAMON.  On success, creation time is stored back to
++  CREATETIME.  */
+ int
+ agent_scd_genkey (int keyno, int force, u32 *createtime)
+ {
+diff --git a/g10/keygen.c b/g10/keygen.c
+index 64e0d43..a59435d 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -3756,17 +3756,26 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
+   if (card_serialno)
+     {
+ #ifdef ENABLE_CARD_SUPPORT
++      gpg_error_t err;
++      struct agent_card_info_s info;
++
++      memset (&info, 0, sizeof (info));
++      err = agent_scd_getattr ("KEY-ATTR", &info);
++      if (err)
++        {
++          log_error (_("error getting current key info: %s\n"), gpg_strerror (err));
++          return;
++        }
++
+       r = xcalloc (1, sizeof *r + strlen (card_serialno) );
+       r->key = pSERIALNO;
+       strcpy( r->u.value, card_serialno);
+       r->next = para;
+       para = r;
+ 
+-      algo = PUBKEY_ALGO_RSA;
+-
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pKEYTYPE;
+-      sprintf( r->u.value, "%d", algo );
++      sprintf( r->u.value, "%d", info.key_attr[0].algo );
+       r->next = para;
+       para = r;
+       r = xcalloc (1, sizeof *r + 20 );
+@@ -3774,10 +3783,28 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
+       strcpy (r->u.value, "sign");
+       r->next = para;
+       para = r;
++      if (info.key_attr[0].algo == PUBKEY_ALGO_RSA)
++        {
++          r = xcalloc (1, sizeof *r + 20 );
++          r->key = pKEYLENGTH;
++          sprintf( r->u.value, "%u", info.key_attr[0].nbits);
++          r->next = para;
++          para = r;
++        }
++      else if (info.key_attr[0].algo == PUBKEY_ALGO_ECDSA
++               || info.key_attr[0].algo == PUBKEY_ALGO_EDDSA
++               || info.key_attr[0].algo == PUBKEY_ALGO_ECDH)
++        {
++          r = xcalloc (1, sizeof *r + strlen (info.key_attr[0].curve));
++          r->key = pKEYCURVE;
++          strcpy (r->u.value, info.key_attr[0].curve);
++          r->next = para;
++          para = r;
++        }
+ 
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pSUBKEYTYPE;
+-      sprintf( r->u.value, "%d", algo );
++      sprintf( r->u.value, "%d", info.key_attr[1].algo );
+       r->next = para;
+       para = r;
+       r = xcalloc (1, sizeof *r + 20 );
+@@ -3785,10 +3812,28 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
+       strcpy (r->u.value, "encrypt");
+       r->next = para;
+       para = r;
++      if (info.key_attr[1].algo == PUBKEY_ALGO_RSA)
++        {
++          r = xcalloc (1, sizeof *r + 20 );
++          r->key = pSUBKEYLENGTH;
++          sprintf( r->u.value, "%u", info.key_attr[1].nbits);
++          r->next = para;
++          para = r;
++        }
++      else if (info.key_attr[1].algo == PUBKEY_ALGO_ECDSA
++               || info.key_attr[1].algo == PUBKEY_ALGO_EDDSA
++               || info.key_attr[1].algo == PUBKEY_ALGO_ECDH)
++        {
++          r = xcalloc (1, sizeof *r + strlen (info.key_attr[1].curve));
++          r->key = pSUBKEYCURVE;
++          strcpy (r->u.value, info.key_attr[1].curve);
++          r->next = para;
++          para = r;
++        }
+ 
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pAUTHKEYTYPE;
+-      sprintf( r->u.value, "%d", algo );
++      sprintf( r->u.value, "%d", info.key_attr[2].algo );
+       r->next = para;
+       para = r;
+ 
+@@ -4873,6 +4918,7 @@ gen_card_key (int keyno, int is_primary, kbnode_t pub_root,
+   unsigned char *public;
+   gcry_sexp_t s_key;
+ 
++  memset (&info, 0, sizeof (info));
+   err = agent_scd_getattr ("KEY-ATTR", &info);
+   if (err)
+     {
+@@ -4931,8 +4977,8 @@ gen_card_key (int keyno, int is_primary, kbnode_t pub_root,
+   if (algo == PUBKEY_ALGO_RSA)
+     err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
+   else if (algo == PUBKEY_ALGO_ECDSA
+-	   || algo == PUBKEY_ALGO_EDDSA
+-	   || algo == PUBKEY_ALGO_ECDH )
++           || algo == PUBKEY_ALGO_EDDSA
++           || algo == PUBKEY_ALGO_ECDH )
+     err = ecckey_from_sexp (pk->pkey, s_key, algo);
+   else
+     err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index f909c6f..e6a7698 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -1312,10 +1312,10 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+                  const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp)
+ {
+   gpg_error_t err;
+-  unsigned char *qbuf;
++  unsigned char *qbuf = NULL;
+   const unsigned char *ecc_q;
+   size_t ecc_q_len;
+-  gcry_mpi_t oid;
++  gcry_mpi_t oid = NULL;
+   int n;
+   const unsigned char *oidbuf;
+   size_t oid_len;
+@@ -1338,15 +1338,16 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+   if (!oidbuf)
+     {
+       err = gpg_error_from_syserror ();
+-      gcry_mpi_release (oid);
+-      return err;
++      goto leave;
+     }
+-  gcry_mpi_release (oid);
+   oid_len = (n+7)/8;
+ 
+   qbuf = xtrymalloc (ecc_q_len + 1);
+   if (!qbuf)
+-    return gpg_error_from_syserror ();
++    {
++      err = gpg_error_from_syserror ();
++      goto leave;
++    }
+ 
+   if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
+     {               /* Prepend 0x40 prefix.  */
+@@ -1359,7 +1360,7 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+ 
+   if (ctrl)
+     {
+-      send_key_data (ctrl, "q", ecc_q, ecc_q_len);
++      send_key_data (ctrl, "q", qbuf, ecc_q_len);
+       send_key_data (ctrl, "curve", oidbuf, oid_len);
+     }
+ 
+@@ -1399,6 +1400,7 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+   curve = openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 1);
+   err = gcry_sexp_build (r_sexp, NULL, format, curve, (int)ecc_q_len, qbuf);
+  leave:
++  gcry_mpi_release (oid);
+   xfree (qbuf);
+   return err;
+ }
+@@ -3344,8 +3346,8 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+   const char *oidstr = NULL;
+   int flag_djb_tweak = 0;
+   int algo;
+-  gcry_mpi_t oid;
+-  const unsigned char *oidbuf = NULL;
++  gcry_mpi_t oid = NULL;
++  const unsigned char *oidbuf;
+   unsigned int n;
+   size_t oid_len;
+   unsigned char fprbuf[20];
+@@ -3498,10 +3500,8 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+   if (!oidbuf)
+     {
+       err = gpg_error_from_syserror ();
+-      gcry_mpi_release (oid);
+       goto leave;
+     }
+-  gcry_mpi_release (oid);
+   oid_len = (n+7)/8;
+ 
+   if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
+@@ -3583,6 +3583,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+                    ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
+ 
+  leave:
++  gcry_mpi_release (oid);
+   return err;
+ }
+ 
diff --git a/debian/patches/0088-g10-Write-first-keybox-record-in-binary-mode.patch b/debian/patches/0088-g10-Write-first-keybox-record-in-binary-mode.patch
new file mode 100644
index 0000000..e05cf16
--- /dev/null
+++ b/debian/patches/0088-g10-Write-first-keybox-record-in-binary-mode.patch
@@ -0,0 +1,27 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Fri, 21 Oct 2016 14:59:26 +0200
+Subject: g10: Write first keybox record in binary mode
+
+* g10/keydb.c (maybe_create_keyring_or_box): Open in binary mode.
+
+--
+This fixes keybox corruption on windows.
+
+Signed-off-by: Andre Heinecke <aheinecke at intevation.de>
+---
+ g10/keydb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/g10/keydb.c b/g10/keydb.c
+index e49e25f..b959f05 100644
+--- a/g10/keydb.c
++++ b/g10/keydb.c
+@@ -415,7 +415,7 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
+      that the detection magic will work the next time it is used.  */
+   if (is_box)
+     {
+-      FILE *fp = fopen (filename, "w");
++      FILE *fp = fopen (filename, "wb");
+       if (!fp)
+         rc = gpg_error_from_syserror ();
+       else
diff --git a/debian/patches/0089-g10-More-card-key-generation-change.patch b/debian/patches/0089-g10-More-card-key-generation-change.patch
new file mode 100644
index 0000000..09ca3c8
--- /dev/null
+++ b/debian/patches/0089-g10-More-card-key-generation-change.patch
@@ -0,0 +1,161 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Sat, 22 Oct 2016 08:45:35 +0900
+Subject: g10: More card key generation change.
+
+* g10/keygen.c (gen_card_key): Add back ALGO as the second argument.
+Don't get ALGO by KEY-ATTR by this function.  It's caller to provide
+ALGO.  Don't do that by both of caller and callee.
+(generate_keypair): Only put paramerters needed.  Use parameters
+for ALGO to call gen_card_key.
+(generate_card_subkeypair): Get ALGO and call gen_card_key with it.
+
+--
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ g10/keygen.c | 63 +++++++++++++++++++++++-------------------------------------
+ 1 file changed, 24 insertions(+), 39 deletions(-)
+
+diff --git a/g10/keygen.c b/g10/keygen.c
+index a59435d..61e070c 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -152,10 +152,11 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+                                      u32 *r_expire,
+                                      unsigned int *r_nbits, char **r_curve);
+ static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+-				 struct output_control_s *outctrl, int card );
++                                 struct output_control_s *outctrl, int card );
+ static int write_keyblock (iobuf_t out, kbnode_t node);
+-static gpg_error_t gen_card_key (int keyno, int is_primary, kbnode_t pub_root,
+-                                 u32 *timestamp, u32 expireval);
++static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
++                                 kbnode_t pub_root, u32 *timestamp,
++                                 u32 expireval);
+ 
+ 
+ static void
+@@ -255,7 +256,7 @@ keygen_add_key_expire (PKT_signature *sig, void *opaque)
+ 
+       buf[0] = (u >> 24) & 0xff;
+       buf[1] = (u >> 16) & 0xff;
+-      buf[2] = (u >>	8) & 0xff;
++      buf[2] = (u >>  8) & 0xff;
+       buf[3] = u & 0xff;
+       build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4);
+     }
+@@ -3783,24 +3784,6 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
+       strcpy (r->u.value, "sign");
+       r->next = para;
+       para = r;
+-      if (info.key_attr[0].algo == PUBKEY_ALGO_RSA)
+-        {
+-          r = xcalloc (1, sizeof *r + 20 );
+-          r->key = pKEYLENGTH;
+-          sprintf( r->u.value, "%u", info.key_attr[0].nbits);
+-          r->next = para;
+-          para = r;
+-        }
+-      else if (info.key_attr[0].algo == PUBKEY_ALGO_ECDSA
+-               || info.key_attr[0].algo == PUBKEY_ALGO_EDDSA
+-               || info.key_attr[0].algo == PUBKEY_ALGO_ECDH)
+-        {
+-          r = xcalloc (1, sizeof *r + strlen (info.key_attr[0].curve));
+-          r->key = pKEYCURVE;
+-          strcpy (r->u.value, info.key_attr[0].curve);
+-          r->next = para;
+-          para = r;
+-        }
+ 
+       r = xcalloc (1, sizeof *r + 20 );
+       r->key = pSUBKEYTYPE;
+@@ -4282,7 +4265,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+                      get_parameter_passphrase (para),
+                      &cache_nonce, NULL);
+   else
+-    err = gen_card_key (1, 1, pub_root, &timestamp,
++    err = gen_card_key (1, get_parameter_algo( para, pKEYTYPE, NULL ),
++                        1, pub_root, &timestamp,
+                         get_parameter_u32 (para, pKEYEXPIRE));
+ 
+   /* Get the pointer to the generated public key packet.  */
+@@ -4320,7 +4304,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+ 
+   if (!err && card && get_parameter (para, pAUTHKEYTYPE))
+     {
+-      err = gen_card_key (3, 0, pub_root, &timestamp,
++      err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
++                          0, pub_root, &timestamp,
+                           get_parameter_u32 (para, pKEYEXPIRE));
+       if (!err)
+         err = write_keybinding (pub_root, pri_psk, NULL,
+@@ -4359,7 +4344,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+         }
+       else
+         {
+-          err = gen_card_key (2, 0, pub_root, &timestamp,
++          err = gen_card_key (2, 0, get_parameter_algo (para, pSUBKEYTYPE, NULL),
++                              pub_root, &timestamp,
+                               get_parameter_u32 (para, pKEYEXPIRE));
+         }
+ 
+@@ -4796,9 +4782,20 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
+   u32 cur_time;
+   struct para_data_s *para = NULL;
+   PKT_public_key *sub_pk = NULL;
++  int algo;
++  struct agent_card_info_s info;
+ 
+   log_assert (keyno >= 1 && keyno <= 3);
+ 
++  memset (&info, 0, sizeof (info));
++  err = agent_scd_getattr ("KEY-ATTR", &info);
++  if (err)
++    {
++      log_error (_("error getting current key info: %s\n"), gpg_strerror (err));
++      return err;
++    }
++  algo = info.key_attr[keyno-1].algo;
++
+   para = xtrycalloc (1, sizeof *para + strlen (serialno) );
+   if (!para)
+     {
+@@ -4857,7 +4854,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
+ 
+   /* Note, that depending on the backend, the card key generation may
+      update CUR_TIME.  */
+-  err = gen_card_key (keyno, 0, pub_keyblock, &cur_time, expire);
++  err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire);
+   /* Get the pointer to the generated public subkey packet.  */
+   if (!err)
+     {
+@@ -4905,29 +4902,17 @@ write_keyblock( IOBUF out, KBNODE node )
+ 
+ /* Note that timestamp is an in/out arg. */
+ static gpg_error_t
+-gen_card_key (int keyno, int is_primary, kbnode_t pub_root,
++gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
+               u32 *timestamp, u32 expireval)
+ {
+ #ifdef ENABLE_CARD_SUPPORT
+   gpg_error_t err;
+-  struct agent_card_info_s info;
+-  int algo;
+   PACKET *pkt;
+   PKT_public_key *pk;
+   char keyid[10];
+   unsigned char *public;
+   gcry_sexp_t s_key;
+ 
+-  memset (&info, 0, sizeof (info));
+-  err = agent_scd_getattr ("KEY-ATTR", &info);
+-  if (err)
+-    {
+-      log_error (_("error getting current key info: %s\n"), gpg_strerror (err));
+-      return err;
+-    }
+-
+-  algo = info.key_attr[keyno-1].algo;
+-
+   snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno);
+ 
+   pk = xtrycalloc (1, sizeof *pk );
diff --git a/debian/patches/0090-g10-Fix-card-keygen-for-decryption.patch b/debian/patches/0090-g10-Fix-card-keygen-for-decryption.patch
new file mode 100644
index 0000000..49e11d6
--- /dev/null
+++ b/debian/patches/0090-g10-Fix-card-keygen-for-decryption.patch
@@ -0,0 +1,29 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Mon, 24 Oct 2016 07:52:40 +0900
+Subject: g10: Fix card keygen for decryption.
+
+* g10/keygen.c (do_generate_keypair): Fix arguments.
+
+--
+
+Reported-by: Grumpy
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ g10/keygen.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/g10/keygen.c b/g10/keygen.c
+index 61e070c..ed529c7 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -4344,8 +4344,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+         }
+       else
+         {
+-          err = gen_card_key (2, 0, get_parameter_algo (para, pSUBKEYTYPE, NULL),
+-                              pub_root, &timestamp,
++          err = gen_card_key (2, get_parameter_algo (para, pSUBKEYTYPE, NULL),
++                              0, pub_root, &timestamp,
+                               get_parameter_u32 (para, pKEYEXPIRE));
+         }
+ 
diff --git a/debian/patches/0091-common-Fix-openpgp_is_curve_supported.patch b/debian/patches/0091-common-Fix-openpgp_is_curve_supported.patch
new file mode 100644
index 0000000..9c087f5
--- /dev/null
+++ b/debian/patches/0091-common-Fix-openpgp_is_curve_supported.patch
@@ -0,0 +1,30 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Mon, 24 Oct 2016 11:20:14 +0900
+Subject: common: Fix openpgp_is_curve_supported.
+
+* common/openpgp-oid.c (openpgp_is_curve_supported): Support both of
+canonical name of the curve and alias.
+
+--
+Only alias (the name for print) was allowed before this change.
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ common/openpgp-oid.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
+index 7c93547..dd549e0 100644
+--- a/common/openpgp-oid.c
++++ b/common/openpgp-oid.c
+@@ -424,8 +424,8 @@ openpgp_is_curve_supported (const char *name, int *r_algo)
+     *r_algo = 0;
+   for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++)
+     {
+-      if (!strcmp (name, (oidtable[idx].alias? oidtable[idx].alias
+-                          /**/               : oidtable[idx].name))
++      if ((!strcmp (name, oidtable[idx].name)
++           || (oidtable[idx].alias && !strcmp (name, (oidtable[idx].alias))))
+           && curve_supported_p (oidtable[idx].name))
+         {
+           if (r_algo)
diff --git a/debian/patches/0092-scd-Use-canonical-curve-name-of-libgcrypt.patch b/debian/patches/0092-scd-Use-canonical-curve-name-of-libgcrypt.patch
new file mode 100644
index 0000000..edc7c42
--- /dev/null
+++ b/debian/patches/0092-scd-Use-canonical-curve-name-of-libgcrypt.patch
@@ -0,0 +1,318 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Mon, 24 Oct 2016 11:22:44 +0900
+Subject: scd: Use canonical curve name of libgcrypt.
+
+* scd/app-openpgp.c (send_key_attr): Use curve instead of OID.
+(ecdh_params): New.
+(ecc_read_pubkey): Use ecdh_params.  Use curve name.
+(ecc_writekey): Likewise.
+(ecc_curve): Rename from ecc_oid.
+(parse_algorithm_attribute): Use ecc_curve.
+* g10/call-agent.c (learn_status_cb): Use openpgp_is_curve_supported to
+intern the curve name string.
+* g10/card-util.c (card_status): Conver curve name to alias for print.
+--
+Now, sdcaemon answer for KEY-ATTR is in the canonical curve name
+instead of the alias.  Since it is used of key generation for
+card encryption key with backup, it should be canonical name.
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ g10/call-agent.c  | 10 +------
+ g10/card-util.c   | 13 +++++++-
+ scd/app-openpgp.c | 89 ++++++++++++++++++++++++++++++++++++-------------------
+ 3 files changed, 71 insertions(+), 41 deletions(-)
+
+diff --git a/g10/call-agent.c b/g10/call-agent.c
+index e7af001..b17a80f 100644
+--- a/g10/call-agent.c
++++ b/g10/call-agent.c
+@@ -624,15 +624,7 @@ learn_status_cb (void *opaque, const char *line)
+         parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10);
+       else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
+                || algo == PUBKEY_ALGO_EDDSA)
+-        {
+-          const char *curve;
+-
+-          for (i = 0; (curve = openpgp_enum_curves (&i));)
+-            if (!strcmp (curve, line+n))
+-              break;
+-
+-          parm->key_attr[keyno].curve = curve;
+-        }
++        parm->key_attr[keyno].curve = openpgp_is_curve_supported (line+n, NULL);
+     }
+   else if (keywordlen == 12 && !memcmp (keyword, "PRIVATE-DO-", 11)
+            && strchr("1234", keyword[11]))
+diff --git a/g10/card-util.c b/g10/card-util.c
+index 2f3f714..b5fe84b 100644
+--- a/g10/card-util.c
++++ b/g10/card-util.c
+@@ -568,7 +568,18 @@ card_status (estream_t fp, char *serialno, size_t serialnobuflen)
+             else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH
+                      || info.key_attr[i].algo == PUBKEY_ALGO_ECDSA
+                      || info.key_attr[i].algo == PUBKEY_ALGO_EDDSA)
+-              tty_fprintf (fp, " %s", info.key_attr[i].curve);
++              {
++                const char *curve_for_print = "?";
++
++                if (info.key_attr[i].curve)
++                  {
++                    const char *oid;
++                    oid = openpgp_curve_to_oid (info.key_attr[i].curve, NULL);
++                    if (oid)
++                      curve_for_print = openpgp_oid_to_curve (oid, 0);
++                  }
++                tty_fprintf (fp, " %s", curve_for_print);
++              }
+           tty_fprintf (fp, "\n");
+         }
+       tty_fprintf (fp,    "Max. PIN lengths .: %d %d %d\n",
+diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
+index e6a7698..4e042e7 100644
+--- a/scd/app-openpgp.c
++++ b/scd/app-openpgp.c
+@@ -228,7 +228,7 @@ struct app_local_s {
+         rsa_key_format_t format;
+       } rsa;
+       struct {
+-        const char *oid;
++        const char *curve;
+         int flags;
+       } ecc;
+     };
+@@ -913,7 +913,7 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno)
+                 keyno==1? PUBKEY_ALGO_ECDH :
+                 (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
+                 PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA,
+-                openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 0));
++                app->app_local->keyattr[keyno].ecc.curve);
+     }
+   else
+     snprintf (buffer, sizeof buffer, "%d 0 0 UNKNOWN", keyno+1);
+@@ -1307,6 +1307,29 @@ rsa_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at,  int keyno,
+   return err;
+ }
+ 
++
++/* Determine KDF hash algorithm and KEK encryption algorithm by CURVE.  */
++static const unsigned char*
++ecdh_params (const char *curve)
++{
++  unsigned int nbits;
++
++  openpgp_curve_to_oid (curve, &nbits);
++
++  /* See RFC-6637 for those constants.
++         0x03: Number of bytes
++         0x01: Version for this parameter format
++         KDF algo
++        KEK algo
++  */
++  if (nbits <= 256)
++    return (const unsigned char*)"\x03\x01\x08\x07";
++  else if (nbits <= 384)
++    return (const unsigned char*)"\x03\x01\x09\x08";
++  else
++    return (const unsigned char*)"\x03\x01\x0a\x09";
++}
++
+ static gpg_error_t
+ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+                  const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp)
+@@ -1317,11 +1340,12 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+   size_t ecc_q_len;
+   gcry_mpi_t oid = NULL;
+   int n;
++  const char *curve;
++  const char *oidstr;
+   const unsigned char *oidbuf;
+   size_t oid_len;
+   int algo;
+   const char *format;
+-  const char *curve;
+ 
+   ecc_q = find_tlv (data, datalen, 0x0086, &ecc_q_len);
+   if (!ecc_q)
+@@ -1330,10 +1354,11 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+       return gpg_error (GPG_ERR_CARD);
+     }
+ 
+-  err = openpgp_oid_from_str (app->app_local->keyattr[keyno].ecc.oid, &oid);
++  curve = app->app_local->keyattr[keyno].ecc.curve;
++  oidstr = openpgp_curve_to_oid (curve, NULL);
++  err = openpgp_oid_from_str (oidstr, &oid);
+   if (err)
+     return err;
+-
+   oidbuf = gcry_mpi_get_opaque (oid, &n);
+   if (!oidbuf)
+     {
+@@ -1367,7 +1392,7 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+   if (keyno == 1)
+     {
+       if (ctrl)
+-        send_key_data (ctrl, "kdf", "\x03\x01\x08\x07", (size_t)4);
++        send_key_data (ctrl, "kdf/kek", ecdh_params (curve), (size_t)4);
+       algo = PUBKEY_ALGO_ECDH;
+     }
+   else
+@@ -1383,7 +1408,7 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+       unsigned char fprbuf[20];
+ 
+       err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
+-                       qbuf, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
++                       qbuf, ecc_q_len, ecdh_params (curve), (size_t)4);
+       if (err)
+         goto leave;
+ 
+@@ -1397,8 +1422,9 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
+   else
+     format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))";
+ 
+-  curve = openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 1);
+-  err = gcry_sexp_build (r_sexp, NULL, format, curve, (int)ecc_q_len, qbuf);
++  err = gcry_sexp_build (r_sexp, NULL, format,
++                         app->app_local->keyattr[keyno].ecc.curve,
++                         (int)ecc_q_len, qbuf);
+  leave:
+   gcry_mpi_release (oid);
+   xfree (qbuf);
+@@ -3342,8 +3368,9 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+   const unsigned char *ecc_q = NULL;
+   const unsigned char *ecc_d = NULL;
+   size_t ecc_q_len, ecc_d_len;
++  const char *curve = NULL;
+   u32 created_at = 0;
+-  const char *oidstr = NULL;
++  const char *oidstr;
+   int flag_djb_tweak = 0;
+   int algo;
+   gcry_mpi_t oid = NULL;
+@@ -3372,22 +3399,22 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+ 
+       if (tok && toklen == 5 && !memcmp (tok, "curve", 5))
+         {
+-          unsigned char *curve;
++          char *curve_name;
+ 
+           if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+             goto leave;
+ 
+-          curve = xtrymalloc (toklen+1);
+-          if (!curve)
++          curve_name = xtrymalloc (toklen+1);
++          if (!curve_name)
+             {
+               err = gpg_error_from_syserror ();
+               goto leave;
+             }
+ 
+-          memcpy (curve, tok, toklen);
+-          curve[toklen] = 0;
+-          oidstr = openpgp_curve_to_oid (curve, NULL);
+-          xfree (curve);
++          memcpy (curve_name, tok, toklen);
++          curve_name[toklen] = 0;
++          curve = openpgp_is_curve_supported (curve_name, NULL);
++          xfree (curve_name);
+         }
+       else if (tok && toklen == 5 && !memcmp (tok, "flags", 5))
+         {
+@@ -3474,7 +3501,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+ 
+   /* Check that we have all parameters and that they match the card
+      description. */
+-  if (!oidstr)
++  if (!curve)
+     {
+       log_error (_("unsupported curve\n"));
+       err = gpg_error (GPG_ERR_INV_VALUE);
+@@ -3493,6 +3520,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+   else
+     algo = PUBKEY_ALGO_ECDSA;
+ 
++  oidstr = openpgp_curve_to_oid (curve, NULL);
+   err = openpgp_oid_from_str (oidstr, &oid);
+   if (err)
+     goto leave;
+@@ -3505,7 +3533,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+   oid_len = (n+7)/8;
+ 
+   if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
+-      || app->app_local->keyattr[keyno].ecc.oid != oidstr
++      || app->app_local->keyattr[keyno].ecc.curve != curve
+       || (flag_djb_tweak !=
+           (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
+     {
+@@ -3580,7 +3608,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
+     }
+ 
+   err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
+-                   ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
++                   ecc_q, ecc_q_len, ecdh_params (curve), (size_t)4);
+ 
+  leave:
+   gcry_mpi_release (oid);
+@@ -4578,12 +4606,11 @@ parse_historical (struct app_local_s *apploc,
+ 
+ /*
+  * Check if the OID in an DER encoding is available by GnuPG/libgcrypt,
+- * and return the constant string in dotted decimal form.
+- * Return NULL if not available.
++ * and return the curve name.  Return NULL if not available.
+  * The constant string is not allocated dynamically, never free it.
+  */
+ static const char *
+-ecc_oid (unsigned char *buf, size_t buflen)
++ecc_curve (unsigned char *buf, size_t buflen)
+ {
+   gcry_mpi_t oid;
+   char *oidstr;
+@@ -4608,7 +4635,7 @@ ecc_oid (unsigned char *buf, size_t buflen)
+   if (!oidstr)
+     return NULL;
+ 
+-  result = openpgp_curve_to_oid (oidstr, NULL);
++  result = openpgp_oid_to_curve (oidstr, 1);
+   xfree (oidstr);
+   return result;
+ }
+@@ -4671,7 +4698,7 @@ parse_algorithm_attribute (app_t app, int keyno)
+   else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA
+            || *buffer == PUBKEY_ALGO_EDDSA)
+     {
+-      const char *oid;
++      const char *curve;
+       int oidlen = buflen - 1;
+ 
+       app->app_local->keyattr[keyno].ecc.flags = 0;
+@@ -4683,22 +4710,22 @@ parse_algorithm_attribute (app_t app, int keyno)
+             app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_PUBKEY;
+         }
+ 
+-      oid = ecc_oid (buffer + 1, oidlen);
++      curve = ecc_curve (buffer + 1, oidlen);
+ 
+-      if (!oid)
++      if (!curve)
+         log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1);
+       else
+         {
+           app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC;
+-          app->app_local->keyattr[keyno].ecc.oid = oid;
++          app->app_local->keyattr[keyno].ecc.curve = curve;
+           if (*buffer == PUBKEY_ALGO_EDDSA
+               || (*buffer == PUBKEY_ALGO_ECDH
+-                  && !strcmp (app->app_local->keyattr[keyno].ecc.oid,
+-                              "1.3.6.1.4.1.3029.1.5.1")))
++                  && !strcmp (app->app_local->keyattr[keyno].ecc.curve,
++                              "Curve25519")))
+             app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_DJB_TWEAK;
+           if (opt.verbose)
+             log_printf
+-              ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid,
++              ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.curve,
+                !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
+                "": keyno==1? " (djb-tweak)": " (eddsa)");
+         }
diff --git a/debian/patches/0093-agent-Slightly-change-structure-of-cmd_readkey.patch b/debian/patches/0093-agent-Slightly-change-structure-of-cmd_readkey.patch
new file mode 100644
index 0000000..2a57606
--- /dev/null
+++ b/debian/patches/0093-agent-Slightly-change-structure-of-cmd_readkey.patch
@@ -0,0 +1,117 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Mon, 24 Oct 2016 12:55:21 +0200
+Subject: agent: Slightly change structure of cmd_readkey.
+
+* agent/command.c (cmd_readkey): Avoid a leave label in the middle of
+the code.  Remove the special return.
+--
+
+This helps to get better debug output.
+
+The set_error macro which is used by parse_keygrip merely sets the
+error code into the Assuan context.  It is thus no problem anymore to
+call leave_cmd after having used set_error.  This might havve been
+diffferent in the past.
+
+Signed-off-by: Werner Koch <wk at gnupg.org>
+---
+ agent/command.c | 60 +++++++++++++++++++++++++++++----------------------------
+ 1 file changed, 31 insertions(+), 29 deletions(-)
+
+diff --git a/agent/command.c b/agent/command.c
+index b17c62d..ba9fdf7 100644
+--- a/agent/command.c
++++ b/agent/command.c
+@@ -384,7 +384,9 @@ progress_cb (ctrl_t ctrl, const char *what, int printchar,
+ }
+ 
+ 
+-/* Helper to print a message while leaving a command.  */
++/* Helper to print a message while leaving a command.  Note that this
++ * function does not call assuan_set_error; the caller may do this
++ * prior to calling us.  */
+ static gpg_error_t
+ leave_cmd (assuan_context_t ctx, gpg_error_t err)
+ {
+@@ -993,17 +995,19 @@ cmd_readkey (assuan_context_t ctx, char *line)
+   unsigned char grip[20];
+   gcry_sexp_t s_pkey = NULL;
+   unsigned char *pkbuf = NULL;
++  char *serialno = NULL;
+   size_t pkbuflen;
++  const char *opt_card;
+ 
+   if (ctrl->restricted)
+     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ 
+-  if (has_option_name (line, "--card"))
+-    {
+-      const char *keyid;
+-      char *serialno = NULL;
++  opt_card = has_option_name (line, "--card");
++  line = skip_options (line);
+ 
+-      keyid = skip_options (line);
++  if (opt_card)
++    {
++      const char *keyid = opt_card;
+ 
+       rc = agent_card_getattr (ctrl, "SERIALNO", &serialno);
+       if (rc)
+@@ -1035,35 +1039,33 @@ cmd_readkey (assuan_context_t ctx, char *line)
+         goto leave;
+ 
+       rc = assuan_send_data (ctx, pkbuf, pkbuflen);
+-
+- leave:
+-      xfree (serialno);
+-      xfree (pkbuf);
+-      gcry_sexp_release (s_pkey);
+-      return leave_cmd (ctx, rc);
+     }
+-
+-  rc = parse_keygrip (ctx, line, grip);
+-  if (rc)
+-    return rc; /* Return immediately as this is already an Assuan error code.*/
+-
+-  rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
+-  if (!rc)
++  else
+     {
+-      pkbuflen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
+-      assert (pkbuflen);
+-      pkbuf = xtrymalloc (pkbuflen);
+-      if (!pkbuf)
+-        rc = gpg_error_from_syserror ();
+-      else
++      rc = parse_keygrip (ctx, line, grip);
++      if (rc)
++        goto leave;
++
++      rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
++      if (!rc)
+         {
+-          gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, pkbuf, pkbuflen);
+-          rc = assuan_send_data (ctx, pkbuf, pkbuflen);
+-          xfree (pkbuf);
++          pkbuflen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
++          log_assert (pkbuflen);
++          pkbuf = xtrymalloc (pkbuflen);
++          if (!pkbuf)
++            rc = gpg_error_from_syserror ();
++          else
++            {
++              gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, pkbuf, pkbuflen);
++              rc = assuan_send_data (ctx, pkbuf, pkbuflen);
++            }
+         }
+-      gcry_sexp_release (s_pkey);
+     }
+ 
++ leave:
++  xfree (serialno);
++  xfree (pkbuf);
++  gcry_sexp_release (s_pkey);
+   return leave_cmd (ctx, rc);
+ }
+ 
diff --git a/debian/patches/0094-agent-Minor-cleanup-for-recent-change-in-findkey.c.patch b/debian/patches/0094-agent-Minor-cleanup-for-recent-change-in-findkey.c.patch
new file mode 100644
index 0000000..3005c22
--- /dev/null
+++ b/debian/patches/0094-agent-Minor-cleanup-for-recent-change-in-findkey.c.patch
@@ -0,0 +1,32 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Mon, 24 Oct 2016 13:01:06 +0200
+Subject: agent: Minor cleanup for recent change in findkey.c
+
+* agent/findkey.c (agent_write_private_key): Avoid label name error.
+
+Signed-off-by: Werner Koch <wk at gnupg.org>
+---
+ agent/findkey.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/agent/findkey.c b/agent/findkey.c
+index 162e8c2..c67dc72 100644
+--- a/agent/findkey.c
++++ b/agent/findkey.c
+@@ -157,14 +157,10 @@ agent_write_private_key (const unsigned char *grip,
+         {
+           fp = es_fopen (fname, "wbx,mode=-rw");
+           if (!fp)
+-            {
+-              tmperr = gpg_error_from_syserror ();
+-              goto error;
+-            }
++            tmperr = gpg_error_from_syserror ();
+         }
+-      else
++      if (!fp)
+         {
+-        error:
+           log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
+           xfree (fname);
+           return tmperr;
diff --git a/debian/patches/0095-gpg-Replace-two-sprintf-calls.patch b/debian/patches/0095-gpg-Replace-two-sprintf-calls.patch
new file mode 100644
index 0000000..7e0d5c3
--- /dev/null
+++ b/debian/patches/0095-gpg-Replace-two-sprintf-calls.patch
@@ -0,0 +1,54 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Mon, 24 Oct 2016 13:12:05 +0200
+Subject: gpg: Replace two sprintf calls.
+
+* g10/keygen.c (print_status_key_created): Use snprintf for now.
+(ask_expire_interval): Replace xmalloc and sprintf by xasprintf.
+--
+
+Future updates: Replace code like
+
+   r = xcalloc (1, sizeof *r + 20 );
+   r->key = pKEYLENGTH;
+   sprintf( r->u.value, "%u", info.key_attr[0].nbits);
+
+by something like
+
+   r = new_r_with_value ("%u", info.key_attr[0].nbits);
+   r->key = pKEYLENGTH;
+
+Signed-off-by: Werner Koch <wk at gnupg.org>
+---
+ g10/keygen.c | 11 +++--------
+ 1 file changed, 3 insertions(+), 8 deletions(-)
+
+diff --git a/g10/keygen.c b/g10/keygen.c
+index ed529c7..d98b70b 100644
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -180,8 +180,9 @@ print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
+           *p++ = ' ';
+           fingerprint_from_pk (pk, array, &n);
+           s = array;
++          /* Fixme: Use bin2hex */
+           for (i=0; i < n ; i++, s++, p += 2)
+-            sprintf (p, "%02X", *s);
++            snprintf (p, 3, "%02X", *s);
+         }
+     }
+   if (*handle)
+@@ -2428,13 +2429,7 @@ ask_expire_interval(int object,const char *def_expire)
+ 	  {
+ 	    char *prompt;
+ 
+-#define PROMPTSTRING _("Signature is valid for? (%s) ")
+-	    /* This will actually end up larger than necessary because
+-	       of the 2 bytes for '%s' */
+-	    prompt=xmalloc(strlen(PROMPTSTRING)+strlen(def_expire)+1);
+-	    sprintf(prompt,PROMPTSTRING,def_expire);
+-#undef PROMPTSTRING
+-
++	    prompt = xasprintf (_("Signature is valid for? (%s) "), def_expire);
+ 	    answer = cpr_get("siggen.valid",prompt);
+ 	    xfree(prompt);
+ 
diff --git a/debian/patches/0096-agent-tests-w32-Fix-relaying-pinentry-user-data-fix-.patch b/debian/patches/0096-agent-tests-w32-Fix-relaying-pinentry-user-data-fix-.patch
new file mode 100644
index 0000000..a730f2f
--- /dev/null
+++ b/debian/patches/0096-agent-tests-w32-Fix-relaying-pinentry-user-data-fix-.patch
@@ -0,0 +1,190 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 25 Oct 2016 17:07:08 +0200
+Subject: agent, tests, w32: Fix relaying pinentry user data,
+ fix fake-pinentry.
+
+* agent/call-pinentry.c (start_pinentry): Also send the user data
+using an Assuan 'OPTION' command.
+* tests/openpgp/fake-pinentry.c (get_passphrase): Fix updating
+passphrase file.
+(spacep): Include newline characters.
+(rstrip): New function.
+(main): Handle Windows line endings.  Handle the userdata option, and
+restart with the new options.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ agent/call-pinentry.c         | 13 +++++++++
+ tests/openpgp/fake-pinentry.c | 65 ++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 71 insertions(+), 7 deletions(-)
+
+diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
+index 46db9e8..813df9a 100644
+--- a/agent/call-pinentry.c
++++ b/agent/call-pinentry.c
+@@ -354,6 +354,19 @@ start_pinentry (ctrl_t ctrl)
+   if (DBG_IPC)
+     log_debug ("connection to PIN entry established\n");
+ 
++  value = session_env_getenv (ctrl->session_env, "PINENTRY_USER_DATA");
++  if (value != NULL)
++    {
++      char *optstr;
++      if (asprintf (&optstr, "OPTION pinentry-user-data=%s", value) < 0 )
++	return unlock_pinentry (out_of_core ());
++      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
++			    NULL);
++      xfree (optstr);
++      if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION)
++        return unlock_pinentry (rc);
++    }
++
+   rc = assuan_transact (entry_ctx,
+                         opt.no_grab? "OPTION no-grab":"OPTION grab",
+                         NULL, NULL, NULL, NULL, NULL, NULL);
+diff --git a/tests/openpgp/fake-pinentry.c b/tests/openpgp/fake-pinentry.c
+index 6ef6126..baa79a8 100644
+--- a/tests/openpgp/fake-pinentry.c
++++ b/tests/openpgp/fake-pinentry.c
+@@ -18,10 +18,12 @@
+  * along with this program; if not, see <http://www.gnu.org/licenses/>.
+  */
+ 
++#include <errno.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdarg.h>
++#include <unistd.h>
+ 
+ FILE *log_stream;
+ 
+@@ -108,12 +110,39 @@ get_passphrase (const char *fname)
+ 
+   fclose (source);
+   fclose (sink);
+-  rename (fname_new, fname);
++  if (unlink (fname))
++    {
++      fprintf (stderr, "Failed to remove %s: %s",
++               fname, strerror (errno));
++      exit (1);
++    }
++
++  if (rename (fname_new, fname))
++    {
++      fprintf (stderr, "Failed to rename %s to %s: %s",
++               fname, fname_new, strerror (errno));
++      exit (1);
++    }
+   return passphrase;
+ }
+ 
+ 

+-#define spacep(p)   (*(p) == ' ' || *(p) == '\t')
++#define spacep(p)   (*(p) == ' ' || *(p) == '\t' \
++                     || *(p) == '\r' || *(p) == '\n')
++
++/* rstrip line.  */
++void
++rstrip (char *buffer)
++{
++  char *p;
++  for (p = buffer + strlen (buffer) - 1; p >= buffer; p--)
++    {
++      if (! spacep (p))
++        break;
++      *p = 0;
++    }
++}
++
+ 
+ /* Skip over options in LINE.
+ 
+@@ -164,6 +193,8 @@ int
+ main (int argc, char **argv)
+ {
+   char *args;
++  char *option_user_data = NULL;
++  int got_environment_user_data;
+   char *logfile;
+   char *passphrasefile;
+   char *passphrase;
+@@ -175,9 +206,11 @@ main (int argc, char **argv)
+   setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
+ 
+   args = getenv ("PINENTRY_USER_DATA");
++  got_environment_user_data = args != NULL;
+   if (! args)
+     args = "";
+ 
++ restart:
+   logfile = option_value (args, "--logfile");
+   if (logfile)
+     {
+@@ -214,9 +247,7 @@ main (int argc, char **argv)
+           return 1;
+         }
+ 
+-      p = passphrase + strlen (passphrase) - 1;
+-      if (*p == '\n')
+-        *p = 0;
++      rstrip (passphrase);
+     }
+   else
+     {
+@@ -225,12 +256,13 @@ main (int argc, char **argv)
+         passphrase = "no PINENTRY_USER_DATA -- using default passphrase";
+     }
+ 
+-  reply ("# fake-pinentry started.  Passphrase='%s'.\n", passphrase);
++  reply ("# fake-pinentry(%d) started.  Passphrase='%s'.\n",
++         getpid (), passphrase);
+   reply ("OK - what's up?\n");
+ 
+   while (! feof (stdin))
+     {
+-      char buffer[1024];
++      char buffer[1024], *p;
+ 
+       if (fgets (buffer, sizeof buffer, stdin) == NULL)
+ 	break;
+@@ -238,6 +270,8 @@ main (int argc, char **argv)
+       if (log_stream)
+         fprintf (log_stream, "< %s", buffer);
+ 
++      rstrip (buffer);
++
+       if (strncmp (buffer, "GETPIN", 6) == 0)
+         reply ("D %s\n", passphrase);
+       else if (strncmp (buffer, "BYE", 3) == 0)
+@@ -245,6 +279,22 @@ main (int argc, char **argv)
+ 	  reply ("OK\n");
+ 	  break;
+ 	}
++#define OPT_USER_DATA	"OPTION pinentry-user-data="
++      else if (strncmp (buffer, OPT_USER_DATA, strlen (OPT_USER_DATA)) == 0)
++        {
++          if (got_environment_user_data)
++            {
++              reply ("OK - I already got the data from the environment.\n");
++              continue;
++            }
++
++          if (log_stream)
++            fclose (log_stream);
++          log_stream = NULL;
++          free (option_user_data);
++          option_user_data = args = strdup (buffer + strlen (OPT_USER_DATA));
++          goto restart;
++        }
+ 
+       reply ("OK\n");
+     }
+@@ -253,5 +303,6 @@ main (int argc, char **argv)
+   if (log_stream)
+     fclose (log_stream);
+ 
++  free (option_user_data);
+   return 0;
+ }
diff --git a/debian/patches/series b/debian/patches/series
index 0de45be..de68121 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -61,3 +61,36 @@
 0061-common-Avoid-pointer-arithmetic-on-string-literals.patch
 0062-agent-dirmngr-scd-Fix-init_common_subsystems.patch
 0063-agent-Fix-get_socket_name.patch
+0064-tools-Fix-error-handling.patch
+0065-g10-Fix-a-column-s-type-in-TOFU-DB.patch
+0066-agent-Move-inotify-code-to-common-and-improve-it.patch
+0067-agent-Use-straightforward-names-for-the-default-sock.patch
+0068-gpgconf-Fix-for-homedir.patch
+0069-scd-Fix-keytocard-for-ECC.patch
+0070-doc-Point-gpg-agent-1-at-the-right-gpg-manpage-in-SE.patch
+0071-doc-Document-how-to-manually-shut-down-gpg-agent.patch
+0072-scd-minor-cleanup-to-merge-other-works.patch
+0073-scd-Support-ECC-key-generation.patch
+0074-common-w32-Make-use-of-default_errsource-in-exechelp.patch
+0075-common-w32-Extend-gnupg_create_inbound_pipe-et-al.patch
+0076-common-w32-Communicate-with-child-in-non-blocking-mo.patch
+0077-common-Fix-copying-data-to-estreams.patch
+0078-agent-Add-card-option-for-READKEY.patch
+0079-g10-smartcard-keygen-change.patch
+0080-scd-GENKEY-updates-the-public-key-in-APP.patch
+0081-agent-g10-Fix-keygen.patch
+0082-agent-Fix-saving-with-FORCE-1.patch
+0083-Fix-use-cases-of-snprintf.patch
+0084-g10-Support-ECC-for-gen_card_key.patch
+0085-g10-Don-t-ask-keysize-for-for-non-RSA-card.patch
+0086-scd-Fix-segfault-changing-key-attr.patch
+0087-g10-scd-Fix-ECC-keygen.patch
+0088-g10-Write-first-keybox-record-in-binary-mode.patch
+0089-g10-More-card-key-generation-change.patch
+0090-g10-Fix-card-keygen-for-decryption.patch
+0091-common-Fix-openpgp_is_curve_supported.patch
+0092-scd-Use-canonical-curve-name-of-libgcrypt.patch
+0093-agent-Slightly-change-structure-of-cmd_readkey.patch
+0094-agent-Minor-cleanup-for-recent-change-in-findkey.c.patch
+0095-gpg-Replace-two-sprintf-calls.patch
+0096-agent-tests-w32-Fix-relaying-pinentry-user-data-fix-.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git



More information about the Pkg-gnupg-commit mailing list