[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