gpg: Improve function documentation and some comments.
[gnupg.git] / g10 / getkey.c
index 0399344..a5f5689 100644 (file)
@@ -562,7 +562,11 @@ get_seckey (PKT_public_key *pk, u32 *keyid)
   release_kbnode (keyblock);
 
   if (!err)
-    err = agent_probe_secret_key (/*ctrl*/NULL, pk);
+    {
+      err = agent_probe_secret_key (/*ctrl*/NULL, pk);
+      if (err)
+       release_public_key_parts (pk);
+    }
 
   return err;
 }
@@ -588,8 +592,12 @@ skip_unusable (void *dummy, u32 * keyid, int uid_no)
 
   pk = keyblock->pkt->pkt.public_key;
 
-  /* Is the user ID in question revoked/expired? */
-  if (uid_no)
+  /* Is the key revoked or expired?  */
+  if (pk->flags.revoked || pk->has_expired)
+    unusable = 1;
+
+  /* Is the user ID in question revoked or expired? */
+  if (!unusable && uid_no)
     {
       KBNODE node;
       int uids_seen = 0;
@@ -890,7 +898,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
            case AKL_CERT:
              mechanism = "DNS CERT";
              glo_ctrl.in_auto_key_retrieve++;
-             rc = keyserver_import_cert (ctrl, name, &fpr, &fpr_len);
+             rc = keyserver_import_cert (ctrl, name, 0, &fpr, &fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
@@ -901,6 +909,13 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
+           case AKL_DANE:
+             mechanism = "DANE";
+             glo_ctrl.in_auto_key_retrieve++;
+             rc = keyserver_import_cert (ctrl, name, 1, &fpr, &fpr_len);
+             glo_ctrl.in_auto_key_retrieve--;
+             break;
+
            case AKL_LDAP:
              mechanism = "LDAP";
              glo_ctrl.in_auto_key_retrieve++;
@@ -1528,7 +1543,15 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
 
   signode = NULL;
   sigdate = 0; /* Helper variable to find the latest signature.  */
-  for (k = keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next)
+
+  /* According to Section 11.1 of RFC 4880, the public key comes first
+     and is immediately followed by any signature packets that modify
+     it.  */
+  for (k = keyblock;
+       k && k->pkt->pkttype != PKT_USER_ID
+        && k->pkt->pkttype != PKT_ATTRIBUTE
+        && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+       k = k->next)
     {
       if (k->pkt->pkttype == PKT_SIGNATURE)
        {
@@ -1686,11 +1709,16 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
       }
 
   /* Second pass: Look at the self-signature of all user IDs.  */
+
+  /* According to RFC 4880 section 11.1, user id and attribute packets
+     are in the second section, after the public key packet and before
+     the subkey packets.  */
   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 (k->pkt->pkttype == PKT_USER_ID || k->pkt->pkttype == PKT_ATTRIBUTE)
+       /* New user id packet.  */
        {
          if (uidnode && signode)
            /* Apply the data from the most recent self-signed packet
@@ -1699,7 +1727,12 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
              fixup_uidnode (uidnode, signode, keytimestamp);
              pk->flags.valid = 1;
            }
-         uidnode = k;
+         /* Clear SIGNODE.  The only relevant self-signed data for
+            UIDNODE follows it.  */
+         if (k->pkt->pkttype == PKT_USER_ID)
+           uidnode = k;
+         else
+           uidnode = NULL;
          signode = NULL;
          sigdate = 0;
        }
@@ -2405,19 +2438,32 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
 
   latest_date = 0;
   latest_key = NULL;
-  /* Do not look at subkeys if a certification key is requested.  */
-  if ((!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) && !req_prim)
+  /* Set latest_key to the latest (the one with the most recent
+     timestamp) good (valid, not revoked, not expired, etc.) subkey.
+
+     Don't bother if we are only looking for a primary key or we need
+     an exact match and the exact match is not a subkey.  */
+  if (req_prim || (foundk && foundk->pkt->pkttype != PKT_PUBLIC_SUBKEY))
+    ;
+  else
     {
       KBNODE nextk;
+
       /* Either start a loop or check just this one subkey.  */
       for (k = foundk ? foundk : keyblock; k; k = nextk)
        {
          PKT_public_key *pk;
-         nextk = k->next;
+
+         if (foundk)
+           /* If FOUNDK is not NULL, then only consider that exact
+              key, i.e., don't iterate.  */
+           nextk = NULL;
+         else
+           nextk = k->next;
+
          if (k->pkt->pkttype != PKT_PUBLIC_SUBKEY)
            continue;
-         if (foundk)
-           nextk = NULL; /* what a hack */
+
          pk = k->pkt->pkt.public_key;
          if (DBG_LOOKUP)
            log_debug ("\tchecking subkey %08lX\n",
@@ -2469,9 +2515,17 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
        }
     }
 
-  /* Okay now try the primary key unless we want an exact
-   * key ID match on a subkey */
-  if ((!latest_key && !(ctx->exact && foundk != keyblock)) || req_prim)
+  /* Check if the primary key is ok (valid, not revoke, not expire,
+     matches requested usage) if:
+
+       - we didn't find an appropriate subkey and we're not doing an
+         exact search,
+
+       - we're doing an exact match and the exact match was the
+         primary key, or,
+
+       - we're just considering the primary key.  */
+  if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
     {
       PKT_public_key *pk;
       if (DBG_LOOKUP && !foundk && !req_prim)
@@ -3013,6 +3067,8 @@ parse_auto_key_locate (char *options)
 #endif
       else if (ascii_strcasecmp (tok, "pka") == 0)
        akl->type = AKL_PKA;
+      else if (ascii_strcasecmp (tok, "dane") == 0)
+       akl->type = AKL_DANE;
       else if ((akl->spec = parse_keyserver_uri (tok, 1)))
        akl->type = AKL_SPEC;
       else