gpg: Extra check for sign usage when verifying a data signature.
[gnupg.git] / g10 / call-agent.c
index 26de72e..6ee82a5 100644 (file)
@@ -15,7 +15,7 @@
  * 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/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
-#include <assert.h>
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
 #endif
 
 #include "gpg.h"
 #include <assuan.h>
-#include "util.h"
-#include "membuf.h"
+#include "../common/util.h"
+#include "../common/membuf.h"
 #include "options.h"
-#include "i18n.h"
-#include "asshelp.h"
-#include "sysutils.h"
+#include "../common/i18n.h"
+#include "../common/asshelp.h"
+#include "../common/sysutils.h"
 #include "call-agent.h"
-#include "status.h"
+#include "../common/status.h"
 #include "../common/shareddefs.h"
-#include "host2net.h"
+#include "../common/host2net.h"
 
 #define CONTROL_D ('D' - 'A' + 1)
 
@@ -104,13 +103,6 @@ struct cache_nonce_parm_s
 };
 
 
-struct scd_genkey_parm_s
-{
-  struct agent_card_genkey_s *cgk;
-  char *savedbytes;     /* Malloced space to save key parameter chunks.  */
-};
-
-
 static gpg_error_t learn_status_cb (void *opaque, const char *line);
 
 
@@ -137,18 +129,6 @@ status_sc_op_failure (int rc)
 }
 
 
-static gpg_error_t
-membuf_data_cb (void *opaque, const void *buffer, size_t length)
-{
-  membuf_t *data = opaque;
-
-  if (buffer)
-    put_membuf (data, buffer, length);
-  return 0;
-}
-
-
-
 /* This is the default inquiry callback.  It mainly handles the
    Pinentry notifications.  */
 static gpg_error_t
@@ -180,7 +160,8 @@ default_inq_cb (void *opaque, const char *line)
           char buf[32];
 
           if (parm->keyinfo.keyid)
-            emit_status_need_passphrase (parm->keyinfo.keyid,
+            emit_status_need_passphrase (parm->ctrl,
+                                         parm->keyinfo.keyid,
                                          parm->keyinfo.mainkeyid,
                                          parm->keyinfo.pubkey_algo);
 
@@ -202,73 +183,55 @@ default_inq_cb (void *opaque, const char *line)
 }
 
 
-/* Check whether gnome-keyring hijacked the gpg-agent.  */
-static void
-check_hijacking (assuan_context_t ctx)
+/* Print a warning if the server's version number is less than our
+   version number.  Returns an error code on a connection problem.  */
+static gpg_error_t
+warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode)
 {
-  membuf_t mb;
-  char *string;
-
-  init_membuf (&mb, 64);
-
-  /* AGENT_ID is a command implemented by gnome-keyring-daemon.  It
-     does not return any data but an OK line with a remark.  */
-  if (assuan_transact (ctx, "AGENT_ID",
-                       membuf_data_cb, &mb, NULL, NULL, NULL, NULL))
-    {
-      xfree (get_membuf (&mb, NULL));
-      return; /* Error - Probably not hijacked.  */
-    }
-  put_membuf (&mb, "", 1);
-  string = get_membuf (&mb, NULL);
-  if (!string || !*string)
-    {
-      /* Definitely hijacked - show a warning prompt.  */
-      static int shown;
-      const char warn1[] =
-        "The GNOME keyring manager hijacked the GnuPG agent.";
-      const char warn2[] =
-        "GnuPG will not work properly - please configure that "
-        "tool to not interfere with the GnuPG system!";
-      log_info ("WARNING: %s\n", warn1);
-      log_info ("WARNING: %s\n", warn2);
-      /*                 (GPG_ERR_SOURCRE_GPG, GPG_ERR_NO_AGENT) */
-      write_status_text (STATUS_ERROR, "check_hijacking 33554509");
-      xfree (string);
-      string = strconcat (warn1, "\n\n", warn2, NULL);
-      if (string && !shown && !opt.batch)
+  gpg_error_t err;
+  char *serverversion;
+  const char *myversion = strusage (13);
+
+  err = get_assuan_server_version (ctx, mode, &serverversion);
+  if (err)
+    log_log (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED?
+             GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
+             _("error getting version from '%s': %s\n"),
+             servername, gpg_strerror (err));
+  else if (compare_version_strings (serverversion, myversion) < 0)
+    {
+      char *warn;
+
+      warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
+                           servername, serverversion, myversion);
+      if (!warn)
+        err = gpg_error_from_syserror ();
+      else
         {
-          /* NB: The Pinentry based prompt will only work if a
-             gnome-keyring manager passes invalid commands on to the
-             original gpg-agent.  */
-          char *cmd, *cmdargs;
-
-          cmdargs = percent_plus_escape (string);
-          cmd = strconcat ("GET_CONFIRMATION ", cmdargs, NULL);
-          xfree (cmdargs);
-          if (cmd)
+          log_info (_("WARNING: %s\n"), warn);
+          if (!opt.quiet)
             {
-              struct default_inq_parm_s dfltparm;
-
-              memset (&dfltparm, 0, sizeof dfltparm);
-              dfltparm.ctx = ctx;
-              assuan_transact (ctx, cmd, NULL, NULL,
-                               default_inq_cb, &dfltparm,
-                               NULL, NULL);
-              xfree (cmd);
-              shown = 1;
+              log_info (_("Note: Outdated servers may lack important"
+                          " security fixes.\n"));
+              log_info (_("Note: Use the command \"%s\" to restart them.\n"),
+                        "gpgconf --kill all");
             }
+          write_status_strings (STATUS_WARNING, "server_version_mismatch 0",
+                                " ", warn, NULL);
+          xfree (warn);
         }
     }
-  xfree (string);
+  xfree (serverversion);
+  return err;
 }
 
 
+#define FLAG_FOR_CARD_SUPPRESS_ERRORS 2
 
 /* Try to connect to the agent via socket or fork it off and work by
    pipes.  Handle the server's initial greeting */
 static int
-start_agent (ctrl_t ctrl, int for_card)
+start_agent (ctrl_t ctrl, int flag_for_card)
 {
   int rc;
 
@@ -282,7 +245,6 @@ start_agent (ctrl_t ctrl, int for_card)
     {
       rc = start_new_gpg_agent (&agent_ctx,
                                 GPG_ERR_SOURCE_DEFAULT,
-                                opt.homedir,
                                 opt.agent_program,
                                 opt.lc_ctype, opt.lc_messages,
                                 opt.session_env,
@@ -298,7 +260,8 @@ start_agent (ctrl_t ctrl, int for_card)
               log_info (_("no gpg-agent running in this session\n"));
             }
         }
-      else if (!rc)
+      else if (!rc
+               && !(rc = warn_version_mismatch (agent_ctx, GPG_AGENT_NAME, 0)))
         {
           /* Tell the agent that we support Pinentry notifications.
              No error checking so that it will work also with older
@@ -326,20 +289,57 @@ start_agent (ctrl_t ctrl, int for_card)
                 }
             }
 
-          check_hijacking (agent_ctx);
+          /* Pass on the request origin.  */
+          if (opt.request_origin)
+            {
+              char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
+                                     str_request_origin (opt.request_origin));
+              rc = assuan_transact (agent_ctx, tmp,
+                               NULL, NULL, NULL, NULL, NULL, NULL);
+              xfree (tmp);
+              if (rc)
+                {
+                  log_error ("setting request origin '%s' failed: %s\n",
+                             str_request_origin (opt.request_origin),
+                             gpg_strerror (rc));
+                  write_status_error ("set_request_origin", rc);
+                }
+            }
+
+          /* In DE_VS mode under Windows we require that the JENT RNG
+           * is active.  */
+#ifdef HAVE_W32_SYSTEM
+          if (!rc && opt.compliance == CO_DE_VS)
+            {
+              if (assuan_transact (agent_ctx, "GETINFO jent_active",
+                                   NULL, NULL, NULL, NULL, NULL, NULL))
+                {
+                  rc = gpg_error (GPG_ERR_FORBIDDEN);
+                  log_error (_("%s is not compliant with %s mode\n"),
+                             GPG_AGENT_NAME,
+                             gnupg_compliance_option_string (opt.compliance));
+                  write_status_error ("random-compliance", rc);
+                }
+            }
+#endif /*HAVE_W32_SYSTEM*/
+
         }
     }
 
-  if (!rc && for_card && !did_early_card_test)
+  if (!rc && flag_for_card && !did_early_card_test)
     {
       /* Request the serial number of the card for an early test.  */
       struct agent_card_info_s info;
 
       memset (&info, 0, sizeof info);
-      rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
-                            NULL, NULL, NULL, NULL,
-                            learn_status_cb, &info);
-      if (rc)
+
+      if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
+        rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
+      if (!rc)
+        rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
+                              NULL, NULL, NULL, NULL,
+                              learn_status_cb, &info);
+      if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
         {
           switch (gpg_err_code (rc))
             {
@@ -388,7 +388,7 @@ unescape_status_string (const unsigned char *s)
 }
 
 
-/* Take a 20 byte hexencoded string and put it into the the provided
+/* Take a 20 byte hexencoded string and put it into the provided
    20 byte buffer FPR in binary format. */
 static int
 unhexify_fpr (const char *hexstr, unsigned char *fpr)
@@ -398,10 +398,11 @@ unhexify_fpr (const char *hexstr, unsigned char *fpr)
 
   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
     ;
-  if (*s || (n != 40))
+  if ((*s && *s != ' ') || (n != 40))
     return 0; /* no fingerprint (invalid or wrong length). */
-  for (s=hexstr, n=0; *s; s += 2, n++)
+  for (s=hexstr, n=0; *s && n < 20; s += 2, n++)
     fpr[n] = xtoi_2 (s);
+
   return 1; /* okay */
 }
 
@@ -607,6 +608,8 @@ learn_status_cb (void *opaque, const char *line)
                     parm->extcap.ki = abool;
                   else if (!strcmp (p, "aac"))
                     parm->extcap.aac = abool;
+                  else if (!strcmp (p, "kdf"))
+                    parm->extcap.kdf = abool;
                   else if (!strcmp (p, "si"))
                     parm->status_indicator = strtoul (p2, NULL, 10);
                 }
@@ -642,6 +645,24 @@ learn_status_cb (void *opaque, const char *line)
       else if (no == 3)
         parm->fpr3time = strtoul (line, NULL, 10);
     }
+  else if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
+    {
+      const char *hexgrp = line;
+      int no;
+
+      while (*line && !spacep (line))
+        line++;
+      while (spacep (line))
+        line++;
+      if (strncmp (line, "OPENPGP.", 8))
+        ;
+      else if ((no = atoi (line+8)) == 1)
+        unhexify_fpr (hexgrp, parm->grp1);
+      else if (no == 2)
+        unhexify_fpr (hexgrp, parm->grp2);
+      else if (no == 3)
+        unhexify_fpr (hexgrp, parm->grp3);
+    }
   else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
     {
       int no = atoi (line);
@@ -672,25 +693,14 @@ learn_status_cb (void *opaque, const char *line)
         parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10);
       else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
                || algo == PUBKEY_ALGO_EDDSA)
-        {
-          const char *curve;
-
-          i = 0;
-          do
-            {
-              curve = openpgp_enum_curves (&i);
-              if (!strcmp (curve, line+n))
-                break;
-            }
-          while (curve != NULL);
-          parm->key_attr[keyno].curve = curve;
-        }
+        parm->key_attr[keyno].curve = openpgp_is_curve_supported (line + n,
+                                                                  NULL, NULL);
     }
   else if (keywordlen == 12 && !memcmp (keyword, "PRIVATE-DO-", 11)
            && strchr("1234", keyword[11]))
     {
       int no = keyword[11] - '1';
-      assert (no >= 0 && no <= 3);
+      log_assert (no >= 0 && no <= 3);
       xfree (parm->private_do[no]);
       parm->private_do[no] = unescape_status_string (line);
     }
@@ -715,18 +725,6 @@ agent_scd_learn (struct agent_card_info_s *info, int force)
   if (rc)
     return rc;
 
-  /* Send the serialno command to initialize the connection.  We don't
-     care about the data returned.  If the card has already been
-     initialized, this is a very fast command.  The main reason we
-     need to do this here is to handle a card removed case so that an
-     "l" command in --card-edit can be used to show ta newly inserted
-     card.  We request the openpgp card because that is what we
-     expect. */
-  rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
-                        NULL, NULL, NULL, NULL, NULL, NULL);
-  if (rc)
-    return rc;
-
   parm.ctx = agent_ctx;
   rc = assuan_transact (agent_ctx,
                         force ? "LEARN --sendinfo --force" : "LEARN --sendinfo",
@@ -778,9 +776,9 @@ agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
 
       init_membuf (&mb, 256);
 
-      snprintf (line, DIM(line)-1, "SCD APDU %s", hexapdu);
+      snprintf (line, DIM(line), "SCD APDU %s", hexapdu);
       err = assuan_transact (agent_ctx, line,
-                             membuf_data_cb, &mb, NULL, NULL, NULL, NULL);
+                             put_membuf_cb, &mb, NULL, NULL, NULL, NULL);
       if (!err)
         {
           data = get_membuf (&mb, &datalen);
@@ -809,15 +807,14 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
   struct default_inq_parm_s parm;
 
   memset (&parm, 0, sizeof parm);
-  parm.ctx = agent_ctx;
 
-  snprintf (line, DIM(line)-1, "KEYTOCARD %s%s %s OPENPGP.%d %s",
+  snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s",
             force?"--force ": "", hexgrip, serialno, keyno, timestamp);
-  line[DIM(line)-1] = 0;
 
   rc = start_agent (NULL, 1);
   if (rc)
     return rc;
+  parm.ctx = agent_ctx;
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm,
                         NULL, NULL);
@@ -829,7 +826,7 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
 \f
 /* Call the agent to retrieve a data object.  This function returns
    the data in the same structure as used by the learn command.  It is
-   allowed to update such a structure using this commmand. */
+   allowed to update such a structure using this command. */
 int
 agent_scd_getattr (const char *name, struct agent_card_info_s *info)
 {
@@ -954,8 +951,7 @@ agent_scd_writecert (const char *certidstr,
 
   memset (&parms, 0, sizeof parms);
 
-  snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SCD WRITECERT %s", certidstr);
   dfltparm.ctx = agent_ctx;
   parms.dflt = &dfltparm;
   parms.certdata = certdata;
@@ -1008,8 +1004,7 @@ agent_scd_writekey (int keyno, const char *serialno,
 
   memset (&parms, 0, sizeof parms);
 
-  snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SCD WRITEKEY --force OPENPGP.%d", keyno);
   dfltparm.ctx = agent_ctx;
   parms.dflt = &dfltparm;
   parms.keydata = keydata;
@@ -1024,248 +1019,99 @@ agent_scd_writekey (int keyno, const char *serialno,
 
 
 \f
-static gpg_error_t
-scd_genkey_cb_append_savedbytes (struct scd_genkey_parm_s *parm,
-                                 const char *line)
-{
-  gpg_error_t err = 0;
-  char *p;
-
-  if (!parm->savedbytes)
-    {
-      parm->savedbytes = xtrystrdup (line);
-      if (!parm->savedbytes)
-        err = gpg_error_from_syserror ();
-    }
-  else
-    {
-      p = xtrymalloc (strlen (parm->savedbytes) + strlen (line) + 1);
-      if (!p)
-        err = gpg_error_from_syserror ();
-      else
-        {
-          strcpy (stpcpy (p, parm->savedbytes), line);
-          xfree (parm->savedbytes);
-          parm->savedbytes = p;
-        }
-    }
-
-  return err;
-}
-
 /* Status callback for the SCD GENKEY command. */
 static gpg_error_t
 scd_genkey_cb (void *opaque, const char *line)
 {
-  struct scd_genkey_parm_s *parm = opaque;
+  u32 *createtime = opaque;
   const char *keyword = line;
   int keywordlen;
-  gpg_error_t rc = 0;
 
   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
     ;
   while (spacep (line))
     line++;
 
 if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
     {
-      parm->cgk->fprvalid = unhexify_fpr (line, parm->cgk->fpr);
-    }
-  else if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
-    {
-      gcry_mpi_t a;
-      const char *name = line;
-
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-
-      if (*name == '-' && spacep (name+1))
-        rc = scd_genkey_cb_append_savedbytes (parm, line);
-      else
-        {
-          if (parm->savedbytes)
-            {
-              rc = scd_genkey_cb_append_savedbytes (parm, line);
-              if (!rc)
-                rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX,
-                                    parm->savedbytes, 0, NULL);
-            }
-          else
-            rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
-          if (rc)
-            log_error ("error parsing received key data: %s\n",
-                       gpg_strerror (rc));
-          else if (*name == 'n' && spacep (name+1))
-            parm->cgk->n = a;
-          else if (*name == 'e' && spacep (name+1))
-            parm->cgk->e = a;
-          else
-            {
-              log_info ("unknown parameter name in received key data\n");
-              gcry_mpi_release (a);
-              rc = gpg_error (GPG_ERR_INV_PARAMETER);
-            }
-
-          xfree (parm->savedbytes);
-          parm->savedbytes = NULL;
-        }
-    }
-  else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
-    {
-      parm->cgk->created_at = (u32)strtoul (line, NULL, 10);
+      *createtime = (u32)strtoul (line, NULL, 10);
     }
   else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen))
     {
       write_status_text (STATUS_PROGRESS, line);
     }
 
-  return rc;
+  return 0;
 }
 
-/* Send a GENKEY command to the SCdaemon.  SERIALNO is not used in
-   this implementation.  If CREATEDATE is not 0, it will be passed to
-   SCDAEMON so that the key is created with this timestamp.  INFO will
-   receive information about the generated key.  */
+/* Send a GENKEY command to the SCdaemon.  If *CREATETIME is not 0,
+  the value will be passed to SCDAEMON with --timestamp option so that
+  the key is created with this.  Otherwise, timestamp was generated by
+  SCDEAMON.  On success, creation time is stored back to
+  CREATETIME.  */
 int
-agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
-                  const char *serialno, u32 createtime)
+agent_scd_genkey (int keyno, int force, u32 *createtime)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
   gnupg_isotime_t tbuf;
-  struct scd_genkey_parm_s parms;
   struct default_inq_parm_s dfltparm;
 
   memset (&dfltparm, 0, sizeof dfltparm);
 
-  (void)serialno;
-
-  memset (&parms, 0, sizeof parms);
-  parms.cgk = info;
-
   rc = start_agent (NULL, 1);
   if (rc)
     return rc;
 
-  if (createtime)
-    epoch2isotime (tbuf, createtime);
+  if (*createtime)
+    epoch2isotime (tbuf, *createtime);
   else
     *tbuf = 0;
 
-  snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d",
+  snprintf (line, DIM(line), "SCD GENKEY %s%s %s %d",
             *tbuf? "--timestamp=":"", tbuf,
             force? "--force":"",
             keyno);
-  line[DIM(line)-1] = 0;
 
   dfltparm.ctx = agent_ctx;
-  memset (info, 0, sizeof *info);
   rc = assuan_transact (agent_ctx, line,
                         NULL, NULL, default_inq_cb, &dfltparm,
-                        scd_genkey_cb, &parms);
-
-  xfree (parms.savedbytes);
+                        scd_genkey_cb, createtime);
 
   status_sc_op_failure (rc);
   return rc;
 }
-
-
-
 \f
-/* Issue an SCD SERIALNO openpgp command and if SERIALNO is not NULL
-   ask the user to insert the requested card.  */
-gpg_error_t
-select_openpgp (const char *serialno)
+/* Return the serial number of the card or an appropriate error.  The
+   serial number is returned as a hexstring. */
+int
+agent_scd_serialno (char **r_serialno, const char *demand)
 {
-  gpg_error_t err;
-
-  /* Send the serialno command to initialize the connection.  Without
-     a given S/N we don't care about the data returned.  If the card
-     has already been initialized, this is a very fast command.  We
-     request the openpgp card because that is what we expect.
-
-     Note that an opt.limit_card_insert_tries of 1 means: No tries at
-     all whereas 0 means do not limit the number of tries.  Due to the
-     sue of a pinentry prompt with a cancel option we use it here in a
-     boolean sense.  */
-  if (!serialno || opt.limit_card_insert_tries == 1)
-    err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
-                           NULL, NULL, NULL, NULL, NULL, NULL);
-  else
-    {
-      char *this_sn = NULL;
-      char *desc;
-      int ask;
-      char *want_sn;
-      char *p;
-
-      want_sn = xtrystrdup (serialno);
-      if (!want_sn)
-        return gpg_error_from_syserror ();
-      p = strchr (want_sn, '/');
-      if (p)
-        *p = 0;
+  int err;
+  char *serialno = NULL;
+  char line[ASSUAN_LINELENGTH];
 
-      do
-        {
-          ask = 0;
-          err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
-                                 NULL, NULL, NULL, NULL,
-                                 get_serialno_cb, &this_sn);
-          if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
-            ask = 1;
-          else if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
-            ask = 2;
-          else if (err)
-            ;
-          else if (this_sn)
-            {
-              if (strcmp (want_sn, this_sn))
-                ask = 2;
-            }
+  err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS);
+  if (err)
+    return err;
 
-          xfree (this_sn);
-          this_sn = NULL;
+  if (!demand)
+    strcpy (line, "SCD SERIALNO");
+  else
+    snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand);
 
-          if (ask)
-            {
-              char *formatted = NULL;
-              char *ocodeset = i18n_switchto_utf8 ();
-
-              if (!strncmp (want_sn, "D27600012401", 12)
-                  && strlen (want_sn) == 32 )
-                formatted = xtryasprintf ("(%.4s) %.8s",
-                                          want_sn + 16, want_sn + 20);
-
-              err = 0;
-              desc = xtryasprintf
-                ("%s:\n\n"
-                 "  \"%s\"",
-                 ask == 1
-                 ? _("Please insert the card with serial number")
-                 : _("Please remove the current card and "
-                     "insert the one with serial number"),
-                 formatted? formatted : want_sn);
-              if (!desc)
-                err = gpg_error_from_syserror ();
-              xfree (formatted);
-              i18n_switchback (ocodeset);
-              if (!err)
-                err = gpg_agent_get_confirmation (desc);
-              xfree (desc);
-            }
-        }
-      while (ask && !err);
-      xfree (want_sn);
+  err = assuan_transact (agent_ctx, line,
+                         NULL, NULL, NULL, NULL,
+                         get_serialno_cb, &serialno);
+  if (err)
+    {
+      xfree (serialno);
+      return err;
     }
 
-  return err;
+  *r_serialno = serialno;
+  return 0;
 }
-
-
 \f
 /* Send a READCERT command to the SCdaemon. */
 int
@@ -1289,10 +1135,9 @@ agent_scd_readcert (const char *certidstr,
 
   init_membuf (&data, 2048);
 
-  snprintf (line, DIM(line)-1, "SCD READCERT %s", certidstr);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SCD READCERT %s", certidstr);
   rc = assuan_transact (agent_ctx, line,
-                        membuf_data_cb, &data,
+                        put_membuf_cb, &data,
                         default_inq_cb, &dfltparm,
                         NULL, NULL);
   if (rc)
@@ -1306,8 +1151,72 @@ agent_scd_readcert (const char *certidstr,
 
   return 0;
 }
+\f
+struct card_cardlist_parm_s {
+  int error;
+  strlist_t list;
+};
 
 
+/* Callback function for agent_card_cardlist.  */
+static gpg_error_t
+card_cardlist_cb (void *opaque, const char *line)
+{
+  struct card_cardlist_parm_s *parm = opaque;
+  const char *keyword = line;
+  int keywordlen;
+
+  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+    ;
+  while (spacep (line))
+    line++;
+
+  if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+    {
+      const char *s;
+      int n;
+
+      for (n=0,s=line; hexdigitp (s); s++, n++)
+        ;
+
+      if (!n || (n&1) || *s)
+        parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
+      else
+        add_to_strlist (&parm->list, line);
+    }
+
+  return 0;
+}
+
+/* Return cardlist.  */
+int
+agent_scd_cardlist (strlist_t *result)
+{
+  int err;
+  char line[ASSUAN_LINELENGTH];
+  struct card_cardlist_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+  *result = NULL;
+  err = start_agent (NULL, 1);
+  if (err)
+    return err;
+
+  strcpy (line, "SCD GETINFO card_list");
+
+  err = assuan_transact (agent_ctx, line,
+                         NULL, NULL, NULL, NULL,
+                         card_cardlist_cb, &parm);
+  if (!err && parm.error)
+    err = parm.error;
+
+  if (!err)
+    *result = parm.list;
+  else
+    free_strlist (parm.list);
+
+  return 0;
+}
 \f
 /* Change the PIN of an OpenPGP card or reset the retry counter.
    CHVNO 1: Change the PIN
@@ -1340,8 +1249,7 @@ agent_scd_change_pin (int chvno, const char *serialno)
     return rc;
   dfltparm.ctx = agent_ctx;
 
-  snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SCD PASSWD %s %d", reset, chvno);
   rc = assuan_transact (agent_ctx, line,
                         NULL, NULL,
                         default_inq_cb, &dfltparm,
@@ -1368,8 +1276,7 @@ agent_scd_checkpin  (const char *serialno)
     return rc;
   dfltparm.ctx = agent_ctx;
 
-  snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SCD CHECKPIN %s", serialno);
   rc = assuan_transact (agent_ctx, line,
                         NULL, NULL,
                         default_inq_cb, &dfltparm,
@@ -1439,7 +1346,7 @@ agent_get_passphrase (const char *cache_id,
     if (!(arg4 = percent_plus_escape (desc_msg)))
       goto no_mem;
 
-  snprintf (line, DIM(line)-1,
+  snprintf (line, DIM(line),
             "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s",
             repeat,
             check? " --check --qualitybar":"",
@@ -1447,7 +1354,6 @@ agent_get_passphrase (const char *cache_id,
             arg2? arg2:"X",
             arg3? arg3:"X",
             arg4? arg4:"X");
-  line[DIM(line)-1] = 0;
   xfree (arg1);
   xfree (arg2);
   xfree (arg3);
@@ -1455,7 +1361,7 @@ agent_get_passphrase (const char *cache_id,
 
   init_membuf_secure (&data, 64);
   rc = assuan_transact (agent_ctx, line,
-                        membuf_data_cb, &data,
+                        put_membuf_cb, &data,
                         default_inq_cb, &dfltparm,
                         NULL, NULL);
 
@@ -1496,8 +1402,7 @@ agent_clear_passphrase (const char *cache_id)
     return rc;
   dfltparm.ctx = agent_ctx;
 
-  snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "CLEAR_PASSPHRASE %s", cache_id);
   return assuan_transact (agent_ctx, line,
                           NULL, NULL,
                           default_inq_cb, &dfltparm,
@@ -1525,8 +1430,7 @@ gpg_agent_get_confirmation (const char *desc)
   tmp = percent_plus_escape (desc);
   if (!tmp)
     return gpg_error_from_syserror ();
-  snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", tmp);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "GET_CONFIRMATION %s", tmp);
   xfree (tmp);
 
   rc = assuan_transact (agent_ctx, line,
@@ -1553,7 +1457,7 @@ agent_get_s2k_count (unsigned long *r_count)
 
   init_membuf (&data, 32);
   err = assuan_transact (agent_ctx, "GETINFO s2k_count",
-                        membuf_data_cb, &data,
+                        put_membuf_cb, &data,
                         NULL, NULL, NULL, NULL);
   if (err)
     xfree (get_membuf (&data, NULL));
@@ -1651,28 +1555,35 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
 
 
 \f
+struct keyinfo_data_parm_s
+{
+  char *serialno;
+  int cleartext;
+};
+
+
 static gpg_error_t
 keyinfo_status_cb (void *opaque, const char *line)
 {
-  char **serialno = opaque;
-  const char *s, *s2;
+  struct keyinfo_data_parm_s *data = opaque;
+  int is_smartcard;
+  char *s;
 
-  if ((s = has_leading_keyword (line, "KEYINFO")) && !*serialno)
+  if ((s = has_leading_keyword (line, "KEYINFO")) && data)
     {
-      s = strchr (s, ' ');
-      if (s && s[1] == 'T' && s[2] == ' ' && s[3])
+      /* Parse the arguments:
+       *      0        1        2        3       4          5
+       *   <keygrip> <type> <serialno> <idstr> <cached> <protection>
+       */
+      char *fields[6];
+
+      if (split_fields (s, fields, DIM (fields)) == 6)
         {
-          s += 3;
-          s2 = strchr (s, ' ');
-          if ( s2 > s )
-            {
-              *serialno = xtrymalloc ((s2 - s)+1);
-              if (*serialno)
-                {
-                  memcpy (*serialno, s, s2 - s);
-                  (*serialno)[s2 - s] = 0;
-                }
-            }
+          is_smartcard = (fields[1][0] == 'T');
+          if (is_smartcard && !data->serialno && strcmp (fields[2], "-"))
+            data->serialno = xtrystrdup (fields[2]);
+          /* 'P' for protected, 'C' for clear */
+          data->cleartext = (fields[5][0] == 'C');
         }
     }
   return 0;
@@ -1681,13 +1592,20 @@ keyinfo_status_cb (void *opaque, const char *line)
 
 /* Return the serial number for a secret key.  If the returned serial
    number is NULL, the key is not stored on a smartcard.  Caller needs
-   to free R_SERIALNO.  */
+   to free R_SERIALNO.
+
+   if r_cleartext is not NULL, the referenced int will be set to 1 if
+   the agent's copy of the key is stored in the clear, or 0 otherwise
+*/
 gpg_error_t
-agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
+                   char **r_serialno, int *r_cleartext)
 {
   gpg_error_t err;
   char line[ASSUAN_LINELENGTH];
-  char *serialno = NULL;
+  struct keyinfo_data_parm_s keyinfo;
+
+  memset (&keyinfo, 0,sizeof keyinfo);
 
   *r_serialno = NULL;
 
@@ -1698,21 +1616,24 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
   if (!hexkeygrip || strlen (hexkeygrip) != 40)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
 
   err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
-                         keyinfo_status_cb, &serialno);
-  if (!err && serialno)
+                         keyinfo_status_cb, &keyinfo);
+  if (!err && keyinfo.serialno)
     {
       /* Sanity check for bad characters.  */
-      if (strpbrk (serialno, ":\n\r"))
+      if (strpbrk (keyinfo.serialno, ":\n\r"))
         err = GPG_ERR_INV_VALUE;
     }
   if (err)
-    xfree (serialno);
+    xfree (keyinfo.serialno);
   else
-    *r_serialno = serialno;
+    {
+      *r_serialno = keyinfo.serialno;
+      if (r_cleartext)
+        *r_cleartext = keyinfo.cleartext;
+    }
   return err;
 }
 
@@ -1723,30 +1644,29 @@ static gpg_error_t
 cache_nonce_status_cb (void *opaque, const char *line)
 {
   struct cache_nonce_parm_s *parm = opaque;
-  const char *keyword = line;
-  int keywordlen;
-
-  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
-    ;
-  while (spacep (line))
-    line++;
+  const char *s;
 
-  if (keywordlen == 11 && !memcmp (keyword, "CACHE_NONCE", keywordlen))
+  if ((s = has_leading_keyword (line, "CACHE_NONCE")))
     {
       if (parm->cache_nonce_addr)
         {
           xfree (*parm->cache_nonce_addr);
-          *parm->cache_nonce_addr = xtrystrdup (line);
+          *parm->cache_nonce_addr = xtrystrdup (s);
         }
     }
-  else if (keywordlen == 12 && !memcmp (keyword, "PASSWD_NONCE", keywordlen))
+  else if ((s = has_leading_keyword (line, "PASSWD_NONCE")))
     {
       if (parm->passwd_nonce_addr)
         {
           xfree (*parm->passwd_nonce_addr);
-          *parm->passwd_nonce_addr = xtrystrdup (line);
+          *parm->passwd_nonce_addr = xtrystrdup (s);
         }
     }
+  else if ((s = has_leading_keyword (line, "PROGRESS")))
+    {
+      if (opt.enable_progress_filter)
+        write_status_text (STATUS_PROGRESS, s);
+    }
 
   return 0;
 }
@@ -1785,7 +1705,7 @@ inq_genkey_parms (void *opaque, const char *line)
    PASSPHRASE is not NULL the agent is requested to protect the key
    with that passphrase instead of asking for one.  */
 gpg_error_t
-agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
+agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, char **passwd_nonce_addr,
               const char *keyparms, int no_protection,
               const char *passphrase, gcry_sexp_t *r_pubkey)
 {
@@ -1807,25 +1727,32 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
     return err;
   dfltparm.ctx = agent_ctx;
 
-  err = assuan_transact (agent_ctx, "RESET",
-                         NULL, NULL, NULL, NULL, NULL, NULL);
-  if (err)
-    return err;
+  if (passwd_nonce_addr && *passwd_nonce_addr)
+    ; /* A RESET would flush the passwd nonce cache.  */
+  else
+    {
+      err = assuan_transact (agent_ctx, "RESET",
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+      if (err)
+        return err;
+    }
 
   init_membuf (&data, 1024);
   gk_parm.dflt     = &dfltparm;
   gk_parm.keyparms = keyparms;
   gk_parm.passphrase = passphrase;
-  snprintf (line, sizeof line, "GENKEY%s%s%s",
+  snprintf (line, sizeof line, "GENKEY%s%s%s%s%s",
             no_protection? " --no-protection" :
             passphrase   ? " --inq-passwd" :
             /*          */ "",
+            passwd_nonce_addr && *passwd_nonce_addr? " --passwd-nonce=":"",
+            passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
             cache_nonce_addr && *cache_nonce_addr? " ":"",
             cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"");
   cn_parm.cache_nonce_addr = cache_nonce_addr;
   cn_parm.passwd_nonce_addr = NULL;
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
+                         put_membuf_cb, &data,
                          inq_genkey_parms, &gk_parm,
                          cache_nonce_status_cb, &cn_parm);
   if (err)
@@ -1875,11 +1802,12 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   if (err)
     return err;
 
-  snprintf (line, DIM(line)-1, "%sREADKEY %s", fromcard? "SCD ":"", hexkeygrip);
+  snprintf (line, DIM(line), "READKEY %s%s", fromcard? "--card ":"",
+            hexkeygrip);
 
   init_membuf (&data, 1024);
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
+                         put_membuf_cb, &data,
                          default_inq_cb, &dfltparm,
                          NULL, NULL);
   if (err)
@@ -1939,16 +1867,14 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce,
   if (err)
     return err;
 
-  snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SIGKEY %s", keygrip);
   err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (err)
     return err;
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       err = assuan_transact (agent_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (err)
@@ -1967,7 +1893,7 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce,
             cache_nonce? " -- ":"",
             cache_nonce? cache_nonce:"");
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
+                         put_membuf_cb, &data,
                          default_inq_cb, &dfltparm,
                          NULL, NULL);
   if (err)
@@ -2079,8 +2005,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       err = assuan_transact (agent_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (err)
@@ -2097,7 +2022,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
     if (err)
       return err;
     err = assuan_transact (agent_ctx, "PKDECRYPT",
-                           membuf_data_cb, &data,
+                           put_membuf_cb, &data,
                            inq_ciphertext_cb, &parm,
                            padding_info_cb, r_padding);
     xfree (parm.ciphertext);
@@ -2112,7 +2037,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
   buf = get_membuf (&data, &len);
   if (!buf)
     return gpg_error_from_syserror ();
-  assert (len); /* (we forced Nul termination.)  */
+  log_assert (len); /* (we forced Nul termination.)  */
 
   if (*buf != '(')
     {
@@ -2172,12 +2097,12 @@ agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen)
     return err;
   dfltparm.ctx = agent_ctx;
 
-  snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
+  snprintf (line, DIM(line), "KEYWRAP_KEY %s",
             forexport? "--export":"--import");
 
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
+                         put_membuf_cb, &data,
                          default_inq_cb, &dfltparm,
                          NULL, NULL);
   if (err)
@@ -2216,7 +2141,8 @@ inq_import_key_parms (void *opaque, const char *line)
 /* Call the agent to import a key into the agent.  */
 gpg_error_t
 agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
-                  const void *key, size_t keylen, int unattended, int force)
+                  const void *key, size_t keylen, int unattended, int force,
+                 u32 *keyid, u32 *mainkeyid, int pubkey_algo)
 {
   gpg_error_t err;
   struct import_key_parm_s parm;
@@ -2226,6 +2152,9 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
 
   memset (&dfltparm, 0, sizeof dfltparm);
   dfltparm.ctrl = ctrl;
+  dfltparm.keyinfo.keyid       = keyid;
+  dfltparm.keyinfo.mainkeyid   = mainkeyid;
+  dfltparm.keyinfo.pubkey_algo = pubkey_algo;
 
   err = start_agent (ctrl, 0);
   if (err)
@@ -2234,8 +2163,7 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       err = assuan_transact (agent_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (err)
@@ -2264,14 +2192,17 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
 \f
 /* Receive a secret key from the agent.  HEXKEYGRIP is the hexified
    keygrip, DESC a prompt to be displayed with the agent's passphrase
-   question (needs to be plus+percent escaped).  If CACHE_NONCE_ADDR
-   is not NULL the agent is advised to first try a passphrase
-   associated with that nonce.  On success the key is stored as a
-   canonical S-expression at R_RESULT and R_RESULTLEN.  */
+   question (needs to be plus+percent escaped).  if OPENPGP_PROTECTED
+   is not zero, ensure that the key material is returned in RFC
+   4880-compatible passphrased-protected form.  If CACHE_NONCE_ADDR is
+   not NULL the agent is advised to first try a passphrase associated
+   with that nonce.  On success the key is stored as a canonical
+   S-expression at R_RESULT and R_RESULTLEN.  */
 gpg_error_t
 agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
-                  char **cache_nonce_addr,
-                  unsigned char **r_result, size_t *r_resultlen)
+                  int openpgp_protected, char **cache_nonce_addr,
+                  unsigned char **r_result, size_t *r_resultlen,
+                 u32 *keyid, u32 *mainkeyid, int pubkey_algo)
 {
   gpg_error_t err;
   struct cache_nonce_parm_s cn_parm;
@@ -2283,6 +2214,9 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
 
   memset (&dfltparm, 0, sizeof dfltparm);
   dfltparm.ctrl = ctrl;
+  dfltparm.keyinfo.keyid       = keyid;
+  dfltparm.keyinfo.mainkeyid   = mainkeyid;
+  dfltparm.keyinfo.pubkey_algo = pubkey_algo;
 
   *r_result = NULL;
 
@@ -2293,14 +2227,15 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       err = assuan_transact (agent_ctx, line,
                              NULL, NULL, NULL, NULL, NULL, NULL);
       if (err)
         return err;
     }
 
-  snprintf (line, DIM(line)-1, "EXPORT_KEY --openpgp %s%s %s",
+  snprintf (line, DIM(line), "EXPORT_KEY %s%s%s %s",
+            openpgp_protected ? "--openpgp ":"",
             cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
             cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
             hexkeygrip);
@@ -2309,7 +2244,7 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   cn_parm.cache_nonce_addr = cache_nonce_addr;
   cn_parm.passwd_nonce_addr = NULL;
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
+                         put_membuf_cb, &data,
                          default_inq_cb, &dfltparm,
                          cache_nonce_status_cb, &cn_parm);
   if (err)
@@ -2329,9 +2264,11 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
 \f
 /* Ask the agent to delete the key identified by HEXKEYGRIP.  If DESC
    is not NULL, display DESC instead of the default description
-   message.  */
+   message.  If FORCE is true the agent is advised not to ask for
+   confirmation. */
 gpg_error_t
-agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
+agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+                  int force)
 {
   gpg_error_t err;
   char line[ASSUAN_LINELENGTH];
@@ -2349,14 +2286,15 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       err = assuan_transact (agent_ctx, line,
                              NULL, NULL, NULL, NULL, NULL, NULL);
       if (err)
         return err;
     }
 
-  snprintf (line, DIM(line)-1, "DELETE_KEY %s", hexkeygrip);
+  snprintf (line, DIM(line), "DELETE_KEY%s %s",
+            force? " --force":"", hexkeygrip);
   err = assuan_transact (agent_ctx, line, NULL, NULL,
                          default_inq_cb, &dfltparm,
                          NULL, NULL);
@@ -2366,13 +2304,14 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
 
 \f
 /* Ask the agent to change the passphrase of the key identified by
-   HEXKEYGRIP.  If DESC is not NULL, display DESC instead of the
-   default description message.  If CACHE_NONCE_ADDR is not NULL the
-   agent is advised to first try a passphrase associated with that
-   nonce.  If PASSWD_NONCE_ADDR is not NULL the agent will try to use
-   the passphrase associated with that nonce.  */
+ * HEXKEYGRIP.  If DESC is not NULL, display DESC instead of the
+ * default description message.  If CACHE_NONCE_ADDR is not NULL the
+ * agent is advised to first try a passphrase associated with that
+ * nonce.  If PASSWD_NONCE_ADDR is not NULL the agent will try to use
+ * the passphrase associated with that nonce for the new passphrase.
+ * If VERIFY is true the passphrase is only verified.  */
 gpg_error_t
-agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify,
               char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
@@ -2391,22 +2330,27 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   if (!hexkeygrip || strlen (hexkeygrip) != 40)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       err = assuan_transact (agent_ctx, line,
                              NULL, NULL, NULL, NULL, NULL, NULL);
       if (err)
         return err;
     }
 
-  snprintf (line, DIM(line)-1, "PASSWD %s%s %s%s %s",
-            cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
-            cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
-            passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
-            passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
-            hexkeygrip);
+  if (verify)
+    snprintf (line, DIM(line), "PASSWD %s%s --verify %s",
+              cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+              cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+              hexkeygrip);
+  else
+    snprintf (line, DIM(line), "PASSWD %s%s %s%s %s",
+              cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+              cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+              passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
+              passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
+              hexkeygrip);
   cn_parm.cache_nonce_addr = cache_nonce_addr;
   cn_parm.passwd_nonce_addr = passwd_nonce_addr;
   err = assuan_transact (agent_ctx, line, NULL, NULL,
@@ -2415,32 +2359,17 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   return err;
 }
 
+
 /* Return the version reported by gpg-agent.  */
 gpg_error_t
 agent_get_version (ctrl_t ctrl, char **r_version)
 {
   gpg_error_t err;
-  membuf_t data;
 
   err = start_agent (ctrl, 0);
   if (err)
     return err;
 
-  init_membuf (&data, 64);
-  err = assuan_transact (agent_ctx, "GETINFO version",
-                        membuf_data_cb, &data,
-                        NULL, NULL, NULL, NULL);
-  if (err)
-    {
-      xfree (get_membuf (&data, NULL));
-      *r_version = NULL;
-    }
-  else
-    {
-      put_membuf (&data, "", 1);
-      *r_version = get_membuf (&data, NULL);
-      if (!*r_version)
-        err = gpg_error_from_syserror ();
-    }
+  err = get_assuan_server_version (agent_ctx, 0, r_version);
   return err;
 }