[Pkg-gnupg-commit] [gnupg2] 01/12: import a bunch of fixes from upstream

Daniel Kahn Gillmor dkg at fifthhorseman.net
Mon Aug 1 22:26:34 UTC 2016


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

dkg pushed a commit to branch experimental
in repository gnupg2.

commit 96166f07843454aa86d7083076892c69f38083b1
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sat Jul 30 13:27:34 2016 -0400

    import a bunch of fixes from upstream
---
 .../0003-agent-Fix-passphrase-cache-lookups.patch  | 107 +++++
 ...x-race-conditions-for-release_application.patch |  58 +++
 .../0005-tests-Add-test-for-ssh-support.patch      | 259 ++++++++++++
 .../0006-agent-Add-known-keys-to-sshcontrol.patch  |  85 ++++
 ...x-card-removal-reset-on-multiple-contexts.patch | 186 +++++++++
 debian/patches/0008-g10-Fix-crash.patch            |  43 ++
 ...09-g10-Drop-superfluous-begin-transaction.patch |  38 ++
 debian/patches/0010-g10-Fix-error-handling.patch   |  32 ++
 ...y-ignore-legacy-keys-in-the-keyring-cache.patch | 464 +++++++++++++++++++++
 .../0012-gpgscm-Make-function-more-general.patch   |  26 ++
 .../0013-g10-Fix-key-import-statistics.patch       | 176 ++++++++
 .../0014-common-Add-unit-test-for-exectool.patch   | 264 ++++++++++++
 ...ork-resource-cleanup-when-handling-errors.patch |  77 ++++
 .../0016-common-Avoid-excessive-stack-use.patch    | 135 ++++++
 ...lude-upstream-tests-openpgp-run-tests.scm.patch | 224 ++++++++++
 ...gscm-Make-the-verbose-setting-more-useful.patch | 127 ++++++
 ...ot-shadow-common-function-name-in-catch-m.patch |  26 ++
 .../0020-common-Fix-iobuf_peek-corner-case.patch   | 178 ++++++++
 ...21-gpgsm-Fix-machine-readable-key-listing.patch |  24 ++
 debian/patches/series                              |  19 +
 20 files changed, 2548 insertions(+)

diff --git a/debian/patches/0003-agent-Fix-passphrase-cache-lookups.patch b/debian/patches/0003-agent-Fix-passphrase-cache-lookups.patch
new file mode 100644
index 0000000..944afff
--- /dev/null
+++ b/debian/patches/0003-agent-Fix-passphrase-cache-lookups.patch
@@ -0,0 +1,107 @@
+From: Justus Winter <justus at g10code.com>
+Date: Mon, 18 Jul 2016 12:51:38 +0200
+Subject: agent: Fix passphrase cache lookups.
+
+CACHE_MODE_ANY is supposed to match any cache mode except
+CACHE_MODE_IGNORE, but the code used '==' to compare cache modes.
+
+* agent/cache.c (cache_mode_equal): New function.
+(agent_set_cache): Use the new function to compare cache modes.
+(agent_get_cache): Likewise.
+* tests/openpgp/Makefile.am (TESTS): Add new test.
+* tests/openpgp/issue2015.scm: New file.
+
+GnuPG-bug-id: 2015
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ agent/cache.c               | 13 +++++++++++--
+ tests/openpgp/Makefile.am   |  1 +
+ tests/openpgp/issue2015.scm | 29 +++++++++++++++++++++++++++++
+ 3 files changed, 41 insertions(+), 2 deletions(-)
+ create mode 100755 tests/openpgp/issue2015.scm
+
+diff --git a/agent/cache.c b/agent/cache.c
+index 3fffd2d..83107a6 100644
+--- a/agent/cache.c
++++ b/agent/cache.c
+@@ -299,6 +299,15 @@ agent_flush_cache (void)
+ }
+ 
+ 
++/* Compare two cache modes.  */
++static int
++cache_mode_equal (cache_mode_t a, cache_mode_t b)
++{
++  /* CACHE_MODE_ANY matches any mode other than CACHE_MODE_IGNORE.  */
++  return ((a == CACHE_MODE_ANY && b != CACHE_MODE_IGNORE)
++          || (b == CACHE_MODE_ANY && a != CACHE_MODE_IGNORE) || a == b);
++}
++
+ 
+ /* Store the string DATA in the cache under KEY and mark it with a
+    maximum lifetime of TTL seconds.  If there is already data under
+@@ -333,7 +342,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
+     {
+       if (((cache_mode != CACHE_MODE_USER
+             && cache_mode != CACHE_MODE_NONCE)
+-           || r->cache_mode == cache_mode)
++           || cache_mode_equal (r->cache_mode, cache_mode))
+           && !strcmp (r->key, key))
+         break;
+     }
+@@ -416,7 +425,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
+       if (r->pw
+           && ((cache_mode != CACHE_MODE_USER
+                && cache_mode != CACHE_MODE_NONCE)
+-              || r->cache_mode == cache_mode)
++              || cache_mode_equal (r->cache_mode, cache_mode))
+           && !strcmp (r->key, key))
+         {
+           /* Note: To avoid races KEY may not be accessed anymore below.  */
+diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am
+index 012a3f2..e8f46da 100644
+--- a/tests/openpgp/Makefile.am
++++ b/tests/openpgp/Makefile.am
+@@ -81,6 +81,7 @@ TESTS = setup.scm \
+ 	use-exact-key.scm \
+ 	default-key.scm \
+ 	export.scm \
++	issue2015.scm \
+ 	finish.scm
+ 
+ 
+diff --git a/tests/openpgp/issue2015.scm b/tests/openpgp/issue2015.scm
+new file mode 100755
+index 0000000..536cb8f
+--- /dev/null
++++ b/tests/openpgp/issue2015.scm
+@@ -0,0 +1,29 @@
++#!/usr/bin/env gpgscm
++
++;; Copyright (C) 2016 g10 Code GmbH
++;;
++;; This file is part of GnuPG.
++;;
++;; GnuPG is free software; you can redistribute it and/or modify
++;; it under the terms of the GNU General Public License as published by
++;; the Free Software Foundation; either version 3 of the License, or
++;; (at your option) any later version.
++;;
++;; GnuPG is distributed in the hope that it will be useful,
++;; but WITHOUT ANY WARRANTY; without even the implied warranty of
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++;; GNU General Public License for more details.
++;;
++;; You should have received a copy of the GNU General Public License
++;; along with this program; if not, see <http://www.gnu.org/licenses/>.
++
++(load (with-path "defs.scm"))
++
++(info "Checking passphrase cache (issue2015)...")
++(call-check `(,(tool 'gpg-preset-passphrase)
++	      --preset --passphrase some_passphrase some_id))
++
++(let ((response (call-popen `(,(tool 'gpg-connect-agent))
++			    "GET_PASSPHRASE --no-ask some_id X X X")))
++  (unless (string=? response "OK 736F6D655F70617373706872617365\n")
++	  (error "Could not retrieve passphrase from cache:" response)))
diff --git a/debian/patches/0004-scd-Fix-race-conditions-for-release_application.patch b/debian/patches/0004-scd-Fix-race-conditions-for-release_application.patch
new file mode 100644
index 0000000..ae959a3
--- /dev/null
+++ b/debian/patches/0004-scd-Fix-race-conditions-for-release_application.patch
@@ -0,0 +1,58 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Tue, 19 Jul 2016 10:53:39 +0900
+Subject: scd: Fix race conditions for release_application.
+
+* scd/command.c (do_reset, cmd_restart): Reset app_ctx before calling
+release_application.
+
+--
+
+Thanks to Ben Warren for the report.
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ scd/command.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/scd/command.c b/scd/command.c
+index a4a2ba0..5842ee7 100644
+--- a/scd/command.c
++++ b/scd/command.c
+@@ -261,6 +261,7 @@ do_reset (ctrl_t ctrl, int send_reset)
+   int vrdr = ctrl->server_local->vreader_idx;
+   int slot;
+   int err;
++  struct app_ctx_s *app = ctrl->app_ctx;
+ 
+   if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_table))))
+     BUG ();
+@@ -268,10 +269,10 @@ do_reset (ctrl_t ctrl, int send_reset)
+   /* If there is an active application, release it.  Tell all other
+      sessions using the same application to release the
+      application.  */
+-  if (ctrl->app_ctx)
++  if (app)
+     {
+-      release_application (ctrl->app_ctx);
+       ctrl->app_ctx = NULL;
++      release_application (app);
+       if (send_reset)
+         {
+           struct server_local_s *sl;
+@@ -1742,13 +1743,14 @@ static gpg_error_t
+ cmd_restart (assuan_context_t ctx, char *line)
+ {
+   ctrl_t ctrl = assuan_get_pointer (ctx);
++  struct app_ctx_s *app = ctrl->app_ctx;
+ 
+   (void)line;
+ 
+-  if (ctrl->app_ctx)
++  if (app)
+     {
+-      release_application (ctrl->app_ctx);
+       ctrl->app_ctx = NULL;
++      release_application (app);
+     }
+   if (locked_session && ctrl->server_local == locked_session)
+     {
diff --git a/debian/patches/0005-tests-Add-test-for-ssh-support.patch b/debian/patches/0005-tests-Add-test-for-ssh-support.patch
new file mode 100644
index 0000000..1d1f1a3
--- /dev/null
+++ b/debian/patches/0005-tests-Add-test-for-ssh-support.patch
@@ -0,0 +1,259 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 19 Jul 2016 16:17:22 +0200
+Subject: tests: Add test for ssh support.
+
+* tests/gpgscm/tests.scm (path-expand): New function.
+* tests/openpgp/Makefile.am (TESTS): Add new test.
+(sample_keys): Add new keys.
+(CLEANFILES): Clean ssh socket and control file.
+* tests/openpgp/fake-pinentry.c (main): Add a default passphrase.
+* tests/openpgp/gpg-agent.conf.tmpl: Enable ssh support.
+* tests/openpgp/samplekeys/ssh-dsa.key: New file.
+* tests/openpgp/samplekeys/ssh-ecdsa.key: Likewise.
+* tests/openpgp/samplekeys/ssh-ed25519.key: Likewise.
+* tests/openpgp/samplekeys/ssh-rsa.key: Likewise.
+* tests/openpgp/ssh.scm: Likewise.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ tests/gpgscm/tests.scm                   | 14 +++++++--
+ tests/openpgp/Makefile.am                |  9 ++++--
+ tests/openpgp/fake-pinentry.c            |  6 +++-
+ tests/openpgp/gpg-agent.conf.tmpl        |  1 +
+ tests/openpgp/samplekeys/ssh-dsa.key     | 12 ++++++++
+ tests/openpgp/samplekeys/ssh-ecdsa.key   |  5 +++
+ tests/openpgp/samplekeys/ssh-ed25519.key |  7 +++++
+ tests/openpgp/samplekeys/ssh-rsa.key     | 27 +++++++++++++++++
+ tests/openpgp/ssh.scm                    | 52 ++++++++++++++++++++++++++++++++
+ 9 files changed, 127 insertions(+), 6 deletions(-)
+ create mode 100644 tests/openpgp/samplekeys/ssh-dsa.key
+ create mode 100644 tests/openpgp/samplekeys/ssh-ecdsa.key
+ create mode 100644 tests/openpgp/samplekeys/ssh-ed25519.key
+ create mode 100644 tests/openpgp/samplekeys/ssh-rsa.key
+ create mode 100755 tests/openpgp/ssh.scm
+
+diff --git a/tests/gpgscm/tests.scm b/tests/gpgscm/tests.scm
+index c32e2fa..58b1430 100644
+--- a/tests/gpgscm/tests.scm
++++ b/tests/gpgscm/tests.scm
+@@ -183,10 +183,12 @@
+ (define (in-srcdir what)
+   (canonical-path (string-append (getenv "srcdir") "/" what)))
+ 
+-(define (with-path name)
+-  (let loop ((path (string-split (getenv "GPGSCM_PATH") #\:)))
++;; Try to find NAME in PATHS.  Returns the full path name on success,
++;; or raises an error.
++(define (path-expand name paths)
++  (let loop ((path paths))
+     (if (null? path)
+-	name
++	(throw "Could not find" name "in" paths)
+ 	(let* ((qualified-name (string-append (car path) "/" name))
+ 	       (file-exists (call-with-input-file qualified-name
+ 			      (lambda (x) #t))))
+@@ -194,6 +196,12 @@
+ 	      qualified-name
+ 	      (loop (cdr path)))))))
+ 
++;; Expand NAME using the gpgscm load path.  Use like this:
++;;   (load (with-path "library.scm"))
++(define (with-path name)
++  (catch name
++	 (path-expand name (string-split (getenv "GPGSCM_PATH") *pathsep*))))
++
+ (define (basename path)
+   (let ((i (string-index path #\/)))
+     (if (equal? i #f)
+diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am
+index e8f46da..f1dcf15 100644
+--- a/tests/openpgp/Makefile.am
++++ b/tests/openpgp/Makefile.am
+@@ -81,6 +81,7 @@ TESTS = setup.scm \
+ 	use-exact-key.scm \
+ 	default-key.scm \
+ 	export.scm \
++	ssh.scm \
+ 	issue2015.scm \
+ 	finish.scm
+ 
+@@ -145,7 +146,11 @@ sample_keys = samplekeys/README \
+ 	      samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc \
+               samplekeys/rsa-rsa-sample-1.asc \
+               samplekeys/ed25519-cv25519-sample-1.asc \
+-	      samplekeys/silent-running.asc
++	      samplekeys/silent-running.asc \
++	      samplekeys/ssh-dsa.key \
++	      samplekeys/ssh-ecdsa.key \
++	      samplekeys/ssh-ed25519.key \
++	      samplekeys/ssh-rsa.key
+ 
+ EXTRA_DIST = defs.inc defs.scm pinentry.sh $(TESTS) $(TEST_FILES) \
+ 	     mkdemodirs signdemokey $(priv_keys) $(sample_keys)   \
+@@ -157,7 +162,7 @@ CLEANFILES = prepared.stamp x y yy z out err  $(data_files) \
+ 	     pubring.gpg pubring.gpg~ pubring.kbx pubring.kbx~ \
+ 	     secring.gpg pubring.pkr secring.skr \
+ 	     gnupg-test.stop random_seed gpg-agent.log tofu.db \
+-	     passphrases
++	     passphrases sshcontrol S.gpg-agent.ssh
+ 
+ clean-local:
+ 	-rm -rf private-keys-v1.d openpgp-revocs.d tofu.d gpgtar.d
+diff --git a/tests/openpgp/fake-pinentry.c b/tests/openpgp/fake-pinentry.c
+index a651726..6ef6126 100644
+--- a/tests/openpgp/fake-pinentry.c
++++ b/tests/openpgp/fake-pinentry.c
+@@ -219,7 +219,11 @@ main (int argc, char **argv)
+         *p = 0;
+     }
+   else
+-    passphrase = skip_options (args);
++    {
++      passphrase = skip_options (args);
++      if (*passphrase == 0)
++        passphrase = "no PINENTRY_USER_DATA -- using default passphrase";
++    }
+ 
+   reply ("# fake-pinentry started.  Passphrase='%s'.\n", passphrase);
+   reply ("OK - what's up?\n");
+diff --git a/tests/openpgp/gpg-agent.conf.tmpl b/tests/openpgp/gpg-agent.conf.tmpl
+index 70e1633..3559150 100644
+--- a/tests/openpgp/gpg-agent.conf.tmpl
++++ b/tests/openpgp/gpg-agent.conf.tmpl
+@@ -1,2 +1,3 @@
+ allow-preset-passphrase
+ no-grab
++enable-ssh-support
+diff --git a/tests/openpgp/samplekeys/ssh-dsa.key b/tests/openpgp/samplekeys/ssh-dsa.key
+new file mode 100644
+index 0000000..58707b3
+--- /dev/null
++++ b/tests/openpgp/samplekeys/ssh-dsa.key
+@@ -0,0 +1,12 @@
++-----BEGIN DSA PRIVATE KEY-----
++MIIBvAIBAAKBgQCx0bAMKBKzYJugVtUFRRiF8jV4eT8mowj5C0q4QRPuPAGgPdqq
++g1PKmoIpCKLynqH29+BFErp1OOenWKRdu9claTu0lmIrMYeYw8liKsyMTg5/DxoV
++sRXD1DFoKdeZPDVUxOEQWsLf/IuuLXy4c9GxzET88wUDeieV+GcYQFADoQIVAKS7
++giO+VWOnwqr0p/csUWltpo8TAoGBAJcVpe9riXRuxJtmy1sbJJzOvtPtXk5MCpGs
++T/KEXJuVZvu334zkySDd9Is1ML2g5e81ONRCgCGHpwNOzoLC4+yp+pr1E+B2xkUY
++ouEtZWhKlbaYw7UdHiRRMEVJqvu+CdyI2gwOveDSrVhoXmGyz9PQVNoiuRXP2hMF
++C21jNnBrAoGBAILRAY0/mqsaOTII3uC8KvqwbKlmPnYMJr0COmU1PbOXvaeyWLqG
++NHhwPZg6OEhqEk+WMIwb2Dcv70AIYKQU8jX0elh0lk6pE8bomn7/ZIkqa60VG1Cx
++8x2GUNag78LvnLfmUPAXOrrCPfbGuqdogCymUz1qrtEzdOSbeBvCMAAFAhQr1sV4
+++UWhlUoExLMDdIyT/ohfxQ==
++-----END DSA PRIVATE KEY-----
+diff --git a/tests/openpgp/samplekeys/ssh-ecdsa.key b/tests/openpgp/samplekeys/ssh-ecdsa.key
+new file mode 100644
+index 0000000..db7c45c
+--- /dev/null
++++ b/tests/openpgp/samplekeys/ssh-ecdsa.key
+@@ -0,0 +1,5 @@
++-----BEGIN EC PRIVATE KEY-----
++MHcCAQEEIF8Mt42n5l2eJB2rk5TSnS98xAtR2VfmmI96WT5OtFrdoAoGCCqGSM49
++AwEHoUQDQgAEsphhghltvEj+1rFEcIlSNy2ze7IMHdhGsH060PwOzjKTy15M8zHI
++uaH9SOMXTzn3Bial8bxrXLsOYEhRZhYSrA==
++-----END EC PRIVATE KEY-----
+diff --git a/tests/openpgp/samplekeys/ssh-ed25519.key b/tests/openpgp/samplekeys/ssh-ed25519.key
+new file mode 100644
+index 0000000..c3760b8
+--- /dev/null
++++ b/tests/openpgp/samplekeys/ssh-ed25519.key
+@@ -0,0 +1,7 @@
++-----BEGIN OPENSSH PRIVATE KEY-----
++b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
++QyNTUxOQAAACARyDcsgSrXAdihOuO5lN+qVKVPdwsXCmOZ61XYVUA1MAAAAJAOqdhVDqnY
++VQAAAAtzc2gtZWQyNTUxOQAAACARyDcsgSrXAdihOuO5lN+qVKVPdwsXCmOZ61XYVUA1MA
++AAAEATyEkvuhAExcEet+Rc2Qz2Fxg4iIi4XXJLpZFKwWsY3hHINyyBKtcB2KE647mU36pU
++pU93CxcKY5nrVdhVQDUwAAAACHRlc3Qga2V5AQIDBAU=
++-----END OPENSSH PRIVATE KEY-----
+diff --git a/tests/openpgp/samplekeys/ssh-rsa.key b/tests/openpgp/samplekeys/ssh-rsa.key
+new file mode 100644
+index 0000000..ef0425c
+--- /dev/null
++++ b/tests/openpgp/samplekeys/ssh-rsa.key
+@@ -0,0 +1,27 @@
++-----BEGIN RSA PRIVATE KEY-----
++MIIEpgIBAAKCAQEAxp4sIUtrNBl4Vbd4075CmtHmwxTc0FhQIGw36kptbrWReLb9
++Np0RQylKyc6qUruxZlCdPVFo7iX3vs272/0GEakPv0DAsKGbe1nTsMyxxz0o3dP4
++JQOlOGEnpETa0ybfPLMX1+qNiBdm7HLjqcP5+S0Exb0Z0deFNIhEP6XckUEgHmwA
++/AdDdUUKwwvZeZOi4XyBVt0vXzwM/+84ro27O+CZm9Du3qe1jTIsX7jUrqsUBhp9
++eUwa1jXfXuJJo9b4/GeP4S9x8U7ho+BQ6/HH03dzcKaY3FftanCZkcwxfGBBUiCK
++pIA5WgKimLcgP2R75Y3jilDoBh5HyIdGXo0aFwIDAQABAoIBAQCBXLIHeXS4eUJc
++KeSjnQ8KgV4Yf3UWqf5+L533lkRSUCYQhrbDpGeC49kXOejLe/4eUrEnJ+f8/HOx
++LZSGwvT5+bAM9CLMqGV5YNc1Fw1PZHFCkfXUPdyVrQnBvyr7Th0mDsuf0OAf3IYn
++yOipQMCGX6D1HaY8e3AB+CLjhab0X1vAwvqzPb/HIdtMhRWlJxzbuqnE3kr+Ccvz
++us3vmD4VBp0CF0f+yblcibMCHdHY6j8Ir6Qeq6Mbd6lEXRPW1TgUqP15idVaJ4AF
++1kGXDW9O0ycgrbopGZfk5yY60fEHGdr4QYjx2Gtx2xQcnPcjJ+j5kGgubKWxNhJE
++Qx7DPdYxAoGBAP29S+wD1df0U+Tr0x06N6M/nSjNacGs12Oq/ehNJHhTYUO9fWUl
++M2X/MXRMMMGsnGaLNsrLao9Jnq0ZU5GFICWYeVBvaCvRrGngbqJBy8jRv+QYyaQs
++AckLcdgLGvjhcXonHDcbcxpug7/qFwakT+KY2s11FrHBEzbAIuDiSSKfAoGBAMhj
++KPkrjWJh3xxpFrFnGYj5aF86ExrPe2LAP/8F6Ez7dQN+4bA6O5F4hpJ/X0q/6s0n
++IBljo/DgARCBjbwDSaAMEWdm8HDeBhJsSCdQHW38ylaRDi8CQDKR60N3a/tV1MRJ
++4fKoHZ+7HH3wc+Bjv3oDovwVyUMG7ekCjeqbqI2JAoGBAOkhYX5Jz9KJBAPSwLeb
++4760FfuFL+PooEVMt9kV96ouQbFxiqLB2UWfgJqv3iQ0Kcb1pbQRzag1Jfs4x9Vu
++ESk5vEyw729DSDxHHp8qAMhUHxC9zZZvcHx9bW3oVjHRQOfQw1XGfK0OWTKdK+bI
++VTWG55HaQK21DahCREmG31dVAoGBALBH80KHmsAioziGBi2YKjGCXtvu5eGfBsdP
++orzBQKOATmb91qLGB6MoaRI1NOo4POGu+qD7M7xyAt23aq0sIzfFhgX1260e1C6e
++zTawVsNsL7/JqbWXAEy8az+VrguTbTIkYL2sQStEWoM75WRPu6El09p5e+0YCnEC
++C0CJINUpAoGBAPF1fpPINHlUW+Bvo4Nj3935QgZI47yTplDusptyfYgFYXw6ZYel
++y5Zgv9TWZlmW9FDTp4XVgn5zQTEN1LdL7vNXWV9aOvfrqPk5ClBkxhndgq7j6MFs
++9+9V06HJDIsSrC0D/ajIkP+iT9Hd6eEZMkJ6y6XtTbkJGYt2zOtnrpb6
++-----END RSA PRIVATE KEY-----
+diff --git a/tests/openpgp/ssh.scm b/tests/openpgp/ssh.scm
+new file mode 100755
+index 0000000..cc47772
+--- /dev/null
++++ b/tests/openpgp/ssh.scm
+@@ -0,0 +1,52 @@
++#!/usr/bin/env gpgscm
++
++;; Copyright (C) 2016 g10 Code GmbH
++;;
++;; This file is part of GnuPG.
++;;
++;; GnuPG is free software; you can redistribute it and/or modify
++;; it under the terms of the GNU General Public License as published by
++;; the Free Software Foundation; either version 3 of the License, or
++;; (at your option) any later version.
++;;
++;; GnuPG is distributed in the hope that it will be useful,
++;; but WITHOUT ANY WARRANTY; without even the implied warranty of
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++;; GNU General Public License for more details.
++;;
++;; You should have received a copy of the GNU General Public License
++;; along with this program; if not, see <http://www.gnu.org/licenses/>.
++
++(load (with-path "defs.scm"))
++
++(define GNUPGHOME (getenv "GNUPGHOME"))
++(if (string=? "" GNUPGHOME)
++    (error "GNUPGHOME not set"))
++
++(setenv "SSH_AUTH_SOCK" (path-join GNUPGHOME "S.gpg-agent.ssh") #t)
++
++(define SSH-ADD #f)
++(catch (skip "ssh-add not found")
++       (set! SSH-ADD
++	     (path-expand "ssh-add" (string-split (getenv "PATH") *pathsep*))))
++
++(define keys
++  '(("dsa" "MD5:9a:e1:f1:5f:46:ea:a5:06:e1:e2:f8:38:8e:06:54:58")
++    ("rsa" "MD5:c9:85:b5:55:00:84:a9:82:5a:df:d6:62:1b:5a:28:22")
++    ("ecdsa" "MD5:93:37:30:a6:4e:e7:6a:22:79:77:8e:bf:ed:14:e9:8e")
++    ("ed25519" "MD5:08:df:be:af:d2:f5:32:20:3a:1c:56:06:be:31:0f:bf")))
++
++(for-each-p'
++ "Importing ssh keys..."
++ (lambda (key)
++   (let ((file (path-join (in-srcdir "samplekeys")
++			  (string-append "ssh-" (car key) ".key")))
++	 (hash (cadr key)))
++     ;; We pipe the key to ssh-add so that it won't complain about
++     ;; file's permissions.
++     (pipe:do
++      (pipe:open file (logior O_RDONLY O_BINARY))
++      (pipe:spawn `(,SSH-ADD -)))
++     (unless (string-contains? (call-popen `(,SSH-ADD -l "-E" md5) "") hash)
++	     (error "key not added"))))
++ car keys)
diff --git a/debian/patches/0006-agent-Add-known-keys-to-sshcontrol.patch b/debian/patches/0006-agent-Add-known-keys-to-sshcontrol.patch
new file mode 100644
index 0000000..6ca2bc0
--- /dev/null
+++ b/debian/patches/0006-agent-Add-known-keys-to-sshcontrol.patch
@@ -0,0 +1,85 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 19 Jul 2016 16:48:38 +0200
+Subject: agent: Add known keys to sshcontrol.
+
+* agent/command-ssh.c (ssh_identity_register): Add a key to sshcontrol
+even if it is already in the private key store.
+* tests/openpgp/ssh.scm: Test this.
+
+GnuPG-bug-id: 2316
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ agent/command-ssh.c   | 16 +++++++++-------
+ tests/openpgp/ssh.scm | 12 ++++++++++++
+ 2 files changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/agent/command-ssh.c b/agent/command-ssh.c
+index e3cd4b9..48f1b3d 100644
+--- a/agent/command-ssh.c
++++ b/agent/command-ssh.c
+@@ -3152,8 +3152,8 @@ reenter_compare_cb (struct pin_entry_info_s *pi)
+ /* Store the ssh KEY into our local key storage and protect it after
+    asking for a passphrase.  Cache that passphrase.  TTL is the
+    maximum caching time for that key.  If the key already exists in
+-   our key storage, don't do anything.  When entering a new key also
+-   add an entry to the sshcontrol file.  */
++   our key storage, don't do anything.  When entering a key also add
++   an entry to the sshcontrol file.  */
+ static gpg_error_t
+ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
+                        gcry_sexp_t key, int ttl, int confirm)
+@@ -3175,15 +3175,17 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
+   if (err)
+     goto out;
+ 
+-  /* Check whether the key is already in our key storage.  Don't do
+-     anything then.  */
+-  if ( !agent_key_available (key_grip_raw) )
+-    goto out; /* Yes, key is available.  */
++  bin2hex (key_grip_raw, 20, key_grip);
+ 
+   err = ssh_get_fingerprint_string (key, &key_fpr);
+   if (err)
+     goto out;
+ 
++  /* Check whether the key is already in our key storage.  Don't do
++     anything then besides (re-)adding it to sshcontrol.  */
++  if ( !agent_key_available (key_grip_raw) )
++    goto key_exists; /* Yes, key is available.  */
++
+   err = ssh_key_extract_comment (key, &comment);
+   if (err)
+     goto out;
+@@ -3249,11 +3251,11 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
+     goto out;
+ 
+   /* Cache this passphrase. */
+-  bin2hex (key_grip_raw, 20, key_grip);
+   err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl);
+   if (err)
+     goto out;
+ 
++ key_exists:
+   /* And add an entry to the sshcontrol file.  */
+   err = add_control_entry (ctrl, spec, key_grip, key_fpr, ttl, confirm);
+ 
+diff --git a/tests/openpgp/ssh.scm b/tests/openpgp/ssh.scm
+index cc47772..fe0b115 100755
+--- a/tests/openpgp/ssh.scm
++++ b/tests/openpgp/ssh.scm
+@@ -50,3 +50,15 @@
+      (unless (string-contains? (call-popen `(,SSH-ADD -l "-E" md5) "") hash)
+ 	     (error "key not added"))))
+  car keys)
++
++(info "Checking for issue2316...")
++(unlink (string-append GNUPGHOME "/sshcontrol"))
++(pipe:do
++ (pipe:open (path-join (in-srcdir "samplekeys")
++		       (string-append "ssh-rsa.key"))
++	    (logior O_RDONLY O_BINARY))
++ (pipe:spawn `(,SSH-ADD -)))
++(unless
++ (string-contains? (call-popen `(,SSH-ADD -l "-E" md5) "")
++		   "MD5:c9:85:b5:55:00:84:a9:82:5a:df:d6:62:1b:5a:28:22")
++ (error "known private key not (re-)added to sshcontrol"))
diff --git a/debian/patches/0007-scd-Fix-card-removal-reset-on-multiple-contexts.patch b/debian/patches/0007-scd-Fix-card-removal-reset-on-multiple-contexts.patch
new file mode 100644
index 0000000..1688449
--- /dev/null
+++ b/debian/patches/0007-scd-Fix-card-removal-reset-on-multiple-contexts.patch
@@ -0,0 +1,186 @@
+From: NIIBE Yutaka <gniibe at fsij.org>
+Date: Wed, 20 Jul 2016 11:35:05 +0900
+Subject: scd: Fix card removal/reset on multiple contexts.
+
+* scd/app.c (application_notify_card_reset): Add message for debug.
+*scd/command.c (update_card_removed): Call release_application and set
+SLOT -1 here.
+(struct server_local_s): Remove app_ctx_marked_for_release.
+(do_reset): Don't mark release but call release_application here.
+(open_card): Remove app_ctx_marked_for_release handling.
+(update_reader_status_file): Don't set SLOT here, so that it can be
+released the APP by application_notify_card_reset in
+update_card_removed.
+--
+
+Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>
+---
+ scd/app.c     |  4 +++
+ scd/command.c | 84 ++++++++++++++++++++++++++++++-----------------------------
+ 2 files changed, 47 insertions(+), 41 deletions(-)
+
+diff --git a/scd/app.c b/scd/app.c
+index 51464a2..55b8edd 100644
+--- a/scd/app.c
++++ b/scd/app.c
+@@ -168,8 +168,12 @@ application_notify_card_reset (int slot)
+   /* Release the APP, as it's not reusable any more.  */
+   if (lock_table[slot].app)
+     {
++      if (lock_table[slot].app->ref_count)
++        log_bug ("trying to release active context\n");
++
+       deallocate_app (lock_table[slot].app);
+       lock_table[slot].app = NULL;
++      log_debug ("application has been released\n");
+     }
+ 
+   unlock_reader (slot);
+diff --git a/scd/command.c b/scd/command.c
+index 5842ee7..d90c320 100644
+--- a/scd/command.c
++++ b/scd/command.c
+@@ -129,10 +129,6 @@ struct server_local_s
+      continue operation. */
+   int card_removed;
+ 
+-  /* Flag indicating that the application context needs to be released
+-     at the next opportunity.  */
+-  int app_ctx_marked_for_release;
+-
+   /* A disconnect command has been sent.  */
+   int disconnect_allowed;
+ 
+@@ -209,14 +205,28 @@ update_card_removed (int vrdr, int value)
+     return;
+ 
+   for (sl=session_list; sl; sl = sl->next_session)
+-    if (sl->ctrl_backlink
+-        && sl->ctrl_backlink->server_local->vreader_idx == vrdr)
+-      {
+-        sl->card_removed = value;
+-      }
++    {
++      ctrl_t ctrl = sl->ctrl_backlink;
++
++      if (ctrl && ctrl->server_local->vreader_idx == vrdr)
++        {
++          sl->card_removed = value;
++          if (value)
++            {
++              struct app_ctx_s *app = ctrl->app_ctx;
++              ctrl->app_ctx = NULL;
++              release_application (app);
++            }
++        }
++    }
++
+   /* Let the card application layer know about the removal.  */
+   if (value)
+-    application_notify_card_reset (vreader_slot (vrdr));
++    {
++      log_debug ("Removal of a card: %d\n", vrdr);
++      application_notify_card_reset (vreader_slot (vrdr));
++      vreader_table[vrdr].slot = -1;
++    }
+ }
+ 
+ 
+@@ -266,23 +276,31 @@ do_reset (ctrl_t ctrl, int send_reset)
+   if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_table))))
+     BUG ();
+ 
+-  /* If there is an active application, release it.  Tell all other
+-     sessions using the same application to release the
+-     application.  */
++  /* If there is an active application, release it. */
+   if (app)
+     {
+       ctrl->app_ctx = NULL;
+       release_application (app);
+-      if (send_reset)
++    }
++
++  /* Release the same application which is used by other sessions.  */
++  if (send_reset)
++    {
++      struct server_local_s *sl;
++
++      for (sl=session_list; sl; sl = sl->next_session)
+         {
+-          struct server_local_s *sl;
++          ctrl_t c = sl->ctrl_backlink;
+ 
+-          for (sl=session_list; sl; sl = sl->next_session)
+-            if (sl->ctrl_backlink
+-                && sl->ctrl_backlink->server_local->vreader_idx == vrdr)
+-              {
+-                sl->app_ctx_marked_for_release = 1;
+-              }
++          if (c && c != ctrl && c->server_local->vreader_idx == vrdr)
++            {
++              struct app_ctx_s *app0 = c->app_ctx;
++              if (app0)
++                {
++                  c->app_ctx = NULL;
++                  release_application (app0);
++                }
++            }
+         }
+     }
+ 
+@@ -300,8 +318,8 @@ do_reset (ctrl_t ctrl, int send_reset)
+         case SW_HOST_CARD_INACTIVE:
+           break;
+         default:
+-	  apdu_close_reader (slot);
+-          vreader_table[vrdr].slot = slot = -1;
++          apdu_close_reader (slot);
++          vreader_table[vrdr].slot = -1;
+           break;
+         }
+     }
+@@ -427,16 +445,6 @@ open_card (ctrl_t ctrl, const char *apptype)
+   if ( IS_LOCKED (ctrl) )
+     return gpg_error (GPG_ERR_LOCKED);
+ 
+-  /* If the application has been marked for release do it now.  We
+-     can't do it immediately in do_reset because the application may
+-     still be in use.  */
+-  if (ctrl->server_local->app_ctx_marked_for_release)
+-    {
+-      ctrl->server_local->app_ctx_marked_for_release = 0;
+-      release_application (ctrl->app_ctx);
+-      ctrl->app_ctx = NULL;
+-    }
+-
+   /* If we are already initialized for one specific application we
+      need to check that the client didn't requested a specific
+      application different from the one in use before we continue. */
+@@ -2031,14 +2039,10 @@ scd_command_handler (ctrl_t ctrl, int fd)
+   session_list = ctrl->server_local;
+   ctrl->server_local->ctrl_backlink = ctrl;
+   ctrl->server_local->assuan_ctx = ctx;
+-  ctrl->server_local->vreader_idx = -1;
+ 
+   /* We open the reader right at startup so that the ticker is able to
+      update the status file. */
+-  if (ctrl->server_local->vreader_idx == -1)
+-    {
+-      ctrl->server_local->vreader_idx = get_current_reader ();
+-    }
++  ctrl->server_local->vreader_idx = get_current_reader ();
+ 
+   /* Command processing loop. */
+   for (;;)
+@@ -2256,9 +2260,7 @@ update_reader_status_file (int set_card_removed_flag)
+       if (sw_apdu == SW_HOST_NO_READER)
+         {
+           /* Most likely the _reader_ has been unplugged.  */
+-          application_notify_card_reset (vr->slot);
+-	  apdu_close_reader (vr->slot);
+-          vr->slot = -1;
++          apdu_close_reader (vr->slot);
+           status = 0;
+           changed = vr->changed;
+         }
diff --git a/debian/patches/0008-g10-Fix-crash.patch b/debian/patches/0008-g10-Fix-crash.patch
new file mode 100644
index 0000000..70878de
--- /dev/null
+++ b/debian/patches/0008-g10-Fix-crash.patch
@@ -0,0 +1,43 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 21 Jul 2016 11:49:33 +0200
+Subject: g10: Fix crash.
+
+* g10/tofu.c (tofu_closedbs): Fix freeing database handles up to the
+cache limit.  Previously, this would crash if db_cache_count == count.
+
+Reported-by: Ben Kibbey <bjk at luxsci.net>
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ g10/tofu.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/g10/tofu.c b/g10/tofu.c
+index 471aec6..0b9d848 100644
+--- a/g10/tofu.c
++++ b/g10/tofu.c
+@@ -1104,8 +1104,14 @@ tofu_closedbs (ctrl_t ctrl)
+              is easy to skip the first COUNT entries since we still
+              have a handle on the old head.  */
+           int skip = DB_CACHE_ENTRIES - count;
+-          while (-- skip > 0)
+-            old_head = old_head->next;
++          if (skip < 0)
++            for (old_head = db_cache, skip = DB_CACHE_ENTRIES;
++                 skip > 0;
++                 old_head = old_head->next, skip--)
++              { /* Do nothing.  */ }
++          else
++            while (-- skip > 0)
++              old_head = old_head->next;
+ 
+           *old_head->prevp = NULL;
+ 
+@@ -1116,6 +1122,8 @@ tofu_closedbs (ctrl_t ctrl)
+               old_head = db;
+               db_cache_count --;
+             }
++
++          log_assert (db_cache_count == DB_CACHE_ENTRIES);
+         }
+     }
+ 
diff --git a/debian/patches/0009-g10-Drop-superfluous-begin-transaction.patch b/debian/patches/0009-g10-Drop-superfluous-begin-transaction.patch
new file mode 100644
index 0000000..54b1b89
--- /dev/null
+++ b/debian/patches/0009-g10-Drop-superfluous-begin-transaction.patch
@@ -0,0 +1,38 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 21 Jul 2016 18:07:22 +0200
+Subject: g10: Drop superfluous begin transaction.
+
+* g10/tofu.c (record_binding): We only need a transaction for the
+split format.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ g10/tofu.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+diff --git a/g10/tofu.c b/g10/tofu.c
+index 0b9d848..847c023 100644
+--- a/g10/tofu.c
++++ b/g10/tofu.c
+@@ -1199,6 +1199,7 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
+        only place where we start two transaction and we always start
+        transaction on the DB_KEY DB first, thus deadlock is not
+        possible.  */
++    /* We only need a transaction for the split format.  */
+     {
+       db_key = getdb (dbs, fingerprint, DB_KEY);
+       if (! db_key)
+@@ -1215,13 +1216,6 @@ record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
+       if (rc)
+         goto out_revert_one;
+     }
+-  else
+-    {
+-      rc = begin_transaction (db_email, 1);
+-      if (rc)
+-        goto leave;
+-    }
+-
+ 
+   if (show_old)
+     /* Get the old policy.  Since this is just for informational
diff --git a/debian/patches/0010-g10-Fix-error-handling.patch b/debian/patches/0010-g10-Fix-error-handling.patch
new file mode 100644
index 0000000..ff627fd
--- /dev/null
+++ b/debian/patches/0010-g10-Fix-error-handling.patch
@@ -0,0 +1,32 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 21 Jul 2016 18:22:18 +0200
+Subject: g10: Fix error handling.
+
+* g10/tofu.c (show_statistics): Fix error handling, 0 is a valid
+duration.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ g10/tofu.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/g10/tofu.c b/g10/tofu.c
+index 847c023..a2732ff 100644
+--- a/g10/tofu.c
++++ b/g10/tofu.c
+@@ -2504,12 +2504,12 @@ show_statistics (tofu_dbs_t dbs, const char *fingerprint,
+         }
+       else
+ 	{
+-          string_to_long (&first_seen_ago, strlist->next->d, 0, __LINE__);
+-	  string_to_long (&most_recent_seen_ago, strlist->next->next->d, 0,
++          string_to_long (&first_seen_ago, strlist->next->d, -1, __LINE__);
++	  string_to_long (&most_recent_seen_ago, strlist->next->next->d, -1,
+                           __LINE__);
+ 	}
+ 
+-      if (messages == -1 || first_seen_ago == 0)
++      if (messages == -1 || first_seen_ago == -1)
+         {
+           write_stats_status (0, TOFU_POLICY_NONE, -1, -1);
+           log_info (_("Failed to collect signature statistics for \"%s\"\n"
diff --git a/debian/patches/0011-g10-Properly-ignore-legacy-keys-in-the-keyring-cache.patch b/debian/patches/0011-g10-Properly-ignore-legacy-keys-in-the-keyring-cache.patch
new file mode 100644
index 0000000..0c1bbb5
--- /dev/null
+++ b/debian/patches/0011-g10-Properly-ignore-legacy-keys-in-the-keyring-cache.patch
@@ -0,0 +1,464 @@
+From: Justus Winter <justus at g10code.com>
+Date: Fri, 22 Jul 2016 13:29:26 +0200
+Subject: g10: Properly ignore legacy keys in the keyring cache.
+
+* g10/keyring.c (keyring_rebuild_cache): Properly ignore legacy keys
+in the keyring cache.
+* tests/migrations/Makefile.am (TESTS): Add new test.
+* tests/migrations/common.scm (GPG-no-batch): New variable.
+(run-test): New function.
+* tests/migrations/issue2276.scm: New file.
+* tests/migrations/issue2276.tar.asc: Likewise.
+
+GnuPG-bug-id: 2276
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ g10/keyring.c                      |   5 +-
+ tests/migrations/Makefile.am       |   6 +-
+ tests/migrations/common.scm        |  13 ++
+ tests/migrations/issue2276.scm     |  32 ++++
+ tests/migrations/issue2276.tar.asc | 326 +++++++++++++++++++++++++++++++++++++
+ 5 files changed, 376 insertions(+), 6 deletions(-)
+ create mode 100755 tests/migrations/issue2276.scm
+ create mode 100644 tests/migrations/issue2276.tar.asc
+
+diff --git a/g10/keyring.c b/g10/keyring.c
+index 843975e..0611b2e 100644
+--- a/g10/keyring.c
++++ b/g10/keyring.c
+@@ -1455,7 +1455,7 @@ keyring_rebuild_cache (void *token,int noisy)
+ 
+   for (;;)
+     {
+-      rc = keyring_search (hd, &desc, 1, NULL, 0);
++      rc = keyring_search (hd, &desc, 1, NULL, 1 /* ignore_legacy */);
+       if (rc)
+         break;  /* ready.  */
+ 
+@@ -1492,9 +1492,6 @@ keyring_rebuild_cache (void *token,int noisy)
+             goto leave;
+         }
+ 
+-      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+-        continue;
+-
+       release_kbnode (keyblock);
+       rc = keyring_get_keyblock (hd, &keyblock);
+       if (rc)
+diff --git a/tests/migrations/Makefile.am b/tests/migrations/Makefile.am
+index 9c82d66..ce9eb45 100644
+--- a/tests/migrations/Makefile.am
++++ b/tests/migrations/Makefile.am
+@@ -34,10 +34,12 @@ TESTS_ENVIRONMENT = GPG_AGENT_INFO= LC_ALL=C \
+ 	GPGSCM_PATH=$(top_srcdir)/tests/gpgscm:$(top_srcdir)/tests/migrations
+ 
+ TESTS = from-classic.scm \
+-	extended-pkf.scm
++	extended-pkf.scm \
++	issue2276.scm
+ 
+ TEST_FILES = from-classic.tar.asc \
+-	     extended-pkf.tar.asc
++	     extended-pkf.tar.asc \
++	     issue2276.tar.asc
+ 
+ EXTRA_DIST = common.scm $(TESTS) $(TEST_FILES)
+ 
+diff --git a/tests/migrations/common.scm b/tests/migrations/common.scm
+index 79f69e5..944d4f6 100644
+--- a/tests/migrations/common.scm
++++ b/tests/migrations/common.scm
+@@ -30,6 +30,9 @@
+ 	      --no-secmem-warning --batch
+ 	      ,(string-append "--agent-program=" GPG-AGENT
+ 			      "|--debug-quick-random")))
++(define GPG-no-batch
++  (filter (lambda (arg) (not (equal? arg '--batch))) GPG))
++
+ (define GPGTAR (qualify (string-append (getcwd) "/../../tools/gpgtar")))
+ 
+ (define (untar-armored source-name)
+@@ -37,3 +40,13 @@
+    (pipe:open source-name (logior O_RDONLY O_BINARY))
+    (pipe:spawn `(, at GPG --dearmor))
+    (pipe:spawn `(,GPGTAR --extract --directory=. -))))
++
++(define (run-test message src-tarball test)
++  (catch (skip "gpgtar not built")
++	 (call-check `(,GPGTAR --help)))
++
++  (with-temporary-working-directory
++   (info message)
++   (untar-armored src-tarball)
++   (setenv "GNUPGHOME" (getcwd) #t)
++   (test (getcwd))))
+diff --git a/tests/migrations/issue2276.scm b/tests/migrations/issue2276.scm
+new file mode 100755
+index 0000000..9a0c160
+--- /dev/null
++++ b/tests/migrations/issue2276.scm
+@@ -0,0 +1,32 @@
++#!/usr/bin/env gpgscm
++
++;; Copyright (C) 2016 g10 Code GmbH
++;;
++;; This file is part of GnuPG.
++;;
++;; GnuPG is free software; you can redistribute it and/or modify
++;; it under the terms of the GNU General Public License as published by
++;; the Free Software Foundation; either version 3 of the License, or
++;; (at your option) any later version.
++;;
++;; GnuPG is distributed in the hope that it will be useful,
++;; but WITHOUT ANY WARRANTY; without even the implied warranty of
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++;; GNU General Public License for more details.
++;;
++;; You should have received a copy of the GNU General Public License
++;; along with this program; if not, see <http://www.gnu.org/licenses/>.
++
++(load (with-path "common.scm"))
++
++(run-test
++ "Checking migration with legacy key (issue2276)..."
++ ;; This tarball contains a keyring with a legacy key.
++ (in-srcdir "issue2276.tar.asc")
++ (lambda (gpghome)
++   ;; GnuPG up to 2.1.14 failed to skip the legacy key when updating
++   ;; the trust database and thereby rebuilding the keyring cache.
++   (call-check `(, at GPG-no-batch --check-trustdb))
++
++   ;; Check that the other key is fine.
++   (call-check `(, at GPG --list-keys alpha))))
+diff --git a/tests/migrations/issue2276.tar.asc b/tests/migrations/issue2276.tar.asc
+new file mode 100644
+index 0000000..7890e40
+--- /dev/null
++++ b/tests/migrations/issue2276.tar.asc
+@@ -0,0 +1,326 @@
++-----BEGIN PGP ARMORED FILE-----
++Version: GnuPG v2
++Comment: Use "gpg --dearmor" for unpacking
++
++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
++PfCkoPx8BumENc26EIIdRB3EoSGwAgAAmQGiBDbjjp4RBAC2ZbFDX0wmJI8yLDYQ
++dIiZeAuHLmfyHsqXaLGUMZtWiAvn/hNpctwahmzKm5oXinHUvUkLOQ0s8rOlu15n
++hw4azc30rTP1LsIkn5zORNnFdgYC6RKyhOeim/63+/yGtdnTm49lVfaCqwsEmBCE
++kXaeWDGq+ie1b89J89T6n/JquwCgoQkjVeVGG+B/SzJ6+yifdHWQVkcD/RXDyLXX
++4+WHGP2aet51XlKojWGwsZmc9LPPYhwU/RcUO7ce1QQb0XFlUVFBhY0JQpM/ty/k
++Ni+aGWFzigbQ+HAWZkUvA8+VIAVneN+p+SHhGIyLTXKpAYTq46AwvllZ5Cpvf02C
++p/+W1aVyA0qnBWMyeIxXmR9HOi6lxxn5cjajA/9VZufOXWqCXkBvz4Oy3Q5FbjQQ
++0/+ty8rDn8OTaiPi41FyUnEi6LO+qyBS09FjnZj++PkcRcXW99SNxmEJRY7MuNHt
++5wIvEH2jNEOJ9lszzZFBDbuwsjXHK35+lPbGEy69xCP26iEafysKKbRXJhE1C+tk
++8SnK+Gm62sivmK/5arQpQWxwaGEgVGVzdCAoZGVtbyBrZXkpIDxhbHBoYUBleGFt
++cGxlLm5ldD6IVQQTEQIAFQUCNuOOngMLCgMDFQMCAxYCAQIXgAAKCRAtcnzHaGl3
++NDl4AKCBLmRplv/8ZfSqep5IjqEAuaXvWwCgl6NEzT+/WewPTGcwZY+pLkycLv2w
++AgADiFUEExECABUFAjbjjp4DCwoDAxUDAgMWAgECF4AACgkQLXJ8x2hpdzQ5eACe
++K6Lhwfi6QpDYuQufYxxGtZGwDcwAoJnXbazUo9cj8kwsFMEYIT1KJhAksAIAA7QQ
++QWxpY2UgKGRlbW8ga2V5KYhVBBMRAgAVBQI247arAwsKAwMVAwIDFgIBAheAAAoJ
++EC1yfMdoaXc0J4wAn0x5RWtqCjklzo93B143k4zBvLftAKCFbrlxlNCUPVsGUir9
++AzxvP0A3gbACAAO0J0FsZmEgVGVzdCAoZGVtbyBrZXkpIDxhbGZhQGV4YW1wbGUu
++bmV0PohVBBMRAgAVBQI247hYAwsKAwMVAwIDFgIBAheAAAoJEC1yfMdoaXc0t8IA
++oJPwa6j+Vm5Vi3Nvuo8JZri4PJ/DAJ9dqbmaJdB8FdJnHfGh1rXK3y/JcrACAAO5
++AQ0ENuOPDxAEAJyN1x9X9LsjfX2Z8O9s7BzMO9OoOxFtvZw+FA0BuDs0WVYkq1Gu
++Z9/XiO0K30zvtZnlb7NMvBfz7xbLeYx+vKzy5xkq18+LE5dU+HKKdRQZKrrwgCsD
++y8tJRO447QsiLTksCDqPMaE32OCRBF5nKrG5vih7/cmEhf2CuAn+2yM3AAMHA/0Z
++5eYysaLnAwPeqQ9vNvUyrCxUEmrvl4svG7zkkg3ZcgAbDpDQUmnijt3gEBCoAzO3
++c41TU5wJaUNBEPGPWfKcTlmBEGJWjK50QQuA2diGncxIS5SDs+QVaf434a6/KFVQ
++cCmV7K8/T2S8/nuGJ/rIlFL5XovW6A/S9mYEjh2pD4hGBBgRAgAGBQI2448PAAoJ
++EC1yfMdoaXc0IKkAn3A15g/LjVXSoPwvb6iNyUp3apJ7AJ0cc1Xh4v4ie9zgirbx
++ax21fRqIKrACAAOTjMG8t+0AoIVuuXGU0JQ9WwZSKv0DPG8/QDeBsAIAA7QnQWxm
++YSBUZXN0IChkZW1vIGtleSkgPGFsZmFAZXhhbXBsZS5uZXQ+iFUEExECABUFAjbj
++uFgDCwoDAxUDAgMWAgECF4AACgkQLXJ8x2hpdzS3wgCgk/BrqP5WblWLc2+6jwlm
++uLg8n8MAn12puZol0HwV0nNlY3JpbmcuZ3BnAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNjAwADAwMDE3NTAAMDAwMTc1MAAwMDAw
++MDAwMDAwMAAxMjc0NDQwNjEyMQAwMTM1MzIAIDAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDB0ZXl0aG9v
++bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHRleXRob29uAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++dHJ1c3RkYi5ncGcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAADAwMDA2MDAAMDAwMTc1MAAwMDAxNzUwADAwMDAwMDAyMjYwADEyNzQ0NDA2
++MTMyADAxMzYwMwAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHRleXRob29uAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAdGV5dGhvb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZ3BnAwMBBQECAABXkgxa
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
++=YNes
++-----END PGP ARMORED FILE-----
diff --git a/debian/patches/0012-gpgscm-Make-function-more-general.patch b/debian/patches/0012-gpgscm-Make-function-more-general.patch
new file mode 100644
index 0000000..e0471b6
--- /dev/null
+++ b/debian/patches/0012-gpgscm-Make-function-more-general.patch
@@ -0,0 +1,26 @@
+From: Justus Winter <justus at g10code.com>
+Date: Fri, 22 Jul 2016 17:42:17 +0200
+Subject: gpgscm: Make function more general.
+
+* tests/gpgscm/tests.scm (in-srcdir): Accept more path fragments.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ tests/gpgscm/tests.scm | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tests/gpgscm/tests.scm b/tests/gpgscm/tests.scm
+index 58b1430..e14e0e3 100644
+--- a/tests/gpgscm/tests.scm
++++ b/tests/gpgscm/tests.scm
+@@ -180,8 +180,8 @@
+       path
+       (string-append (getcwd) "/" path)))
+ 
+-(define (in-srcdir what)
+-  (canonical-path (string-append (getenv "srcdir") "/" what)))
++(define (in-srcdir . names)
++  (canonical-path (apply path-join (cons (getenv "srcdir") names))))
+ 
+ ;; Try to find NAME in PATHS.  Returns the full path name on success,
+ ;; or raises an error.
diff --git a/debian/patches/0013-g10-Fix-key-import-statistics.patch b/debian/patches/0013-g10-Fix-key-import-statistics.patch
new file mode 100644
index 0000000..58a3986
--- /dev/null
+++ b/debian/patches/0013-g10-Fix-key-import-statistics.patch
@@ -0,0 +1,176 @@
+From: Justus Winter <justus at g10code.com>
+Date: Mon, 25 Jul 2016 12:41:28 +0200
+Subject: g10: Fix key import statistics.
+
+'transfer_secret_keys' collects statistics on a subkey-basis, while
+the other code does not.  This leads to inflated numbers when
+importing secret keys.  E.g. 'count' is incremented by the main
+parsing loop in 'import', and again in 'transfer_secret_keys', leading
+to a total of 3 if one key with two secret subkeys is imported.
+
+* g10/import.c (import_secret_one): Adjust to the fact that
+'transfer_secret_keys' collects subkey statistics.
+* tests/openpgp/Makefile.am (TESTS): Add new test.
+* tests/openpgp/issue2346.scm: New file.
+* tests/openpgp/samplekeys/issue2346.gpg: Likewise.
+
+GnuPG-bug-id: 2346
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ g10/import.c                           | 17 +++++++---
+ tests/openpgp/Makefile.am              |  1 +
+ tests/openpgp/issue2346.scm            | 33 ++++++++++++++++++++
+ tests/openpgp/samplekeys/issue2346.gpg | 57 ++++++++++++++++++++++++++++++++++
+ 4 files changed, 104 insertions(+), 4 deletions(-)
+ create mode 100755 tests/openpgp/issue2346.scm
+ create mode 100644 tests/openpgp/samplekeys/issue2346.gpg
+
+diff --git a/g10/import.c b/g10/import.c
+index 375bd03..b83f371 100644
+--- a/g10/import.c
++++ b/g10/import.c
+@@ -2067,8 +2067,11 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
+             {
+               gpg_error_t err;
+ 
+-	      nr_prev = stats->secret_imported;
+-              err = transfer_secret_keys (ctrl, stats, keyblock, batch, 0);
++              /* transfer_secret_keys collects subkey stats.  */
++              struct import_stats_s subkey_stats = {0};
++
++              err = transfer_secret_keys (ctrl, &subkey_stats, keyblock,
++                                          batch, 0);
+               if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
+                 {
+                   /* TRANSLATORS: For smartcard, each private key on
+@@ -2091,8 +2094,14 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
+                   if (!opt.quiet)
+                     log_info (_("key %s: secret key imported\n"),
+                               keystr_from_pk (pk));
+-		  if (stats->secret_imported > nr_prev)
+-		    status |= 1;
++		  if (subkey_stats.secret_imported)
++                    {
++                      status |= 1;
++                      stats->secret_imported += 1;
++                    }
++		  if (subkey_stats.secret_dups)
++                    stats->secret_dups += 1;
++
+                   if (is_status_enabled ())
+                     print_import_ok (pk, status);
+                   check_prefs (ctrl, node);
+diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am
+index f1dcf15..b65cc6d 100644
+--- a/tests/openpgp/Makefile.am
++++ b/tests/openpgp/Makefile.am
+@@ -83,6 +83,7 @@ TESTS = setup.scm \
+ 	export.scm \
+ 	ssh.scm \
+ 	issue2015.scm \
++	issue2346.scm \
+ 	finish.scm
+ 
+ 
+diff --git a/tests/openpgp/issue2346.scm b/tests/openpgp/issue2346.scm
+new file mode 100755
+index 0000000..b336566
+--- /dev/null
++++ b/tests/openpgp/issue2346.scm
+@@ -0,0 +1,33 @@
++#!/usr/bin/env gpgscm
++
++;; Copyright (C) 2016 g10 Code GmbH
++;;
++;; This file is part of GnuPG.
++;;
++;; GnuPG is free software; you can redistribute it and/or modify
++;; it under the terms of the GNU General Public License as published by
++;; the Free Software Foundation; either version 3 of the License, or
++;; (at your option) any later version.
++;;
++;; GnuPG is distributed in the hope that it will be useful,
++;; but WITHOUT ANY WARRANTY; without even the implied warranty of
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++;; GNU General Public License for more details.
++;;
++;; You should have received a copy of the GNU General Public License
++;; along with this program; if not, see <http://www.gnu.org/licenses/>.
++
++(load (with-path "defs.scm"))
++
++(define key (in-srcdir "samplekeys/issue2346.gpg"))
++(define old-home (getenv "GNUPGHOME"))
++
++(with-temporary-working-directory
++ (file-copy (path-join old-home "gpg.conf") "gpg.conf")
++ (file-copy (path-join old-home "gpg-agent.conf") "gpg-agent.conf")
++ (setenv "GNUPGHOME" "." #t)
++
++ (info "Checking import statistics (issue2346)...")
++ (let ((status (call-popen `(, at GPG --status-fd=1 --import ,key) "")))
++   (unless (string-contains? status "IMPORT_RES 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0")
++	   (error "Unexpected number of keys imported" status))))
+diff --git a/tests/openpgp/samplekeys/issue2346.gpg b/tests/openpgp/samplekeys/issue2346.gpg
+new file mode 100644
+index 0000000..cc2d5a8
+--- /dev/null
++++ b/tests/openpgp/samplekeys/issue2346.gpg
+@@ -0,0 +1,57 @@
++-----BEGIN PGP PRIVATE KEY BLOCK-----
++Version: GnuPG v2
++
++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
++=njf7
++-----END PGP PRIVATE KEY BLOCK-----
diff --git a/debian/patches/0014-common-Add-unit-test-for-exectool.patch b/debian/patches/0014-common-Add-unit-test-for-exectool.patch
new file mode 100644
index 0000000..0d102d6
--- /dev/null
+++ b/debian/patches/0014-common-Add-unit-test-for-exectool.patch
@@ -0,0 +1,264 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 26 Jul 2016 14:29:12 +0200
+Subject: common: Add unit test for exectool.
+
+* common/Makefile.am: Build new test.
+* common/t-exectool.c: New file.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/Makefile.am  |   3 +-
+ common/t-exectool.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 225 insertions(+), 1 deletion(-)
+ create mode 100644 common/t-exectool.c
+
+diff --git a/common/Makefile.am b/common/Makefile.am
+index 6f9d96d..759800b 100644
+--- a/common/Makefile.am
++++ b/common/Makefile.am
+@@ -160,7 +160,7 @@ module_tests = t-stringhelp t-timestuff \
+ 	       t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
+ 	       t-name-value t-ccparray t-recsel
+ if !HAVE_W32CE_SYSTEM
+-module_tests += t-exechelp
++module_tests += t-exechelp t-exectool
+ endif
+ if HAVE_W32_SYSTEM
+ module_tests += t-w32-reg
+@@ -196,6 +196,7 @@ t_helpfile_LDADD = $(t_common_ldadd)
+ t_sexputil_LDADD = $(t_common_ldadd)
+ t_b64_LDADD = $(t_common_ldadd)
+ t_exechelp_LDADD = $(t_common_ldadd)
++t_exectool_LDADD = $(t_common_ldadd)
+ t_session_env_LDADD = $(t_common_ldadd)
+ t_openpgp_oid_LDADD = $(t_common_ldadd)
+ t_ssh_utils_LDADD = $(t_common_ldadd)
+diff --git a/common/t-exectool.c b/common/t-exectool.c
+new file mode 100644
+index 0000000..bbbf8fa
+--- /dev/null
++++ b/common/t-exectool.c
+@@ -0,0 +1,223 @@
++/* t-exectool.c - Module test for exectool.c
++ * Copyright (C) 2016 g10 Code GmbH
++ *
++ * This file is part of GnuPG.
++ *
++ * GnuPG is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GnuPG is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <config.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <assert.h>
++#include <unistd.h>
++
++#include "util.h"
++#include "exectool.h"
++
++static int verbose;
++
++#define fail(msg, err)                                           \
++  do { fprintf (stderr, "%s:%d: %s failed: %s\n",                \
++                __FILE__,__LINE__, (msg), gpg_strerror (err));   \
++    exit (1);                                                    \
++  } while(0)
++
++static void
++test_executing_true (void)
++{
++  gpg_error_t err;
++  const char *argv[] = { "/bin/true", NULL };
++  char *result;
++  size_t len;
++
++  if (access (argv[0], X_OK))
++    {
++      fprintf (stderr, "skipping test: %s not executable: %s",
++               argv[0], strerror (errno));
++      return;
++    }
++
++  if (verbose)
++    fprintf (stderr, "Executing %s...\n", argv[0]);
++
++  err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
++  if (err)
++    fail ("gnupg_exec_tool", err);
++
++  assert (result);
++  assert (len == 0);
++  free (result);
++}
++
++static void
++test_executing_false (void)
++{
++  gpg_error_t err;
++  const char *argv[] = { "/bin/false", NULL };
++  char *result;
++  size_t len;
++
++  if (access (argv[0], X_OK))
++    {
++      fprintf (stderr, "skipping test: %s not executable: %s",
++               argv[0], strerror (errno));
++      return;
++    }
++
++  if (verbose)
++    fprintf (stderr, "Executing %s...\n", argv[0]);
++
++  err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
++  assert (err == GPG_ERR_GENERAL);
++}
++
++static void
++test_executing_cat (const char *vector)
++{
++  gpg_error_t err;
++  const char *argv[] = { "/bin/cat", NULL };
++  char *result;
++  size_t len;
++
++  if (access (argv[0], X_OK))
++    {
++      fprintf (stderr, "skipping test: %s not executable: %s",
++               argv[0], strerror (errno));
++      return;
++    }
++
++  if (verbose)
++    fprintf (stderr, "Executing %s...\n", argv[0]);
++
++  err = gnupg_exec_tool (argv[0], &argv[1], vector, &result, &len);
++  if (err)
++    fail ("gnupg_exec_tool", err);
++
++  assert (result);
++
++  /* gnupg_exec_tool returns the correct length... */
++  assert (len == strlen (vector));
++  /* ... but 0-terminates data for ease of use.  */
++  assert (result[len] == 0);
++
++  assert (strcmp (result, vector) == 0);
++  free (result);
++}
++
++
++static void
++test_catting_cat (void)
++{
++  gpg_error_t err;
++  const char *argv[] = { "/bin/cat", "/bin/cat", NULL };
++  char *result;
++  size_t len;
++  estream_t in;
++  char *reference, *p;
++  size_t reference_len;
++
++  if (access (argv[0], X_OK))
++    {
++      fprintf (stderr, "skipping test: %s not executable: %s",
++               argv[0], strerror (errno));
++      return;
++    }
++
++  in = es_fopen (argv[1], "r");
++  if (in == NULL)
++    {
++      fprintf (stderr, "skipping test: could not open %s: %s",
++               argv[1], strerror (errno));
++      return;
++    }
++
++  err = es_fseek (in, 0L, SEEK_END);
++  if (err)
++    {
++      fprintf (stderr, "skipping test: could not seek in %s: %s",
++               argv[1], gpg_strerror (err));
++      return;
++    }
++
++  reference_len = es_ftell (in);
++  err = es_fseek (in, 0L, SEEK_SET);
++  assert (!err || !"rewinding failed");
++
++  reference = malloc (reference_len);
++  assert (reference || !"allocating reference buffer failed");
++
++  for (p = reference; p - reference < reference_len; )
++    {
++      size_t bytes_read, left;
++      left = reference_len - (p - reference);
++      if (left > 4096)
++        left = 4096;
++      err = es_read (in, p, left, &bytes_read);
++      if (err)
++        {
++          fprintf (stderr, "error reading %s: %s",
++                   argv[1], gpg_strerror (err));
++          exit (1);
++        }
++
++      p += bytes_read;
++    }
++  es_fclose (in);
++
++  if (verbose)
++    fprintf (stderr, "Executing %s %s...\n", argv[0], argv[1]);
++
++  err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
++  if (err)
++    fail ("gnupg_exec_tool", err);
++
++  assert (result);
++
++  /* gnupg_exec_tool returns the correct length... */
++  assert (len == reference_len);
++  assert (memcmp (result, reference, reference_len) == 0);
++  free (reference);
++  free (result);
++}
++
++
++int
++main (int argc, char **argv)
++{
++  int i;
++  char binjunk[256];
++
++  if (argc)
++    { argc--; argv++; }
++  if (argc && !strcmp (argv[0], "--verbose"))
++    {
++      verbose = 1;
++      argc--; argv++;
++    }
++
++  test_executing_true ();
++  test_executing_false ();
++  test_executing_cat ("Talking to myself here...");
++
++  for (i = 0; i < 255 /* one less */; i++)
++    binjunk[i] = i + 1;	/* avoid 0 */
++  binjunk[255] = 0;
++
++  test_executing_cat (binjunk);
++  test_catting_cat ();
++
++  return 0;
++}
diff --git a/debian/patches/0015-common-Rework-resource-cleanup-when-handling-errors.patch b/debian/patches/0015-common-Rework-resource-cleanup-when-handling-errors.patch
new file mode 100644
index 0000000..5852bac
--- /dev/null
+++ b/debian/patches/0015-common-Rework-resource-cleanup-when-handling-errors.patch
@@ -0,0 +1,77 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 26 Jul 2016 14:31:11 +0200
+Subject: common: Rework resource cleanup when handling errors.
+
+* common/exectool.c (gnupg_exec_tool_stream): Rework error handling.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/exectool.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+diff --git a/common/exectool.c b/common/exectool.c
+index b43e7cb..9c1cf65 100644
+--- a/common/exectool.c
++++ b/common/exectool.c
+@@ -1,5 +1,6 @@
+ /* exectool.c - Utility functions to execute a helper tool
+  * Copyright (C) 2015 Werner Koch
++ * Copyright (C) 2016 g10 Code GmbH
+  *
+  * This file is part of GnuPG.
+  *
+@@ -303,10 +304,10 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+                         void *status_cb_value)
+ {
+   gpg_error_t err;
+-  pid_t pid;
++  pid_t pid = (pid_t) -1;
+   estream_t infp = NULL;
+   estream_t extrafp = NULL;
+-  estream_t outfp, errfp;
++  estream_t outfp = NULL, errfp = NULL;
+   es_poll_t fds[4];
+   int exceptclose[2];
+   int extrapipe[2] = {-1, -1};
+@@ -329,7 +330,10 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+   fderrstate.buffer_size = 256;
+   fderrstate.buffer = xtrymalloc (fderrstate.buffer_size);
+   if (!fderrstate.buffer)
+-    return my_error_from_syserror ();
++    {
++      err = my_error_from_syserror ();
++      goto leave;
++    }
+ 
+   if (inextra)
+     {
+@@ -338,8 +342,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+         {
+           log_error ("error running outbound pipe for extra fp: %s\n",
+                      gpg_strerror (err));
+-          xfree (fderrstate.buffer);
+-          return err;
++          goto leave;
+         }
+       exceptclose[0] = extrapipe[0]; /* Do not close in child. */
+       exceptclose[1] = -1;
+@@ -369,9 +372,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+   if (err)
+     {
+       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
+-      es_fclose (extrafp);
+-      xfree (fderrstate.buffer);
+-      return err;
++      goto leave;
+     }
+ 
+   fds[0].stream = infp;
+@@ -494,7 +495,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+   pid = (pid_t)(-1);
+ 
+  leave:
+-  if (err)
++  if (err && pid != (pid_t) -1)
+     gnupg_kill_process (pid);
+ 
+   es_fclose (infp);
diff --git a/debian/patches/0016-common-Avoid-excessive-stack-use.patch b/debian/patches/0016-common-Avoid-excessive-stack-use.patch
new file mode 100644
index 0000000..a1dcc9c
--- /dev/null
+++ b/debian/patches/0016-common-Avoid-excessive-stack-use.patch
@@ -0,0 +1,135 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 26 Jul 2016 14:49:02 +0200
+Subject: common: Avoid excessive stack use.
+
+* common/exectool.c (copy_buffer_shred): Make passing NULL a nop.
+(gnupg_exec_tool_stream): Allocate copy buffers from the heap.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/exectool.c | 53 +++++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 39 insertions(+), 14 deletions(-)
+
+diff --git a/common/exectool.c b/common/exectool.c
+index 9c1cf65..e46071c 100644
+--- a/common/exectool.c
++++ b/common/exectool.c
+@@ -214,6 +214,8 @@ copy_buffer_init (struct copy_buffer *c)
+ static void
+ copy_buffer_shred (struct copy_buffer *c)
+ {
++  if (c == NULL)
++    return;
+   wipememory (c->buffer, sizeof c->buffer);
+   c->writep = NULL;
+   c->nread = ~0U;
+@@ -316,13 +318,34 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+   int argsaveidx;
+   int count;
+   read_and_log_buffer_t fderrstate;
+-  struct copy_buffer cpbuf_in, cpbuf_out, cpbuf_extra; /* Fixme: malloc them. */
++  struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
+ 
+   memset (fds, 0, sizeof fds);
+   memset (&fderrstate, 0, sizeof fderrstate);
+-  copy_buffer_init (&cpbuf_in);
+-  copy_buffer_init (&cpbuf_out);
+-  copy_buffer_init (&cpbuf_extra);
++
++  cpbuf_in = xtrymalloc (sizeof *cpbuf_in);
++  if (cpbuf_in == NULL)
++    {
++      err = my_error_from_syserror ();
++      goto leave;
++    }
++  copy_buffer_init (cpbuf_in);
++
++  cpbuf_out = xtrymalloc (sizeof *cpbuf_out);
++  if (cpbuf_out == NULL)
++    {
++      err = my_error_from_syserror ();
++      goto leave;
++    }
++  copy_buffer_init (cpbuf_out);
++
++  cpbuf_extra = xtrymalloc (sizeof *cpbuf_extra);
++  if (cpbuf_extra == NULL)
++    {
++      err = my_error_from_syserror ();
++      goto leave;
++    }
++  copy_buffer_init (cpbuf_extra);
+ 
+   fderrstate.pgmname = pgmname;
+   fderrstate.status_cb = status_cb;
+@@ -408,7 +431,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+ 
+       if (fds[0].got_write)
+         {
+-          err = copy_buffer_do_copy (&cpbuf_in, input, fds[0].stream);
++          err = copy_buffer_do_copy (cpbuf_in, input, fds[0].stream);
+           if (err)
+             {
+               log_error ("error feeding data to '%s': %s\n",
+@@ -418,7 +441,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+ 
+           if (es_feof (input))
+             {
+-              err = copy_buffer_flush (&cpbuf_in, fds[0].stream);
++              err = copy_buffer_flush (cpbuf_in, fds[0].stream);
+               if (err)
+                 {
+                   log_error ("error feeding data to '%s': %s\n",
+@@ -434,7 +457,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+       if (fds[3].got_write)
+         {
+           log_assert (inextra);
+-          err = copy_buffer_do_copy (&cpbuf_extra, inextra, fds[3].stream);
++          err = copy_buffer_do_copy (cpbuf_extra, inextra, fds[3].stream);
+           if (err)
+             {
+               log_error ("error feeding data to '%s': %s\n",
+@@ -444,7 +467,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+ 
+           if (es_feof (inextra))
+             {
+-              err = copy_buffer_flush (&cpbuf_extra, fds[3].stream);
++              err = copy_buffer_flush (cpbuf_extra, fds[3].stream);
+               if (err)
+                 {
+                   log_error ("error feeding data to '%s': %s\n",
+@@ -459,7 +482,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+ 
+       if (fds[1].got_read)
+         {
+-          err = copy_buffer_do_copy (&cpbuf_out, fds[1].stream, output);
++          err = copy_buffer_do_copy (cpbuf_out, fds[1].stream, output);
+           if (err)
+             {
+               log_error ("error reading data from '%s': %s\n",
+@@ -469,7 +492,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+ 
+           if (es_feof (fds[1].stream))
+             {
+-              err = copy_buffer_flush (&cpbuf_out, output);
++              err = copy_buffer_flush (cpbuf_out, output);
+               if (err)
+                 {
+                   log_error ("error reading data from '%s': %s\n",
+@@ -506,10 +529,12 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+     gnupg_wait_process (pgmname, pid, 1, NULL);
+   gnupg_release_process (pid);
+ 
+-  copy_buffer_shred (&cpbuf_in);
+-  copy_buffer_shred (&cpbuf_out);
+-  if (inextra)
+-    copy_buffer_shred (&cpbuf_extra);
++  copy_buffer_shred (cpbuf_in);
++  xfree (cpbuf_in);
++  copy_buffer_shred (cpbuf_out);
++  xfree (cpbuf_out);
++  copy_buffer_shred (cpbuf_extra);
++  xfree (cpbuf_extra);
+   xfree (fderrstate.buffer);
+   return err;
+ }
diff --git a/debian/patches/0017-include-upstream-tests-openpgp-run-tests.scm.patch b/debian/patches/0017-include-upstream-tests-openpgp-run-tests.scm.patch
new file mode 100644
index 0000000..5795ba6
--- /dev/null
+++ b/debian/patches/0017-include-upstream-tests-openpgp-run-tests.scm.patch
@@ -0,0 +1,224 @@
+From: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+Date: Sat, 30 Jul 2016 13:26:03 -0400
+Subject: include upstream tests/openpgp/run-tests.scm
+
+---
+ tests/openpgp/run-tests.scm | 209 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 209 insertions(+)
+ create mode 100644 tests/openpgp/run-tests.scm
+
+diff --git a/tests/openpgp/run-tests.scm b/tests/openpgp/run-tests.scm
+new file mode 100644
+index 0000000..a921fdb
+--- /dev/null
++++ b/tests/openpgp/run-tests.scm
+@@ -0,0 +1,209 @@
++;; Test-suite runner.
++;;
++;; Copyright (C) 2016 g10 Code GmbH
++;;
++;; This file is part of GnuPG.
++;;
++;; GnuPG is free software; you can redistribute it and/or modify
++;; it under the terms of the GNU General Public License as published by
++;; the Free Software Foundation; either version 3 of the License, or
++;; (at your option) any later version.
++;;
++;; GnuPG is distributed in the hope that it will be useful,
++;; but WITHOUT ANY WARRANTY; without even the implied warranty of
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++;; GNU General Public License for more details.
++;;
++;; You should have received a copy of the GNU General Public License
++;; along with this program; if not, see <http://www.gnu.org/licenses/>.
++
++(if (string=? "" (getenv "srcdir"))
++    (begin
++      (echo "Environment variable 'srcdir' not set.  Please point it to"
++	    "tests/openpgp.")
++      (exit 2)))
++
++;; Set objdir so that the tests can locate built programs.
++(setenv "objdir" (getcwd) #f)
++
++(define test-pool
++  (package
++   (define (new procs)
++     (package
++      (define (add test)
++	(new (cons test procs)))
++      (define (wait)
++	(let ((unfinished (filter (lambda (t) (not t::retcode)) procs)))
++	  (if (null? unfinished)
++	      (package)
++	      (let* ((commands (map (lambda (t) t::command) unfinished))
++		     (pids (map (lambda (t) t::pid) unfinished))
++		     (results
++		      (map (lambda (pid retcode) (list pid retcode))
++			   pids
++			   (wait-processes (map stringify commands) pids #t))))
++		(new
++		 (map (lambda (t)
++			(if t::retcode
++			    t
++			    (t::set-retcode (cadr (assoc t::pid results)))))
++		      procs))))))
++      (define (passed)
++	(filter (lambda (p) (= 0 p::retcode)) procs))
++      (define (skipped)
++	(filter (lambda (p) (= 77 p::retcode)) procs))
++      (define (hard-errored)
++	(filter (lambda (p) (= 99 p::retcode)) procs))
++      (define (failed)
++	(filter (lambda (p)
++		  (not (or (= 0 p::retcode) (= 77 p::retcode)
++			   (= 99 p::retcode))))
++		procs))
++      (define (report)
++	(echo (length procs) "tests run,"
++	      (length (passed)) "succeeded,"
++	      (length (failed)) "failed,"
++	      (length (skipped)) "skipped.")
++	(length (failed)))))))
++
++(define (verbosity n)
++  (if (= 0 n) '() (cons '--verbose (verbosity (- n 1)))))
++
++(define test
++  (package
++   (define (scm name . args)
++     (new name #f `(,*argv0* ,@(verbosity *verbose*) , at args
++			     ,(in-srcdir name)) #f #f))
++   (define (new name directory command pid retcode)
++     (package
++      (define (set-directory x)
++	(new name x command pid retcode))
++      (define (set-retcode x)
++	(new name directory command pid x))
++      (define (set-pid x)
++	(new name directory command x retcode))
++      (define (run-sync)
++	(with-working-directory directory
++	  (let* ((p (inbound-pipe))
++		 (pid (spawn-process-fd command CLOSED_FD
++					(:write-end p) (:write-end p))))
++	    (close (:write-end p))
++	    (splice (:read-end p) STDERR_FILENO)
++	    (close (:read-end p))
++	    (let ((t' (set-retcode (wait-process name pid #t))))
++	      (t'::report)
++	      t'))))
++      (define (run-sync-quiet)
++	(with-working-directory directory
++	  (set-retcode
++	   (wait-process
++	    name (spawn-process-fd command CLOSED_FD CLOSED_FD CLOSED_FD) #t))))
++      (define (run-async)
++	(with-working-directory directory
++	  (set-pid (spawn-process-fd command CLOSED_FD CLOSED_FD CLOSED_FD))))
++      (define (status)
++	(let ((t (assoc retcode '((0 "PASS") (77 "SKIP") (99 "ERROR")))))
++	  (if (not t) "FAIL" (cadr t))))
++      (define (report)
++	(echo (string-append (status retcode) ":") name))))))
++
++(define (run-tests-parallel-shared setup teardown . tests)
++  (setup::run-sync)
++  (let loop ((pool (test-pool::new '())) (tests' tests))
++    (if (null? tests')
++	(let ((results (pool::wait)))
++	  (for-each (lambda (t) (t::report)) results::procs)
++	  (teardown::run-sync)
++	  (exit (results::report)))
++	(let ((test (car tests')))
++	  (loop (pool::add (test::run-async)) (cdr tests'))))))
++
++(define (run-tests-parallel-isolated setup teardown . tests)
++  (let loop ((pool (test-pool::new '())) (tests' tests))
++    (if (null? tests')
++	(let ((results (pool::wait)))
++	  (for-each (lambda (t)
++		      (let ((teardown' (teardown::set-directory t::directory)))
++			(teardown'::run-sync-quiet))
++		      (unlink-recursively t::directory)
++		      (t::report)) results::procs)
++	  (exit (results::report)))
++	(let* ((wd (mkdtemp "gpgscm-XXXXXX"))
++	       (test (car tests'))
++	       (test' (test::set-directory wd))
++	       (setup' (setup::set-directory wd)))
++	  (setup'::run-sync-quiet)
++	  (loop (pool::add (test'::run-async)) (cdr tests'))))))
++
++(define (run-tests-sequential-shared setup teardown . tests)
++  (let loop ((pool (test-pool::new '()))
++	     (tests' `(,setup , at tests ,teardown)))
++    (if (null? tests')
++	(let ((results (pool::wait)))
++	  (exit (results::report)))
++	(let ((test (car tests')))
++	  (loop (pool::add (test::run-sync)) (cdr tests'))))))
++
++(define (run-tests-sequential-isolated setup teardown . tests)
++  (let loop ((pool (test-pool::new '())) (tests' tests))
++    (if (null? tests')
++	(let ((results (pool::wait)))
++	  (for-each (lambda (t)
++		      (let ((teardown' (teardown::set-directory t::directory)))
++			(teardown'::run-sync-quiet))
++		      (unlink-recursively t::directory))
++		    results::procs)
++	  (exit (results::report)))
++	(let* ((wd (mkdtemp "gpgscm-XXXXXX"))
++	       (test (car tests'))
++	       (test' (test::set-directory wd))
++	       (setup' (setup::set-directory wd)))
++	  (setup'::run-sync-quiet)
++	  (loop (pool::add (test'::run-sync)) (cdr tests'))))))
++
++(define all-tests
++  '("version.scm"
++    "mds.scm"
++    "decrypt.scm"
++    "decrypt-dsa.scm"
++    "sigs.scm"
++    "sigs-dsa.scm"
++    "encrypt.scm"
++    "encrypt-dsa.scm"
++    "seat.scm"
++    "clearsig.scm"
++    "encryptp.scm"
++    "detach.scm"
++    "detachm.scm"
++    "armsigs.scm"
++    "armencrypt.scm"
++    "armencryptp.scm"
++    "signencrypt.scm"
++    "signencrypt-dsa.scm"
++    "armsignencrypt.scm"
++    "armdetach.scm"
++    "armdetachm.scm"
++    "genkey1024.scm"
++    "conventional.scm"
++    "conventional-mdc.scm"
++    "multisig.scm"
++    "verify.scm"
++    "armor.scm"
++    "import.scm"
++    "ecc.scm"
++    "4gb-packet.scm"
++    "gpgtar.scm"
++    "use-exact-key.scm"
++    "default-key.scm"))
++
++(let* ((runner (if (member "--parallel" *args*)
++		  (if (member "--shared" *args*)
++		      run-tests-parallel-shared
++		      run-tests-parallel-isolated)
++		  (if (member "--shared" *args*)
++		      run-tests-sequential-shared
++		      run-tests-sequential-isolated)))
++       (tests' (filter (lambda (arg) (not (string-prefix? arg "--"))) *args*))
++       (tests (if (null? tests') all-tests tests')))
++  (apply runner (append (list (test::scm "setup.scm") (test::scm "finish.scm"))
++			(map test::scm tests))))
diff --git a/debian/patches/0018-gpgscm-Make-the-verbose-setting-more-useful.patch b/debian/patches/0018-gpgscm-Make-the-verbose-setting-more-useful.patch
new file mode 100644
index 0000000..2f935a9
--- /dev/null
+++ b/debian/patches/0018-gpgscm-Make-the-verbose-setting-more-useful.patch
@@ -0,0 +1,127 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 26 Jul 2016 15:53:50 +0200
+Subject: gpgscm: Make the verbose setting more useful.
+
+* tests/gpgscm/ffi.c (do_get_verbose): New function.
+(do_set_verbose): Likewise.
+(ffi_init): Turn *verbose* into a function, add *set-verbose!*.
+* tests/gpgscm/tests.scm (call): Adapt accordingly.
+(call-with-io): Dump output if *verbose* is high.
+(pipe-do): Adapt accordingly.
+* tests/openpgp/defs.scm: Set verbosity according to environment.
+* tests/openpgp/run-tests.scm (test): Adapt accordingly.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ tests/gpgscm/ffi.c          | 27 ++++++++++++++++++++++++++-
+ tests/gpgscm/tests.scm      | 11 ++++++++---
+ tests/openpgp/defs.scm      |  4 ++++
+ tests/openpgp/run-tests.scm |  2 +-
+ 4 files changed, 39 insertions(+), 5 deletions(-)
+
+diff --git a/tests/gpgscm/ffi.c b/tests/gpgscm/ffi.c
+index 5494c4d..c37bf1d 100644
+--- a/tests/gpgscm/ffi.c
++++ b/tests/gpgscm/ffi.c
+@@ -1052,6 +1052,30 @@ do_glob (scheme *sc, pointer args)
+ }
+ 
+ 

++
++static pointer
++do_get_verbose (scheme *sc, pointer args)
++{
++  FFI_PROLOG ();
++  FFI_ARGS_DONE_OR_RETURN (sc, args);
++  FFI_RETURN_INT (sc, verbose);
++}
++
++static pointer
++do_set_verbose (scheme *sc, pointer args)
++{
++  FFI_PROLOG ();
++  int new_verbosity, old;
++  FFI_ARG_OR_RETURN (sc, int, new_verbosity, number, args);
++  FFI_ARGS_DONE_OR_RETURN (sc, args);
++
++  old = verbose;
++  verbose = new_verbosity;
++
++  FFI_RETURN_INT (sc, old);
++}
++
++

+ gpg_error_t
+ ffi_list2argv (scheme *sc, pointer list, char ***argv, size_t *len)
+ {
+@@ -1260,7 +1284,8 @@ ffi_init (scheme *sc, const char *argv0, int argc, const char **argv)
+   ffi_define_function (sc, prompt);
+ 
+   /* Configuration.  */
+-  ffi_define (sc, "*verbose*", sc->vptr->mk_integer (sc, verbose));
++  ffi_define_function_name (sc, "*verbose*", get_verbose);
++  ffi_define_function_name (sc, "*set-verbose!*", set_verbose);
+ 
+   ffi_define (sc, "*argv0*", sc->vptr->mk_string (sc, argv0));
+   for (i = argc - 1; i >= 0; i--)
+diff --git a/tests/gpgscm/tests.scm b/tests/gpgscm/tests.scm
+index e14e0e3..f97b22e 100644
+--- a/tests/gpgscm/tests.scm
++++ b/tests/gpgscm/tests.scm
+@@ -92,8 +92,8 @@
+ (define (call what)
+   (call-with-fds what
+ 		 CLOSED_FD
+-		 (if (< *verbose* 0) STDOUT_FILENO CLOSED_FD)
+-		 (if (< *verbose* 0) STDERR_FILENO CLOSED_FD)))
++		 (if (< (*verbose*) 0) STDOUT_FILENO CLOSED_FD)
++		 (if (< (*verbose*) 0) STDERR_FILENO CLOSED_FD)))
+ 
+ ;; Accessor functions for the results of 'spawn-process'.
+ (define :stdin car)
+@@ -110,6 +110,11 @@
+ 	   (result (wait-process (car what) (:pid h) #t)))
+       (es-fclose (:stdout h))
+       (es-fclose (:stderr h))
++      (if (> (*verbose*) 2)
++	  (begin
++	    (echo (stringify what) "returned:" result)
++	    (echo (stringify what) "wrote to stdout:" out)
++	    (echo (stringify what) "wrote to stderr:" err)))
+       (list result out err))))
+ 
+ ;; Accessor function for the results of 'call-with-io'.  ':stdout' and
+@@ -360,7 +365,7 @@
+   (lambda (M)
+     (define (do-spawn M new-source)
+       (let ((pid (spawn-process-fd command M::source M::sink
+-				   (if (> *verbose* 0)
++				   (if (> (*verbose*) 0)
+ 				       STDERR_FILENO CLOSED_FD)))
+ 	    (M' (M::set-source new-source)))
+ 	(M'::add-proc command pid)))
+diff --git a/tests/openpgp/defs.scm b/tests/openpgp/defs.scm
+index 8ceffc8..06bc0b8 100644
+--- a/tests/openpgp/defs.scm
++++ b/tests/openpgp/defs.scm
+@@ -132,3 +132,7 @@
+        (list (string->number (cadr p)) (caddr p))))
+    (string-split
+     (call-popen `(, at GPG --with-colons , at args) input) #\newline)))
++
++(let ((verbose (string->number (getenv "verbose"))))
++  (if (number? verbose)
++      (*set-verbose!* verbose)))
+diff --git a/tests/openpgp/run-tests.scm b/tests/openpgp/run-tests.scm
+index a921fdb..ad94baf 100644
+--- a/tests/openpgp/run-tests.scm
++++ b/tests/openpgp/run-tests.scm
+@@ -72,7 +72,7 @@
+ (define test
+   (package
+    (define (scm name . args)
+-     (new name #f `(,*argv0* ,@(verbosity *verbose*) , at args
++     (new name #f `(,*argv0* ,@(verbosity (*verbose*)) , at args
+ 			     ,(in-srcdir name)) #f #f))
+    (define (new name directory command pid retcode)
+      (package
diff --git a/debian/patches/0019-gpgscm-Do-not-shadow-common-function-name-in-catch-m.patch b/debian/patches/0019-gpgscm-Do-not-shadow-common-function-name-in-catch-m.patch
new file mode 100644
index 0000000..0605208
--- /dev/null
+++ b/debian/patches/0019-gpgscm-Do-not-shadow-common-function-name-in-catch-m.patch
@@ -0,0 +1,26 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 26 Jul 2016 18:35:58 +0200
+Subject: gpgscm: Do not shadow common function name in catch macro.
+
+* tests/gpgscm/init.scm (catch): Do not shadow 'exit'.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ tests/gpgscm/init.scm | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tests/gpgscm/init.scm b/tests/gpgscm/init.scm
+index 0889366..b32172b 100644
+--- a/tests/gpgscm/init.scm
++++ b/tests/gpgscm/init.scm
+@@ -572,8 +572,8 @@
+ 
+ (macro (catch form)
+      (let ((label (gensym)))
+-          `(call/cc (lambda (exit)
+-               (push-handler (lambda (*error*) (exit ,(cadr form))))
++          `(call/cc (lambda (**exit**)
++               (push-handler (lambda (*error*) (**exit** ,(cadr form))))
+                (let ((,label (begin ,@(cddr form))))
+                     (pop-handler)
+                     ,label)))))
diff --git a/debian/patches/0020-common-Fix-iobuf_peek-corner-case.patch b/debian/patches/0020-common-Fix-iobuf_peek-corner-case.patch
new file mode 100644
index 0000000..4e98817
--- /dev/null
+++ b/debian/patches/0020-common-Fix-iobuf_peek-corner-case.patch
@@ -0,0 +1,178 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 26 Jul 2016 18:29:01 +0200
+Subject: common: Fix iobuf_peek corner case.
+
+Previously, iobuf_peek on a file smaller than 'buflen' would hang.
+
+* common/iobuf.c (underflow): Generalize by adding a target parameter.
+(iobuf_peek): Use this to prevent looping here.
+* tests/openpgp/Makefile.am (TESTS): Add new test.
+* tests/openpgp/setup.scm (dearmor): Move function...
+* tests/openpgp/defs.scm (dearmor): ... here.
+* tests/openpgp/issue2419.scm: New file.
+* tests/openpgp/samplemsgs/issue2419.asc: Likewise.
+
+GnuPG-bug-id: 2419
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ common/iobuf.c                         | 18 +++++++++++++++---
+ tests/openpgp/Makefile.am              |  1 +
+ tests/openpgp/defs.scm                 |  7 +++++++
+ tests/openpgp/issue2419.scm            | 28 ++++++++++++++++++++++++++++
+ tests/openpgp/samplemsgs/issue2419.asc |  7 +++++++
+ tests/openpgp/setup.scm                |  8 --------
+ 6 files changed, 58 insertions(+), 11 deletions(-)
+ create mode 100755 tests/openpgp/issue2419.scm
+ create mode 100644 tests/openpgp/samplemsgs/issue2419.asc
+
+diff --git a/common/iobuf.c b/common/iobuf.c
+index f3d67b4..9d582ca 100644
+--- a/common/iobuf.c
++++ b/common/iobuf.c
+@@ -162,6 +162,7 @@ static int special_names_enabled;
+ 
+ /* Local prototypes.  */
+ static int underflow (iobuf_t a, int clear_pending_eof);
++static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
+ static int translate_file_handle (int fd, int for_write);
+ 
+ /* Sends any pending data to the filter's FILTER function.  Note: this
+@@ -1769,12 +1770,23 @@ iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
+ 
+ 
+ /****************
+- * read underflow: read more bytes into the buffer and return
++ * read underflow: read at least one byte into the buffer and return
+  * the first byte or -1 on EOF.
+  */
+ static int
+ underflow (iobuf_t a, int clear_pending_eof)
+ {
++  return underflow_target (a, clear_pending_eof, 1);
++}
++
++
++/****************
++ * read underflow: read TARGET bytes into the buffer and return
++ * the first byte or -1 on EOF.
++ */
++static int
++underflow_target (iobuf_t a, int clear_pending_eof, size_t target)
++{
+   size_t len;
+   int rc;
+ 
+@@ -1799,7 +1811,7 @@ underflow (iobuf_t a, int clear_pending_eof)
+   memmove (a->d.buf, &a->d.buf[a->d.start], a->d.len);
+   a->d.start = 0;
+ 
+-  if (a->d.len == 0 && a->filter_eof)
++  if (a->d.len < target && a->filter_eof)
+     /* The last time we tried to read from this filter, we got an EOF.
+        We couldn't return the EOF, because there was buffered data.
+        Since there is no longer any buffered data, return the
+@@ -2090,7 +2102,7 @@ iobuf_peek (iobuf_t a, byte * buf, unsigned buflen)
+      request.  */
+   while (buflen > a->d.len - a->d.start)
+     {
+-      if (underflow (a, 0) == -1)
++      if (underflow_target (a, 0, buflen) == -1)
+ 	/* EOF.  We can't read any more.  */
+ 	break;
+ 
+diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am
+index b65cc6d..71457bf 100644
+--- a/tests/openpgp/Makefile.am
++++ b/tests/openpgp/Makefile.am
+@@ -84,6 +84,7 @@ TESTS = setup.scm \
+ 	ssh.scm \
+ 	issue2015.scm \
+ 	issue2346.scm \
++	issue2419.scm \
+ 	finish.scm
+ 
+ 
+diff --git a/tests/openpgp/defs.scm b/tests/openpgp/defs.scm
+index 06bc0b8..9408cd5 100644
+--- a/tests/openpgp/defs.scm
++++ b/tests/openpgp/defs.scm
+@@ -133,6 +133,13 @@
+    (string-split
+     (call-popen `(, at GPG --with-colons , at args) input) #\newline)))
+ 
++;; Dearmor a file.
++(define (dearmor source-name sink-name)
++  (pipe:do
++   (pipe:open source-name (logior O_RDONLY O_BINARY))
++   (pipe:spawn `(, at GPG --dearmor))
++   (pipe:write-to sink-name (logior O_WRONLY O_CREAT O_BINARY) #o600)))
++
+ (let ((verbose (string->number (getenv "verbose"))))
+   (if (number? verbose)
+       (*set-verbose!* verbose)))
+diff --git a/tests/openpgp/issue2419.scm b/tests/openpgp/issue2419.scm
+new file mode 100755
+index 0000000..efc42a6
+--- /dev/null
++++ b/tests/openpgp/issue2419.scm
+@@ -0,0 +1,28 @@
++#!/usr/bin/env gpgscm
++
++;; Copyright (C) 2016 g10 Code GmbH
++;;
++;; This file is part of GnuPG.
++;;
++;; GnuPG is free software; you can redistribute it and/or modify
++;; it under the terms of the GNU General Public License as published by
++;; the Free Software Foundation; either version 3 of the License, or
++;; (at your option) any later version.
++;;
++;; GnuPG is distributed in the hope that it will be useful,
++;; but WITHOUT ANY WARRANTY; without even the implied warranty of
++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++;; GNU General Public License for more details.
++;;
++;; You should have received a copy of the GNU General Public License
++;; along with this program; if not, see <http://www.gnu.org/licenses/>.
++
++(load (with-path "defs.scm"))
++
++(info "Checking iobuf_peek corner case (issue2419)...")
++(lettmp
++ (onebyte)
++ (dearmor (in-srcdir "samplemsgs/issue2419.asc") onebyte)
++ (catch (assert (string-contains? *error* "invalid packet"))
++	(call-popen `(, at GPG --list-packets ,onebyte) "")
++	(error "Expected an error but got none")))
+diff --git a/tests/openpgp/samplemsgs/issue2419.asc b/tests/openpgp/samplemsgs/issue2419.asc
+new file mode 100644
+index 0000000..b73efed
+--- /dev/null
++++ b/tests/openpgp/samplemsgs/issue2419.asc
+@@ -0,0 +1,7 @@
++-----BEGIN PGP ARMORED FILE-----
++Version: GnuPG v2
++Comment: Use "gpg --dearmor" for unpacking
++
++AA==
++=YWnT
++-----END PGP ARMORED FILE-----
+diff --git a/tests/openpgp/setup.scm b/tests/openpgp/setup.scm
+index 9ad19c2..8fc1543 100755
+--- a/tests/openpgp/setup.scm
++++ b/tests/openpgp/setup.scm
+@@ -55,14 +55,6 @@
+ 		     CLOSED_FD fd STDERR_FILENO)))
+   '(500 9000 32000 80000))
+ 
+-(define (dearmor source-name sink-name)
+-  (pipe:do
+-   (pipe:open source-name (logior O_RDONLY O_BINARY))
+-   (pipe:spawn `(, at GPG --dearmor))
+-   (pipe:write-to sink-name
+-		  (logior O_WRONLY O_CREAT O_BINARY)
+-		  #o600)))
+-
+ (for-each-p "Unpacking samples"
+   (lambda (name)
+     (dearmor (in-srcdir (string-append name "o.asc")) name))
diff --git a/debian/patches/0021-gpgsm-Fix-machine-readable-key-listing.patch b/debian/patches/0021-gpgsm-Fix-machine-readable-key-listing.patch
new file mode 100644
index 0000000..6ff6e5a
--- /dev/null
+++ b/debian/patches/0021-gpgsm-Fix-machine-readable-key-listing.patch
@@ -0,0 +1,24 @@
+From: Justus Winter <justus at g10code.com>
+Date: Mon, 1 Aug 2016 12:32:36 +0200
+Subject: gpgsm: Fix machine-readable key listing.
+
+* sm/keylist.c (list_cert_colon): Drop superfluous colon.
+
+GnuPG-bug-id: 2432
+Signed-off-by: Justus Winter <justus at g10code.com>
+---
+ sm/keylist.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/sm/keylist.c b/sm/keylist.c
+index dab1295..0d975c3 100644
+--- a/sm/keylist.c
++++ b/sm/keylist.c
+@@ -494,7 +494,6 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
+   es_putc (':', fp);
+   /* Field 12, capabilities: */
+   print_capabilities (cert, fp);
+-  es_putc (':', fp);
+   /* Field 13, not used: */
+   es_putc (':', fp);
+   if (have_secret || ctrl->with_secret)
diff --git a/debian/patches/series b/debian/patches/series
index 160913f..037694f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,21 @@
 0001-avoid-beta-warning.patch
 0002-Avoid-simple-memory-dumps-via-ptrace.patch
+0003-agent-Fix-passphrase-cache-lookups.patch
+0004-scd-Fix-race-conditions-for-release_application.patch
+0005-tests-Add-test-for-ssh-support.patch
+0006-agent-Add-known-keys-to-sshcontrol.patch
+0007-scd-Fix-card-removal-reset-on-multiple-contexts.patch
+0008-g10-Fix-crash.patch
+0009-g10-Drop-superfluous-begin-transaction.patch
+0010-g10-Fix-error-handling.patch
+0011-g10-Properly-ignore-legacy-keys-in-the-keyring-cache.patch
+0012-gpgscm-Make-function-more-general.patch
+0013-g10-Fix-key-import-statistics.patch
+0014-common-Add-unit-test-for-exectool.patch
+0015-common-Rework-resource-cleanup-when-handling-errors.patch
+0016-common-Avoid-excessive-stack-use.patch
+0017-include-upstream-tests-openpgp-run-tests.scm.patch
+0018-gpgscm-Make-the-verbose-setting-more-useful.patch
+0019-gpgscm-Do-not-shadow-common-function-name-in-catch-m.patch
+0020-common-Fix-iobuf_peek-corner-case.patch
+0021-gpgsm-Fix-machine-readable-key-listing.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