gpg: Change --show-session-key to print the session key earlier.
[gnupg.git] / g10 / getkey.c
index 8d98348..4453a92 100644 (file)
@@ -128,17 +128,20 @@ void
 cache_public_key (PKT_public_key * pk)
 {
 #if MAX_PK_CACHE_ENTRIES
 cache_public_key (PKT_public_key * pk)
 {
 #if MAX_PK_CACHE_ENTRIES
-  pk_cache_entry_t ce;
+  pk_cache_entry_t ce, ce2;
   u32 keyid[2];
 
   if (pk_cache_disabled)
     return;
 
   u32 keyid[2];
 
   if (pk_cache_disabled)
     return;
 
-  if (pk->dont_cache)
+  if (pk->flags.dont_cache)
     return;
 
   if (is_ELGAMAL (pk->pubkey_algo)
     return;
 
   if (is_ELGAMAL (pk->pubkey_algo)
-      || pk->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA (pk->pubkey_algo))
+      || pk->pubkey_algo == PUBKEY_ALGO_DSA
+      || pk->pubkey_algo == PUBKEY_ALGO_ECDSA
+      || pk->pubkey_algo == PUBKEY_ALGO_ECDH
+      || is_RSA (pk->pubkey_algo))
     {
       keyid_from_pk (pk, keyid);
     }
     {
       keyid_from_pk (pk, keyid);
     }
@@ -155,11 +158,25 @@ cache_public_key (PKT_public_key * pk)
 
   if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES)
     {
 
   if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES)
     {
-      /* fixme: Use another algorithm to free some cache slots.  */
-      pk_cache_disabled = 1;
-      if (opt.verbose > 1)
-       log_info (_("too many entries in pk cache - disabled\n"));
-      return;
+      int n;
+
+      /* Remove the last 50% of the entries.  */
+      for (ce = pk_cache, n = 0; ce && n < pk_cache_entries/2; n++)
+        ce = ce->next;
+      if (ce != pk_cache && ce->next)
+        {
+          ce2 = ce->next;
+          ce->next = NULL;
+          ce = ce2;
+          for (; ce; ce = ce2)
+            {
+              ce2 = ce->next;
+              free_public_key (ce->pk);
+              xfree (ce);
+              pk_cache_entries--;
+            }
+        }
+      assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
     }
   pk_cache_entries++;
   ce = xmalloc (sizeof *ce);
     }
   pk_cache_entries++;
   ce = xmalloc (sizeof *ce);
@@ -428,7 +445,7 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
 
   hd = keydb_new ();
   rc = keydb_search_kid (hd, keyid);
 
   hd = keydb_new ();
   rc = keydb_search_kid (hd, keyid);
-  if (rc == -1)
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
@@ -441,8 +458,9 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
       return G10ERR_NO_PUBKEY;
     }
 
       return G10ERR_NO_PUBKEY;
     }
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
-         || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+  assert (keyblock && keyblock->pkt
+          && (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY));
 
   keyid_from_pk (keyblock->pkt->pkt.public_key, pkid);
   if (keyid[0] == pkid[0] && keyid[1] == pkid[1])
 
   keyid_from_pk (keyblock->pkt->pkt.public_key, pkid);
   if (keyid[0] == pkid[0] && keyid[1] == pkid[1])
@@ -568,8 +586,9 @@ leave:
  * 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.
  * 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,
 static int
 key_byname (GETKEY_CTX *retctx, strlist_t namelist,
            PKT_public_key *pk,
@@ -613,7 +632,7 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
        {
          gpg_error_t err;
 
        {
          gpg_error_t err;
 
-         err = classify_user_id (r->d, &ctx->items[n]);
+         err = classify_user_id (r->d, &ctx->items[n], 1);
 
          if (ctx->items[n].exact)
            ctx->exact = 1;
 
          if (ctx->items[n].exact)
            ctx->exact = 1;
@@ -868,12 +887,12 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
          if (!rc)
            {
              /* Key found.  */
          if (!rc)
            {
              /* Key found.  */
-             log_info (_("automatically retrieved `%s' via %s\n"),
+             log_info (_("automatically retrieved '%s' via %s\n"),
                        name, mechanism);
              break;
            }
          if (rc != G10ERR_NO_PUBKEY || opt.verbose || no_fingerprint)
                        name, mechanism);
              break;
            }
          if (rc != G10ERR_NO_PUBKEY || opt.verbose || no_fingerprint)
-           log_info (_("error retrieving `%s' via %s: %s\n"),
+           log_info (_("error retrieving '%s' via %s: %s\n"),
                      name, mechanism,
                      no_fingerprint ? _("No fingerprint") : g10_errstr (rc));
        }
                      name, mechanism,
                      no_fingerprint ? _("No fingerprint") : g10_errstr (rc));
        }
@@ -988,7 +1007,7 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
 
   hd = keydb_new ();
   rc = keydb_search_fpr (hd, fprbuf);
 
   hd = keydb_new ();
   rc = keydb_search_fpr (hd, fprbuf);
-  if (rc == -1)
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
@@ -1135,7 +1154,7 @@ get_seckeyblock_byfprint (kbnode_t *ret_keyblock,
 
 
 \f
 
 
 \f
-/* The new function to return a key.  
+/* The new function to return a key.
    FIXME: Document it.  */
 gpg_error_t
 getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
    FIXME: Document it.  */
 gpg_error_t
 getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
@@ -1146,17 +1165,18 @@ getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
 }
 
 
 }
 
 
-/* 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
  * 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
- * available key is used. 
- * 
+ * available key is used.
+ *
  * FIXME: Explain what is up with unusable keys.
  *
  * FIXME: We also have the get_pubkey_byname function which has a
  * FIXME: Explain what is up with unusable keys.
  *
  * FIXME: We also have the get_pubkey_byname function which has a
@@ -1179,7 +1199,7 @@ getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
 
   err = key_byname (retctx, namelist, pk, want_secret, with_unusable,
                     ret_keyblock, NULL);
 
   err = key_byname (retctx, namelist, pk, want_secret, with_unusable,
                     ret_keyblock, NULL);
-  
+
   /* FIXME: Check that we really return GPG_ERR_NO_SECKEY if
      WANT_SECRET has been used.  */
 
   /* FIXME: Check that we really return GPG_ERR_NO_SECKEY if
      WANT_SECRET has been used.  */
 
@@ -1271,13 +1291,19 @@ parse_key_usage (PKT_signature * sig)
 
       if (flags)
        key_usage |= PUBKEY_USAGE_UNKNOWN;
 
       if (flags)
        key_usage |= PUBKEY_USAGE_UNKNOWN;
+
+      if (!key_usage)
+       key_usage |= PUBKEY_USAGE_NONE;
     }
     }
+  else if (p) /* Key flags of length zero.  */
+    key_usage |= PUBKEY_USAGE_NONE;
 
   /* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a
      capability that we do not handle.  This serves to distinguish
      between a zero key usage which we handle as the default
      capabilities for that algorithm, and a usage that we do not
 
   /* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a
      capability that we do not handle.  This serves to distinguish
      between a zero key usage which we handle as the default
      capabilities for that algorithm, and a usage that we do not
-     handle. */
+     handle.  Likewise we use PUBKEY_USAGE_NONE to indicate that
+     key_flags have been given but they do not specify any usage.  */
 
   return key_usage;
 }
 
   return key_usage;
 }
@@ -1409,6 +1435,8 @@ sig_to_revoke_info (PKT_signature * sig, struct revoke_info *rinfo)
   rinfo->keyid[1] = sig->keyid[1];
 }
 
   rinfo->keyid[1] = sig->keyid[1];
 }
 
+
+/* Note that R_REVOKED may be set to 0, 1 or 2.  */
 static void
 merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                     struct revoke_info *rinfo)
 static void
 merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                     struct revoke_info *rinfo)
@@ -1569,7 +1597,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
 
       /* Mark that key as valid: One direct key signature should
        * render a key as valid.  */
 
       /* Mark that key as valid: One direct key signature should
        * render a key as valid.  */
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* Pass 1.5: Look for key revocation signatures that were not made
     }
 
   /* Pass 1.5: Look for key revocation signatures that were not made
@@ -1597,7 +1625,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                    break;
                  }
                else if (rc == G10ERR_NO_PUBKEY)
                    break;
                  }
                else if (rc == G10ERR_NO_PUBKEY)
-                 pk->maybe_revoked = 1;
+                 pk->flags.maybe_revoked = 1;
 
                /* A failure here means the sig did not verify, was
                   not issued by a revocation key, or a revocation
 
                /* A failure here means the sig did not verify, was
                   not issued by a revocation key, or a revocation
@@ -1621,7 +1649,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
          if (uidnode && signode)
            {
              fixup_uidnode (uidnode, signode, keytimestamp);
          if (uidnode && signode)
            {
              fixup_uidnode (uidnode, signode, keytimestamp);
-             pk->is_valid = 1;
+             pk->flags.valid = 1;
            }
          uidnode = k;
          signode = NULL;
            }
          uidnode = k;
          signode = NULL;
@@ -1657,22 +1685,22 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
   if (uidnode && signode)
     {
       fixup_uidnode (uidnode, signode, keytimestamp);
   if (uidnode && signode)
     {
       fixup_uidnode (uidnode, signode, keytimestamp);
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* If the key isn't valid yet, and we have
      --allow-non-selfsigned-uid set, then force it valid. */
     }
 
   /* If the key isn't valid yet, and we have
      --allow-non-selfsigned-uid set, then force it valid. */
-  if (!pk->is_valid && opt.allow_non_selfsigned_uid)
+  if (!pk->flags.valid && opt.allow_non_selfsigned_uid)
     {
       if (opt.verbose)
        log_info (_("Invalid key %s made valid by"
                    " --allow-non-selfsigned-uid\n"), keystr_from_pk (pk));
     {
       if (opt.verbose)
        log_info (_("Invalid key %s made valid by"
                    " --allow-non-selfsigned-uid\n"), keystr_from_pk (pk));
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* The key STILL isn't valid, so try and find an ultimately
      trusted signature. */
     }
 
   /* The key STILL isn't valid, so try and find an ultimately
      trusted signature. */
-  if (!pk->is_valid)
+  if (!pk->flags.valid)
     {
       uidnode = NULL;
 
     {
       uidnode = NULL;
 
@@ -1703,7 +1731,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                      && get_ownertrust (ultimate_pk) == TRUST_ULTIMATE)
                    {
                      free_public_key (ultimate_pk);
                      && get_ownertrust (ultimate_pk) == TRUST_ULTIMATE)
                    {
                      free_public_key (ultimate_pk);
-                     pk->is_valid = 1;
+                     pk->flags.valid = 1;
                      break;
                    }
 
                      break;
                    }
 
@@ -1940,7 +1968,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
   subpk = subnode->pkt->pkt.public_key;
   keytimestamp = subpk->timestamp;
 
   subpk = subnode->pkt->pkt.public_key;
   keytimestamp = subpk->timestamp;
 
-  subpk->is_valid = 0;
+  subpk->flags.valid = 0;
   subpk->main_keyid[0] = mainpk->main_keyid[0];
   subpk->main_keyid[1] = mainpk->main_keyid[1];
 
   subpk->main_keyid[0] = mainpk->main_keyid[0];
   subpk->main_keyid[1] = mainpk->main_keyid[1];
 
@@ -1967,7 +1995,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
                     subkeys rather than re-sign old ones as the
                     problem is in the distribution.  Plus, PGP (7)
                     does this the same way.  */
                     subkeys rather than re-sign old ones as the
                     problem is in the distribution.  Plus, PGP (7)
                     does this the same way.  */
-                 subpk->is_revoked = 1;
+                 subpk->flags.revoked = 1;
                  sig_to_revoke_info (sig, &subpk->revoked);
                  /* Although we could stop now, we continue to
                   * figure out other information like the old expiration
                  sig_to_revoke_info (sig, &subpk->revoked);
                  /* Although we could stop now, we continue to
                   * figure out other information like the old expiration
@@ -2023,10 +2051,10 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
   if (openpgp_pk_test_algo (subpk->pubkey_algo))
     return;
 
   if (openpgp_pk_test_algo (subpk->pubkey_algo))
     return;
 
-  subpk->is_valid = 1;
+  subpk->flags.valid = 1;
 
   /* Find the most recent 0x19 embedded signature on our self-sig. */
 
   /* Find the most recent 0x19 embedded signature on our self-sig. */
-  if (subpk->backsig == 0)
+  if (!subpk->flags.backsig)
     {
       int seq = 0;
       size_t n;
     {
       int seq = 0;
       size_t n;
@@ -2091,9 +2119,9 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
 
          /* 2==valid, 1==invalid, 0==didn't check */
          if (check_backsig (mainpk, subpk, backsig) == 0)
 
          /* 2==valid, 1==invalid, 0==didn't check */
          if (check_backsig (mainpk, subpk, backsig) == 0)
-           subpk->backsig = 2;
+           subpk->flags.backsig = 2;
          else
          else
-           subpk->backsig = 1;
+           subpk->flags.backsig = 1;
 
          free_seckey_enc (backsig);
        }
 
          free_seckey_enc (backsig);
        }
@@ -2121,7 +2149,7 @@ merge_selfsigs (KBNODE keyblock)
   struct revoke_info rinfo;
   PKT_public_key *main_pk;
   prefitem_t *prefs;
   struct revoke_info rinfo;
   PKT_public_key *main_pk;
   prefitem_t *prefs;
-  int mdc_feature;
+  unsigned int mdc_feature;
 
   if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
     {
 
   if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
     {
@@ -2149,7 +2177,7 @@ merge_selfsigs (KBNODE keyblock)
     }
 
   main_pk = keyblock->pkt->pkt.public_key;
     }
 
   main_pk = keyblock->pkt->pkt.public_key;
-  if (revoked || main_pk->has_expired || !main_pk->is_valid)
+  if (revoked || main_pk->has_expired || !main_pk->flags.valid)
     {
       /* If the primary key is revoked, expired, or invalid we
        * better set the appropriate flags on that key and all
     {
       /* If the primary key is revoked, expired, or invalid we
        * better set the appropriate flags on that key and all
@@ -2160,11 +2188,11 @@ merge_selfsigs (KBNODE keyblock)
              || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
            {
              PKT_public_key *pk = k->pkt->pkt.public_key;
              || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
            {
              PKT_public_key *pk = k->pkt->pkt.public_key;
-             if (!main_pk->is_valid)
-               pk->is_valid = 0;
-             if (revoked && !pk->is_revoked)
+             if (!main_pk->flags.valid)
+               pk->flags.valid = 0;
+             if (revoked && !pk->flags.revoked)
                {
                {
-                 pk->is_revoked = revoked;
+                 pk->flags.revoked = revoked;
                  memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
                }
              if (main_pk->has_expired)
                  memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
                }
              if (main_pk->has_expired)
@@ -2204,7 +2232,7 @@ merge_selfsigs (KBNODE keyblock)
          if (pk->prefs)
            xfree (pk->prefs);
          pk->prefs = copy_prefs (prefs);
          if (pk->prefs)
            xfree (pk->prefs);
          pk->prefs = copy_prefs (prefs);
-         pk->mdc_feature = mdc_feature;
+         pk->flags.mdc = mdc_feature;
        }
     }
 }
        }
     }
 }
@@ -2311,13 +2339,13 @@ finish_lookup (GETKEY_CTX ctx)
          if (DBG_CACHE)
            log_debug ("\tchecking subkey %08lX\n",
                       (ulong) keyid_from_pk (pk, NULL));
          if (DBG_CACHE)
            log_debug ("\tchecking subkey %08lX\n",
                       (ulong) keyid_from_pk (pk, NULL));
-         if (!pk->is_valid)
+         if (!pk->flags.valid)
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey not valid\n");
              continue;
            }
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey not valid\n");
              continue;
            }
-         if (pk->is_revoked)
+         if (pk->flags.revoked)
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey has been revoked\n");
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey has been revoked\n");
@@ -2366,12 +2394,12 @@ finish_lookup (GETKEY_CTX ctx)
       if (DBG_CACHE && !foundk && !req_prim)
        log_debug ("\tno suitable subkeys found - trying primary\n");
       pk = keyblock->pkt->pkt.public_key;
       if (DBG_CACHE && !foundk && !req_prim)
        log_debug ("\tno suitable subkeys found - trying primary\n");
       pk = keyblock->pkt->pkt.public_key;
-      if (!pk->is_valid)
+      if (!pk->flags.valid)
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key not valid\n");
        }
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key not valid\n");
        }
-      else if (pk->is_revoked)
+      else if (pk->flags.revoked)
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key has been revoked\n");
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key has been revoked\n");
@@ -2443,7 +2471,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
   int no_suitable_key = 0;
 
   rc = 0;
   int no_suitable_key = 0;
 
   rc = 0;
-  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems)))
+  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL)))
     {
       /* If we are searching for the first key we have to make sure
          that the next iteration does not do an implicit reset.
     {
       /* If we are searching for the first key we have to make sure
          that the next iteration does not do an implicit reset.
@@ -2459,7 +2487,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
          goto skip;
        }
 
          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
         goto skip; /* No secret key available.  */
 
       /* Warning: node flag bits 0 and 1 should be preserved by
@@ -2479,9 +2507,9 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
       release_kbnode (ctx->keyblock);
       ctx->keyblock = NULL;
     }
       release_kbnode (ctx->keyblock);
       ctx->keyblock = NULL;
     }
-  
+
 found:
 found:
-  if (rc && rc != -1)
+  if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     log_error ("keydb_search failed: %s\n", g10_errstr (rc));
 
   if (!rc)
     log_error ("keydb_search failed: %s\n", g10_errstr (rc));
 
   if (!rc)
@@ -2489,9 +2517,9 @@ found:
       *ret_keyblock = ctx->keyblock; /* Return the keyblock.  */
       ctx->keyblock = NULL;
     }
       *ret_keyblock = ctx->keyblock; /* Return the keyblock.  */
       ctx->keyblock = NULL;
     }
-  else if (rc == -1 && no_suitable_key)
+  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key)
     rc = want_secret? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
     rc = want_secret? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
-  else if (rc == -1)
+  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     rc = want_secret? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
 
   release_kbnode (ctx->keyblock);
     rc = want_secret? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
 
   release_kbnode (ctx->keyblock);
@@ -2504,57 +2532,42 @@ found:
 
 
 
 
 
 
-/****************
- * 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)
  *  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.
  */
  *  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;
   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;
 
   } *c = *context;
 
-
   if (!c)
     {
       /* Make a new 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;
       *context = c;
-      c->hd = keydb_new (1);  /*FIXME*/
-      c->first = 1;
-      c->keyblock = NULL;
-      c->node = NULL;
     }
 
   if (!sk)
     {
       /* Free the context.  */
     }
 
   if (!sk)
     {
       /* Free the context.  */
-      keydb_release (c->hd);
       release_kbnode (c->keyblock);
       xfree (c);
       *context = NULL;
       release_kbnode (c->keyblock);
       xfree (c);
       *context = NULL;
@@ -2562,48 +2575,79 @@ enum_secret_keys (void **context, PKT_public_key * sk,
     }
 
   if (c->eof)
     }
 
   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)
        {
       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.  */
            }
              c->node = c->node->next;
              return 0; /* Found.  */
            }
-       }
-      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;
+      /* Dispose the keyblock and continue.  */
+      release_kbnode (c->keyblock);
+      c->keyblock = NULL;
     }
     }
-  while (!rc);
-
-  return rc; /* Error.  */
-#endif
 }
 }
-\f
-
 
 
+\f
 /*********************************************
  ***********  User ID printing helpers *******
  *********************************************/
 /*********************************************
  ***********  User ID printing helpers *******
  *********************************************/
@@ -2852,7 +2896,7 @@ have_secret_key_with_kid (u32 *keyid)
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0] = keyid[0];
   desc.u.kid[1] = keyid[1];
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0] = keyid[0];
   desc.u.kid[1] = keyid[1];
-  while (!result && !(err = keydb_search (kdbhd, &desc, 1)))
+  while (!result && !(err = keydb_search (kdbhd, &desc, 1, NULL)))
     {
       desc.mode = KEYDB_SEARCH_MODE_NEXT;
       err = keydb_get_keyblock (kdbhd, &keyblock);
     {
       desc.mode = KEYDB_SEARCH_MODE_NEXT;
       err = keydb_get_keyblock (kdbhd, &keyblock);