Commit message: gpg: Distinguish between missing and cleared key flags.

* include/cipher.h (PUBKEY_USAGE_NONE): New.
* g10/getkey.c (parse_key_usage): Set new flag.
--

We do not want to use the default capabilities (derived from the
algorithm) if any key flags are given in a signature.  Thus if key
flags are used in any way, the default key capabilities are never
used.

This allows to create a key with key flags set to all zero so it can't
be used.  This better reflects common sense.
CVE: CVE-2013-4351
CWE: CWE-310
Vulnerability description: GnuPG 1.4.x, 2.0.x, and 2.1.x treats a key flags subpacket with all bits cleared (no usage permitted) as if it has all bits set (all usage permitted), which might allow remote attackers to bypass intended cryptographic protection mechanisms by leveraging the subkey.

Project: gnupg
File: getkey.c

get_pubkey_byfprint_fast (PKT_public_key * pk,
			  const byte * fprint, size_t fprint_len)
{
  int rc = 0;
  KEYDB_HANDLE hd;
  KBNODE keyblock;
  byte fprbuf[MAX_FINGERPRINT_LEN];
  int i;

  for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++)
    fprbuf[i] = fprint[i];
  while (i < MAX_FINGERPRINT_LEN)
    fprbuf[i++] = 0;

  hd = keydb_new ();
  rc = keydb_search_fpr (hd, fprbuf);
  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
    {
      keydb_release (hd);
      return G10ERR_NO_PUBKEY;
    }
  rc = keydb_get_keyblock (hd, &keyblock);
  keydb_release (hd);
  if (rc)
    {
      log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc));
      return G10ERR_NO_PUBKEY;
    }

  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
	  || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
  if (pk)
    copy_public_key (pk, keyblock->pkt->pkt.public_key);
  release_kbnode (keyblock);

  /* Not caching key here since it won't have all of the fields
     properly set. */

  return 0;
}

Project: gnupg
File: getkey.c

getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
{
  int rc; /* Fixme:  Make sure this is proper gpg_error */

  rc = lookup (ctx, ret_keyblock, ctx->want_secret);
  if (!rc && pk && ret_keyblock)
    pk_from_block (ctx, pk, *ret_keyblock);

  return rc;
}

Project: gnupg
File: getkey.c

get_user_id (u32 * keyid, size_t * rn)
{
  user_id_db_t r;
  char *p;
  int pass = 0;

  /* Try it two times; second pass reads from key resources.  */
  do
    {
      for (r = user_id_db; r; r = r->next)
	{
	  keyid_list_t a;
	  for (a = r->keyids; a; a = a->next)
	    {
	      if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
		{
		  p = xmalloc (r->len);
		  memcpy (p, r->name, r->len);
		  *rn = r->len;
		  return p;
		}
	    }
	}
    }
  while (++pass < 2 && !get_pubkey (NULL, keyid));
  p = xstrdup (user_id_not_found_utf8 ());
  *rn = strlen (p);
  return p;
}

Project: gnupg
File: getkey.c

cache_public_key (PKT_public_key * pk)
{
#if MAX_PK_CACHE_ENTRIES
  pk_cache_entry_t ce;
  u32 keyid[2];

  if (pk_cache_disabled)
    return;

  if (pk->flags.dont_cache)
    return;

  if (is_ELGAMAL (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);
    }
  else
    return; /* Don't know how to get the keyid.  */

  for (ce = pk_cache; ce; ce = ce->next)
    if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
      {
	if (DBG_CACHE)
	  log_debug ("cache_public_key: already in cache\n");
	return;
      }

  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;
    }
  pk_cache_entries++;
  ce = xmalloc (sizeof *ce);
  ce->next = pk_cache;
  pk_cache = ce;
  ce->pk = copy_public_key (NULL, pk);
  ce->keyid[0] = keyid[0];
  ce->keyid[1] = keyid[1];
#endif
}

Project: gnupg
File: getkey.c

merge_public_with_secret (KBNODE pubblock, KBNODE secblock)
{
  KBNODE pub;

  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);

  for (pub = pubblock; pub; pub = pub->next)
    {
      if (pub->pkt->pkttype == PKT_PUBLIC_KEY)
	{
	  PKT_public_key *pk = pub->pkt->pkt.public_key;
	  PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
	  assert (pub == pubblock); /* Only in the first node.  */
	  /* There is nothing to compare in this case, so just replace
	   * some information.  */
	  copy_public_parts_to_secret_key (pk, sk);
	  free_public_key (pk);
	  pub->pkt->pkttype = PKT_SECRET_KEY;
	  pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
	}
      else if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
	{
	  KBNODE sec;
	  PKT_public_key *pk = pub->pkt->pkt.public_key;

	  /* This is more complicated: It may happen that the sequence
	   * of the subkeys dosn't match, so we have to find the
	   * appropriate secret key.  */
	  for (sec = secblock->next; sec; sec = sec->next)
	    {
	      if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
		{
		  PKT_secret_key *sk = sec->pkt->pkt.secret_key;
		  if (!cmp_public_secret_key (pk, sk))
		    {
		      copy_public_parts_to_secret_key (pk, sk);
		      free_public_key (pk);
		      pub->pkt->pkttype = PKT_SECRET_SUBKEY;
		      pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
		      break;
		    }
		}
	    }
	  if (!sec)
	    BUG (); /* Already checked in premerge.  */
	}
    }
}

Project: gnupg
File: getkey.c

get_pubkey_next (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE * ret_keyblock)
{
  int rc;

  rc = lookup (ctx, ret_keyblock, 0);
  if (!rc && pk && ret_keyblock)
    pk_from_block (ctx, pk, *ret_keyblock);

  return rc;
}

Project: gnupg
File: getkey.c

premerge_public_with_secret (KBNODE pubblock, KBNODE secblock)
{
  KBNODE last, pub;

  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);

  for (pub = pubblock, last = NULL; pub; last = pub, pub = pub->next)
    {
      pub->flag &= ~3; /* Reset bits 0 and 1.  */
      if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
	{
	  KBNODE sec;
	  PKT_public_key *pk = pub->pkt->pkt.public_key;

	  for (sec = secblock->next; sec; sec = sec->next)
	    {
	      if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
		{
		  PKT_secret_key *sk = sec->pkt->pkt.secret_key;
		  if (!cmp_public_secret_key (pk, sk))
		    {
		      if (sk->protect.s2k.mode == 1001)
			{
			  /* The secret parts are not available so
			     we can't use that key for signing etc.
			     Fix the pubkey usage */
			  pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG
						| PUBKEY_USAGE_AUTH);
			}
		      /* Transfer flag bits 0 and 1 to the pubblock.  */
		      pub->flag |= (sec->flag & 3);
		      break;
		    }
		}
	    }
	  if (!sec)
	    {
	      KBNODE next, ll;

	      if (opt.verbose)
		log_info (_("no secret subkey"
			    " for public subkey %s - ignoring\n"),
			  keystr_from_pk (pk));
	      /* We have to remove the subkey in this case.  */
	      assert (last);
	      /* Find the next subkey.  */
	      for (next = pub->next, ll = pub;
		   next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY;
		   ll = next, next = next->next)
		;
	      /* Make new link.  */
	      last->next = next;
	      /* Release this public subkey with all sigs.  */
	      ll->next = NULL;
	      release_kbnode (pub);
	      /* Let the loop continue.  */
	      pub = last;
	    }
	}
    }
  /* We need to copy the found bits (0 and 1) from the secret key to
     the public key.  This has already been done for the subkeys but
     got lost on the primary key - fix it here.  */
  pubblock->flag |= (secblock->flag & 3);
}

Project: gnupg
File: getkey.c

get_keyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
		       size_t fprint_len)
{
  int rc;

  if (fprint_len == 20 || fprint_len == 16)
    {
      struct getkey_ctx_s ctx;

      memset (&ctx, 0, sizeof ctx);
      ctx.not_allocated = 1;
      ctx.kr_handle = keydb_new ();
      ctx.nitems = 1;
      ctx.items[0].mode = (fprint_len == 16
                           ? KEYDB_SEARCH_MODE_FPR16
                           : KEYDB_SEARCH_MODE_FPR20);
      memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
      rc = lookup (&ctx, ret_keyblock, 0);
      get_pubkey_end (&ctx);
    }
  else
    rc = G10ERR_GENERAL; /* Oops */

  return rc;
}

Project: gnupg
File: getkey.c

lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
{
  int rc;
  int no_suitable_key = 0;

  rc = 0;
  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems)))
    {
      /* If we are searching for the first key we have to make sure
         that the next iteration does not do an implicit reset.
         This can be triggered by an empty key ring. */
      if (ctx->nitems && ctx->items->mode == KEYDB_SEARCH_MODE_FIRST)
	ctx->items->mode = KEYDB_SEARCH_MODE_NEXT;

      rc = keydb_get_keyblock (ctx->kr_handle, &ctx->keyblock);
      if (rc)
	{
	  log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc));
	  rc = 0;
	  goto skip;
	}

      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
       * merge_selfsigs.  For secret keys, premerge did tranfer the
       * keys to the keyblock.  */
      merge_selfsigs (ctx->keyblock);
      if (finish_lookup (ctx))
	{
	  no_suitable_key = 0;
	  goto found;
	}
      else
	no_suitable_key = 1;

    skip:
      /* Release resources and continue search. */
      release_kbnode (ctx->keyblock);
      ctx->keyblock = NULL;
    }

found:
  if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
    log_error ("keydb_search failed: %s\n", g10_errstr (rc));

  if (!rc)
    {
      *ret_keyblock = ctx->keyblock; /* Return the keyblock.  */
      ctx->keyblock = NULL;
    }
  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key)
    rc = want_secret? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
    rc = want_secret? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;

  release_kbnode (ctx->keyblock);
  ctx->keyblock = NULL;

  ctx->last_rc = rc;
  return rc;
}

Project: gnupg
File: getkey.c

get_user_id_string (u32 * keyid)
{
  user_id_db_t r;
  char *p;
  int pass = 0;
  /* Try it two times; second pass reads from key resources.  */
  do
    {
      for (r = user_id_db; r; r = r->next)
	{
	  keyid_list_t a;
	  for (a = r->keyids; a; a = a->next)
	    {
	      if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
		{
		  p = xmalloc (keystrlen () + 1 + r->len + 1);
		  sprintf (p, "%s %.*s", keystr (keyid), r->len, r->name);
		  return p;
		}
	    }
	}
    }
  while (++pass < 2 && !get_pubkey (NULL, keyid));
  p = xmalloc (keystrlen () + 5);
  sprintf (p, "%s [?]", keystr (keyid));
  return p;
}

Project: gnupg
File: getkey.c

get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
		   const char *name, KBNODE * ret_keyblock,
		   KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl)
{
  int rc;
  strlist_t namelist = NULL;
  struct akl *akl;
  int is_mbox;
  int nodefault = 0;
  int anylocalfirst = 0;

  if (retctx)
    *retctx = NULL;

  is_mbox = is_valid_mailbox (name);

  /* Check whether we the default local search has been disabled.
     This is the case if either the "nodefault" or the "local" keyword
     are in the list of auto key locate mechanisms.

     ANYLOCALFIRST is set if the search order has the local method
     before any other or if "local" is used first by default.  This
     makes sure that if a RETCTX is used it gets only set if a local
     search has precedence over the other search methods and only then
     a followup call to get_pubkey_next shall succeed.  */
  if (!no_akl)
    {
      for (akl = opt.auto_key_locate; akl; akl = akl->next)
	if (akl->type == AKL_NODEFAULT || akl->type == AKL_LOCAL)
	  {
	    nodefault = 1;
	    break;
	  }
      for (akl = opt.auto_key_locate; akl; akl = akl->next)
	if (akl->type != AKL_NODEFAULT)
	  {
	    if (akl->type == AKL_LOCAL)
	      anylocalfirst = 1;
	    break;
	  }
    }

  if (!nodefault)
    anylocalfirst = 1;

  if (nodefault && is_mbox)
    {
      /* Nodefault but a mailbox - let the AKL locate the key.  */
      rc = G10ERR_NO_PUBKEY;
    }
  else
    {
      add_to_strlist (&namelist, name);
      rc = key_byname (retctx, namelist, pk, 0,
		       include_unusable, ret_keyblock, ret_kdbhd);
    }

  /* If the requested name resembles a valid mailbox and automatic
     retrieval has been enabled, we try to import the key. */
  if (gpg_err_code (rc) == G10ERR_NO_PUBKEY && !no_akl && is_mbox)
    {
      for (akl = opt.auto_key_locate; akl; akl = akl->next)
	{
	  unsigned char *fpr = NULL;
	  size_t fpr_len;
	  int did_key_byname = 0;
	  int no_fingerprint = 0;
	  const char *mechanism = "?";

	  switch (akl->type)
	    {
	    case AKL_NODEFAULT:
	      /* This is a dummy mechanism.  */
	      mechanism = "None";
	      rc = G10ERR_NO_PUBKEY;
	      break;

	    case AKL_LOCAL:
	      mechanism = "Local";
	      did_key_byname = 1;
	      if (retctx)
		{
		  get_pubkey_end (*retctx);
		  *retctx = NULL;
		}
	      add_to_strlist (&namelist, name);
	      rc = key_byname (anylocalfirst ? retctx : NULL,
			       namelist, pk, 0,
			       include_unusable, ret_keyblock, ret_kdbhd);
	      break;

	    case AKL_CERT:
	      mechanism = "DNS CERT";
	      glo_ctrl.in_auto_key_retrieve++;
	      rc = keyserver_import_cert (ctrl, name, &fpr, &fpr_len);
	      glo_ctrl.in_auto_key_retrieve--;
	      break;

	    case AKL_PKA:
	      mechanism = "PKA";
	      glo_ctrl.in_auto_key_retrieve++;
	      rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len);
	      glo_ctrl.in_auto_key_retrieve--;
	      break;

	    case AKL_LDAP:
	      mechanism = "LDAP";
	      glo_ctrl.in_auto_key_retrieve++;
	      rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
	      glo_ctrl.in_auto_key_retrieve--;
	      break;

	    case AKL_KEYSERVER:
	      /* Strictly speaking, we don't need to only use a valid
	         mailbox for the getname search, but it helps cut down
	         on the problem of searching for something like "john"
	         and getting a whole lot of keys back. */
	      if (opt.keyserver)
		{
		  mechanism = opt.keyserver->uri;
		  glo_ctrl.in_auto_key_retrieve++;
		  rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
                                              opt.keyserver);
		  glo_ctrl.in_auto_key_retrieve--;
		}
	      else
		{
		  mechanism = "Unconfigured keyserver";
		  rc = G10ERR_NO_PUBKEY;
		}
	      break;

	    case AKL_SPEC:
	      {
		struct keyserver_spec *keyserver;

		mechanism = akl->spec->uri;
		keyserver = keyserver_match (akl->spec);
		glo_ctrl.in_auto_key_retrieve++;
		rc = keyserver_import_name (ctrl,
                                            name, &fpr, &fpr_len, keyserver);
		glo_ctrl.in_auto_key_retrieve--;
	      }
	      break;
	    }

	  /* Use the fingerprint of the key that we actually fetched.
	     This helps prevent problems where the key that we fetched
	     doesn't have the same name that we used to fetch it.  In
	     the case of CERT and PKA, this is an actual security
	     requirement as the URL might point to a key put in by an
	     attacker.  By forcing the use of the fingerprint, we
	     won't use the attacker's key here. */
	  if (!rc && fpr)
	    {
	      char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];

	      assert (fpr_len <= MAX_FINGERPRINT_LEN);

	      free_strlist (namelist);
	      namelist = NULL;

	      bin2hex (fpr, fpr_len, fpr_string);

	      if (opt.verbose)
		log_info ("auto-key-locate found fingerprint %s\n",
			  fpr_string);

	      add_to_strlist (&namelist, fpr_string);
	    }
	  else if (!rc && !fpr && !did_key_byname)
	    {
	      no_fingerprint = 1;
	      rc = G10ERR_NO_PUBKEY;
	    }
	  xfree (fpr);
	  fpr = NULL;

	  if (!rc && !did_key_byname)
	    {
	      if (retctx)
		{
		  get_pubkey_end (*retctx);
		  *retctx = NULL;
		}
	      rc = key_byname (anylocalfirst ? retctx : NULL,
			       namelist, pk, 0,
			       include_unusable, ret_keyblock, ret_kdbhd);
	    }
	  if (!rc)
	    {
	      /* Key found.  */
	      log_info (_("automatically retrieved '%s' via %s\n"),
			name, mechanism);
	      break;
	    }
	  if (rc != G10ERR_NO_PUBKEY || opt.verbose || no_fingerprint)
	    log_info (_("error retrieving '%s' via %s: %s\n"),
		      name, mechanism,
		      no_fingerprint ? _("No fingerprint") : g10_errstr (rc));
	}
    }


  if (rc && retctx)
    {
      get_pubkey_end (*retctx);
      *retctx = NULL;
    }

  if (retctx && *retctx)
    {
      assert (!(*retctx)->extra_list);
      (*retctx)->extra_list = namelist;
    }
  else
    free_strlist (namelist);
  return rc;
}

Project: gnupg
File: getkey.c

get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
{
  int rc = 0;
  KEYDB_HANDLE hd;
  KBNODE keyblock;
  u32 pkid[2];

  assert (pk);
#if MAX_PK_CACHE_ENTRIES
  {
    /* Try to get it from the cache */
    pk_cache_entry_t ce;

    for (ce = pk_cache; ce; ce = ce->next)
      {
	if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
	  {
	    if (pk)
	      copy_public_key (pk, ce->pk);
	    return 0;
	  }
      }
  }
#endif

  hd = keydb_new ();
  rc = keydb_search_kid (hd, keyid);
  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
    {
      keydb_release (hd);
      return G10ERR_NO_PUBKEY;
    }
  rc = keydb_get_keyblock (hd, &keyblock);
  keydb_release (hd);
  if (rc)
    {
      log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc));
      return G10ERR_NO_PUBKEY;
    }

  assert (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])
    copy_public_key (pk, keyblock->pkt->pkt.public_key);
  else
    rc = G10ERR_NO_PUBKEY;

  release_kbnode (keyblock);

  /* Not caching key here since it won't have all of the fields
     properly set. */

  return rc;
}

Project: gnupg
File: getkey.c

have_secret_key_with_kid (u32 *keyid)
{
  gpg_error_t err;
  KEYDB_HANDLE kdbhd;
  KEYDB_SEARCH_DESC desc;
  kbnode_t keyblock;
  kbnode_t node;
  int result = 0;

  kdbhd = keydb_new ();
  memset (&desc, 0, sizeof desc);
  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)))
    {
      desc.mode = KEYDB_SEARCH_MODE_NEXT;
      err = keydb_get_keyblock (kdbhd, &keyblock);
      if (err)
        {
          log_error (_("error reading keyblock: %s\n"), g10_errstr (err));
          break;
        }

      for (node = keyblock; node; node = node->next)
	{
          /* Bit 0 of the flags is set if the search found the key
             using that key or subkey.  */
	  if ((node->flag & 1))
            {
              assert (node->pkt->pkttype == PKT_PUBLIC_KEY
                      || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);

              if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
                {
                  result = 1;
                  break;
                }
	    }
	}
      release_kbnode (keyblock);
    }
  keydb_release (kdbhd);
  return result;
}

Project: gnupg
File: getkey.c

get_pubkey (PKT_public_key * pk, u32 * keyid)
{
  int internal = 0;
  int rc = 0;

#if MAX_PK_CACHE_ENTRIES
  if (pk)
    {
      /* Try to get it from the cache.  We don't do this when pk is
         NULL as it does not guarantee that the user IDs are
         cached. */
      pk_cache_entry_t ce;
      for (ce = pk_cache; ce; ce = ce->next)
	{
	  if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
	    {
	      copy_public_key (pk, ce->pk);
	      return 0;
	    }
	}
    }
#endif
  /* More init stuff.  */
  if (!pk)
    {
      pk = xmalloc_clear (sizeof *pk);
      internal++;
    }


  /* Do a lookup.  */
  {
    struct getkey_ctx_s ctx;
    KBNODE kb = NULL;
    memset (&ctx, 0, sizeof ctx);
    ctx.exact = 1; /* Use the key ID exactly as given.  */
    ctx.not_allocated = 1;
    ctx.kr_handle = keydb_new ();
    ctx.nitems = 1;
    ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
    ctx.items[0].u.kid[0] = keyid[0];
    ctx.items[0].u.kid[1] = keyid[1];
    ctx.req_algo = pk->req_algo;
    ctx.req_usage = pk->req_usage;
    rc = lookup (&ctx, &kb, 0);
    if (!rc)
      {
	pk_from_block (&ctx, pk, kb);
      }
    get_pubkey_end (&ctx);
    release_kbnode (kb);
  }
  if (!rc)
    goto leave;

  rc = G10ERR_NO_PUBKEY;

leave:
  if (!rc)
    cache_public_key (pk);
  if (internal)
    free_public_key (pk);
  return rc;
}

Project: gnupg
File: getkey.c

cache_user_id (KBNODE keyblock)
{
  user_id_db_t r;
  const char *uid;
  size_t uidlen;
  keyid_list_t keyids = NULL;
  KBNODE k;

  for (k = keyblock; k; k = k->next)
    {
      if (k->pkt->pkttype == PKT_PUBLIC_KEY
	  || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
	{
	  keyid_list_t a = xmalloc_clear (sizeof *a);
	  /* Hmmm: For a long list of keyids it might be an advantage
	   * to append the keys.  */
	  keyid_from_pk (k->pkt->pkt.public_key, a->keyid);
	  /* First check for duplicates.  */
	  for (r = user_id_db; r; r = r->next)
	    {
	      keyid_list_t b = r->keyids;
	      for (b = r->keyids; b; b = b->next)
		{
		  if (b->keyid[0] == a->keyid[0]
		      && b->keyid[1] == a->keyid[1])
		    {
		      if (DBG_CACHE)
			log_debug ("cache_user_id: already in cache\n");
		      release_keyid_list (keyids);
		      xfree (a);
		      return;
		    }
		}
	    }
	  /* Now put it into the cache.  */
	  a->next = keyids;
	  keyids = a;
	}
    }
  if (!keyids)
    BUG (); /* No key no fun.  */


  uid = get_primary_uid (keyblock, &uidlen);

  if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES)
    {
      /* fixme: use another algorithm to free some cache slots */
      r = user_id_db;
      user_id_db = r->next;
      release_keyid_list (r->keyids);
      xfree (r);
      uid_cache_entries--;
    }
  r = xmalloc (sizeof *r + uidlen - 1);
  r->keyids = keyids;
  r->len = uidlen;
  memcpy (r->name, uid, r->len);
  r->next = user_id_db;
  user_id_db = r;
  uid_cache_entries++;
}

Project: gnupg
File: getkey.c

getkey_end (getkey_ctx_t ctx)
{
  get_pubkey_end (ctx);
}

Project: gnupg
File: getkey.c

merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
		     struct revoke_info *rinfo)
{
  PKT_public_key *pk = NULL;
  KBNODE k;
  u32 kid[2];
  u32 sigdate, uiddate, uiddate2;
  KBNODE signode, uidnode, uidnode2;
  u32 curtime = make_timestamp ();
  unsigned int key_usage = 0;
  u32 keytimestamp = 0;
  u32 key_expire = 0;
  int key_expire_seen = 0;
  byte sigversion = 0;

  *r_revoked = 0;
  memset (rinfo, 0, sizeof (*rinfo));

  if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
    BUG ();
  pk = keyblock->pkt->pkt.public_key;
  keytimestamp = pk->timestamp;

  keyid_from_pk (pk, kid);
  pk->main_keyid[0] = kid[0];
  pk->main_keyid[1] = kid[1];

  if (pk->version < 4)
    {
      /* Before v4 the key packet itself contains the expiration date
       * and there was no way to change it, so we start with the one
       * from the key packet.  */
      key_expire = pk->max_expiredate;
      key_expire_seen = 1;
    }

  /* First pass: Find the latest direct key self-signature.  We assume
   * that the newest one overrides all others.  */

  /* In case this key was already merged. */
  xfree (pk->revkey);
  pk->revkey = NULL;
  pk->numrevkeys = 0;

  signode = NULL;
  sigdate = 0; /* Helper variable to find the latest signature.  */
  for (k = keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next)
    {
      if (k->pkt->pkttype == PKT_SIGNATURE)
	{
	  PKT_signature *sig = k->pkt->pkt.signature;
	  if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
	    {
	      if (check_key_signature (keyblock, k, NULL))
		; /* Signature did not verify.  */
	      else if (IS_KEY_REV (sig))
		{
		  /* Key has been revoked - there is no way to
		   * override such a revocation, so we theoretically
		   * can stop now.  We should not cope with expiration
		   * times for revocations here because we have to
		   * assume that an attacker can generate all kinds of
		   * signatures.  However due to the fact that the key
		   * has been revoked it does not harm either and by
		   * continuing we gather some more info on that
		   * key.  */
		  *r_revoked = 1;
		  sig_to_revoke_info (sig, rinfo);
		}
	      else if (IS_KEY_SIG (sig))
		{
		  /* Add any revocation keys onto the pk.  This is
		     particularly interesting since we normally only
		     get data from the most recent 1F signature, but
		     you need multiple 1F sigs to properly handle
		     revocation keys (PGP does it this way, and a
		     revocation key could be sensitive and hence in a
		     different signature). */
		  if (sig->revkey)
		    {
		      int i;

		      pk->revkey =
			xrealloc (pk->revkey, sizeof (struct revocation_key) *
				  (pk->numrevkeys + sig->numrevkeys));

		      for (i = 0; i < sig->numrevkeys; i++)
			memcpy (&pk->revkey[pk->numrevkeys++],
				sig->revkey[i],
				sizeof (struct revocation_key));
		    }

		  if (sig->timestamp >= sigdate)
		    {
		      if (sig->flags.expired)
			; /* Signature has expired - ignore it.  */
		      else
			{
			  sigdate = sig->timestamp;
			  signode = k;
			  if (sig->version > sigversion)
			    sigversion = sig->version;

			}
		    }
		}
	    }
	}
    }

  /* Remove dupes from the revocation keys.  */

  if (pk->revkey)
    {
      int i, j, x, changed = 0;

      for (i = 0; i < pk->numrevkeys; i++)
	{
	  for (j = i + 1; j < pk->numrevkeys; j++)
	    {
	      if (memcmp (&pk->revkey[i], &pk->revkey[j],
			  sizeof (struct revocation_key)) == 0)
		{
		  /* remove j */

		  for (x = j; x < pk->numrevkeys - 1; x++)
		    pk->revkey[x] = pk->revkey[x + 1];

		  pk->numrevkeys--;
		  j--;
		  changed = 1;
		}
	    }
	}

      if (changed)
	pk->revkey = xrealloc (pk->revkey,
			       pk->numrevkeys *
			       sizeof (struct revocation_key));
    }

  if (signode)
    {
      /* Some information from a direct key signature take precedence
       * over the same information given in UID sigs.  */
      PKT_signature *sig = signode->pkt->pkt.signature;
      const byte *p;

      key_usage = parse_key_usage (sig);

      p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
      if (p && buffer_to_u32 (p))
	{
	  key_expire = keytimestamp + buffer_to_u32 (p);
	  key_expire_seen = 1;
	}

      /* Mark that key as valid: One direct key signature should
       * render a key as valid.  */
      pk->flags.valid = 1;
    }

  /* Pass 1.5: Look for key revocation signatures that were not made
     by the key (i.e. did a revocation key issue a revocation for
     us?).  Only bother to do this if there is a revocation key in the
     first place and we're not revoked already.  */

  if (!*r_revoked && pk->revkey)
    for (k = keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next)
      {
	if (k->pkt->pkttype == PKT_SIGNATURE)
	  {
	    PKT_signature *sig = k->pkt->pkt.signature;

	    if (IS_KEY_REV (sig) &&
		(sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1]))
	      {
		int rc = check_revocation_keys (pk, sig);
		if (rc == 0)
		  {
		    *r_revoked = 2;
		    sig_to_revoke_info (sig, rinfo);
		    /* Don't continue checking since we can't be any
		       more revoked than this.  */
		    break;
		  }
		else if (rc == G10ERR_NO_PUBKEY)
		  pk->flags.maybe_revoked = 1;

		/* A failure here means the sig did not verify, was
		   not issued by a revocation key, or a revocation
		   key loop was broken.  If a revocation key isn't
		   findable, however, the key might be revoked and
		   we don't know it.  */

		/* TODO: In the future handle subkey and cert
		   revocations?  PGP doesn't, but it's in 2440. */
	      }
	  }
      }

  /* Second pass: Look at the self-signature of all user IDs.  */
  signode = uidnode = NULL;
  sigdate = 0; /* Helper variable to find the latest signature in one UID. */
  for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
    {
      if (k->pkt->pkttype == PKT_USER_ID)
	{
	  if (uidnode && signode)
	    {
	      fixup_uidnode (uidnode, signode, keytimestamp);
	      pk->flags.valid = 1;
	    }
	  uidnode = k;
	  signode = NULL;
	  sigdate = 0;
	}
      else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode)
	{
	  PKT_signature *sig = k->pkt->pkt.signature;
	  if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
	    {
	      if (check_key_signature (keyblock, k, NULL))
		;		/* signature did not verify */
	      else if ((IS_UID_SIG (sig) || IS_UID_REV (sig))
		       && sig->timestamp >= sigdate)
		{
		  /* Note: we allow to invalidate cert revocations
		   * by a newer signature.  An attacker can't use this
		   * because a key should be revoced with a key revocation.
		   * The reason why we have to allow for that is that at
		   * one time an email address may become invalid but later
		   * the same email address may become valid again (hired,
		   * fired, hired again).  */

		  sigdate = sig->timestamp;
		  signode = k;
		  signode->pkt->pkt.signature->flags.chosen_selfsig = 0;
		  if (sig->version > sigversion)
		    sigversion = sig->version;
		}
	    }
	}
    }
  if (uidnode && signode)
    {
      fixup_uidnode (uidnode, signode, keytimestamp);
      pk->flags.valid = 1;
    }

  /* If the key isn't valid yet, and we have
     --allow-non-selfsigned-uid set, then force it valid. */
  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));
      pk->flags.valid = 1;
    }

  /* The key STILL isn't valid, so try and find an ultimately
     trusted signature. */
  if (!pk->flags.valid)
    {
      uidnode = NULL;

      for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
	   k = k->next)
	{
	  if (k->pkt->pkttype == PKT_USER_ID)
	    uidnode = k;
	  else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode)
	    {
	      PKT_signature *sig = k->pkt->pkt.signature;

	      if (sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1])
		{
		  PKT_public_key *ultimate_pk;

		  ultimate_pk = xmalloc_clear (sizeof (*ultimate_pk));

		  /* We don't want to use the full get_pubkey to
		     avoid infinite recursion in certain cases.
		     There is no reason to check that an ultimately
		     trusted key is still valid - if it has been
		     revoked or the user should also renmove the
		     ultimate trust flag.  */
		  if (get_pubkey_fast (ultimate_pk, sig->keyid) == 0
		      && check_key_signature2 (keyblock, k, ultimate_pk,
					       NULL, NULL, NULL, NULL) == 0
		      && get_ownertrust (ultimate_pk) == TRUST_ULTIMATE)
		    {
		      free_public_key (ultimate_pk);
		      pk->flags.valid = 1;
		      break;
		    }

		  free_public_key (ultimate_pk);
		}
	    }
	}
    }

  /* Record the highest selfsig version so we know if this is a v3
     key through and through, or a v3 key with a v4 selfsig
     somewhere.  This is useful in a few places to know if the key
     must be treated as PGP2-style or OpenPGP-style.  Note that a
     selfsig revocation with a higher version number will also raise
     this value.  This is okay since such a revocation must be
     issued by the user (i.e. it cannot be issued by someone else to
     modify the key behavior.) */

  pk->selfsigversion = sigversion;

  /* Now that we had a look at all user IDs we can now get some information
   * from those user IDs.
   */

  if (!key_usage)
    {
      /* Find the latest user ID with key flags set. */
      uiddate = 0; /* Helper to find the latest user ID.  */
      for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
	   k = k->next)
	{
	  if (k->pkt->pkttype == PKT_USER_ID)
	    {
	      PKT_user_id *uid = k->pkt->pkt.user_id;
	      if (uid->help_key_usage && uid->created > uiddate)
		{
		  key_usage = uid->help_key_usage;
		  uiddate = uid->created;
		}
	    }
	}
    }
  if (!key_usage)
    {
      /* No key flags at all: get it from the algo.  */
      key_usage = openpgp_pk_algo_usage (pk->pubkey_algo);
    }
  else
    {
      /* Check that the usage matches the usage as given by the algo.  */
      int x = openpgp_pk_algo_usage (pk->pubkey_algo);
      if (x) /* Mask it down to the actual allowed usage.  */
	key_usage &= x;
    }

  /* Whatever happens, it's a primary key, so it can certify. */
  pk->pubkey_usage = key_usage | PUBKEY_USAGE_CERT;

  if (!key_expire_seen)
    {
      /* Find the latest valid user ID with a key expiration set
       * Note, that this may be a different one from the above because
       * some user IDs may have no expiration date set.  */
      uiddate = 0;
      for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
	   k = k->next)
	{
	  if (k->pkt->pkttype == PKT_USER_ID)
	    {
	      PKT_user_id *uid = k->pkt->pkt.user_id;
	      if (uid->help_key_expire && uid->created > uiddate)
		{
		  key_expire = uid->help_key_expire;
		  uiddate = uid->created;
		}
	    }
	}
    }

  /* Currently only v3 keys have a maximum expiration date, but I'll
     bet v5 keys get this feature again. */
  if (key_expire == 0
      || (pk->max_expiredate && key_expire > pk->max_expiredate))
    key_expire = pk->max_expiredate;

  pk->has_expired = key_expire >= curtime ? 0 : key_expire;
  pk->expiredate = key_expire;

  /* Fixme: we should see how to get rid of the expiretime fields  but
   * this needs changes at other places too. */

  /* And now find the real primary user ID and delete all others.  */
  uiddate = uiddate2 = 0;
  uidnode = uidnode2 = NULL;
  for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
    {
      if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data)
	{
	  PKT_user_id *uid = k->pkt->pkt.user_id;
	  if (uid->is_primary)
	    {
	      if (uid->created > uiddate)
		{
		  uiddate = uid->created;
		  uidnode = k;
		}
	      else if (uid->created == uiddate && uidnode)
		{
		  /* The dates are equal, so we need to do a
		     different (and arbitrary) comparison.  This
		     should rarely, if ever, happen.  It's good to
		     try and guarantee that two different GnuPG
		     users with two different keyrings at least pick
		     the same primary. */
		  if (cmp_user_ids (uid, uidnode->pkt->pkt.user_id) > 0)
		    uidnode = k;
		}
	    }
	  else
	    {
	      if (uid->created > uiddate2)
		{
		  uiddate2 = uid->created;
		  uidnode2 = k;
		}
	      else if (uid->created == uiddate2 && uidnode2)
		{
		  if (cmp_user_ids (uid, uidnode2->pkt->pkt.user_id) > 0)
		    uidnode2 = k;
		}
	    }
	}
    }
  if (uidnode)
    {
      for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
	   k = k->next)
	{
	  if (k->pkt->pkttype == PKT_USER_ID &&
	      !k->pkt->pkt.user_id->attrib_data)
	    {
	      PKT_user_id *uid = k->pkt->pkt.user_id;
	      if (k != uidnode)
		uid->is_primary = 0;
	    }
	}
    }
  else if (uidnode2)
    {
      /* None is flagged primary - use the latest user ID we have,
         and disambiguate with the arbitrary packet comparison. */
      uidnode2->pkt->pkt.user_id->is_primary = 1;
    }
  else
    {
      /* None of our uids were self-signed, so pick the one that
         sorts first to be the primary.  This is the best we can do
         here since there are no self sigs to date the uids. */

      uidnode = NULL;

      for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
	   k = k->next)
	{
	  if (k->pkt->pkttype == PKT_USER_ID
	      && !k->pkt->pkt.user_id->attrib_data)
	    {
	      if (!uidnode)
		{
		  uidnode = k;
		  uidnode->pkt->pkt.user_id->is_primary = 1;
		  continue;
		}
	      else
		{
		  if (cmp_user_ids (k->pkt->pkt.user_id,
				    uidnode->pkt->pkt.user_id) > 0)
		    {
		      uidnode->pkt->pkt.user_id->is_primary = 0;
		      uidnode = k;
		      uidnode->pkt->pkt.user_id->is_primary = 1;
		    }
		  else
		    k->pkt->pkt.user_id->is_primary = 0;	/* just to be
								   safe */
		}
	    }
	}
    }
}

Project: gnupg
File: getkey.c

parse_auto_key_locate (char *options)
{
  char *tok;

  while ((tok = optsep (&options)))
    {
      struct akl *akl, *check, *last = NULL;
      int dupe = 0;

      if (tok[0] == '\0')
	continue;

      akl = xmalloc_clear (sizeof (*akl));

      if (ascii_strcasecmp (tok, "nodefault") == 0)
	akl->type = AKL_NODEFAULT;
      else if (ascii_strcasecmp (tok, "local") == 0)
	akl->type = AKL_LOCAL;
      else if (ascii_strcasecmp (tok, "ldap") == 0)
	akl->type = AKL_LDAP;
      else if (ascii_strcasecmp (tok, "keyserver") == 0)
	akl->type = AKL_KEYSERVER;
#ifdef USE_DNS_CERT
      else if (ascii_strcasecmp (tok, "cert") == 0)
	akl->type = AKL_CERT;
#endif
#ifdef USE_DNS_PKA
      else if (ascii_strcasecmp (tok, "pka") == 0)
	akl->type = AKL_PKA;
#endif
      else if ((akl->spec = parse_keyserver_uri (tok, 1, NULL, 0)))
	akl->type = AKL_SPEC;
      else
	{
	  free_akl (akl);
	  return 0;
	}

      /* We must maintain the order the user gave us */
      for (check = opt.auto_key_locate; check;
	   last = check, check = check->next)
	{
	  /* Check for duplicates */
	  if (check->type == akl->type
	      && (akl->type != AKL_SPEC
		  || (akl->type == AKL_SPEC
		      && strcmp (check->spec->uri, akl->spec->uri) == 0)))
	    {
	      dupe = 1;
	      free_akl (akl);
	      break;
	    }
	}

      if (!dupe)
	{
	  if (last)
	    last->next = akl;
	  else
	    opt.auto_key_locate = akl;
	}
    }

  return 1;
}

Project: gnupg
File: getkey.c

get_pubkey_byfprint (PKT_public_key * pk,
		     const byte * fprint, size_t fprint_len)
{
  int rc;

  if (fprint_len == 20 || fprint_len == 16)
    {
      struct getkey_ctx_s ctx;
      KBNODE kb = NULL;

      memset (&ctx, 0, sizeof ctx);
      ctx.exact = 1;
      ctx.not_allocated = 1;
      ctx.kr_handle = keydb_new ();
      ctx.nitems = 1;
      ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
	: KEYDB_SEARCH_MODE_FPR20;
      memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
      rc = lookup (&ctx, &kb, 0);
      if (!rc && pk)
	pk_from_block (&ctx, pk, kb);
      release_kbnode (kb);
      get_pubkey_end (&ctx);
    }
  else
    rc = G10ERR_GENERAL; /* Oops */
  return rc;
}

Project: gnupg
File: getkey.c

get_pubkey_end (GETKEY_CTX ctx)
{
  if (ctx)
    {
      memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
      keydb_release (ctx->kr_handle);
      free_strlist (ctx->extra_list);
      if (!ctx->not_allocated)
	xfree (ctx);
    }
}

Project: gnupg
File: getkey.c

get_long_user_id_string (u32 * keyid)
{
  user_id_db_t r;
  char *p;
  int pass = 0;
  /* Try it two times; second pass reads from key resources.  */
  do
    {
      for (r = user_id_db; r; r = r->next)
	{
	  keyid_list_t a;
	  for (a = r->keyids; a; a = a->next)
	    {
	      if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
		{
		  p = xmalloc (r->len + 20);
		  sprintf (p, "%08lX%08lX %.*s",
			   (ulong) keyid[0], (ulong) keyid[1],
			   r->len, r->name);
		  return p;
		}
	    }
	}
    }
  while (++pass < 2 && !get_pubkey (NULL, keyid));
  p = xmalloc (25);
  sprintf (p, "%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
  return p;
}