[svn] GnuPG - r5444 - in trunk: . agent common doc g10

svn author wk cvs at cvs.gnupg.org
Wed Oct 13 17:57:12 CEST 2010


Author: wk
Date: 2010-10-13 17:57:08 +0200 (Wed, 13 Oct 2010)
New Revision: 5444

Modified:
   trunk/NEWS
   trunk/agent/ChangeLog
   trunk/agent/agent.h
   trunk/agent/call-pinentry.c
   trunk/agent/command-ssh.c
   trunk/agent/command.c
   trunk/agent/cvt-openpgp.c
   trunk/agent/divert-scd.c
   trunk/agent/findkey.c
   trunk/agent/genkey.c
   trunk/agent/gpg-agent.c
   trunk/agent/pkdecrypt.c
   trunk/agent/pksign.c
   trunk/agent/protect-tool.c
   trunk/common/ChangeLog
   trunk/common/miscellaneous.c
   trunk/common/util.h
   trunk/doc/gpg.texi
   trunk/g10/ChangeLog
   trunk/g10/call-agent.c
   trunk/g10/card-util.c
   trunk/g10/getkey.c
   trunk/g10/gpg.c
   trunk/g10/gpgv.c
   trunk/g10/import.c
   trunk/g10/keydb.h
   trunk/g10/keyedit.c
   trunk/g10/keygen.c
   trunk/g10/keylist.c
   trunk/g10/misc.c
   trunk/g10/options.h
   trunk/g10/passphrase.c
   trunk/g10/pubkey-enc.c
Log:
More agent support for gpg.


[The diff below has been truncated]

Modified: trunk/agent/ChangeLog
===================================================================
--- trunk/agent/ChangeLog	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/ChangeLog	2010-10-13 15:57:08 UTC (rev 5444)
@@ -1,3 +1,24 @@
+2010-10-13  Werner Koch  <wk at g10code.com>
+
+	* call-pinentry.c (agent_get_passphrase): Support the close_button.
+
+	* gpg-agent.c (create_server_socket): Switch back to stderr
+	logging if we are not starting a agent.
+
+	* command.c (cmd_passwd, cmd_export_key): Move mapping of
+	GPG_ERR_FULLY_CANCELED to ..
+	(leave_cmd): .. here.
+	(option_handler): Add option agent-awareness.
+	* protect-tool.c (get_passphrase): Take care of
+	GPG_ERR_FULLY_CANCELED.
+	* findkey.c (try_unprotect_cb): Ditto.
+	(unprotect): Remove the fully_canceled hack.
+	* call-pinentry.c (start_pinentry): Ditto.
+	(agent_askpin): Ditto.
+	* pkdecrypt.c (agent_pkdecrypt): Ditto
+	* pksign.c (agent_pksign_do): Ditto.
+	* genkey.c (agent_ask_new_passphrase): Remove arg CANCEL_ALL.
+
 2010-10-06  Werner Koch  <wk at g10code.com>
 
 	* cvt-openpgp.c (convert_secret_key): Add missing break.

Modified: trunk/common/ChangeLog
===================================================================
--- trunk/common/ChangeLog	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/common/ChangeLog	2010-10-13 15:57:08 UTC (rev 5444)
@@ -1,3 +1,8 @@
+2010-10-13  Werner Koch  <wk at g10code.com>
+
+	* miscellaneous.c (parse_version_number, parse_version_string)
+	(gnupg_compare_version): New.
+
 2010-10-04  Werner Koch  <wk at g10code.com>
 
 	* gettime.c (asctimestamp) [W32CE]: Do not print the timezone.

Modified: trunk/g10/ChangeLog
===================================================================
--- trunk/g10/ChangeLog	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/ChangeLog	2010-10-13 15:57:08 UTC (rev 5444)
@@ -1,3 +1,33 @@
+2010-10-13  Werner Koch  <wk at g10code.com>
+
+	* call-agent.c (start_agent): Send option agent-awareness.
+	(status_sc_op_failure): Take care of GPG_ERR_FULLY_CANCELED.
+	* passphrase.c (passphrase_get): Ditto.
+	* import.c (transfer_secret_keys): Ditto.
+	* card-util.c (write_sc_op_status): Ditto.
+
+	* getkey.c (enum_secret_keys): Rewrite.
+
+	* pubkey-enc.c (get_session_key): Skip keys without an encryption
+	capability.  Handle GPG_ERR_FULLY_CANCELED.
+	* gpg.c: Add option --try-secret-key.
+	* options.h (struct opt): Add field secret_keys_to_try.
+
+	* passphrase.c (next_to_last_passphrase): Remove.
+
+2010-10-12  Werner Koch  <wk at g10code.com>
+
+	* keygen.c (generate_subkeypair): Check availibility of secret parts.
+
+	* keylist.c (print_card_serialno): Change to take a hexified serialno.
+	(list_keyblock_print): Print serialno and stub key indicators.
+	(list_keyblock_colon): Ditto.
+
+	* getkey.c (have_any_secret_key): Remove.  Replace all calls by
+	agent_probe_any_secret_key.
+	* gpgv.c (agent_probe_any_secret_key): New.
+	(agent_get_keyinfo): New.
+
 2010-10-08  Werner Koch  <wk at g10code.com>
 
 	* gpg.c: Add option --with-keygrip.

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/NEWS	2010-10-13 15:57:08 UTC (rev 5444)
@@ -43,11 +43,14 @@
 
  * The OpenPGP import command is now able to merge secret keys.
 
- * Removed options:
+ * Removed GPG options:
     --export-options: export-secret-subkey-passwd
     --simple-sk-checksum
 
+ * New GPG options:
+    --try-secret-key
 
+
 Noteworthy changes in version 2.0.13 (2009-09-04)
 -------------------------------------------------
 

Modified: trunk/agent/agent.h
===================================================================
--- trunk/agent/agent.h	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/agent.h	2010-10-13 15:57:08 UTC (rev 5444)
@@ -253,7 +253,7 @@
 int agent_askpin (ctrl_t ctrl,
                   const char *desc_text, const char *prompt_text,
                   const char *inital_errtext,
-                  struct pin_entry_info_s *pininfo, int *r_cancelall);
+                  struct pin_entry_info_s *pininfo);
 int agent_get_passphrase (ctrl_t ctrl, char **retpass,
                           const char *desc, const char *prompt,
                           const char *errtext, int with_qualitybar);
@@ -291,7 +291,7 @@
 /*-- genkey.c --*/
 int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent);
 gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
-                                      char **r_passphrase, int *r_cancelall);
+                                      char **r_passphrase);
 int agent_genkey (ctrl_t ctrl, const char *cache_nonce,
                   const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
 int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);

Modified: trunk/agent/call-pinentry.c
===================================================================
--- trunk/agent/call-pinentry.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/call-pinentry.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -467,8 +467,10 @@
   else
     {
       rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
-      if (gpg_err_code (rc) == GPG_ERR_CANCELED)
-        return unlock_pinentry (gpg_error (GPG_ERR_CANCELED));
+      if (gpg_err_code (rc) == GPG_ERR_CANCELED
+          || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
+        return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
+                                              gpg_err_code (rc)));
       rc = 0;
     }
 
@@ -727,7 +729,7 @@
 agent_askpin (ctrl_t ctrl,
               const char *desc_text, const char *prompt_text,
               const char *initial_errtext,
-              struct pin_entry_info_s *pininfo, int *r_cancel_all)
+              struct pin_entry_info_s *pininfo)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
@@ -737,9 +739,6 @@
   int saveflag;
   int close_button;
   
-  if (r_cancel_all)
-    *r_cancel_all = 0;
-
   if (opt.batch)
     return 0; /* fixme: we should return BAD PIN */
 
@@ -830,10 +829,10 @@
           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
 
-      /* Set a flag in case the window close button was clicked to
-         cancel the operation.  */
-      if (close_button && r_cancel_all && gpg_err_code (rc) == GPG_ERR_CANCELED)
-        *r_cancel_all = 1;
+      /* Change error code in case the window close button was clicked
+         to cancel the operation.  */
+      if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED)
+        rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
 
       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
         errtext = is_pin? _("PIN too long")
@@ -890,6 +889,7 @@
   char line[ASSUAN_LINELENGTH];
   struct entry_parm_s parm;
   int saveflag;
+  int close_button;
 
   *retpass = NULL;
   if (opt.batch)
@@ -942,14 +942,21 @@
 
   saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
   assuan_begin_confidential (entry_ctx);
+  close_button = 0;
   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
-                        inq_quality, entry_ctx, NULL, NULL);
+                        inq_quality, entry_ctx,
+                        close_button_status_cb, &close_button);
   assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
   /* Most pinentries out in the wild return the old Assuan error code
      for canceled which gets translated to an assuan Cancel error and
      not to the code for a user cancel.  Fix this here. */
   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
+  /* Change error code in case the window close button was clicked
+     to cancel the operation.  */
+  if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED)
+    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
+
   if (rc)
     xfree (parm.buffer);
   else

Modified: trunk/agent/command-ssh.c
===================================================================
--- trunk/agent/command-ssh.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/command-ssh.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -2425,7 +2425,7 @@
   pi2->check_cb_arg = pi->pin;
 
  next_try:
-  err = agent_askpin (ctrl, description, NULL, initial_errtext, pi, NULL);
+  err = agent_askpin (ctrl, description, NULL, initial_errtext, pi);
   initial_errtext = NULL;
   if (err)
     goto out;
@@ -2433,7 +2433,7 @@
   /* Unless the passphrase is empty, ask to confirm it.  */
   if (pi->pin && *pi->pin)
     {
-      err = agent_askpin (ctrl, description2, NULL, NULL, pi2, NULL);
+      err = agent_askpin (ctrl, description2, NULL, NULL, pi2);
       if (err == -1)
 	{ /* The re-entered one did not match and the user did not
 	     hit cancel. */

Modified: trunk/agent/command.c
===================================================================
--- trunk/agent/command.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/command.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -71,6 +71,7 @@
                                 be done. */
   void *import_key;  /* Malloced KEK for the import_key command.  */
   void *export_key;  /* Malloced KEK for the export_key command.  */
+  int allow_fully_canceled; /* Client is aware of GPG_ERR_FULLY_CANCELED.  */
 };
 
 
@@ -364,6 +365,16 @@
       if (!name)
         name = "?";
 
+      /* Not all users of gpg-agent know about the fully canceled
+         error code; map it back if needed.  */
+      if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
+        {
+          ctrl_t ctrl = assuan_get_pointer (ctx);
+
+          if (!ctrl->server_local->allow_fully_canceled)
+            err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
+        }
+
       /* Most code from common/ does not know the error source, thus
          we fix this here.  */
       if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
@@ -1336,12 +1347,7 @@
                             grip, &shadow_info, CACHE_MODE_IGNORE, NULL, 
                             &s_skey, NULL);
   if (rc)
-    {
-      /* Not all users of gpg-agent know about fully cancled; thus we
-         map it back.  */
-      if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
-        rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
-    }
+    ;
   else if (!s_skey)
     {
       log_error ("changing a smartcard PIN is not yet supported\n");
@@ -1643,7 +1649,7 @@
         err = agent_ask_new_passphrase 
           (ctrl, _("Please enter the passphrase to protect the "
                    "imported object within the GnuPG system."),
-           &passphrase, NULL);
+           &passphrase);
       if (err)
         goto leave;
     }
@@ -1751,17 +1757,12 @@
          canonical S-expression.  */
       if (!passphrase)
         {
-          int fully_canceled;
           err = agent_ask_new_passphrase 
             (ctrl, _("This key (or subkey) is not protected with a passphrase."
                      "  Please enter a new passphrase to export it."),
-             &passphrase, &fully_canceled);
+             &passphrase);
           if (err)
-            {
-              if (fully_canceled)
-                err = gpg_error (GPG_ERR_FULLY_CANCELED);
-              goto leave;
-            }
+            goto leave;
         }
       err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen);
     }
@@ -1814,10 +1815,6 @@
   xfree (ctrl->server_local->keydesc);
   ctrl->server_local->keydesc = NULL;
 
-  /* Not all users of gpg-agent know about fully cancled; thus we map
-     it back unless we know that it is okay.  */
-  if (!openpgp && gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
-    err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
   return leave_cmd (ctx, err);
 }
 
@@ -2185,8 +2182,15 @@
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
 
-  if (!strcmp (key, "putenv"))
+  if (!strcmp (key, "agent-awareness"))
     {
+      /* The value is a version string telling us of which agent
+         version the caller is aware of.  */
+      ctrl->server_local->allow_fully_canceled = 
+        gnupg_compare_version (value, "2.1.0");
+    }
+  else if (!strcmp (key, "putenv"))
+    {
       /* Change the session's environment to be used for the
          Pinentry.  Valid values are:
           <NAME>            Delete envvar NAME

Modified: trunk/agent/cvt-openpgp.c
===================================================================
--- trunk/agent/cvt-openpgp.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/cvt-openpgp.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -780,7 +780,7 @@
         err = try_do_unprotect_cb (pi);
     }
   if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
-    err = agent_askpin (ctrl, prompt, NULL, NULL, pi, NULL);
+    err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
   skeyidx = pi_arg.skeyidx;
   if (!err)
     {

Modified: trunk/agent/divert-scd.c
===================================================================
--- trunk/agent/divert-scd.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/divert-scd.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -266,7 +266,7 @@
 
   if (any_flags)
     {
-      rc = agent_askpin (ctrl, info, prompt, again_text, pi, NULL);
+      rc = agent_askpin (ctrl, info, prompt, again_text, pi);
       again_text = NULL;
       if (!rc && newpin)
         {
@@ -288,7 +288,7 @@
                               is_puk?
                               _("Repeat this PUK"):
                               _("Repeat this PIN")),
-                             prompt, NULL, pi2, NULL);
+                             prompt, NULL, pi2);
           if (!rc && strcmp (pi->pin, pi2->pin))
             {
               again_text = (resetcode? 
@@ -312,7 +312,7 @@
                      info? info:"",
                      info? "')":"") < 0)
         desc = NULL;
-      rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi, NULL);
+      rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi);
       xfree (desc);
     }
 

Modified: trunk/agent/findkey.c
===================================================================
--- trunk/agent/findkey.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/findkey.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -169,7 +169,8 @@
                                         _("I'll change it later"), 0);
           if (!err)
             arg->change_required = 1;
-          else if (gpg_err_code (err) == GPG_ERR_CANCELED)
+          else if (gpg_err_code (err) == GPG_ERR_CANCELED
+                   || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
             err = 0;
         }
       xfree (desc);
@@ -290,7 +291,6 @@
   unsigned char *result;
   size_t resultlen;
   char hexgrip[40+1];
-  int fully_canceled;
 
   if (r_passphrase)
     *r_passphrase = NULL;
@@ -383,9 +383,7 @@
   arg.change_required = 0;
   pi->check_cb_arg = &arg;
 
-  rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, &fully_canceled);
-  if (gpg_err_code (rc) == GPG_ERR_CANCELED && fully_canceled)
-    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
+  rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
   if (!rc)
     {
       assert (arg.unprotected_key);

Modified: trunk/agent/genkey.c
===================================================================
--- trunk/agent/genkey.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/genkey.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -290,12 +290,10 @@
    function returns 0 and store the passphrase at R_PASSPHRASE; if the
    user opted not to use a passphrase NULL will be stored there.  The
    user needs to free the returned string.  In case of an error and
-   error code is returned and NULL stored at R_PASSPHRASE.  If
-   R_CANCEL_ALL is not NULL and the user canceled by directly closing
-   the window true will be stored at this address.  */
+   error code is returned and NULL stored at R_PASSPHRASE.  */
 gpg_error_t
 agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
-                          char **r_passphrase, int *r_cancel_all)
+                          char **r_passphrase)
 {
   gpg_error_t err;
   const char *text1 = prompt;
@@ -316,7 +314,7 @@
   pi2->check_cb_arg = pi->pin;
 
  next_try:
-  err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, r_cancel_all);
+  err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
   initial_errtext = NULL;
   if (!err)
     {
@@ -329,7 +327,7 @@
       /* Unless the passphrase is empty, ask to confirm it.  */
       if (pi->pin && *pi->pin)
         {
-          err = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL);
+          err = agent_askpin (ctrl, text2, NULL, NULL, pi2);
           if (err == -1)
             { /* The re-entered one did not match and the user did not
                  hit cancel. */
@@ -381,7 +379,7 @@
     rc = agent_ask_new_passphrase (ctrl, 
                                    _("Please enter the passphrase to%0A"
                                      "to protect your new key"),
-                                   &passphrase, NULL);
+                                   &passphrase);
   if (rc)
     return rc;
 
@@ -473,7 +471,7 @@
 
   rc = agent_ask_new_passphrase (ctrl, 
                                  _("Please enter the new passphrase"),
-                                 &passphrase, NULL);
+                                 &passphrase);
   if (!rc)
     {
       rc = store_key (s_skey, passphrase, 1);

Modified: trunk/agent/gpg-agent.c
===================================================================
--- trunk/agent/gpg-agent.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/gpg-agent.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -1523,6 +1523,8 @@
          a hang.  */
       if (!is_ssh && !check_for_running_agent (1, 1))
         {
+          log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX); 
+          log_set_file (NULL);
           log_error (_("a gpg-agent is already running - "
                        "not starting a new one\n"));
           *name = 0; /* Inhibit removal of the socket by cleanup(). */

Modified: trunk/agent/pkdecrypt.c
===================================================================
--- trunk/agent/pkdecrypt.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/pkdecrypt.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -67,8 +67,6 @@
   rc = agent_key_from_file (ctrl, NULL, desc_text,
                             ctrl->keygrip, &shadow_info,
                             CACHE_MODE_NORMAL, NULL, &s_skey, NULL);
-  if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
-    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
   if (rc)
     {
       if (gpg_err_code (rc) == GPG_ERR_ENOENT)

Modified: trunk/agent/pksign.c
===================================================================
--- trunk/agent/pksign.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/pksign.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -256,8 +256,6 @@
   rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip,
                             &shadow_info, cache_mode, lookup_ttl,
                             &s_skey, NULL);
-  if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
-    rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
   if (rc)
     {
       log_error ("failed to read the secret key\n");

Modified: trunk/agent/protect-tool.c
===================================================================
--- trunk/agent/protect-tool.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/agent/protect-tool.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -704,7 +704,8 @@
                               repeat, repeat, 1, &pw);
   if (err)
     {
-      if (gpg_err_code (err) == GPG_ERR_CANCELED)
+      if (gpg_err_code (err) == GPG_ERR_CANCELED
+          || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
         log_info (_("cancelled\n"));
       else
         log_error (_("error while asking for the passphrase: %s\n"),

Modified: trunk/common/miscellaneous.c
===================================================================
--- trunk/common/miscellaneous.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/common/miscellaneous.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -236,3 +236,81 @@
 }
 
 
+
+/* Parse the first portion of the version number S and store it at
+   NUMBER.  On success, the function returns a pointer into S starting
+   with the first character, which is not part of the initial number
+   portion; on failure, NULL is returned.  */
+static const char*
+parse_version_number (const char *s, int *number)
+{
+  int val = 0;
+  
+  if (*s == '0' && digitp (s+1))
+    return NULL; /* Leading zeros are not allowed.  */
+  for (; digitp (s); s++ )
+    {
+      val *= 10;
+      val += *s - '0';
+    }
+  *number = val;
+  return val < 0? NULL : s;
+}
+
+/* Break up the complete string representation of the version number S,
+   which is expected to have this format:
+
+      <major number>.<minor number>.<micro number><patch level>.
+
+   The major, minor and micro number components will be stored at
+   MAJOR, MINOR and MICRO. On success, a pointer to the last
+   component, the patch level, will be returned; on failure, NULL will
+   be returned.  */
+static const char *
+parse_version_string (const char *s, int *major, int *minor, int *micro)
+{
+  s = parse_version_number (s, major);
+  if (!s || *s != '.')
+    return NULL;
+  s++;
+  s = parse_version_number (s, minor);
+  if (!s || *s != '.')
+    return NULL;
+  s++;
+  s = parse_version_number (s, micro);
+  if (!s)
+    return NULL;
+  return s; /* Patchlevel.  */
+}
+
+/* Return true if version string is at least version B. */
+int
+gnupg_compare_version (const char *a, const char *b)
+{
+  int a_major, a_minor, a_micro;
+  int b_major, b_minor, b_micro;
+  const char *a_plvl, *b_plvl;
+
+  if (!a || !b)
+    return 0;
+
+  /* Parse version A.  */
+  a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
+  if (!a_plvl )
+    return 0; /* Invalid version number.  */
+
+  /* Parse version B.  */
+  b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
+  if (!b_plvl )
+    return 0; /* Invalid version number.  */
+
+  /* Compare version numbers.  */
+  return (a_major > b_major
+          || (a_major == b_major && a_minor > b_minor)
+          || (a_major == b_major && a_minor == b_minor
+              && a_micro > b_micro)
+          || (a_major == b_major && a_minor == b_minor
+              && a_micro == b_micro
+              && strcmp (a_plvl, b_plvl) >= 0));
+}
+

Modified: trunk/common/util.h
===================================================================
--- trunk/common/util.h	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/common/util.h	2010-10-13 15:57:08 UTC (rev 5444)
@@ -267,7 +267,9 @@
 
 int match_multistr (const char *multistr,const char *match);
 
+int gnupg_compare_version (const char *a, const char *b);
 
+
 /*-- Simple replacement functions. */
 #ifndef HAVE_TTYNAME
 /* Systems without ttyname (W32) will merely return NULL. */

Modified: trunk/doc/gpg.texi
===================================================================
--- trunk/doc/gpg.texi	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/doc/gpg.texi	2010-10-13 15:57:08 UTC (rev 5444)
@@ -1782,13 +1782,27 @@
 Use @var{name} as the key to sign with. Note that this option overrides
 @option{--default-key}.
 
+ at ifset gpgtwoone
+ at item --try-secret-key @var{name}
+ at opindex try-secret-key
+For hidden recipients GPG needs to know the keys to use for trial
+decryption.  The key set with @option{--default-key} is always tried
+first, but this is often not sufficient.  This option allows to set more
+keys to be used for trial decryption.  Although any valid user-id
+specification may be used for @var{name} it makes sense to use at least
+the long keyid to avoid ambiguities.  Note that gpg-agent might pop up a
+pinentry for a lot keys to do the trial decryption.  If you want to stop
+all further trial decryption you may use close-window button instead of
+the cancel button.
+ at end ifset
+
 @item --try-all-secrets
 @opindex try-all-secrets
 Don't look at the key ID as stored in the message but try all secret
 keys in turn to find the right decryption key. This option forces the
 behaviour as used by anonymous recipients (created by using
- at option{--throw-keyids}) and might come handy in case where an encrypted
-message contains a bogus key ID.
+ at option{--throw-keyids} or @option{--hidden-recipient}) and might come
+handy in case where an encrypted message contains a bogus key ID.
 
 @item --skip-hidden-recipients
 @itemx --no-skip-hidden-recipients

Modified: trunk/g10/call-agent.c
===================================================================
--- trunk/g10/call-agent.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/call-agent.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -99,6 +99,7 @@
     case 0:
       break;
     case GPG_ERR_CANCELED:
+    case GPG_ERR_FULLY_CANCELED:
       write_status_text (STATUS_SC_OP_FAILURE, "1");
       break;
     case GPG_ERR_BAD_PIN:
@@ -142,6 +143,11 @@
              agents.  */
           assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
                            NULL, NULL, NULL, NULL, NULL, NULL);
+          /* Tell the agent about what version we are aware.  This is
+             here used to indirectly enable GPG_ERR_FULLY_CANCELED.  */
+          assuan_transact (agent_ctx, "OPTION agent-awareness=2.1.0",
+                           NULL, NULL, NULL, NULL, NULL, NULL);
+          
         }
     }
 

Modified: trunk/g10/card-util.c
===================================================================
--- trunk/g10/card-util.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/card-util.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -58,6 +58,7 @@
       break;
 #if GNUPG_MAJOR_VERSION != 1
     case GPG_ERR_CANCELED:
+    case GPG_ERR_FULLY_CANCELED:
       write_status_text (STATUS_SC_OP_FAILURE, "1");
       break;
     case GPG_ERR_BAD_PIN:

Modified: trunk/g10/getkey.c
===================================================================
--- trunk/g10/getkey.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/getkey.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -568,8 +568,9 @@
  * first pubkey certificate which has the given name in a user_id.  If
  * PK has the pubkey algo set, the function will only return a pubkey
  * with that algo.  If NAMELIST is NULL, the first key is returned.
- * The caller should provide storage for the PK.  If RET_KB is not
- * NULL the function will return the keyblock there.  */
+ * The caller should provide storage for the PK or pass NULL if it is
+ * not needed.  If RET_KB is not NULL the function stores the entire
+ * keyblock at that address.  */
 static int
 key_byname (GETKEY_CTX *retctx, strlist_t namelist,
 	    PKT_public_key *pk,
@@ -1146,12 +1147,13 @@
 }
 
 
-/* Get a key by name and store it into PK.  If RETCTX is not NULL
- * return the search context which needs to be released by the caller
- * using getkey_end.  If NAME is NULL use the default key (see below).
- * On success and if RET_KEYBLOCK is not NULL the found keyblock is
- * stored at this address.  WANT_SECRET passed as true requires that a
- * secret key is available for the selected key.
+/* Get a key by name and store it into PK if that is not NULL.  If
+ * RETCTX is not NULL return the search context which needs to be
+ * released by the caller using getkey_end.  If NAME is NULL use the
+ * default key (see below).  On success and if RET_KEYBLOCK is not
+ * NULL the found keyblock is stored at this address.  WANT_SECRET
+ * passed as true requires that a secret key is available for the
+ * selected key.
  * 
  * If WANT_SECRET is true and NAME is NULL and a default key has been
  * defined that defined key is used.  In all other cases the first
@@ -2459,7 +2461,7 @@
 	  goto skip;
 	}
 
-      if (want_secret && !have_any_secret_key (NULL, ctx->keyblock))
+      if (want_secret && agent_probe_any_secret_key (NULL, ctx->keyblock))
         goto skip; /* No secret key available.  */
 
       /* Warning: node flag bits 0 and 1 should be preserved by
@@ -2504,57 +2506,42 @@
 
 
 
-/****************
- * FIXME: Replace by the generic function
- *        It does not work as it is right now - it is used at
- *        one place:  to get the key for an anonymous recipient.
- *
- * set with_subkeys true to include subkeys
- * set with_spm true to include secret-parts-missing keys
- *
- * Enumerate all primary secret keys.  Caller must use these procedure:
+/*
+ * Enumerate certain secret keys.  Caller must use these procedure:
  *  1) create a void pointer and initialize it to NULL
  *  2) pass this void pointer by reference to this function
  *     and provide space for the secret key (pass a buffer for sk)
- *  3) call this function as long as it does not return -1
- *     to indicate EOF.
+ *  3) call this function as long as it does not return an error.
+ *     The error code GPG_ERR_EOF indicates the end of the listing.
  *  4) Always call this function a last time with SK set to NULL,
  *     so that can free it's context.
  */
-int
-enum_secret_keys (void **context, PKT_public_key * sk,
-		  int with_subkeys, int with_spm)
+gpg_error_t
+enum_secret_keys (void **context, PKT_public_key *sk)
 {
-  log_debug ("FIXME: Anonymous recipient does not yet work\n");
-  return -1;
-#if 0
-
-  int rc = 0;
+  gpg_error_t err = 0;
+  const char *name;
   struct
   {
     int eof;
-    int first;
-    KEYDB_HANDLE hd;
-    KBNODE keyblock;
-    KBNODE node;
+    int state;
+    strlist_t sl;
+    kbnode_t keyblock;
+    kbnode_t node;
   } *c = *context;
 
-
   if (!c)
     {
       /* Make a new context.  */
-      c = xmalloc_clear (sizeof *c);
+      c = xtrycalloc (1, sizeof *c);
+      if (!c)
+        return gpg_error_from_syserror ();
       *context = c;
-      c->hd = keydb_new (1);  /*FIXME*/
-      c->first = 1;
-      c->keyblock = NULL;
-      c->node = NULL;
     }
 
   if (!sk)
     {
       /* Free the context.  */
-      keydb_release (c->hd);
       release_kbnode (c->keyblock);
       xfree (c);
       *context = NULL;
@@ -2562,48 +2549,79 @@
     }
 
   if (c->eof)
-    return -1;
+    return gpg_error (GPG_ERR_EOF);
 
-  do
+  for (;;)
     {
-      /* Get the next secret key from the current keyblock.  */
+      /* Loop until we have a keyblock.  */
+      while (!c->keyblock)
+        {
+          /* Loop over the list of secret keys.  */
+          do 
+            {
+              name = NULL;
+              switch (c->state)
+                {
+                case 0: /* First try to use the --default-key.  */
+                  if (opt.def_secret_key && *opt.def_secret_key)
+                    name = opt.def_secret_key;
+                  c->state = 1;
+                  break;
+                  
+                case 1: /* Init list of keys to try.  */
+                  c->sl = opt.secret_keys_to_try;
+                  c->state++;
+                  break;
+                  
+                case 2: /* Get next item from list.  */
+                  if (c->sl)
+                    {
+                      name = c->sl->d;
+                      c->sl = c->sl->next;
+                    }
+                  else
+                    c->state++;
+                  break;
+
+                default: /* No more names to check - stop.  */  
+                  c->eof = 1;
+                  return gpg_error (GPG_ERR_EOF);
+                }
+            }
+          while (!name || !*name);
+
+          err = getkey_byname (NULL, NULL, name, 1, &c->keyblock);
+          if (err)
+            {
+              /* getkey_byname might return a keyblock even in the
+                 error case - I have not checked.  Thus better release
+                 it.  */
+              release_kbnode (c->keyblock);
+              c->keyblock = NULL;
+            }
+          else
+            c->node = c->keyblock;
+        }
+      
+      /* Get the next key from the current keyblock.  */
       for (; c->node; c->node = c->node->next)
 	{
-	  if ((c->node->pkt->pkttype == PKT_SECRET_KEY
-	       || (with_subkeys
-		   && c->node->pkt->pkttype == PKT_SECRET_SUBKEY))
-	      && !(c->node->pkt->pkt.secret_key->protect.s2k.mode == 1001
-		   && !with_spm))
+	  if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
+              || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
 	    {
-	      copy_secret_key (sk, c->node->pkt->pkt.secret_key);
+	      copy_public_key (sk, c->node->pkt->pkt.public_key);
 	      c->node = c->node->next;
 	      return 0;	/* Found.  */
 	    }
-	}
+        }
+
+      /* Dispose the keyblock and continue.  */
       release_kbnode (c->keyblock);
-      c->keyblock = c->node = NULL;
-
-      rc = c->first ? keydb_search_first (c->hd) : keydb_search_next (c->hd);
-      c->first = 0;
-      if (rc)
-	{
-	  keydb_release (c->hd);
-	  c->hd = NULL;
-	  c->eof = 1;
-	  return -1; /* eof */
-	}
-
-      rc = keydb_get_keyblock (c->hd, &c->keyblock);
-      c->node = c->keyblock;
+      c->keyblock = NULL;
     }
-  while (!rc);
+}
 
-  return rc; /* Error.  */
-#endif
-}
 
-
-
 /*********************************************
  ***********  User ID printing helpers *******
  *********************************************/

Modified: trunk/g10/gpg.c
===================================================================
--- trunk/g10/gpg.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/gpg.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -177,6 +177,7 @@
     oDefRecipient,
     oDefRecipientSelf,
     oNoDefRecipient,
+    oTrySecretKey,
     oOptions,
     oDebug,
     oDebugLevel,
@@ -460,6 +461,8 @@
   ARGPARSE_s_s (oLocalUser, "local-user",
                 N_("|USER-ID|use USER-ID to sign or decrypt")),
 
+  ARGPARSE_s_s (oTrySecretKey, "try-secret-key", "@"),
+
   ARGPARSE_s_i (oCompress, NULL,
                 N_("|N|set compress level to N (0 disables)")),
   ARGPARSE_s_i (oCompressLevel, "compress-level", "@"),
@@ -1622,6 +1625,7 @@
   es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("default-key:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_NONE);
+  es_printf ("try-secret-key:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("auto-key-locate:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
   es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
@@ -2526,6 +2530,12 @@
 	    sl->flags = 2;
             any_explicit_recipient = 1;
 	    break;
+
+	  case oTrySecretKey: 
+	    add_to_strlist2 (&opt.secret_keys_to_try,
+                             pargs.r.ret_str, utf8_strings);
+	    break;
+
 	  case oTextmodeShort: opt.textmode = 2; break;
 	  case oTextmode: opt.textmode=1;  break;
 	  case oNoTextmode: opt.textmode=0;  break;

Modified: trunk/g10/gpgv.c
===================================================================
--- trunk/g10/gpgv.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/gpgv.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -546,3 +546,21 @@
   (void)pk;
   return gpg_error (GPG_ERR_NO_SECKEY);
 }
+
+gpg_error_t
+agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
+{
+  (void)ctrl;
+  (void)keyblock;
+  return gpg_error (GPG_ERR_NO_SECKEY);
+}
+
+gpg_error_t
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+{
+  (void)ctrl;
+  (void)hexkeygrip;
+  *r_serialno = NULL;
+  return gpg_error (GPG_ERR_NO_SECKEY);
+}
+  

Modified: trunk/g10/import.c
===================================================================
--- trunk/g10/import.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/import.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -362,7 +362,7 @@
  * Read the next keyblock from stream A.
  * PENDING_PKT should be initialzed to NULL
  * and not chnaged form the caller.
- * Retunr: 0 = okay, -1 no more blocks or another errorcode.
+ * Return: 0 = okay, -1 no more blocks or another errorcode.
  */
 static int
 read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
@@ -1142,8 +1142,15 @@
       stats->count++;
       stats->secret_read++;
 
-      /* For now we ignore the stub keys becuase we don't have real
-         support for them in gpg-agent.  */
+      /* We ignore stub keys.  The way we handle them in other parts
+         of the code is by asking the agent whether any secret key is
+         available for a given keyblock and then concluding that we
+         have a secret key; all secret (sub)keys of the keyblock the
+         agent does not know of are then stub keys.  This works also
+         for card stub keys.  The learn command or the card-status
+         command may be used to check with the agent whether a card
+         has been inserted and a stub key is in turn generated by the
+         agent.  */
       if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
         continue;
 
@@ -1288,7 +1295,8 @@
               write_status (STATUS_RSA_OR_IDEA);
               idea_cipher_warn (0);
             }
-          if (gpg_err_code (err) == GPG_ERR_CANCELED)
+          if (gpg_err_code (err) == GPG_ERR_CANCELED
+              || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
             break; /* Don't try the other subkeys.  */
         }
     }

Modified: trunk/g10/keydb.h
===================================================================
--- trunk/g10/keydb.h	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/keydb.h	2010-10-13 15:57:08 UTC (rev 5444)
@@ -241,11 +241,8 @@
                          kbnode_t *ret_keyblock);
 void getkey_end (getkey_ctx_t ctx);
 
-int have_any_secret_key (ctrl_t ctrl, kbnode_t keyblock);
+gpg_error_t enum_secret_keys (void **context, PKT_public_key *pk);
 
-
-//int enum_secret_keys( void **context, PKT_secret_key *sk,
-//		      int with_subkeys, int with_spm );
 void merge_keys_and_selfsig( KBNODE keyblock );
 char*get_user_id_string( u32 *keyid );
 char*get_user_id_string_native( u32 *keyid );

Modified: trunk/g10/keyedit.c
===================================================================
--- trunk/g10/keyedit.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/keyedit.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -1638,7 +1638,7 @@
   /* See whether we have a matching secret key.  */
   if (seckey_check)
     { 
-      have_seckey = have_any_secret_key (ctrl, keyblock);
+      have_seckey = !agent_probe_any_secret_key (ctrl, keyblock);
       if (have_seckey && !quiet)
 	tty_printf (_("Secret key is available.\n"));
     }

Modified: trunk/g10/keygen.c
===================================================================
--- trunk/g10/keygen.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/keygen.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -3441,6 +3441,8 @@
   u32 expire;
   unsigned int nbits;
   u32 cur_time;
+  char *hexgrip = NULL;
+  char *serialno = NULL;
 
   /* Break out the primary key.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@@ -3476,38 +3478,17 @@
       goto leave;
     }
 
-#warning ask gpg-agent on the availibility of the secret key
-  /* if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001) */
-  /*   { */
-  /*     tty_printf (_("Secret parts of primary key are not available.\n")); */
-  /*     err = G10ERR_NO_SECKEY; */
-  /*     goto leave; */
-  /*   } */
+  err = hexkeygrip_from_pk (pri_psk, &hexgrip);
+  if (err)
+    goto leave;
+  if (agent_get_keyinfo (NULL, hexgrip, &serialno))
+    {
+      tty_printf (_("Secret parts of primary key are not available.\n"));
+      goto leave;
+    }
+  if (serialno)
+    tty_printf (_("Secret parts of primary key are stored on-card.\n"));
 
-
-  /* /\* Unprotect to get the passphrase.  *\/ */
-  /* switch (is_secret_key_protected (pri_sk) ) */
-  /*   { */
-  /*   case -1: */
-  /*     err = G10ERR_PUBKEY_ALGO; */
-  /*     break; */
-  /*   case 0: */
-  /*     tty_printf (_("This key is not protected.\n")); */
-  /*     break; */
-  /*   case -2: */
-  /*     tty_printf (_("Secret parts of primary key are stored on-card.\n")); */
-  /*     ask_pass = 1; */
-  /*     break; */
-  /*   default: */
-  /*     tty_printf (_("Key is protected.\n")); */
-  /*     err = check_secret_key ( pri_sk, 0 ); */
-  /*     if (!err) */
-  /*       passphrase = get_last_passphrase(); */
-  /*     break; */
-  /*   } */
-  /* if (err) */
-  /*   goto leave; */
-
   algo = ask_algo (1, NULL, &use);
   assert (algo);
   nbits = ask_keysize (algo, 0);
@@ -3536,6 +3517,8 @@
   write_status_text (STATUS_KEY_CREATED, "S");
 
  leave:
+  xfree (hexgrip);
+  xfree (serialno);
   if (err)
     log_error (_("Key generation failed: %s\n"), g10_errstr (err) );
   return err;

Modified: trunk/g10/keylist.c
===================================================================
--- trunk/g10/keylist.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/keylist.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -40,11 +40,12 @@
 #include "main.h"
 #include "i18n.h"
 #include "status.h"
+#include "call-agent.h"
 
 static void list_all (int);
 static void list_one (strlist_t names, int secret);
 static void locate_one (ctrl_t ctrl, strlist_t names);
-static void print_card_serialno (PKT_public_key *sk);
+static void print_card_serialno (const char *serialno);
 
 struct sig_stats
 {
@@ -175,6 +176,7 @@
 
 /* Print basic information of a secret key including the card serial
    number information.  */
+#ifdef ENABLE_CARD_SUPPORT
 void
 print_card_key_info (estream_t fp, kbnode_t keyblock)
 {
@@ -224,9 +226,9 @@
   /*       } */
   /*   } */
 }
+#endif /*ENABLE_CARD_SUPPORT*/
 
 
-
 /* Flags = 0x01 hashed 0x02 critical.  */
 static void
 status_one_subpacket (sigsubpkttype_t type, size_t len, int flags,
@@ -444,7 +446,7 @@
 	  log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc));
 	  goto leave;
 	}
-      if (secret && !have_any_secret_key (NULL, keyblock))
+      if (secret && agent_probe_any_secret_key (NULL, keyblock))
         ; /* Secret key listing requested but this isn't one.  */
       else
         {
@@ -757,13 +759,15 @@
 static void
 list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
 {
-  int rc = 0;
+  int rc;
   KBNODE kbctx;
   KBNODE node;
   PKT_public_key *pk;
   struct sig_stats *stats = opaque;
   int skip_sigs = 0;
   int s2k_char;
+  char *hexgrip = NULL;
+  char *serialno = NULL;
 
   /* Get the keyid from the keyblock.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@@ -775,11 +779,24 @@
     }
 
   pk = node->pkt->pkt.public_key;
+
+  if (secret || opt.with_keygrip)
+    {
+      rc = hexkeygrip_from_pk (pk, &hexgrip);
+      if (rc)
+        log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
+    }
+
+  if (secret)
+    {
+      if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
+        s2k_char = serialno? '>':' ';
+      else
+        s2k_char = '#';  /* Key not found.  */
+    }
+  else
+    s2k_char = ' ';
   
-  /* Fixme: Get s2k mode from the agent.  */
-  s2k_char = (/*(sk->protect.s2k.mode == 1001)? '#' :
-                (sk->protect.s2k.mode == 1002)? '>' : */' ');
-  
   check_trustdb_stale ();
 
   es_fprintf (es_stdout, "%s%c  %4u%c/%s %s", 
@@ -822,20 +839,12 @@
   if (fpr)
     print_fingerprint (pk, 0);
 
-  if (opt.with_keygrip)
-    {
-      char *p;
+  if (opt.with_keygrip && hexgrip)
+    es_fprintf (es_stdout, "      Keygrip = %s\n", hexgrip);
 
-      if (!hexkeygrip_from_pk (pk, &p))
-        {
-          es_fprintf (es_stdout, "      Keygrip = %s\n", p);
-          xfree (p);
-        }
-    }
+  if (serialno)
+    print_card_serialno (serialno);
 
-  /* FIXME: Change this function to take a PK and ask the agent:  */
-  /* if (secret) print_card_serialno (sk); */
-
   if (opt.with_key_data)
     print_key_data (pk);
 
@@ -895,10 +904,25 @@
 	  else
 	    skip_sigs = 0;
 
-          /* Fixme: Get s2k mode from the agent.  */
-          s2k_char = (/*(sk->protect.s2k.mode == 1001)? '#' :
-                        (sk->protect.s2k.mode == 1002)? '>' : */' ');
-
+          xfree (serialno); serialno = NULL;
+          xfree (hexgrip); hexgrip = NULL;
+          if (secret || opt.with_keygrip)
+            {
+              rc = hexkeygrip_from_pk (pk2, &hexgrip);
+              if (rc)
+                log_error ("error computing a keygrip: %s\n",
+                           gpg_strerror (rc));
+            }
+          if (secret)
+            {
+              if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
+                s2k_char = serialno? '>':' ';
+              else
+                s2k_char = '#';  /* Key not found.  */
+            }
+          else
+            s2k_char = ' ';
+          
 	  es_fprintf (es_stdout, "%s%c  %4u%c/%s %s",
                   secret? "ssb":"sub",
                   s2k_char,
@@ -926,20 +950,11 @@
 	  if (fpr > 1)
             {
               print_fingerprint (pk2, 0);
-              /* FIXME: (see above) */
-              /* if (secret) */
-              /*   print_card_serialno (sk2); */
+              if (serialno)
+                print_card_serialno (serialno);
             }
-          if (opt.with_keygrip)
-            {
-              char *p;
-              
-              if (!hexkeygrip_from_pk (pk2, &p))
-                {
-                  es_fprintf (es_stdout, "      Keygrip = %s\n", p);
-                  xfree (p);
-                }
-            }
+          if (opt.with_keygrip && hexgrip)
+            es_fprintf (es_stdout, "      Keygrip = %s\n", hexgrip);
 	  if (opt.with_key_data)
 	    print_key_data (pk2);
 	}
@@ -1050,6 +1065,8 @@
 	}
     }
   es_putc ('\n', es_stdout);
+  xfree (serialno);
+  xfree (hexgrip);
 }
 
 void
@@ -1079,7 +1096,7 @@
 static void
 list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
 {
-  int rc = 0;
+  int rc;
   KBNODE kbctx;
   KBNODE node;
   PKT_public_key *pk;
@@ -1088,6 +1105,9 @@
   int ulti_hack = 0;
   int i;
   char *p;
+  char *hexgrip = NULL;
+  char *serialno = NULL;
+  int stubkey;
 
   /* Get the keyid from the keyblock.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@@ -1099,6 +1119,15 @@
     }
 
   pk = node->pkt->pkt.public_key;
+  if (secret || opt.with_keygrip || opt.with_key_data)
+    {
+      rc = hexkeygrip_from_pk (pk, &hexgrip);
+      if (rc)
+        log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
+    }
+  stubkey = 0;
+  if (secret && agent_get_keyinfo (NULL, hexgrip, &serialno))
+    stubkey = 1;  /* Key not found.  */
 
   keyid_from_pk (pk, keyid);
   es_fputs (secret? "sec:":"pub:", es_stdout);
@@ -1135,16 +1164,10 @@
     {
       es_putc (':', es_stdout);		/* End of field 13. */
       es_putc (':', es_stdout);		/* End of field 14. */
-      if (/*FIXME sk->protect.s2k.mode*/1 == 1001)
-	es_putc ('#', es_stdout);		/* Key is just a stub. */
-      else if (/*FIXME sk->protect.s2k.mode*/1 == 1002)
-	{
-	  /* Key is stored on an external token (card) or handled by
-	     the gpg-agent.  Print the serial number of that token
-	     here. */
-	  /* FIXME: for (i = 0; i < sk->protect.ivlen; i++) */
-	  /*   es_fprintf (es_stdout, "%02X", sk->protect.iv[i]); */
-	}
+      if (stubkey)
+	es_putc ('#', es_stdout);
+      else if (serialno)
+        es_fputs(serialno, es_stdout);
       es_putc (':', es_stdout);		/* End of field 15. */
     }
   es_putc ('\n', es_stdout);
@@ -1154,11 +1177,8 @@
     print_fingerprint (pk, 0);
   if (opt.with_key_data || opt.with_keygrip)
     {
-      if (!hexkeygrip_from_pk (pk, &p))
-        {
-          es_fprintf (es_stdout, "grp:::::::::%s:\n", p);
-          xfree (p);
-        }
+      if (hexgrip)
+        es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
       if (opt.with_key_data)
         print_key_data (pk);
     }
@@ -1213,8 +1233,22 @@
       else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
 	{
 	  u32 keyid2[2];
-	  PKT_public_key *pk2 = node->pkt->pkt.public_key;
+	  PKT_public_key *pk2;
 
+          pk2 = node->pkt->pkt.public_key;
+          xfree (hexgrip); hexgrip = NULL;
+          xfree (serialno); serialno = NULL;
+          if (secret || opt.with_keygrip || opt.with_key_data)
+            {
+              rc = hexkeygrip_from_pk (pk2, &hexgrip);
+              if (rc)
+                log_error ("error computing a keygrip: %s\n",
+                           gpg_strerror (rc));
+            }
+          stubkey = 0;
+          if (secret && agent_get_keyinfo (NULL, hexgrip, &serialno))
+            stubkey = 1;  /* Key not found.  */
+
 	  keyid_from_pk (pk2, keyid2);
 	  es_fputs (secret? "ssb:":"sub:", es_stdout);
 	  if (!pk2->is_valid)
@@ -1243,16 +1277,10 @@
             {
               es_putc (':', es_stdout);	/* End of field 13. */
               es_putc (':', es_stdout);	/* End of field 14. */
-              if (/*FIXME:sk2->protect.s2k.mode*/1 == 1001)
-                es_putc ('#', es_stdout);	/* Key is just a stub. */
-              else if (/*FIXME: sk2->protect.s2k.mode*/1 == 1002)
-                {
-                  /* Key is stored on an external token (card) or
-                     handled by the gpg-agent.  Print the serial
-                     number of that token here. */
-                  /* FIXME: for (i = 0; i < sk2->protect.ivlen; i++)
-                     es_fprintf (es_stdout, "%02X", sk2->protect.iv[i]); */
-                }
+              if (stubkey)
+                es_putc ('#', es_stdout);
+              else if (serialno)
+                es_fputs (serialno, es_stdout);
               es_putc (':', es_stdout);	/* End of field 15. */
             }
 	  es_putc ('\n', es_stdout);
@@ -1260,11 +1288,8 @@
 	    print_fingerprint (pk2, 0);
 	  if (opt.with_key_data || opt.with_keygrip)
             {
-              if (!hexkeygrip_from_pk (pk2, &p))
-                {
-                  es_fprintf (es_stdout, "grp:::::::::%s:\n", p);
-                  xfree (p);
-                }
+              if (hexgrip)
+                es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
               if (opt.with_key_data)
                 print_key_data (pk2);
             }
@@ -1385,6 +1410,9 @@
 	  /* fixme: check or list other sigs here */
 	}
     }
+
+  xfree (hexgrip);
+  xfree (serialno);
 }
 
 /*
@@ -1550,38 +1578,25 @@
 
 /* Print the serial number of an OpenPGP card if available.  */
 static void
-print_card_serialno (PKT_public_key *pk)
+print_card_serialno (const char *serialno)
 {
-  log_debug ("Fixme: Needs to be adjusted to gpg-agent\n");
-  /* int i; */
+  if (!serialno)
+    return;
+  if (opt.with_colons)
+    return; /* Handled elsewhere. */
 
-  /* if (!sk) */
-  /*   return; */
-  /* if (!sk->is_protected || sk->protect.s2k.mode != 1002) */
-  /*   return; /\* Not a card. *\/ */
-  /* if (opt.with_colons) */
-  /*   return; /\* Handled elsewhere. *\/ */
-
-  /* es_fputs (_("      Card serial no. ="), es_stdout); */
-  /* es_putc (' ', es_stdout); */
-  /* if (sk->protect.ivlen == 16 */
-  /*     && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6)) */
-  /*   {		 */
-  /*     /\* This is an OpenPGP card. Just print the relevant part.  *\/ */
-  /*     for (i = 8; i < 14; i++) */
-  /*       { */
-  /*         if (i == 10) */
-  /*           es_putc (' ', es_stdout); */
-  /*         es_fprintf (es_stdout, "%02X", sk->protect.iv[i]); */
-  /*       } */
-  /*   } */
-  /* else */
-  /*   { */
-  /*     /\* Something is wrong: Print all.  *\/ */
-  /*     for (i = 0; i < sk->protect.ivlen; i++) */
-  /*       es_fprintf (es_stdout, "%02X", sk->protect.iv[i]); */
-  /*   } */
-  /* es_putc ('\n', es_stdout); */
+  es_fputs (_("      Card serial no. ="), es_stdout);
+  es_putc (' ', es_stdout);
+  if (strlen (serialno) == 32 && !strncmp (serialno, "D27600012401", 12))
+    {
+      /* This is an OpenPGP card.  Print the relevant part.  */
+      /* Example: D2760001240101010001000003470000 */
+      /*                          xxxxyyyyyyyy     */
+      es_fprintf (es_stdout, "%.*s %.*s", 4, serialno+16, 8, serialno+20);
+    }
+ else
+   es_fputs (serialno, es_stdout);
+  es_putc ('\n', es_stdout);
 }
 
 

Modified: trunk/g10/misc.c
===================================================================
--- trunk/g10/misc.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/misc.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -555,11 +555,10 @@
   /*     if(agent_scd_getattr("SIG-COUNTER",&info)==0) */
   /*       return info.sig_counter; */
   /*   }   */
-#endif
-
-  /* How to do this without a card? */
-
+#else
+  (void)pk;
   return 0;
+#endif
 }
 
 /* Expand %-strings.  Returns a string which must be xfreed.  Returns

Modified: trunk/g10/options.h
===================================================================
--- trunk/g10/options.h	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/options.h	2010-10-13 15:57:08 UTC (rev 5444)
@@ -79,6 +79,8 @@
   const char *def_secret_key;
   char *def_recipient;
   int def_recipient_self;
+  strlist_t secret_keys_to_try;
+
   int def_cert_level;
   int min_cert_level;
   int ask_cert_level;

Modified: trunk/g10/passphrase.c
===================================================================
--- trunk/g10/passphrase.c	2010-10-11 12:36:27 UTC (rev 5443)
+++ trunk/g10/passphrase.c	2010-10-13 15:57:08 UTC (rev 5444)
@@ -211,17 +211,6 @@
   return p;
 }
 
-/* As if we had used the passphrase - make it the last_pw. */
-void
-next_to_last_passphrase(void)
-{
-  if (next_pw)
-    {
-      last_pw=next_pw;
-      next_pw=NULL;
-    }
-}
-
 /* Here's an interesting question: since this passphrase was passed in
    on the command line, is there really any point in using secure
    memory for it?  I'm going with 'yes', since it doesn't hurt, and
@@ -407,7 +396,8 @@
 
   if (!rc)




More information about the Gnupg-commits mailing list