gpg-agent features of loopback-pinentry mode, preset_passphrase

NIIBE Yutaka gniibe at
Tue May 19 07:03:21 CEST 2015

On 05/18/2015 07:12 PM, Werner Koch wrote:
> Actually, I expected that the loopback mode would be used with
> --command-fd and not with the one-time setting of a passphrase.  I kept
> passphrase working because that can be used for symmteric encryption.
> After all loopback mode is a hack to bypass the standard way of asking
> for passphrases and to allow a simpler thing than a pinentry-wrapper
> (e.g. for use by CGIs).  We should never advertise it as a way to query
> an unprotect-the-secret-key-passphrase - this would defeat the split
> between gpg and gpg-agent.
> Your suggestion to query the availibility of feature first is good from
> the average user perspective.  However, average users should not use the
> loopback mode anyway (unless a tool uses it invisible).

Thank you for the explanation.  I understand the intent and

I decline adding error message to user for suggesting loopback mode.

Well, let's consider how to handle the issue 1928:

With classic and stable versions, it worked:

  (0) gpg --batch --passphrase-file pass-file --decrypt encrypted-file

Now with 2.1, what's the answer to the existing script(s)?

Using command-file, it would be:

  (1) gpg --batch --pinentry-mode=loopback --command-file input-file \
          --decrypt encrypted-file

This requires allow-loopback-pinentry option in .gnupg/gpg-agent.conf.

I understand that using loopback mode is for expert, so, I think that
the requirement of configuration of allow-loopback-pinentry is
legitimate (it makes sense to have default as not allowing loopback

Although it would not be intended, following also works with 2.1 (with
allow-loopback-pinentry option of gpg-agent).

  (2) gpg2 --batch --pinentry-mode=loopback --passphrase-file pass-file \
           --decrypt encrypted-file

While the split between gpg and gpg-agent highly makes sense for
interactive usages, in general, there might still be valid usages
where it doesn't matter much and where it's OK to invoke gpg-agent for
every invocation of gpg command.

While we lead/ask people to pinentry wrapper solution or (1) with
GnuPG 2.1, I think that requiring change from (0) to (1) or (2) would
be still a regression.

Just in case, following is a patch to support (0) with GnuPG 2.1.  It
let give gpg to pass "OPTION pinentry-mode=loopback" when the function
have_static_passphrase returns true and to offer the string of
get_static_passphrase to gpg-agent.

BTW, in the commit of 1cd6445eec4c3642ad92afb02f3563a01cc10c10 in
January 30, 2013, I think that the comment

	/* We do not pass errors to avoid breaking other code.  */

should have been removed.

diff --git a/g10/call-agent.c b/g10/call-agent.c
index edee66e..258a48b 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -163,18 +163,18 @@ default_inq_cb (void *opaque, const char *line)
       if (err)
         log_error (_("failed to proxy %s inquiry to client\n"),
-      /* We do not pass errors to avoid breaking other code.  */
+      return err;
-  else if ((has_leading_keyword (line, "PASSPHRASE")
-            || has_leading_keyword (line, "NEW_PASSPHRASE"))
-           && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
+  if ((has_leading_keyword (line, "PASSPHRASE")
+       || has_leading_keyword (line, "NEW_PASSPHRASE")))
       if (have_static_passphrase ())
           const char *s = get_static_passphrase ();
-          err = assuan_send_data (parm->ctx, s, strlen (s));
+          return assuan_send_data (parm->ctx, s, strlen (s));
-      else
+      else if (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
           char *pw;

@@ -189,11 +189,11 @@ default_inq_cb (void *opaque, const char *line)
             err = assuan_send_data (parm->ctx, pw, strlen (pw));
           xfree (pw);
+          return err;
-  else
-    log_debug ("ignoring gpg-agent inquiry '%s'\n", line);

+  log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
   return err;

@@ -306,9 +306,10 @@ start_agent (ctrl_t ctrl, int for_card)
           assuan_transact (agent_ctx, "OPTION agent-awareness=2.1.0",
                            NULL, NULL, NULL, NULL, NULL, NULL);
           /* Pass on the pinentry mode.  */
-          if (opt.pinentry_mode)
+          if (have_static_passphrase () || opt.pinentry_mode)
               char *tmp = xasprintf ("OPTION pinentry-mode=%s",
+                                     opt.batch ? "loopback" :
                                      str_pinentry_mode (opt.pinentry_mode));
               rc = assuan_transact (agent_ctx, tmp,
                                NULL, NULL, NULL, NULL, NULL, NULL);

More information about the Gnupg-devel mailing list