From ddd69ff66c28f237ad262040a6cffc15be691a9e Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Mon, 25 Jul 2016 10:40:25 +0200 Subject: [PATCH] g10: Prefer keys requiring no further user interaction. * g10/call-agent.c (agent_set_pinentry_mode): New function. (start_agent): Use new function. * g10/call-agent.h (agent_set_pinentry_mode): New prototype. * g10/gpgv.c (agent_set_pinentry_mode): New stub. * g10/mainproc.c (proc_packets): Try with PINENTRY_MODE_CANCEL first. (proc_encryption_packets): Likewise. * g10/test-stubs.c (agent_set_pinentry_mode): New stub. * tests/openpgp/Makefile.am (TESTS): Add new test. * tests/openpgp/issue1955.scm: New file. GnuPG-bug-id: 1955 Signed-off-by: Justus Winter --- g10/call-agent.c | 54 ++++++++++++++++++++++++++----------- g10/call-agent.h | 2 ++ g10/gpgv.c | 5 ++++ g10/mainproc.c | 19 +++++++++++-- g10/test-stubs.c | 5 ++++ tests/openpgp/Makefile.am | 1 + tests/openpgp/issue1955.scm | 47 ++++++++++++++++++++++++++++++++ 7 files changed, 116 insertions(+), 17 deletions(-) create mode 100755 tests/openpgp/issue1955.scm diff --git a/g10/call-agent.c b/g10/call-agent.c index a023654bc..bd81811fc 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -285,6 +285,44 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode) return err; } +int +agent_set_pinentry_mode (int pinentry_mode, int *old_mode) +{ + int rc; + char *tmp; + + if (agent_ctx == NULL) + { + if (old_mode) + *old_mode = opt.pinentry_mode; + + opt.pinentry_mode = pinentry_mode; + return 0; + } + + tmp = xasprintf ("OPTION pinentry-mode=%s", + str_pinentry_mode (pinentry_mode)); + rc = assuan_transact (agent_ctx, tmp, + NULL, NULL, NULL, NULL, NULL, NULL); + xfree (tmp); + if (rc) + { + log_error ("setting pinentry mode '%s' failed: %s\n", + str_pinentry_mode (pinentry_mode), + gpg_strerror (rc)); + write_status_error ("set_pinentry_mode", rc); + } + else + { + if (old_mode) + *old_mode = opt.pinentry_mode; + + opt.pinentry_mode = pinentry_mode; + } + + return rc; +} + /* Try to connect to the agent via socket or fork it off and work by pipes. Handle the server's initial greeting */ @@ -332,21 +370,7 @@ start_agent (ctrl_t ctrl, int for_card) NULL, NULL, NULL, NULL, NULL, NULL); /* Pass on the pinentry mode. */ if (opt.pinentry_mode) - { - char *tmp = xasprintf ("OPTION pinentry-mode=%s", - str_pinentry_mode (opt.pinentry_mode)); - rc = assuan_transact (agent_ctx, tmp, - NULL, NULL, NULL, NULL, NULL, NULL); - xfree (tmp); - if (rc) - { - log_error ("setting pinentry mode '%s' failed: %s\n", - str_pinentry_mode (opt.pinentry_mode), - gpg_strerror (rc)); - write_status_error ("set_pinentry_mode", rc); - } - } - + agent_set_pinentry_mode (opt.pinentry_mode, NULL); check_hijacking (agent_ctx); } } diff --git a/g10/call-agent.h b/g10/call-agent.h index d85a6fd5d..154adfce2 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -123,6 +123,8 @@ int agent_scd_checkpin (const char *serialno); /* Dummy function, only implemented by gpg 1.4. */ void agent_clear_pin_cache (const char *sn); +/* XXX */ +int agent_set_pinentry_mode (int pinentry_mode, int *old_mode); /* Send the GET_PASSPHRASE command to the agent. */ gpg_error_t agent_get_passphrase (const char *cache_id, diff --git a/g10/gpgv.c b/g10/gpgv.c index d08dc5a7a..ee52a5e42 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -697,3 +697,8 @@ void tofu_end_batch_update (void) { } + +int +agent_set_pinentry_mode (int pinentry_mode, int *old_mode) +{ +} diff --git a/g10/mainproc.c b/g10/mainproc.c index 4217ccdb4..2ac8f7c51 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -39,6 +39,8 @@ #include "photoid.h" #include "mbox-util.h" #include "call-dirmngr.h" +#include "call-agent.h" +#include "../common/shareddefs.h" /* Put an upper limit on nested packets. The 32 is an arbitrary value, a much lower should actually be sufficient. */ @@ -1174,13 +1176,19 @@ int proc_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) { int rc; + int old_mode; CTX c = xmalloc_clear (sizeof *c); c->ctrl = ctrl; c->anchor = anchor; - rc = do_proc_packets (ctrl, c, a); - xfree (c); + agent_set_pinentry_mode (PINENTRY_MODE_CANCEL, &old_mode); + rc = do_proc_packets (ctrl, c, a); + agent_set_pinentry_mode (old_mode, NULL); + if (rc) + rc = do_proc_packets (ctrl, c, a); + + xfree (c); return rc; } @@ -1272,12 +1280,19 @@ int proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) { CTX c = xmalloc_clear (sizeof *c); + int old_mode; int rc; c->ctrl = ctrl; c->anchor = anchor; c->encrypt_only = 1; + + agent_set_pinentry_mode (PINENTRY_MODE_CANCEL, &old_mode); rc = do_proc_packets (ctrl, c, a); + agent_set_pinentry_mode (old_mode, NULL); + if (rc) + rc = do_proc_packets (ctrl, c, a); + xfree (c); return rc; } diff --git a/g10/test-stubs.c b/g10/test-stubs.c index 6f50759d5..f7ba387a8 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -505,3 +505,8 @@ void tofu_end_batch_update (void) { } + +int +agent_set_pinentry_mode (int pinentry_mode, int *old_mode) +{ +} diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am index f1dcf15da..f020691fc 100644 --- a/tests/openpgp/Makefile.am +++ b/tests/openpgp/Makefile.am @@ -82,6 +82,7 @@ TESTS = setup.scm \ default-key.scm \ export.scm \ ssh.scm \ + issue1955.scm \ issue2015.scm \ finish.scm diff --git a/tests/openpgp/issue1955.scm b/tests/openpgp/issue1955.scm new file mode 100755 index 000000000..287896f93 --- /dev/null +++ b/tests/openpgp/issue1955.scm @@ -0,0 +1,47 @@ +#!/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 . + +(load (with-path "defs.scm")) + +(lettmp + (logfile) + + (define (dump logfile) + (call-with-input-file logfile + (lambda (port) + (display (read-all port))))) + + (setenv "PINENTRY_USER_DATA" + (string-append "--logfile=" logfile " " usrpass1) #t) + + (echo "Killing gpg-agent...") + (call-check `(,(tool 'gpg-connect-agent) --verbose killagent /bye)) + (echo "Starting gpg-agent...") + (call-check `(,(tool 'gpg-connect-agent) --verbose /bye)) + + (for-each-p + "Checking that keys requiring no interactions are preferred (issue1955)..." + (lambda (test) + (let ((file (in-srcdir "samplemsgs" + (string-append "issue1955." test ".gpg")))) + (assert + (string-contains? (call-check `(,@GPG --decrypt ,file)) "geheim")) + (if (file-exists? logfile) + (error "GnuPG used the key requiring a passphrase")))) + '("one.two" "two.one")))