[git] GnuPG - branch, master, updated. gnupg-2.1.10-60-g5c75992

by Neal H. Walfield cvs at cvs.gnupg.org
Tue Dec 22 15:16:57 CET 2015


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  5c759924fb92b6de7ab3baed7871e5114ebd2505 (commit)
       via  4654384fe7a4dcee113dacf27c398b13dea5d0be (commit)
       via  7195b94345b0bb937477dc47fc5ec27fb108a099 (commit)
       via  dc52995d85048ed12ae8b9f330e9ca41a4030aae (commit)
       via  ffe0b7a6dd6bfaec62f81f511b3caf08978bb269 (commit)
       via  4103850c2e51274984f69443dee34295cbb8c282 (commit)
       via  dc417bf0c555a7416d0aedde6645fd1087660f92 (commit)
       via  02eb9fc9d5863abcfed6af704e618f8cac7cc2e8 (commit)
       via  1cceba163b17b5e9fd7c89e5b40e3d7e1cffc885 (commit)
       via  4143cc1c3783c54a6f733f08a4739e4e5fb0c8b3 (commit)
       via  7fe4be0416cdc9269011bc4213b8a22d6ced295c (commit)
       via  478ca6c75bbf529f95974224dfb7d71bd5860a96 (commit)
       via  ee8a8ec1cf4605e5af427f9c8b01b3609c82cbe7 (commit)
      from  d8392299f311f8cfcf8bc02679dd3ae7ef8cc6d7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 5c759924fb92b6de7ab3baed7871e5114ebd2505
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Dec 22 15:07:51 2015 +0100

    gpg: Fix type.
    
    * g10/keygen.c (card_write_key_to_backup_file): Change n to a size_t.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/keygen.c b/g10/keygen.c
index c50e04d..8bb7906 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -3863,7 +3863,7 @@ card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir)
     {
       unsigned char array[MAX_FINGERPRINT_LEN];
       char *fprbuf, *p;
-      int n;
+      size_t n;
       int i;
 
       iobuf_close (fp);

commit 4654384fe7a4dcee113dacf27c398b13dea5d0be
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Dec 22 14:59:36 2015 +0100

    gpg: Fix error message.
    
    * g10/getkey.c (parse_def_secret_key): Fix error message.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/getkey.c b/g10/getkey.c
index 45c3f51..24c9636 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1449,7 +1449,7 @@ parse_def_secret_key (ctrl_t ctrl)
       err = classify_user_id (t->d, &desc, 1);
       if (err)
         {
-          log_error (_("secret key \"%s\" not found: %s\n"),
+          log_error (_("error parsing search description \"%s\": %s\n"),
                      t->d, gpg_strerror (err));
           if (!opt.quiet)
             log_info (_("(check argument of option '%s')\n"), "--default-key");

commit 7195b94345b0bb937477dc47fc5ec27fb108a099
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Dec 22 14:57:53 2015 +0100

    gpg: Don't check for ambiguous keys.
    
    * g10/gpg.c (struct result): Move from here...
    * g10/keydb.h (struct pubkey): ... to here.  Update users.
    * g10/gpg.c (check_user_ids): Move from here...
    * g10/getkey.c (get_pubkeys): ... to here.  Update users.  Use
    get_pubkey_byname to look up the keys (this also prunes invalid keys).
    (pubkey_free): New function.
    (pubkeys_free): New function.
    * g10/gpg.c (main): Don't check for ambiguous key specifications.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>
    Regression-due-to: e8c53fc
    
    This change not only moves the checks for ambiguous key specifications
    from gpg.c to getkey.c, it also disables the checks.  The old code was
    too divorced from the actual key lookups and, as such, it reproduced
    the logic.  Unfortunately, the reproduction was a poor one: despite
    fixing some inconsistencies (e.g., 10cca02), it still didn't deal with
    group expansion or the auto key lookup functionality.  Given the
    amount of instability introduced by this change, we (Neal & Werner)
    decided it is better to defer introducing this functionality until
    2.3.

diff --git a/NEWS b/NEWS
index c19c1cd..2ee35e6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
 Noteworthy changes in version 2.1.11 (unreleased)
 -------------------------------------------------
 
+ * gpg: Don't check for ambigious or non-matching key specification in
+   the config file or given to --encrypt-to.  This feature will return
+   in 2.3.x.
 
 Noteworthy changes in version 2.1.10 (2015-12-04)
 -------------------------------------------------
diff --git a/g10/getkey.c b/g10/getkey.c
index ad0c207..45c3f51 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -366,6 +366,282 @@ getkey_disable_caches ()
 }
 
 
+void
+pubkey_free (struct pubkey *key)
+{
+  xfree (key->pk);
+  release_kbnode (key->keyblock);
+  xfree (key);
+}
+
+void
+pubkeys_free (struct pubkey *keys)
+{
+  while (keys)
+    {
+      struct pubkey *next = keys->next;
+      pubkey_free (keys);
+      keys = next;
+    }
+}
+
+/* Returns all keys that match the search specfication SEARCH_TERMS.
+
+   This function also checks for and warns about duplicate entries in
+   the keydb, which can occur if the user has configured multiple
+   keyrings or keyboxes or if a keyring or keybox was corrupted.
+
+   Note: SEARCH_TERMS will not be expanded (i.e., it may not be a
+   group).
+
+   USE is the operation for which the key is required.  It must be
+   either PUBKEY_USAGE_ENC, PUBKEY_USAGE_SIG, PUBKEY_USAGE_CERT or
+   PUBKEY_USAGE_AUTH.
+
+   XXX: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are
+   implemented.
+
+   INCLUDE_UNUSABLE indicates whether disabled keys are allowed.
+   (Recipients specified with --encrypt-to and --hidden-encrypt-to may
+   be disabled.  It is possible to edit disabled keys.)
+
+   SOURCE is the context in which SEARCH_TERMS was specified, e.g.,
+   "--encrypt-to", etc.  If this function is called interactively,
+   then this should be NULL.
+
+   If WARN_POSSIBLY_AMBIGUOUS is set, then emits a warning if the user
+   does not specify a long key id or a fingerprint.
+
+   The results are placed in *KEYS.  *KEYS must be NULL!  */
+gpg_error_t
+get_pubkeys (ctrl_t ctrl,
+             char *search_terms, int use, int include_unusable, char *source,
+             int warn_possibly_ambiguous,
+             struct pubkey **keys)
+{
+  /* We show a warning when a key appears multiple times in the DB.
+     This can happen for two reasons:
+
+       - The user has configured multiple keyrings or keyboxes.
+
+       - The keyring or keybox has been corrupted in some way, e.g., a
+         bug or a random process changing them.
+
+     For each duplicate, we only want to show the key once.  Hence,
+     this list.  */
+  static strlist_t key_dups;
+
+  /* USE transformed to a string.  */
+  char *use_str;
+
+  gpg_error_t err;
+
+  KEYDB_SEARCH_DESC desc;
+
+  GETKEY_CTX ctx;
+  struct pubkey *results = NULL;
+  struct pubkey *r;
+
+  int count;
+
+  char fingerprint[2 * MAX_FINGERPRINT_LEN + 1];
+
+  if (DBG_LOOKUP)
+    {
+      log_debug ("\n");
+      log_debug ("%s: Checking %s=%s\n",
+                 __func__, source ? source : "user input", search_terms);
+    }
+
+  if (*keys)
+    log_bug ("%s: KEYS should be NULL!\n", __func__);
+
+  switch (use)
+    {
+    case PUBKEY_USAGE_ENC: use_str = "encrypt"; break;
+    case PUBKEY_USAGE_SIG: use_str = "sign"; break;
+    case PUBKEY_USAGE_CERT: use_str = "cetify"; break;
+    case PUBKEY_USAGE_AUTH: use_str = "authentication"; break;
+    default: log_bug ("%s: Bad value for USE (%d)\n", __func__, use);
+    }
+
+  if (use == PUBKEY_USAGE_CERT || use == PUBKEY_USAGE_AUTH)
+    log_bug ("%s: use=%s is unimplemented.\n", __func__, use_str);
+
+  err = classify_user_id (search_terms, &desc, 1);
+  if (err)
+    {
+      log_info (_("key \"%s\" not found: %s\n"),
+                search_terms, gpg_strerror (err));
+      if (!opt.quiet && source)
+        log_info (_("(check argument of option '%s')\n"), source);
+      goto out;
+    }
+
+  if (warn_possibly_ambiguous
+      && ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
+            || desc.mode == KEYDB_SEARCH_MODE_FPR16
+            || desc.mode == KEYDB_SEARCH_MODE_FPR20
+            || desc.mode == KEYDB_SEARCH_MODE_FPR))
+    {
+      log_info (_("Warning: '%s' should be a long key ID or a fingerprint\n"),
+                search_terms);
+      if (!opt.quiet && source)
+        log_info (_("(check argument of option '%s')\n"), source);
+    }
+
+  /* Gather all of the results.  */
+  ctx = NULL;
+  count = 0;
+  do
+    {
+      PKT_public_key *pk = xmalloc_clear (sizeof *pk);
+      KBNODE kb;
+      pk->req_usage = use;
+
+      if (! ctx)
+        err = get_pubkey_byname (ctrl, &ctx, pk, search_terms, &kb, NULL,
+                                 include_unusable, 1);
+      else
+        err = getkey_next (ctx, pk, &kb);
+
+      if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+        /* No more results.   */
+        {
+          xfree (pk);
+          break;
+        }
+      else if (err)
+        /* An error (other than "not found").  */
+        {
+          log_error (_("error looking up: %s\n"),
+                     gpg_strerror (err));
+          xfree (pk);
+          break;
+        }
+
+      /* Another result!  */
+      count ++;
+
+      r = xmalloc_clear (sizeof (*r));
+      r->pk = pk;
+      r->keyblock = kb;
+      r->next = results;
+      results = r;
+    }
+  while (ctx);
+  getkey_end (ctx);
+
+  if (DBG_LOOKUP)
+    {
+      log_debug ("%s resulted in %d matches.\n", search_terms, count);
+      for (r = results; r; r = r->next)
+        log_debug ("  %s\n",
+                   hexfingerprint (r->keyblock->pkt->pkt.public_key,
+                                   fingerprint, sizeof (fingerprint)));
+    }
+
+  if (! results && gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+    /* No match.  */
+    {
+      if (DBG_LOOKUP)
+        log_debug ("%s: '%s' not found.\n", __func__, search_terms);
+
+      log_info (_("key \"%s\" not found\n"), search_terms);
+      if (!opt.quiet && source)
+        log_info (_("(check argument of option '%s')\n"), source);
+
+      goto out;
+    }
+  else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+    /* No more matches.  */
+    ;
+  else if (err)
+    /* Some other error.  An error message was already printed
+       out.  Free RESULTS and continue.  */
+    goto out;
+
+  /* Check for duplicates.  */
+  if (DBG_LOOKUP)
+    log_debug ("%s: Checking results of %s='%s' for dups\n",
+               __func__, source ? source : "user input", search_terms);
+  count = 0;
+  for (r = results; r; r = r->next)
+    {
+      struct pubkey **prevp;
+      struct pubkey *next;
+      struct pubkey *r2;
+      int dups = 0;
+
+      prevp = &r->next;
+      next = r->next;
+      while ((r2 = next))
+        {
+          if (cmp_public_keys (r->keyblock->pkt->pkt.public_key,
+                               r2->keyblock->pkt->pkt.public_key) != 0)
+            /* Not a dup.  */
+            {
+              prevp = &r2->next;
+              next = r2->next;
+              continue;
+            }
+
+          dups ++;
+          count ++;
+
+          /* Remove R2 from the list.  */
+          *prevp = r2->next;
+          release_kbnode (r2->keyblock);
+          next = r2->next;
+          xfree (r2);
+        }
+
+      if (dups)
+        {
+          hexfingerprint (r->keyblock->pkt->pkt.public_key,
+                          fingerprint, sizeof fingerprint);
+          if (! strlist_find (key_dups, fingerprint))
+            {
+              char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
+
+              log_info (_("Warning: %s appears in the keyring %d times.\n"),
+                        format_hexfingerprint (fingerprint,
+                                               fingerprint_formatted,
+                                               sizeof fingerprint_formatted),
+                        1 + dups);
+              add_to_strlist (&key_dups, fingerprint);
+            }
+        }
+    }
+
+  if (DBG_LOOKUP && count)
+    {
+      log_debug ("After removing %d dups:\n", count);
+      for (r = results, count = 0; r; r = r->next)
+        log_debug ("  %d: %s\n",
+                   count,
+                   hexfingerprint (r->keyblock->pkt->pkt.public_key,
+                                   fingerprint, sizeof fingerprint));
+    }
+
+ out:
+  if (err)
+    {
+      while ((r = results))
+        {
+          results = results->next;
+          pubkey_free (r);
+          release_kbnode (r->keyblock);
+          xfree (r);
+        }
+    }
+  else
+    *keys = results;
+
+  return err;
+}
+
+
 static void
 pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
 	       KBNODE found_key)
diff --git a/g10/gpg.c b/g10/gpg.c
index 71f44ed..0e61238 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -2101,506 +2101,6 @@ get_default_configname (void)
   return configname;
 }
 
-struct result
-{
-  struct result *next;
-  kbnode_t keyblock;
-  int processed;
-};
-
-/* We show a warning when a key appears multiple times in the DB.  */
-static strlist_t key_dups;
-
-static gpg_error_t
-check_user_ids (strlist_t *sp,
-                int warn_possibly_ambiguous,
-                int error_if_not_found)
-{
-  strlist_t s = *sp;
-  strlist_t s2 = NULL;
-  strlist_t t;
-
-  gpg_error_t rc = 0;
-  gpg_error_t err;
-
-  KEYDB_HANDLE hd = NULL;
-
-  char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
-
-  /* A quick check to avoid allocating a new strlist if we can skip
-     all keys.  Handles also the case of !SP.  See below for details.  */
-  for (t = s; t && (!(t->flags & PK_LIST_CONFIG)
-                    && !(t->flags & PK_LIST_ENCRYPT_TO)); t = t->next)
-    ;
-  if (!t)
-    return 0;
-
-  for (t = s; t; t = t->next)
-    {
-      const char *option_str;
-      int option;
-
-      KEYDB_SEARCH_DESC desc;
-      struct result *results = NULL;
-      struct result *r;
-
-      int count;
-
-      /* We also potentially need a ! at the end.  */
-      char fingerprint[2 * MAX_FINGERPRINT_LEN + 1 + 1];
-      char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
-
-      KBNODE best_kb;
-      PKT_public_key *best_pk;
-
-      /* Whether the key is for encryption or signing.  */
-      int encrypt = 1;
-
-      /* If the key has been given on the command line and it has not
-         been given by one of the encrypt-to options, we skip the
-         checks.  The reason is that the actual key selection code
-         does its own checks and provides proper status message to the
-         caller to detect the wrong keys.  */
-      if (!(t->flags & PK_LIST_CONFIG) && !(t->flags & PK_LIST_ENCRYPT_TO))
-        {
-          add_to_strlist (&s2, t->d);
-          s2->flags = t->flags;
-          continue;
-        }
-
-      option = t->flags >> PK_LIST_SHIFT;
-      switch (option)
-        {
-        case oDefaultKey:
-          option_str = "--default-key";
-          encrypt = 0;
-          break;
-        case oLocalUser:
-          option_str = "--local-user";
-          encrypt = 0;
-          break;
-
-        case oEncryptTo: option_str = "--encrypt-to"; break;
-        case oHiddenEncryptTo: option_str = "--hidden-encrypt-to"; break;
-        case oEncryptToDefaultKey: option_str = "--encrypt-to-default-key"; break;
-        case oRecipient: option_str = "--recipient"; break;
-        case oHiddenRecipient: option_str = "--hidden-recipient"; break;
-        default:
-          log_bug ("Unsupport option: %d\n", (t->flags >> PK_LIST_SHIFT));
-        }
-
-      if (DBG_LOOKUP)
-        {
-          log_debug ("\n");
-          log_debug ("%s: Checking %s=%s\n", __func__, option_str, t->d);
-        }
-
-      err = classify_user_id (t->d, &desc, 1);
-      if (err)
-        {
-          if (! rc)
-            rc = err;
-
-          log_error (_("key \"%s\" not found: %s\n"),
-                       t->d, gpg_strerror (err));
-          if (!opt.quiet)
-            log_info (_("(check argument of option '%s')\n"), option_str);
-          continue;
-        }
-
-      if (warn_possibly_ambiguous
-          && ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
-                || desc.mode == KEYDB_SEARCH_MODE_FPR16
-                || desc.mode == KEYDB_SEARCH_MODE_FPR20
-                || desc.mode == KEYDB_SEARCH_MODE_FPR))
-        log_info (_("Warning: value '%s' for option '%s'"
-                    " should be a long key ID or a fingerprint\n"),
-                  t->d, option_str);
-
-      if (! hd)
-        {
-          hd = keydb_new ();
-          if (!hd)
-            {
-              rc = gpg_error_from_syserror ();
-              break;
-            }
-        }
-      else
-        keydb_search_reset (hd);
-
-      /* Gather all of the results.  */
-      count = 0;
-      while (1)
-        {
-          KBNODE kb;
-
-          err = keydb_search (hd, &desc, 1, NULL);
-          if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-              || gpg_err_code (err) == GPG_ERR_EOF)
-            /* No more results.   */
-            break;
-          else if (err)
-            /* An error (other than "not found").  */
-            {
-              log_error (_("error searching the keyring: %s\n"),
-                         gpg_strerror (err));
-              break;
-            }
-
-          err = keydb_get_keyblock (hd, &kb);
-          if (err)
-            {
-              log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
-              break;
-            }
-
-          /* Another result!  */
-          count ++;
-
-          r = xmalloc_clear (sizeof (*r));
-          r->keyblock = kb;
-          r->next = results;
-          results = r;
-        }
-
-      if (DBG_LOOKUP)
-        {
-          log_debug ("%s resulted in %d matches.\n", t->d, count);
-          for (r = results; r; r = r->next)
-            log_debug ("  %s\n",
-                       hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                       fingerprint, sizeof (fingerprint)));
-        }
-
-      if (! results && (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-                        || gpg_err_code (err) == GPG_ERR_EOF))
-        /* No match.  */
-        {
-          if (DBG_LOOKUP)
-            log_debug ("%s: '%s' not found.\n", __func__, t->d);
-
-          if (error_if_not_found)
-            {
-              if (! rc)
-                rc = err;
-
-              log_error (_("key \"%s\" not found\n"), t->d);
-              if (!opt.quiet)
-                log_info (_("(check argument of option '%s')\n"), option_str);
-            }
-          continue;
-        }
-      else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-               || gpg_err_code (err) == GPG_ERR_EOF)
-        /* No more matches.  */
-        ;
-      else if (err)
-        /* Some other error.  An error message was already printed
-           out.  Free RESULTS and continue.  */
-        {
-          if (! rc)
-            rc = err;
-
-          while ((r = results))
-            {
-              results = results->next;
-              release_kbnode (r->keyblock);
-              xfree (r);
-            }
-
-          continue;
-        }
-
-      /* Check for duplicates.  */
-
-      if (DBG_LOOKUP)
-        log_debug ("%s: Checking results of %s='%s' for dups\n",
-                   __func__, option_str, t->d);
-      while (1)
-        {
-          struct result **prevp;
-          struct result *next;
-          struct result *r2;
-          int dups = 0;
-
-          /* After checking a result, we set R->PROCESSED.  Find the
-             next unprocessed result.  */
-          for (r = results; r; r = r->next)
-            if (! r->processed)
-              break;
-
-          if (! r)
-            /* There is nothing left to check.  */
-            break;
-
-          hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                          fingerprint, sizeof fingerprint);
-          r->processed = 1;
-
-          prevp = &results;
-          next = results;
-          while ((r2 = next))
-            {
-              if (r2->processed)
-                {
-                  prevp = &r2->next;
-                  next = r2->next;
-                  continue;
-                }
-
-              hexfingerprint (r2->keyblock->pkt->pkt.public_key,
-                              fingerprint2, sizeof fingerprint2);
-
-              if (strcmp (fingerprint, fingerprint2) != 0)
-                /* Not a dup.  */
-                {
-                  prevp = &r2->next;
-                  next = r2->next;
-                  continue;
-                }
-
-              dups ++;
-
-              /* Remove R2 from the list.  */
-              *prevp = r2->next;
-              release_kbnode (r2->keyblock);
-              next = r2->next;
-              xfree (r2);
-            }
-
-          if (dups && ! strlist_find (key_dups, fingerprint))
-            {
-              log_info (_("Warning: %s appears in the keyring %d times.\n"),
-                        format_hexfingerprint (fingerprint,
-                                               fingerprint_formatted,
-                                               sizeof fingerprint_formatted),
-                        1 + dups);
-              add_to_strlist (&key_dups, fingerprint);
-            }
-        }
-
-      if (DBG_LOOKUP)
-        {
-          log_debug ("After removing dups:\n");
-          for (r = results, count = 0; r; r = r->next)
-            {
-              count ++;
-              log_debug ("  %d: %s\n",
-                         count,
-                         hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                         fingerprint, sizeof fingerprint));
-            }
-        }
-
-      /* Now we find the best key.  */
-      assert (results);
-      /* Prune invalid keys.  */
-      {
-        int ambiguous = 0;
-
-        if (DBG_LOOKUP)
-          log_debug ("Pruning bad keys.\n");
-
-        best_pk = NULL;
-        for (r = results; r; r = r->next)
-          {
-            KBNODE kb = r->keyblock;
-            PKT_public_key *pk = kb->pkt->pkt.public_key;
-            KBNODE n;
-
-            /* Merge in the data from the self sigs so that things
-               like the revoked status are available.  */
-            merge_keys_and_selfsig (kb);
-
-            if (/* Using disabled keys with --encrypt-to is allowed.  */
-                ! (option == oEncryptTo || option == oHiddenEncryptTo)
-                && pk_is_disabled (pk))
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping disabled key: %s\n",
-                             hexfingerprint (pk, fingerprint,
-                                             sizeof fingerprint));
-                continue;
-              }
-            if (pk->flags.revoked)
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping revoked key: %s\n",
-                             hexfingerprint (pk, fingerprint,
-                                             sizeof fingerprint));
-                continue;
-              }
-            if (pk->has_expired)
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping expired key: %s\n",
-                             hexfingerprint (pk, fingerprint,
-                                             sizeof fingerprint));
-                continue;
-              }
-
-            /* Check for the required encryption or signing
-               capability.  */
-            n = kb;
-            do
-              {
-                PKT_public_key *key = n->pkt->pkt.public_key;
-
-                if ((/* Using disabled keys with --encrypt-to is allowed.  */
-                     pk_is_disabled (key)
-                     && ! (option == oEncryptTo
-                           || option == oHiddenEncryptTo))
-                    || key->flags.revoked
-                    || key->has_expired)
-                  /* Invalid.  */
-                  continue;
-
-                if (encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_ENC))
-                  continue;
-                if (! encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_SIG))
-                  continue;
-
-                /* Key passes basic tests.  */
-                break;
-              }
-            while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
-
-            if (! n)
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping %s, which does not have %s capability.\n",
-                             hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                             fingerprint, sizeof fingerprint),
-                             encrypt ? "encrypt" : "sign");
-                continue;
-              }
-            else if (DBG_LOOKUP)
-              log_debug ("  %s is valid and has %s capability.\n",
-                         hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                         fingerprint, sizeof fingerprint),
-                         encrypt ? "encrypt" : "sign");
-
-
-            if (! best_pk)
-              {
-                best_pk = pk;
-                best_kb = kb;
-                continue;
-              }
-
-            /* We have multiple candidates.  Prefer the newer key.
-
-               XXX: we should also consider key capabilities (if we
-               are encrypting to the key, does it have an encryption
-               capability?).
-
-               XXX: if we are signing, then we should consider the
-               key that is actually available (e.g., if one is on a
-               smart card).  */
-            ambiguous = 1;
-            if (best_pk->timestamp < pk->timestamp)
-              best_pk = pk;
-          }
-
-        if (! results)
-          {
-            if (encrypt)
-              log_error (_("%s: no matching keys are valid encryption keys"),
-                         t->d);
-            else
-              log_error (_("%s: no matching keys are valid signing keys"),
-                         t->d);
-            if (!opt.quiet)
-              log_info (_("(check argument of option '%s')\n"), option_str);
-            continue;
-          }
-
-        if (ambiguous)
-          {
-            /* TRANSLATORS: The %s prints a key specification which
-               for example has been given at the command line.
-               Lines with fingerprints are printed after this
-               message.  */
-            log_error (_("key specification '%s' is ambiguous\n"),
-                       t->d);
-            if (!opt.quiet)
-              log_info (_("(check argument of option '%s')\n"),
-                        option_str);
-
-            log_info (_("'%s' matches at least:\n"), t->d);
-
-            for (r = results; r; r = r->next)
-              log_info ("  %s\n",
-                        format_hexfingerprint
-                        (hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                         fingerprint, sizeof fingerprint),
-                         fingerprint_formatted,
-                         sizeof fingerprint_formatted));
-
-            if (! rc)
-              rc = GPG_ERR_AMBIGUOUS_NAME;
-          }
-      }
-
-      if ((desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
-           || desc.mode == KEYDB_SEARCH_MODE_LONG_KID
-           || desc.mode == KEYDB_SEARCH_MODE_FPR16
-           || desc.mode == KEYDB_SEARCH_MODE_FPR20)
-          && strchr (t->d, '!'))
-        /* Exact search.  In this case we want to set FINGERPRINT not
-           to the primary key, but the key (primary or sub) that
-           matched the search criteria.  Note: there will always be
-           exactly one match.  */
-        {
-          kbnode_t n = best_kb;
-          PKT_public_key *match = NULL;
-          int i;
-
-          do
-            {
-              if ((n->flag & 1))
-                /* The matched node.  */
-                {
-                  assert (! match);
-                  match = n->pkt->pkt.public_key;
-                }
-            }
-          while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
-          assert (match);
-
-          hexfingerprint (match, fingerprint, sizeof fingerprint);
-          i = strlen (fingerprint);
-          fingerprint[i] = '!';
-          fingerprint[i + 1] = '\0';
-        }
-      else
-        hexfingerprint (best_pk, fingerprint, sizeof fingerprint);
-
-      add_to_strlist (&s2, fingerprint);
-      s2->flags = s->flags;
-
-      {
-        struct result *next = results;
-        while ((r = next))
-          {
-            next = r->next;
-            release_kbnode (r->keyblock);
-            xfree (r);
-          }
-      }
-    }
-
-  strlist_rev (&s2);
-
-  keydb_release (hd);
-
-  free_strlist (s);
-  *sp = s2;
-  return rc;
-}
-
-
 int
 main (int argc, char **argv)
 {
@@ -4280,18 +3780,6 @@ main (int argc, char **argv)
         break;
       }
 
-    {
-      rc = check_user_ids (&locusr, 1, 1);
-      if (rc)
-        g10_exit (1);
-      rc = check_user_ids (&remusr, 0, 1);
-      if (rc)
-        g10_exit (1);
-      rc = check_user_ids (&opt.def_secret_key, 1, 0);
-      if (rc)
-        g10_exit (1);
-    }
-
     /* The command dispatcher.  */
     switch( cmd )
       {
diff --git a/g10/keydb.h b/g10/keydb.h
index 556b537..66bfa57 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -485,6 +485,29 @@ int get_pubkey_fast ( PKT_public_key *pk, u32 *keyid );
    using merge_selfsigs.  */
 KBNODE get_pubkeyblock( u32 *keyid );
 
+/* A list used by get_pubkeys to gather all of the matches.  */
+struct pubkey
+{
+  struct pubkey *next;
+  /* The key to use (either the public key or the subkey).  */
+  PKT_public_key *pk;
+  kbnode_t keyblock;
+};
+
+/* Free a single key.  This does not remove key from any list!  */
+void pubkey_free (struct pubkey *key);
+
+/* Free a list of public keys.  */
+void pubkeys_free (struct pubkey *keys);
+
+/* Returns all keys that match the search specfication SEARCH_TERMS.
+   The returned keys should be freed using pubkeys_free.  */
+gpg_error_t
+get_pubkeys (ctrl_t ctrl,
+             char *search_terms, int use, int include_unusable, char *source,
+             int warn_possibly_ambiguous,
+             struct pubkey **keys);
+
 /* Find a public key identified by the name NAME.
 
    If name appears to be a valid valid RFC822 mailbox (i.e., email
diff --git a/g10/pkclist.c b/g10/pkclist.c
index b6a213f..d7e78cb 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -914,6 +914,13 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
   else
     remusr = rcpts;
 
+  /* XXX: Change this function to use get_pubkeys instead of
+     get_pubkey_byname to detect ambiguous key specifications and warn
+     about duplicate keyblocks.  For ambiguous key specifications on
+     the command line or provided interactively, prompt the user to
+     select the best key.  If a key specification is ambiguous and we
+     are in batch mode, die.  */
+
   if (opt.encrypt_to_default_key)
     {
       static int warned;
diff --git a/g10/skclist.c b/g10/skclist.c
index 3d137b2..1eb0633 100644
--- a/g10/skclist.c
+++ b/g10/skclist.c
@@ -120,6 +120,13 @@ build_sk_list (ctrl_t ctrl,
   gpg_error_t err;
   SK_LIST sk_list = NULL;
 
+  /* XXX: Change this function to use get_pubkeys instead of
+     getkey_byname to detect ambiguous key specifications and warn
+     about duplicate keyblocks.  For ambiguous key specifications on
+     the command line or provided interactively, prompt the user to
+     select the best key.  If a key specification is ambiguous and we
+     are in batch mode, die.  */
+
   if (!locusr) /* No user ids given - use the default key.  */
     {
       PKT_public_key *pk;

commit dc52995d85048ed12ae8b9f330e9ca41a4030aae
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Dec 22 14:21:18 2015 +0100

    gpg: Lazily evaluate --default-key.
    
    * g10/gpg.c (main): If --encrypt-to-default-key is specified, don't
    add --default-key's value to REMUSR here...
    * g10/pkclist.c (build_pk_list): ... do it here.
    * tests/openpgp/Makefile.am (TESTS): Add default-key.test.
    * tests/openpgp/default-key.test: New file.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/gpg.c b/g10/gpg.c
index 11dbf56..71f44ed 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -4281,8 +4281,6 @@ main (int argc, char **argv)
       }
 
     {
-      int have_def_secret_key = opt.def_secret_key != NULL;
-
       rc = check_user_ids (&locusr, 1, 1);
       if (rc)
         g10_exit (1);
@@ -4292,25 +4290,6 @@ main (int argc, char **argv)
       rc = check_user_ids (&opt.def_secret_key, 1, 0);
       if (rc)
         g10_exit (1);
-
-      if (opt.encrypt_to_default_key)
-        {
-          const char *default_key = parse_def_secret_key (ctrl);
-          if (default_key)
-            {
-              sl = add_to_strlist2 (&remusr, default_key, utf8_strings);
-              sl->flags = ((oEncryptToDefaultKey << PK_LIST_SHIFT)
-                           | PK_LIST_ENCRYPT_TO);
-              if (opt.encrypt_to_default_key == 2)
-                sl->flags |= PK_LIST_CONFIG;
-            }
-          else if (have_def_secret_key)
-            log_info (_("option '%s' given, but no valid default keys given\n"),
-                      "--encrypt-to-default-key");
-          else
-            log_info (_("option '%s' given, but option '%s' not given\n"),
-                      "--encrypt-to-default-key", "--default-key");
-        }
     }
 
     /* The command dispatcher.  */
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 39a24f7..b6a213f 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -914,6 +914,53 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
   else
     remusr = rcpts;
 
+  if (opt.encrypt_to_default_key)
+    {
+      static int warned;
+
+      const char *default_key = parse_def_secret_key (ctrl);
+      if (default_key)
+        {
+          PK_LIST r = xmalloc_clear (sizeof *r);
+
+          r->pk = xmalloc_clear (sizeof *r->pk);
+          r->pk->req_usage = PUBKEY_USAGE_ENC;
+
+          rc = get_pubkey_byname (ctrl, NULL, r->pk, default_key,
+                                   NULL, NULL, 0, 1);
+          if (rc)
+            {
+              xfree (r->pk);
+              xfree (r);
+
+              log_error (_("Can't encrypt to '%s'.\n"), default_key);
+              if (!opt.quiet)
+                log_info (_("(check argument of option '%s')\n"),
+                          "--default-key");
+            }
+          else
+            {
+              r->next = pk_list;
+              r->flags = 0;
+              pk_list = r;
+            }
+        }
+      else if (opt.def_secret_key)
+        {
+          if (! warned)
+            log_info (_("option '%s' given, but no valid default keys given\n"),
+                      "--encrypt-to-default-key");
+          warned = 1;
+        }
+      else
+        {
+          if (! warned)
+            log_info (_("option '%s' given, but option '%s' not given\n"),
+                      "--encrypt-to-default-key", "--default-key");
+          warned = 1;
+        }
+    }
+
   /* Check whether there are any recipients in the list and build the
    * list of the encrypt-to ones (we always trust them). */
   for ( rov = remusr; rov; rov = rov->next )
diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am
index 914de8c..a04b62c 100644
--- a/tests/openpgp/Makefile.am
+++ b/tests/openpgp/Makefile.am
@@ -46,7 +46,7 @@ TESTS = version.test mds.test \
 	multisig.test verify.test armor.test \
 	import.test ecc.test 4gb-packet.test \
 	$(sqlite3_dependent_tests) \
-	gpgtar.test use-exact-key.test \
+	gpgtar.test use-exact-key.test default-key.test \
 	finish.test
 
 
diff --git a/tests/openpgp/default-key.test b/tests/openpgp/default-key.test
new file mode 100755
index 0000000..bfb84ac
--- /dev/null
+++ b/tests/openpgp/default-key.test
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+. $srcdir/defs.inc || exit 3
+
+#set -x
+
+# Make sure $srcdir is set.
+if test "x$srcdir" = x
+then
+    echo srcdir environment variable not set!
+    exit 1
+fi
+
+# Import the sample key
+#
+# pub   1024R/8BC90111 2015-12-02
+#       Key fingerprint = E657 FB60 7BB4 F21C 90BB  6651 BC06 7AF2 8BC9 0111
+# uid       [ultimate] Barrett Brown <barrett at example.org>
+# sub   1024R/3E880CFF 2015-12-02 (encryption)
+# sub   1024R/F5F77B83 2015-12-02 (signing)
+# sub   1024R/45117079 2015-12-02 (encryption)
+# sub   1024R/1EA97479 2015-12-02 (signing)
+info "Importing public key."
+if $GPG --import $srcdir/samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc
+then
+    :
+else
+    error "$k: import failed"
+fi
+
+# By default, the most recent, valid signing subkey (1EA97479).
+for x in 8BC90111 3E880CFF F5F77B83 45117079 1EA97479
+do
+    info
+    info "Trying --default-key $x"
+
+    if ! echo | $GPG --default-key "$x" -s | $GPG --verify --status-fd=1 \
+            | grep -q 'VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479'
+    then
+        echo | $GPG --default-key "$x" -s | $GPG --verify --status-fd=2
+        error "Unexpected key used for signing (not the signing subkey, specified \"$x\")."
+        exit 1
+    fi
+done
+
+# By default, the most recent, valid encryption subkey (45117079).
+for x in 8BC90111 3E880CFF F5F77B83 45117079 1EA97479
+do
+    info
+    info "Trying --default-key $x --encrypt-to-default-key"
+
+    # We need another recipient, because --encrypt-to-default-key is
+    # not considered a recipient and gpg doesn't encrypt without any
+    # recipients.
+    #
+    # Note: it doesn't matter whether we specify the primary key or
+    # a subkey: the newest encryption subkey will be used.
+    if ! echo | $GPG --trust-model=always \
+                     --default-key "$x" --encrypt-to-default-key \
+                     -r 439F02CA -e \
+            | $GPG --list-packets \
+            | grep -q "keyid[ ][A-F0-9]*45117079"
+    then
+        echo | $GPG --trust-model=always \
+                    --default-key "$x" --encrypt-to-default-key \
+                    -r 439F02CA -e \
+            | $GPG --list-packets 1>&2
+        error "Unexpected key used for signing (specified \"$x\")."
+        exit 1
+    fi
+done
+
+exit 0

commit ffe0b7a6dd6bfaec62f81f511b3caf08978bb269
Author: Neal H. Walfield <neal at g10code.com>
Date:   Fri Dec 18 13:26:40 2015 +0100

    gpg: Remove unused parameter.
    
    * g10/pkclist.c (build_pk_list): Remove parameter use, which is always
    called set to PUBKEY_USAGE_ENC.  Update callers.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/encrypt.c b/g10/encrypt.c
index 4432f29..bca1123 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -500,7 +500,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
     pk_list = provided_keys;
   else
     {
-      if ((rc = build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC)))
+      if ((rc = build_pk_list (ctrl, remusr, &pk_list)))
         {
           release_progress_context (pfx);
           return rc;
diff --git a/g10/keydb.h b/g10/keydb.h
index 0425e74..556b537 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -373,8 +373,7 @@ void show_revocation_reason( PKT_public_key *pk, int mode );
 int  check_signatures_trust( PKT_signature *sig );
 
 void release_pk_list (PK_LIST pk_list);
-int  build_pk_list (ctrl_t ctrl,
-                    strlist_t rcpts, PK_LIST *ret_pk_list, unsigned use);
+int  build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
 gpg_error_t find_and_check_key (ctrl_t ctrl,
                                 const char *name, unsigned int use,
                                 int mark_hidden, pk_list_t *pk_list_addr);
diff --git a/g10/pkclist.c b/g10/pkclist.c
index c865660..39a24f7 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -893,15 +893,12 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
      Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
      Bit 1 (PK_LIST_HIDDEN)    : This is a hidden recipient.
 
-   USE is the desired use for the key - usually PUBKEY_USAGE_ENC.
-
    On success a list of keys is stored at the address RET_PK_LIST; the
    caller must free this list.  On error the value at this address is
    not changed.
  */
 int
-build_pk_list (ctrl_t ctrl,
-               strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use )
+build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
 {
   PK_LIST pk_list = NULL;
   PKT_public_key *pk=NULL;
@@ -938,12 +935,12 @@ build_pk_list (ctrl_t ctrl,
               compliance_failure();
             }
         }
-      else if ( (use & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to )
+      else if (!opt.no_encrypt_to)
         {
-          /* Encryption has been requested and --encrypt-to has not
-             been disabled.  Check this encrypt-to key. */
+          /* --encrypt-to has not been disabled.  Check this
+             encrypt-to key. */
           pk = xmalloc_clear( sizeof *pk );
-          pk->req_usage = use;
+          pk->req_usage = PUBKEY_USAGE_ENC;
 
           /* We explicitly allow encrypt-to to an disabled key; thus
              we pass 1 for the second last argument and 1 as the last
@@ -956,7 +953,8 @@ build_pk_list (ctrl_t ctrl,
               send_status_inv_recp (0, rov->d);
               goto fail;
             }
-          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, use)) )
+          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
+                                                PUBKEY_USAGE_ENC)) )
             {
               /* Skip the actual key if the key is already present
                * in the list.  Add it to our list if not. */
@@ -1084,11 +1082,12 @@ build_pk_list (ctrl_t ctrl,
           /* Get and check key for the current name. */
           free_public_key (pk);
           pk = xmalloc_clear( sizeof *pk );
-          pk->req_usage = use;
+          pk->req_usage = PUBKEY_USAGE_ENC;
           rc = get_pubkey_byname (ctrl, NULL, pk, answer, NULL, NULL, 0, 0 );
           if (rc)
             tty_printf(_("No such user ID.\n"));
-          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, use)) )
+          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
+                                                PUBKEY_USAGE_ENC)) )
             {
               if ( have_def_rec )
                 {
@@ -1157,14 +1156,15 @@ build_pk_list (ctrl_t ctrl,
     {
       /* We are in batch mode and have only a default recipient. */
       pk = xmalloc_clear( sizeof *pk );
-      pk->req_usage = use;
+      pk->req_usage = PUBKEY_USAGE_ENC;
 
       /* The default recipient is allowed to be disabled; thus pass 1
          as second last argument.  We also don't want an AKL. */
       rc = get_pubkey_byname (ctrl, NULL, pk, def_rec, NULL, NULL, 1, 1);
       if (rc)
         log_error(_("unknown default recipient \"%s\"\n"), def_rec );
-      else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo, use)) )
+      else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo,
+                                           PUBKEY_USAGE_ENC)) )
         {
           /* Mark any_recipients here since the default recipient
              would have been used if it wasn't already there.  It
@@ -1199,7 +1199,7 @@ build_pk_list (ctrl_t ctrl,
           if ( (remusr->flags & PK_LIST_ENCRYPT_TO) )
             continue; /* encrypt-to keys are already handled. */
 
-          rc = find_and_check_key (ctrl, remusr->d, use,
+          rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
                                    !!(remusr->flags&PK_LIST_HIDDEN),
                                    &pk_list);
           if (rc)
diff --git a/g10/sign.c b/g10/sign.c
index baa0068..79a5f3b 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -773,7 +773,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
 	goto leave;
 
     if (encryptflag
-        && (rc=build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC)))
+        && (rc=build_pk_list (ctrl, remusr, &pk_list)))
       goto leave;
 
     /* prepare iobufs */

commit 4103850c2e51274984f69443dee34295cbb8c282
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Dec 17 13:15:18 2015 +0100

    gpg: Improve check for ambiguous keys.
    
    * g10/gpg.c (check_user_ids): When checking for ambiguous keys, ignore
    encryption-only keys when a signing key is needed and vice-versa.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/gpg.c b/g10/gpg.c
index 2f96bd7..11dbf56 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -2153,6 +2153,9 @@ check_user_ids (strlist_t *sp,
       KBNODE best_kb;
       PKT_public_key *best_pk;
 
+      /* Whether the key is for encryption or signing.  */
+      int encrypt = 1;
+
       /* If the key has been given on the command line and it has not
          been given by one of the encrypt-to options, we skip the
          checks.  The reason is that the actual key selection code
@@ -2168,13 +2171,20 @@ check_user_ids (strlist_t *sp,
       option = t->flags >> PK_LIST_SHIFT;
       switch (option)
         {
-        case oDefaultKey: option_str = "--default-key"; break;
+        case oDefaultKey:
+          option_str = "--default-key";
+          encrypt = 0;
+          break;
+        case oLocalUser:
+          option_str = "--local-user";
+          encrypt = 0;
+          break;
+
         case oEncryptTo: option_str = "--encrypt-to"; break;
         case oHiddenEncryptTo: option_str = "--hidden-encrypt-to"; break;
         case oEncryptToDefaultKey: option_str = "--encrypt-to-default-key"; break;
         case oRecipient: option_str = "--recipient"; break;
         case oHiddenRecipient: option_str = "--hidden-recipient"; break;
-        case oLocalUser: option_str = "--local-user"; break;
         default:
           log_bug ("Unsupport option: %d\n", (t->flags >> PK_LIST_SHIFT));
         }
@@ -2385,114 +2395,153 @@ check_user_ids (strlist_t *sp,
 
       /* Now we find the best key.  */
       assert (results);
-      if (! results->next)
-        /* There is only one key.  */
-        {
-          best_kb = results->keyblock;
-          best_pk = best_kb->pkt->pkt.public_key;
-        }
-      else
-        /* We have more than one matching key.  Prune invalid
-           keys.  */
-        {
-          int ambiguous = 0;
+      /* Prune invalid keys.  */
+      {
+        int ambiguous = 0;
 
-          if (DBG_LOOKUP)
-            log_debug ("Pruning bad keys.\n");
+        if (DBG_LOOKUP)
+          log_debug ("Pruning bad keys.\n");
 
-          best_pk = NULL;
-          for (r = results; r; r = r->next)
-            {
-              /* Merge in the data from the self sigs so that things
-                 like the revoked status are available.  */
-              merge_keys_and_selfsig (r->keyblock);
-              r->processed = 0;
-            }
+        best_pk = NULL;
+        for (r = results; r; r = r->next)
+          {
+            KBNODE kb = r->keyblock;
+            PKT_public_key *pk = kb->pkt->pkt.public_key;
+            KBNODE n;
 
-          for (r = results; r; r = r->next)
-            {
-              KBNODE kb = r->keyblock;
-              PKT_public_key *pk = kb->pkt->pkt.public_key;
+            /* Merge in the data from the self sigs so that things
+               like the revoked status are available.  */
+            merge_keys_and_selfsig (kb);
 
-              if (/* Using disabled keys with --encrypt-to is allowed.  */
-                  ! (option == oEncryptTo || option == oHiddenEncryptTo)
-                  && pk_is_disabled (pk))
-                {
-                  if (DBG_LOOKUP)
-                    log_debug ("  Skipping disabled key: %s\n",
-                               hexfingerprint (pk, fingerprint,
-                                               sizeof fingerprint));
-                  r->processed = 1;
+            if (/* Using disabled keys with --encrypt-to is allowed.  */
+                ! (option == oEncryptTo || option == oHiddenEncryptTo)
+                && pk_is_disabled (pk))
+              {
+                if (DBG_LOOKUP)
+                  log_debug ("  Skipping disabled key: %s\n",
+                             hexfingerprint (pk, fingerprint,
+                                             sizeof fingerprint));
+                continue;
+              }
+            if (pk->flags.revoked)
+              {
+                if (DBG_LOOKUP)
+                  log_debug ("  Skipping revoked key: %s\n",
+                             hexfingerprint (pk, fingerprint,
+                                             sizeof fingerprint));
+                continue;
+              }
+            if (pk->has_expired)
+              {
+                if (DBG_LOOKUP)
+                  log_debug ("  Skipping expired key: %s\n",
+                             hexfingerprint (pk, fingerprint,
+                                             sizeof fingerprint));
+                continue;
+              }
+
+            /* Check for the required encryption or signing
+               capability.  */
+            n = kb;
+            do
+              {
+                PKT_public_key *key = n->pkt->pkt.public_key;
+
+                if ((/* Using disabled keys with --encrypt-to is allowed.  */
+                     pk_is_disabled (key)
+                     && ! (option == oEncryptTo
+                           || option == oHiddenEncryptTo))
+                    || key->flags.revoked
+                    || key->has_expired)
+                  /* Invalid.  */
                   continue;
-                }
-              if (pk->flags.revoked)
-                {
-                  if (DBG_LOOKUP)
-                    log_debug ("  Skipping revoked key: %s\n",
-                               hexfingerprint (pk, fingerprint,
-                                               sizeof fingerprint));
-                  r->processed = 1;
+
+                if (encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_ENC))
                   continue;
-                }
-              if (pk->has_expired)
-                {
-                  if (DBG_LOOKUP)
-                    log_debug ("  Skipping expired key: %s\n",
-                               hexfingerprint (pk, fingerprint,
-                                               sizeof fingerprint));
-                  r->processed = 1;
+                if (! encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_SIG))
                   continue;
-                }
 
-              if (! best_pk)
-                {
-                  best_pk = pk;
-                  best_kb = kb;
-                  r->processed = 1;
-                  continue;
-                }
+                /* Key passes basic tests.  */
+                break;
+              }
+            while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
 
-              /* We have multiple candidates.  Prefer the newer key.
+            if (! n)
+              {
+                if (DBG_LOOKUP)
+                  log_debug ("  Skipping %s, which does not have %s capability.\n",
+                             hexfingerprint (r->keyblock->pkt->pkt.public_key,
+                                             fingerprint, sizeof fingerprint),
+                             encrypt ? "encrypt" : "sign");
+                continue;
+              }
+            else if (DBG_LOOKUP)
+              log_debug ("  %s is valid and has %s capability.\n",
+                         hexfingerprint (r->keyblock->pkt->pkt.public_key,
+                                         fingerprint, sizeof fingerprint),
+                         encrypt ? "encrypt" : "sign");
 
-                 XXX: we should also consider key capabilities (if we
-                 are encrypting to the key, does it have an encryption
-                 capability?).
 
-                 XXX: if we are signing, then we should consider the
-                 key that is actually available (e.g., if one is on a
-                 smart card).  */
-              ambiguous = 1;
-              if (best_pk->timestamp < pk->timestamp)
+            if (! best_pk)
+              {
                 best_pk = pk;
-            }
+                best_kb = kb;
+                continue;
+              }
 
-          if (ambiguous)
-            {
-              /* TRANSLATORS: The %s prints a key specification which
-                 for example has been given at the command line.
-                 Lines with fingerprints are printed after this
-                 message.  */
-              log_error (_("key specification '%s' is ambiguous\n"),
-                         t->d);
-              if (!opt.quiet)
-                log_info (_("(check argument of option '%s')\n"),
-                          option_str);
+            /* We have multiple candidates.  Prefer the newer key.
 
-              log_info (_("'%s' matches at least:\n"), t->d);
+               XXX: we should also consider key capabilities (if we
+               are encrypting to the key, does it have an encryption
+               capability?).
 
-              for (r = results; r; r = r->next)
-                if (! r->processed)
-                  log_info ("  %s\n",
-                            format_hexfingerprint
-                            (hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                             fingerprint, sizeof fingerprint),
-                             fingerprint_formatted,
-                             sizeof fingerprint_formatted));
+               XXX: if we are signing, then we should consider the
+               key that is actually available (e.g., if one is on a
+               smart card).  */
+            ambiguous = 1;
+            if (best_pk->timestamp < pk->timestamp)
+              best_pk = pk;
+          }
 
-              if (! rc)
-                rc = GPG_ERR_AMBIGUOUS_NAME;
-            }
-        }
+        if (! results)
+          {
+            if (encrypt)
+              log_error (_("%s: no matching keys are valid encryption keys"),
+                         t->d);
+            else
+              log_error (_("%s: no matching keys are valid signing keys"),
+                         t->d);
+            if (!opt.quiet)
+              log_info (_("(check argument of option '%s')\n"), option_str);
+            continue;
+          }
+
+        if (ambiguous)
+          {
+            /* TRANSLATORS: The %s prints a key specification which
+               for example has been given at the command line.
+               Lines with fingerprints are printed after this
+               message.  */
+            log_error (_("key specification '%s' is ambiguous\n"),
+                       t->d);
+            if (!opt.quiet)
+              log_info (_("(check argument of option '%s')\n"),
+                        option_str);
+
+            log_info (_("'%s' matches at least:\n"), t->d);
+
+            for (r = results; r; r = r->next)
+              log_info ("  %s\n",
+                        format_hexfingerprint
+                        (hexfingerprint (r->keyblock->pkt->pkt.public_key,
+                                         fingerprint, sizeof fingerprint),
+                         fingerprint_formatted,
+                         sizeof fingerprint_formatted));
+
+            if (! rc)
+              rc = GPG_ERR_AMBIGUOUS_NAME;
+          }
+      }
 
       if ((desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
            || desc.mode == KEYDB_SEARCH_MODE_LONG_KID

commit dc417bf0c555a7416d0aedde6645fd1087660f92
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Dec 15 20:05:20 2015 +0100

    gpg: Fix TOCTTOU when updating keyblocks.
    
    * g10/keydb.c (keydb_update_keyblock): Don't replace the record at the
    current offset.  After taking the lock, extract the fingerprint from
    the keyblock, find it and then replace it.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>
    GnuPG-bug-id: 2193
    
    Between locating the record to update and actually updating the
    keyblock, it is possible that another process modifies the keyring,
    which causes the update to corrupt the keyring.  This is due to a time
    of check to time of use bug.  The fix is straightforward: both
    operations must be done while holding the lock.  This changes the
    semantics of the function slightly, but no callers need to be
    modified.  Further, it now becomes impossible to replace key A with B;
    this function will only ever update B.

diff --git a/g10/keydb.c b/g10/keydb.c
index b308199..fb4966c 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -1386,6 +1386,12 @@ gpg_error_t
 keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
 {
   gpg_error_t err;
+  PKT_public_key *pk = kb->pkt->pkt.public_key;
+  KEYDB_SEARCH_DESC desc;
+  size_t len;
+
+  assert (kb);
+  assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
@@ -1393,9 +1399,6 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
   kid_not_found_flush ();
   keyblock_cache_clear (hd);
 
-  if (hd->found < 0 || hd->found >= hd->used)
-    return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
-
   if (opt.dry_run)
     return 0;
 
@@ -1403,6 +1406,19 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
   if (err)
     return err;
 
+  memset (&desc, 0, sizeof (desc));
+  fingerprint_from_pk (pk, desc.u.fpr, &len);
+  if (len == 20)
+    desc.mode = KEYDB_SEARCH_MODE_FPR20;
+  else
+    log_bug ("%s: Unsupported key length: %zd\n", __func__, len);
+
+  keydb_search_reset (hd);
+  err = keydb_search (hd, &desc, 1, NULL);
+  if (err)
+    return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
+  assert (hd->found >= 0 && hd->found < hd->used);
+
   switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
diff --git a/g10/keydb.h b/g10/keydb.h
index 4164767..0425e74 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -255,12 +255,21 @@ const char *keydb_get_resource_name (KEYDB_HANDLE hd);
    for the user ID node.  */
 gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
 
-/* Replace the currently selected keyblock (i.e., the last result
-   returned by keydb_search) with the key block in KB.
+/* Update the keyblock KB (i.e., extract the fingerprint and find the
+   corresponding keyblock in the keyring).
 
    This doesn't do anything if --dry-run was specified.
 
-   Returns 0 on success.  Otherwise, it returns an error code.  */
+   Returns 0 on success.  Otherwise, it returns an error code.  Note:
+   if there isn't a keyblock in the keyring corresponding to KB, then
+   this function returns GPG_ERR_VALUE_NOT_FOUND.
+
+   This function selects the matching record and modifies the current
+   file position to point to the record just after the selected entry.
+   Thus, if you do a subsequent search using HD, you should first do a
+   keydb_search_reset.  Further, if the selected record is important,
+   you should use keydb_push_found_state and keydb_pop_found_state to
+   save and restore it.  */
 gpg_error_t keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
 
 /* Insert a keyblock into one of the underlying keyrings or keyboxes.

commit 02eb9fc9d5863abcfed6af704e618f8cac7cc2e8
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Dec 17 12:49:06 2015 +0100

    Only add the user supplied CFLAGS after running any autoconf tests.
    
    * configure.ac: Only add the user supplied CFLAGS after running any
    autoconf tests.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>
    
    If the user's CFLAGS include -Werror, then some configure tests fail.
    To avoid this, we only add the user's CFLAGS after all of the
    configure tests have run.

diff --git a/configure.ac b/configure.ac
index 77487b2..266eae5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,13 @@ AB_INIT
 
 AC_GNU_SOURCE
 
+# Before we do anything with the C compiler, we first save the user's
+# CFLAGS (they are restored at the end of the configure script).  This
+# is because some configure checks don't work with -Werror, but we'd
+# like to use -Werror with our build.
+CFLAGS_orig=$CFLAGS
+CFLAGS=
+
 # Some status variables.
 have_gpg_error=no
 have_libgcrypt=no
@@ -1576,6 +1583,11 @@ AC_ARG_ENABLE(optimization,
                    fi])
 
 #
+# Add user CFLAGS.
+#
+CFLAGS="$CFLAGS $CFLAGS_orig"
+
+#
 # Decide what to build
 #
 

commit 1cceba163b17b5e9fd7c89e5b40e3d7e1cffc885
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Dec 17 12:16:22 2015 +0100

    gpg: Suppress a warning.
    
    * dirmngr/dns-stuff.c (enable_dns_tormode): Reference new_circuit to
    avoid a warning when ADNS is not available.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index 1bf6cfc..63dfc8d 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -119,6 +119,8 @@ static char tor_credentials[50];
 gpg_error_t
 enable_dns_tormode (int new_circuit)
 {
+  (void) new_circuit;
+
 #if defined(USE_DNS_CERT) && defined(USE_ADNS)
 # if HAVE_ADNS_IF_TORMODE
    if (!*tor_credentials || new_circuit)

commit 4143cc1c3783c54a6f733f08a4739e4e5fb0c8b3
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Dec 17 10:56:48 2015 +0100

    gpg: Remove dead code.
    
    * kbx/keybox-defs.h (struct keybox_found_s): Remove unused fields
    offset and n_packets.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h
index 8d795ab..6fe9847 100644
--- a/kbx/keybox-defs.h
+++ b/kbx/keybox-defs.h
@@ -80,10 +80,8 @@ struct keybox_name
 struct keybox_found_s
 {
   KEYBOXBLOB blob;
-  off_t offset;
   size_t pk_no;
   size_t uid_no;
-  unsigned int n_packets; /*used for delete and update*/
 };
 
 struct keybox_handle {

commit 7fe4be0416cdc9269011bc4213b8a22d6ced295c
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Dec 17 10:55:29 2015 +0100

    gpg: Display the key that is invalid, not the search description.
    
    * g10/getkey.c (parse_def_secret_key): Display the key that is
    invalid, not the search description.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/getkey.c b/g10/getkey.c
index 589f240..ad0c207 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1225,22 +1225,22 @@ parse_def_secret_key (ctrl_t ctrl)
           if (pk->flags.revoked)
             {
               if (DBG_LOOKUP)
-                log_debug ("not using %s as default key, %s\n",
-                           t->d, "revoked");
+                log_debug (_("not using %s as default key, %s"),
+                           keystr_from_pk (pk), "revoked");
               continue;
             }
           if (pk->has_expired)
             {
               if (DBG_LOOKUP)
-                log_debug ("not using %s as default key, %s\n",
-                           t->d, "expired");
+                log_debug (_("not using %s as default key, %s"),
+                           keystr_from_pk (pk), "expired");
               continue;
             }
           if (pk_is_disabled (pk))
             {
               if (DBG_LOOKUP)
-                log_debug ("not using %s as default key, %s\n",
-                           t->d, "disabled");
+                log_debug (_("not using %s as default key, %s"),
+                           keystr_from_pk (pk), "disabled");
               continue;
             }
 

commit 478ca6c75bbf529f95974224dfb7d71bd5860a96
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Dec 17 10:44:55 2015 +0100

    gpg: Mark more options as coming from the config file (when this holds)
    
    * g10/gpg.c (main): When --default-key or --encrypt-to-default-key is
    taken from the config file, note this.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>
    Regression-due-to: 28311d1

diff --git a/g10/gpg.c b/g10/gpg.c
index ee38be4..2f96bd7 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -3056,6 +3056,8 @@ main (int argc, char **argv)
 	  case oDefaultKey:
             sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
             sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
             break;
 	  case oDefRecipient:
             if( *pargs.r.ret_str )
@@ -3259,7 +3261,7 @@ main (int argc, char **argv)
               sl->flags |= PK_LIST_CONFIG;
 	    break;
           case oEncryptToDefaultKey:
-            opt.encrypt_to_default_key = 1;
+            opt.encrypt_to_default_key = configfp ? 2 : 1;
             break;
 	  case oRecipient: /* store the recipient */
 	    sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
@@ -4250,6 +4252,8 @@ main (int argc, char **argv)
               sl = add_to_strlist2 (&remusr, default_key, utf8_strings);
               sl->flags = ((oEncryptToDefaultKey << PK_LIST_SHIFT)
                            | PK_LIST_ENCRYPT_TO);
+              if (opt.encrypt_to_default_key == 2)
+                sl->flags |= PK_LIST_CONFIG;
             }
           else if (have_def_secret_key)
             log_info (_("option '%s' given, but no valid default keys given\n"),

commit ee8a8ec1cf4605e5af427f9c8b01b3609c82cbe7
Author: Neal H. Walfield <neal at g10code.com>
Date:   Thu Dec 17 10:36:27 2015 +0100

    gpg: Use enums instead of defines.
    
    * g10/keydb.h (PK_LIST_ENCRYPT_TO): Change from a macro to an enum.
    (PK_LIST_HIDDEN): Likewise.
    (PK_LIST_CONFIG): Likewise.
    (PK_LIST_SHIFT): Likewise.n
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>
    
    Using an enum has the advantage that the symbol can be used in gdb.

diff --git a/g10/keydb.h b/g10/keydb.h
index d7aa432..4164767 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -70,12 +70,18 @@ enum resource_type {
 
 
 /* Bit flags used with build_pk_list.  */
-#define PK_LIST_ENCRYPT_TO 1   /* This is an encrypt-to recipient.  */
-#define PK_LIST_HIDDEN     2   /* This is a hidden recipient.       */
-#define PK_LIST_CONFIG     4   /* Specified via config file.        */
+enum
+  {
+    PK_LIST_ENCRYPT_TO=1,   /* This is an encrypt-to recipient.  */
+    PK_LIST_HIDDEN=2,       /* This is a hidden recipient.       */
+    PK_LIST_CONFIG=4        /* Specified via config file.        */
+  };
 /* To store private data in the flags they must be left shifted by
    this value.  */
-#define PK_LIST_SHIFT      3
+enum
+  {
+    PK_LIST_SHIFT=3
+  };
 
 /****************
  * A data structure to hold information about the external position

-----------------------------------------------------------------------

Summary of changes:
 NEWS                           |   3 +
 configure.ac                   |  12 +
 dirmngr/dns-stuff.c            |   2 +
 g10/encrypt.c                  |   2 +-
 g10/getkey.c                   | 290 +++++++++++++++++++++++-
 g10/gpg.c                      | 486 +----------------------------------------
 g10/keydb.c                    |  22 +-
 g10/keydb.h                    |  55 ++++-
 g10/keygen.c                   |   2 +-
 g10/pkclist.c                  |  82 +++++--
 g10/sign.c                     |   2 +-
 g10/skclist.c                  |   7 +
 kbx/keybox-defs.h              |   2 -
 tests/openpgp/Makefile.am      |   2 +-
 tests/openpgp/default-key.test |  73 +++++++
 15 files changed, 520 insertions(+), 522 deletions(-)
 create mode 100755 tests/openpgp/default-key.test


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list